1. 混合检索 (Hybrid Search):精度与广度的数学融合

混合检索不是简单的“拼凑”,而是为了弥补单一检索模态的数学缺陷。

核心痛点

  • 稠密检索(Dense Retrieval / Vector Search)的缺陷:基于语义向量。它擅长理解“意思”,但对精确匹配非常弱。例如,搜索“错误码 8023”,向量模型可能会将其关联到“网络连接错误”,但不一定能精准匹配到含有“8023”这个具体数字的文档。

  • 稀疏检索(Sparse Retrieval / Keyword Search)的缺陷:基于词频(如 BM25)。它擅长精确匹配字符,但无法理解语义。例如,搜索“苹果手机”,它无法匹配到只有“iPhone”字眼的文档,因为如果不建立同义词库,这两个词在字面上毫无重叠。

深度实现机制

混合检索通过同时执行上述两种检索,然后将结果融合。

A. 算法层:BM25 + Embedding

  1. 并行检索

    • 路 A (Sparse):对 Query 进行分词,去除停用词,在倒排索引中运行 BM25 算法,计算词项(Term)在文档中的 TF-IDF 权重。

    • 路 B (Dense):将 Query 输入 Embedding 模型(如 text-embedding-3bge-m3),生成 768 或 1024 维向量,在向量数据库中进行 ANN(近似最近邻)搜索。

  2. 结果池:你现在得到了两个列表,一个是 BM25 认为最重要的 Top-50,一个是向量认为最相关的 Top-50。

B. 融合层:RRF (Reciprocal Rank Fusion,倒数排名融合)

这是混合检索中最关键的一步。因为 BM25 的得分(可能是 0-15)和向量相似度(可能是 0.6-0.9)不在同一个量级,直接加权求和(Weighted Sum)非常难调参。RRF 是一种基于排名的“无参数”融合算法。

  • RRF 公式

    RRFscore(d) = \sum_{r \in R} \frac{1}{k + r(d)}

    • $d$:文档。

    • $R$:不同的检索器集合(BM25 和 Vector)。

    • $k$:平滑常数(通常设为 60)。

    • $r(d)$:该文档在某个检索器中的排名(Rank)。

  • 原理详解:如果一个文档在 BM25 中排第 1,在 Vector 中排第 1,它的分数会极高。如果它只在其中一个列表中出现且排名靠后,分数就会很低。RRF 巧妙地规避了分值标准不统一的问题,只看“排名”。

应用场景建议

  • 代码库搜索:必须用混合检索。函数名(精确)+ 功能描述(语义)。

  • 电商搜索:必须用混合检索。产品型号(精确)+ 描述(语义)。


2. 查询构建 (Query Construction / Self-Querying):自然语言转结构化过滤

许多开发者误以为 RAG 只是把文本扔进向量库。但在实际业务中,数据往往带有大量的结构化元数据(Metadata)。查询构建的本质,是将用户的自然语言意图,转化为向量检索 + 结构化过滤的组合。

核心痛点

用户提问:“我想找去年评分最高的几部科幻电影。”

  • 纯向量检索的失败:Embedding 模型很难在向量空间中精确表达“去年(2024年)”这个时间概念,也很难通过距离来衡量“评分数值”。

  • 解决方案:将“去年”和“评分最高”从向量搜索中剥离出来,转化为数据库的 Filter 条件。

深度工作流 (Self-Querying)

A. 属性提取 (Attribute Extraction)

利用 LLM 分析用户的 Prompt,提取出两部分信息:

  1. 查询内容 (Search Term):用于向量检索的文本(如:“科幻电影”)。

  2. 过滤条件 (Filter Conditions):用于 SQL 或 Metadata 过滤的结构化数据。

  • Prompt 示例

    用户输入:"推荐几双 100 美元以下的耐克跑步鞋。"

    你的任务:提取品牌、价格区间和搜索关键词。

    输出 JSON:

    JSON

    {
      "query": "跑步鞋",
      "filter": {
        "brand": "Nike",
        "price": {"$lt": 100}
      }
    }
    

B. 检索执行 (Execution Strategy)

得到 JSON 后,进入向量数据库执行,这里有两种核心策略:

  1. Pre-filtering (前置过滤)推荐方式。先根据 brand="Nike" AND price < 100 筛选出所有符合条件的文档,然后在这些文档中进行向量相似度搜索。这能保证结果 100% 符合硬性条件。

  2. Post-filtering (后置过滤):先向量搜索 Top-100,然后再把不符合条件的剔除。缺点:如果符合条件的文档很少,可能都被过滤掉了,导致召回为零。

C. 难点与优化

  • 基数过大 (High Cardinality):如果元数据字段有几万个可能的值(如具体的“作者名”),LLM 可能会产生幻觉或拼写错误。

    • 优化:在 Prompt 中注入合法的 Enum 值列表;或者使用模糊匹配(Fuzzy Match)来校正 LLM 提取的过滤词。


3. Text-to-SQL:结构化数据的 RAG

企业的核心数据往往不在文档里,而是在关系型数据库(Relational DB)中。Text-to-SQL 是 RAG 的一个特殊分支,它不检索文本块,而是检索数据行。

工作流程详解

A. Schema Linking (模式链接)

LLM 不知道你的数据库长什么样。你需要将数据库的 Schema(表名、列名、外键关系、甚至几行示例数据)喂给 LLM。

  • Context Window 挑战:如果数据库有 100 张表,Prompt 放不下。

  • 优化:先利用 RAG 检索出与用户问题最相关的那几张表的 Schema,只把这部分 Schema 放入 Prompt。

B. SQL 生成与校验

  • Prompt Engineering:使用 Few-Shot Prompting(少样本提示)。提供 3-5 个“问题 -> 正确 SQL”的示例,极大提升准确率。

  • Self-Correction (自愈)

    1. LLM 生成 SQL。

    2. 代码尝试在数据库执行。

    3. 如果报错(如 Column not found),将错误信息回传给 LLM,让它进行自我修正并重新生成。

C. 结果合成

数据库返回的是 Rows (表格数据)。

  • 直接把表格扔给用户体验不好。

  • 最后一步是将用户的原始问题 + 执行的 SQL + 查询结果(表格) 一起喂给 LLM,让它生成一段通顺的自然语言回答。

Text-to-SQL 的特有优化

  • 语义层 (Semantic Layer):数据库的列名往往是缩写(如 c_limit),LLM 看不懂。需要在中间加一层映射,告诉 LLM c_limit = "Credit Limit (信用额度)"。

  • 安全控制绝对禁止 LLM 生成 DROP, DELETE, UPDATE 语句。务必在数据库权限层面限制为 READ ONLY,并在生成层进行关键词拦截。


4. 查询重构与分发 (Refactoring & Routing):理解意图的艺术

这是 RAG 变得“智能”的分水岭。用户的原始提问往往是模糊、缺失上下文或极其复杂的。直接检索原始提问通常效果不佳。

A. 查询重构 (Query Refactoring / Transformation)

1. 多路查询 (Multi-Query / Query Expansion)

  • 场景:用户问题可能可以用多种方式表述,或者包含多个子问题。

  • 做法:让 LLM 基于原始问题生成 3-5 个不同角度的变体。

    • 原始:“RAG 怎么优化?”

    • 变体 1:“RAG 向量检索的各种索引对比”

    • 变体 2:“基于 LLM 的重排序策略”

    • 变体 3:“混合检索的实现原理”

  • 执行:并行检索这 5 个问题,然后对结果去重。这能极大提升召回率(Recall)

2. 分解 (Decomposition / Sub-Questioning)

  • 场景:复杂推理问题。

  • 例子:“GitHub 的创始人现在的公司的最新产品是什么?”

  • 做法:LLM 拆解问题:

    1. GitHub 创始人是谁? -> 检索 -> 得到“Chris Wanstrath”。

    2. Chris Wanstrath 现在在哪家公司? -> 检索 -> 得到“B company”。

    3. B company 的最新产品是什么? -> 检索 -> 最终答案。

  • 这是 CoT (Chain of Thought) 在检索过程中的应用,通常通过 Agent 循环执行。

3. HyDE (Hypothetical Document Embeddings)

  • 原理:向量相似度中,“问题”和“答案”的向量距离其实挺远的(一个是疑问句,一个是陈述句)。

  • 做法

    1. 用户提问。

    2. 让 LLM 瞎编一个假设性答案(哪怕事实是错的,但涵盖了相关领域的术语)。

    3. 将这个“假设性答案”向量化,去数据库检索。

  • 优势:利用“答案”去找“答案”,语义匹配度显著提高。

B. 查询分发 (Query Routing / Logic Routing)

RAG 系统往往集成了多种数据源(SQL 库、向量库、Web 搜索、工具 API)。Router 就像是一个交通指挥官。

1. 逻辑路由 (Logical Routing)

利用 LLM 的分类能力。

  • Prompt

    "你是一个路由助手。基于用户的问题,选择以下工具之一:['SQL_Database' (用于查销售数据), 'Vector_DB' (用于查公司文档), 'Calculator' (用于数学计算)]。"

    用户输入:"去年我们在上海的销售额是多少?"

    输出:"SQL_Database"

2. 语义路由 (Semantic Routing)

这是一种更快速、低成本的方法。

  • 做法:预先为每个 Tool 定义几个“典型问题”并计算向量。

  • 执行:当用户新问题进来时,计算其向量,查找与哪个 Tool 的“典型问题”向量最接近,就路由给谁。这种方法不需要调用 LLM,仅需一次向量计算,速度极快。


总结:如何组合使用?

一个顶级的 RAG 系统通常是这样串联的:

  1. 用户提问

  2. 查询路由:判断是去查 SQL 还是查向量库。

    • 如果是 SQL -> Text-to-SQL 流程。

    • 如果是文档 -> 查询重构(生成多个变体)。

  3. 查询构建:从变体中提取元数据过滤器(时间、分类)。

  4. 混合检索:带上过滤器,并行执行 BM25 + Vector Search。

  5. RRF 融合:合并结果。

  6. 重排序 (Rerank):对 Top-K 结果精排。

  7. 生成:LLM 给出答案。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐