1. 从 Vibe Coding 到 SDD:我为什么把写代码的时间挪去写规范
先说结论:Vibe Coding 不是不能用,而是它在项目复杂度超过某个阈值之后,会以"上下文丢失、架构漂移、幻觉难排查"三种方式反噬你。我最近在一个用户行为分析后台项目上做了三次对照实验——手搓 SDD、OpenSpec、Superpowers,基准是纯人工 5 天工时,最终最快压到 2.5 天,提效约 50%。但比数字更值钱的是:AI 在规范约束下没有写出任何跨库 JOIN、没有在 Controller 里塞业务逻辑、全局异常处理器一次生成即符合要求。
SDD(Spec-Driven Development,规范驱动开发)是什么?一句话:代码不再是一等公民,规范才是,代码只是规范的衍生品。它适合谁?适合那些已经用 Claude Code、Cline、Codex 写了不少代码,但发现"AI 越写越乱、Review 越来越累"的中等规模项目开发者。如果你只是写个脚本、改个工具函数,Vibe Coding 完全够用,不必上这套。
Vibe Coding 的三个真实痛点,我在项目里都踩到了。第一,上下文易丢失:项目有几十个文件,AI 写着写着就"忘记"前置条件,前面定的 DTO 命名规范到第三个接口就变了。第二,架构规范难约束:团队约定禁止跨库事务、禁止在 Controller 写业务逻辑,但 AI 不会主动遵守,它只对当前对话负责。第三,幻觉频发且难排查:来回对话让 AI 猜意图,生成的代码带隐蔽 Bug,人工排查成本比手写还高。
SDD 把开发流向从"需求 → 直接撸代码 → 人工修 Bug"改成"需求 → 写规范(人工主导)→ AI 按规范生成 → 人工 Review"。开发者的角色从"代码打字员"变成"系统架构设计者 + Reviewer"。这篇文章我会把三种路径的配置片段、规格模板、任务拆解、验收清单全部摊开,并且演示怎么用 TaoToken 统一 Key 和 API 通道接入,避免在多个工具之间反复切换密钥。
我试过的最直观感受是:写规范那半天很"不程序员",但它把后面两天的返工全吃掉了。下面按"问题场景 → TaoToken 前置 → 可复制配置 → 验证 → 排错 → 选型"的顺序展开,你可以直接照着做。
2. TaoToken 前置:统一 Key 与 API 通道,别让密钥管理拖慢 SDD 节奏
SDD 工作流有个容易被忽略的摩擦点:你会同时用 Claude Code 做生成、用 OpenSpec CLI 做状态机、用 Superpowers 的 subagent 做并行执行,如果每个工具都单独配一套密钥和 Base URL,切换成本会吃掉提效收益。我的做法是用 TaoToken 作为统一通道,一个 Key、一个 Base URL 打通所有工具。
TaoToken 是什么、能做什么:它是一个统一的模型 API 接入层,提供兼容主流协议的统一入口,你可以在控制台创建 API Key,然后在 Claude Code、Cline、Codex 等工具里填同一套 Base URL + Key + Model ID。适合谁:需要多工具协作、又不想为每个工具单独维护密钥和额度的开发者。官网入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 根地址是 https://taotoken.net/api (这个不加 UTM,配置里就填它)。
具体操作分三步。第一步,打开控制台创建 Key:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,在 API Keys 页面新建一个密钥,命名建议带上用途,比如 sdd-claude-code,方便后面按项目区分。第二步,如果你要长期跑编码和 Agent 任务,去 Coding Plan 页面看套餐:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,按量或包周期都行,先小额度试跑再放大。第三步,把 Key 写进环境变量,别硬编码进仓库:
# ~/.zshrc 或 ~/.bashrc
export TAOTOKEN_API_KEY="sk-你的密钥"
export TAOTOKEN_BASE_URL="https://taotoken.net/api"
这里有个关键点:SDD 的规范文件(CLAUDE.md、openspec/config.yaml、docs/superpowers/)会进 Git,但密钥绝对不能进。用环境变量 + 工具自身的配置文件引用变量,是最稳的做法。我踩过的坑是早期把 Key 直接写进 settings.json 提交了,虽然及时撤销,但这类事故完全可以用环境变量避免。
模型选择上,SDD 的"写规范"阶段建议用推理能力强的模型,因为你要它理解架构约束、写出 WHEN/THEN 场景;"按模板施工"阶段可以用更快的模型,因为 Superpowers 的计划文件已经把代码模板给全了,AI 只需要照抄加验证。TaoToken 的模型对话入口可以先用小样本试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,把一段 CLAUDE.md 丢进去问"这条约束你会怎么落地",能快速判断模型是否吃透了规范。
接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面有各工具的 Base URL 填法。记住三件套的固定格式:Base URL 填 https://taotoken.net/api,Key 填你创建的那串,Model ID 填控制台里对应模型的标识。这三样在 Claude Code、Cline、Codex 里是同一套,不用改。
3. 可复制配置:Claude Code settings、OpenSpec config.yaml 与 Superpowers 计划模板
这一节是全文最"能抄"的部分。我把三种路径的配置文件原样贴出来,路径和字段名都和我项目里一致,你改改项目名就能用。
3.1 Claude Code 的 settings.json 接入片段
Claude Code 读取项目级或用户级 settings。我用项目级 .claude/settings.json,把 Base URL 和 Key 通过环境变量注入:
{
"env": {
"ANTHROPIC_BASE_URL": "https://taotoken.net/api",
"ANTHROPIC_AUTH_TOKEN": "${TAOTOKEN_API_KEY}",
"ANTHROPIC_MODEL": "你的模型ID"
},
"permissions": {
"allow": ["Bash(mvn test:*)", "Bash(git commit:*)"]
}
}
注意 ANTHROPIC_AUTH_TOKEN 引用的是环境变量,不是明文。permissions.allow 里我放行了 mvn test 和 git commit,因为 Superpowers 的 TDD 循环要反复跑测试和提交,每次弹确认会打断节奏。Model ID 去控制台查,别照抄别人的。
3.2 OpenSpec 的 config.yaml
OpenSpec 初始化后在 openspec/config.yaml 里配置 schema、项目上下文和 per-artifact 规则:
schema: spec-driven
context: |
Tech stack: Spring Boot 2.x, MyBatis Plus 3.5
多数据源:user-db (MySQL) / biz-db (业务数据库)
禁止跨库事务,Service 层内存合并
禁止在 Controller 写业务逻辑
rules:
tasks:
- 每个任务不超过 30 分钟工作量
- 验证类任务必须列明验证标准
context 这段会被 CLI 透传给每个工件的生成指令,等于给 AI 的"项目宪法"。rules.tasks 是 per-artifact 的,比全局约束更精准,因为它在生成 tasks.md 时专门注入。
3.3 Superpowers 的计划文件头部
Superpowers 的计划文件放在 docs/superpowers/plans/,头部要声明执行方式,否则 subagent 不知道怎么跑:
> For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
> (recommended) or superpowers:executing-plans to implement this plan task-by-task.
> Steps use checkbox (- [ ]) syntax for tracking.
- [ ] Step 1:创建 failing test(完整测试代码,此时实现类不存在)
- [ ] Step 2:运行测试 → 确认 RED(mvn test -Dtest=XxxTest)
- [ ] Step 3:创建实现代码(完整 Java 文件,含注解、方法签名、逻辑)
- [ ] Step N-1:运行测试 → 确认 GREEN
- [ ] Step N:Commit(指定 commit message 格式)
3.4 手搓 SDD 的 CLAUDE.md 核心约束
手搓路径最关键的是项目根目录的 CLAUDE.md,我列了 12 节,这里摘最要命的两节:
## 四、多数据源规范
| 数据源标识 | 数据库 | 用途 |
|------------|--------|------|
| user-db | MySQL | 用户认证、账户数据 |
| biz-db | 业务库 | 行为事件、业务数据 |
跨库查询禁止在同一个事务中混用两个数据源。
如果业务需要聚合两个库的数据,在 Service 层分别调用各自数据源的 Service,在内存中合并结果。
## 五、异常处理
错误码分段规则、GlobalExceptionHandler 的三类拦截要求:
业务异常 → HTTP 200 + 业务错误码;参数校验失败 → HTTP 400;未预期异常 → HTTP 500 且不暴露堆栈。
这三套配置的共同点是:把"AI 不该自由发挥的地方"写成机器可读的约束。手搓靠 CLAUDE.md 全局约束,OpenSpec 靠 config.yaml + 四层工件,Superpowers 靠计划文件里的完整代码模板。约束越往下越细,AI 执行阶段的自由度越小,但规范编写投入越大。
4. 验证请求与成功结果:从规格模板到 mvn test GREEN 的完整链路
配置写完不算数,得验证 AI 真的按规范产出。我用一个"数据大盘"接口做端到端验证,链路是:Feature Spec → AI 生成 → Code Review → 单元测试 → 接口实测。
4.1 规格模板:高内聚的 Feature Spec
手搓 SDD 的 Feature Spec 要把 PRD 业务规则和 SQL 逻辑融合在一份文件里,别让 AI 拿到割裂的片段:
# Feature Spec: 数据大盘 (Dashboard)
## 1. Context
帮助运营团队追踪核心 OKR 达成情况,指标下滑时快速定位根因。
## 2. Requirements
- 主 KPI:期间活跃用户数、期间转化任务数
- 漏斗模块:注册/搜索/浏览结果/发起转化/持续跟进 五步用户数
## 3. Data & Logic
> API 读取数据源:所有统计类 API 读取预聚合统计表 stats_daily,不直查源表。
SELECT SUM(active_user_count) AS active_user_count,
SUM(conversion_task_count) AS conversion_task_count
FROM stats_daily
WHERE stat_date >= #{startDate} AND stat_date < #{endDate};
## 4. Constraints
1. API 层所有查询均走 @DS("biz-db") 的统计表,单库读取,无跨库操作
2. 漏斗数据需返回 List,若统计表中某天数据缺失,Service 层补 0 返回
注意第 4 节第 2 条——"数据缺失补 0 还是跳过"这种边界,必须在 Spec 阶段定死,否则 AI 生成的行为是随机的。这就是 SDD 和 Vibe Coding 的本质区别:把决策前置。
4.2 验收清单
我给自己列了一份可勾选的验收清单,每次 AI 生成后逐项过:
- [ ] Controller 无业务逻辑,只做参数校验和 Service 调用
- [ ] SQL 使用 #{} 占位符,无 ${} 拼接
- [ ] 多数据源路由注解在正确层级(Mapper 层 vs Service 层)
- [ ] 全局异常处理器覆盖业务/校验/未预期三类
- [ ] 单元测试首次运行 GREEN
- [ ] 接口返回结构与 Spec 中 DTO 字段一致
4.3 验证请求与成功结果
Superpowers 路径下,验证是自动化的。计划文件里每个 Task 内嵌 TDD 红绿循环,执行时跑:
mvn test -Dtest=DashboardServiceTest
成功结果是 Tests run: 8, Failures: 0, Errors: 0, Skipped: 0,然后 git commit 对应 Task。我项目里最终的提交序列是这样的:
feat: add BizAuthInterceptor and extend MapperScan
feat: add ETL mapper layer (EtlBizMapper, EtlUserMapper)
feat: add DailyStatsService + DailyStatsJob
feat: add StatsQueryMapper with all stats queries
feat: add Dashboard API (GET /api/biz/dashboard/kpi and /funnel)
每个 commit 对应计划里一个 Task,且都通过了对应单元测试。接口层实测用 curl 验证返回结构:
curl -s "http://localhost:8080/api/biz/dashboard/kpi?startDate=2024-01-01&endDate=2024-01-31" \
-H "Authorization: Bearer test-token"
成功返回是统一响应格式 {"code":0,"data":{"activeUserCount":1234,"conversionTaskCount":56},"msg":"ok"},字段名和 Spec 里 DTO 完全对齐。这一步能过,说明从规范到代码的链路是通的。
OpenSpec 路径的验证靠 openspec status --change "<name>" --json 看工件依赖图和进度,openspec instructions apply --json 返回剩余任务列表,CLI 解析 tasks.md 里的 checkbox 计算进度,AI 不会重复实现已完成任务。手搓路径则靠人工 Code Review 对照验收清单,主观但快。
5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth 报错
这一节按真实报错来,都是我或身边人踩过的。
5.1 401 Unauthorized
最常见。原因通常是 Key 没生效或 Base URL 填错。排查顺序:先确认环境变量 echo $TAOTOKEN_API_KEY 有值;再确认 settings.json 里 ANTHROPIC_AUTH_TOKEN 引用的是变量名而不是字面量 ${TAOTOKEN_API_KEY} 被当字符串;最后确认 Base URL 是 https://taotoken.net/api,别多写 /v1 或少写协议头。三件套(Base URL + Key + Model ID)任何一项错都会 401 或 404。
5.2 local proxy failed
这个报错通常出现在工具尝试走本地代理但代理没起。先检查你的环境里有没有残留的 HTTP_PROXY/HTTPS_PROXY 变量,env | grep -i proxy 看一眼,有就 unset 掉。然后确认工具配置里没有指向 127.0.0.1:xxxx 的代理地址。TaoToken 是直连 API 通道,不需要本地代理,配置里把代理项清空即可。
5.3 reading choices 报错
典型是响应结构解析失败,常见于模型返回了非预期格式(比如被网关拦截返回 HTML)。排查:用 curl 直接打一次 API 看原始响应:
curl -s https://taotoken.net/api/v1/messages \
-H "Authorization: Bearer $TAOTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"你的模型ID","max_tokens":64,"messages":[{"role":"user","content":"ping"}]}'
如果返回 HTML 或错误 JSON,说明 Key/模型 ID 有问题;如果返回正常 JSON 但工具仍报 reading choices,那是工具版本和协议不匹配,升级工具或换兼容模式。
5.4 OAuth 相关报错
Claude Code 某些版本会走 OAuth 流程,如果你用 API Key 接入却触发了 OAuth 校验,会报 token 无效。解决:确认 settings.json 里用的是 ANTHROPIC_AUTH_TOKEN 而非 OAuth 的 token 字段,并在启动时显式指定 API Key 模式。Codex 的 auth.json 路径也要注意,Key 要写在对应字段里,别和 OAuth 字段混用。
5.5 OpenSpec 工作流被绕过
不是报错但更隐蔽:Claude 没写完 proposal 就直接写 design,或没跑完 tasks 就归档。解法是在 CLAUDE.md 里加硬约束:
## 工作流约束(最高优先级)
- 禁止在没有对应 tasks.md checkbox 的情况下编写实现代码
- 任何功能实现前,必须确认 openspec/changes/<name>/tasks.md 存在且相关任务为 - [ ]
- 完成任务后必须立即将 tasks.md 中对应项从 - [ ] 改为 - [x]
再把 tasks 粒度做细,"实现 service 层"这种模糊任务会被一口气做完,改成"创建 DailyStatsService.java,只包含方法签名,不实现方法体"就强制分步确认。根本解法还是人工把控节奏:propose 完成后明确说"我确认了,开始实现",别一句"帮我做完整个流程"。
6. 三工具选型与 CTA:按项目复杂度选路径,用统一通道收尾
三种路径的对比我整理成一张表,你按自己项目对号入座:
| 维度 | 手搓 SDD | OpenSpec | Superpowers |
|---|---|---|---|
| 上手成本 | 极低,零工具依赖 | 中等,需学 CLI + 工件结构 | 中等,需熟悉 Skill 体系 |
| 规范投入 | 低(CLAUDE.md + Feature Spec) | 中(4 层工件 × 变更数) | 高(1 设计文档 + 1 大型计划) |
| 决策可追溯 | 差(散落聊天记录) | 优(每变更独立 design.md) | 中(有决策无显式 rationale) |
| 执行速度 | 中(人工交互驱动) | 中(人工分步确认) | 快(subagent 并行 + 代码模板) |
| 质量验证 | 主观 Code Review | 对照 WHEN/THEN spec | 自动化测试(mvn test) |
| 适用场景 | 快速验证 / 熟悉域 | 多人协作 / 长期维护 | 需求清晰 / 快速交付 |
选型建议很直接:首次尝试 SDD 想快速感受价值,选手搓 SDD;需求不确定、多人协作、重长期维护,选 OpenSpec;需求清晰、设计经验丰富、追求执行效率,选 Superpowers;想兼顾决策治理与执行效率,用 OpenSpec 梳理 design.md,再把内容作为 Superpowers 设计文档的输入,两者结合比单用任何一个都稳。
四条核心结论,我按重要性排:第一,规范文件的本质是降低 AI 决策负担,越往下走 AI 自由度越小、确定性越高,但没有最好的方式,只有匹配项目复杂度的方式。第二,Superpowers 顺畅的代价是设计阶段要求极高精准性,一个字段语义歧义就导致 ETL SQL 返工,不熟悉的业务域先用 OpenSpec 梳理决策更稳。第三,SDD 的核心价值不只是提速,而是提升代码质量的下限——没有跨库 JOIN、没有 Controller 业务逻辑、没有 SQL 注入、异常处理器一次成型。第四,开发者角色从"写代码"转向"定义规范",最花时间的部分是把隐性架构意图显式化。
最后落到工具链收尾。无论你选哪条路径,密钥和通道管理都建议统一:去 API Keys 页面创建你的 Key(https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ),按接入文档把 Base URL 填成 https://taotoken.net/api(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ),长期跑编码和 Agent 任务就去 Coding Plan 看套餐(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= )。先用模型对话入口小样本验证模型是否吃透你的 CLAUDE.md(https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ),确认没问题再放大到整个 SDD 工作流。Claude Code 的接入细节在文档里有专门章节(https://taotoken.net/doc/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ),照着填三件套即可。



被折叠的 条评论
为什么被折叠?



