AI Agent白手起家31: 根据语义相似度动态选择 Few Shot 示例

纲要

  • 动态示例选择进阶:从长度到语义
  • 核心概念
    • SemanticSimilarityExampleSelector:基于语义相似度从示例池中选择与输入最相关的示例
    • 向量嵌入(Embedding)与向量数据库(如 Chroma
    • 余弦相似度:衡量向量空间距离的常用算法
  • 关键流程:准备示例 → 定义嵌入模型和向量数据库 → 创建选择器 → 组合 Few Shot 提示词模板 → 调用 LLM
  • 涉及组件:langchain_core.example_selectorslangchain_community.embeddingslangchain_community.vectorstores
  • 代码演示:完整可运行的 Python 脚本,使用 FakeEmbeddings 模拟嵌入过程,无需外部 API Key

引言

在上一篇文章中,我们介绍了根据长度动态截取示例的 LengthBasedExampleSelector,它虽然能够控制上下文窗口的大小,但选择逻辑过于机械:只是从列表头部开始依次添加示例,完全不考虑示例与当前输入的相关性。如果示例池里混杂了中文和英文、天气和情绪等多种场景,长度选择器很可能给出与当前任务毫不相干的例子。

LangChain 提供了另一种更智能的选择器------SemanticSimilarityExampleSelector,它利用文本嵌入技术,将输入和示例都映射到向量空间,然后通过计算余弦相似度,从示例池中选出语义最接近的 Top-K 个示例。这种方式可以轻松实现跨语言、跨领域的精准匹配,让 Few Shot 提示真正"看懂"输入的内容。

工作原理

其本质是检索增强生成(RAG)在提示词构建阶段的应用,整体流程如下:
#mermaid-svg-TCsjSKKM1Ak4xioH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TCsjSKKM1Ak4xioH .error-icon{fill:#552222;}#mermaid-svg-TCsjSKKM1Ak4xioH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TCsjSKKM1Ak4xioH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TCsjSKKM1Ak4xioH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TCsjSKKM1Ak4xioH .marker.cross{stroke:#333333;}#mermaid-svg-TCsjSKKM1Ak4xioH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TCsjSKKM1Ak4xioH p{margin:0;}#mermaid-svg-TCsjSKKM1Ak4xioH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster-label text{fill:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster-label span{color:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster-label span p{background-color:transparent;}#mermaid-svg-TCsjSKKM1Ak4xioH .label text,#mermaid-svg-TCsjSKKM1Ak4xioH span{fill:#333;color:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH .node rect,#mermaid-svg-TCsjSKKM1Ak4xioH .node circle,#mermaid-svg-TCsjSKKM1Ak4xioH .node ellipse,#mermaid-svg-TCsjSKKM1Ak4xioH .node polygon,#mermaid-svg-TCsjSKKM1Ak4xioH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TCsjSKKM1Ak4xioH .rough-node .label text,#mermaid-svg-TCsjSKKM1Ak4xioH .node .label text,#mermaid-svg-TCsjSKKM1Ak4xioH .image-shape .label,#mermaid-svg-TCsjSKKM1Ak4xioH .icon-shape .label{text-anchor:middle;}#mermaid-svg-TCsjSKKM1Ak4xioH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TCsjSKKM1Ak4xioH .rough-node .label,#mermaid-svg-TCsjSKKM1Ak4xioH .node .label,#mermaid-svg-TCsjSKKM1Ak4xioH .image-shape .label,#mermaid-svg-TCsjSKKM1Ak4xioH .icon-shape .label{text-align:center;}#mermaid-svg-TCsjSKKM1Ak4xioH .node.clickable{cursor:pointer;}#mermaid-svg-TCsjSKKM1Ak4xioH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TCsjSKKM1Ak4xioH .arrowheadPath{fill:#333333;}#mermaid-svg-TCsjSKKM1Ak4xioH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TCsjSKKM1Ak4xioH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TCsjSKKM1Ak4xioH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TCsjSKKM1Ak4xioH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TCsjSKKM1Ak4xioH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TCsjSKKM1Ak4xioH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster text{fill:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH .cluster span{color:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TCsjSKKM1Ak4xioH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TCsjSKKM1Ak4xioH rect.text{fill:none;stroke-width:0;}#mermaid-svg-TCsjSKKM1Ak4xioH .icon-shape,#mermaid-svg-TCsjSKKM1Ak4xioH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TCsjSKKM1Ak4xioH .icon-shape p,#mermaid-svg-TCsjSKKM1Ak4xioH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TCsjSKKM1Ak4xioH .icon-shape .label rect,#mermaid-svg-TCsjSKKM1Ak4xioH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TCsjSKKM1Ak4xioH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TCsjSKKM1Ak4xioH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TCsjSKKM1Ak4xioH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 示例池
向量化并存入Chroma
用户输入
向量化
在Chroma中做相似度搜索
返回Top-K最相似示例
组合进Few Shot提示词模板

  • 向量化:使用嵌入模型(Embedding Model)将文本转换为高维向量。
  • 存储:将示例向量存入向量数据库(本文使用轻量级的 Chroma)。
  • 查询:将用户输入也向量化,通过余弦相似度计算与各示例向量的距离,返回距离最近(即语义最相似)的 K 个示例。

完整可运行代码

为了让你无需任何外部 API Key 即可运行,本示例使用 FakeEmbeddings 模拟向量嵌入。实际项目中只需替换为真实的嵌入模型(如 OpenAI 或 HuggingFace 模型),代码结构完全一致。

首先安装依赖:

bash 复制代码
pip install langchain langchain-core langchain-community chromadb

核心代码:

python 复制代码
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_community.embeddings.fake import FakeEmbeddings
from langchain_community.vectorstores import Chroma

# 1. 准备示例池(反义词任务)
examples = [
    {"input": "happy", "output": "sad"},
    {"input": "高兴", "output": "悲伤"},
    {"input": "sunny", "output": "gloomy"},
    {"input": "晴朗", "output": "阴沉"},
    {"input": "big", "output": "small"},
]

# 2. 定义示例格式化模板
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="原词: {input}\n反义词: {output}"
)

# 3. 创建语义相似度示例选择器
#    使用 FakeEmbeddings 模拟嵌入,size 参数指定向量维度
embedding_model = FakeEmbeddings(size=128)

example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples=examples,
    embeddings=embedding_model,
    vectorstore_cls=Chroma,      # 使用 Chroma 作为向量数据库
    k=1,                         # 每次选择最相似的 1 个示例
)

# 4. 构建动态 Few Shot 提示词模板
dynamic_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="给出每个输入词的反义词:",
    suffix="原词: {input}\n反义词:",
    input_variables=["input"],
)

# 5. 测试:输入英文情绪词,期望选中情绪相关示例
print("=== 输入: worried ===")
print(dynamic_prompt.format(input="worried"))
print()

# 6. 测试:输入中文天气词,期望选中天气相关示例
print("=== 输入: 晴朗 ===")
print(dynamic_prompt.format(input="晴朗"))

运行后可以看到,worried 会匹配到情绪相关的示例(如 happy/sad),晴朗 则匹配到天气相关的示例(如 sunny/gloomy晴朗/阴沉)。注意 FakeEmbeddings 使用随机向量,因此结果可能略有随机性;若换成真实嵌入模型,匹配会非常精准。

与长度选择器的对比

特性 长度选择器 (LengthBasedExampleSelector) 语义选择器 (SemanticSimilarityExampleSelector)
选择依据 示例字符数 + 顺序 输入与示例的语义相似度
能否跨语言 不支持 支持(嵌入模型通常跨语言)
计算开销 极低 较高(需向量化和相似度搜索)
适用场景 示例少且顺序重要 示例多、任务多变、要求高相关性

使用建议

  • 嵌入模型选型 :对中文任务推荐使用 text-embedding-ada-002(OpenAI)或开源的 BAAI/bge-large-zh,它们对中英文混合场景支持良好。
  • Top-K 设置k 值一般设为 1~3,过多示例可能引入噪声。可根据实际效果调整。
  • 向量数据库:Chroma 适合原型开发和小规模数据;生产环境可考虑 FAISS、Pinecone、Milvus 等。
  • 示例池维护:定期更新示例池并重新生成向量,以保持与最新任务的语义一致性。

总结

SemanticSimilarityExampleSelector 将检索增强生成(RAG)的向量检索思路应用于提示词工程,让 Few Shot 示例的选择从"机械截断"进化为"智能检索"。

它充分利用了嵌入模型捕捉语义的能力,无论输入是中文还是英文,都能从庞大的示例池中精准捞出最有参考价值的样例,大幅提升 Few Shot 的命中率和回答质量。

相关推荐
ting94520003 小时前
Humalike X Hermes 深度技术剖析:单指令注入群聊社交智能的底层架构、算法与跨 IM 平台实现
人工智能·算法·架构
吴声子夜歌3 小时前
Java面试——算法
java·算法·面试
涤生大数据3 小时前
一次“没有运行日志”的DolphinScheduler任务失败排查
大数据·数据库·人工智能·状态模式
东风破_3 小时前
Vibe Coding 上头之后,我开始用 SDD 给 AI 编程加一张“施工图”
人工智能·程序员
h_a_o777oah4 小时前
【图论】Tarjan 缩点:解决有向图中环的问题
c++·算法·图论·acm·强连通分量·缩点·tarjan
Tisfy4 小时前
LeetCode 1386.安排电影院座位:哈希表+位运算
算法·leetcode·散列表·题解·哈希表
weixin_403810134 小时前
AI智能体写安卓自动化脚本教程:Cursor/Trae+CLI 实战,自然语言生成代码
android·人工智能·自动化·跨境电商·安卓自动化脚本·多账户运营
深圳雨林凯AI4 小时前
雨林凯AI四方连图介质适配原理:像素密度、纱线纹理与颜色管理怎么协调
人工智能
Nil2085 小时前
leetcode 199二叉树的右视图
算法·leetcode·深度优先
ZGIAI5 小时前
ZGI 混合检索:汇集候选并统一重排
人工智能·架构