我一直觉得,把零样本学习和少样本学习放在同一节课里讲,真是又省事又容易让人误会的安排。省事是因为它俩都依赖同一个底层机制——上下文学习;误会是因为很多人学完之后,以为零样本就是“啥也不给直接问”,少样本就是“多给几个例子而已”,至于这个机制到底怎么提升推理能力、为什么提升、卡在哪儿了,完全没有感觉,更别说在实际项目里把它调成一套稳定可用的配置。
先给个最直观的场景。你让大语言模型判断一堆客服工单的情感倾向,直接一条条丢给它,它的输出可能一会儿正一会儿负,还时不时带一句解释。但你在提示里预先放上两三条带标准答案的对话样例,再开始问新的工单——同一个模型、同样的权重、同样的温度,输出立刻稳定得多。这个过程中模型参数一个都没动,它仅仅是“读了”几个例子,行为就变了。这就是上下文学习的魔力,也是少样本学习区别于传统少样本训练方法的核心理由。
这篇博文想讲清楚三件事:上下文学习的机理到底可能是什么;怎样把零样本/少样本提示做成一套可靠的生产配置;以及在什么情况下该果断放弃上下文学习、转向微调。无论你是正在做提示工程、准备把大模型接进业务系统,还是单纯想理解“为什么几个例子这么关键”,这篇内容应该都能用上。
1. 从“参数学习”到“语境学习”:范式转变的核心理解
1.1 零样本、少样本与上下文学习到底指什么
先把术语掰开。零样本学习(zero-shot)可以泛指模型在没有见过该类任务标注样本的情况下完成推断;在大语言模型语境里,更常见的含义是“只给任务描述,不提供任何示例,直接把输入丢进去要答案”。少样本学习(few-shot)在传统机器学习里是“用极少标注样本做训练”,但在大模型这里,通常指“在提示里放几个输入输出示例,模型读完就地输出”——全程没有梯度更新,没有权重变化。
两者共同的引擎叫上下文学习(In-Context Learning,ICL):模型通过前向传播时读取到的上下文(指令、示例、输入)来改变自己的输出分布,而不是靠反向传播调整参数。这也是为什么这个章节标题里把零样本、少样本和上下文学习放在一起——它们不是并列的三种技术,而是“两种场景”加上“同一个引擎”。
术语容易打架,是因为“少样本学习”这个词在旧时代很重,在现在很轻。以前你拿几百条数据在小型模型上微调,那叫少样本学习;现在你在提示里写5条示例,也常被叫少样本学习。两者差的不是数量级,而是学习发生的载体彻底变了。我的习惯是:遇到有人聊少样本学习,先确认他说的是“上下文少样本”还是“梯度少样本”,否则后面全是鸡同鸭讲。
1.2 权重没动,模型凭什么会了?
我最初接触大模型时的困惑就是这个:如果不更新权重,模型怎么算“学会”?后来我把这个问题拆成了两半。
第一半:模型预训练时已经在海量文本里见过无数“模式配对”——输入句子、对它的回复、分类标签、推理步骤……这些知识作为隐式能力沉淀在权重里。比如它看过几千万条“这条评论是正面还是负面”的语料,情感判断的神经通路早就有了。
第二半:模型读到你给的示例时,并不需要重新练出这条通路,它只需要在上下文里“激活”对应的通路。几个例子起的作用更像按开关,而不是喂养分。按完开关之后,模型在解码每一步token时,都会把上下文里的示例当成“参照物”,来决定下一个token该落在哪里。
这种“联想型学习”有一句特别贴切的类比:你给一个资深厨师一份菜谱和两个成品参考图,他就能照着做出一模一样的菜,不是因为他在你面前练了厨艺,而是因为他本来就会做,只是需要你告诉他“今天要做这道菜”。大模型的权重就是那个厨师的厨艺,上下文就是今天的要求。
所以范式转变的本质是:传统机器学习把学习定义为“调整参数直到拟合”,上下文学习把学习定义为“在推理时构造一个任务环境,让预训练时的技能被精准触发”。参数学习给你的是“肌肉记忆”,语境学习给你的是“临场发挥”。
这个理解直接影响做法:你要做的不是“教”模型完成任务,而是“唤醒”它已经会的任务。提示设计的第一性原理,是让上下文的格式、词汇、句式尽可能贴近它在预训练语料里见过的、该类任务的自然文本形态。
2. 为什么几个例子就能改变行为?ICL机理的几个硬核解释
2.1 隐式任务识别:示例是“任务指纹”
学界对上下文学习的机制目前没有最终定论,但这不妨碍我们了解几种主流解释,每个都有实验支持。
第一种解释叫任务识别。模型在阅读上下文时,会下意识地根据示例的样式推断出“这像是什么任务”。比如示例是“电影台词:……,用户评价:正面/负面”,模型就会把后续输入套进这个任务模板。从这个角度看,示例相当于一个“任务指纹”——它告诉模型现在处于哪个语言游戏里,模型接着按那个游戏规则输出。
这解释了为什么示例的格式这么重要:如果任务指纹被噪声干扰得很模糊(比如示例里夹杂无关内容),模型就识别失败。我见过很多项目把少样本示例当成“附属品”随便填进提示,结果效果波动极大,就是这个机制在捣乱。反过来,当示例的格式高度统一、标签词明确,模型任务识别的成功率就会显著上升。
2.2 隐式贝叶斯推断:把示例当作证据更新先验
第二种解释是,模型其实在做隐式的贝叶斯推断。预训练导致它对“下一个token”有一个先验分布,而上下文里的示例则相当于证据,让它在输出类别上的后验分布朝着示例所暗示的方向收窄。通俗讲,示例改变了模型对不同答案的“主观概率”;你放两条负面例子,它输出负面标签的概率就会高一些;你放三条正面例子,它又会偏正面。
这个解释能帮我们理解标签分布问题——示例里某一类比另一类多,模型输出也更偏向那一类。模型输出的不是一个“理性的任务解”,而更像“围绕证据加权后的概率采样”。
对做分类任务的人来说,这意味着要像做统计一样小心地控制示例的标签比例,消除偏见。一个常见操作是:每个类别固定放同样数量的示例,哪怕某些类别在真实业务里占比很低,也要在示例里保持均衡,否则模型会因为示例的“多数派效应”而高估低频类别的发生概率。
2.3 归纳头与模式复制:注意力层面的机械解释
第三种解释来自机制层面的研究。有研究者观察到,Transformer内部存在一种被称为“归纳头”的模式:当上下文里出现“A B A”这样的结构,注意力头会把两个A对齐,然后预测下一个token时倾向于复制曾经跟在A后面的B。这种“找相似序列然后照搬”的机制,会让模型在做少样本时特别容易跟着示例走:示例里怎么写的,它就更可能照着写。
这个机制往好了说是让模型快速对齐示例风格和输出格式;往坏了说就是“过拟合到示例表面形式”。比如你示例里用了JSON,它就会尽量回JSON;你示例里带了解释,它就也带解释——哪怕任务并不需要解释。理解这一层,你就能解释很多“玄学”现象:为什么示例顺序一变结果就变、为什么模型会复制示例里的错误标签。
2.4 机制不明的阶段,我们能抓住什么
老实说,这三种解释之间并不互斥,更像是在不同抽象层面解释同一个现象。任务识别偏向宏观意图,贝叶斯推断偏向概率视角,归纳头偏向微观机制。学界还没有完全统一的答案,但这不影响我们得到实用的结论:
- 示例的格式、标签、顺序都会显著影响输出,所以示例需要被当作工程变量来管理;
- 模型的预训练语料决定了它认哪种“任务指纹”,所以示例的风格要贴近真实世界文本,而不是生造的抽象格式;
- 上下文学习的本质可以被理解为“按需触发+局部模仿+概率偏置”三者的混合,它不是模型真正的泛化能力增长。
这些认知直接决定了我写提示的手感:永远不轻视示例设计,但我也不指望光靠堆示例就能让模型学会一个它从未接触过的新技能。
3. 提示模板与上下文工程:从零样本到少样本的实战编排
3.1 零样本:最省事,但先检查“任务指纹”是否清晰
零样本意味着提示里没有任何输入输出示例,只有任务描述和输入。它的优点是快、省token、流程干净;缺点是模型靠什么确认自己在做哪个任务?只能靠任务描述本身。所以零样本提示的关键是“把任务描述写得像模板”。
我的常用结构是三段式:角色(system)+任务内容(user)+输出约束(最后一句话)。比如做客服工单情感分类时,我会写:
你是一个客服工单分析助手。对每条消息,只输出三个词之一:正面 / 负面 / 中性,不要输出其他文字。
就这么清晰的三段。注意,很多教程喜欢给角色加戏(“你是一位资深情感分析专家”),实测下来对任务识别帮助有限,有时甚至因为引入无关风格,使输出变得花哨。我一般只在需要特定语气或专业术语时才加角色。
零样本做推理类任务时,有的模型容易“抢答”——直接给结论不给过程;有的则会稳定一些。如果你发现零样本输出很飘,先不要急着怀疑模型笨,先检查两点:任务描述里是否包含足够的历史任务关键词;是否给了明确的输出格式约束。大多数零样本翻车,其实翻在这两点上。
3.2 少样本:示例的质量、顺序与标签比例
一旦零样本不稳定,最快修正手段就是加示例。示例有几个硬指标。
- 代表性:每个输出类别至少一条,输入形态要有区分度;
- 多样性:尽量覆盖不同表达长度、句式,而不是挑几条最典型的;
- 标签比例:每个类别的示例数尽量接近,至少不能差出一倍;
- 顺序:很多人忽略,模型习惯偏向靠后的信息,所以可以把最易混淆的示例放在序列后段。
数量上我建议起点是4~8条。太少模型可能没抓到任务指纹,太多会稀释注意力且成本升高。我之前在某个信息抽取任务里做过对比,2条示例准确率约78%,5条示例涨到89%,加到12条反而只涨了0.4个百分点。这个边际收益递减非常明显,示例数量不是线性优势。
为了让你对成本有感觉,我列一次典型对比测试的体感数据(模型输出稳定度主观评估):
| 示例数量 | 准确率观察 | token消耗 | 延迟体感 | 稳定度 |
|---|---|---|---|---|
| 0条(零样本) | 约76% | 最少 | 最低 | 不稳,偶尔格式漂移 |
| 2条 | 约78% | 低 | 低 | 略好 |
| 5条 | 约89% | 中 | 中 | 稳定 |
| 8条 | 约89% | 中高 | 中高 | 稳定 |
| 12条以上 | 约89.4% | 高 | 明显上升 | 偶发“迷失在中间” |
3.3 示例的“长相”决定成功半径:格式工程
示例用什么格式呈现,我把它称为“长相工程”。同一个信息,用自然语言段落、JSON结构、XML标签、Markdown列表表示,模型的响应风格会完全不同。原因是模型预训练时在不同格式下的“模式强度”不同。
我的经验排序:对绝大多数结构化抽取任务,JSON是目前兼容性最好的输出格式;对分类任务,用简短自然语言或固定标签词足够;对生成总结类任务,示例最好也是完整段落而不是干巴巴的模板。最怕的是混搭:示例用JSON,输出要求却是纯文本,模型反而会被两股力量拉扯。
举个例子,判断新闻标题所属领域的少样本提示,可以写成这样:
任务:判断新闻标题所属领域。仅输出:科技 / 财经 / 体育 / 文娱。 示例: 输入:某公司发布新一代电池,能量密度提升30% 输出:科技 输入:美股高开低走,科技股领跌 输出:财经 输入:球队官宣新主帅,签约两年 输出:体育 --- 输入:{待判断标题} 输出:这种“输入:”+“输出:”的模式,几乎就是模型在预训练语料里最常看到的人机对话模板,任务指纹识别的成功率极高。分隔符用“---”或换行都可以,关键是全提示保持一致。
3.4 输出约束与后处理
少样本提示里最被低估的一项工作,是输出可解析性设计。你让模型输出“不要其他文字”,它还是会偶尔给你带个句号、引号、斜杠;你让它输出JSON,它可能输出成markdown代码块。解决方式是双保险:提示里给出一句“直接输出结果,不要解释,不要使用代码块”;后处理时再用正则或JSON解析器加一层兜底。
别指望模型百分百遵守指令,工程上永远要给自己留护栏。这些编排经验,核心都是在做同一件事:让上下文的每一部分都为“任务指纹识别”服务——指令负责定位任务,示例负责确定风格,输出约束负责校准终态。
4. 推理链的涌现:以“逻辑一致性”为核心的提示策略与参数工程
4.1 为什么零样本也能“推理”,却总是不稳定
第三章处理的场景还偏分类和抽取,推理能力才是标题里真正的重头戏。什么叫推理能力?我的定义是:模型能在不做检索、不看外部资料的情况下,通过多步操作得到新结论。数学应用题、多跳问答、代码逻辑解释、策略规划都算。
零样本模型当然能做这些,但它是“快思考”——直接根据统计偏好给出最可能的答案。对于小学应用题这种分布很稠密的还行,一遇到稍微反直觉的题,快思考就会给出自信的错误答案。核心问题在于模型跳过了从条件到结论的推导闭环,中间步骤一旦缺失,错误的概率就指数上升。
4.2 把思维过程写出来:提示重构与思维链的触发
最简单的改进是让模型在给出最终答案前,把推理步骤显式地写出来,这正是思维链(Chain-of-Thought)提示做的事。它的本质是:增加模型在前向传播中“思考”的token预算,让每一步结论都能被后续步骤引用,从而缩小从条件到结论的跳跃幅度。
零样本触发词那一句“让我们一步一步思考”确实有效,但不建议当成万能钥匙。有效的原因是这个句式在预训练数据里高频出现在“严谨解题”语境里,相当于一个任务指纹开关;但它在有些领域也会诱导模型生成冗长的、看似合理但完全跑偏的解释。我的做法是:任务需要数学或逻辑时再上,情感分类之类的就没必要。
少样本版本更强:在示例里直接展示推理过程。格式建议:
Q:某个果园原来有苹果树120棵,又种了30棵,先后死了5棵,现在有多少棵? A:先算总数:120+30=150;再减去死树:150-5=145。答案是145。这种“Q+A带过程”的示例,等于给模型示范了输出的“思维方式”而不只是最终答案。我做过对比实验:同样一道多步推理题,零样本直接答的正确率约55%,零样本加“思考”触发词约74%,加上两条带过程的少样本示例后约86%。这个差距非常大,而且全部发生在权重冻结的状态下。
4.3 解码参数与自洽性:稳定性比单发准确率更值钱
提示词写好了,解码参数也不能瞎调。总结我这几年的经验:
- 分类/抽取类任务:temperature 0~0.2,top_p 0.9以内,输出稳定优先;
- 开放生成/创意任务:temperature 0.7~1.0有意义,写的文本更有多样性;
- 推理任务:temperature可以低(接近0),但如果你要的是“逻辑一致性”而不是“单个答案”,更有效的手段是做自洽性采样:同一道题用较高温度(比如0.5~0.7)跑5~8次,再把答案多数投票。这个“sample and vote”思路能把不稳定模型变成相对可靠的推理器。
推理任务上自洽性的效果,原理和集成学习一个道理:单次解码可能被局部较强的token路径带走,多次采样相当于探索更多条件组合,多数投票抑制随机噪声。缺点是成本乘了N倍。我在高价值推理场景(比如小额金融审核、逻辑判断)会用5次采样,一般场景则只跑1次。
4.4 让模型“自查”:逻辑一致性检验的实战技巧
还有一个容易被忽视的推理提升手段:把推理过程作为一个可回溯的文本,交给模型自己检查。比如先让它给答案和步骤,再追问一句“你刚才的步骤里有没有哪一步用错了条件?如果没有,请确认最终答案。”这种简单的自查提示,在小模型上往往能抓住代数符号抄错这类低级错误。
注意,自查也不是无限的——追问太多次,模型会开始“自我纠结”,甚至把对的改成错的。我的底线是:最多自查两轮,第三轮就开始信任第一轮。
这些技巧加在一起,效果就是标题里那句话:上下文学习确实能提升推理能力,但提升的前提是提示策略主动把“推理过程”变成显式上下文,而不是指望模型默默消化。
5. 上下文的限度:示例选择、顺序敏感性与若干实战陷阱
5.1 示例顺序的“近朱者赤”陷阱
前面提过顺序敏感,这里展开。我在一类情感分类任务上做过小实验:同一批5条示例,顺序完全打乱后,同一批测试输入的预测仅在顺序变化下就有8~12个点的准确率波动。原因就是前面归纳头机制里的“邻近效应”:模型倾向于受越靠近输入位置的示例影响越强。
这意味着两件事:第一,调提示时如果要对比效果,必须固定示例顺序,否则你对比的是顺序带来的噪声;第二,生产环境里可以决定把最有代表性的、最容易出错的示例放在离输入最近的位置。我在实际测试里发现,把“困难示例”放在序列末尾,通常比放在开头效果更稳,因为模型会把刚读到的模式迁移到后续输入上。
5.2 标签分布与“多数派偏见”
跟顺序类似的是标签比例。如果5条示例有4条都是“正面”,模型输出的正面比例会显著提高;这不是因为它觉得数据里正面多,而是因为它把示例当成了概率证据。
有个实验很直接:把示例中所有标签故意翻转来写(比如明明是正面标注成负面),模型测试时也会跟着把正面判成负面。这个现象常被当作“模型在抄袭示例”的证据,但它也揭示了上下文学习的上限:示例是模型唯一能看见的任务分布,示例若是坏的,模型只会更高效地学坏。
线上跑分类任务时,我建议每上线一批示例前,用一个小验证集跑一遍标签平衡检测,防止某类样本在上下文里悄悄占多,尤其当业务数据天然不均衡时。
5.3 上下文长度与“迷失在中间”
什么时候少样本该止步?当示例本身很长、每条都要占几百token时,示例数量可能多到让后续输入处于上下文的中部,而注意力对这种长上下文的覆盖并不均匀——于是出现“迷失在中间”:模型对上下文开头和结尾的内容记得更清楚,对中间内容记忆模糊。
所以我的铁律是:把最重要的示例放开头,最相关的示例放结尾,中间只放支撑性示例;如果上下文总长度超过模型窗口的一半,宁可砍示例也不要无限堆。少样本是“让模型看到线索”,不是“让模型读完一本书”。
5.4 错误传染与格式漂移
另一个高频坑是错误传染。示例中只要有一条标注错了,模型不仅可能学错,还会因为样例间的规律性把它当成“规律”。所以示例质量必须人工或用小模型两轮审核,不敢用没跑过验证的样本直接上提示。
格式漂移则更隐蔽。你要求输出JSON,模型偶尔回一个markdown代码块;你要求输出情感词,它给你附带一句“我将这样判断”。这种漂移的解法有三层:提示层加强约束、解码后加解析兜底、连续漂移时用规则强制改写。把后处理当作上下文学习的一部分,而不是事后补丁。
5.5 故障排查清单
当你怀疑少样本提示出问题时,按这个顺序查:先查示例顺序变动是否影响结果;再查标签比例;然后查示例格式是否和输出要求一致;再查上下文长度是否超窗;最后再怀疑模型版本和参数设置。我几乎每次都能在这个清单上定位问题,而不是盲目换模型或堆示例。
6. 上下文学习与微调的选型判断:什么场景该坚持ICL
6.1 ICL最“舒适”的场景
什么样的任务最适合用上下文学习?我的判断标准有三条:任务形态变化频繁;标注样本稀缺;对透明可控要求高。
比如你是一个产品运营,今天要抽客服工单里的退货原因,明天要看评论里的价格敏感词,后天要做竞品信息对比。每个任务的样本都不多、需求各异,如果用微调就得为每个任务准备数据和训练流程,而用上下文学习,只需要每个任务写几条示例,几分钟就能上线。这种“多任务、小样本、快迭代”的场景,我是坚决用ICL的。
另外,上下文学习对“可解释性”有天然优势——你给用户展示“模型是参考这5条示例得出答案的”,比解释一个微调黑盒容易得多。我在需要向非技术同事解释模型行为时,ICL几乎是首选。
6.2 该转微调的三个明确信号
但ICL不是银弹。我的经验里,出现以下信号就该考虑微调(或至少做轻量微调):
- 任务固定且长期运行:同一类任务每周跑几百万次,每次带8条示例的成本在token上非常可观;把任务逻辑写进权重,比每次携带示例便宜得多。
- 上下文长度塞不下所需知识:需要引用长文档、知识库、大量规则时,示例撑不起这个体量。
- 模型输出怎么调都差一截且格式需求严苛:比如必须输出特定schema,但模型总是记不住,这时候微调等于把提示的有效部分固化到权重里。
轻量微调方案(在底座上增加少量低秩适配层)逐渐成为这个场景的标准答案:只需要几百到几千条数据、成本不高、改动可控,还能保留底座模型的通用能力。
6.3 我建议的顺序:先上下文,后微调
很多项目一上来就定义“我们要微调一个垂类模型”,我总劝他们先别急。正确顺序应该是:
- 先写一个极其清晰的零样本提示,跑通流程;
- 如果效果不够,加4~8条高质量的少样本示例;
- 如果还不够,加推理链示例或做自洽性采样;
- 只有前两步把天花板摸出来了,发现确实卡在“上下文学习表达不了这个任务逻辑”上,才考虑轻量微调。
这套顺序的价值在于:它用几小时的提示调优,替代了可能几天的工作,而且提示调优得到的“任务指纹”理解,能为后续微调的数据设计提供直接指导——你知道模型哪里理解得不对,才知道该给什么样的训练样本。
6.4 一点收尾的体会
做提示工程这几年,我最大的体会是:不要神化上下文学习,也别低估它。它的本质是给一个已经被预训练知识填满的模型装配“临时说明书”,说明书写得好不好,直接决定模型能否调用出它早已具备的推理能力。对模型权重里的知识来说,“上下文学习提升推理能力”这半句话,我更愿意理解为“上下文学习唤醒了沉睡的推理能力”。
所以,下次你遇到模型表现不佳,先别急着怪模型笨,也别急着上训练,先问自己一句:我给它的语境,足够让它知道自己现在是谁、在做什么、要做到什么程度了吗?这比切换更大的模型或堆更多参数,往往都更快见效。