LlamaIndex 系列【21】语义检索(Semantic Search)

文章目录

  • [1. 关键词检索和语义检索](#1. 关键词检索和语义检索)
    • [1.1 关键词检索](#1.1 关键词检索)
    • [1.2 语义检索](#1.2 语义检索)
  • [2. 标准工作链路](#2. 标准工作链路)
  • [3. 核心原理](#3. 核心原理)
    • [3.1 Embedding 向量](#3.1 Embedding 向量)
    • [3.2 向量相似度](#3.2 向量相似度)
      • [3.2.1 欧氏距离](#3.2.1 欧氏距离)
      • [3.2.2 原始点积](#3.2.2 原始点积)
      • [3.2.3 余弦相似度](#3.2.3 余弦相似度)
  • [4. 向量索引检索器 API](#4. 向量索引检索器 API)
    • [4.1 VectorIndexAutoRetriever (向量存储自动检索器)](#4.1 VectorIndexAutoRetriever (向量存储自动检索器))
    • [4.2 VectorIndexRetriever(向量索引标准检索器)](#4.2 VectorIndexRetriever(向量索引标准检索器))
  • [5. 案例案例](#5. 案例案例)
    • [5.1 构建向量索引](#5.1 构建向量索引)
    • [5.2 构建向量检索器](#5.2 构建向量检索器)
      • [5.2.1 方式一:快捷方法 as_retriever()](#5.2.1 方式一:快捷方法 as_retriever())
      • [5.2.2 方式二:显式实例化 VectorIndexRetriever](#5.2.2 方式二:显式实例化 VectorIndexRetriever)
      • [5.2.3 方式三:智能自动检索器 VectorIndexAutoRetriever](#5.2.3 方式三:智能自动检索器 VectorIndexAutoRetriever)
    • [5.3 执行检索](#5.3 执行检索)

1. 关键词检索和语义检索

1.1 关键词检索

BM25TF‑IDF 都属于关键词检索(词法检索),只做字面词汇匹配:

  1. 识别不了同义词开心愉悦 语义完全相同,但关键词检索会判定二者不匹配;
  2. 无法处理一词多义:同一个词语放在不同句子里意思不一样,词法检索只会单纯判定词汇命中;
  3. 用户换一套话术提问,就找不到对应的文档

关键词检索只在乎单词是否出现过 ,并不读懂文字背后真正的语义。想要解决这个短板,就要依靠语义检索


1.2 语义检索

语义检索,是不局限于文字表面的词汇匹配 ,去理解用户查询和文档内在含义、意图,基于语义相似度完成内容召回的检索方式。

核心实现原理

  1. 通过 Embedding 嵌入模型,将问句、文档转换成高维稠密向量;
  2. 在向量空间中,语义相近的文本对应的向量距离更近;
  3. 使用余弦相似度等方式计算向量相似度,筛选并排序最相似的文档作为检索结果。

语义检索不再依赖字面关键词比对:即便查询和文档用词完全不一样,只要含义相近,就可以成功匹配,捕捉关键词检索识别不到的细微语义差别。

关键词检索与语义检索都会把文本转为向量,再计算相似度打分,差异只在于向量怎么生成

  • 关键词检索TF‑IDF / BM25):通过统计词频构造稀疏向量
  • 语义检索Embedding):使用预训练嵌入模型生成稠密向量

2. 标准工作链路

工作链路说明

  1. 文本输入 :准备知识库原始文档 Documents,接收用户查询语句 Prompt
  2. 向量化处理 :将文档与用户提问送入同一个 Embedding Model(嵌入模型),把自然语言转换为计算机可运算的高维向量;
  3. 映射至向量空间 :全部向量落在同一多维向量空间内,语义相近的文本,向量空间距离更近
  4. 相似度排序召回 :计算查询向量和文档向量的距离,按照相似度从高到低排序,返回距离最近的 Top‑K 相关文档,完成语义检索。

核心逻辑:不再匹配字面词汇,依靠向量空间距离判断文本语义相似度。

3. 核心原理

3.1 Embedding 向量

嵌入模型可以将任意粒度的文本(词语、句子、段落、长文档)映射为高维空间中的坐标点,通过一组数值组成的向量承载文本的语义信息。

  1. 向量空间核心规则:语义含义越相近的两段文本,在向量空间中的空间距离越近;文本语义差异越大,向量之间的距离也就越远。
  2. 向量维度说明 :二维、三维坐标仅用于可视化展示。实际工程落地中,向量维度通常在 100 ~ 1000维以上;更高的维度可以捕捉更细粒度的语义差别,提升区分效果。
  3. 多粒度编码能力:嵌入模型支持对不同长度的文本生成独立向量,无论是单个词汇、短句段落,还是完整长文档,都可以得到唯一对应的语义向量。

示例:

  • 句子 1他在课堂上轻声说话
  • 句子 2上课时他压低声音低语

两句话用词并不完全相同,但表达的含义高度一致,二者生成的向量在空间中距离很近;而和语义无关的文本,向量距离会显著拉大。


3.2 向量相似度

在通过嵌入模型得到查询向量和文档向量之后,我们需要一种量化规则,用来判断两段文本语义的相近程度。

三种向量相似度衡量方式:

度量指标 取值范围 向量同向 向量垂直 向量反向 核心关注点 适用场景
欧氏距离 [ 0 , + ∞ ) [0,+\infty) [0,+∞) 距离很小 中等距离 距离很大 空间绝对直线距离 低维向量场景,文本检索极少使用
原始点积 ( − ∞ , + ∞ ) (-\infty,+\infty) (−∞,+∞) 正数 0 0 0 负数 方向 + 向量长度共同打分 向量模长携带业务权重的特殊场景
余弦相似度 − 1 , 1 -1,1 −1,1 1 1 1 0 0 0 − 1 -1 −1 仅关注向量方向,忽略模长 通用语义检索、RAG知识库问答

3.2.1 欧氏距离

欧氏距离计算两个向量在高维空间中的直线几何距离

  • 取值范围: [ 0 , + ∞ ) [0,+\infty) [0,+∞)
  • 判定规则:数值越小,向量在空间上越靠近,语义相似度越高;数值越大,语义差异越大。
  • 特点:关注向量完整的空间坐标差异,同时兼顾方向与模长。
  • 局限:高维场景下距离区分效果变差,RAG 语义检索中并不常用

欧氏距离,就是高维空间中两个向量点之间的直线长度,用来衡量两点在空间里相隔多远。

公式( n 维向量):

d ( a , b ) = ∑ i = 1 n ( a i − b i ) 2 d(a,b)=\sqrt{\sum_{i=1}^n(a_i-b_i)^2} d(a,b)=i=1∑n(ai−bi)2

  1. 把两个向量每一维坐标依次相减、平方后全部累加,最后开平方根,得到直线距离。
  2. 取值范围: [ 0 , + ∞ ) \boldsymbol{[0,+\infty)} [0,+∞)
    • d = 0 d=0 d=0:两个点完全重合,向量一模一样
    • 数值越小 → 空间位置越近 → 语义相似度越高
    • 数值越大 → 空间位置越远 → 语义差异越大

直观理解(二维平面),平面上 3 个点 A 、 B 、 C A、B、C A、B、C:

  • A A A 和 B B B 靠得很近,欧氏距离短,语义相似
  • A A A 和 C C C 相隔很远,欧氏距离长,语义差别大

3.2.2 原始点积

原始点积 将两个向量对应维度的值逐一相乘后累加求和,最终计算分值同时受向量方向向量模长(长度)双重因素共同影响。

  • 取值范围: ( − ∞ , + ∞ ) \boldsymbol{(-\infty,+\infty)} (−∞,+∞)
  • 判定规则:向量同向时计算结果为正数,互相垂直时值等于 0,方向相反时结果为负数;在方向保持一致的前提下,向量模长越大,最终得分越高。
  • 特点:最终分数自带向量长度带来的权重增益,更长文本生成的大模长向量更容易获得更高的匹配分值。
  • 局限:相似度评分会被文本长度干扰,无法公平对比长短不一的文本;仅适合向量模长本身具备业务权重含义的特殊场景。

公式( n 维向量):

a ⋅ b = ∑ i = 1 n a i b i \boldsymbol a \cdot \boldsymbol b=\sum_{i=1}^n a_ib_i a⋅b=i=1∑naibi

举例:向量 10 , 10 10,10 10,10 100 , 100 100,100 100,100,两个向量的指向方向完全相同,但后者向量模长更大,因此原始点积的计算结果会明显更高。

3.2.3 余弦相似度

余弦相似度 本质计算两个向量之间的夹角,对点积做归一化处理,剔除向量长度带来的影响,只关注向量的方向

公式:

cos ⁡ θ = a ⋅ b ∥ a ∥ ∥ b ∥ \cos\theta=\frac{\boldsymbol a \cdot \boldsymbol b}{\Vert a\Vert\Vert b\Vert} cosθ=∥a∥∥b∥a⋅b

  • 取值范围: − 1 , 1 -1,1 −1,1
  • 判定规则:分值等于 1 代表方向完全一致;分值等于 0 代表向量互相垂直,语义无关;分值等于 -1 代表语义完全相反。分数越靠近 1 ,语义相似度越高。
  • 关键等价关系:当向量执行 L2 归一化 (强制所有向量模长= 1 ),归一化后的点积 = 余弦相似度。向量数据库底层经常使用该特性加速计算,效果不变,性能更高。
  • 适用场景:RAG、语义检索的首选方案,不受句子长短影响,只判断语义是否相近。

示例,二维平面中有两个向量:红色点 10 , 10 \boldsymbol{10,10} 10,10、蓝色点 100 , 100 \boldsymbol{100,100} 100,100

  • 两个点从原点出发,在同一条射线上,夹角 θ = 0 \boldsymbol{\theta=0} θ=0,方向完全一致
  • 两个向量长度差别巨大: 100 , 100 100,100 100,100 的向量明显更长
  • 余弦相似度只看夹角,不关心两点在空间上离得远不远

4. 向量索引检索器 API

向量检索器是 RAG 体系中负责稠密语义召回的核心组件,通过计算查询向量与文档向量的空间相似度,从向量库中召回语义最相关的文档片段。

4.1 VectorIndexAutoRetriever (向量存储自动检索器)

父类:BaseAutoRetriever

面向向量索引的检索组件,依靠大模型自动生成向量查询参数(自动推导过滤条件、召回条数),无需人工硬编码过滤规则。

参数列表:

参数 类型 说明 默认值
index VectorStoreIndex 向量存储索引实例 必填
vector_store_info VectorStoreInfo 描述向量库内容、支持哪些元数据过滤字段;LLM依靠这段自然语言描述自动生成查询条件 必填
prompt_template_str Optionalstr 自定义LLM提示词模板;传空则使用内置默认模板 None
similarity_top_k int 默认召回文档条数 DEFAULT_SIMILARITY_TOP_K
empty_query_top_k Optionalint 当LLM推导出来的查询文本为空(仅使用元数据过滤)时,返回的文档数量;为 None 时复用 similarity_top_k 10
max_top_k int top_k 上限值;LLM输出的召回条数不会超过该值 10
vector_store_query_mode str 向量查询模式,完整取值参考 VectorStoreQueryMode DEFAULT
default_empty_query_vector OptionalList\[float] 空查询时使用的默认向量;查询文本为空时使用该向量检索 None
callback_manager OptionalCallbackManager 回调管理器,用于链路追踪与埋点 None
verbose bool 是否打印详细调试日志 False

4.2 VectorIndexRetriever(向量索引标准检索器)

父类:BaseRetriever

常规向量检索实现,参数由开发者手动固定传入 ,是日常 RAG 最基础的召回组件。

参数列表:

参数 类型 说明 默认值
index VectorStoreIndex 向量存储索引实例 必填
similarity_top_k int 召回相似度最高的前K条文档 DEFAULT_SIMILARITY_TOP_K
vector_store_query_mode str 向量查询模式,完整取值参考 VectorStoreQueryMode DEFAULT
filters OptionalMetadataFilters 元数据过滤条件 None
alpha float 稀疏/稠密混合检索权重,仅在混合检索模式生效 None
doc_ids OptionalList\[str] 限定仅在指定文档ID列表内检索 None
vector_store_kwargs dict 查询时透传给向量数据库的自定义扩展参数 必填

5. 案例案例

5.1 构建向量索引

LlamaIndex 系列【13】索引存储:SimpleIndexStore中已经介绍过怎么构建向量索引。

直接从之前的持久化目录中加载:

python 复制代码
loaded_storage_context = StorageContext.from_defaults(persist_dir="./storage")
vector_index = VectorStoreIndex(storage_context=loaded_storage_context)

5.2 构建向量检索器

LlamaIndex 提供了三种构建向量检索器的方式,分别适配快速原型开发、生产级精细化控制、智能动态查询三类典型场景。

5.2.1 方式一:快捷方法 as_retriever()

这是最简洁的构建方式,直接调用 VectorStoreIndex 内置的工厂方法生成检索器,内部自动注入索引实例并封装默认参数,代码量最少,适合快速验证与原型开发。

python 复制代码
# 最简写法:使用全局默认 top_k 与标准查询模式
vector_retriever = vector_index.as_retriever()

# 带基础参数配置写法
vector_retriever = vector_index.as_retriever(
    similarity_top_k=3,
    vector_store_query_mode="default"
)

说明

  • 内部本质:对 VectorIndexRetriever 构造函数的封装,自动传入当前 index 实例;
  • 常用可配置项:similarity_top_k 控制召回结果条数,vector_store_query_mode 指定向量查询模式;
  • 适用场景:业务规则简单、无需复杂过滤的标准 RAG 场景,以及快速验证检索效果的开发阶段。

5.2.2 方式二:显式实例化 VectorIndexRetriever

手动实例化标准向量检索器,开放完整参数配置能力,支持自定义元数据过滤、混合检索权重、文档范围限定等高级能力,是生产环境做性能调优与业务管控的首选方式。

python 复制代码
from llama_index.core.indices.vector_store.retrievers.retriever import VectorIndexRetriever
from llama_index.core.vector_stores.types import (
    MetadataFilters,
    MetadataFilter,
    FilterOperator
)

# 定义前置元数据过滤条件
filters = MetadataFilters(
    filters=[
        MetadataFilter(key="doc_type", value="product", operator=FilterOperator.EQ)
    ]
)

vector_retriever = VectorIndexRetriever(
    index=vector_index,                # 绑定目标向量索引实例
    similarity_top_k=4,               # 召回相似度 Top 4 的文档片段
    filters=filters,                  # 检索前按元数据过滤文档范围
    alpha=0.5,                        # 混合查询模式下稀疏/稠密检索的权重系数
    doc_ids=["doc_001", "doc_002"],  # 强制限定仅在指定文档范围内检索
    vector_store_query_mode="default",# 向量库查询模式
    vector_store_kwargs={}            # 透传给底层向量数据库的扩展参数
)

说明

  • 核心优势:参数完整可控,支持过滤、范围隔离、权重调优等高级配置,满足生产环境的精细化需求;
  • 兼容性:输出标准 List[NodeWithScore] 结构,与 BM25 等其他检索器完全对齐,可直接接入混合检索链路;
  • 适用场景:生产环境性能调优、多租户数据隔离、按业务维度定向检索等场景。

5.2.3 方式三:智能自动检索器 VectorIndexAutoRetriever

基于大语言模型自动解析用户自然语言查询,动态生成元数据过滤条件与召回数量,无需人工硬编码过滤规则,适合元数据维度多、查询条件灵活多变的前台业务场景。

python 复制代码
from llama_index.core.indices.vector_store.retrievers.auto_retriever.auto_retriever import VectorIndexAutoRetriever
from llama_index.core.vector_stores.types import VectorStoreInfo

# 向 LLM 描述向量库的内容边界与元数据字段定义
vector_store_info = VectorStoreInfo(
    content_info="企业内部知识库,涵盖产品手册、运维规范、架构设计三类文档",
    metadata_info=[
        {"name": "category", "type": "string", "description": "文档分类:product / ops / architecture"},
        {"name": "version", "type": "integer", "description": "文档版本号,取值 1、2、3"},
        {"name": "department", "type": "string", "description": "负责部门:研发 / 运维 / 产品"}
    ]
)

vector_retriever = VectorIndexAutoRetriever(
    index=vector_index,
    vector_store_info=vector_store_info,
    similarity_top_k=2,       # 默认召回条数基准值
    max_top_k=6,              # LLM 动态调整召回条数的上限
    empty_query_top_k=10,     # 纯元数据过滤、无查询文本时的召回条数
    verbose=False
)

说明

  • 执行链路:用户自然语言提问 → LLM 解析并提取过滤条件、召回数量 → 组装标准向量查询 → 执行检索返回结果;
  • 适用场景:面向终端用户的开放式检索、多维度智能筛选问答、低代码配置型知识库系统;
  • 注意事项:检索过程会额外产生一次 LLM 调用,接口延迟与调用成本略高于普通向量检索器。

5.3 执行检索

检索器构建完成之后,统一调用 retrieve() 方法执行召回逻辑。LlamaIndex 对所有继承自 BaseRetriever 的检索组件提供完全一致的调用接口 ,向量检索器、BM25 检索器、图谱检索器、混合检索器均可使用同一套调用方式,返回标准化结果对象 List[NodeWithScore]

直接传入字符串问句执行检索,是业务开发中最常用的调用形式。

python 复制代码
# 传入自然语言,执行召回
retrieval_result = vector_retriever.retrieve("简述产品部署流程")

# 遍历打印检索结果
for item in retrieval_result:
    print(f"匹配得分:{item.score:.4f}")
    print(f"文档内容:{item.node.text}")
    print(f"元数据信息:{item.node.metadata}\n")

返回对象说明

  • List[NodeWithScore]:检索结果列表,按匹配分数从高到低排序
    • item.score:相似度 / BM25 匹配分值
    • item.node:原始文档块对象,包含文本 text、唯一标识 node_id、业务元数据 metadata
相关推荐
长谷深风1112 小时前
AI记忆会过期,会冲突,更需要治理
人工智能·ai·大模型·prompt·memory·aiagent
云烟成雨TD2 小时前
LlamaIndex 系列【20】关键词检索(Keyword Search):BM 25 算法
ai·agent·rag·llamaindex
Summer-Bright2 小时前
深度 | GPT-6 Astra 的相变:从「会答」到「会做」,OpenAI 把对齐做成了护城河
人工智能·gpt·ai·astra·gpt-6
然我3 小时前
从 Service 到生命周期:Agent Runtime 的插件内核
前端·javascript·agent
武雄(小星Ai)3 小时前
Cursor 断供 OpenAI 模型倒计时:11月12日前,AI 编程工具怎么选
ai·开发工具·对比评测
AIGC大时代4 小时前
评科研 LLM/Agent:从读论文抽检到 ERA 树搜索写可计分实证软件
llm·agent·评测·科学发现·google research
机械改造鹅4 小时前
从零开始拆解Pi系列——(10)slash 命令系统
agent
叭一下叭4 小时前
前端转Agent开发:如何自研一个记忆模块的?
agent
山顶夕景4 小时前
【Omni】OmniGAIA: Towards Native Omni-Modal AI Agents
agent·多模态·vlm·omni·全模态