1. 从一次“规格写歪了”的翻车说起
Claude Code 是 Anthropic 推出的终端级 AI 编程代理,能读文件、跑命令、改代码、执行多步任务;Spec Coding(规格驱动开发,SDD)则是先写规格文档、再让 AI 按规格落代码的工作流。把这两者拼在一起,适合谁?适合已经能用 Claude Code 跑通单文件修改、但一遇到“跨 5 个文件 + 3 层目录”的模块就频繁返工的开发者。我这次要验证的,就是它在规格驱动下到底能走多远、在哪里会掉链子。
先说结论性的场景:我拿一个“定时任务管理”小模块做边界验证——独立路由、完整 CRUD、执行记录列表、检索过滤,对接 6 个后端接口。规格文档先写清楚 proposal(为什么做)、design(怎么做)、tasks(分几步),再让 Claude Code 按 tasks 逐条执行。整个过程里,真正卡住我的不是模型写代码的能力,而是三件事:settings.json 骨架没配对导致 MCP 起不来、规格里字段定义含糊导致 AI 自行“脑补”、以及验证动作没有固定记录方式导致返工无法复盘。
这篇就按可复现的路径走一遍:先给 settings.json 骨架,再接入统一 Key/API 通道,然后跑通一个最小 SDD 项目,最后把边界用例的验证动作和结果记录方式固定下来。你照着做,能拿到一份可复制的配置和一套可复用的验证清单。
2. TaoToken 前置:统一 Key 与 API 通道接入
Claude Code 默认走 Anthropic 官方通道,但在国内网络环境下直连经常超时,而且多项目切换时 Key 管理很乱。我的做法是用 TaoToken 做统一入口:一个 Key 管所有模型调用,API 地址统一,Claude Code 的 settings.json 里只改 base_url 和 api_key 两个字段。
先注册并拿到 Key。打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,进控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,Key 列表在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。创建时建议按项目命名,比如claude-code-sdd,方便后面排查是哪个项目在消耗额度。
API 基础地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,直接填进配置即可。如果你用的是 Claude Code 的 Anthropic 兼容模式,base_url 填https://taotoken.net/api,模型名按平台文档里列出的 Claude 系列填写。
提示:Key 只在创建时完整显示一次,复制后立刻存进密码管理器。不要写进会提交到 Git 的 settings.json,用环境变量注入。
接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各客户端的完整配置示例。我实测下来,Claude Code 走这个通道后,长会话的稳定性比直连好很多,尤其是连续跑 30 条以上指令时不容易断。
3. 可复制配置:settings.json 骨架与 MCP 接入
Claude Code 的配置分两层:全局~/.claude/settings.json管模型通道和权限,项目级.claude/settings.json管项目专属的 MCP 和规则。下面这份是我验证过的骨架,直接改 Key 就能用。
3.1 全局 settings.json 骨架
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" }, "permissions": { "allow": [ "Read", "Glob", "Grep", "Edit", "Write", "Bash(pnpm *)", "Bash(git diff *)", "Bash(git status)" ], "deny": [ "Bash(rm -rf *)", "Bash(git push *)", "Read(./.env)" ] }, "includeCoAuthoredBy": false }几个关键点。ANTHROPIC_BASE_URL指向 TaoToken 的 API 地址,不要加尾部斜杠。permissions.allow里我放开了pnpm和只读的 git 命令,但把git push和rm -rf放进 deny——这是边界验证的一部分,后面会讲为什么。includeCoAuthoredBy设为 false 是为了让提交记录干净,避免 AI 署名混进正式仓库。
3.2 项目级 MCP 接入配置
MCP(Model Context Protocol)是让 Claude Code 访问外部工具的标准协议。我在项目里接了两个 MCP:一个读接口文档,一个读需求文档。项目级配置放在.claude/settings.json:
{ "mcpServers": { "api-docs": { "command": "npx", "args": ["-y", "@your-org/api-docs-mcp"], "env": { "API_DOC_TOKEN": "${API_DOC_TOKEN}" } }, "feishu-docs": { "command": "npx", "args": ["-y", "@your-org/feishu-mcp"], "env": { "FEISHU_APP_ID": "${FEISHU_APP_ID}", "FEISHU_APP_SECRET": "${FEISHU_APP_SECRET}" } } } }MCP 的 token 全部走环境变量,不硬编码。启动 Claude Code 前先export API_DOC_TOKEN=xxx,或者在 shell 的 rc 文件里配好。验证 MCP 是否挂载成功,在 Claude Code 里输入/mcp就能看到已连接的服务列表。
3.3 规格目录结构
SDD 的核心是规格先行。我在项目根目录建了openspec/目录,每个变更一个子目录:
openspec/ └── changes/ └── add-scheduled-task/ ├── proposal.md # 为什么做、解决什么问题 ├── design.md # 技术方案、数据结构、接口约定 ├── specs/ │ └── task.md # 功能规格:字段、行为、边界 └── tasks.md # 分步执行清单tasks.md是 Claude Code 直接消费的文件,每条任务要有明确的输入和验收标准。比如:
## Task 3: 生成接口类型定义 - 输入:design.md 中 6 个接口的字段表 - 动作:在 src/services/task/interface.ts 生成 ICreateTaskReq 等类型 - 验收:tsc --noEmit 通过,字段注释完整4. 验证请求:跑通最小 SDD 项目
配置就绪后,跑一个最小闭环验证。我选的场景是“定时任务管理”模块,因为它同时覆盖了 CRUD、列表检索、执行记录三个典型模式,又不会大到失控。
4.1 启动与规格加载
在项目根目录启动 Claude Code,先让它读规格:
claude进入交互后输入:
请阅读 openspec/changes/add-scheduled-task/ 下的全部文件, 总结 proposal、design、tasks 的核心内容,并确认你理解的执行顺序。这一步是边界验证的第一道关卡。如果 AI 总结出的执行顺序和 tasks.md 不一致,说明规格里有歧义,先改规格再往下走。我实测时第一次就发现 design.md 里“执行记录”和“检索结果”两个概念混用,AI 把检索结果当成了执行记录的子集,纠正后才对齐。
4.2 按 tasks 逐条执行
确认理解一致后,让 AI 按 tasks 执行:
按 tasks.md 的顺序执行 Task 1 到 Task 3, 每完成一条更新 tasks.md 的勾选状态, 遇到需要我决策的点先停下来问。Task 1 是生成目录骨架,Task 2 是接口类型定义,Task 3 是列表页组件。执行过程中 Claude Code 会调用 Read、Write、Bash 等工具。我在 settings.json 里放开了pnpm权限,所以它能自己跑pnpm tsc --noEmit做类型检查。
4.3 验证动作与结果记录
每条 task 完成后,我固定做三个验证动作,并把结果记进openspec/changes/add-scheduled-task/verify.md:
| 验证项 | 命令 | 通过标准 | 记录方式 |
|---|---|---|---|
| 类型检查 | pnpm tsc --noEmit | 零错误 | 贴退出码和错误数 |
| 单元测试 | pnpm vitest run src/services/task | 全绿 | 贴测试用例数 |
| 接口联调 | 通过 MCP 拉取接口文档比对字段 | 字段名、类型、必填项一致 | 贴比对差异表 |
这个记录方式是我踩过坑之后定下来的。之前只记“通过了”,结果三天后回归时完全想不起来当时验的是什么。现在每条记录都带命令和输出,回归时直接重跑即可。
4.4 成功结果
6 个接口的类型定义一次生成,tsc零错误。列表页组件生成后,字段名和接口文档完全一致,没有出现常见的taskNamevstask_name这种命名漂移。执行记录列表的检索过滤逻辑,AI 按 specs 里的边界条件(空结果、超长关键词、特殊字符)都做了处理。整个模块从规格加载到验证通过,人工指令不到 10 条。
5. 本篇常见错排查
5.1 MCP 启动失败:command not found
最常见的是npx找不到包。先确认 Node 版本 ≥ 18,再手动跑一次npx -y @your-org/api-docs-mcp看报错。如果是网络问题导致拉包超时,配好 npm 镜像源。还有一种情况是 MCP 的 env 变量没传进去,Claude Code 启动时不会自动读 shell 的 rc 文件,需要在启动前手动 export。
5.2 规格歧义导致 AI 脑补
表现是 AI 生成的代码“看起来对但不符合预期”。根因是 specs 里字段定义含糊,比如只写“状态字段”没写枚举值。排查方法:让 AI 复述它理解的规格,对比你的预期。修复方法:在 specs 里把枚举、必填、默认值全部写死。我现在的习惯是每个字段都写成表格,类型、必填、枚举、示例四列齐全。
5.3 权限配置过松或过严
过松的风险是 AI 执行了危险命令,过严的表现是 AI 频繁请求权限打断流程。我的经验是:读操作全放开,写操作按目录放开,危险命令(rm、push、force)一律 deny。如果 AI 频繁请求某个命令的权限,先想清楚这个命令是否真的需要,再决定加不加进 allow。
5.4 跨会话上下文丢失
Claude Code 的会话是独立的,新会话看不到之前的对话。SDD 的价值在这里体现:规格文件是持久化的上下文,新会话只要重新读openspec/目录就能恢复状态。如果发现 AI 在新会话里“失忆”,检查是不是没让它先读规格。
5.5 验证记录缺失导致回归困难
这是最隐蔽的坑。当时觉得“通过了就行”,一周后回归时完全不知道当时验了什么。修复方法就是上面那张验证表,每条 task 完成后强制记录命令和输出。记录文件本身也纳入版本管理,回归时直接 diff。
6. 边界用例:AI 在哪里会失效
跑完最小闭环后,我专门设计了几组边界用例来探能力边界。
第一组是“规格真空”:故意在 specs 里留一个没定义的字段,看 AI 怎么处理。结果是它自行填了一个“合理默认值”,功能正确但和团队约定不符。这说明规范文件是约束而非能力,留白的地方 AI 会脑补。
第二组是“信息孤岛”:让 AI 改一个依赖 CI 环境变量的构建配置。它在本地改对了,但 CI 上失败,因为它看不到 CI 的实际环境。这类问题的特征是“AI 每次分析都对,但解的都是当前暴露的那一层”。
第三组是“目标模糊”:输入“优化一下列表页”,看它会不会先澄清。结果是它直接改了组件结构,没有先问目标。这验证了 SDD 里 proposal 阶段强制写“Why”的必要性。
这三组用例的结论是:AI 的失效不是随机的,而是可归类的——规范真空、信息孤岛、目标模糊。对应的解法分别是补规范、前置环境差异、强制澄清目标。
7. 语义一致 CTA:按你的场景选入口
如果你卡在接入环节,比如 settings.json 报错、MCP 起不来、Key 鉴权失败,先去 API Keys 页面确认 Key 状态 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,再对照接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 逐项检查配置。
如果你想先验证模型在规格驱动下的表现,不想直接改本地项目,可以用模型对话入口 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 贴一段 specs 让它复述理解,确认对齐后再落到代码。
如果你打算长期用 Claude Code 跑 SDD 或 Agent 类任务,指令量大、会话长,建议看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,按项目维度管理额度,避免多项目混用导致排查困难。
最后补一个我踩过的坑:验证记录文件一定要和规格文件放在同一个变更目录下,回归时一起 diff。我一开始把 verify.md 放在项目根目录,结果变更多了之后完全对不上号,后来统一挪进openspec/changes/<变更名>/才理顺。