围绕 Claude Design 搭建出稿队列,TaoToken 填进 secret
1. 统一聊天界面之后前端出稿队列要解决的真实问题Anthropic 把 Claude Chat 与 Claude Cowork 整合到一个统一入口Claude Docs、Claude Slides 也加入其中Claude Design 同样能从聊天界面直接访问。对前端基建开发者来说真正的变化不是界面上多了几个按钮而是“设计稿出稿—文档出稿—幻灯片出稿”从零散手动操作变成可以排队、重试、审计和自动落盘的任务流。先用 TaoToken 获取 KeyTaoToken 官网再把请求 Base URL 设为https://taotoken.net/api。本文按这个前提给出一份 secret 配置、一个可重试的队列脚本以及 Design、Docs、Slides 三类出稿结果的对照表。很多团队在第一次接出稿队列时会犯三个典型错误第一把 Key 写进前端源码或VITE_变量导致预览环境和生产环境互相污染第二把 Claude Code 的ANTHROPIC_*变量直接复制给 Codex结果 Codex 侧读不到配置第三队列没有幂等和重试某个任务 429 后整批卡死第二天只能人工补。前端基建要做的不是再包一层聊天 UI而是把“取 Key、设 Base URL、提交任务、处理错误、落盘结果”这条路径标准化。下面这套方案的核心目标很明确在本地和 CI 中都能用同一个TAOTOKEN_API_KEYClaude Code、Codex、CC Switch 各自使用正确配置队列脚本围绕design、doc、slides三类任务生成出稿文件最后用索引 JSON 做结果对照。先把 secret 配置拆开不把任何真实 Key 提交到仓库。2. Secret 配置TaoToken Key、Base URL 与三套工具链第一步是在 TaoToken 控制台创建 Key然后在本地只保留占位符。你可以从 API Keys 进入控制台创建也可以在 TaoToken 官网 先了解模型对话和 Coding Plan。无论用哪种方式Base URL 在工具配置里都写https://taotoken.net/api不要给它拼接 UTM 参数UTM 只用于网页入口统计。本地开发建议建.env.local并确保.gitignore包含它# .env.local TAOTOKEN_API_KEYYOUR_API_KEY TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELclaude-sonnet-4-5 QUEUE_CONCURRENCY2如果是 GitHub Actions则把 Key 放到仓库 Secrets 中工作流只读环境变量# .github/workflows/draft-queue.yml name: draft-queue on: workflow_dispatch: jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - run: npx tsx queue-worker.ts env: TAOTOKEN_API_KEY: ${{ secrets.TAOTOKEN_API_KEY }} TAOTOKEN_BASE_URL: https://taotoken.net/api TAOTOKEN_MODEL: claude-sonnet-4-5Claude Code 使用settings.json或项目级.claude/settings.local.json变量名走ANTHROPIC_*。这是一套独立配置不要和 Codex 混用{ env: { ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_MODEL: claude-sonnet-4-5 } }Codex 使用config.toml不要写ANTHROPIC_*。Codex 侧应该使用自己的 provider 配置和TAOTOKEN_API_KEY# ~/.codex/config.toml model gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatCC Switch 可以理解成“供应商切换三件套”名称、Base URL、Key。配置时只填这三项避免在多个工具之间复制错误变量{ providers: [ { name: taotoken, baseUrl: https://taotoken.net/api, apiKey: YOUR_API_KEY } ] }再强调一次边界Claude Code 用settings.json和ANTHROPIC_*Codex 用config.toml和TAOTOKEN_API_KEYCC Switch 管供应商三件套。三者不要交叉套用。这样出稿队列脚本只需要读取TAOTOKEN_API_KEY和TAOTOKEN_BASE_URL不依赖具体 IDE 的配置文件。3. 队列脚本Design/Docs/Slides 任务如何串成可重试 worker出稿队列的输入不应该是一段随手写的聊天记录而应该是结构化任务。前端基建可以先定义一个tasks.json把 Claude Design 相关出稿、技术文档出稿、幻灯片大纲出稿都收进同一张表[ { id: design-home-001, type: design, title: 首页设计稿出稿说明, input: 组件树Header、Hero、FeatureGrid、Footer设计 tokencolor.bg、color.text、radius.card状态loading、empty、error断点375、768、1280 }, { id: doc-api-002, type: doc, title: 出稿队列 API 文档初稿, input: 接口创建任务、查询任务、下载结果配置TAOTOKEN_API_KEY、TAOTOKEN_BASE_URLhttps://taotoken.net/api错误401、404、429 }, { id: slides-review-003, type: slides, title: 设计出稿流程评审幻灯片, input: 背景统一聊天界面目标可排队、可重试、可对照角色前端基建、设计、文档下一步接入 CI } ]队列脚本用 Node 18 的fetch即可。下面这份queue-worker.ts包含并发控制、指数退避、空结果检查和 Markdown 落盘// queue-worker.ts import { readFile, mkdir, writeFile } from node:fs/promises; import path from node:path; type TaskType design | doc | slides; type Task { id: string; type: TaskType; title: string; input: string; }; type Draft { id: string; type: TaskType; title: string; content: string; raw: unknown; }; const API_KEY process.env.TAOTOKEN_API_KEY; const BASE_URL (process.env.TAOTOKEN_BASE_URL ?? https://taotoken.net/api).replace(/\/$/, ); const MODEL process.env.TAOTOKEN_MODEL ?? claude-sonnet-4-5; const CONCURRENCY Number(process.env.QUEUE_CONCURRENCY ?? 2); const OUT_DIR path.resolve(drafts); if (!API_KEY) { throw new Error(缺少 TAOTOKEN_API_KEY请先在 TaoToken 控制台创建 Key); } const prompts: RecordTaskType, (task: Task) string { design: (task) [ 你是前端基建出稿助手。请根据设计说明输出 Markdown必须包含, 1. 组件树, 2. 设计 token 映射表, 3. 状态与交互, 4. 响应式断点, 5. 验收清单, , 任务${task.title}, task.input, ].join(\n), doc: (task) [ 请把材料整理成技术文档初稿包含标题、摘要、背景、步骤、配置示例、排障。, 配置中的 Base URL 统一写 https://taotoken.net/api。, , 任务${task.title}, task.input, ].join(\n), slides: (task) [ 请把材料整理成幻灯片大纲。每页包含页标题、3-5 个要点、演讲备注。, , 任务${task.title}, task.input, ].join(\n), }; function sleep(ms: number) { return new Promise((resolve) setTimeout(resolve, ms)); } async function callTaoToken(task: Task, attempt 1): PromiseDraft { const body { model: MODEL, temperature: 0.2, messages: [ { role: system, content: 你负责把统一聊天界面中的设计、文档、幻灯片需求整理成结构化出稿。, }, { role: user, content: prompts[task.type](task), }, ], }; const response await fetch(${BASE_URL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY}, }, body: JSON.stringify(body), }); if (!response.ok) { const detail await response.text(); if (attempt 4 (response.status 429 || response.status 500)) { await sleep(2 ** attempt * 500); return callTaoToken(task, attempt 1); } throw new Error(TaoToken 请求失败 ${response.status}: ${detail}); } const json (await response.json()) as { choices?: Array{ message?: { content?: string } }; }; const content json.choices?.[0]?.message?.content ?? ; if (!content.trim()) { throw new Error(任务 ${task.id} 返回空内容); } return { id: task.id, type: task.type, title: task.title, content, raw: json, }; } async function run() { const tasks JSON.parse(await readFile(tasks.json, utf8)) as Task[]; await mkdir(OUT_DIR, { recursive: true }); const results: Draft[] []; let cursor 0; async function worker() { while (cursor tasks.length) { const task tasks[cursor]; const draft await callTaoToken(task); const file path.join(OUT_DIR, ${task.id}.md); await writeFile(file, draft.content, utf8); results.push(draft); console.log(完成 ${task.id} - ${file}); } } const workerCount Math.min(CONCURRENCY, tasks.length); await Promise.all(Array.from({ length: workerCount }, worker)); await writeFile( path.join(OUT_DIR, index.json), JSON.stringify(results, null, 2), utf8 ); console.log(全部完成共 ${results.length} 条); } run().catch((error) { console.error(error); process.exit(1); });本地运行方式如下。注意YOUR_API_KEY必须替换成真实 KeyBase URL 保持不带 UTMexport TAOTOKEN_API_KEYYOUR_API_KEY export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODELclaude-sonnet-4-5 npx tsx queue-worker.ts如果你希望任务幂等可以在 worker 里先判断drafts/${task.id}.md是否存在存在则跳过。这个判断对 CI 很有用同一批设计稿出稿重跑时不会重复消耗额度也不会覆盖人工改过的结果。队列脚本的建议是“输入稳定、输出可追踪、失败可重试”而不是把所有逻辑塞进一个聊天窗口。4. 出稿结果对照三类任务的字段、验收与落盘队列跑通后必须有一张对照表否则你无法判断生成结果是否可用于前端基建。Design、Docs、Slides 三类任务的输入、输出和验收点不同但落盘结构可以统一成id.md index.json。类型输入重点输出主体落盘文件验收点design组件树、设计 token、交互状态、断点组件树、token 映射、状态表、响应式说明、验收清单drafts/design-home-001.md每个 token 能追溯到输入代码块标语言断点覆盖 375/768/1280doc需求、接口、配置、错误码标题、摘要、背景、步骤、配置示例、排障drafts/doc-api-002.md命令可复制Base URL 为https://taotoken.net/api401/404/429 都有说明slides背景、目标、角色、下一步每页标题、3-5 个要点、演讲备注drafts/slides-review-003.md单页要点不超 5 条备注能独立讲清一页没有多余装饰性文字为了让结果可检索可以再加一个normalize函数把 Markdown 出稿转成索引记录。这样前端页面、内部文档站或 CI 报告都能读取同一份 JSONtype DraftIndex { id: string; type: TaskType; title: string; file: string; headings: string[]; codeBlocks: number; model: string; }; function normalizeDraft(draft: Draft, file: string): DraftIndex { const headings draft.content .split(\n) .filter((line) /^#{1,3}\s/.test(line)) .map((line) line.replace(/^#\s*/, ).trim()); const codeBlocks Math.floor((draft.content.match(//g) ?? []).length / 2); return { id: draft.id, type: draft.type, title: draft.title, file, headings, codeBlocks, model: MODEL, }; }对照时重点看三件事。第一design出稿是否把 Claude Design 里的组件描述转成了可执行的前端字段而不是只复述需求。第二doc出稿是否把 TaoToken Key、Base URL、Claude Code 配置、Codex 配置分开写清楚尤其不能把ANTHROPIC_*塞进 Codex。第三slides出稿是否适合评审而不是把文档段落原样复制成几十页。如果团队有设计系统还可以在 normalize 后再跑一次本地校验检查每个design结果是否包含color.、radius.、breakpoint.等前缀检查doc结果是否出现YOUR_API_KEY占位符检查slides每页要点数量。校验脚本只在本地读 Markdown不连接任何生产数据库也不让队列直接改线上配置。5. 常见排障401、404、429 与模型名不匹配接入队列后最常见的错误是 401。原因通常不是 TaoToken 不可用而是YOUR_API_KEY没有替换或者 CI 中没有注入TAOTOKEN_API_KEY。先在本地用 curl 验证 Key 和 Base URL。下面命令由你在本地终端执行curl -sS https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-5,messages:[{role:user,content:输出三条出稿队列验收清单}]}如果返回 401去 TaoToken 官网 重新确认 Key 状态并在控制台重新创建后只更新.env.local或 CI Secrets。不要在前端代码里硬编码。404 一般来自 Base URL 拼接错误。队列脚本里 Base URL 是https://taotoken.net/api手动请求路径是${BASE_URL}/v1/chat/completions。如果你填成https://taotoken.net/api/又手动加/v1/chat/completions就可能出现双斜杠如果填成https://taotoken.net/api/v1又会重复/v1。统一用replace(/\/$/, )去掉尾斜杠。Claude Code 的ANTHROPIC_BASE_URL只填https://taotoken.net/api不要手动加/v1/messages。429 表示并发或频率触发限制。队列脚本已经用2 ** attempt * 500做指数退避并限制QUEUE_CONCURRENCY2。如果团队多人同时跑建议把并发降到 1或者按任务类型拆队列先跑design再跑doc最后跑slides。不要把 429 当成失败直接丢弃应该让任务重新入队。模型名不匹配也会导致请求失败。脚本里的claude-sonnet-4-5只是示例实际可用模型 ID 以 TaoToken 模型对话页为准。你可以先通过模型对话验证模型名再把TAOTOKEN_MODEL写进环境变量。不要在 Codex 的config.toml里写ANTHROPIC_MODELCodex 只认自己的model和model_provider。Claude Code 排障时可以临时导出环境变量核对export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_BASE_URLhttps://taotoken.net/api claude如果 Claude Code 正常而队列脚本 401说明 Key 在settings.json中有效但 shell 环境没有TAOTOKEN_API_KEY。如果 Codex 正常而 Claude Code 失败检查是否把TAOTOKEN_API_KEY写进了 Claude CodeClaude Code 侧应使用ANTHROPIC_AUTH_TOKEN。两边分开问题会少很多。6. 与 Claude Code、Codex、CC Switch 的协同配置出稿队列不是孤立的脚本它会和日常编码工具共存。推荐把配置分成三层个人工具层、项目队列层、CI 层。个人工具层包括 Claude Code、Codex、CC Switch项目队列层读取.env.localCI 层只读仓库 Secrets。三层之间只共享一个 Key 名称不共享错误的变量前缀。Claude Code 的settings.json可以放在用户级也可以放在项目级。用户级适合个人 Key项目级适合团队统一 Base URL。示例{ env: { ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_MODEL: claude-sonnet-4-5 }, permissions: { allow: [] } }Codex 的config.toml则保持独立。下面这份配置只用于 Codex不能复制ANTHROPIC_*model gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatCC Switch 的三件套适合频繁切换供应商的人。配置时只维护名称、Base URL、Key 来源{ providers: [ { name: taotoken, baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY } ] }如果团队里有人同时用 Claude Code 和 Codex建议在 README 里写清楚两张表。第一张表写“工具—配置文件—变量前缀”Claude Code 是settings.jsonANTHROPIC_*Codex 是config.tomlTAOTOKEN_API_KEYCC Switch 是供应商三件套。第二张表写“Base URL—是否带 UTM”所有工具配置统一https://taotoken.net/api不带 UTM网页入口才带 UTM。这样新人不会把网页链接误填进工具配置。另外队列脚本中的模型调用建议只依赖环境变量不直接读 Claude Code 或 Codex 的配置文件。原因是 CI 环境没有这些个人配置。正确做法是队列脚本读TAOTOKEN_API_KEY、TAOTOKEN_BASE_URL、TAOTOKEN_MODELClaude Code 和 Codex 各自读自己的配置它们之间通过同一个 TaoToken Key 关联而不是通过复制变量关联。7. 从本地队列到团队使用安全边界与 CTA 路径当队列跑通后下一步是把它放进团队流程。安全边界至少包括.env.local不入库CI 只使用 Secrets日志不打印完整 Key生成结果中的YOUR_API_KEY占位符不能被真实 Key 替换预览环境与生产环境使用不同 Key 或不同项目。队列任务可以并发但写文件要按id隔离避免两个任务写同一个结果。出稿结果对照建议在 CI 中做轻量校验而不是重新调用模型。比如检查drafts/index.json是否存在、每个任务是否有对应.md、每个design任务是否包含验收清单、每个doc任务是否包含 Base URL、每个slides任务是否包含备注。这样即使模型输出有波动基建层也能给出明确失败原因。如果你还没有开始配置推荐按下面顺序走一遍模型对话验证可用性先确认模型能正常返回内容再决定用哪个模型 ID。入口是 模型对话。Coding Plan 评估持续出稿如果队列要长期跑先看 Coding Plan再决定并发和重试策略。创建 Key 并填入 secret在 API Keys 创建YOUR_API_KEY对应的真实 Key写入.env.local或 CI Secrets。Claude Code 配置核对如果还要在终端里直接改队列脚本按 Claude Code 文档 配置settings.json和ANTHROPIC_*但不要把它套给 Codex。最后再回到本文的主线Claude Design 从统一聊天界面访问后前端团队完全可以把它当成出稿队列的一类任务源。TaoToken 填入 secret 后Base URL 固定为https://taotoken.net/api队列脚本负责排队、重试、落盘出稿对照表负责验收。先替换YOUR_API_KEY把tasks.json里的示例任务跑通再把design、doc、slides三类结果接入 CI。这样统一聊天界面带来的不是更多手动入口而是一条可维护的前端出稿基础设施。