上一章《评测、基准与幻觉》说:单次分数不算数——这一章说明它为什么会飘。
2020 年 GPT-3 的论文发现:写几个例子,模型就能做训练时没教过的事——
这不是
在有「上下文学习」之前,让模型学会一个新任务的流程是这样的: 标注几千条数据 → 微调 → 得到一个专用模型。每次换任务都得重来一遍。
上下文学习把这个流程压成了一句话:
它从来没有被训练过"把词重复一遍"这个任务。它是从你给的两个例子里,现场推出的规律。
零样本 Zero-shot:不给例子,直接问。
单样本 One-shot:给 1 个例子。
少样本 Few-shot:给几个例子(通常 4~8 个)。
区别只是你给了几个例子,模型本身没有任何变化。
注意:此处的「零样本」说的是提示里给不给示例;CLIP 的「零样本分类」是另一回事——
指不针对该类别训练。见 ViT / 多模态章。
互动 · 「给几个例子」到底改了什么
像找一个见多识广但从没上过这门课的人。
你不教他理论,只是给他看两道例题,然后递上第三道。他看一眼就说:"哦,你是想让我把字重复一遍。"
他不是学会了这个任务,他是认出了这个任务的模式。
这就是上下文学习最接近真相的描述——它更像识别,而不是学习。
答案藏在
模型在
同一副骨架,可以装任何任务
模型在
为什么给例子比讲规则更有效?因为例子直接匹配了模型在
下面这个演示实现了一个"模式归纳器"—— 内置一池候选规则(重复、反转、取后两个字、加后缀……), 用你给的例子给每条规则打分,再用得分最高的规则去预测。 然后拿一整套测试任务跑一遍,统计这个示意模型自己的准确率。
先说明:本节和下面的曲线、读数都来自本页自搭的示意模型,它只把「只读最前面几个例子」和「注意力饱和」写成两条规则——趋势与真实大语言模型(LLM)一致,不是对某个真实模型的实测。
互动 · 示意模型里,例子数量对准确率的影响
互动 · 每多一个例子,能排除掉多少种可能
上面那条虚线(还活着的候选规则)就是「例子越多越准」的全部机制:每多给一个例子,能被解释的候选就少一批;两三个之后通常只剩一条,预测就唯一了。 准确率猛涨不是模型变聪明,是能被误选的规则已经被筛没了。
| 例子个数 | 会发生什么 |
|---|---|
| 太少 | 模型抓不住规律 |
| 4~8 个 | 最好——「少样本」的「少」不是客气话,它真是个最优区间 |
| 太多 | ① 例子占满上下文,真正的任务说明被稀释;② 例子之间可能冲突(同一个输入不同标签);③ 上下文越长,中间部分越容易被忽略(Lost in the Middle:关键信息放在长上下文中间时最容易被漏掉,见《RAG 检索增强》) |
理论上,示例的顺序不应该影响结果——它们提供的信息是完全一样的。 但实际上影响非常大。而且这个影响不是随机的。
互动 · 同一批例子,打乱顺序后的波动
互动 · 同一批例子,只换顺序,准确率会跳
互动 · 模型会照抄示例里的标签比例(标签偏置)
| 效应 | 表现 | 机制猜测 |
|---|---|---|
| 位置偏好 | 最前面、和紧挨着查询的例子,影响都比较大;中间的最弱 | 在 |
| 标签偏置 | 如果例子里"正面"出现得比"负面"多,模型会倾向答"正面"——哪怕查询明显是负面的 | 模型从示例里算了标签的先验分布,并把它当成了答案的先验 |
| 随机改错标签 | 把示例里的标签随机改错,性能几乎不掉——典型只降 0–5% | 说明模型主要依赖示例的格式和标签空间,而不是标签是否正确 |
| 示例格式的一致性 | 示例文本和标签的分隔符是否统一,影响很大 | 格式是模型识别"这是对照表"的信号 |
如果你的提示效果对示例顺序敏感,那么:
① 你测出来的效果不稳定——换个顺序可能差 10 个点;
② 你看到的"某次调用效果特别好"很可能是运气,不是提示写得好;
③ 上线后用户输入变化,顺序效应会以你无法复现的方式影响结果。
正确做法:评估提示时至少跑 5~10 种随机顺序,看均值和方差。只看单次结果的自测是没有意义的。
推荐的摆法:把最有区分力的例子放最前面(这个示意模型的窗口只读最前几个);把和查询最像的那个放最后(真实模型通常在结尾处读得更清)。
下面是真正被验证有效的几条。注意:每一条都有一个"为什么", 而不是"大家都这么做"。
互动 · 为什么「一步步想」有用:把一步大计算拆成几步小计算
把上面四条放在一起看,会发现它们是同一个逻辑的不同侧面:
模型的行为由"当前上下文最像训练数据里的什么"决定。
· 角色设定 → 让上下文更像某类语料
· 输出格式约束 → 缩小候选空间,让"最像的那个"更明确
· 分步骤 → 把串行推理外化,让每一步都变成独立的、简单的模式匹配
· 示例顺序 → 改变了上下文的形状,从而改变了"最像什么"
提示工程本质上是在做"上下文检索":不用去数据库里查,要的是在模型的训练分布里找到最匹配的那块区域。
| 症状 | 真实原因 | 怎么修 |
|---|---|---|
| 输出格式时对时不对 | 你只在指令里描述了格式,没有在示例里展示它 | 在示例里就把格式写死。用 JSON 就每个示例都是 JSON |
| 约束互相打架 | "要详细" + "不超过 50 字" + "覆盖所有要点"——三条在长回答上不可兼得 | 给约束排优先级,或者干脆减少约束数量 |
| 关键信息被忽略 | 上下文很长时,开头和结尾被记住的概率远高于中间(Lost in the Middle) | 把最重要的指令重复一次放在最后,或把关键材料放开头 |
| 混入了无关内容 | 无关文本会稀释信号,而且可能意外匹配到别的模式 | 删掉所有"以防万一"的补充说明 |
| 换个模型就废了 | 提示是针对某个模型过拟合出来的——它利用了那个模型的特定偏置 | 写提示时保留"为什么这样写"的理由;换模型要有回归测试集 |
| 示例写错了但效果更好 | 如果示例标签全是同一个,模型会学到这个偏置,在某些测试集上"看起来"准确率更高 | 这是假的提升。检查示例的标签分布是否均衡 |
互动 · 上下文越长,中间那段越容易被忘记
写提示像给一个极其聪明但从没来过你公司、而且看不见你表情的新同事写工单。
他不会问你,也不会猜你的意图——他严格按字面理解,并且会下意识地模仿你给的任何样例。
所以:你说的话会被字面执行,你做的示范会被完全照抄。
当这两者冲突时,他通常听示范的。
互动 · 点一下看每一步在改什么
互动 · Self-Consistency:多采几条一起投票,值不值
| 方法 | 核心做法 | 什么时候值得用 |
|---|---|---|
| Zero-shot | 直接下指令,不给例子 | 任务简单、模型足够强。迭代最快 |
| Few-shot | 给 4~8 个示例 | 最通用的做法。任务是"照格式做事"时尤其有效 |
| CoT 思维链 | 要求"一步步想",或示例里就带推理过程 | 数学、逻辑、多跳推理。本质是把串行计算外化到上下文 |
| Self-Consistency | 采样多条推理路径,对答案投票 | 有唯一正确答案的任务。代价是 N 倍成本 |
| ReAct | 让模型交替进行"推理"和"调工具" | 需要外部信息或计算的任务(《Agent 与工具调用》的基础) |
| APE / OPRO | 让模型自己生成并迭代优化提示 | 有明确评估指标、且你愿意跑很多次调用时 |
| DSPy | 把提示当成可编译的程序,用数据自动调优 | 有几十到几百条标注数据、想要可复现的流水线时 |
前面说模型会「现场归纳规律」。把它拆开其实只有两步: 每条候选规则先算一个分,再用分数投票。 下面这张表就是那两步——拖一下例子个数,看规则一条条被淘汰。
默认给了 3 个例子,但模型只读最前面的 2 个(注意力饱和),多出来的第 3 个不参与打分——所以下面公式里的分母是 2。
互动 · 一张打分表:九条规则,谁还活着
这张表就是这一章唯一的公式(上面那张卡)在跑:c 是「能解释几个被读到的例子」,π 是这条规则本身多常见,s 是两者的合成。 一个例子能排掉一批候选,但排得最少;到两三个例子之后,通常只剩一条规则能解释全部被读到的例子——预测就唯一了。
| 问题 | 说明 | 什么时候真的会痛 → 换什么 |
|---|---|---|
| 极度依赖模型 | 一条精心调过的提示,换一个模型版本可能直接失效。 模型升级本来该是好事,却变成了回归测试的负担 | 版本一升就翻车、要重调 → 写提示时保留「为什么这样写」的理由,建一组回归测试集(固定输入,用来确认改动没把原来好的弄坏) |
| 效果不可复现 | 温度不为 0 时,同一个提示每次结果不同;示例顺序一变效果就飘。 你没法像代码那样"跑一遍确认它还对" | 要可复现的线上效果 → 温度调低、示例顺序固定,并跑多种顺序看方差 |
| 脆弱得不像工程 | 加一个句号、把"请"去掉,效果可能变化。 这让提示变得难以维护——你不知道哪一句是真正起作用的 | 提示要长期维护、多人协作 → 别把它当代码管;用 DSPy 这类把它编译成可复现的流水线 |
| 上下文是花钱买的 | 示例越多,每次调用的输入 |
调用量大、按 token 计费 → 停在曲线的拐点(3~4 个示例),别靠堆示例 |
| 无法真正"教"新知识 | 上下文学习只能激活模型已经会的能力或模式。 它学不会训练数据里完全不存在的东西 | 要灌新知识 / 新语言 → 继续预训练(把知识写进权重)或 《RAG 检索增强》;行为类微调做不到这件事(见 《LoRA 与高效微调》) |
| 提示本身可能被攻击 | 用户输入里如果混进"忽略以上指令",模型可能照做。 这是提示注入(Prompt Injection) | 用户输入不可信、会拼进提示 → 见 《对齐、安全与越狱》 |
互动 · 例子越多,每次调用越贵
互动 · 把两边放一起:每多花一千 token,能换回多少准确率
这一章只推了一条公式(就在上面「数学」那节),但它仍然落在七条线里某一条上。
回到第 4 节那张“打乱顺序后的波动”。把「例子个数」滑杆拖到 6, 再看那几根柱子的高度差——同一批例子,只是换个顺序,准确率就上下跳。
那个跳动就是“触发,不是教学”的证据:如果模型真在学一套固定规则,顺序不该有这么大影响。 它在乎,说明答什么取决于上下文里放了什么——这是一次前向的匹配,不是权重里的稳定知识。 如果你刚才没有想指着那几根柱子说这句话,这一节对你就是没用的——回到图上再拖一次。
互动 · 只看一次结果,等于只看运气
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 一个提示 = 系统指令(平台预先设定、用户看不见的那段)+ k 个「输入→输出」例子 + 1 个查询,全部拼成一条 token 序列;模型只在最后一个位置取出一个概率分布,权重零更新 |
| C 参数账本 | 0 个参数被更新——全站唯一训练成本为零的一章。但推理成本不是零:7B 模型 fp16 权重约 14 GB,每生成一个 token 都要把它基本读一遍;提示从 2-shot 加到 8-shot,输入长度约翻 3~4 倍。KV 读写随 token 数线性增长,注意力算力是平方级 |
| F 违背了哪个直觉 | 直觉是「不更新权重就没法学新东西」;这一章整个在说:不更新权重也能改行为 |
它接住了上一章的什么:《评测、基准与幻觉》讲的是怎么判断模型行不行; 这一章解释为什么同一个提示的分数会飘——看单次结果不算评测,得跑多种顺序。
它给下一章留了什么:例子多到放不下时,得先按相关度把最该放的那几条挑出来 → 《向量嵌入与检索》。再往后,有些任务靠措辞永远做不成,那就得动权重 → 《LoRA 与高效微调》。
上下文学习 = 不更新任何权重,只在提示里给几个例子,模型现场归纳出规律——它做的是认出并延续预训练里见过的模式形状,所以示范比解释有效。
顺序和标签比例会明显改变结果,评估提示必须跑多种随机顺序、看方差,不能只看单次。
上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。