
摘要 :本文是《LLM技术全景:从Token到部署》系列第七篇。为什么大模型"看几个例子就能举一反三",而无需任何参数更新?为什么只是加上"Let's think step by step",数学推理准确率就能翻倍?本文深度解析两大神秘能力------In-Context Learning(上下文学习)与Chain-of-Thought(思维链),拆解其工作机制,探讨涌现现象背后的规律,并给出实用的Prompt工程指南。
阅读收获:① 理解ICL为什么不需要梯度更新却能学习;② 掌握CoT的几种变体及适用场景;③ 了解涌现能力的本质与尺度依赖;④ 学会编写高效的Few-shot Prompt。
一、引言:大模型有多"神奇"?
2020年,GPT-3横空出世,1750亿参数、45TB训练数据。研究人员惊讶地发现:这个模型几乎不需要任何微调,只需在输入时给几个例子,就能完成全新任务------这就是 In-Context Learning。
2022年,谷歌的研究员Jason Wei在论文里写了一句话:给模型的提示里加上"Let's think step by step"(让我们一步一步地思考),模型的数学推理准确率从17%飙升至78% 。这就是 Chain-of-Thought。
这两个能力共同揭示了一个事实:大模型不只是一个"更大的自动补全",它具有真正意义上的推理与学习能力。
传统机器学习范式:
数据 → 训练(更新权重)→ 模型 → 推理
大模型新范式:
预训练模型(权重固定)+ Prompt(含例子/指令)→ 正确输出
↑
In-Context Learning!(零梯度更新)
二、In-Context Learning(ICL):无需训练的学习
2.1 什么是 ICL?
In-Context Learning 是指:给模型一段包含"示例"的提示(Prompt),模型能根据这些示例推断任务模式,并对新问题作出正确回答------全程不更新任何参数。
根据示例数量,ICL分为三个层级:
Zero-shot:
Prompt: "将下面的句子翻译成英文:我爱北京天安门。"
Output: "I love Beijing's Tiananmen Square."
(没有示例,模型完全靠预训练知识)
One-shot:
Prompt: "将下面的句子翻译成英文:
示例:苹果 → apple
现在翻译:橙子 → "
Output: "orange"
(给了1个示例)
Few-shot:
Prompt: "情感分析(正面/负面):
这部电影太精彩了! → 正面
服务态度很差,再也不来了 → 负面
食物很新鲜,价格也合理 → "
Output: "正面"
(给了多个示例)
2.2 ICL 的工作机制:预训练的功劳
ICL之所以神奇,根本原因在于预训练阶段已经见过数以亿计的任务模式。
研究发现(Min et al., 2022),ICL中示例的标签正确性并不那么重要,重要的是:
| 因素 | 重要性 | 说明 |
|---|---|---|
| 输入-输出格式 | ⭐⭐⭐⭐⭐ | 示例要明确展示"输入是什么,输出是什么" |
| 输入分布 | ⭐⭐⭐⭐ | 示例要与测试输入的类型一致 |
| 标签空间 | ⭐⭐⭐⭐ | 示例要展示可能的输出标签范围 |
| 标签正确性 | ⭐⭐ | 即使标签是随机的,模型依然有一定性能! |
这说明:ICL的核心是激活模型的任务识别能力,而非真正的"从例子中学习"。
2.3 ICL 的理论解释
学界对ICL的工作原理仍有争论,主要有三种假说:
假说1:隐式梯度下降(Meta-learning视角)
python
# Akyurek et al. (2022) 的理论:
# Transformer的前向传播等价于在隐空间做梯度下降
# 直观理解:
# - 示例 = "训练数据"
# - Attention层 = "隐式梯度更新"
# - 最终预测 = "收敛后的推断"
# 关键:这一切发生在前向传播中,而非反向传播!
假说2:任务识别(Bayesian Inference视角)
模型通过示例推断任务的"后验概率":
- P(任务 | 示例) ∝ P(示例 | 任务) × P(任务)
- 模型在预训练时见过大量"翻译"、"情感分析"任务
- 示例帮助模型"识别"当前任务类型,激活相应能力
假说3:检索增强视角
示例触发了模型对预训练数据中相似任务的"记忆检索":
- 模型记住了大量(输入, 输出)对
- 示例帮助模型找到最相关的"记忆"
- 这解释了为何模型见过的任务域ICL效果更好
2.4 ICL 的实用技巧
技巧1:示例选择策略
python
from sentence_transformers import SentenceTransformer
import numpy as np
# 动态Few-shot:选择与测试输入最相似的示例
def select_few_shot_examples(query, example_pool, k=3):
model = SentenceTransformer('paraphrase-multilingual-mpnet-base-v2')
query_emb = model.encode(query)
example_embs = model.encode([e['input'] for e in example_pool])
# 计算余弦相似度
similarities = np.dot(example_embs, query_emb) / (
np.linalg.norm(example_embs, axis=1) * np.linalg.norm(query_emb)
)
# 选择最相似的k个示例
top_k_indices = np.argsort(similarities)[-k:][::-1]
return [example_pool[i] for i in top_k_indices]
# 使用示例
examples = [
{"input": "这家餐厅环境很好", "output": "正面"},
{"input": "等待时间太长了", "output": "负面"},
{"input": "价格实惠,推荐", "output": "正面"},
# ... 更多示例
]
query = "菜品口感一般,不过服务不错"
selected = select_few_shot_examples(query, examples, k=2)
技巧2:示例排序有影响
研究发现,示例的排列顺序会显著影响ICL性能。一般原则:
- 最相关的示例放最后(离Query最近)
- 避免将所有同类标签的示例放在一起(如全部正面最后全部负面)
- 最优顺序因模型而异,可以尝试多种排列
技巧3:示例数量的边际递减
性能增益
↑
│████
│ ████
│ ████
│ ████████
│ ████████████████
└─────────────────────────────────────→ 示例数量
0-shot 1-shot 3-shot 5-shot 10-shot
规律:3-5个示例通常达到95%以上的饱和性能
超过10个示例边际收益显著递减,且占用宝贵上下文
三、Chain-of-Thought(CoT):让模型"想清楚再回答"
3.1 什么是思维链?
Chain-of-Thought Prompting 是指:引导模型在给出最终答案前,先输出中间推理步骤。
经典实验对比(Wei et al., 2022):
【标准Prompt】
问:Roger有5个网球,他又买了2罐,每罐3个球。他现在有几个球?
答:11个。
【CoT Prompt】
问:Roger有5个网球,他又买了2罐,每罐3个球。他现在有几个球?
思考过程:Roger开始有5个球。2罐,每罐3个,共6个球。5 + 6 = 11。
答:11个。
【CoT的价值】:在"标准Prompt"下,小模型容易在复杂推理中犯错。
加上中间步骤后,模型必须"一步步思考",降低了跳步出错的概率。
3.2 CoT 的三种主要变体
变体1:Manual CoT(人工思维链)
提供人工编写的推理示例,显式展示中间步骤:
python
prompt = """
解题过程示例:
Q: 一家商店有150本书,上午卖出了40本,下午又进货80本,现在有多少本?
A:
步骤1:上午卖出后:150 - 40 = 110本
步骤2:下午进货后:110 + 80 = 190本
答案:190本
现在请解答:
Q: 小明有24块糖,他给了小红1/3,小红又吃掉了4块,小红现在有几块糖?
A:
"""
# 模型会仿照示例的格式,一步步输出推理过程
变体2:Zero-shot CoT(零样本思维链)
无需示例,只需魔法咒语:
python
# Kojima et al. (2022) 发现的神奇结论:
# 在问题末尾加上 "Let's think step by step" 即可触发CoT
prompt_standard = "1 + 1 × 2 = ?" # 常见错误:2
prompt_zero_shot_cot = """
1 + 1 × 2 = ?
Let's think step by step.
"""
# 模型输出:先进行乘法:1 × 2 = 2,再进行加法:1 + 2 = 3,答案是3。
# 中文等价触发语:
cot_triggers = [
"让我们一步一步地思考:",
"请详细分析过程:",
"思考步骤如下:",
"首先,让我们分析这道题:",
]
变体3:Auto-CoT(自动生成思维链)
无需人工编写推理步骤,让模型自动生成CoT示例:
python
def auto_cot(questions, test_question, llm):
"""
1. 对每个问题,用Zero-shot CoT生成推理过程
2. 选择代表性示例作为Few-shot
3. 用这些自动生成的CoT示例来回答测试问题
"""
# 步骤1:生成CoT
cot_examples = []
for q in questions:
cot_response = llm(f"{q}\nLet's think step by step.")
cot_examples.append({"question": q, "cot": cot_response})
# 步骤2:按多样性聚类,选代表示例
selected = cluster_and_select(cot_examples, k=8)
# 步骤3:构建Few-shot Prompt
few_shot_prompt = build_prompt(selected, test_question)
return llm(few_shot_prompt)
3.3 CoT 的高级变体
Tree-of-Thoughts(ToT):从"链"到"树"
标准CoT(线性):
问题 → 步骤1 → 步骤2 → 步骤3 → 答案
(只有一条路径,走错就走错了)
ToT(树形):
问题
/ \
思路A 思路B
/ \ \
A1 A2 B1
↓ ↓ ↓
答案1 答案2 答案3
(多路径并行,选最优)
python
# ToT 核心思想(伪代码)
def tree_of_thoughts(problem, breadth=3, depth=4):
"""
breadth: 每步生成的候选思路数量
depth: 推理深度(步骤数)
"""
current_thoughts = [problem]
for step in range(depth):
new_thoughts = []
for thought in current_thoughts:
# 生成b个候选下一步
candidates = llm.generate_candidates(thought, n=breadth)
# 评估每个候选的价值
evaluated = llm.evaluate(candidates)
# 选择最有价值的继续
new_thoughts.extend(select_top_k(evaluated, k=breadth))
current_thoughts = new_thoughts
# 最终选择最优路径
return select_best(current_thoughts)
Graph-of-Thoughts(GoT):从"树"到"图"
ToT的进一步演化,允许不同推理路径之间相互"参考"和"融合",形成图结构。适合需要综合多角度的复杂推理任务。
Self-Consistency(自洽解码):
python
# 核心思想:多次采样,投票取最优
import collections
def self_consistency_cot(question, llm, n_samples=20, temperature=0.7):
"""
1. 用CoT Prompt + 高温度采样生成n个答案
2. 对答案进行多数投票
3. 得票最多的答案通常最准确
"""
answers = []
for _ in range(n_samples):
response = llm(
f"{question}\nLet's think step by step.",
temperature=temperature
)
# 提取最终答案(从推理过程中)
answer = extract_answer(response)
answers.append(answer)
# 多数投票
vote_count = collections.Counter(answers)
final_answer = vote_count.most_common(1)[0][0]
return final_answer
# 为什么有效?
# - 错误的推理路径是随机的(不会系统性地指向同一个错误答案)
# - 正确的推理路径趋向一致(都指向同一个正确答案)
# - 20次采样 + 投票 >> 1次确定性生成
3.4 CoT 的边界条件
CoT并非万能,它在特定条件下才有效:
| 条件 | CoT是否有效 | 原因 |
|---|---|---|
| 模型 < 7B参数 | ❌ 通常无效 | 小模型缺乏"隐式推理能力",强迫输出步骤反而出错 |
| 模型 ≥ 70B参数 | ✅ 显著有效 | 大模型已具备"跟随推理示例"的能力 |
| 算术推理任务 | ✅ 大幅提升 | 步骤化推导降低计算错误 |
| 常识推理任务 | ✅ 有效 | 显式化中间知识有助于推理 |
| 简单分类任务 | ➖ 有时反效 | 强迫输出步骤反而拖慢速度,性能无提升 |
| 事实性问答 | ➖ 无明显提升 | 此类任务不需要推理,直接检索即可 |
四、涌现能力(Emergent Abilities):能力的"量变引起质变"
4.1 什么是涌现?
涌现(Emergence) 指的是:随着模型规模增长,某些能力会在特定阈值后突然出现,而非线性增长。
能力强度
↑
│ ████
│ ████
│ ████
│ ████
│ ████
│████
└─────────────────────────────────→ 模型规模(参数量/FLOPs)
1B 10B 100B 500B 1T
规律:
- 涌现点因能力不同而不同
- 阈值之前:随机猜测水平
- 阈值之后:突然可用
- 代表能力:多步算术、多语言翻译、常识推理
4.2 已知的涌现能力清单
Google DeepMind(Wei et al., 2022)在170+任务中系统记录了涌现现象:
| 能力类别 | 代表任务 | 大约涌现阈值 | 描述 |
|---|---|---|---|
| 多步数学推理 | 三位数加减乘除 | ~50B参数 | 小模型随机猜,大模型准确计算 |
| 词汇类比 | "男人:国王 :: 女人:?" → 皇后 | ~40B参数 | 需要理解词语间的语义关系 |
| 多语言翻译 | 低资源语言互译 | ~10B参数 | 未见过的语言对之间的迁移 |
| 代码理解与生成 | 根据注释写函数 | ~30B参数 | 理解函数意图并实现 |
| 因果推理 | 判断事件的因果关系 | ~60B参数 | 区分相关性与因果性 |
| In-Context CoT | 看示例后自主推理 | ~100B参数 | ICL + CoT同时工作 |
4.3 涌现是真实的吗?
2023年,斯坦福的研究(Schaeffer et al., 2023)提出了一个颠覆性质疑:
传统观点:
涌现是模型内部能力的突然涌现
→ 揭示了大模型的本质
Schaeffer质疑:
涌现可能是"评估指标"的artifact!
用正确率(Accuracy):
错 → 错 → 错 → 对 (看起来突然涌现)
用更细粒度的指标(如对数概率):
0.1 → 0.3 → 0.6 → 0.9 (其实是平滑提升的)
结论 :涌现现象的"突然性"部分是测量方式的产物,但大规模模型确实具有小模型不具备的新质能力------这一事实不可否认。
4.4 为什么涌现对实践者重要?
理解涌现给我们带来的实践启示:
1. 选模型时:
如果任务需要复杂推理,不要用7B以下的模型"省钱"
→ 小模型 + CoT Prompt ≠ 大模型的效果
2. 评估时:
对涌现型能力,小规模实验不可靠
→ 在7B模型上测试CoT效果,不代表在70B上也无效
3. 训练时:
当训练损失停止下降,并不意味着能力没有提升
→ 继续训练,等待涌现点的到来
4. 产品设计时:
今天用API的复杂任务,1-2年后可能在端侧设备上运行
→ 设计时保持架构灵活性
五、实战:构建高效的 ICL + CoT Prompt
5.1 Prompt 设计模板
python
def build_powerful_prompt(
task_description: str,
examples: list[dict], # [{"input": ..., "reasoning": ..., "output": ...}]
query: str,
use_cot: bool = True
) -> str:
"""构建包含ICL + CoT的高效Prompt"""
prompt_parts = []
# 1. 系统指令(任务描述)
prompt_parts.append(f"## 任务说明\n{task_description}\n")
# 2. Few-shot 示例(含CoT)
if examples:
prompt_parts.append("## 示例\n")
for i, ex in enumerate(examples, 1):
prompt_parts.append(f"### 示例{i}")
prompt_parts.append(f"输入:{ex['input']}")
if use_cot and 'reasoning' in ex:
prompt_parts.append(f"分析过程:{ex['reasoning']}")
prompt_parts.append(f"输出:{ex['output']}\n")
# 3. 当前问题
prompt_parts.append(f"## 当前问题")
prompt_parts.append(f"输入:{query}")
if use_cot:
prompt_parts.append("分析过程:") # 引导模型输出推理过程
else:
prompt_parts.append("输出:")
return "\n".join(prompt_parts)
# 完整使用示例
examples = [
{
"input": "某产品上月销售额100万,本月增长了15%,本月销售额是多少?",
"reasoning": "增长额 = 100 × 15% = 15万。本月销售额 = 100 + 15 = 115万。",
"output": "115万"
},
{
"input": "仓库有500件商品,出库了120件,入库了80件,现有多少件?",
"reasoning": "出库后:500 - 120 = 380件。入库后:380 + 80 = 460件。",
"output": "460件"
}
]
prompt = build_powerful_prompt(
task_description="你是一个精准的数学计算助手,需要先分析计算过程,再给出最终答案。",
examples=examples,
query="某公司有员工300人,年末裁员10%,但新入职了25人,年末共有多少员工?",
use_cot=True
)
print(prompt)
5.2 实际效果对比
用 Qwen-2.5-7B 测试不同Prompt策略在数学推理上的效果:
| Prompt策略 | GSM8K准确率 | 延迟(ms/token) | 说明 |
|---|---|---|---|
| Zero-shot | 52.3% | 18 | 直接问答,不给示例 |
| Zero-shot CoT | 70.1% | 22 | 加"让我们一步步想" |
| 3-shot | 63.5% | 25 | 3个示例,无推理步骤 |
| 3-shot CoT | 79.8% | 30 | 3个示例 + 推理过程 |
| 3-shot CoT + Self-Consistency(×10) | 85.2% | 300 | 10次采样 + 投票 |
关键结论:
- Zero-shot CoT vs Zero-shot:+17.8%,代价极小(稍多几个token)
- 3-shot CoT vs 3-shot:+16.3%,推理示例至关重要
- Self-Consistency:继续+5.4%,但代价是10倍延迟------适合高精度场景
5.3 常见陷阱与对策
python
# 陷阱1:CoT"幻觉"------推理过程看似正确,实则有误
# 表现:
# Q: 2^10 = ?
# CoT: 2^1=2, 2^2=4, 2^4=16, 2^8=256... 所以2^10=512
# (推理步骤跳步了!正确应是 256 × 4 = 1024)
# 对策:使用Self-Consistency + 答案验证
def verify_cot_answer(question, cot_response, expected_type="number"):
"""验证CoT推理过程的一致性"""
# 1. 从推理中提取中间值
intermediate_values = extract_numbers(cot_response)
# 2. 独立重新计算最终答案
recalculated = recalculate_from_steps(intermediate_values)
# 3. 与CoT最终答案对比
stated_answer = extract_final_answer(cot_response)
return recalculated == stated_answer
# 陷阱2:示例选择偏差------示例全是"正面",导致分类偏向正面
# 对策:确保示例涵盖所有标签类别,均衡分布
# 陷阱3:格式不一致------有时输出格式与示例不同
# 对策:在指令中明确格式要求
bad_prompt = "分析情感:我很开心 → ?"
good_prompt = """
情感分析(只回答"正面"或"负面",不要其他内容):
我很开心 → 正面
这太糟糕了 → 负面
还不错嘛 → """ # 格式明确
六、ICL vs 微调:什么时候选哪个?
这是实践中最常见的决策问题:
使用 ICL(In-Context Learning)的场景:
✅ 任务多变,难以收集大量标注数据
✅ 需要快速原型验证(几分钟内)
✅ 推理成本可接受(上下文较长)
✅ 任务在预训练数据分布内
✅ 对话系统(每次可定制行为)
使用微调(Fine-tuning)的场景:
✅ 有几百-几千条高质量标注数据
✅ 任务高度专业化(领域外知识)
✅ 需要稳定一致的输出格式
✅ 推理成本敏感(短Prompt)
✅ 生产系统(性能要求高)
决策树:
任务是否需要专业领域知识?
├── 是 → 有标注数据?
│ ├── 有(>500条)→ 微调(LoRA/SFT)
│ └── 没有 → RAG + Few-shot CoT
└── 否 → 任务复杂度如何?
├── 简单推理 → Zero-shot CoT
├── 中等复杂 → 3-5 shot CoT
└── 高度复杂 → Few-shot CoT + Self-Consistency
七、总结与展望
本文核心要点
1. ICL(In-Context Learning):
✓ 零梯度更新的"无参数学习"
✓ 本质是模式识别 + 任务激活
✓ 示例格式比标签正确性更重要
✓ 3-5个示例通常够用
2. CoT(思维链):
✓ 三种变体:Manual / Zero-shot / Auto
✓ 高级变体:ToT / Self-Consistency
✓ 仅对 >7B 的大模型有效
✓ Zero-shot CoT:一句话提升30%推理准确率
3. 涌现能力:
✓ 能力在阈值后突然出现,非线性增长
✓ 测量方式影响"涌现"的外观
✓ 大模型确实具有小模型不具备的新质能力
4. 实用建议:
✓ 先用Zero-shot CoT试水,成本极低
✓ 复杂推理 + 精度要求高 → Self-Consistency
✓ 选择示例时,动态检索 > 随机选取
✓ ICL失效时,考虑微调而非堆叠更多示例
技术演进方向
2020: GPT-3 → ICL的诞生("大力出奇迹")
2022: CoT → 推理能力显式化
2022: Self-Consistency → 采样+投票替代确定性
2023: ToT / GoT → 从线性推理到树/图结构
2024: o1 / DeepSeek-R1 → 推理时计算扩展("想更久")
2025: 推理模型成为默认范式,CoT内化为训练目标
2026: 更长思维链 + 验证器 = 自主纠错推理
趋势:推理时计算(Inference-time Compute)
从"训练更多数据"转向"推理时想更久"
o1系列的成功证明了这一路径的潜力
下期预告:《阶段总结:基础篇知识图谱与学习路径》------回顾前7篇的知识体系,梳理大模型基础认知的完整地图,并给出针对不同读者群体的学习建议。
参考资料
- Brown et al. (2020) --- Language Models are Few-Shot Learners(GPT-3论文,ICL的奠基之作)
- Wei et al. (2022) --- Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
- Min et al. (2022) --- Rethinking the Role of Demonstrations(揭示ICL标签正确性并不关键)
- Wang et al. (2022) --- Self-Consistency Improves Chain of Thought Reasoning
- Yao et al. (2023) --- Tree of Thoughts: Deliberate Problem Solving with Large Language Models
- Wei et al. (2022) --- Emergent Abilities of Large Language Models
- Schaeffer et al. (2023) --- Are Emergent Abilities of Large Language Models a Mirage?
- Akyurek et al. (2022) --- What Learning Algorithm is In-Context Learning? Investigations with Linear Models
延伸讨论
思考题:
- 你认为ICL是"真正的学习"还是"模式匹配"?它们的区别是什么?
- 为什么CoT对小模型(<7B)无效,甚至有时降低性能?
- 如果你要为一个医疗问诊系统选择Prompt策略,你会选ICL还是微调?为什么?
实践作业:
- 用OpenAI API或本地模型,对比Zero-shot / 3-shot / Zero-shot CoT在一个推理任务(如GSM8K数学题)上的准确率
- 实现一个简单的Self-Consistency采样(5次采样 + 多数投票)
- 观察不同触发词("请一步步思考" / "先分析过程" / "Let's think step by step")对模型推理的影响