上一篇里我们拆开了一个现象:让 AI 补全几行代码很顺,让它做完一整个任务却常常翻车。原因是程序越长,你没说清的地方越多,而每一个没说清的地方,模型都会替你填一个答案——不通知你,直接写进代码。
那么问题就落到最实际的一步:我到底该说清哪些东西?
答案不是“把需求写得更长”。这一篇把它变成一份可以照着填的清单。
一、模糊的不是想法,是那些没被决定的岔路
先纠正一个常见的误解。你说“帮我写个脚本压缩一下图片”,这句话并不算模糊——你自己心里其实有画面。问题在于这个画面只存在于你脑子里,而代码里每一个必须给出答案的地方,都没得到答案。
这类地方我叫它 分叉点:代码必须在这里选一条路,而你的需求没有指定是哪条。分叉点不会报错,模型照常给你一份跑得起来的代码,只是它替你选了。等你看见结果才发现“这不是我要的”,返工就开始了。
所以写需求不是描述,而是 把分叉点一条条找出来,自己决定,然后写下来。
二、一句话需求里,藏着六个待定的答案
拿一个具体的例子。你原本想说的只有一句:
帮我写个 Python 脚本,把
photos/里的图片压缩一下。
这句话里至少藏着六个模型必须自己决定的地方:
- 结果写到哪?覆盖原图,还是另存一个目录?
- 目标是什么?固定输出质量,还是把文件压到某个大小以内?要不要限制宽高?
- 只处理
.jpg吗?文件夹里混着.gif、.heic、.pdf怎么办? - 某张图打不开的时候,是报错停下,还是跳过继续?
- 能用哪些库?Python 3.8 还是 3.11?
- 跑完怎么知道它做对了?打印什么,还是不打印?
这六条里,任何一条你不在乎,都可以交给模型去选。但你得先意识到它在替你选——没被意识到的默认选择,就是你后来返工的来源。
三、要交代的五类信息
把上面的岔路归一下类,就五个槽位。前四类是内容,最后一条在措辞里。
第一,做完的样子。 用一句能观察的话说清“什么叫做完了”。不是“跑通就行”,而是“output/ 里每张图都不超过 500 KB,宽高不超过 1920 像素,随便打开一张看不出明显色块”。有了这句,你事后不用逐行读代码,跑一遍就知道对不对。官方指南也把它列为核心习惯:提前说清验收标准,比来回改三轮更省事 1。
第二,输入、输出和边界。 说清数据从哪来、长什么样、到哪去、格式是什么,以及那些“不常见但一定会遇到”的情况:文件夹是空的、多了一层子目录、某一列缺失。研究者记录过对一批代码生成提示词的改进过程,其中“把输入输出格式写清楚”出现在 44% 的改进里,“补上执行后结果必须满足什么”出现在 23% 里,“明确要用哪些库、各自干什么”出现在 19% 里,“写清该抛什么异常或打印什么错误”出现在 12% 里 2。
第三,环境与约束。 这一类最容易被忽略,因为它不在需求里,而在你的项目里:能用哪些依赖、不许引入新库、必须复用已有的哪个函数、哪些目录不许动、跑测试用哪条命令。模型看不到这些,就会按训练里见过的常见形状去写——这正是上一篇说的 API 误用和“把已有函数又抄一遍”的来源。约束要写成它读代码看不出来的那种;它能自己看明白的,写进去只是占地方。
第四,出错时的表现。 别写“优雅地处理错误”,这种话等于没写。要么说“打不开的文件记下名字继续处理下一个”,要么说“参数少于两个就抛 ValueError”。具体怎么出错,是需求的一部分,不是实现细节。
第五,措辞。 有两个小习惯很值钱。一是对必须做到的事用“必须”,而不是“应该”“可以”;在这份研究里,把含糊的“应该”改成明确的“必须”就是常见的一类改进 2。二是少用“否则”“按需”“相关文件”“合适的”这类词——它们把决定又推回给了模型。要用“否则”,就把两个分支都讲明白:“当 A 成立时做 X;当 A 不成立时做 Y” 2。
把这些填进去,同一个例子会长成这样:
写一个
compress.py,处理photos/下所有.jpg和.png。 输出写到output/,文件名不变,后缀统一为.jpg;photos/里的原文件不动。 每张图宽高不超过 1920 像素,文件不超过 500 KB;先按宽高缩,再降质量,直到满足。 如果降到质量 60 还是不满足,就保留这一张并记入失败。 环境:Python 3.11,只允许用Pillow,不要调用 ImageMagick 这类外部命令。 遇到.gif、.heic或非图片文件,跳过并计数;某个文件读不出来时记录文件名继续下一个,不要中断。 结束时打印一行:done: 成功 N,跳过 M,失败 K。
它并不算长,但每一句都消掉了一个原本由模型代填的答案。
有一点要说清楚:那几个百分比统计的是“改进提示词时,各类修改出现的次数”,说明的是大家最容易漏掉什么,不是每条改动带来多少收益。而且这些任务大多是单函数级别的基准题,里面出现最多的一类修改其实是“把算法本身讲清楚”(57%)2——你在真实项目里未必需要这么多,反而“项目里能用什么”这类约束更容易漏。
四、约束不是越多越好,同时分清两件事
约束太多会互相淹没。Claude Code 的官方文档给出的经验是:如果一个规则明明写在了项目说明文件里、它却反复违反,通常不是它“不听话”,而是文件太长,重要规则被噪音盖住了,删掉一半往往比再补一条更有效 3。
所以每条约束都问一句:它消掉了哪个具体的猜测? 没有明确答案的,删掉。
这里顺便分清两层东西。一次性的需求 回答“这次要做成什么样”;项目里一贯的约定 回答“这个项目里通常怎么做”。后者值得单独放进一个文件,让工具每次开工时自动读到,比如 Claude Code 的 CLAUDE.md,或者通用的 AGENTS.md 4。里面只放读代码看不出来的东西:构建和测试命令、必须遵守的风格、不许改的目录、踩过的坑 3。这样你就不必在每条需求里重复交代同一件事。
五、漏掉的分叉点,让它先替你列出来
你不必靠自己想全。一个很省力的做法是:先要计划,先别要代码。
先别改代码。告诉我你打算怎么做,特别是你打算自己决定的地方,以及理由。
它列出的计划里,每一个准备自行拍板的地方,都是你该确认的分叉点 1。这比凭空想清单容易得多,而且确认发生在写代码之前,代价最低——改一份几行的计划,远比改一份已经写好的脚本便宜。这也正是下一步要做的事:让 AI 先规划,再动手。
收尾:三句话的自检
需求发出去之前,问自己三件事:
- 别人(或者一周后的你)拿着这段话,能不能判断它做完了没有?
- 里面有没有“合适的”“按需”“相关文件”这类把决定让出去的词?
- 每条约束各自消掉了哪个猜测?没有的话,删掉。
写需求的目标从来不是把话写多,而是把 原本会由模型默默替你做的那些决定,收回到自己手上。