侧边栏壁纸
博主头像
MobotStone AI

行动起来,活在当下

  • 累计撰写 79 篇文章
  • 累计创建 9 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

AI写的代码看着全对、逻辑也自洽,为什么就是“不是我们想要的”?

Administrator
2026-07-17 / 0 评论 / 1 点赞 / 115 阅读 / 0 字

“沟通最大的敌人,就是我们‘自以为沟通好了’的幻觉。” —— 威廉·H·怀特(社会学家、城市规划家、《财富》杂志编辑,1950年)

当 AI 写出烂代码时,大家往往先怪 AI 笨 —— 但绝大多数时候,问题出在需求(Spec)上,而不是 AI 身上。 同样一个功能,如果只写一句“帮我做个好看的用户面板”,和写一份写明了范围、限制条件和验收标准的精准需求,用同一个 AI 跑,结果会天差地别。含糊、不完整或自相矛盾的任务描述,会让 AI 代码的准确率直接暴跌 20% 到 40%(数据来自学术研究 《When Prompts Go Wrong: Evaluating Code Model Robustness to Ambiguous, Contradictory, and Incomplete Task Descriptions》arXiv:2507.20439) —— 这可不是玄学,而是实打实的科学实验得出的结论。 接下来的十分钟,我将把我总结的7 条法则和 1 个清单,专门用来解决 AI 胡思乱想的漏洞。你还会明白为什么说写好需求,才是你唯一能 100% 掌控的“完美法宝”。AI 就像一个“从不提问”的程序员:你写什么它就执行什么,它只听你的字面意思,不懂你的“良苦用心”。

核心提炼 —— 这篇文章最想告诉你的一点

最关键的一点是:AI 遇到没说清楚的地方,是绝对不会主动提问的。 如果是资深程序员,发现需求有漏洞会找你确认;而 AI 则是默默用它训练数据里概率最高的“套路”把洞补上 —— 然后完美避开你的真实意图。结果就是,它给你的代码“错得极其精准”:语法全对,逻辑自洽,但根本不是你想要的。

这带来的实际启示很简单:你控制不了 AI 的智商上限,但你完全可以控制需求文档的质量。 一份合格的 AI 需求,必须讲清楚 AI 最容易瞎猜的 5 件事:

  • 预期结果 —— 最终要达到什么效果,而不是教它怎么写代码。

  • 范围与非目标 —— 明确哪些事情是它绝对不要做的。

  • 限制条件 —— 技术栈、版本、代码规范、性能限制等。

  • 验收标准 —— 怎么测试算通过?让人一眼就能照着勾选确认。

  • 边缘与异常情况 —— 因为正常流程只占实际运行的一小部分。

记住一个核心原则:需求不是越长越好,而是要**“信息多重确认”(Signal Redundancy)**。用不同方式(比如文字描述 + 限制条件 + 示例)把同一个要求说清楚,比写一整篇废话管用得多。如果读完本文你只记住一句话,那就是:在怪 AI 之前,先看看这 5 件事你漏掉了哪一件。

既然知道了关键点在哪,我们来看看这背后的原理 —— 为什么一个需求漏洞,就一定会变成一堆烂代码?

为什么需求质量决定一切

AI 的脑子里没有“我不知道,我得问问”这个选项。当你的任务描述有缺失时,AI 不会停下来,而是直接用概率最高的词把话接下去。更糟糕的是,你写的一个敏感词可能会激活它脑子里的某个固定“套路”。比如你写“排序并返回前 N 个”,AI 就会高高兴兴地套用它在几万个训练样本里见过的最经典模板 —— 哪怕这个模板根本不适合你当前的场景。

这就是“因为漏洞而产生幻觉”的机制。代码语法上毫无破绽,但业务逻辑上错得离谱,因为没人告诉它它不知道的事情。换句话说,错误不是 AI 自己凭空造出来的,而是你留下的空白造成的。

数据也佐证了这一点。一项严谨的对照实验显示,模糊、残缺或自相矛盾的需求,会把 AI 的首轮代码准确率拉低 20% 到 40%,其中“前后矛盾”的需求杀伤力最大(跌幅达 40%)。需要说明的是,这个研究是在特定评测集(HumanEval 和 MBPP)上做的,实际开发中情况更复杂,但规律是一样的:需求稍微一糊涂,写出来的代码就容易“鸡同鸭讲”。软件工程历史上的各种 Bug 分析也证明了同样的道理:生产环境里的一大半 Bug,其实都源于当初没把需求理清楚,而不是代码写错了。

要理解这个原理,我们不用看那些枯燥的测试数据,看一个著名的历史教训就够了:“火星气候探测器”坠毁事件。 1999年9月,这个飞了整整9个月的探测器,在试图进入火星轨道时瞬间烧毁。原因听起来让人哭笑不得:制造飞船的洛克希德·马丁公司在软件里用的是“英制”单位(磅),而负责导航的喷气推进实验室(JPL)以为是“公制”单位(牛顿)——双方在对接接口时,谁也没去统一这个单位。数据传输得非常精准,发送、接收、存储都没出任何差错,但整整9个月里,这个小小的“单位误会”让飞船的轨道偏得越来越多。正如事故调查小组所说,它死得“极其精准、无可辩驳”。 而今天,AI接受我们指令(Token)的方式,跟当年那台软件接受数字一模一样:你给它什么它就吃什么,根本不会多问一句这些数字到底代表什么意思。

不过,我们也要讲句公道话:不能把所有锅都甩给指令。“只要写好需求(Spec),AI就能干好活”这句话也并不是绝对的。在某些情况下,再完美的指令也救不了场。

比如,一项针对资深程序员的真实对比测试显示:有时候,AI反而让这些高手的干活速度变慢了——尽管他们主观上“感觉”自己变快了。在这种情况下,写更完美的指令也没能挽救效率的下滑(数据来自METR研究,《Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity》arXiv:2507.09089;测试对象为使用 Cursor Pro + Claude 3.5/3.7 的 16 位开发者在自家开源项目上的表现,作者指出该结果不能代表所有软件工程情况)。 另外,那些在“模拟考试”(学术测试集)中能拿 84% 到 89% 高分的明星 AI 模型,一旦放到真实的工作环境里(比如从零生成完整的 Java 类),得分竟然会惨跌到 25% 到 34%(数据来自《超越人工测试集》,《Beyond Synthetic Benchmarks: Evaluating LLM Performance on Real-World Class-Level Code Generation》arXiv:2510.26130)。这不仅仅是因为需求没写好,还因为 AI 缺乏对整个项目的全局感知,或者在抓取背景信息时失败了。 所以,结论并不是“AI干不好活,全是因为你需求写得烂”。 而是:在影响 AI 表现的众多因素中,写好需求(Spec)是你唯一能完全掌控的最大杠杆。在你抱怨“这AI太笨、根本不能用”之前,先花点小钱、对照“五个痛点”检查一下自己的任务描述,这绝对是性价比最高的排查方式。这能帮你找准问题到底出在哪里。

既然“沟通上的信息差”是问题的根源,那么问题来了:我们该用什么具体的方法来填平这个差距呢?

核心招式:让 AI 听懂人话的七条写需求黄金法则

对团队来说,有个好消息:这些核心要素是数得清、学得会的——这不需要天赋,只需要一点规范和纪律。接下来的七条法则,是从无数开发工具、研究论文和一线从业者的实战经验中提炼出来的共识。它们之所以威力巨大,并不是因为它们规定了什么死板的格式,而是因为它们精准地填补了那些沟通漏洞。记住,格式只是工具,解决问题才是终极目标。

规则 1 —— 关注“结果”,而不是“实现过程”

多描述系统要表现出什么行为,而不是教它怎么写代码。告诉 AI 系统最终要达到什么目的、怎么算成功,而不是教它用什么循环语句去写。在需求文档里塞一堆伪代码只会适得其反:这会带偏 AI 的思路,把“要做什么”和“怎么去做”给混为一谈。你的角色是规划终极目标的“架构师”,至于怎么搬砖盖楼,那是“施工队”(AI)的事。

规则 2 —— 不仅要说“做什么”,还要说“不做什么”

明确指出这次修改不涉及哪些内容,和说清楚要做什么一样重要。如果不画好边界,AI 就会像个没有合同约束的包工头——它会自作聪明地加一些它觉得“挺合理”但你压根不需要的功能。只需加一句简单的话,比如“不导出附件,不修改数据库表结构”,就能帮你省去事后花几个小时清理冗余代码的痛苦。

规则 3 —— 写出“可测试的”验收标准

这是写好一份需求文档的核心。验收标准必须是可以测试的、有明确边界的、非黑即白的,而且一次只关注一件事。像“运行流畅”这种模糊的话绝对不行。相反,“在 1 万条记录下,列表接口 95% 的响应时间要在 200 毫秒以内”就是一个好标准,因为测试人员不需要问任何人,自己就能测出来合不合格。

这里有一个大白话标准:如果一个需求不问产品经理就没办法证明它通过了,那它就还只是个草稿,不能算正式要求。 好的验收标准既能给 AI 指明方向,也能在你发现 AI 乱写代码时,有理有据地直接“退货”。

规则 4 —— 强迫写出错误流程和极端情况

在实际运行中,一帆风顺的“正常流程”其实只占少数,但大多数人写需求时只写这一种情况。如果你不告诉 AI 遇到“列表为空”、“没有权限”或“超出限制”时该怎么办,AI 就会根据它以前学过的套路凭空瞎猜一套报错处理。你至少得提供:一个报错流程、一个极端情况、以及一个空数据或无权限的情况。代码上线后容易崩溃的地方,往往就是这三个你没交代清楚的漏洞。

5. 规则 5 —— 给足背景信息和限制条件

AI 并不了解你的代码库。你需要主动告诉它:用的是什么技术栈和版本、代码规范是什么、禁用哪些第三方库、输出格式是什么,以及硬性的性能限制。你不说,不代表 AI 就会保持沉默——它会开始“盲猜”。 这和写丢需求是一个道理:你没交代清楚的地方,AI 就会用它脑子里最常见的套路去填补,而那套路大概率不适合你的项目。

6. 规则 6 —— 给出具体的例子,而不是一堆死规矩

给几个典型、多样的“输入-输出”实例,效果远比写一堆又臭又长的规则和特殊情况要好。各大 AI 厂商的官方指南也证实了这一点:与其罗列一大堆“例外情况”,不如直接给它展示精心挑选的例子。对 AI 来说,一张图、一个例子胜过千言万语。给出一个“正确输出长啥样”的真实样例,比写一整段文字解释能减少更多误解。

7. 规则 7 —— 复杂度和详细度要匹配

“完美,不是指没有东西可以往里加了,而是指没有东西可以往外减了。” —— 安托万·德·圣-埃克苏佩里(《小王子》作者)

说句实话:关于“需求写短点好还是长点好”,行业内还没有定论,任何拍胸脯向你保证有绝对标准的人,都是在忽悠你。 支持“写短点”的人认为:AI 的注意力是有限的,为了显示个日期而写几百行的需求简直是灾难。支持“写详细点”的人则拿研究说话:写满限制条件、输入输出和极端情况的详细描述,能显著提升 AI 的准确率,少写一条限制,准确率就会立马掉下来。 一个聪明的折中办法是:不纠结长短,而是根据任务的难易程度,让信息的详尽程度与难度匹配。 如果只是想让一个按钮居中,那就写短点;如果是要实现一套带 Token 刷新的 OAuth 授权,那就得写得详详细细。最关键的是,你要通过多种渠道(描述、限制、例子)把同一个要求传达清楚,而不是去数需求写了多少行。

这些规则听起来都很合理。接下来,让我们看看同一个功能,在“糟糕的写法”和“优秀的写法”下分别长什么样。

同样一个功能,两份截然不同的需求说明

我们来看一个实际的任务:做一个把用户列表导出为 CSV 文件的接口。这是我平时最常看到的版本:

做一个导出用户到 CSV 的接口,记得做好用一点。

试想一下,如果一个不会主动追问细节的 AI 模型(或程序员)看到这句话,它会怎么做?CSV 格式是什么?用什么分隔符?用什么编码?——没写。要导出哪些列?是所有字段还是只导出公开信息?——不知道。如果用户列表是空的怎么办?——没定义。

谁有权限调用这个接口?——没解决。如果一次性导出十万条数据,系统会不会卡死?——全凭运气。面对这些空白,AI 只能靠“瞎猜”来填补——而从概率上讲,只要是猜,就总会有猜错你心思的时候。

现在,我们来看看把这些“漏洞”都堵死之后的同一个任务:

预期结果(Outcome):通过 GET /users/export 接口,下载包含“活跃用户”列表的 CSV 文件。

范围(Scope):仅限活跃用户。导出列:id, email, created_at。
非目标(Non-goals):不导出已注销账号,不导出账单数据,不修改任何数据。

限制条件(Constraints):采用 UTF-8 编码,用英文逗号分隔,第一行为表头;数据量超过 5000 条时使用流式传输(stream response);仅限管理员权限。

验收标准(Acceptance criteria):
- 如果有 3 个活跃用户,返回 3 行数据 + 1 行表头。
- 如果没有用户,只返回表头,并返回状态码 200。
- 非管理员调用,返回 403 错误,且不下载任何 CSV 内容。
- 5 万条数据下,响应时间在 2 秒以内(采用流式传输)。

示例输出(Example output):
id,email,created_at
42,ada@example.com,2026-01-12

第二个版本其实并没有长篇大论——它只是在第一个版本“装聋作哑”的地方,给出了精确的交代

规则 1 用明确的“预期结果”代替了含糊的“做好用一点”;规则 2 砍掉了不相关的附件和账单导出需求;规则 3 把“运行流畅”拆解成了四个可验证的具体条件;规则 4 规范了“数据为空”和“没有权限”这两种特殊情况;规则 5 则定死了编码格式、分隔符以及流式传输的门槛。

这恰恰证明了我们一开始的观点:决定最终结果好坏的,不是字数的多少,而是你有没有把这五个“漏洞”堵死。

即便是按照这种方式写出来的需求文档(Spec),也很难在第一版就做到天衣无缝。关键在于,我们要学会如何一步步去完善和迭代它。

如何一步步完善需求文档(Spec)

需求文档可不是写完就大功告成、束之高阁的。它是“活的”,是在一个循环里不断成长起来的:你写测试、敲代码,看看哪里掉链子,然后把需求文档里没写明白的地方补齐,接着再重复这个过程。

测试不仅能揪出代码里的 Bug,还能照出需求文档里的漏洞。 一个测试没通过,往往是在提醒你:“嘿,这里的规则之前没写完整!”而不仅仅是代码写错了。在这个过程中,一个清晰、分步走的工作流能起到立竿见影的效果。在 AlphaCodium 的一项研究(《Code Generation with AlphaCodium: From Prompt Engineering to Flow Engineering》arXiv:2401.08500)中,研究人员把给 GPT-4 的指令从“一次性打包交代”改成了“分步骤引导”,结果 GPT-4 在解决高难度编程竞赛题时的成功率直接从 19% 飙升到了 44%(这是在 CodeContests 竞赛数据集上的表现。虽然竞赛题和我们平时的实际开发工作不太一样,但这个趋势与其他关于“迭代方法”的观察是一致的,都证明了分步迭代的威力)。

这种循环也衍生出一个简单却金科玉律的原则:当代码和需求文档对不上时,一切以文档为准。 需求文档是“合同”,代码只是“执行合同的具体方案”。测试报错,不一定代表代码写错了,有时它其实是在拉响第一声警报:你的文档已经开始脱离实际了。这就是“文档失效(Specification Rot)”的苗头——即文档和实际代码逐渐各走各的路——不过,这就是另外一个故事了。

凡事都有两面性,掌握规范的另一面,是知道什么时候不该写需求文档(Spec)。比如改个小 Bug、做个探索性的原型、或者写个单测就能搞定的任务——在这些情况下,写一份完整的文档纯属浪费时间,得不偿失。记住一条原则:根据风险大小,来决定投入多少精力

如果你写个简单的测试就能验证结果,说明影响范围很小,可以放手去干。但只要涉及到权限、支付或数据完整性,无论如何都得老老实实写文档。另外,这里还有一个“迭代陷阱”:AI 助手(Agent)有时候会钻空子,即使没写测试,它也会把任务标记为“已完成”——也就是所谓的“文档看着没问题,代码其实没写完”。因此,最终的把关人必须是人类,而不是 AI

整个工作流程需要一个“质检站”。这就是“检查清单”发挥作用的地方——在把文档交给 AI 助手之前,用它做最后一次把关。

需求文档(Spec)验证清单

在把文档发给 AI 助手之前,先对照下面这个简短的清单过一遍。这可不是什么官僚主义,而是一个**“退单机制”**(不合格就退回重写),也是培养团队写好文档最省钱的方法。你可以直接复制下面这个版本:

  • 每一条验收标准都符合“如果/当/那么”(Given/When/Then)的格式(即:背景 → 触发事件 → 预期结果),或者类似的清晰逻辑。

  • 至少有一条标准考虑到了报错或异常情况

  • 至少有一条标准考虑到了数据为空、权限限制或极端边界情况

  • 明确写出非目标——也就是这次改动“绝对不做什么”。

  • 在动手开发之前,每一条标准都必须定好“怎么证明它做到了”(比如通过自动化测试、日志还是截图)。

  • 如果想不出怎么证明,说明标准写得太模糊了——倒回去,重新写清楚。

那张清单就是你最好的培训教材。我们要像对待代码一样对待需求文档(Spec)和提示词(Prompts):给它们做版本管理、对比修改差异、在合并发布前做回归测试。像审查代码(Code Review)一样去审查需求,应该成为大家的日常习惯。

把优秀和糟糕的需求案例(比如上一节提到的那些)在团队里传阅,当成大家的参考标准。这里有一个来自高安全要求行业的妙招,非常值得借鉴:亚马逊 AWS 的工程师们只花了两到三周,就学会了怎么写严谨的系统规范,并立刻揪出了现实中的 Bug。而秘诀仅仅在于,把那些听起来“吓人”的条条框框,包装成了普通、实用的日常规范。(这里参考了 2015 年 ACM 通讯的研究,虽然原文指的是 TLA+ 这种形式化模型检查语言——它和给 AI 写自然语言需求有些许不同,但道理是相通的)。阻碍我们把需求写好的,往往是心理上的抗拒,而不是技术上的难度。

这就是让这项技能如此值钱的奥秘所在。写出一份好的需求,需要像写出好代码一样严谨的逻辑思维——正因为这件事不容易,它才显得格外有价值。

总结

整篇文章说到底其实就一句话:你能真正掌控的杠杆是“需求”,而不是“AI模型”。模型不会主动问你漏掉了什么前提条件——它只会用训练数据里的套路自行脑补。因此,一份漏洞百出的任务描述会系统性地带偏 AI,哪怕最后写出来的代码看起来没什么问题,结果也是错的。

以下是这篇文章最值得你带走的四点收获:

  • 一份优秀的需求要堵住五个漏洞:预期结果、工作范围(以及明确不做什么)、限制条件、可测试的验收标准、极端情况及失败预案。

  • 关键在于信息量(有效细节)要配得上任务的复杂度,而不是字数越多越好。

  • 需求是在循环中迭代出来的——用测试来暴露漏洞,在把任务交给 AI 之前,用清单做好最后的把关。

  • 杠杆在你手里,不在 AI 手里:在怪 AI 太笨之前,先检查一下自己的任务说明写清楚了没有。

1

评论区