上下文学习像临时做贝叶斯:为什么大模型不改权重也能跟着例子走

一篇从零开始的 In-Context Learning 深度讲解:模型没有更新权重,却能根据 prompt 里的几个例子临时跟上任务。一个有力解释是,它在上下文里推断当前任务是什么。

有个现象非常神奇:

苹果 -> apple
香蕉 -> banana
猫 -> ?

大模型会答:

cat

再换一种:

苹果 -> 🍎
香蕉 -> 🍌
猫 -> ?

它又会答:

🐱

同一个模型,同一组权重,没有重新训练,只是 prompt 里的例子变了,它就临时换了任务。

这叫 In-Context Learning,上下文学习。

问题是:

模型权重明明没变,它到底“学”了什么?

一个很有解释力的答案是:

它不是现场学习新技能,而是在猜“我现在被放进了哪种任务模式”。

这就是 “In-Context Learning as Bayesian Inference”,把上下文学习理解成临时做贝叶斯推断。

先把贝叶斯讲成人话

贝叶斯听起来很数学,但最核心的想法很简单:

你本来对世界有一个猜测,看到新证据后,更新这个猜测。

比如你听到厨房里有声音。

你心里可能有几个候选解释:

猜测一开始的可信度
家人在做饭50%
外卖到了30%
东西掉了20%

这叫先验,prior。它是你在看到更多证据前的初始判断。

然后你又闻到了炒菜味。

这个证据对“家人在做饭”很友好,对“外卖到了”也有点可能,对“东西掉了”就不太友好。

于是你的判断更新成:

猜测看到证据后的可信度
家人在做饭85%
外卖到了12%
东西掉了3%

这叫后验,posterior。它是看完证据后的新判断。

中间还有一个词叫似然,likelihood。它问的是:

如果某个猜测是真的,那我看到这个证据的可能性有多大?

贝叶斯推断就是把这三件事连起来:

  1. 先验:我原来觉得哪些解释可能。
  2. 证据:我现在看到了什么。
  3. 后验:看完证据后,我该更相信哪个解释。

公式长这样:

P(hD)=P(Dh)P(h)P(D)P(h \mid D)=\frac{P(D \mid h)P(h)}{P(D)}

这里的符号不用怕。

符号人话
h一个候选解释,也可以理解成一种任务
D已经看到的数据,也就是 prompt 里的例子
P(h)先验,我一开始多相信这个解释
P(D \mid h)似然,如果这个解释是真的,看到这些例子有多合理
P(h \mid D)后验,看完例子后,我现在多相信这个解释

整句话翻译成人话就是:

一个解释最后有多可信,取决于它一开始多可信,以及它能不能解释眼前这些证据。

上下文学习里的“隐变量”:当前任务是什么

现在回到大模型。

prompt 里给了几个例子:

苹果 -> apple
香蕉 -> banana
猫 -> ?

这几个例子本身不是最终答案。它们更像证据。

模型真正要猜的是隐藏在背后的任务:

候选任务能不能解释这些例子
中文翻译成英文很能解释
中文变成 emoji解释不了
输出拼音解释不了
输出水果类别只能解释一部分

“当前任务是什么”没有直接写出来,所以它是一个隐变量。

所谓隐变量,就是:

它很重要,但你不能直接看见,只能通过现象反推。

大模型在 prompt 里看到几个输入输出对,就像侦探看到几条线索。它不是重新训练自己,而是在内部提高某个任务假设的可信度。

一个极小数字例子

假设模型脑子里只有两个候选任务:

  1. T1:中文转英文。
  2. T2:中文转 emoji。

一开始,它不知道你想干嘛,所以先验各占一半:

任务先验
T1 中文转英文50%
T2 中文转 emoji50%

现在看到一个例子:

苹果 -> apple

如果当前任务真是中文转英文,看到这个例子很合理。我们给它一个似然 0.9。

如果当前任务真是中文转 emoji,看到 apple 而不是 🍎 就不太合理。我们给它一个似然 0.1。

贝叶斯更新前,可以把它想成“可信票数”:

任务先验似然相乘后的分数
T1 中文转英文0.50.90.45
T2 中文转 emoji0.50.10.05

把分数归一化,让它们加起来等于 1:

任务后验
T1 中文转英文90%
T2 中文转 emoji10%

只看一个例子,模型已经明显更相信“中文转英文”。

再看到第二个例子:

香蕉 -> banana

如果继续用同样的直觉,T1 再乘 0.9,T2 再乘 0.1:

任务上一步分数新似然新分数
T1 中文转英文0.450.90.405
T2 中文转 emoji0.050.10.005

归一化后:

任务后验
T1 中文转英文98.8%
T2 中文转 emoji1.2%

所以当你问:

猫 -> ?

模型最合理的输出就是:

cat

注意,这里没有任何权重更新。

变的是模型在当前上下文里对“任务是什么”的判断。

所以 ICL 到底学了什么

上下文学习里的“学习”,不是传统训练意义上的学习。

传统训练是:

看数据 -> 算 loss -> 反向传播 -> 改权重

上下文学习是:

看 prompt 里的例子 -> 在前向传播中形成当前任务判断 -> 按这个判断输出答案

权重没有变,变的是这一次推理过程里的内部状态。

可以把它想成:

模型长期训练得到很多“任务模式”的经验,prompt 里的例子帮助它临时选中其中一种模式。

这就像你去参加一个不说明规则的小测验。

题目给你:

2 -> 4
3 -> 9
5 -> 25
6 -> ?

你很快猜到规则是平方,所以答 36。

你不是刚刚才学会平方。你早就会。你只是通过前几个例子推断出“这次考的是平方规则”。

大模型的 ICL 也可以这样理解:

它不是从零学新技能,而是在上下文里识别并调用一个可能的任务结构。

更一般的公式:先猜任务,再预测答案

刚才只看了两个任务。真实情况里,候选任务可能非常多。

用数学写,就是:

  1. h 是一个候选任务。
  2. D 是 prompt 里的示例。
  3. x_* 是新输入。
  4. y_* 是要预测的新输出。

模型可以先根据 D 更新对任务的判断:

P(hD)P(h \mid D)

然后预测答案:

P(yx,D)=hP(yx,h)P(hD)P(y_* \mid x_*, D)=\sum_h P(y_* \mid x_*, h)P(h \mid D)

这句话的人话版是:

对每一种可能任务,都想一下它会给什么答案;再按“我有多相信这个任务”加权平均。

如果模型 99% 相信这是中文转英文,那 猫 -> cat 的概率就高。

如果模型 99% 相信这是中文转 emoji,那 猫 -> 🐱 的概率就高。

如果证据不够明确,模型就会摇摆。

比如:

苹果 -> apple
橘子 -> orange
牛奶 -> ?

这可能是中文转英文,也可能是“食物名转英文”。两个任务在这个输入上刚好都输出 milk,所以你看不出冲突。

但如果接着问:

跑步 -> ?

“中文转英文”会输出 running,而“食物名转英文”会觉得任务范围不对。上下文里的任务判断会影响模型如何处理边界情况。

线性回归小例子:不背答案,而是猜一条线

研究 ICL 时,很多论文会用线性回归做玩具实验。

例如,prompt 里给模型几个点:

x = 1, y = 3
x = 2, y = 5
x = 3, y = 7
x = 4, y = ?

人会猜:

y = 2x + 1

所以 x = 4 时,y = 9

从贝叶斯角度看,隐藏任务不是“中文转英文”这种离散任务,而是一条隐藏函数:

y = ax + b

这里的 ab 不知道,需要从例子里反推。

prompt 里的点越多,可能的直线越少;证据越强,模型对某条线的信心越高。

这就是为什么线性回归经常被用来研究 ICL:它足够简单,可以精确讨论“模型是不是在上下文里学了一个函数”。

相关研究发现,Transformer 在某些受控任务上确实能表现得像在上下文里执行某种学习算法。这个算法有时接近最小二乘,有时接近梯度下降,有时又能被贝叶斯视角解释。

参考入口:What Can Transformers Learn In-Context?,以及 Transformers Learn In-Context by Gradient Descent

为什么预训练会让模型拥有这种能力

大模型预训练时看的不是孤立句子,而是大量连续文本。

连续文本里天然有隐藏规律:

  1. 一篇文章有主题。
  2. 一段代码有风格。
  3. 一个表格有列含义。
  4. 一组问答有固定格式。
  5. 一个对话有角色关系。

模型训练目标是预测下一个 token。

要预测得好,它不能只看前一个词,还要推断更大的上下文状态:

这是什么文体?
现在是谁在说话?
用户想要什么格式?
前面几个例子暗示了什么规则?
当前文本属于哪种任务模式?

所以,预训练可能迫使模型学会一种能力:

从上下文里反推隐藏结构。

这正好像贝叶斯推断。

Xie 等人的解释是,如果预训练数据本身有长程一致性,比如同一篇文档里共享主题或隐含概念,那么为了预测下一个 token,模型就需要根据已经看到的上下文推断这个隐藏概念。于是,在下游 prompt 里,几个示例也能被当成证据,用来推断当前任务。

参考入口:An Explanation of In-context Learning as Implicit Bayesian Inference

这和“模型记住了模板”有什么区别

有人会说:

这不就是记住了很多模板吗?

一部分确实可能是模板。大模型肯定见过大量 输入 -> 输出 的格式。

但 ICL 更有意思的地方在于,它不只复读固定模板,而是能根据例子临时适配:

blit -> A
dax -> B
wug -> A
zorp -> ?

如果前面例子暗示了某个抽象规则,模型可能会尝试跟随这个规则,即使这些词没有真实含义。

贝叶斯视角会说:

模板只是候选任务的一种。模型真正做的是在许多候选解释之间重新分配可信度。

这也解释了为什么示例顺序、数量、格式会影响结果。

因为这些都会改变模型对当前任务的判断。

贝叶斯视角和梯度下降视角冲突吗

不一定冲突。

研究 ICL 有两种常见解释:

  1. 贝叶斯视角:模型在上下文里推断隐藏任务。
  2. 梯度下降视角:Transformer 的前向传播可以模拟一种学习算法,像是在内部做几步梯度更新。

这两种解释听起来不同,但可能是在不同层面看同一件事。

比如你做线性回归,有两种说法:

  1. 贝叶斯说:我根据数据更新对斜率和截距的分布。
  2. 优化说:我用算法找到让误差最小的斜率和截距。

在某些条件下,这两种方法会给出接近的答案。

所以更稳妥的说法是:

ICL 不是只能用一种理论解释。贝叶斯解释强调“任务不确定性”,梯度下降解释强调“模型在前向传播中实现了学习算法”。

对小型受控模型,我们可以比较精确地验证这些说法。对真实前沿 LLM,它们更像有用的透镜,还不能说已经完全解释。

参考入口:In-Context Learning through the Bayesian PrismCan Transformers Learn Full Bayesian Inference in Context?Transformers Implement Functional Gradient Descent to Learn Non-Linear Functions In Context,以及持怀疑态度的讨论:Do Pretrained Transformers Learn In-Context by Gradient Descent?

一个完整的人话模型

现在可以把整件事串起来。

当你写:

红 -> red
蓝 -> blue
绿 -> ?

模型内部可能发生的是:

  1. 它读到 红 -> red,开始猜:也许是翻译任务。
  2. 它读到 蓝 -> blue,翻译任务的可信度继续升高。
  3. 它看到 绿 -> ?,把 绿 放进“中文转英文”这个任务模式里。
  4. 它输出 green

如果你写:

红 -> #ff0000
蓝 -> #0000ff
绿 -> ?

模型会换成另一个任务模式:

  1. 颜色中文名转十六进制色值。
  2. 绿 对应 #00ff00 或类似答案。

它不是刚刚学会颜色,也不是修改了权重。

它是在上下文里做了任务识别。

用一句话总结:

Prompt 里的例子不是训练数据,而是证据;模型不是更新权重,而是更新对当前任务的判断。

这能解释哪些现象

贝叶斯视角可以解释很多你日常使用大模型时遇到的现象。

1. 为什么 few-shot 有用

几个例子能快速缩小候选任务范围。

没有例子时,模型只能靠指令猜;有例子时,模型能从输入输出关系里推断任务。

2. 为什么格式很重要

格式本身也是证据。

Q: ...
A: ...

输入:
输出:

会让模型进入不同的任务模式。

3. 为什么坏例子会带偏模型

如果示例里有错误,模型可能会把错误也当成规则的一部分。

比如你给它:

1 + 1 = 3
2 + 2 = 5
3 + 3 = ?

它可能会猜这是“正确答案加 1”的任务,而不是普通加法。

4. 为什么指令和例子冲突时会混乱

如果你写:

请把中文翻译成英文。

苹果 -> 🍎
香蕉 -> 🍌
猫 -> ?

指令说翻译,例子说 emoji。

这时模型要在两个证据之间权衡。不同模型、不同 prompt、不同采样参数,结果都可能变化。

5. 为什么模型会过度模仿

如果示例里的答案很啰嗦,模型可能也变啰嗦。

因为它不只在猜“语义任务”,也在猜“输出风格任务”。

它不能解释什么

贝叶斯视角很好用,但不要过度神化。

它不能保证:

  1. 模型真的严格按贝叶斯公式计算。
  2. 模型一定能从少数例子学到正确规则。
  3. 模型不会受表面格式、位置偏差、训练语料记忆影响。
  4. 模型能处理训练分布外的全新任务。
  5. 模型的每个 ICL 行为都来自同一种机制。

真实大模型很复杂。它可能同时使用:

  1. 模板匹配。
  2. 语义理解。
  3. 上下文里的任务推断。
  4. 内部模拟的优化算法。
  5. 训练时记下的常见格式和答案。

所以,最准确的说法不是:

ICL 就是贝叶斯。

而是:

ICL 可以被很好地理解成一种近似的、隐式的贝叶斯任务推断。

怎么把这个视角用到 prompt 里

理解这个视角后,写 prompt 会更清楚。

如果你想让模型稳定跟随任务,不要只写抽象要求。要给它足够清晰的证据。

1. 示例要代表真实任务

不要给太简单、太单一的例子。

如果真实任务里有边界情况,示例里最好放一个边界情况。

2. 示例格式要一致

模型会把格式也当成任务的一部分。

前两个例子用短答案,第三个例子突然长解释,模型就会犹豫。

3. 指令和示例不要互相打架

指令是一种证据,示例也是一种证据。

两者冲突时,模型不一定知道该信谁。

4. 先给规则,再给例子

规则给先验,例子给证据。

两者配合,比只给其中一个更稳定。

5. 对复杂任务,给反例

如果某些输出不应该出现,反例能帮模型排除错误任务。

这在分类、抽取、审核类任务里尤其有用。

最后用一句话收束

上下文学习最迷人的地方在于:

模型看起来像是在 prompt 里现场学习,但它更可能是在用已有能力,对“当前任务是什么”做快速推断。

这就是贝叶斯视角的价值。

它把一个神秘现象翻译成了更朴素的流程:

看到例子
-> 猜隐藏任务
-> 更新任务可信度
-> 按最可能的任务生成答案

所以,大模型的 ICL 不是魔法。

它更像一种临时的模式识别:

这几个例子告诉我,我现在应该扮演哪种函数。