最近在折腾大语言模型落地的时候,我发现自己越来越频繁地用一个词:上下文学习。无论是让模型做文本分类、信息抽取,还是数学推理,零样本学习和少样本学习这两条路几乎成了我每天都要面对的必经之路。说零样本,就是不给任何示例直接问;说少样本,就是塞几条示例再让模型干活。而这两种能力,本质上都依赖上下文学习——模型通过提示词里的内容,在推理阶段临时调整自己的行为。今天这篇文章,我就把这段时间反复测试、踩坑、优化后的理解整理出来,聊聊上下文学习到底怎么提升推理能力,以及实际操作中应该怎么设计提示词。
这个主题适合三类人:正在做大模型应用开发、但又没有批量训练数据的人;想搞清楚为什么“多塞几条示例效果就变好”的算法工程师;以及刚开始接触提示词工程、想少走弯路的产品和技术同学。我不会堆论文公式,尽量用干活的角度把原理和实操讲明白。
1. 什么是零样本与少样本学习:先分清这三件事
1.1 零样本学习:一句话讲清楚“没教过也能干”
零样本学习的字面意思是:模型在训练阶段从来没有见过某个具体任务的数据,但你直接给它一个指令,它就能输出符合要求的结果。举个例子,我手里的模型没专门做过“判断外卖评价是好评还是差评”这个任务,但我把一条评论文本发给它,告诉它“请判断情感倾向”,它也能给出靠谱的回答。这就是零样本。
它为什么能做到?根本原因是预训练阶段模型见过海量文本,语言的规律、任务的形态、甚至很多任务本身的样子都已经藏在参数里了。推理时它做的不是“从零学习”,而是“从记忆里找到最匹配的知识再组织输出”。这就像一个新员工入职,虽然没有专门培训过某个流程,但靠过去的基础知识和岗位说明,也能把事情办个七八分。零样本的关键是:指令要能把模型记忆里对应的能力“激活”出来,指令写得模糊,激活的就是一堆无关内容。
不过零样本也有明显的天花板。任务越专业、输出格式越特殊、逻辑链条越长,零样本的表现就越不稳定。我实测过不少场景,零样本的准确率勉强能用,但离上线要求差得远。这时候就需要少样本学习出马。
1.2 少样本学习:几条示例为什么能“稳住”模型
少样本学习的操作很直观:在提示词里附带几条输入输出示例,然后让模型照着这些示例处理新的输入。还是刚才外卖评价的例子,我不再空口说“请判断情感倾向”,而是先给模型看两条“评价+情感标签”的例子,再把真正要判断的评论接在后面。
这几条示例的作用,表面上是在“教”模型,实际上更像是在“对表”。模型本来就会做情感判断,但它不确定你要的“正面”是指“好评”还是“积极”,也不确定输出只给一个词还是给一段解释。示例一给,这些不确定信息全部被锁定。少样本学习解决的核心问题不是“不会做”,而是“不知道按什么格式、什么口径做”。所以哪怕示例数量很少,往往效果就有肉眼可见的提升。
我把零样本和少样本的差异做了个简单对比,方便理解:
| 对比维度 | 零样本学习 | 少样本学习 |
|---|---|---|
| 示例数量 | 0条 | 通常2到16条 |
| 适用场景 | 快速验证、通用性问题 | 格式严格、口径专业、推理链条长 |
| 效果基线 | 波动大,依赖指令质量 | 更稳定,输出格式更可控 |
| 主要成本 | 几乎为零 | 需要人工准备少量示例 |
| 对模型的要求 | 通用理解能力强 | 在通用能力基础上进一步约束 |
1.3 上下文学习:把“提示词里塞内容”这件事正式化
上下文学习(In-Context Learning)是零样本和少样本背后的统一机制。它指的是:模型在推理阶段直接读取上下文窗口里的全部内容,包括任务描述、示例、当前输入,然后根据这些上下文预测下一个词。模型参数全程不更新,一切调整都发生在这一次前向计算里。
这个机制最迷人的地方在于:外部输入的几条示例,能在不改动任何权重的前提下改变模型行为,而且改变幅度可以相当大。早期有人把它类比成一种“隐式的微调”,意思是模型通过注意力机制,在内部模拟了一个类似梯度更新的过程。从使用者角度看,我们不需要理解内部细节,只需要掌握一个核心逻辑:提示词里的内容不是简单的“背景说明”,而是真正影响模型推理路径的一部分。
2. 上下文学习为什么能提升推理能力:拆开来看机制
2.1 任务识别的隐喻:示例让模型“认出”了任务
我倾向于用“任务识别”来理解上下文学习的作用。模型面对任何输入,首先要判断当前面临的是什么任务。零样本模式下,它只能靠任务描述去猜;少样本模式下,示例提供了一组具体的输入输出对应关系,相当于把“任务定义”从抽象变成了具体。
举个容易理解的类比。你让一个熟手师傅干活,只说“把这个处理一下”,他大概率懵;但你给他看一个已经处理好的样品,他立刻知道你要什么。示例就是这个“样品”。模型在预训练阶段见过无数种任务形态,少样本示例的作用不是教会它新技能,而是帮它定位到现在要做的是哪一种。一旦任务被正确识别,模型储存的相关能力就会被统一调度起来,推理质量自然上升。
实际开发中这个观点非常有指导意义。如果你发现零样本效果很差,最先怀疑的往往不是模型笨,而是任务描述不够具体,模型根本没认出来这是什么任务。这时候与其重新微调模型,不如先给几条示例试试。
2.2 隐式微调与注意力路径:示例如何改变内部计算
更底层的解释要回到模型结构本身。当示例被拼接进输入序列后,整个序列会一起经过注意力层计算。每一条示例都会通过注意力权重,影响当前位置的表征生成。有研究把这种现象解释为:前向传播过程中,模型在内部隐式地完成了一次“假想梯度更新”,等效于对模型行为做了一次轻量级调整。
这个解释能回答一个常见疑问:为什么示例不能随便塞?因为注意力机制对序列位置敏感,前面的内容对后面的内容影响更大,示例之间的排列顺序会被注意力模式放大。不同顺序下,模型关注的重点不同,输出结果就可能不同。我在实测中也经常发现,同样的示例换个顺序,准确率能差好几个百分点。
这不代表我们每次都要穷举所有排列,但它提醒我们:上下文学习不是简单的“模板拼接”,而是真实参与计算的推理过程,设计提示词时必须把它当作一个整体来考虑。
2.3 贝叶斯视角:少样本示例校准了输出分布
第三种理解角度稍微数学一点,但很实用。可以把上下文学习看成是对任务的后验分布估计:模型在给定示例的情况下,推测当前任务最有可能是什么,以及输出应该服从什么分布。简单说,示例帮助模型把输出概率从“各类别均匀”校准到“符合示例呈现的规律”。
这个视角能解释很多现象。比如你做情感分类,示例里只出现“正面”和“负面”两个标签词,模型输出的词汇空间就会被压缩到这两个词附近,不会再飘出“还行”“一般”这种中间表达。示例的数量、标签分布、词汇选择,都会直接改变模型对输出分布的估计。
所以少样本示例的标签需要保持均衡,至少不能严重偏斜。如果示例里五条都是正面的,只有一条是负面的,模型会以为这个任务主要输出正面,推理时会隐性偏向正面,导致真实评价被误判。这不是玄学,而是输出分布在起作用。
3. 手把手实操:零样本和少样本提示词的设计与优化
3.1 零样本提示词设计:先学会把话说清楚
零样本模式下没有示例兜底,提示词的质量几乎决定了一切。我的基本框架有三要素:任务描述、输出约束、输入位置。
请对以下评论进行情感倾向判断。 要求: 1. 只输出“正面”或“负面”; 2. 不要输出解释; 3. 直接给出结果。 评论:这家店的出餐速度很快,味道也不错。 输出:这个模板看起来很朴素,但每一句话都有作用。“只输出”约束了答案空间,“不要输出解释”切断了模型解释的惯性,“输出:”则明确了生成起点。我的经验是:开头第一句先点明任务名称,让模型尽早定位任务类型;中间给约束时用否定句和肯定句搭配,比单一肯定句更有效;末尾的输出占位符别省略,它相当于告诉模型“你该输出了”。
实操中我常遇到的情况是,零样本的输出内容本身是对的,但格式不达标。比如模型在标签前后加了“结果是”“我觉得”这类废话。这其实还是约束不够。可以在要求里专门加一条:“禁止输出除标签外的任何字符。”如果模型还是不听话,说明这个任务的零样本上限偏低,该考虑少样本了。
3.2 少样本示例选择:质量、多样性、针对性
少样本模式下,示例的挑选比示例数量更重要。我常用的挑选原则有四个:正确性、多样性、代表性、格式一致性。正确性不用多说,示例标签错了会直接带偏模型。多样性是让示例覆盖不同写法和边界情况,比如情感判断里既要有明显的正面、负面,也要有带转折和反讽的文本。代表性是让示例贴近真实部署场景的数据分布。
示例数量方面,2到4条通常能解决大部分格式问题,更复杂的任务(比如抽取多个字段、多步推理)需要8到16条。但不要盲目追求多。我试过把示例加到20条以上,效果反而变差,原因是指令和当前输入在上下文中的相对权重被稀释了。模型在长上下文里更容易“走神”,准确率并不稳定。对于常见的通用任务,8条以内基本是甜点区间。
格式一致性是我特别想强调的一条。所有示例的输出部分格式必须完全统一,连标点符号都不能混用。比如情感判断里,一条示例输出“正面”,另一条输出“正面。”都会造成干扰。模型对格式的敏感程度远超我们的直觉,细微不一致会直接反映在结果波动上。
3.3 实际案例:从分类到抽取再到数学推理
我拿三个场景演示具体怎么用少样本提示词。
场景一是情感分类。我的示例会这样组织:
判断以下评论的情感,只输出“正面”或“负面”。 示例1: 评论:空调噪音太大,差评。 输出:负面 示例2: 评论:客服态度很好,处理速度很快。 输出:正面 评论:等了一个小时都没送到,汤都凉了,不过骑手小哥态度还行。 输出:场景二是信息抽取。这里示例的价值更大,因为它能同时教会模型“抽什么”和“怎么输出”:
从客服记录中抽取用户反馈的“问题类型”和“期望解决方案”,按JSON格式输出。 客服记录:用户反映订单一直显示已发货但物流没有更新,希望能尽快联系快递确认。 输出:{"问题类型": "物流异常", "期望解决方案": "联系快递确认"} 客服记录:用户收到商品后发现有破损,要求补发或退款。 输出:{"问题类型": "商品破损", "期望解决方案": "补发或退款"} 客服记录:用户想修改收货地址,但是后台系统已经锁定无法操作。 输出:场景三是数学推理。少样本示例可以顺便示范推理过程,效果远好于只给答案。这里用的是带步骤的示例:
请根据示例中的推理过程,回答下面的数学问题。 示例: 问题:一个商店早上卖出12个面包,下午卖出的是早上的2倍少3个,问全天一共卖出多少个? 推理:下午卖出12*2-3=21个,全天卖出12+21=33个。 答案:33 问题:小明有8个苹果,小红给了他3个,他又吃掉2个,还剩下几个? 推理:注意示例里的“推理:”和“答案:”是两个明确的阶段。这样做的好处是,模型在处理新问题时,也会学着先在“推理”阶段写出过程,再在“答案”阶段给出结论。这种格式上的模仿是少样本提升推理能力最直接的体现。
3.4 上下文学习的窗口管理:示例和指令的重量分配
设计提示词时,要记住上下文窗口的容量是有限的。示例、指令、当前输入、历史对话(如果有)都要占用空间。我见过不少开发者一股脑把长文档塞进上下文,结果示例被挤得没剩多少位置,模型输出质量直线下降。
我的习惯是:先定当前输入的最大长度,再根据剩余空间倒推示例数量。比如某个任务需要处理约2000字的长文本,那么示例最好控制在2到4条,每条也尽量精简。如果输入本身很短,比如一句话分类,那就可以放手用8条示例把格式彻底锁死。在实际工程中,还可以把示例做成固定前缀,动态拼接当前输入,这样每次请求的示例部分保持不变,便于统一管理。
窗口管理还有个小技巧:示例放在输入前面,当前输入放在最后。这样模型在生成输出时,离它最近的上下文包含了最新任务信息,不容易被前面大段示例带偏。如果示例和当前输入交替排列,模型位置编码会变得混乱,效果往往更差。
4. 常见问题与排查技巧实录
4.1 示例顺序敏感:同样的示例,换个顺序效果就变了
少样本学习最让人头疼的问题之一,就是结果对示例顺序非常敏感。我早期做分类任务时,把示例按“正面、负面、正面、负面”交替排列,准确率比较高;后来不小心把正面示例全放到前面,负面示例放后面,准确率掉了将近8个百分点。原因在于模型会把示例顺序当成一种隐性规律,连续出现同类标签时,它会默认当前任务输出偏向那一类。
排查这类问题,最直接的办法是做几次顺序轮换测试。把示例顺序倒过来再跑一遍,如果结果波动明显,说明模型对顺序敏感,需要找一种稳定排序。我的经验是“交替排列+类别均衡”通常最稳。还可以把输出位置的示例固定为与当前输入最相似的案例,让它压轴出现,效果往往会更好。
4.2 示例数量与上下文长度冲突:多给示例还是多留空间
我经常被问到:“为什么我的示例加了那么多,效果反而差了?”这里有一个容易被忽略的矛盾:示例越多,模型模仿依据越丰富,但上下文窗口里留给指令和当前输入的相对空间越小。当示例过于冗长,占据大部分上下文时,模型可能过度关注示例表面特征,忽略了实际任务。
排查时分两步。第一步,统计提示词里指令、示例、当前输入各自的字符占比,如果示例超过70%,就要精简。第二步,做一次示例数量消融实验:从0条开始逐步增加,记录每个配置下的效果,找到拐点。多数情况下,效果曲线是倒U型,有一个最优数量区间,超过后开始下降。这个区间因任务复杂度和模型能力而异,但经验值通常在4到16条之间。
4.3 标签分布偏斜与格式污染
少样本示例中,各类别的标签数量如果不均衡,模型会学到错误的先验分布。我做意图识别时曾用7条“查物流”和1条“退换货”示例,结果模型把大量“退换货”请求误判为“查物流”。标签分布和实际业务分布越接近,模型判断越准。解决方案是保持示例类别比例接近真实场景,如果无法做到完全均衡,至少不要让某一类占据绝对多数。
格式污染是另一个高频问题。模型可能把示例里的冗余文本原样复制到输出里。比如示例输出中带了“标签:正面”,那么新输入也会生成“标签:正面”。解决方式有两种:一是把所有示例的输出格式改成我们真正想要的目标格式,让模型只模仿好格式;二是明确在用词上区分“示例”和“目标输出”,减少混淆。
4.4 零样本CoT与少样本CoT的差距:光说“一步步想”还不够
遇到复杂推理任务时,我经常用思维链(CoT)技巧。零样本CoT的做法是在提示词末尾加一句“请一步步思考再给出答案”,有时也能显著提升结果。但它不稳定,某些任务上几乎无效果。少样本CoT则是在示例里包含完整的推理步骤,模型会模仿这个“先推理后回答”的行为模式,效果比零样本CoT稳定得多。
这里要特别提醒:示例里的推理步骤不要乱写。推理过程要逻辑连贯、语言简洁,并且最终的答案必须正确。如果示例推理本身有跳跃或错误,模型会把这种错误模式学走。我见过最糟糕的情况是,示例里推理步骤复杂但答案错了,模型开始照着同样的方式输出长篇错误推理。少样本CoT的核心不是“让模型写步骤”,而是“让模型学一套对的做法”,示例质量直接决定学习质量。
下面是一张快速排查表,遇到问题可以直接对照:
| 现象 | 可能原因 | 排查与处理 |
|---|---|---|
| 零样本输出内容正确但格式乱 | 指令约束不具体 | 增加否定式约束,明确输出占位符 |
| 示例顺序调整后结果波动大 | 模型对位置敏感 | 交替排列示例,固定最优顺序 |
| 示例增加但效果下降 | 示例挤占上下文空间 | 精简示例数量,缩短示例文本 |
| 某一类结果被系统性误判 | 示例标签分布偏斜 | 按真实业务比例重配示例标签 |
| 输出带示例里的冗余前缀 | 格式污染 | 统一示例输出格式,去除多余内容 |
| 复杂推理答案对但过程错 | 示例推理链质量不足 | 重写示例推理步骤,保证逻辑完整 |
5. 影响范围与扩展思路:从提示词工程到模型选型
5.1 上下文学习对传统训练范式的冲击
上下文学习的普及,很大程度上改变了做NLP任务的方式。以前遇到一个新任务,主流思路是准备训练集、微调模型、再部署。现在很多场景下,直接设计好提示词就能解决问题,省掉了数据标注、训练调参、模型部署等一系列环节。对于团队资源有限的小项目,这是革命性的变化。
当然这不是说微调没用了。模型本身能力不足、任务领域非常特殊、或者需要长期稳定输出时,微调仍有不可替代的价值。但上下文学习的意义在于:它把“模型能力适应”这件事变成了“推理时动态调整”,调整成本几乎为零,试错速度大幅提升。
5.2 对应用开发者的启发:优先把上下文学习用到位
我现在的开发习惯是,接到一个新任务,先不做微调决策,而是先花时间设计一套高质量的少样本提示词,用它跑出当前模型的能力上限。如果提示词已经做得很足,模型依然达不到业务指标,再去考虑微调或更换更大规模的模型。这个顺序能帮我省下大量无谓的训练成本。
这里有一个容易被忽略的点:上下文学习的上限受模型基础能力制约。有些任务逻辑链条极长、需要大量领域知识,少样本示例只能引导模型把已有能力发挥出来,无法凭空创造新能力。所以不要指望靠几条示例就让模型学会它训练时从未接触过的推理模式。理解这个边界,能帮你更快做出正确判断。
5.3 结合检索与工具:把少样本示例变成动态组件
少样本学习还有一种更高级的用法:动态检索示例。不把示例固定写死在提示词里,而是针对每个新输入,从已有的标注样本库中检索最相似的几条作为示例。这样能做到“同分布示例”始终出现在上下文里,效果比固定示例更稳定。我在做客服工单分类时用过这个方案,准确率比固定示例版本高出不少。
实践中可以把示例存储在一个结构化的样本库中,用简单的向量检索来挑选与当前输入最接近的案例。成本不高,技术上也不复杂,却能让少样本能力上一个台阶。这个方向我认为值得每一位在做落地应用的朋友深入研究。上下文学习的潜力还没有被完全挖掘,动态示例、自动示例优化、多轮上下文校准这些方向都能带来实际收益。
就我个人实际跑下来的体会,少样本学习的威力被很多人低估了。它不是“没有数据时的妥协方案”,而是一种高效、可控、低成本的模型能力调用方式。用好它的关键不在于堆示例,而在于理解上下文学习背后的原理,然后把指令、示例、格式、顺序这些细节打磨到位。踩过几次坑之后你会发现,大部分真实业务场景根本走不到微调那一步,先把上下文学习用到极致,收益就已经非常可观。如果后面有机会,我还会再单独聊聊动态示例检索和自动提示词优化的具体实现,那是这个方向上更进一步的玩法。