一.混合检索
1.稀疏向量和稠密向量
-
稀疏向量:也被称为“词法向量”,维度高,但多为0,通常用于关键词的精确匹配,将文档视为一堆词的集合,不考虑其语法和顺序,每一维向量都代表一个词,向量中的非零值代表该词在文档中的重要性。
-
密集向量:也被称为“语义向量”,由深度学习模型生成的,低维度,且每一个维度都有数值,代表某种抽象的特征。通过将原始数据映射到一个向量空间中,意思相近的词,在空间中位置也相近。
-
对比
| 特性 | 稀疏向量 (Sparse Vector) | 稠密向量 (Dense Vector) |
|---|---|---|
| 代表技术 | BM25, TF-IDF | BERT, OpenAI Embeddings, BGE |
| 关注点 | 关键词、专有名词、编码 | 语义、上下文、情绪 |
| 维度 | 极高(词典大小,如 50,000+) | 较低且固定(如 768 或 1536) |
| 匹配方式 | 有没有这个词语 | 语义是否相近 |
| 优点 | 极其精准,不会产生幻觉匹配 | 能理解“苹果”和“水果”的关联 |
| 缺点 | 无法理解同义词(如“西红柿”和“番茄”) | 容易漏掉特定的产品型号或罕见人名 |
2.混合检索
在RAG系统的构建中,单打独斗的检索方式往往会遇到瓶颈。稀疏向量能匹配到关键词,但是不灵活,稠密向量懂语义,但是容易“幻觉”。
结合两种向量的优点,混合检索同时利用稀疏向量的精准匹配和密集向量的语义深度,具备搜索引擎一样的“精准度”和像人类一样的“理解能力”。
3.如何合并结果
由于稀疏检索的评分(几十分)和稠密检索的评分(0-1)不在一个量级上,不能直接相加。 有两种处理方法:
-
倒数排序融合(BRF)
-
原理:不看分数,只看排名,一个文档在不同检索系统中的排名越靠前,得分越高。
-
简化公式:( 通常取 60)。
-
特点:简单粗暴,准确性高,不需要手动调权重。
-
-
线性加权组合
-
原理:先把两种评分归一化处理,然后手动赋权重。
-
栗子:。
-
特点:灵活性高,例如,如果对专业术语要求较高,可以提高稀疏检索的权重值。
-
二.查询构建
在RAG系统的优化中,查询构建是指在检索用户的原问题时,利用LLM大模型对问题进行重写,拆解或转换的过程。
举个栗子:用户的提问往往是口语化,模糊的,甚至包含多个子问题。查询构建的任务就是把这些“不完美的任务”加工一下,转换成容易被搜索引擎理解的形式。
1.文本到元数据过滤器
在RAG中也称为“自查询检索器”,就是把用户的提问,翻译成数据库理解的“条件筛选语句”。
- 准备离线索引:在构建索引阶段中,存入文档时为每一个片段附加标签,向LLM清晰地描述文档内容和每一个元数据字段的含义。例如:
# 3. 配置元数据字段信息
metadata_field_info = [
AttributeInfo(
name="title",
description="视频标题(字符串)",
type="string",
),
AttributeInfo(
name="author",
description="视频作者(字符串)",
type="string",
),
AttributeInfo(
name="view_count",
description="视频观看次数(整数)",
type="integer",
),
AttributeInfo(
name="length",
description="视频长度(整数)",
type="integer"
)
]
# 4. 创建自查询检索器
llm = ChatDeepSeek(
model="deepseek-chat",
temperature=0,
api_key=os.getenv("DEEPSEEK_API_KEY")
)
retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vectorstore,
document_contents="记录视频标题、作者、观看次数等信息的视频元数据",
metadata_field_info=metadata_field_info,
enable_limit=True,
verbose=True
)
- 查询解析:当用户输入时,自查询检索器会调用LLM,将查询解析为两部分:
-
语义查询器:进行语义搜索的部分,例如“周杰伦演唱会评价”。
-
元数据过滤器:结构化的过滤条件,例如:
{"date": {">": "2025-10-26"}, "likes": {">": 1000}} -
- 执行查询:将上一步解析的语义查询字符串和元数据过滤器结果发送给向量数据库,进行一次包含语义搜索和元数据过滤的查询。
2.文本到Cypher
Cypher 是专门为图形数据库(如 Neo4j)设计的查询语言(类似于 SQL 之于关系型数据库)。在 RAG 系统中,它是实现 GraphRAG(图增强检索) 的核心技术。
- 工作流程:
-
Schema 注入: 你需要先告诉 LLM 图数据库的结构(有哪些节点标签,如
Person,Project;有哪些关系类型,如WORKS_IN,LEADS)。 -
查询翻译: LLM 根据用户的问题生成 Cypher 代码。
-
语法纠错(可选): 有时会再加一层 LLM 校验,确保生成的代码没有语法错误。
-
执行与反馈: 数据库返回结果,LLM 再结合这个结果生成最终的人类语言回答。
-
3.文本到SQL
在实际的开发中,大量有价值的数据一般存储在数据库中,比如订单信息,商品信息,用户信息...,文本到sql是将用户的自然语言,通过大模型翻译为操作数据库的sql语句。
-
工作流程:
-
Schema注入:将数据库的表名,列名,字段类型以及它们之间的关系(主键外键)告诉大模型。
-
翻译为sql语句:大模型根据Schema注入和用户的问题生成sql语句。
-
执行验证:在沙盒环境下运行sql。并验证错误,将错误信息反馈的大模型让它重新执行。
-
结果解读:将数据库返回的数据交给大模型,让它组织加工返回给用户。
-
-
待解决的问题
-
输入模糊:用户的提问一般较口语化,可能会使大模型分不清用户的真实意图。
-
复杂逻辑:当涉及到表与表之间的复杂链接查询时,大模型容易产生逻辑幻觉。
-
安全性:必须防止用户通过输入诱导大模型生成删库的危险语句。
-
-
优化策略:
| 方案 | 具体做法 | 效果 |
|---|---|---|
| 提供精确数据模型 | 向llm提供数据库中相关表的create table语句。 | 极大提升逻辑准确性。 |
| 错误修正与反思 | 生成语句后,先做一步执行,如果返回有错误,将错误信息返回给llm,重新生成语句。 | 降低“幻觉”风险 |
| 提供示例 | 在prompts中加入一些问题->sql的例子 | 学习构造语句,减少逻辑错误 |
三.查询重构与分发
用户的原始问题往往不是最优的检索输入。它可能过于复杂、包含歧义,或者与文档的实际措辞存在偏差。为了解决这些问题,我们需要在检索之前对用户的查询进行“预处理”,对问题进行“精装修”。
1.查询翻译
查询翻译是为了弥补用户的自然语言提问和文档中存储信息之间的“语义鸿沟”,通过重写,分解或扩展查询,可以显著提高检索的准确率。
-
提示工程:最直接的查询重构方法,通过prompts引导llm改写用户的原始问题,使其更利于检索。
-
多查询分解:当用户的问题包含多个主体和意图时,可以将这个复杂问题分解为多个子问题,从不同维度分析答案。例如:
-
原问:“如何优化 Vue3 性能?”
-
翻译结果:
- “Vue3 渲染优化技巧”
- “Vue3 内存泄漏排查”
- “Vite 构建体积优化”
-
-
退步提示:有时用户的问题过于具体细节,模型直接作答可能容易出错。退步提示首先将用户的问题抽象为更基础,概况的“退步问题”;然后大模型先获取退步问题的答案,然后结合用户的原始问题作为上下文,进行最终推理。例如:
-
原问:“在 Windows 11 下安装 Node.js v20 报错 XXX 怎么办?”
-
翻译结果:“Node.js 环境安装及常见环境配置错误解决”。
-
-
假设性文档嵌入(HyDE):不直接使用用户的原始查询,通过一个生成式大模型来构造一个“假设性的”,能够完美回答这个问题的文档。然后将此“完美文档”嵌入到向量数据库中,再从向量数据库中找与之相似度最高的文档。
2.查询路由
当系统接入了多个不同的数据源或具备多种处理能力时,查询路由就作为智能调度中心,动态选择合适的路径。其本质是替代硬编码规则,通过语义理解将查询分配到最匹配的数据源,处理组件,提示词模板,从而提升系统的效率与准确性。
根据应用场景的不同,查询路由分为以下3种:
-
数据源路由:根据查询意图,将其路由到不同的知识库。例如:
-
提问“我昨天的订单在哪?” -> 路由到 SQL 数据库。
-
提问“怎么退货?” -> 路由到 向量知识库 (Vector DB) 。
-
提问“今天天气怎么样?” -> 路由到 实时搜索 API。
-
-
组件路由:根据问题的复杂性,将其分配给不同的处理组件。例如:
-
简单问题:直接采用向量数据库最相似匹配。
-
复杂问题:调用agent或methods。
-
-
提示词模板路由:基于关键词或特定的元数据触发,动态选择最优的提示词模板。例如:
-
如果问题中包含“代码”或“报错”,直接强制分发到“技术文档库”模板。
-
数学问题,选用包含分步思考逻辑的提示模板。
-
参考文章
DataWhale All-in-RAG | 大模型应用开发实战一:RAG技术全栈指南