我用 AI 写完一个需求后才发现,最难的不是 prompt,而是验收

0 阅读7分钟

现在写需求的流程已经变成这样:在 Claude Code 里把需求描述清楚,它直接把组件、样式、请求逻辑一起生成出来,主流程几分钟就能跑通。

真正让我在提交前停下来的,从来不是"它写得快不快",而是另一个问题:我怎么确认这份代码达到了能提交的标准?

用得越久我越清楚一件事:prompt 决定产出速度,验收决定能不能提交。这篇把我自己正在用的验收方法整理出来:5 个必验项,加一份把验收标准直接写进 prompt 的模板。

先算一笔时间账:写的时间没了,验的时间还在

以前的分配大致是八分写、两分验:代码是自己一行行敲的,敲的过程中脑子已经顺带过了一遍,验收只是收尾。

现在倒过来了。生成只占几分钟,剩下的大块时间全花在确认上:这段代码在什么情况下会不成立?改动的范围有没有超出我的预期?

这不是我的个人体感,有实验佐证。研究机构 METR 找了一批资深开发者做对照实验:使用 AI 工具的那组,实际完成时间比自己动手慢了 19%,而他们事前预计自己会快 24%。

快慢之间的 43 个百分点差在哪?我的理解是:生成的时间被压缩了,确认的时间一点没少。错觉来自"写"的部分——prompt 一发,代码唰唰地出来,体感极快;瓶颈藏在"验"的部分——你得逐个回答"它对不对",而这件事没有任何加速。

所以验收才是现在真正的硬技能。它至少分三层:

  1. 功能路径:主流程能不能跑通。这层 AI 做得最好,也是"完成错觉"的主要来源。
  2. 边界条件:输入走到极端、状态停在中间、请求时序错开时,代码还能不能成立。
  3. 回归范围:这次改动有没有顺手动了不该动的东西。

下面 5 个必验项,就是围绕后两层来的。

一次典型的验收:AI 给的列表页缺了什么

拿我常写的需求举例。在 Claude Code 里丢一句"实现一个用户列表,支持关键词搜索",一两分钟后拿到这样的组件:

function UserList({ keyword }: { keyword: string }) {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    fetch(`/api/users?q=${keyword}`)
      .then((r) => r.json())
      .then(setUsers);
  }, [keyword]);

  return (
    <ul>
      {users.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

类型齐全,渲染正常,输入关键词立刻有结果。按"功能路径"这一层,它已经完成了。但拿 5 个必验项过一遍,问题全在里面。

第一项:三态——加载、空、错误。 AI 默认只写成功路径。断网一次、造一批空数据、让接口返回一次失败,分别看页面呈现什么。这个组件三个分支都没有:加载中是白屏,空数据是空白,请求失败是静默——用户只会觉得"页面坏了"。

第二项:边界值——空、超长、快慢。 空关键词发不发请求?输入两百个字符的搜索词,URL 参数没编码会不会出问题?快速连续输入时,前一个慢请求的响应回来,会不会覆盖掉新结果?最后这个是经典竞态,搜索类功能的高发事故。

第三项:清理——卸载之后还活着的东西。 组件卸载后,在途请求还在飞,响应回来往一个已经不存在的组件里 setState。控制台的 warning 只是最轻的后果。验收动作很具体:切走页面,打开 Network 面板,看请求有没有被取消。

第四项:假类型——类型对,不代表数据对。 r.json() 的结果直接进了 setUsers,中间没有任何校验。接口哪天把返回结构包了一层 { code, data },TypeScript 不会报错——运行时的数据和编译时的类型声明,本来就是两回事。验收时搜一遍 anyas 和非空断言,看类型是真的在把关,还是只在哄你安心。

第五项:回归范围——diff 里有没有你没让它碰的东西。 这一项在组件之外。你让它改列表页,它顺手把共享的 formatDate 改了签名,因为它判断"这样更通用"。生成速度越快,一次带出的改动越多。验收动作:先用 git diff 圈出改动范围,凡是共享工具函数、公共样式、全局配置,逐行看。

5 项过完,这个"几分钟就完成"的组件,大概还要再花几十分钟才能提交。这就是时间账的真相。但换个角度想:这几十分钟里做的判断,恰恰是 AI 替代不了的那部分。

更省力的做法:把验收标准写进 prompt

上面是事后验收。更划算的做法,是让验收标准在生成之前就存在——直接写进需求描述:

实现一个用户列表,支持关键词搜索。

验收标准(完成后逐条自查,并在回复里标注结果):
1. 加载中、空数据、请求失败三种状态都有对应 UI
2. 关键词变化时取消上一次未完成请求,旧结果不得覆盖新结果
3. 组件卸载后不得更新状态,不得保留在途请求
4. 请求参数需编码;响应结构先校验再使用
5. 只允许改动 UserList 相关文件,不得修改共享工具函数

完成后输出:改动过的文件列表,以及上述每一条的自查结果。

这套模板的效果比我预期的好,最明显的两点:

一是返工率降下来了。三态、竞态、清理这些以前靠"我忘了说"的事情,现在成了需求的一部分,AI 生成第一版就会带上。

二是自查结果本身就是情报。让它逐条标注,它经常会在第 3 条老老实实写"未处理"——它知道这条标准,只是默认你没提就不做。哪些是能力问题,哪些是沟通问题,自查结果会告诉你。

但要把边界说清楚:模板不转移责任。AI 的自查是用来降低返工的,不是替你验收的。最后一道人工抽验永远要在——验收标准写得再细,也没有人能替你回答"这个错误提示用户能不能看懂"。

验收清单速查表

必验项验收动作在抓什么
三态断网一次、空数据一批、看加载中呈现只写成功路径的实现
边界值空输入、超长输入、快速连续输入各来一次竞态、参数未编码、极端输入崩溃
清理卸载组件,看 Network 里请求是否取消在途请求、残留监听、定时器
假类型搜 any、as、非空断言,看响应有无校验类型声明和运行时数据脱节
回归范围git diff 圈改动,共享代码逐行看顺手优化带出的外溢改动

从写代码的人,变成定标准的人

用 AI 之前,前端的价值主要体现在实现上:谁能把功能写出来,谁就有产出。用 AI 之后,实现的边际价值被压薄了,真正拉开差距的变成两件事:能不能把"什么算对"说清楚,以及能不能高效地确认它。

验收标准写得清楚的人,敢把需求整段交给 AI,然后只做有依据的抽验;写不清楚的人,只能对着 AI 的输出逐行看——那比自己去写还慢。METR 实验里那 43 个百分点的错觉,一半就来自这里:没有标准,"看起来完成了"和"完成了"之间就没有刻度。

所以,别把精力全花在打磨 prompt 的措辞上。prompt 的上限,取决于你在里面放了多少验收标准。

你的验收底线画在哪?哪些必须人眼过一遍,哪些敢直接交给测试用例?评论区聊聊你的清单——你的一条必验项,可能正好补上别人缺的那条。