我最近在补 agent-spec + no-mistakes,这一路把 AI 编码从玄学补到了流水线
这事不是从“我要搞工程化”开始的,是我被 AI 和 CI 轮流收拾烦了
我一开始真没想那么大。
最早就是一段很普通的活。仓库里有个流程要收口,接口行为不能飘,异常路径得补,最好还能顺手把提交前的校验接一接。按理说这活挺适合让 AI 先干一轮,我只要收尾就行。
我当时也是这么想的。
第一轮看着还真行。代码动了,测试也补了,注释写得比我自己还整齐。我差点就准备往下推了。
再看两眼,后背开始发凉。
AI 把“收口”理解成了“顺便再帮你理一理”,多改了不该动的地方。最烦的不是它直接爆红,而是它长得像没问题。你打开 diff,会觉得这人还挺懂;你跑一遍 happy path,也不一定炸;你真让它进 PR,才会发现脏东西混得挺自然。
这种翻车最恶心的地方就在这儿。
不是它写不出来。
不是它一眼假。
是它七分像,三分悬。
你明知道哪儿不太对,又没法在第一秒把它钉死。最后只能靠自己一段一段扒,一条一条试,整个人像在给一个很会说话的实习生擦屁股。
我那阵子真有点烦透了。
我先怪模型,怪着怪着发现锅不在模型身上
我第一反应挺标准的。
先怪模型不够强。
再怪上下文没喂够。
再怪 prompt 写得不够狠。
最后连“要不要套个 agent 让它先 review 自己”这种路子我都想过。
写提示词的时候我也不是没下功夫。
我会写:
- 不要改无关文件
- 保持兼容
- 补测试
- 输出前自检
- 不要影响已有接口
写得跟立军令状似的。
结果还是不稳。
后面我才承认一个不太舒服的事实:这些话大半只是愿望,不是契约。AI 看到了,也可能理解了,但你没法稳定验证它到底做到哪一步,更没法在它跑偏的时候第一时间把它拦下来。
卡到这里,我脑子里那根筋才拧过来。
问题根本不只是“AI 怎么写代码”。
问题是“我到底给了它什么任务”,以及“它写完以后,到底谁来证明它真写对了”。
这两件事没立住,模型再强也容易写成玄学。
我第一次看 agent-spec,心里挺不屑的
说实话,第一次看到agent-spec这个名字,我脑子里冒出来的话不太好听。
我当时想的是:
这不就是把需求文档再换个格式写一遍吗?
因为太像了。
有spec,有结构,有规则,一眼看上去就容易被误判成“规范化写 prompt 的工具”。
我一开始就是这么看它的。
再往下摸才发现,方向完全不是那么回事。
它盯的不是 prompt 漂不漂亮。
它盯的是 AI 下场写代码之前,那层一直被大家糊过去的东西:
- 这次到底要干什么
- 哪些技术决定已经拍板
- 哪些地方能动,哪些地方别碰
- 什么行为算完成
到这时我才反应过来,agent-spec想补的不是写作层,是编译层。
以前我给 AI 的输入,大半是 PRD、Issue、群聊、口头补充、临时共识。信息不是没有,是太散,散到最后全变成一句潜台词:
“你应该懂我意思吧。”
AI 最会在这种地方出事。
它不是完全不懂。
它是懂一半,补一半,剩下一半靠猜。
agent-spec干的事就一句话:
先别让它猜。
真落到手上,我先被 Task Contract 这玩意儿狠狠干老实了
我前面一直把“需求写清楚”理解成一件挺主观的事。
直到我真开始写 Task Contract。
第一脚就摔了。
我按普通 Markdown 的习惯写,标题先来,元信息跟上,想着差不多就行。结果lint直接不认。那会儿我还不服,心想格式问题能有多难,补两条横线不就完了。
结果补完照样不认。
我又去对模板、看生成结果、盯解析逻辑,来回折腾了几轮,才发现这东西不是“像 YAML 就行”,它就是一套自己的 DSL。字段怎么写,分隔线放哪儿,开头能不能先来个大标题,它都认得死死的。
这回把我心态直接掰正了。
因为它不是在帮我排版。
它是在逼我别糊弄。
后面还有一脚更逗。
我写场景的时候,顺手写了“假设 / 当 / 则”。我脑子里完全没问题,中文读着也顺。结果lint还是挑刺,说我的场景 shape 不完整。
我当时第一反应是:
不是,我结果都写了,你还想怎样?
回头再看才懂,它对关键字就是硬匹配。你写则,它不当Then。中文场景里,它认的是那么。
这事看着细,打我打得挺疼。
因为它把一个我之前一直模模糊糊知道、但没认真承认的事钉死了:
需求不光要让人看懂,还得让机器稳定看懂。
这句话一旦真吃进去,Task Contract 的味道就完全变了。
它不再是“我整理了一份文档”。
它更像“我先把这次任务压成一块硬东西,再把 AI 放进来干活”。
又试了几轮,我才反应过来它真正管的是题目
我现在回头看,agent-spec最值钱的不是命令多,也不是概念新。
它值钱的地方很土,但很硬。
它逼我先把一团散装需求压成四块:
Intent说清这次到底干什么Decisions把已经定死的技术选择锁住Boundaries提前讲明白哪里能动、哪里是红线Completion Criteria把“完成”落成场景,不再靠感觉
我前面一直想把 AI 训练成一个靠谱执行者。后面发现想快了。
题目都没压实,执行者再靠谱也得靠猜。
这也是我对agent-spec彻底改观的地方。
它不负责让 AI 更聪明。
它负责让题目别那么飘。
再往后跑,我才慢慢把这条链走顺
前面我有个误判,老把agent-spec当成“先建个契约文件”的辅助工具。
真跑过一遍以后才明白,它好用不是因为单个命令多猛,是因为你会被它一步步逼到一个没法偷懒的位置。
我第一次真照着走,是先敲了个init,把任务骨架起出来。那一下最明显的感觉不是“模板生成了”,而是我没法继续装糊涂了。目标写不写得明白,哪些技术决定已经拍板,哪些地方能动、哪些地方别碰,全得先摊开。
骨架一出来,我本来还想直接塞给 AI。手都伸过去了,又停住了,先跑了个lint。这步后来成了我的固定动作,因为人刚写完需求时特别容易自我感觉良好,读着顺、看着全,脑子里已经开始自动脑补“差不多了吧”。lint一下来,模糊动词、缺失场景、格式乱写、验证入口没绑,基本藏不住。
前面我还老跳contract,总觉得这一步有点像多余展示。真挨过几次打以后,我不跳了。把契约渲染出来看一眼,特别像把脑子里的散装要求摊平在桌上。只要这里还虚,后面不管喂给 AI 还是喂给人,都是继续碰运气。
再往后我才慢慢把plan这步看重。前面我一直很乐观,觉得仓库都在这儿了,AI 自己看呗。真被它教育过几轮以后,这种乐观基本没了。plan好用的地方,不是“又多跑了个命令”,而是它把契约、代码上下文、实施顺序一起压出来。到这时候,AI 更像接到一张施工单,不像抱着一份抽象要求在那儿猜。
等 AI 真改完,我现在第一反应也不是先打开 diff 感动自己,而是直接跑lifecycle。这步我已经当主验收口看了。以前所谓“完成”,经常只是 AI 说完成了、我看着像完成了、本地随手点几下没炸。现在不行,lifecycle没过,就是没过。
最后才是guard。前面我第一次看到它的时候,还觉得这是不是有点太严了。后面仓库里一旦变成多人并行、多个 agent 一起改,才知道这玩意儿不是在装严格,它是在替你守门。单任务我盯lifecycle,整仓改动我看guard,这样整个节奏才算真立住。
写到这里我才发现,最难删掉的其实是那些空话
我前面老把“写契约”理解成一种格式劳动。
后面发现根本不是。
真正难的地方,是它逼你把平时最爱说的那些空话全扔掉。
比如这种句子:
- 把流程理顺
- 补一补异常处理
- 尽量保持兼容
- 顺手清理代码
这些话人都爱说,AI 也最容易顺着这种话开始自由发挥。
一旦你真把它写进 Task Contract,就会发现这几句几乎都不够用。
因为它们根本没回答最关键的东西:
- 兼容到哪一层
- 哪个返回结构不能动
- 哪条行为必须有测试证明
- 哪些文件哪怕手痒也别碰
我后面真正开始顺手,是在我肯承认一件很尴尬的事以后:
不是 AI 总把需求理解歪。
有时候是我给它的东西,本来就不够硬。
再看 no-mistakes,我才明白它堵的是出口
我前面还犯过另一个误判。
我以为前面契约写实了,后面差不多就能稳住。
结果不是。
契约解决的是“这次到底让 AI 干什么”。no-mistakes解决的是“它干完以后,这堆改动有没有资格继续往前走”。
这俩东西根本不是一个层面。
我现在不会拿它们互相替代,我会把它们一前一后摆好:
agent-spec在前面卡题目、边界、验证条件no-mistakes在后面卡推送校验、CI 预检、PR 整洁度
这个分工一旦想通,很多纠结会自己消失。
需求没压实,门禁拦不住“认真做错题”。
门禁不够硬,契约也挡不住“脏改动混进来”。
我更愿意把no-mistakes放在三个口子上:
本地准备推送前,先把明显脏改动拦住。
CI 里再做一层预检,别让主分支替我试错。
PR 准备发出去的时候,再确认这次改动值不值得让别人 review。
这样一来,AI 写码就不是“写完了,大家来祈祷”,而是“先过契约,再过门禁,最后才轮到人看”。
这句顺序一改,整件事的气质都变了。
直到这两头接上,我才第一次觉得它像工程
我前面一直在找那个感觉。
什么叫 AI 真进工程流程了?
不是聊天窗口里回得多快。
不是一口气吐多少代码。
也不是“它居然懂这个框架”。
我现在认的那条线是这样的:
先把 PRD、Issue、口头补充要求压成 requirements。
再把 requirements 压成 Task Contract。
AI 按契约去实现。agent-spec用lint、plan、lifecycle、guard去验。no-mistakes再把推送、CI、PR 那几个出口堵住。
这条线一摆出来,我前面为什么老翻车就很好解释了。
我老是把前两步省了,直接把需求和代码焊在一起,中间全靠模型脑补。写顺的时候像开挂,写歪的时候像开盲盒。
现在多出来的那几层,看着麻烦,实际上是在替整条链降噪。
AI 还是会写错。
需求还是会写歪。
命令还是会跑崩。
但这些错开始有地方接住,不再全压在“人最后看一眼”上。
再学下去,我准备把知识这层也顺手补上
前面我一直把agent-spec当任务级工具看。
看到explain、wiki、图和架构视图以后,我才反应过来,它补的还有另一种老毛病:知识总是散。
一个需求做完,最烦的不是代码本身,是过两周以后你再回来看,很多东西又要重新猜:
为什么当时要这么改。
哪条行为到底被哪个场景证明过。
哪块边界是刻意定下来的,哪块只是碰巧现在能跑。
这种时候,wiki和解释视图就不是装饰品了。
我前面挺烦“写完代码还得补知识资产”这件事。
后面想开了,反正最后都得补,那不如在任务还热的时候,把这些骨架顺手搭起来。
这轮学下来,我脑子里先记住的是这几个坑
这轮折腾完,我脑子里已经有一套很现实的排查顺序了。
如果一开始就跑不起来,我先看 Cargo 环境和工具本体是不是装好。
如果lint一上来就骂,我先看 front-matter、字段名、场景关键字,是不是又拿普通 Markdown 的脑回路在写契约。
如果场景写着写着发虚,我先看Completion Criteria到底有没有真绑到可验证行为。
如果guard把改动拦在门外,我先查是不是边界没写死,或者 staged/worktree 混进了不该动的东西。
如果no-mistakes在推送前后继续拦,我就默认它不是在找我麻烦,而是在替我挡一次本来会进 PR 的事故。
还有一件事我现在也想得很清楚。
不是所有活都值得上这整套。
改个文案、调个样式、重命名几个变量,用这套确实有点重。
但接口兼容、CLI 输出、协议行为、rewrite、迁移、parity 这种活,我后面会优先上。再往上走到多 agent 协作、多人并行改仓库,这套东西只会更值钱。
下次再碰到这种任务,我第一眼不会先盯模型版本,也不会先想着把 prompt 再写狠一点。
我会先看两件事:
- 这次任务有没有被写成真正能验的契约
- 这次改动进仓库之前,有没有硬门替我拦住侥幸
这两个口子不堵,AI 写得再花都不算稳。
这两个口子堵住了,模型就算没那么神,活也终于更像工程。
你们现在让 AI 改代码,最容易翻车的地方是在题目这头,还是在提交、CI、PR 这头?我现在回头看,后面这半截脏流水线带来的坑,真不比模型乱写少。