纲要
- 回顾余弦相似度选择器的优势与局限
- 最大边际相关性(MMR)算法
- 目标:在相关性与多样性之间取得平衡
- 核心机制:惩罚与已选示例过于相似的样本
- LangChain 中的 MMR 示例选择器
MaxMarginalRelevanceExampleSelector- 与余弦相似度选择器的对比
- 完整可运行代码:使用 FAISS 向量库与
FakeEmbeddings模拟嵌入 - 适用场景与选型建议
引言
基于余弦相似度的 SemanticSimilarityExampleSelector 能够从示例池中精准地找出与输入语义最相似的 Top-K 个示例。然而,当示例池中存在大量高度相似的样本时(例如几乎相同的双语版本),余弦相似度选择器往往会返回多个“同质化”的示例。这些示例虽然都与输入相关,但彼此之间没有提供额外的多样性信息,导致 Few-Shot 提示中的示例缺乏代表性。
为了解决这个问题,LangChain 提供了基于最大边际相关性(Maximal Marginal Relevance,简称 MMR)的示例选择器。MMR 在保证示例与输入相关的同时,刻意避免选出过于雷同的样本,从而让 Few-Shot 提示中的示例更具代表性,覆盖更多视角。
MMR 算法原理
MMR 最初应用于信息检索和文本摘要领域,其核心思想是:在每一步选择新的结果时,既考虑该结果与查询的相关性,又考虑其与已选择结果的差异性。
在示例选择场景中,MMR 的计算逻辑如下:
- 首先找到与输入最相似(余弦相似度最大)的示例,并将其选入结果集。
- 对于后续候选示例,其最终得分为:
- 相关性得分:候选示例与输入之间的余弦相似度。
- 多样性惩罚:候选示例与已选示例集合之间的最大余弦相似度。
- 最终得分 = 相关性得分 - λ × 多样性惩罚(其中 λ 为惩罚系数,通常取 0.5)。
- 选择最终得分最高的示例加入结果集,重复此过程直到选出 K 个示例。
MMR 通过引入多样性惩罚机制,有效避免了示例同质化问题,使得最终选出的 Top-K 个示例既能保持与任务的高度相关,又能尽量分散在语义空间的不同方向上,从而向模型提供更丰富的参考信息。
MMR 与余弦相似度选择器的对比
下表直观展示了两种选择器在相同输入下的行为差异。示例池中包含中英文情绪词、天气词以及体型词,输入为“难过”,K 值设为 2。
| 选择器类型 | 输入 | K 值 | 返回示例 | 特点 |
|---|---|---|---|---|
| 余弦相似度 | 难过 | 2 | 高兴/悲伤, happy/sad | 两个示例高度同质(中英对照),仅体现情绪维度 |
| MMR | 难过 | 2 | 高兴/悲伤, tall/short 或 big/small | 第一个示例最相关,第二个示例来自不同语义方向,增加多样性 |
可见,MMR 避免了“把鸡蛋放在一个篮子里”的问题,尤其适用于示例池规模较大且存在多条近似示例的场景。
完整可运行代码
以下代码使用 FAISS 向量库和 FakeEmbeddings 模拟嵌入过程,演示 MaxMarginalRelevanceExampleSelector 的用法。无需任何外部 API Key 即可运行。适用的 LangChain 版本为 >=0.2.0。
安装依赖:
pip install langchain langchain-core langchain-community faiss-cpu
核心代码:
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector
from langchain_community.embeddings.fake import FakeEmbeddings
from langchain_community.vectorstores import FAISS
# 1. 构建示例池(包含中英文、情绪与体型等多类反义词)
examples = [
{"input": "happy", "output": "sad"},
{"input": "高兴", "output": "悲伤"},
{"input": "sunny", "output": "gloomy"},
{"input": "晴朗", "output": "阴沉"},
{"input": "tall", "output": "short"},
{"input": "高", "output": "矮"},
]
# 2. 示例格式化模板
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="原词: {input}\n反义词: {output}"
)
# 3. 创建 MMR 示例选择器
# 使用 FakeEmbeddings(size=128) 模拟嵌入
embedding_model = FakeEmbeddings(size=128)
mmr_selector = MaxMarginalRelevanceExampleSelector.from_examples(
examples=examples,
embeddings=embedding_model,
vectorstore_cls=FAISS,
k=2, # 返回 2 个示例
fetch_k=5, # 先获取 5 个候选再从中做 MMR 筛选
)
# 4. 构建 Few Shot 提示词模板
mmr_prompt = FewShotPromptTemplate(
example_selector=mmr_selector,
example_prompt=example_prompt,
prefix="给出每个输入词的反义词:",
suffix="原词: {input}\n反义词:",
input_variables=["input"],
)
# 5. 测试:输入中文情绪词“难过”
print("=== 输入: 难过 ===")
print(mmr_prompt.format(input="难过"))
运行上述代码后,输入“难过”会优先匹配到 高兴/悲伤 这一最相关的示例。第二个示例则可能是 tall/short 或 高/矮 等与情绪无关但能提供其他维度信息的条目,从而实现了多样化的 Few-Shot 示例组合。
代码说明
FakeEmbeddings:LangChain 提供的模拟嵌入模型,无需真实 API 即可生成随机向量,便于本地测试和演示。FAISS:Facebook 开源的向量相似度检索库,此处作为向量存储后端。fetch_k:指定 MMR 从向量库中初筛的候选数量。适当增大fetch_k可以给 MMR 提供更大的选择空间,但也会增加计算开销。MaxMarginalRelevanceExampleSelector.from_examples:类方法,接收示例列表、嵌入模型、向量库类和检索参数,返回配置好的 MMR 选择器实例。
适用场景与选型建议
- 优先选用余弦相似度选择器的情况:示例池规模较小,且每条示例都具有不可替代的独特信息;任务对多样性的要求不高,最相关的一两条示例即可满足需求。
- 推荐使用 MMR 选择器的情况:示例池中包含大量语义重复或中英对照的“冗余”样本;希望用较少的 K 值覆盖更多的语义方向,提高提示的泛化能力。
- 参数调优建议:
fetch_k通常设置为k的 2~3 倍,以平衡多样性与计算效率。若示例池高度同质化,可适当增大fetch_k并调高 λ 值(默认 0.5),以加强多样性惩罚。
API 速览
MaxMarginalRelevanceExampleSelector
所属库:langchain_core.example_selectors
类方法:from_examples
方法签名:
from_examples(
examples: List[dict],
embeddings: Embeddings,
vectorstore_cls: Type[VectorStore],
k: int,
fetch_k: int,
**kwargs
) -> MaxMarginalRelevanceExampleSelector
参数说明:
examples:示例列表,每个元素为包含输入输出字段的字典。embeddings:嵌入模型实例,用于将文本转换为向量。vectorstore_cls:向量库类,需实现from_texts和similarity_search方法。k:最终返回的示例数量。fetch_k:从向量库中初筛的候选数量。
返回值:配置完成的 MaxMarginalRelevanceExampleSelector 实例。
Demo 示例
基于上述核心代码,可构建一个完整的 HTML 界面来演示 MMR 选择器与余弦相似度选择器的效果差异。以下为简化版 Flask 后端示例:
from flask import Flask, request, jsonify
from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector, SemanticSimilarityExampleSelector
from langchain_community.embeddings.fake import FakeEmbeddings
from langchain_community.vectorstores import FAISS
app = Flask(__name__)
examples = [
{"input": "happy", "output": "sad"},
{"input": "高兴", "output": "悲伤"},
{"input": "sunny", "output": "gloomy"},
{"input": "晴朗", "output": "阴沉"},
{"input": "tall", "output": "short"},
{"input": "高", "output": "矮"},
]
embedding_model = FakeEmbeddings(size=128)
@app.route("/select", methods=["POST"])
def select_examples():
data = request.json
query = data.get("query", "")
selector_type = data.get("selector_type", "mmr")
if selector_type == "mmr":
selector = MaxMarginalRelevanceExampleSelector.from_examples(
examples=examples,
embeddings=embedding_model,
vectorstore_cls=FAISS,
k=2,
fetch_k=5
)
else:
selector = SemanticSimilarityExampleSelector.from_examples(
examples=examples,
embeddings=embedding_model,
vectorstore_cls=FAISS,
k=2
)
selected = selector.select_examples({"input": query})
return jsonify(selected)
if __name__ == "__main__":
app.run(debug=True)
运行说明:保存为 app.py,执行 python app.py 启动服务。发送 POST 请求至 /select,携带 JSON 参数 {"query": "难过", "selector_type": "mmr"} 即可获取选择结果。
技术点总结:
- MMR 与余弦相似度选择器的对比实现。
- FAISS 向量库的本地化部署与使用。
- 基于 Flask 的轻量级 API 封装。
参考文档
官方文档:
参考链接:
总结
MMR 示例选择器是余弦相似度选择器的有力补充,它通过引入多样性惩罚机制,有效避免了示例同质化问题。
在示例池庞大且存在大量相似样本的情况下,MMR 能够以更少的示例数量提供更全面的参考信息,从而进一步提升大模型 Few-Shot 学习的效率与效果。
342



被折叠的 条评论
为什么被折叠?



