返回文章

澄清阶段:先把“完成”写成一份可数的清单

这是五阶段系列的第一篇。前面五篇是五层约束——语言层 、样式层、状态层、工程层、美学层——讲代码往哪写;从这篇起讲五个阶段,管一件事怎么从一句话走到交付。母篇是《从能跑到可交付:一套前端 AI 协作系统的设计笔记 》。我用的系统是开源的 frontend-harness-cli ,文中所有规则都能在仓库里找到对应实现。

一句“把首页做完”

先看一个具体的场景。

你对 AI 说:把待办应用的首页做完。它干了六个小时,交出一个相当完整的页面:顶部有横幅,中间有统计卡片,列表带筛选和搜索,空状态还配了插画。

你要的其实只有一件事:打开页面,输入框里打字,回车,一条待办出现在列表里。

没有一行代码是"错"的。筛选能用,搜索能用,统计数字也对。错的是方向:它花了六个小时做你没要的东西,你要的那件小事反而只是页面的一角。这个错误在什么时候被发现的?在验收的时候——也就是最贵的时候。六个小时已经花出去了,返工不是改几行代码,是推倒重来。

“把首页做完"这句话里有多少个没说清的问题?待办只有标题,还是能加备注和截止日期?删掉要不要确认、能不能恢复?刷新之后数据还在不在?列表按新到旧还是旧到新排?每一个没问的问题,生成的时候都会被模型用自己的默认值填上。模糊的指令不会被执行,只会被放大:你留了十个空白,它替你掷十次硬币,全对的概率可以自己算。

澄清阶段要做的,就是把这十次掷硬币挪到写代码之前——在对话里问一句只要几秒,在验收时发现错了要几小时。

为什么第一阶段不写一行代码

澄清阶段是五个阶段里的第一个,整段由规划者一个角色负责。它不写产品代码,一行都不写。它唯一的产出是把一句话需求变成一份锁定的合同。

“锁定"是关键词。需求聊在对话里是会蒸发的:后面实现、评测、确认三个阶段接手的都是上下文全新的角色,它们没有参加过你的对话,不知道你们当时"说好了"什么。它们能依靠的只有文件。所以合同必须落盘,而且必须在任何代码出现之前落盘——顺序反过来,合同就会变成对已有代码的追认,那就不是合同,是说明书。

这也解释了一件容易被问到的事:这套系统里没有单独的"写文档"阶段。文档不在最后补,它就是澄清阶段的产出本身。每份契约文件都是在做决定的当下写下的,不是事后凭记忆重构的。

澄清怎么跑:先问清,再落盘

澄清分两步,顺序不能换。

第一步是访谈(技能 clarify-requirements)。规划者拿着你的一句话需求开始提问,一直问到开放问题清零为止。注意结束条件:不是规划者"感觉差不多了”,是未回答的问题数量等于零——一个可以数的状态。

问题长什么样?都是那种"不问就一定会被默认值填上"的:空列表显示什么?排序是新在前还是旧在前?删除能不能撤销?哪些状态必须有——加载中、为空、出错、无权限,少一个,生成时就少一个,后面评测时就会缺一块。访谈问的不是品味,是边界。

第二步是落盘,按固定顺序写七份契约文件:

  • prd.md——需求本身。核心是编号:REQ-1、REQ-2、……每条需求一个编号,一句可测的话。“可测"的意思是,一个没参与开发的人拿着这句话,能判断做没做到。
  • vision.md——“好样子"长什么样,写成锚点。比如空列表不是"简洁美观”,而是"显示一句话和一个添加按钮”。锚点是给后面评测阶段当标尺用的,形容词当不了标尺。
  • tech-design.md——技术方案:怎么实现、用哪些现成的东西、边界在哪。
  • pages.json——页面清单:有哪些页面、各自的路由和状态。
  • tasks.json——把工作拆成任务,一份有序的施工单。
  • rubric.json——评分表:每条需求对应哪些检查,哪些是必查项,哪些品质条目挂在哪个锚点上。
  • e2e-cases.json——端到端用例,要求覆盖六个类别,不许只测主线流程。

写完不等于澄清结束。还有一道门。

覆盖门禁:覆盖不全,不许往下走

澄清的出口有一道覆盖门禁(clarify-done),由内核机械核查,不是规划者自己汇报"都齐了”。核查的是每个需求编号在三处是否都有着落:

第一,rubric.json 里至少有一条针对它的必查项(essential)——最核心的功能检查,缺了它,这条需求做没做到根本无人过问。

第二,至少有一条挂在锚点上的品质条目;实在不需要的,必须留一份书面豁免。豁免要签字画押式的留痕,理由是:跳过可以,但必须是"决定跳过",不能是"忘了"。

第三,e2e-cases.json 里有覆盖它的用例,且整体用例要凑齐六个类别。

任何一个编号缺了任何一处,状态机就不许推进到实现阶段。不是警告,是停住。一行产品代码都不许写。

为什么卡得这么硬?因为覆盖缺口是隐形的。一条没有检查项的需求,后面不会有人发现它没做:实现阶段照着任务清单干活,评测阶段照着评分表打分,两份清单里都没有它,它就等于不存在。等用户验收时才发现"这个功能根本没做",又回到了六个小时返工的老路。门禁的本质是把"每条需求都有人管"从愿望变成一道可以数的账:编号是分母,三处着落是分子,对不上就停。

设计一:考卷出在考试之前

评分表 rubric.json 在澄清阶段就写好,和需求同一批落盘。这个时序有两个理由。

一个来自 Anthropic 的发现:评分标准的措辞不只是用来判断产出的好坏,它会反过来塑造生成者的产出方向。 你把"完成"写成什么样的清单,生成时它就朝那个方向收敛。评分表先行,它就不只是考卷,还是方向盘。

另一个理由更朴素:需求清单是评测阶段的考卷。考卷必须出在考试之前。等代码写完再回头定"什么叫做对了",定的必然是代码已经做到的样子——等于让考生自己出题,人人满分。把清单钉在写代码之前,评测才有资格说"不对",因为"对"的定义在产出存在之前就已经写下了。

编号在这里的作用也清楚了:REQ 编号是 prd 和 rubric 两份文件之间的连接键。有了稳定的编号,“每条需求都被检查到了"才是一句可以验证的话;没有编号,覆盖只是一种感觉。

设计二:自带 PRD 时,导入而不是重写

不是所有需求都始于一句话。很多时候你手里已经有一份写好的 PRD,只是没编号、没拆评分表。早期版本遇到这种情况只能把 PRD 当参考材料,让规划者重写一份——重写必然丢信息,措辞一变,原作者的意图就漂了。

现在有专门的导入路径:

harness new <功能名> --prd <文件>

PRD 原文一字不改地落成 prd.md。内核只做一件事:验编号契约。它数编号的连续性——有 REQ-1、REQ-2、REQ-4,就明确报出缺 REQ-3;它永不重编、永不改词。重编会让所有已经引用旧编号的地方全部失效,改词会让合同在你看不见的地方变样,这两件事都比"编号有个缺口"严重得多。

缺口怎么补?澄清还在,但缩减了:不再从零访谈和重写,只剩两件事——确认这份 PRD 就是你要的,以及把缺口逐个补上(缺的编号补编号,缺的品质锚点和用例在这个阶段补齐,覆盖门禁照样要过)。

这条路径背后的判断是:工具应该适应人已有的工作产物,而不是反过来要求人为了工具重做一遍。一份成稿 PRD 是资产,导入它;一句话需求是起点,访谈它。入口不同,出口是同一道门禁。

这一阶段管不了什么

边界照例说清。

澄清能保证的是"每条需求都被写清、被编号、被检查覆盖”,它保证不了需求本身是对的。一份覆盖率百分之百的合同,完全可以精确地描述一个错误的产品——门禁数的是着落,不是判断力。要不要做这个功能、这个功能对用户值不值,澄清阶段不替你回答,它只负责让你在写代码之前把答案看清楚。看清之后改主意,成本是改几行字;这正是它存在的全部意义。

它也保证不了实现的质量。合同写得再细,干活的人可以不按它干——那是下一篇的事:实现阶段,每个任务做完,都得拿得出一个能被内核验真的提交记录。