Prompt Engineering:在黑盒外修修补补
本系列文章将从提示词工程出发,逐步讨论人类如何提升对大模型行为的控制能力:从优化提问方式,到设计输入环境,再到连接外部能力,最终形成可复用的能力单元。
换句话说,我们关注的不只是“如何让模型回答更好”,而是“如何让模型稳定地完成工作”。
本篇是系列的第一篇,我们先从最直观的部分开始:如何写 prompt。
在大模型刚被广泛使用时,人们普遍认为模型表现的好坏,取决于提问方式是否足够清晰。于是各种提示词技巧逐渐出现,例如示例学习、逐步思考等方法。
本文将系统梳理这些常见的提示词策略,并理解它们为何有效 —— 以及它们的边界在哪里。
很多人在刚接触大模型时,会形成一个非常直觉的理解:
大模型 = 输入一段文字 → 输出一段文字
从表面上看,这个理解没有任何问题。对大多数人来说,大模型确实就像一个黑盒:你喂给它一段字符串,它返回给你另一段字符串。于是,一个看似合理的结论就出现了:只要我把 prompt 写好,模型的回答就会变好。
这也是「提示词工程(Prompt Engineering)」最早流行起来的原因。
那么如何能够将提示词写好呢?
对于绝大数人来讲,写提示词基本等同于暴露自己的语文水平,语文水平好的人,能够清晰的向大模型传达自己的需求,语文水平差一点的人,可能半天都问不对问题。
这种提示词我们称之为 一般提示词,或者称之为 zero shot。
zero-shot 这个名称的含义是“没有示例”。这是最简单的一种 prompt 类型。它只提供任务的描述,以及一些供 LLM 开始生成的文本。这个输入可以是任何形式:
- 一个问题
- 一段故事的开头
- 或者一条指令
当 zero-shot 无法满足需求时,可以在 prompt 中加入示例或演示,这就引出了 “one-shot” 和 “few-shot” prompting。
One-shot & few-shot
当你在给 AI 写 prompt 时,很多时候光靠一句话是说不清需求的。这时候,最直接有效的办法就是:给它看例子。例子其实是在告诉模型两件事:
- 你到底想让它干什么
- 最终结果应该长什么样
尤其是当你希望 AI 按某种固定格式输出,或者遵循某种模式时,示例往往比长篇解释更有用。
- 如果只给一个示例,这种方式叫 one-shot。本质上就是:给模型一个“参考答案”,让它照着学。
- 如果给多个示例,就是 few-shot。通过多展示几次相同的模式,模型更容易抓住规律,从而按这个规律生成结果。
至于要给多少个示例,并没有绝对标准,通常取决于:
- 任务有多复杂
- 示例是否清晰、有代表性
- 模型本身的能力
经验上,3~5 个示例通常就能让模型理解模式;任务越复杂,可能需要更多。但示例越多,占用的输入空间也越大,因此有时也需要适当减少。
few-shot prompting 示例:
例子:
评论:这个产品真不错,用得很顺手! → 情感:正面
评论:完全失望,质量太差了。 → 情感:负面
评论:快递到了。 → 情感:中性
评论:外观还行,性能一般般。 → 情感:
例子:
句子:马云是阿里巴巴的创始人。
实体:[马云: 人名], [阿里巴巴: 组织]
句子:乔布斯出生在旧金山。
实体:[乔布斯: 人名], [旧金山: 地点]
句子:李雷明天去北京出差。
实体:
例子:
姓名:张三,年龄:28,职业:工程师
→ {"name": "张三", "age": 28, "job": "工程师"}
姓名:李四,年龄:35,职业:设计师
→ {"name": "李四", "age": 35, "job": "设计师"}
姓名:王五,年龄:40,职业:产品经理
→
Step-back prompting
有时候我们直接把问题丢给 AI,它反而答不好。但如果先让它想一想“相关的原理是什么”,再去回答具体问题,效果往往会明显变好。
这就是 Step-back prompting 的思路:先退一步,再解决问题。
做法其实很简单 —— 不是一上来就问目标问题,而是先问一个更一般、更基础的问题,让模型先进入正确的思考状态;然后再把原问题交给它。
这个“退一步”的过程,相当于帮模型热身:
- 先把相关知识调出来
- 再开始推理
- 最后给出答案
因为模型先理解了原理,再处理细节,所以回答通常会更完整、更有条理,也更不容易跑偏。相比直接提问,这种方式更容易让模型用对知识,而不是靠概率猜测。
另外,它还有一个额外好处:当模型先围绕通用原则思考时,就不太容易被某些局部信息带偏,从而减少一些不合理或片面的回答。下面是一些 Step-back prompting 的示例。
示例 1:知识问答(事实类)
直接提问:
问题:为什么冰箱里的食物更容易保存更久?
Step-back prompting:
问题1:食物腐败通常是由哪些因素造成的?
回答1:主要由微生物繁殖、酶促反应和化学反应引起。
问题2:为什么冰箱里的食物更容易保存更久?
效果:模型先激活“腐败原理”,再回答具体问题,解释会明显更完整。
示例 2:数学/推理
直接提问:
小明买了3支笔,每支5元,又买了一个本子12元,一共花多少钱?
Step-back prompting:
问题1:解决购物总价问题的一般步骤是什么?
回答1:先分别计算每种商品的小计,再将所有小计相加。
问题2:小明买了3支笔,每支5元,又买了一个本子12元,一共花多少钱?
效果:模型更稳定,不容易漏乘或直接相加出错。
Chain of Thought
先来一道简单的乘法题:
369 * 1235 是多少?
你可能会觉得这不算什么难题,但早期的大模型经常会翻车:要么算错,要么答案乱飘。
为什么会这样?
因为大模型本质上是在从左到右预测下一个词元,数字也是“预测”出来的,并不是像计算器那样真的在做运算。所以遇到这种需要严谨计算或多步推理的问题,它很容易中途走偏。
那怎么办?
一种非常有效的办法叫 Chain of Thought:别让模型直接报答案,而是先让它把中间推理过程走一遍。做法也很简单,在问题后面加一句类似 Let's think step by step 的话,常见的提示词包括:
- 请一步一步思考
- 请解释你的推理过程
- 请详细说明你是如何得到这个答案的
CoT 可以与 few-shot prompting 结合使用,zero-shot 场景下结合 CoT 被称之为 零样本思维链策略(zero-shot-CoT strategy),最早由 Kojima 等人于 2022 年发表在一篇名为“Large Language Models Are Zero-Shot Reasoners”的科学论文中。
- 零样本:不提供示例(不给它参考答案)
- 思维链:要求它按步骤推理,再得到结果
CoT 之所以被广泛使用,是因为它有几个很实际的好处。
首先,它几乎没有额外成本,但效果往往很明显。
你不需要重新训练模型,也不用准备示例数据,只要在问题后面加一句“请一步一步思考”,很多推理类问题的正确率就会立刻提升。
其次,它让模型的回答变得更“看得懂”。
模型不再只给你一个结果,而是把中间过程写出来。这样一来:你能理解它为什么得到这个答案,如果出错,也更容易看出是在哪一步推歪了
最后,思维链还能让 prompt 更稳定。
同一个问题换不同模型时,结果通常会有波动;但如果让模型先按步骤推理,再给答案,这种波动往往会变小。换句话说,相比直接问结果,带推理过程的 prompt 更不容易“忽然变笨”。
下面是一些典型的写法示例:
Q: 小明有 3 个苹果,小红给了他 2 个苹果,然后他吃掉了 1 个。问他现在有几个苹果?
请一步步思考。
Q: 如果所有猫都会爬树,汤姆是猫,那么汤姆会爬树吗?
请一步步思考。
Q: 今天是星期三,那么 10 天后是星期几?
请一步步思考。
Q: 小王有 4 支红笔和 5 支蓝笔,他给了朋友 2 支蓝笔和 1 支红笔。现在他还有几支笔?
请一步步思考。
Q: 如果下雨了,地会湿;如果地湿了,孩子们就不能出去玩。现在下雨了。那么孩子们能出去玩吗?
请一步步思考。
最后用一句话总结:逐步思考 = 在没有示例的情况下,要求模型先推理、再作答。
Self-Consistency
在前面我们介绍了 CoT,它能显著提升模型在推理问题上的表现,但很快人们又发现了一个现象:
即使让模型一步一步推理,它仍然会算错。
而且这种错误往往很“随机” —— 同一个问题,多问几次,有时对、有时错。
为什么会这样?
因为大模型在生成推理过程时,本质上仍然是在做概率采样。也就是说:推理路径不是唯一的。有些路径会走到正确答案,有些则会中途偏掉。
既然一次推理不可靠,那最直接的办法就是:多推理几次,再做决定。
这就是 Self-Consistency(自洽性) 的核心思想:
- 让模型对同一个问题进行多次逐步推理
- 得到多条推理路径
- 统计最终答案
- 选择出现次数最多的那个结果
也就是 —— 不相信某一次推理,而相信“多数推理的共识”
它和 CoT 的关系可以简单理解为:
- CoT:让模型思考
- Self-Consistency:让模型多想几次再回答
下面来看一些具体的示例:
普通 CoT:
Q: 小明有 3 个苹果,小红给了他 2 个苹果,然后他吃掉了 1 个。现在他有几个苹果?
请一步步思考。
模型可能得到:
3 + 2 = 5
5 - 1 = 4
答案:4
但也可能出现:
3 + 2 = 6
6 - 1 = 5
答案:5
Self-Consistency 的做法则是让模型多回答几次(例如 5 次):
回答1:4
回答2:4
回答3:5
回答4:4
回答5:4
最终选择多数结果:
最终答案:4
再看一个推理题
Q: 一个班有 30 个学生,其中一半是男生。后来又转来 6 名女生,现在男生占多少比例?
请一步步思考。
单次推理可能出错,但多次推理后,大多数路径会收敛到:
男生:15
总人数:36
比例:15 / 36 ≈ 41.7%
Self-Consistency 就是利用这种“答案收敛现象”来提高正确率。
如何触发 Self-Consistency
Self-Consistency 不是在 prompt 里加一句固定话就能完成的。它的关键不在“写什么”,而在“问几次”。
具体的做法是:对同一个问题多次提问,并让模型保持一定随机性,然后统计答案。
简单流程:
- 使用 CoT 提示词(例如:请一步一步思考)
- 多次调用模型(例如 5~10 次)
- 收集所有最终答案
- 选择出现次数最多的结果
示例(伪代码):
for i in range(5):
ask("请一步一步思考:小明有3个苹果...")
可能得到:
4
4
5
4
4
最终答案取多数:
4
关键点在于需要允许模型产生不同推理路径(通常通过 temperature > 0),否则每次结果都会一样。
一句话总结:Self-Consistency 的触发方式不是“改写 prompt”,而是“重复推理并投票”。
Tree of Thoughts
在 Self-Consistency 中,我们的做法是让模型多推理几次,然后从多个结果中选一个最合理的答案。
但这里有一个问题:模型每一次推理,都是一条完整走到底的路径。如果一开始方向就错了,那么整条推理都会偏掉 —— 即使多试几次,也只是多走了几条错误路线。
于是人们开始思考:能不能不要等推理结束再比较?而是在推理过程中就判断“这条路对不对”?
这就是 Tree of Thoughts(思维树) 的核心思想。
- 普通 CoT 的过程更像这样:选一条路 → 一直走到底 → 得到答案
- ToT 的过程则是:每走一步 → 评估一下 → 选更合理的分支继续
也就是说,模型不再只有一条“思维链”,而是同时探索多种可能,并在过程中进行筛选。
可以把它想象成走迷宫:
- CoT:随便选条路,一直走
- Self-Consistency:多进几次迷宫,看谁先出来
- ToT:每到路口先看看地图,选更可能正确的方向
例如:使用 2、3、7、8 四个数字,通过加减乘除得到 24
普通 CoT 可能这样:
(8 × 3) = 24
24 + 7 = 31
31 − 2 = 29 ❌
路径走错,就结束了。
ToT 的思路则是在中间步骤就进行评估。
候选步骤1:
8 × 3 = 24
→ 已接近目标,保留
候选步骤2:
7 × 2 = 14
→ 距离目标较远,优先级降低
继续展开:
24 = 24 + (7 − 2)
成功
关键点:模型在推理过程中不断比较“哪一步更有希望”,再继续展开。
再例如:设计一个支持撤销功能的文本编辑器状态管理方案。
CoT 思路下,模型可能这样推理:
- 用 useState 保存当前文本
- 每次修改时记录旧值
- 再用一个数组保存历史记录
- 撤销时回退数组最后一项
这是一条线性设计思路。问题在于:
- 如果后来发现需要 redo?
- 如果状态很大怎么办?
- 是否应该用 reducer?
线性思考可能中途才意识到架构不合理。
ToT 思路下模型会并行考虑多个方案:
- 分支 A:使用 useState + history 数组
- 分支 B:使用 useReducer 管理状态栈
- 分支 C:使用 command pattern
- 分支 D:使用 immutable 数据结构 + 时间旅行调试模式
然后评估:
- 哪个扩展性最好?
- 哪个性能更优?
- 哪个实现复杂度最低?
最后选择一个最优方案。
如何触发 Tree of Thoughts
ToT 也不是一句固定提示词,而是一种“分步交互”的提问方式。
核心是:不要一次问完整问题,而是把推理拆成多轮,让模型在中间步骤进行评估和选择。
基本流程:
- 先让模型生成多个候选思路
- 让模型评估这些思路的可行性
- 选择更好的思路继续展开
- 重复以上过程直到得到答案
示例交互:
Q: 使用 2、3、7、8 得到 24
请先给出三种可能的计算方向
模型:
A: (8×3)优先
B: (7×2)优先
C: 加法组合优先
继续:
请评估哪个方向更接近 24,并继续推理
可以不断迭代,直到收敛到答案。
一句话总结:ToT 的触发方式是“多轮分支推理 + 中途选择”,而不是一次性提问。
RCT构词法
当提示词技巧越来越多之后,很多人会遇到一个新问题:明明知道很多技巧,但写 prompt 时依然很乱。
- 有时候信息写了一大段,模型却抓不到重点
- 有时候需求很清楚,结果却跑偏。
问题的根源在于,不是技巧不会用,而是信息没有组织结构。于是有人开始把 prompt 当成一段“自然语言程序”,既然是程序,就需要基本结构。这就出现了一个简单但非常实用的写法:RCT 构词法。
RCT 分别代表三类信息:
- Role(角色):模型应该以什么身份回答
- Context(上下文):当前问题的背景信息
- Task(任务):你希望它完成什么具体工作
也就是说,不再直接向模型提问,而是先交代“你是谁、现在什么情况、你要做什么”。
普通写法:
给我一个午餐建议
模型往往会给出泛泛的答案。
使用 RCT:
你是一名营养师(Role)
我正在健身,坚持16+8间歇性饮食(Context)
请给我一个适合的午餐建议(Task)
回答会明显更贴合需求。
一个标准的,符合 RCT 结构的提示词模板如下:
你是一个 [角色],
现在的背景是 [上下文],
请你完成如下任务:[任务描述]。
或者
假设你是 [角色]。
请基于以下上下文:[上下文内容]。
你的任务是:[任务目标 + 要求]。
写在最后
回顾整篇文章,我们介绍了多种提示词技巧。从最基础的 zero-shot、few-shot,到 step-back、CoT,再到 Self-Consistency 与 Tree of Thoughts,看起来像是在不断叠加新的方法。但如果从更高的视角去看,这些技巧其实可以分成三个层级。
第一层:补充信息,让模型“看懂”。
- One-shot
- Few-shot
当模型不知道你要什么时,就给它示例。本质上是在增加统计线索,让它更容易匹配模式。
第二层:引导思考,让模型“会想”。
- Step-back prompting
- Chain of Thought
当模型容易乱想、跳步、推理不完整时,就要求它一步一步推理。本质上是在约束推理路径,而不是直接索要结果。
第三层:控制搜索,让模型“不拍脑袋”。
- Self-Consistency
- Tree of Thoughts
当单条推理路径不可靠时,就让模型生成多条路径、做中途评估或投票。本质上已经从“单条推理”升级为“多路径搜索”。
而到了最后的 RCT 构词法,我们开始做另一件事情 —— 不再只关心模型如何思考,而开始关心:人类应该如何结构化地表达输入。如果说前面的技巧是在“干预模型的思考过程”,那么 RCT 则是在“规范人类的输入方式”。
至此,我们其实已经可以看到一个趋势:
- 从一开始单纯优化 prompt 写法
- 到后来逐步干预模型的推理方式
- 再到控制搜索路径
我们正在做的,已经不再只是“把问题问好”,而是逐渐意识到:模型的表现,不仅取决于 prompt 的措辞,更取决于它在生成时能看到哪些信息,以及这些信息是如何被组织的。
而这,正是下一篇文章要讨论的主题 —— 从提示词工程,走向上下文工程。
好啦,今天的内容就分享到这里啦,我们下一篇文章再见👋
-EOF-