一、Few-shot 学习基础
Few-shot Prompt 是 In-Context Learning(上下文学习)的核心实现方式——在 Prompt 中提供少量输入-输出示例,让模型"学会"目标任务模式,无需更新模型参数即可完成新任务。
1.1 三种模式对比
| 模式 | 示例数 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|---|
| Zero-shot | 0 | 通用任务、简单分类 | 最简洁、最少 token 消耗 | 复杂任务准确率低 |
| Few-shot | 1-5 | 格式约束、新概念、风格迁移 | 精准控制输出格式和风格 | 需要设计示例 |
| Many-shot | 10-100+ | 复杂模式学习、规则归纳 | 接近微调效果 | token 开销大 |
1.2 In-Context Learning 的工作原理
Few-shot 学习的本质是:模型在前向传播过程中,利用注意力机制从示例中提取出输入-输出的映射模式,并在推理时复用该模式。
# Few-shot 学习示意代码
def build_few_shot_prompt(examples: list, test_input: str) -> str:
"""
examples: [{"input": "...", "output": "..."}, ...]
"""
prompt_parts = []
for i, example in enumerate(examples):
prompt_parts.append(f"输入 {i+1}: {example['input']}")
prompt_parts.append(f"输出 {i+1}: {example['output']}")
prompt_parts.append("")
prompt_parts.append(f"输入 {len(examples)+1}: {test_input}")
prompt_parts.append(f"输出 {len(examples)+1}: ")
return "\n".join(prompt_parts)
# 示例:情感分类
examples = [
{"input": "这部电影太精彩了!", "output": "正面"},
{"input": "质量很差,不推荐购买。", "output": "负面"},
{"input": "还可以吧,一般般。", "output": "中性"},
]
test_input = "服务态度非常好,下次还来!"
prompt = build_few_shot_prompt(examples, test_input)
print(prompt)
二、示例选择策略
2.1 代表性选择
示例要覆盖任务的典型模式,而非随机选取。
import numpy as np
from sentence_transformers import SentenceTransformer
def select_diverse_examples(candidates: list, n: int = 3):
"""
基于嵌入相似度选择多样化的 Few-shot 示例
"""
model = SentenceTransformer('all-MiniLM-L6-v2')
texts = [c["input"] for c in candidates]
embeddings = model.encode(texts)
# 使用 k-means++ 初始化策略:选择彼此距离最远的样本
selected_indices = []
remaining = list(range(len(candidates)))
# 第一个随机选
first = np.random.choice(remaining)
selected_indices.append(first)
remaining.remove(first)
# 后续选与已选距离最大的
for _ in range(n - 1):
distances = []
for r in remaining:
min_dist = min(np.linalg.norm(embeddings[r] - embeddings[s])
for s in selected_indices)
distances.append(min_dist)
best_idx = remaining[np.argmax(distances)]
selected_indices.append(best_idx)
remaining.remove(best_idx)
return [candidates[i] for i in selected_indices]
2.2 难度递进策略
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 简单→复杂 | 从易到难排列示例 | 分类、格式转换 |
| 相似优先 | 与目标问题最相似的示例放在最后 | QA、推理 |
| 边界覆盖 | 选决策边界附近的样本 | 精细分类 |
| 随机排列 | 打乱示例顺序 | 消除位置偏差 |
2.3 示例数量与效果关系
实验数据(GSM8K 数学推理):
示例数 | 准确率 | Token 消耗(avg)
0 | 58.2% | 120 tokens
1 | 68.5% | 280 tokens
3 | 74.1% | 520 tokens
5 | 76.8% | 760 tokens
8 | 77.3% | 1100 tokens
16 | 77.5% | 1900 tokens
关键发现:3-5 个示例性价比最高,再增加收益递减。
三、示例格式设计
3.1 格式一致原则
# ❌ 不规范的格式混搭
examples_bad = [
{"input": "翻译:Hello → ", "output": "你好"},
{"input": "请将 'Goodbye' 翻译成中文", "output": "再见"},
]
# ✅ 格式必须严格一致
examples_good = [
{"input": "English: Hello\nChinese:", "output": "你好"},
{"input": "English: Goodbye\nChinese:", "output": "再见"},
{"input": "English: Thank you\nChinese:", "output": "谢谢"},
]
3.2 标记对齐
输入和输出的分隔标记在整个 Prompt 中保持一致,避免混淆。
✅ 推荐格式 1(XML 标签):
<example>
<input>电影评价:好看</input>
<output>positive</output>
</example>
✅ 推荐格式 2(结构化文本):
## 输入
电影评价:好看
## 输出
positive
✅ 推荐格式 3(Markdown 表格):
| 输入 | 输出 |
|------|------|
| 电影评价:好看 | positive |
3.3 System Prompt + Few-shot 混合设计
system_prompt = """你是一个文本分类专家。请根据输入文本的情感倾向,输出"正面"、"负面"或"中性"。
分类规则:
1. 包含积极正面词汇 → 正面
2. 包含消极负面词汇 → 负面
3. 无明显倾向或中立 → 中性
4. 讽刺或反语 → 根据实际意图判断"""
few_shot_examples = """
输入: 这个产品质量很棒,性价比高
输出: 正面
输入: 垃圾产品,用三天就坏了
输出: 负面
输入: 普普通通,没什么特别之处
输出: 中性
"""
test_input = "这款手机拍照效果超出预期!"
full_prompt = f"{system_prompt}\n\n{few_shot_examples}\n\n输入: {test_input}\n输出:"
四、高级 Few-shot 技术
4.1 动态示例检索
根据测试输入实时检索最相似的示例,而非固定示例集。
import chromadb
from chromadb.utils import embedding_functions
class DynamicFewShot:
def __init__(self, example_db: list):
self.client = chromadb.Client()
self.collection = self.client.create_collection(
name="examples",
embedding_function=embedding_functions.DefaultEmbeddingFunction()
)
# 索引示例
for i, ex in enumerate(example_db):
self.collection.add(
ids=[str(i)],
documents=[ex["input"]],
metadatas=[{"output": ex["output"]}]
)
def retrieve(self, query: str, n: int = 3) -> list:
results = self.collection.query(
query_texts=[query],
n_results=n
)
examples = []
for i, doc in enumerate(results['documents'][0]):
examples.append({
"input": doc,
"output": results['metadatas'][0][i]['output']
})
return examples
# 使用示例
db = [
{"input": "今天天气真好", "output": "positive"},
{"input": "又下雨了,真烦", "output": "negative"},
# ... 更多示例
]
dfs = DynamicFewShot(db)
relevant = dfs.retrieve("这家餐厅太难吃了", n=3)
4.2 标签重排序
当输出空间很大时,先让模型生成候选标签,再基于候选进行 Few-shot。
def two_stage_few_shot(text: str, all_labels: list) -> str:
"""两阶段 Few-shot:先缩小标签范围,再精确分类"""
# Stage 1: 标签精简
stage1_prompt = f"""从以下标签中选出最可能相关的 5 个标签:
{', '.join(all_labels)}
文本: {text}
最相关的标签:"""
# ... 获取模型输出的 5 个候选标签
# Stage 2: 用候选标签相关的 Few-shot 示例精确分类
candidate_labels = ["投诉", "咨询", "建议", "表扬", "售后"] # 假设输出
few_shot_examples = get_examples_for_labels(candidate_labels)
final_prompt = f"{few_shot_examples}\n\n文本: {text}\n标签:"
# ... 调用模型获取最终标签
4.3 带推理的 Few-shot
每个示例不仅包含输入和输出,还包含中间推理步骤。这比纯示例更有效。
| 形式 | 示例 | 适用场景 |
|---|---|---|
| 输入→输出 | 好评→正面 | 简单分类 |
| 输入→推理→输出 | 好评→含积极词汇…→正面 | 复杂推理 |
| 输入→规则→输出 | 好评→规则:积极关键词匹配→正面 | 规则学习 |
| 输入→约束→输出 | 好评→约束:正面;格式:单个词 | 格式约束 |
五、实际案例
5.1 代码生成 Few-shot
# Code generation with few-shot
code_examples = """
输入: Python 函数,计算列表平均值
输出:
def average(lst):
return sum(lst) / len(lst) if lst else 0
输入: Python 函数,将字符串反转
输出:
def reverse_string(s):
return s[::-1]
输入: Python 函数,检查是否为回文
输出:
def is_palindrome(s):
clean = ''.join(c.lower() for c in s if c.isalnum())
return clean == clean[::-1]
"""
test_prompt = f"{code_examples}\n\n输入: Python 函数,合并两个字典\n输出:"
5.2 数据抽取 Few-shot
## 任务:从简历中抽取结构化信息
## 示例 1
文本: 张三,2018年毕业于清华大学计算机系,曾在字节跳动担任高级工程师3年。
输出:
- 姓名: 张三
- 毕业院校: 清华大学
- 毕业年份: 2018年
- 专业: 计算机系
- 最近公司: 字节跳动
- 职位: 高级工程师
- 工作年限: 3年
## 示例 2
文本: 李四,北京大学金融硕士,CFA持证人,目前就职于高盛。
输出:
- 姓名: 李四
- 毕业院校: 北京大学
- 学历: 硕士
- 专业: 金融
- 证书: CFA
- 最近公司: 高盛
## 目标文本
文本: {target_text}
输出:
六、性能调优
6.1 Few-shot 检查清单
- 示例覆盖了所有主要的输出类别
- 示例的输入-输出映射关系清晰无歧义
- 示例格式严格一致(标点、空格、换行)
- 示例数量在 3-5 个之间
- 最复杂或有挑战的示例放在最后
- 示例和测试输入之间没有格式跳跃
- 考虑了示例的 bias(正向/负向平衡)
6.2 常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 模型复制示例输出 | 示例与目标太相似 | 增大输入差异性 |
| 对示例顺序敏感 | 位置偏差 | 多次随机排列取多数 |
| 复杂任务效果差 | 示例不够 | 增加示例或转为 Many-shot |
| 格式不一致 | 输出格式混搭 | 严格对齐格式标记 |
七、总结
Few-shot Prompt 是 Prompt 工程中最实用、最灵活的技术之一。核心要点:
- 示例质量 > 数量 — 3 个好示例远胜 10 个
- 格式一致性是关键 — 模型对格式极其敏感
- 动态检索是进阶方向 — 告别固定示例,拥抱相似度检索
- 与 System Prompt 互补 — 规则 + 示例是最强组合
- 始终考虑 token 预算 — Few-shot 不是免费的
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
