欢迎光临
我们一直在努力

【LangChain】示例选择器(Example Selectors)实战指南

在这里插入图片描述

🔥草莓熊Lotso:个人主页

❄️个人专栏: 《C++知识分享》 《Linux 入门到实践:零基础也能懂》

✨生活是默默的坚持,毅力是永久的享受!


🎬 博主简介:

在这里插入图片描述


文章目录

  • 前言
  • 一. 什么是示例选择器?
  • 二. 四大核心示例选择器原理解析
    • 2.1 按长度选择(LengthBasedExampleSelector)
    • 2.2 按语义相似性选择(SemanticSimilarityExampleSelector)
    • 2.3 按最大边际相关性选择(MaxMarginalRelevanceExampleSelector)
    • 2.4 按 Ngram 重叠选择(NGramOverlapExampleSelector)
  • 三. 实战落地:从零实现四大示例选择器
    • 3.1 环境准备
    • 3.2 按长度选择示例实战
    • 3.3 按语义相似性选择示例实战
    • 3.4 按最大边际相关性选择示例实战
    • 3.5 按 Ngram 重叠选择示例实战
  • 四. 核心考点与选型指南
    • 4.1 四大选择器对比表
    • 4.2 选型建议

前言

少样本提示(Few-shot Prompting)是提升大语言模型性能最有效的手段之一。通过给模型提供几个 “输入 – 输出” 示例,我们可以清晰地告诉模型应该做什么、怎么做、以什么格式输出,从而大幅减少模型 “胡说八道” 的概率,获得更稳定、更符合预期的结果。然而,当我们的示例库越来越大时,一个棘手的问题出现了:如果把所有示例都塞进提示词,会迅速耗尽模型的上下文窗口,导致 API 调用失败,过多的冗余示例会增加 token 成本,还可能混淆模型,反而降低输出质量,不同的查询需要不同的示例,一刀切的示例选择方式效率极低。这正是示例选择器(Example Selectors) 要解决的问题。它能根据给定的输入,从大量示例集中动态、智能地选择最相关的示例子集,在保证提示效果的同时,严格控制上下文长度和调用成本。本文将系统讲解 LangChain 中四大核心示例选择器的原理、适用场景,并提供完整的实战代码和源码解读。


一. 什么是示例选择器?

示例选择器是 LangChain 中专门用于优化少样本提示的核心组件。它的工作流程非常清晰:

  • 接收用户的查询输入
  • 根据预设的策略,从预定义的示例集中筛选出最相关的 N 个示例
  • 将筛选后的示例格式化为模型可理解的消息格式
  • 与用户查询一起构建最终的提示词
  • 它为我们带来了四个核心价值:

    • 控制上下文长度:避免因示例过多导致的上下文窗口溢出
    • 提升提示质量:只保留与查询最相关的示例,减少冗余信息干扰
    • 降低 API 成本:更少的 token 意味着更低的调用费用
    • 提高响应准确性:精准的示例能更好地引导模型输出正确结果

    在这里插入图片描述


    二. 四大核心示例选择器原理解析

    LangChain 内置了四种常用的示例选择器,分别适用于不同的业务场景。下面我们逐一拆解它们的核心原理和适用边界。

    2.1 按长度选择(LengthBasedExampleSelector)

    核心原理:根据用户输入文本的长度动态调整示例数量。输入越短,选择的示例越多;输入越长,选择的示例越少。

    设计逻辑:当用户输入本身已经很长时,留给示例的 token 空间就很小了,此时应该减少示例数量以避免上下文溢出;反之,短输入可以搭配更多示例来提升效果。

    适用场景:对上下文长度有严格限制、token 成本敏感的简单任务。

    核心参数:

    • max_length:提示词的最大长度(默认按单词数统计)
    • get_text_length:自定义文本长度计算函数

    在这里插入图片描述

    2.2 按语义相似性选择(SemanticSimilarityExampleSelector)

    核心原理:将所有示例和用户查询都通过嵌入模型转换为高维向量,然后计算查询向量与所有示例向量之间的余弦相似度,选择相似度最高的 k 个示例。

    关键依赖:

    • 嵌入模型(Embeddings):将文本转换为语义向量
    • 向量数据库(VectorStore):高效存储和检索向量

    适用场景:大多数少样本提示任务,尤其是需要语义理解而非简单关键词匹配的场景。

    核心参数:

    • k:最终返回的示例数量
    • embeddings:嵌入模型实例
    • vectorstore_cls:向量数据库类

    在这里插入图片描述

    2.3 按最大边际相关性选择(MaxMarginalRelevanceExampleSelector)

    解决的问题:纯语义相似性选择有一个致命缺陷 —— 返回的结果往往高度同质化,信息冗余严重。例如,查询 “苹果的价格” 时,可能返回的都是关于红富士苹果价格的示例,而缺少其他品种的信息。

    核心原理:MMR(Maximum Marginal Relevance)算法是一种重新排序技术,它在选择示例时同时兼顾相关性和多样性:

  • 首先从向量库中获取fetch_k个最相似的示例(广撒网)
  • 然后从这fetch_k个示例中,迭代选出既与查询相关、又与已选示例差异最大的k个示例
  • 适用场景:RAG(检索增强生成)、推荐系统、文档摘要等需要结果多样性的场景。

    核心参数:

    • k:最终返回的示例数量
    • fetch_k:初步筛选的候选示例数量(通常fetch_k > k)
    • lambda_mult:控制相关性和多样性的权重(0~1,默认 0.5,值越大越偏向相关性)

    在这里插入图片描述 在这里插入图片描述

    2.4 按 Ngram 重叠选择(NGramOverlapExampleSelector)

    核心原理:计算用户查询和每个示例之间的ngram 重叠度(连续 n 个词的匹配数量),然后按重叠度从高到低排序示例。

    特点:

    • 基于表面形式匹配,不理解语义
    • 速度极快,无需嵌入模型和向量数据库
    • 对同义词、一词多义等情况处理能力差

    适用场景:关键词匹配、代码搜索、精确查询等不需要深度语义理解的场景。

    核心参数:

    • threshold:重叠度阈值,控制是否排除示例
      • -1.0:按重叠度排序,不排除任何示例
      • 0.0:排除与查询没有任何 ngram 重叠的示例
      • >1.0:排除所有示例
    • n:ngram 的长度(默认 2)

    在这里插入图片描述 在这里插入图片描述


    三. 实战落地:从零实现四大示例选择器

    3.1 环境准备

    首先安装所需的依赖包:

    pip install langchain langchain-openai langchain-chroma nltk langchain-community python-dotenv

    然后配置 OpenAI API Key(推荐使用.env文件管理):

    from dotenv import load_dotenv
    load_dotenv() # 加载.env文件中的环境变量

    3.2 按长度选择示例实战

    我们以 “反义词生成” 任务为例,演示 LengthBasedExampleSelector 的使用:

    from langchain_core.example_selectors import LengthBasedExampleSelector
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

    # 1. 定义反义词示例集
    examples = [
    {"input": "happy", "output": "sad"},
    {"input": "tall", "output": "short"},
    {"input": "energetic", "output": "lethargic"},
    {"input": "sunny", "output": "gloomy"},
    {"input": "windy", "output": "calm"},
    ]

    # 2. 定义单个示例的格式化模板
    example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="Input: {input}\\nOutput: {output}",
    )

    # 3. 初始化长度示例选择器
    example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=25, # 提示词的最大长度(单词数)
    )

    # 4. 构建动态少样本提示模板
    dynamic_prompt = FewShotPromptTemplate(
    example_selector=example_selector, # 使用选择器而非固定examples
    example_prompt=example_prompt,
    prefix="给出每个输入的反义词",
    suffix="Input: {adjective}\\nOutput:",
    input_variables=["adjective"],
    )

    # 测试1:短输入
    print("=== 短输入测试 ===")
    print(dynamic_prompt.invoke({"adjective": "big"}).to_string())

    # 测试2:长输入
    print("\\n=== 长输入测试 ===")
    long_input = "非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常 非常大"
    print(dynamic_prompt.invoke({"adjective": long_input}).to_string())

    源码解读:

    • max_length=25表示整个提示词(前缀 + 所有示例 + 后缀)的单词数不能超过 25
    • 默认的长度计算函数是按空格和换行符分割文本,统计单词数量
    • 当输入过长时,选择器会自动从后往前截断示例,直到满足长度限制

    在这里插入图片描述

    3.3 按语义相似性选择示例实战

    from langchain_chroma import Chroma
    from langchain_core.example_selectors import SemanticSimilarityExampleSelector
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
    from langchain_openai import OpenAIEmbeddings

    # 1. 复用之前的反义词示例集
    examples = [
    {"input": "happy", "output": "sad"},
    {"input": "tall", "output": "short"},
    {"input": "energetic", "output": "lethargic"},
    {"input": "sunny", "output": "gloomy"},
    {"input": "windy", "output": "calm"},
    ]

    example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="Input: {input}\\nOutput: {output}",
    )

    # 2. 初始化语义相似示例选择器
    example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples=examples,
    embeddings=OpenAIEmbeddings(model="text-embedding-3-small"), # 嵌入模型
    vectorstore_cls=Chroma, # 使用Chroma内存向量数据库
    k=1, # 只返回最相似的1个示例
    )

    # 3. 构建少样本提示模板
    similar_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="给出每个输入的反义词",
    suffix="Input: {adjective}\\nOutput:",
    input_variables=["adjective"],
    )

    # 测试:查询"worried"(担心的)
    print("=== 语义相似性测试 ===")
    print(similar_prompt.invoke({"adjective": "worried"}).to_string())

    源码解读:

    • from_examples方法会自动将所有示例转换为向量,并存储在 Chroma 向量数据库中
    • 当调用invoke时,选择器会先将查询转换为向量,然后在向量库中搜索最相似的 k 个示例
    • 输出结果会显示最相似的示例是 “happy → sad”,因为它们都表示情绪状态,语义最接近

    在这里插入图片描述 在这里插入图片描述

    3.4 按最大边际相关性选择示例实战

    from langchain_chroma import Chroma
    from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
    from langchain_openai import OpenAIEmbeddings

    examples = [
    {"input": "happy", "output": "sad"},
    {"input": "joyful", "output": "miserable"},
    {"input": "tall", "output": "short"},
    {"input": "energetic", "output": "lethargic"},
    {"input": "sunny", "output": "gloomy"},
    ]

    example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="Input: {input}\\nOutput: {output}",
    )

    # 初始化MMR示例选择器
    example_selector = MaxMarginalRelevanceExampleSelector.from_examples(
    examples=examples,
    embeddings=OpenAIEmbeddings(model="text-embedding-3-small"),
    vectorstore_cls=Chroma,
    k=2, # 最终返回2个示例
    fetch_k=4, # 先获取4个最相似的候选
    )

    mmr_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="给出每个输入的反义词",
    suffix="Input: {adjective}\\nOutput:",
    input_variables=["adjective"],
    )

    # 测试:查询"cheerful"(快乐的)
    print("=== MMR测试 ===")
    print(mmr_prompt.invoke({"adjective": "cheerful"}).to_string())

    源码解读:

    • fetch_k=4表示先从向量库中获取 4 个最相似的示例
    • 然后 MMR 算法会从这 4 个示例中选出 2 个既相关又多样的示例
    • 输出结果会包含 “happy → sad” 和 “joyful → miserable” 吗?不,MMR 会避免选择过于相似的示例,可能会返回 “happy → sad” 和 “energetic → lethargic”,这样既相关又有多样性

    在这里插入图片描述

    3.5 按 Ngram 重叠选择示例实战

    from langchain_community.example_selectors import NGramOverlapExampleSelector
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

    # 1. 定义翻译示例集
    examples = [
    {"input": "See Spot run.", "output": "看见Spot跑。"},
    {"input": "My dog barks.", "output": "我的狗叫。"},
    {"input": "Spot can run.", "output": "Spot可以跑。"},
    ]

    example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="Input: {input}\\nOutput: {output}",
    )

    # 2. 初始化NGram示例选择器(threshold=-1,不排除任何示例)
    example_selector = NGramOverlapExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    threshold=1.0,
    )

    # 3. 构建少样本提示模板
    dynamic_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="给出每个输入的中文翻译",
    suffix="Input: {sentence}\\nOutput:",
    input_variables=["sentence"],
    )

    # 测试:查询"Spot can run fast."
    print("=== NGram重叠测试(threshold=-1) ===")
    print(dynamic_prompt.invoke({"sentence": "Spot can run fast."}).to_string())

    # 测试:threshold=0.0,排除无重叠的示例
    example_selector.threshold = 0.0
    print("\\n=== NGram重叠测试(threshold=0) ===")
    print(dynamic_prompt.invoke({"sentence": "Spot can run fast."}).to_string())

    源码解读:

    • 对于查询 “Spot can run fast.”,与示例 “Spot can run.” 的 2gram 重叠度最高(“Spot can” 和 “can run”)
    • 当threshold=0.0时,与查询没有任何 ngram 重叠的示例会被排除
    • 输出结果会按重叠度从高到低排序示例

    在这里插入图片描述

    在这里插入图片描述


    四. 核心考点与选型指南

    4.1 四大选择器对比表

    选择器类型核心原理依赖优点缺点适用场景
    Length 输入文本长度 简单快速,无额外成本 不考虑语义,效果一般 严格控制 token,简单任务
    Similarity 余弦相似度 嵌入模型 + 向量库 语义匹配,效果好 结果同质化,有嵌入成本 大多数少样本任务
    MMR 相关性 + 多样性 嵌入模型 + 向量库 兼顾相关和多样,减少冗余 计算稍复杂 RAG、推荐系统、文档摘要
    NGram 连续词重叠 nltk 速度极快,无嵌入成本 表面匹配,不理解语义 关键词匹配、代码搜索

    4.2 选型建议

  • 优先选择 SemanticSimilarity:对于大多数需要语义理解的少样本任务,它的效果最好
  • 需要多样性选 MMR:在 RAG、推荐等场景中,MMR 能有效避免结果同质化,提升答案的全面性
  • 成本敏感选 Length/NGram:如果对 token 成本和响应速度要求极高,且任务不需要深度语义理解,可以选择这两种
  • 精确匹配选 NGram:对于代码搜索、关键词查询等场景,NGram 的表面匹配效果反而更好

  • 🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点:
    👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长
    ❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量
    ⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用
    💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑
    🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解
    技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标!

    结语:示例选择器是 LangChain 中优化少样本提示的关键组件,它解决了 “示例太多上下文溢出、示例太少效果不好” 的核心矛盾。在实际开发中,建议先从 SemanticSimilarity 开始尝试,然后根据业务需求逐步优化。如果发现返回的示例过于同质化,可以切换到 MMR;如果对成本和速度有严格要求,可以考虑 Length 或 NGram。未来,随着大模型上下文窗口的不断扩大,示例选择器的作用不会减弱,反而会更加重要。它将在复杂 Agent、多轮对话、长上下文 RAG 等场景中发挥越来越关键的作用,帮助我们构建更高效、更智能的 AI 应用。

    ✨把这些内容吃透超牛的!放松下吧✨

    ʕ˘ᴥ˘ʔ

    づきらど

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » 【LangChain】示例选择器(Example Selectors)实战指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址