别描述,给例子:few-shot prompting
两个例子比三段说明更管用。为什么上下文学习有效,以及怎么写出真正顶用的例子。
描述一种格式很难,展示一种格式很简单。
拿一段解释日期该怎么标准化的文字,跟下面这个比一比:
输入:「下周二」 → 输出:RELATIVE
输入:「3 月 3 日」 → 输出:ABSOLUTE_PARTIAL
输入:「2026-03-03」 → 输出:ABSOLUTE_FULL
输入:「春天某个时候」 → 输出:VAGUE四行字,所有你本来得用文字预先交代清楚的歧义就都解决了。这就是 few-shot prompting,也是实战中写 prompt 时投入产出比最高的单个技巧。
为什么有效
模型在预测接下来是什么。你的例子建立起一个模式,而最合理的续写就是这个模式的又一个实例。
你并没有教会模型任何东西——没有任何参数改变,这次请求结束之后什么也不会留下。你是在构造一个上下文,让想要的输出成为最自然的下一句。这叫做上下文学习(in-context learning),而这里的「学习」是个比喻:它就是单次前向传播内的一次模式补全。
这个机制的一部分,似乎涉及某些注意力头:它们会找到当前模式在更早位置的出现,并预测上次后面跟的是什么。你的例子给了这些头可找的东西。
数量
Zero-shot——只有指令。对于输出显而易见的常见任务够用。
One-shot——一个例子。相比 zero-shot 常常跃升很大,因为它把格式完全钉死了。
Few-shot——通常两到五个。大多数工作的最优区间。
Many-shot——几十个。当任务确实存在边界情况时值得这么做,而且在如今的大上下文窗口下也变得可行。收益会递减,而每个例子都会在每一次请求里消耗 token。
从零个例子到一个例子,通常比从四个加到八个更有用。
造出管用的例子
**覆盖边界,而不是中间。**例子应该选你会做错的那些,而不是显而易见的那些。如果难点在于区分两个类别,那就把最靠近分界线的那一对放进去。
**格式要死板。**每个例子结构相同、分隔符相同、空格相同。你的例子里有不一致,就等于允许输出也不一致。
**类别要平衡。**四个正例加一个反例,会让预测偏向正面。顺序也有影响——末尾连着出现同一个标签,会带偏后面的内容。
**把难看的例子也放进去。**如果输入有时是空的,就展示一个空输入以及该怎么处理。如果有些输入没有有效答案,就展示一个,并展示拒答的样子。
**贴合你的真实分布。**从真实数据里取出来的例子,比编出来的效果好,因为编出来的往往比现实更干净、更整齐。
它比别的做法强在哪
**规定格式。**任何有特定形状的东西——JSON、分类标签、某种特定语气。
难以用语言描述的任务。「按我们内部的风格改写这段」用文字说几乎不可能,给三组改前改后的对照却很简单。
**处理边界情况。**与其逐条列举规则,不如把刁钻的输入和它们正确的处理方式展示出来。
**多次调用之间保持一致。**固定的例子让输出整齐得多,当下游代码要解析它时,这一点很要紧。
它帮不上忙的地方
**补充知识。**例子展示的是形式,不是事实。如果模型不知道你产品的定价,例子也提供不了——那需要检索。
**真正困难的推理。**对于多步问题,推理过程的例子是有用的——但那是思维链,例子要包含演算过程,而不只是答案。
**很长的输出。**few-shot 效果最好的时候,是例子短到能放进去好几个。对于长篇生成,一个例子加上说明通常就是实际的上限。
成本
例子就是 token,每一次请求都要带上。二十个例子、每个 50 token,就是每次调用 1,000 token 的额外开销。
两种缓解办法。把例子放在 prompt 开头一个固定的位置,好让前缀缓存生效。另外,如果你有几百个例子、任务量又大,那么微调就开始在经济上说得通了——它把模式搬进权重里,从而去掉每次请求的那笔开销。
要点回顾
- 例子建立起一个模式,模型把它续写下去;没有任何东西被学到或留下。
- 从零到一是提升最大的一步;两到五个能覆盖大多数情况。
- 选边界用例,格式死板一点,标签要平衡,把难看的输入也放进去。
- 极适合格式和难以描述的任务;对于补充缺失的知识毫无用处。
- 例子每次请求都要花 token——缓存前缀,量大时考虑微调。
下一篇: 让模型一步步思考