跳到主要内容

少样本学习(Few-shot)

少样本学习(Few-shot Learning)是通过在 Prompt 中提供少量输入-输出示例,引导 LLM 理解任务要求和期望输出格式的技术。这是最直观、最有效的提示工程策略之一。

Zero-shot vs One-shot vs Few-shot

根据提供示例数量的不同,分为三种模式:

Zero-shot

不提供任何示例,直接给出任务描述:

将以下产品评论分类为"正面"、"负面"或"中性":
"这款手机的摄像头非常棒,电池续航也超出预期!"

适用场景:模型已经充分理解的通用任务(简单情感分析、语言翻译等)。

One-shot

提供一个示例:

将产品评论分类为"正面"、"负面"或"中性":

示例:
输入:"物流很慢,包装也破损了,很失望。"
输出:负面

请分类:
输入:"这款手机的摄像头非常棒,电池续航也超出预期!"
输出:

Few-shot

提供 3-8 个示例(经验上最优区间):

将产品评论分类为"正面"、"负面"或"中性":

示例1:
输入:"物流很慢,包装也破损了,很失望。"
输出:负面

示例2:
输入:"产品质量一般,价格也算合理,勉强还行。"
输出:中性

示例3:
输入:"超出预期!质量很好,发货也快,强烈推荐!"
输出:正面

请分类:
输入:"颜色跟图片有点差异,不过总体还能接受。"
输出:

示例选择策略

Few-shot 示例的质量比数量更重要。以下是选择高质量示例的核心原则:

多样性

示例应覆盖任务的各种情况,避免只选择"简单的正面案例":

  • 覆盖不同的类别/输出类型
  • 包含边界情况(如"中性"这种难以判断的评论)
  • 体现任务的真实复杂性
# 差的示例集(缺乏多样性)
示例1:很好的产品 → 正面
示例2:非常满意 → 正面
示例3:超级推荐 → 正面

# 好的示例集(多样性充足)
示例1:很好的产品 → 正面
示例2:有点小问题但总体OK → 中性
示例3:质量很差,退货 → 负面
示例4:手感不错但颜色与描述不符 → 中性(边界案例)

相关性

示例应与实际输入在分布上尽可能接近:

  • 领域相关:处理医疗文本时,示例也应来自医疗领域
  • 风格相关:如果实际输入是口语化的,示例也应该是口语化的
  • 难度相关:包含与实际问题相近难度的案例

格式一致性

所有示例必须遵循完全一致的格式,输出格式也必须统一:

  • 相同的字段顺序
  • 相同的标点和换行习惯
  • 一致的语言风格

示例顺序对效果的影响

研究表明,Few-shot 示例的顺序会显著影响模型输出,这被称为"顺序偏差(Order Bias)":

  • 放在最后的示例对模型输出影响最大(近因效应)
  • 因此,最相关或最代表性的示例应放在最后
  • 如果担心顺序偏差影响结果,可以用相同示例以不同顺序测试几次,取平均

建议:将最典型、最具代表性的示例放在示例列表的最后位置。

动态少样本检索(Dynamic Few-shot)

静态 Few-shot 对所有输入使用相同的示例集;动态 Few-shot 根据每个具体输入,实时检索最相关的示例。

from sentence_transformers import SentenceTransformer
import numpy as np

# 示例库(可以有数百条)
example_pool = [
{"input": "...", "output": "..."},
# 数百个示例
]

# 预计算所有示例的 embedding
encoder = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
example_embeddings = encoder.encode([ex["input"] for ex in example_pool])

def get_dynamic_few_shot(query, k=4):
"""根据查询检索最相关的 k 个示例"""
query_embedding = encoder.encode([query])
# 计算余弦相似度
similarities = np.dot(example_embeddings, query_embedding.T).flatten()
# 取 Top-k 最相似的示例
top_k_indices = similarities.argsort()[-k:][::-1]
return [example_pool[i] for i in top_k_indices]

# 使用
query = "这个产品不错,但是客服态度差"
selected_examples = get_dynamic_few_shot(query, k=4)
# 将选出的示例组织为 Few-shot Prompt

动态检索的核心思想:与查询语义最相似的示例,能提供最有针对性的参考,帮助模型处理类似的输入。

示例数量的最优值

理论上,更多示例提供更多信息;实践中,示例越多也会:

  • 增加 Prompt 长度,提高 API 成本
  • 在长上下文中,早期示例可能被遗忘
  • 某些模型在过长 Prompt 时性能下降

经验规律

  • 3-5 个示例:对大多数分类和格式化任务已经足够
  • 8-10 个示例:针对需要精细示例的复杂任务
  • >10 个示例:通常边际收益下降,考虑微调代替

对于每个具体任务,建议通过实验找到最优示例数(分别测试 0、1、3、5、8 个示例的效果)。

Prompt 长度与成本的权衡

Few-shot Prompt 的成本可观:

假设每个示例平均 100 token,使用 5 个示例:
额外成本 = 5 × 100 = 500 token/次请求
每月 10 万次请求:
额外输入 token = 5000 万 token
GPT-4o 成本($5/M token):$250/月 额外费用

成本控制策略:

  • 精简示例文字,去掉冗余解释
  • 动态 Few-shot 只针对复杂输入启用,简单输入用 Zero-shot
  • 考虑将复杂格式示例微调到模型中,减少运行时 Prompt 长度

RAG 与 Few-shot 的结合

RAG(检索增强生成)和 Dynamic Few-shot 都基于相似检索,可以自然结合:

[系统提示]
你是一位专业的法律助手。

[动态检索的类似案例(Few-shot)]
案例1:[与用户问题相似的历史法律问题及答案]
案例2:[另一个相关案例]

[RAG 检索的相关知识文档]
根据《合同法》第XX条:...

[用户问题]
我和供应商签订了合同,对方违约了,我该怎么办?

这种组合利用 Few-shot 告诉模型"如何回答这类问题",利用 RAG 提供"回答问题所需的知识",两者互补。