前言
前几天我看到一篇吐槽 spec-kit 的小评。作者说,自己前前后后被它浪费了 34M Token,最后还是把代码和 spec 全删了。删完之后越想越气,索性写了一篇文章,把这段经历完整复盘了一遍。
我看完之后,几乎全程都在点头。
如果你还没看过我之前那篇 《GLM-5官宣:Agentic Code时代来临,SDD为何反而更重要?》,建议先看一眼。那篇文章讲的是:在 Agentic Code 时代,SDD 为什么反而更重要;而今天这篇文章想讲的是另一面:错的不是 SDD,而是某些在强模型时代依然臃肿、低效、缺少 break 机制的工具实现。
因为这不是个例,我自己也踩过类似的坑。之前我用 spec-kit 折腾过 Node.js 全栈项目和 Java 项目,结果几乎一样:需求没更清楚,架构没更稳定,反而先生成了一大堆越来越长的 Markdown 文档。项目还没落地,docs 目录先失控了。
所以我现在的结论很明确:SDD 这个思想没有错,但 spec-kit 这类重型 SDD 工具,正在随着模型能力提升,越来越像累赘。
真正重要的从来不是“文档写了多少”,而是“文档能不能稳定约束模型,持续指导实现”。
效果展示:我现在只保留 4 份核心文档
我现在在 Codex 5.4 和 Claude Code 里的做法,已经收敛成了一个很轻的文档流:
AGENTS.md
docs/
specify.md
plan.md
task.md
它们各自只做一件事:
specify.md:需求、目标、验收标准plan.md:架构设计、边界、技术约束task.md:任务拆解、执行顺序、验证方式AGENTS.md:项目技术栈、开发原则、安全红线,以及总指挥规则
更关键的是,这 3 份 docs 里的文档不能各自漂着,必须在根目录的 AGENTS.md 里被显式挂载,写清楚它们的具体路径、各自用途,以及 Agent 在什么阶段必须回读哪一份。
这套流程的好处很直接:文档少了,但模型更听话了;约束变少了,但准确率反而更高了。
原因很简单,模型看到的是高信号上下文,不是被一堆仪式化文书糊脸。
spec-kit 为什么失败
如果只用一句话总结,我会说:
spec-kit 的问题不是太讲规范,而是它同时犯了“过度设计”和“设计缺失”两个错误。
1. 过度设计:它写得太多,反而把模型写傻了
spec-kit 的标准链路是 constitution、specify、plan、tasks、implement,每一步都有大量引导词、模板和 MUST 约束。
这在弱模型时代也许有意义,因为当时模型需要很多“扶手”。
但今天的问题是,像 Codex 5.4 这种模型,本身已经内化了不少软件工程常识。你再往它上下文里灌几大段文书、几十条 MUST、无数条边边角角的自然语言约束,本质上是在抢它的注意力。
结果就是:
- 需求被稀释
- 关键约束被淹没
- 实现时细节频繁丢失
- 模型开始在“写代码”和“回头对齐文书”之间来回抽搐
最典型的现象,就是明明要求它用 ORM,它偏要自己拼 SQL;明明说了不要乱关警告,它照样自信地把警告 suppress 掉;明明已经澄清过某条路径无效,它最后还是把第一轮幻觉出来的路径也实现了,再额外套一层兼容层。
这不是模型不聪明,而是上下文里无效噪音太多了。
2. 设计缺失:它没有真正的 break 机制
这才是更致命的问题。
spec-kit 的工作方式更像“追加”而不是“替换”。当你修改需求、澄清路径、删除假设时,它往往不会真正 break 旧方案,而是倾向于:
- 旧需求继续保留
- 新需求再叠一层
- 为两套逻辑做兼容
- 用补丁把系统越缝越厚
于是你会看到一种非常荒诞的状态:
- 前端还活在第一版幻觉需求里
- 后端已经切到了第二版澄清后的路径
- 中间再夹一层“兼容旧逻辑”的过渡代码
如果是单人项目,这种做法几乎是灾难。
因为单人项目最应该做的事情就是:一旦路线改了,就彻底 break,旧代码删掉,不留情面。
不需要兼容过去,不需要保留历史包袱,不需要给幻觉产物搭纪念碑。
3. 它把 LLM 当成了编译器,而不是概率模型
spec-kit 的很多引导词给人的感觉是:只要规则写得足够多,模型就一定会遵守。
但真实情况是,LLM 不是编译器,它不是把每一条规则都等权执行。上下文一长,它天然就更关注开头和结尾,更容易忽略中间。
那问题就来了:
当上下文超过几十 K,spec-kit 里那么多 MUST,到底还有多少真的在生效?
如果一套方法必须依赖海量规则文本才能成立,那它本身就已经很脆弱了。
4. 否定约束会在长上下文里失真
这是我现在越来越确认的一点:LLM 对否定指令的处理,天然不如正向约束稳定。
“不要 A” 这件事,在上下文很长、状态很乱的时候,很容易重新变成 A。
所以你会发现,spec-kit 生成的文档里经常会出现大量这种句子:
- 不要这个
- 不要那个
- 不要兼容旧逻辑
- 不要关闭警告
问题是,这些否定一旦在长上下文里失效,就会直接反噬成正向行为。
这也是为什么很多时候,最有效的写法不是“不要甲”,而是“只允许乙丙丁”。如果必须否定,那也最好写成“不要甲,改用乙”。
5. 工具脚本本身也不够稳
还有一个很现实的问题是,spec-kit 并不只是理念重,它连工具层也未必稳。
比如按编号管理 spec 和分支,本来是为了流程化,但如果脚本允许生成重复前缀,后续一整套流程就可能全部报错。更讽刺的是,脚本都已经坏了,模型还会硬着头皮继续往后跑,最后把整个状态带得更乱。
这类问题说明了一件事:
重流程工具最大的风险,不是某一步没价值,而是只要某个节点坏了,后面所有阶段都会被污染。
SDD 思想没错,错的是重型 SDD 工具错位了
这里一定要分清一件事:
我批评的不是 SDD,而是 spec-kit 这种“把 SDD 过度工具化、过度文书化”的实现方式。
Spec-Driven Development 的核心思想其实很朴素:
- 先有需求
- 再有设计
- 再有计划
- 最后才进入 coding
这一点我现在比以前更认同。
因为没有需求文档、没有设计边界、没有任务计划,直接让 Agent 开写,本质上就是巧妇难为无米之炊。模型再强,也只能在缺失约束的情况下靠猜。
所以真正该被保留的是:
- 需求先行
- 设计先行
- 任务拆解先行
- 再让 Agent 执行
真正该被删除的是:
- 过长的模板
- 低信息密度的阶段文书
- 修改需求时只追加不替换的机制
- 一堆看似专业、实则污染上下文的流程噪音
我现在在 Codex 和 Claude Code 里怎么做
我后来慢慢把工作流收敛成一套更轻的实践。
全局 AGENTS.md / CLAUDE.md,本质上就相当于全局 constitution。
项目内的 docs/specify.md、docs/plan.md、docs/task.md,分别承担需求、设计、任务拆解的职责。
最后再用根目录下一个很克制的 AGENTS.md/CLAUDE.md 去做总指挥。这个总指挥文件里,不只是写原则和分工,还要把 docs/specify.md、docs/plan.md、docs/task.md 明确挂进去,告诉 Agent:
- 这些文档的具体路径是什么
- 每份文档分别负责什么
- 进入需求、设计、执行阶段时必须先看哪一份
specify.md:只写需求主体,不写世界补集
这里最重要的是正向定义:
- 要做什么
- 为谁做
- 成功标准是什么
- 明确不做哪些大项
我现在会非常克制地写“不要什么”,尽量把约束改写成“只允许什么”。
plan.md:只保留会影响实现的设计
这一层不要写成论文。
如果 AGENTS.md 或 CLAUDE.md 里已经写清楚了全局技术栈约束,plan.md 就不要再重复抄一遍。它更适合只写这次实现真正会用到的设计决策和特例约束。
只保留这些内容就够了:
- 模块边界
- 数据流
- 这次功能特有的实现选择
- 参考实现来源
- 明确必须 break 的地方
尤其是“必须 break 的地方”要单独写清楚。只要新路径确认了,旧路径就删,不要追加兼容层。
task.md:任务一定要拆到 Agent 能稳定执行
任务不能只写“完成后端开发”这种大词。
更有效的是这种粒度:
- 修改哪些文件
- 增加哪些接口
- 跑哪些验证命令
- 完成的判定标准是什么
任务拆得越清楚,模型越不容易边写边歪。
AGENTS.md:越短越好,越准越好
AGENTS.md 绝对不能写成长篇背景介绍。
它只应该放高信号内容:
- 项目技术栈和基础约束
- 安全红线
- 开发原则,比如单一职责、开闭原则这类思想约束
docs/specify.md、docs/plan.md、docs/task.md的具体路径和用途说明- 谁负责什么
- 哪些目录谁能改
- 什么时候允许并行
- 哪些情况必须停下来汇报
- 哪些旧逻辑必须直接删除
AGENTS.md 不是第二份需求文档,而是把全局原则和 3 份核心文档串起来的调度中枢。
Superpowers 组合 Skills 的最佳工程实践
我现在更多是在 Codex 或 Claude Code 里被动触发 superpowers skills,而不是主动去堆一条很长的神圣流程。
我的建议是,组合 skills 时遵守 5 条原则。
1. 流程 skill 先于实现 skill
推荐顺序:
brainstorming → writing-plans → subagent-driven-development / dispatching-parallel-agents → requesting-code-review
等主流程稳定了,再接具体领域 skill,比如前端接 frontend-design,Java 接 spring-boot-engineer。
别一上来就让实现 skill 抢跑。
2. 一个阶段只维护一个主文档
需求阶段只改 specify.md,设计阶段只改 plan.md,任务阶段只改 task.md。
不要让每个 skill 再各自产一份新文档,否则很快就会出现多个事实源。
3. 强模型做判断,普通模型做执行
强模型更适合:
- 需求澄清
- 架构收敛
- Code Review
普通模型更适合:
- 机械实现
- 补测试
- 跑验证
这比所有事情都让一个大模型全程硬扛更稳。
4. 必须有 Review Gate
真正的工程护栏不是文档厚度,而是检查点。
至少要有两个 gate:
- 这次实现是否符合当前 spec
- 这次代码质量是否过关
先过 spec gate,再过质量 gate,不然很容易做出一坨“写得挺努力但方向错了”的代码。
5. 被动触发优于手动堆叠
现在模型已经足够强了,很多流程 skill 不需要你每次手工点名全叫一遍。
只要你的文档结构清晰、上下文干净、边界明确,它自然会在该触发的时候触发。
成熟工作流的标志,不是步骤很多,而是步骤很少,但每一步都有效。
总结:重型 spec-kit 会过时,但轻量 SDD 不会
我现在越来越相信一件事:
随着 AI 模型继续迭代,spec-kit 这种重型 SDD 工具只会越来越显得笨重,但 SDD 本身不会过时。
因为软件开发永远需要:
- 把需求说清楚
- 把边界定下来
- 把计划拆出来
- 再把执行交给模型
变的不是这个顺序。
变的是承载这个顺序的工具,必须越来越轻,越来越短,越来越高信号。
所以我现在的立场很明确:
要 SDD,不要文档崇拜。要约束,不要仪式。要 break,不要兼容幻觉。
这可能才是强模型时代更靠谱的 AI 工程化。
引用链接
本文部分观点参考了以下资料,并结合了我自己的实际使用体验:
spec-kit 官方仓库: github.com/github/spec…
superpowers 官方仓库: github.com/obra/superp…
知乎原文: zhuanlan.zhihu.com/p/198354567…
欢迎关注公众号 FishTech Notes,一块交流使用心得!