文章目录
-
- [1. 概念](#1. 概念)
-
- [1.1 什么是示例选择器?](#1.1 什么是示例选择器?)
- [1.2 选择策略](#1.2 选择策略)
- [2. Length 选择器 - 根据长度选择](#2. Length 选择器 - 根据长度选择)
-
- [2.1 概念](#2.1 概念)
- [2.2 通俗理解](#2.2 通俗理解)
- [2.3 使用场景](#2.3 使用场景)
- [2.4 代码示例](#2.4 代码示例)
- [2.5 关键参数](#2.5 关键参数)
- [3. Similarity 选择器 - 根据语义相似性选择](#3. Similarity 选择器 - 根据语义相似性选择)
-
- [3.1 概念](#3.1 概念)
- [3.2 通俗理解](#3.2 通俗理解)
- [3.3 工作原理](#3.3 工作原理)
- [3.4 使用场景](#3.4 使用场景)
- [3.5 代码示例](#3.5 代码示例)
- [3.6 关键参数](#3.6 关键参数)
- [3.7 向量存储说明](#3.7 向量存储说明)
- [4. MMR 选择器 - 最大边际相关性](#4. MMR 选择器 - 最大边际相关性)
-
- [4.1 概念](#4.1 概念)
- [4.2 通俗理解](#4.2 通俗理解)
- [4.3 与 Similarity 的区别](#4.3 与 Similarity 的区别)
- [4.4 工作原理](#4.4 工作原理)
- [4.5 使用场景](#4.5 使用场景)
- [4.6 代码示例](#4.6 代码示例)
- [4.7 关键参数](#4.7 关键参数)
- [5. Ngram 选择器 - N-gram 重叠](#5. Ngram 选择器 - N-gram 重叠)
-
- [5.1 概念](#5.1 概念)
- [5.2 什么是 N-gram?](#5.2 什么是 N-gram?)
- [5.3 通俗理解](#5.3 通俗理解)
- [5.4 与 Similarity 的区别](#5.4 与 Similarity 的区别)
- [5.5 使用场景](#5.5 使用场景)
- [5.6 代码示例](#5.6 代码示例)
- [5.7 重叠度计算示例](#5.7 重叠度计算示例)
- [5.8 关键参数](#5.8 关键参数)
- [6. 四种选择器对比总结](#6. 四种选择器对比总结)
- [7. 实际应用建议](#7. 实际应用建议)
-
- [7.1 如何选择合适的选择器?](#7.1 如何选择合适的选择器?)
- [7.2 组合使用](#7.2 组合使用)
- [7.3 性能对比](#7.3 性能对比)
- [8. 常见问题](#8. 常见问题)
-
- [8.1 为什么需要示例选择器?](#8.1 为什么需要示例选择器?)
- [8.2 如何调试选择器?](#8.2 如何调试选择器?)
- [8.3 向量数据库存储在哪里?](#8.3 向量数据库存储在哪里?)
- [8.4 如何使用纯内存模式?](#8.4 如何使用纯内存模式?)
- [9. 完整示例对比](#9. 完整示例对比)
-
- [9.1 相同输入,不同选择器的结果](#9.1 相同输入,不同选择器的结果)
- [10. 关键要点](#10. 关键要点)
- [12. 参考资料](#12. 参考资料)

1. 概念
1.1 什么是示例选择器?
一旦我们有了示例数据集,就需要考虑提示中应该有多少个示例。关键的权衡是,更多的示例通常会提高性能,但更大的提示会增加成本和延迟。超过某个阈值,太多示例可能会开始混淆模型。
找到正确数量的示例在很大程度上取决于模型、任务、示例的质量以及成本和延迟限制。有趣的是,模型越好,它需要精准的示例就越少。但其实,最佳的方法是使用不同数量的示例进行一些实验。
若此时我们有【大量】的示例数据集。对于大模型来说,就没必要全部使用与参考。我们需要有一种方法可以根据给定的输入,从数据集中选择示例。
在 LangChain 中,示例选择器就可以帮我们从一组【示例的集合】中根据具体策略选择正确的【示例子集】构建少样本提示。

1.2 选择策略
LangChain 提供了四种主要的示例选择策略:
- Length(长度):根据指定【长度】内可以容纳的数量选择示例
- Similarity(语义相似性):使用输入和示例之间的【语义相似性】来决定选择哪些示例
- MMR(最大边际相关性):使用输入和示例之间的【最大边际相关性】来决定要选择哪些示例
- Ngram(N-gram 重叠):使用输入和示例之间的【ngram 重叠】来决定要选择哪些示例
这些其实都是自然语言处理(NLP)里的相似性衡量问题。
2. Length 选择器 - 根据长度选择
2.1 概念
LengthBasedExampleSelector 根据指定的【长度限制】来选择示例。它会计算每个示例的长度,然后选择能够在长度限制内容纳的示例。
2.2 通俗理解
就像打包行李箱:
- 你有一个固定大小的行李箱(max_length)
- 你有很多衣服要带(examples)
- 你会按顺序往里装,直到装不下为止
2.3 使用场景
- 当你的 Prompt 有长度限制时(比如 API 限制)
- 当你想控制成本时(更短的 Prompt = 更便宜)
- 当你的示例长度差异很大时
2.4 代码示例
python
# 根据长度决定的示例选择器
from langchain_core.example_selectors import LengthBasedExampleSelector
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
# 一些例子方便测试
examples = [
{"input": "1$2", "output": "0.5"},
{"input": "2$3", "output": "0.6666666666666666"},
{"input": "3$6", "output": "0.5"},
]
# 提示词模版
template_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
# 创建一个根据长度选择示例的选择器
example_selector = LengthBasedExampleSelector(
examples=examples,
example_prompt=template_prompt,
max_length=5, # 最大长度为5个单词
# 默认函数
# get_text_length: Callable[[str], int] = lambda x: len(re.split("\n| ",x))
# 也可自定义
)
# 少样本提示模版
few_shot_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=template_prompt,
input_variables=["input"],
prefix="请根据以下示例回答问题:",
suffix="问题:{input}\n回答:",
)
# 调用
result = few_shot_prompt.invoke({"input": "4$8"})
print(result.text)
输出示例:
请根据以下示例回答问题:
Input: 1$2
Output: 0.5
问题:4$8
回答:
2.5 关键参数
examples:示例列表example_prompt:示例的格式模板max_length:最大长度限制(单词数)get_text_length:自定义长度计算函数(可选)
3. Similarity 选择器 - 根据语义相似性选择
3.1 概念
SemanticSimilarityExampleSelector 使用【语义相似性】来选择示例。它会将输入和所有示例转换为向量(embeddings),然后计算相似度,选择最相似的示例。
3.2 通俗理解
就像找相似的朋友:
- 你说"我喜欢小狗"
- 系统会找到"小猫"、"小兔子"这些相似的动物示例
- 而不会选择"苹果"、"汽车"这些不相关的
3.3 工作原理
-
文本 → 向量:使用嵌入模型将文本转换为向量
"小狗" → [0.23, -0.45, 0.67, ...] (768维向量) -
存储到向量数据库:使用 Chroma 等向量数据库存储
Chroma 保存:文本 + 向量 + 元数据 -
查询时计算相似度:
- 输入"小象" → 转成向量
- 在 Chroma 中搜索最相似的向量
- 返回最相似的 k 个示例
3.4 使用场景
- 当你的示例有明确的语义含义时
- 当你想根据输入的含义选择相关示例时
- 当你有大量示例需要智能筛选时
3.5 代码示例
python
# 基于语义相似性的示例选择器
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_chroma import Chroma
from langchain_google_genai import GoogleGenerativeAIEmbeddings
# 制造例子基于语义相似性的
examples = [
{"input": "小狗", "output": "狗小"},
{"input": "小猫", "output": "猫小"},
{"input": "苹果", "output": "果果"},
{"input": "橙子", "output": "子子"},
{"input": "巧克力", "output": "巧克力"},
]
# 模版
template_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
# 创建一个根据语义相似性选择示例的选择器
semantic_selector = SemanticSimilarityExampleSelector.from_examples(
# 示例列表
examples,
# 谷歌嵌入模型
GoogleGenerativeAIEmbeddings(model="gemini-embedding-001"),
# 向量存储
Chroma,
k=2, # 生成示例个数
)
# 实例化模版few_shot_prompt
few_shot_prompt = FewShotPromptTemplate(
example_selector=semantic_selector,
example_prompt=template_prompt,
input_variables=["input"],
prefix="请根据以下示例回答问题:",
suffix="问题:{input}\n回答:",
)
# 调用 - 输入"小象"会选择"小狗"、"小猫"这些相似的动物
result = few_shot_prompt.invoke({"input": "小象"})
print(result.text)
输出示例:
请根据以下示例回答问题:
Input: 小狗
Output: 狗小
Input: 小猫
Output: 猫小
问题:小象
回答:
3.6 关键参数
examples:示例列表embeddings:嵌入模型(如 GoogleGenerativeAIEmbeddings)vectorstore:向量存储(如 Chroma)k:返回的示例数量
3.7 向量存储说明
Chroma 是一个向量数据库,默认情况下:
- 存储位置 :本地磁盘(会在当前目录创建
chroma文件夹) - 也支持内存模式:可以配置为纯内存存储
好处:
- 首次运行:计算向量并保存
- 后续运行:直接读取,速度更快
4. MMR 选择器 - 最大边际相关性
4.1 概念
MaxMarginalRelevanceExampleSelector 使用【最大边际相关性】来选择示例。它在相似性和多样性之间取得平衡。
4.2 通俗理解
就像组建一个多元化的团队:
- 你想找"开心"相关的词
- 普通相似性选择器会给你:快乐、高兴、喜悦(都很相似)
- MMR 会给你:快乐(相似)、悲伤(对比)、苹果(多样性)
目的:避免选择过于重复的示例,增加示例的多样性。
4.3 与 Similarity 的区别
| 特性 | Similarity 选择器 | MMR 选择器 |
|---|---|---|
| 选择标准 | 只看相似度 | 相似度 + 多样性 |
| 示例特点 | 可能都很相似 | 相似但有多样性 |
| 使用场景 | 需要高度相关的示例 | 需要相关但不重复的示例 |
| 示例 | 快乐、高兴、喜悦 | 快乐、悲伤、苹果 |
4.4 工作原理
- 先获取相似的 :
fetch_k=5先获取 5 个最相似的示例 - 再选择多样的 :
k=3从这 5 个中选择多样性高的 3 个 - 平衡算法:MMR 算法确保既相关又不重复
4.5 使用场景
- 当你的示例中有很多相似的内容时
- 当你想避免示例过于单一时
- 当你想让 LLM 看到更全面的示例时
4.6 代码示例
python
# 基于mmr的示例选择器(最大边际相关性)
from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_chroma import Chroma
from langchain_google_genai import GoogleGenerativeAIEmbeddings
# 制造例子 - 注意有很多相似的情感词
examples = [
{"input": "快乐", "output": "开心"},
{"input": "高兴", "output": "愉快"},
{"input": "喜悦", "output": "欢乐"},
{"input": "悲伤", "output": "难过"},
{"input": "伤心", "output": "痛苦"},
{"input": "苹果", "output": "水果"},
{"input": "香蕉", "output": "水果"},
{"input": "汽车", "output": "交通工具"},
]
# 模版
template_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Input: {input}\nOutput: {output}",
)
# 创建一个根据基于语义相似性为基础的mmr选择示例的选择器
semantic_selector = MaxMarginalRelevanceExampleSelector.from_examples(
# 示例列表
examples,
# 谷歌嵌入模型
GoogleGenerativeAIEmbeddings(model="gemini-embedding-001"),
# 本地基于内存的向量存储
Chroma,
k=3, # 最终返回3个示例
fetch_k=5, # 先获取5个最相似的,再从中选择多样性高的3个
)
# 实例化模版few_shot_prompt
few_shot_prompt = FewShotPromptTemplate(
example_selector=semantic_selector,
example_prompt=template_prompt,
input_variables=["input"],
prefix="请根据以下示例回答问题:",
suffix="问题:{input}\n回答:",
)
# 调用 - 输入"开心"会选择相似但多样的示例
result = few_shot_prompt.invoke({"input": "开心"})
print(result.text)
输出示例:
请根据以下示例回答问题:
Input: 快乐
Output: 开心
Input: 伤心
Output: 痛苦
Input: 香蕉
Output: 水果
问题:开心
回答:
分析:
- 选择了"快乐"(最相似)
- 选择了"伤心"(情感词但相反,增加多样性)
- 选择了"香蕉"(完全不同类别,增加多样性)
4.7 关键参数
examples:示例列表embeddings:嵌入模型vectorstore:向量存储k:最终返回的示例数量fetch_k:先获取的候选示例数量(应该 > k)
5. Ngram 选择器 - N-gram 重叠
5.1 概念
NGramOverlapExampleSelector 使用【N-gram 重叠】来选择示例。它计算输入和示例之间的 n-gram 重叠度,选择重叠度最高的示例。
5.2 什么是 N-gram?
N-gram 是连续的 n 个字符或词的序列:
示例:"我很喜欢苹果"
- 1-gram(unigram):我、很、喜、欢、苹、果
- 2-gram(bigram):我很、很喜、喜欢、欢苹、苹果
- 3-gram(trigram):我很喜、很喜欢、喜欢苹、欢苹果
5.3 通俗理解
就像找共同话题:
- 你说"我很喜欢橙子"
- 系统会找包含"喜欢"的示例:"喜欢苹果"、"喜欢香蕉"
- 因为它们有共同的 n-gram:"喜欢"
5.4 与 Similarity 的区别
| 特性 | Similarity(语义相似性) | Ngram(字符重叠) |
|---|---|---|
| 匹配方式 | 理解语义含义 | 字符串匹配 |
| 技术 | 向量嵌入 + 余弦相似度 | 字符串重叠计算 |
| 示例 | "快乐" 匹配 "高兴" | "喜欢苹果" 匹配 "喜欢香蕉" |
| 优点 | 理解同义词 | 速度快,不需要模型 |
| 缺点 | 需要嵌入模型 | 不理解语义 |
5.5 使用场景
- 当你的示例有明显的关键词重叠时
- 当你不需要深度语义理解时
- 当你想要快速匹配时(不需要嵌入模型)
5.6 代码示例
python
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_community.example_selectors import NGramOverlapExampleSelector
# 使用简单的中文词组示例,便于观察 n-gram 重叠选择效果
examples = [
{"input": "快乐", "output": "开心"},
{"input": "悲伤", "output": "难过"},
{"input": "愤怒", "output": "生气"},
{"input": "i like apple", "output": "喜欢水果"},
{"input": "喜欢吃香蕉", "output": "喜欢水果"},
{"input": "喜欢汽车", "output": "喜欢交通工具"},
]
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="问题:{input}\n回答:{output}",
)
# NGramOverlapExampleSelector 根据 n-gram 重叠度选择和排序示例
selector = NGramOverlapExampleSelector(
examples=examples,
example_prompt=example_prompt,
threshold=0.0, # 只返回有 n-gram 重叠的示例
)
few_shot_prompt = FewShotPromptTemplate(
example_selector=selector,
example_prompt=example_prompt,
input_variables=["input"],
prefix="请根据以下示例回答问题:\n",
suffix="\n问题:{input}\n回答:",
)
# 测试:输入"i like"会选择包含"i like"的示例
result = few_shot_prompt.invoke({"input": "i like"})
print(result.text)
输出示例:
请根据以下示例回答问题:
问题:i like apple
回答:喜欢水果
问题:i like
回答:
分析:
- 输入"i like"与"i like apple"有最高的 n-gram 重叠
- 所以选择了这个示例
5.7 重叠度计算示例
输入 :"喜欢橙子"
2-gram:喜欢、欢橙、橙子
示例1 :"喜欢苹果"
2-gram :喜欢、欢苹、苹果
重叠 :喜欢(1个)
重叠度:1/5 = 0.2
示例2 :"喜欢吃香蕉"
2-gram :喜欢、欢吃、吃香、香蕉
重叠 :喜欢(1个)
重叠度:1/6 = 0.17
示例3 :"快乐"
2-gram :快乐
重叠 :0个
重叠度:0
结果:选择"喜欢苹果"和"喜欢吃香蕉"
5.8 关键参数
examples:示例列表example_prompt:示例格式模板threshold:重叠度阈值-1.0:返回所有示例(按重叠度排序)0.0:只返回有重叠的示例1.0:只返回完全匹配的示例
6. 四种选择器对比总结
| 选择器 | 选择依据 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|---|
| Length | 长度限制 | 简单、可控成本 | 不考虑相关性 | 有长度限制时 |
| Similarity | 语义相似度 | 理解语义、智能 | 需要嵌入模型 | 需要语义匹配时 |
| MMR | 相似度+多样性 | 避免重复、全面 | 计算复杂 | 需要多样化示例时 |
| Ngram | 字符重叠 | 快速、无需模型 | 不理解语义 | 有明显关键词时 |
7. 实际应用建议
7.1 如何选择合适的选择器?
- 有长度限制 → 使用 Length
- 需要语义理解 → 使用 Similarity
- 避免示例重复 → 使用 MMR
- 关键词匹配 → 使用 Ngram
7.2 组合使用
你也可以组合使用多个选择器:
python
# 先用 Similarity 选出相关的
# 再用 Length 控制长度
# 最后用 MMR 增加多样性
7.3 性能对比
| 选择器 | 速度 | 准确性 | 成本 |
|---|---|---|---|
| Length | ⭐⭐⭐⭐⭐ | ⭐⭐ | 免费 |
| Similarity | ⭐⭐⭐ | ⭐⭐⭐⭐ | 需要嵌入模型 |
| MMR | ⭐⭐ | ⭐⭐⭐⭐⭐ | 需要嵌入模型 |
| Ngram | ⭐⭐⭐⭐ | ⭐⭐⭐ | 免费 |
8. 常见问题
8.1 为什么需要示例选择器?
当你有大量示例时:
- 全部使用 → 成本高、延迟大、可能混淆模型
- 手动选择 → 不智能、不灵活
- 使用选择器 → 自动、智能、高效
8.2 如何调试选择器?
python
# 查看选择了哪些示例
selected = selector.select_examples({"input": "测试输入"})
for ex in selected:
print(f"{ex['input']} -> {ex['output']}")
8.3 向量数据库存储在哪里?
默认情况下,Chroma 会在当前目录创建 chroma 文件夹(也可基于内存创建的,上面写的例子就是被当做内存的了):
d:\trae开发\langchain-learn\示例选择器\
├── chroma/ ← 自动创建的向量数据库
├── length.py
├── Similarity.py
├── MMR.py
└── ngram.py
8.4 如何使用纯内存模式?
python
semantic_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
embeddings,
Chroma,
k=2,
vectorstore_kwargs={
"persist_directory": None # None 表示纯内存
}
)
9. 完整示例对比
9.1 相同输入,不同选择器的结果
输入:"我喜欢水果"
Length 选择器:
选择前 2 个示例(不管相关性)
Similarity 选择器:
选择:苹果、橙子(水果相关)
MMR 选择器:
选择:苹果(水果)、汽车(多样性)
Ngram 选择器:
选择:喜欢苹果、喜欢香蕉(包含"喜欢")
10. 关键要点
- 示例选择器的核心作用:从大量示例中智能选择最合适的子集
- 四种策略各有特点:根据实际需求选择
- Similarity 和 MMR 需要嵌入模型:会产生额外成本
- Length 和 Ngram 不需要模型:速度快、免费
- MMR 是 Similarity 的升级版:增加了多样性考虑
- 实际应用中可以组合使用:发挥各自优势