别让 AI 助手自信地写出废代码:实战“需求门禁”机制
AI 编程助手(Coding Agent)能帮我们写代码,但它最昂贵的代价,往往是“自信满满地实现了一个完全错误的东西”。
我是怎么领悟到这个痛点的?有一次,我给 AI 派了一个任务:“优化新用户的注册流程”。它吭哧吭哧跑了 40 分钟,修改了 11 个文件,还提交了一个代码合并请求(PR),重新设计了一个根本没人抱怨过的表单。代码很干净,测试也通过了。但这堆代码毫无用处,因为任务里根本没定义“优化”是什么意思,而 AI 作为一个没有感情的执行机器,自己脑补了一个解释并死磕到底。
最后,PR 被关闭,分支被删除。我不得不反思,为什么自己花了 API 调用的钱,却买来了一堆人类工程师根本不屑于开始的废代码。
如果把这个任务交给人类工程师,他们会做一件 AI 默认不会做的事:反问(Push back)。“怎么优化?优化给谁看?是第二步的流失率高,还是第四步的文案太绕口?”这种反问本身就是极具价值的工作。高级工程师一半的价值,就在于“在问题明确之前,拒绝盲目动手”。
因此,我发现解决 AI 自动化写代码不靠谱的最大杀招,不是换更聪明的模型,也不是写更长的提示词,而是强制增加一个步骤,让 AI 在结构上必须学会说“不,现在还不行”。
什么是“需求门禁”?
在任何代码被写下之前,我会让 AI 在“只读模式”下运行一次,对着格式化的任务需求和真实的代码库,只回答以下三个问题:
- 需求是否足够清晰,以至于两个正常的工程师会写出差不多的代码?
- 这个改动是否符合代码库当下的实际情况?还是说任务假设了某种根本不存在的架构?
- 为了完成这个任务,我需要自己“脑补”哪些决策?这些决策到底该由谁来做?
评估的结果是一个简短的 Markdown 文件。如果评估结果是“清晰”,流水线就会继续执行并生成 PR。如果带着“未解决的问题”,流水线就会停止,并将这些问题作为评论发回任务追踪系统(如 Jira、Linear),直接 @ 给写任务的人。
这里有两个看似不起眼但至关重要的细节:
第一,门禁必须是“只读”的。 评估阶段绝对不能有修改文件的权限。这不是因为不信任模型,而是为了防止副作用。如果 AI 在评估时能改文件,它就会为了让任务变得可行而“顺手修点东西”,导致你的可行性检查被污染。大多数编程 AI 都有原生的只读模式(比如 Claude Code 的 plan 模式),直接用那个,别指望靠提示词说一句“请不要修改任何东西”就能管用。
第二,问题必须发回任务系统,而不是写在日志里。 躺在服务器日志里的可行性报告没人会看。把“在实现之前,我需要以下问题的答案……”作为评论发到任务追踪器里,能逼着作者去回答。几周下来,这还能“训练”写任务的人。大家会开始写出能一次性通过门禁的任务,因为被机器人打回多少有点尴尬,而被同事打回就没这种感觉。
一个优秀的“拒绝”长什么样?
这里有一个我自己 backlog(任务池)里的真实评估案例,任务标题是“给 API 添加限流”:
此任务尚未准备好实现。未解决的问题:
- 哪个 API?代码库里暴露了公共 REST API(
src/api/)和内部 webhook 接收器(src/webhook-server.ts)。如果对 webhook 接收器限流,会破坏 GitHub 集成的重试机制。- 按什么维度限流?按 IP、按 API Key 还是按账户,这三者的实现完全不同。目前代码库里没有按账户追踪请求的机制。
- 被限流的请求应该收到什么响应?标准的 429 状态码加 Retry-After 头是常规做法,但移动端客户端(根据
docs/clients.md)不处理 429,会直接抛出一个通用错误。建议:将任务拆分为“按 API Key 对公共 REST API 限流,返回 429 + Retry-After”,以及一个单独的客户端适配任务。
你看,每一个问题都死死扎根于 AI 在代码库里找到的真实细节,而不是泛泛而谈的“需求收集”。问题 3 就是那种如果让 AI 瞎猜,上线后就会变成生产事故的坑。而且,任务作者只需两分钟就能回答这三个问题,让任务当天就能进入开发。
这种“基于事实的扎根(Grounding)”就是全部的秘密。“请澄清需求”是废话;“你说给 API 限流,但我们有两个 API,这是它们的路径”才是真同事。
踩过的坑与失败模式
在构建这个机制时,我也遇到了一些坑:
- 门禁变成了“好好先生”:一开始我的提示词是“这个任务可行吗?”模型为了讨好我,几乎对所有任务都说 Yes。后来我换了思路:不问结论,而是让模型列出“实现者需要自己发明的决策清单”。如果清单是空的,就放行;如果有内容,这些内容就是拒绝的理由。模型在“列举模糊点”上比“判断模糊点”强得多。
- 门禁变成了“杠精”:矫枉过正的话,AI 会连改一行文案都要求你写详细规格说明书。我的校准方法是:只有当“猜错会导致 PR 被拒绝”时,这个问题才算阻断性问题。“用哪种灰色”不算阻断,“用哪两个 API 中的一个”才算。
- 盲目信任 AI 会自己停下:有时候 AI 在实现阶段会问“需要我顺便迁移旧数据吗?你想怎么处理?”然后流水线看到退出码是 0,就傻乎乎地把半成品提交了。现在我会扫描 AI 输出的尾部,寻找“哪个选项”、“需要我吗”、“你决定”这类决策型问题。如果以这些问题结尾,就视为运行失败:不提交任何代码,把问题发回任务系统。带着未解答的问题强行提交,就是在上线一个没人拍板的功能。
- 担心成本:门禁确实多了一次模型调用,但很便宜:只读、没有编辑循环、只需几分钟。相比于浪费 40 分钟跑出一个废代码,再浪费人类时间去 Review,它只要触发一次就回本了。在我的日志里,它大约会拦截五分之一的任务,正好是那些以前让我直接关闭 PR 的垃圾任务。
核心启示与工具推荐
如果你正在搭建“从任务到代码”的自动化流水线,请记住:在“拒绝路径”上投入的设计精力,要和“顺利路径”一样多。 顺利路径只是个演示,拒绝路径才能让它在真实的任务池中存活下来,因为现实中很大一部分任务,都是大家在开会间隙匆忙写下的一句话愿望。
AI 完全能察觉到需求的模糊之处。它们缺少的,只是流水线中一个“专门用来察觉模糊”的环节,以及一个“安置这些问题”的地方。给它们这两样东西,下游的所有环节都会变得更顺畅。
为了把这个理念落地,我开发了一款名为 DevIntern 的工具。它能把来自 Jira、Linear、Trello 等追踪器的任务,一路自动处理成经过 Review 的 PR。每一次运行都会先进行这个可行性检查;不清晰的任务会被打回,评估报告会作为 feasibility-assessment.md 保存下来。
你可以像下面这样使用它:
# 使用 DevIntern 工具处理指定的任务票据(如 PROJ-1842)
# 并自动创建代码合并请求(PR)
devintern PROJ-1842 --create-pr
交互式使用是完全免费的,无需注册,并且支持你已经在用的任何编程 AI(如 Claude Code、Codex、Cursor 等),使用你自己的 API Key 即可。
