1.2 提示词工程:把需求说清楚的艺术
工具箱项目刚开始那两周,我没少在提示词上吃亏。同一批重命名脚本的需求,前一次让 AI 生成,一遍过;后一次改了几个字的描述,生成的代码连文件都读不进去。折腾几次才反应过来:问题不在模型,在我的描述方式。后来我总结,所谓提示词工程,核心就一句话——把需求说清楚,说清楚的内容包括任务、输入、输出和约束。
这篇讲我怎么从随口一问,进化到用固定模板写提示词,以及模板每个字段为什么不能省。先剧透结论:提示词的回报率是全书所有技巧里最高的,因为它决定的不只是这一次生成的质量,还决定了后面返工的次数。
场景:同一个需求的两种问法
先看两个真实的对照。第一种问法,也就是我最初的样子:
帮我写个脚本,把照片文件名改一下,日期加分隔符。
AI 给了一段代码,函数名是 rename_photos,日期格式用的是斜杠,没处理序号,也没说怎么处理非照片文件。每个细节我都得再提一轮,来回五次才达到预期,总耗时快二十分钟——比手写还慢。五轮拉锯的账是这样的:
| 轮次 | 我的补充 | 它的新问题 |
|---|---|---|
| 第一轮 | 无 | 日期用了斜杠而非横杠 |
| 第二轮 | 日期改横杠 | 没加序号 |
| 第三轮 | 加三位序号 | 没跳过非照片文件 |
| 第四轮 | 跳过非照片 | 覆盖同名文件 |
| 第五轮 | 同名跳过加日志 | 终于达到预期 |
五轮里没有一轮是模型犯蠢,每一轮它都忠实地执行了我给的字面指令——问题是我每次只说一句话,信息是挤牙膏式供给的。这张表后来贴在我显示器边上,每次想偷懒只写一句需求时就看一眼。
第二种问法,是后来的模板化版本:
任务:写一个 Python 函数 batch_rename(folder),重命名目录下的照片。 输入:folder 是字符串路径,内含 IMG_YYYYMMDD_HHMMSS.jpg 格式的文件。 输出:改名为 YYYY-MM-DD_HH-MM-SS_序号.jpg,序号三位补零,从 001 开始。 约束:跳过不符合格式的文件;目标文件已存在时跳过并打印日志;只用标准库。
一次通过,调试时间接近零。差别全在信息的完整度上。第一种问法里,日期格式、冲突处理、输出格式全是空白,AI 只能猜,猜中概率看运气;第二种问法把这几个洞全填上了,模型的工作从猜谜变成了翻译。后来我把这两种问法分别保存成了 bad 和 good 两个片段文件,新人进项目时先看这两个对照,比讲半小时概念管用。
方案:结构化提示词模板
被五轮拉锯折磨过之后,我把需求里每次都要重复澄清的点整理成了字段,固化成一个模板,整个项目里所有提示词都按它来。模板的价值不在格式好看,而在于它是一张检查清单——填不满的字段,就是你还没想清楚的需求。很多人觉得写提示词花时间,其实填模板比写需求文档快得多,真正慢的是不填模板导致的来回返工。
| 字段 | 作用 | 常见遗漏 |
|---|---|---|
| 角色 | 设定视角,比如你是资深 Python 工程师 | 不写也没大影响,但写了风格更稳 |
| 任务 | 一句话说明做什么,给出函数名 | 只给动词,不给命名和结构 |
| 输入 | 参数类型、数据样例、文件格式 | 忘了说编码和异常输入 |
| 输出 | 返回值、打印格式、文件命名 | 序号、补零、分隔符不明确 |
| 约束 | 只用标准库、不用 print 之外依赖 | 依赖范围不限,引入多余包 |
| 验收 | 给一个可对照的输入输出例子 | 完全不写,模型无法自检 |
其中验收这一栏最容易被忽略,但效果最明显。给一个具体的输入输出例子,等于让模型在生成时先跑一遍脑内测试,生成带 bug 的概率会显著下降。这个思路其实和写单元测试是一回事,只不过写在了提示词里。角色这一栏看似可有可无,实测对代码风格影响很大:不写角色时,模型偶尔会给教学风格的示例代码,满篇 print 调试和注释占一半;写了资深工程师之后,输出基本是直接能进项目的函数形态。
实际项目里,我把模板直接存在一个 snippets 文件里,每次开头:
角色:五年经验的 Python 工程师,偏好标准库和简单实现。
任务:实现 {函数名},{一句话描述}。
输入:{类型与样例}。
输出:{格式与样例}。
约束:{依赖与边界}。
验收:输入 {样例} 时,应得到 {期望结果}。
填空的时候有个顺序窍门:先写输入输出样例,再倒推任务描述。因为样例往往是脑子里最清楚的部分,描述反而含糊。验收样例定下来了,任务字段的措辞自然就准了。这个习惯帮我避免了无数次改来改去的需求拉锯,在 第三章接入大模型 API 时,模板反过来用在了给模型的系统提示词上,效果同样好——毕竟模型调用模型,沟通方式是一模一样的。
填完的版本长这样,可以直接感受一下信息密度:
角色:五年经验的 Python 工程师,偏好标准库和简单实现。
任务:实现 clean_excel(path),清洗销售明细 Excel。
输入:path 是 xlsx 路径,含列:日期、客户、金额,可能有空行和重复行。
输出:返回 pandas DataFrame,列顺序不变,删除空行,金额保留两位小数。
约束:用 pandas,不写文件,不做聚合。
验收:输入三行数据其中一行全空,应返回两行,金额列为 12.50 这种格式。
生成的函数一次跑通,连保留两位小数这种细节都处理对了——它用的是 round 而不是格式化字符串,因为约束里说了返回 DataFrame 而不是写文件,模型自己做了正确的区分。如果提示词里只写清洗一下表格,大概率得到的是一通 dropna 加 groupby 的自选动作。
模板之外还有一个小技巧很值:生成完先别看代码,让模型自己列一遍它做的假设。原话是这么问的:在这个实现里,你对输入数据做了哪些假设?如果输入不满足会怎样?。它通常会主动交代,比如假设金额列全是数字、假设日期列已排序。这些自白就是生成了多少隐性约束,而它们往往就是后面返工的爆点。三秒钟的追问,能换来一次合并时的安心。
踩坑:提示词的三个反模式
模板能覆盖大部分场景,但有几个坑是模板救不了的,需要单独记。
第一个坑是模糊形容词。需求里出现优雅、高效、健壮这类词,等于没说。一次我让模型写一个健壮的网页抓取函数,它加了重试、超时、缓存、UA 轮换,四层嵌套看得我头疼。不是我想要的结果,但它确实做到了字面上的健壮。从那以后,约束字段里我只写可测量的东西:超时 10 秒、重试 3 次、用 requests 库,不写形容词。
第二个坑是历史对话污染。多轮对话里,较早的约束会被后面的修改悄悄覆盖。我遇到过一次,第三轮让模型改异常处理,它顺手把第一轮定的输出格式也改了,而它自己完全没意识到。更隐蔽的一种是角色漂移:第一轮设定你是资深工程师,聊了十轮之后,语气和代码风格会慢慢退化成 新手问答 的味道,变量命名开始随意,注释开始灌水。后来涉及到约束变更,我宁愿开新对话,把模板重新填一遍,也不在旧上下文里缝缝补补。相关的话题在 3.4 多轮对话管理 那节有更系统的讨论。
第三个坑是上下文过载。把整个项目的十个文件全贴进提示词,让模型自己找重点,效果反而比只贴相关文件差。模型在一个长上下文里会迷失焦点,生成内容偏向文件开头和结尾。我的做法是手动筛两个文件以内,配上几句文字说明项目结构,比一股脑全倒进去管用得多。
第四个坑是行业术语不解释。项目里我自己造的词,比如把某一类任务叫晨间任务,提示词里直接写处理晨间任务,模型完全不知道这是啥,只能按字面猜成早上执行的定时任务,方向全错。术语不是不能用,但第一次出现时要给一句定义:晨间任务,指每天上班前需要跑的一批固定数据同步脚本。定义一句话,省掉一整轮澄清。
这四个坑整理成对照表:
| 反模式 | 典型表现 | 修正做法 |
|---|---|---|
| 模糊形容词 | 要健壮、优雅、高性能 | 换成可测量指标 |
| 历史污染 | 改一处动全身 | 约束变更就开新对话 |
| 上下文过载 | 十个文件全贴 | 只贴相关文件加结构说明 |
| 术语不定义 | 自造词直接用 | 首次出现附一句定义 |
小结
提示词工程不是话术,是需求工程。把任务、输入、输出、约束、验收样例五项写全,生成代码的可用率会从三成提到九成以上。这比研究各种花哨技巧都有效,也是整本书后续每一篇的前置技能——第二篇的脚本实战 里你会看到大量按模板写出的需求如何一次跑通。如果你只有时间记住一件事,就记住:先写输入输出样例,再倒推描述,顺序对了,一切都顺。
下一篇 1.3 代码审查 讲生成代码到手之后的下一道工序:怎么在不闭眼信任的前提下,快速判断它能不能合并进项目。
工具箱后来部署在腾讯云上,相关的活动入口放在 AI 办公助手活动页,新入手服务器时可以对比一下价格。
