内容纲要

  • 回顾余弦相似度选择器的优势与局限
  • 最大边际相关性(MMR)算法
    • 目标:在相关性与多样性之间取得平衡
    • 核心机制:惩罚与已选示例过于相似的样本
  • LangChain 中的 MMR 示例选择器
    • MaxMarginalRelevanceExampleSelector
    • 与余弦相似度选择器的对比
  • 完整可运行代码:使用 FAISS 向量库与 FakeEmbeddings 模拟嵌入
  • 适用场景与选型建议

引言

在上一篇文章中,我们介绍了基于余弦相似度的 SemanticSimilarityExampleSelector,它能够从示例池中精准地找出与输入语义最相似的 Top-K 个示例。然而,当示例池中存在大量高度相似的样本时(比如几乎相同的双语版本),余弦相似度选择器往往会返回多个“同质化”的示例,这些示例虽然都与输入相关,但彼此之间却没有提供额外的多样性信息。

为了解决这个问题,LangChain 提供了基于最大边际相关性(Maximal Marginal Relevance,简称 MMR)的示例选择器。MMR 在保证示例与输入相关的同时,刻意避免选出过于雷同的样本,从而让 Few Shot 提示中的示例更具代表性,覆盖更多视角。

MMR 算法原理

MMR 最初应用于信息检索和文本摘要领域,其核心思想是:在每一步选择新的结果时,既考虑该结果与查询的相关性,又考虑其与已选择结果的差异性。在示例选择场景中,MMR 会先找到与输入最相似(余弦相似度最大)的示例,然后在对后续示例进行评分时,对那些与已选示例相似度过高的样本施加“惩罚”,使其得分降低。

这样,最终选出的 Top-K 个示例既能保持与任务的高度相关,又能尽量分散在语义空间的不同方向上,从而向模型提供更丰富的参考信息。

MMR 与余弦相似度选择器的对比

下表直观展示了两种选择器在相同输入下的行为差异(以文中“难过”为例,示例池包含中英文情绪词、天气词以及体型词):

选择器类型 输入 K 值 返回示例 特点
余弦相似度 难过 2 高兴/悲伤, happy/sad 两个示例高度同质(中英对照),仅体现情绪维度
MMR 难过 2 高兴/悲伤, tall/shortbig/small 第一个示例最相关,第二个示例来自不同语义方向,增加多样性

可见,MMR 避免了“把鸡蛋放在一个篮子里”的问题,尤其适用于示例池规模较大且存在多条近似示例的场景。

完整可运行代码

以下代码使用 FAISS 向量库和 FakeEmbeddings 模拟嵌入过程,演示 MaxMarginalRelevanceExampleSelector 的用法。无需任何外部 API Key 即可运行。

安装依赖:

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/shortbig/small 等与情绪无关但能提供其他维度信息的条目,从而实现了多样化的 Few Shot 示例组合。

适用场景与选型建议

  • 优先选用余弦相似度选择器的情况:示例池规模较小,且每条示例都具有不可替代的独特信息;任务对多样性的要求不高,最相关的一两条示例即可满足需求。
  • 推荐使用 MMR 选择器的情况:示例池中包含大量语义重复或中英对照的“冗余”样本;希望用较少的 K 覆盖更多的语义方向,提高提示的泛化能力。
  • 参数调优fetch_k 参数决定了从向量库中初筛出多少个候选,然后再执行 MMR 算法从中选出 k 个。适当增大 fetch_k 可以给 MMR 提供更大的选择空间,但也会增加计算开销。

总结

MMR 示例选择器是余弦相似度选择器的有力补充,它通过引入多样性惩罚机制,有效避免了示例同质化问题。

在示例池庞大且存在大量相似样本的情况下,MMR 能够以更少的示例数量提供更全面的参考信息,从而进一步提升大模型 Few Shot 学习的效率与效果。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐