沈毅全栈与 AI

巴黎 • 新加坡 • 上海

RAG Formation · 第 5 课 · 检索工程

语义搜索、关键词搜索与混合检索

让 SOP 标识符、缩写、名称、日期和概念匹配到真正能找到它们的检索信号——向量、全文、摘要或图谱。

$ lesson --status
▸ course RAG Formation
▸ lesson 05 / 16
▸ phase 检索工程
▸ status 已完成
● build → measure → learn

独立课程

在这里学习完整课程并检验你的理解。

RAG Formation 的 16 节课程内容已完成。本页包含完整课程内容、本地参考资料和可直接在浏览器中完成的即时练习。

本课的具体收获

学完本课,你会填完一张逐题对比表,并选出一个真正得到证据支持的检索改进方案。

观看讲解视频

1 · 最小的实用模型

  • 向量检索(语义):将文本转换为浮点向量嵌入(例如 Qdrant、Pinecone),以捕捉高维相似度、上下文、含义和改写表达,而不是完全相同的词。它跨语言的表现取决于嵌入模型——不要假设,应该实际测量。
  • 全文检索(词法):使用 BM25 等算法和容错匹配(例如 Meilisearch、Elasticsearch),匹配字面词元字符串——精确的编号、名称、缩略词和数字。当精确拼写承载了关键含义时,全文检索就能发挥作用。说明:搜索引擎之间的边界正在演变——像 Meilisearch 这样的引擎现在也能原生处理向量嵌入,实现统一的混合检索。
  • 图谱检索(关系 / 结构化):动态遍历显式的节点、边和实体关系(例如 Neo4j、LightRAG)。它不只是“另一种找片段的办法”——它是唯一能够可靠追踪多跳关联的结构化信号(例如,把分散在不同文档中的事实连接起来),这是向量检索和全文检索单靠自己做不到的。
  • 摘要检索:一个独立索引,为每份完整文档存一个向量化摘要,而不是按片段存。它回答的是“这份文档讲的是什么”——当单个约 500 token 的片段太窄,装不下整份文档的主题时就需要它。
  • 累计并集:在这个实验中,只要来源出现在四路信号中的任意一路,就算被找到。这能说明检索贡献,但不能说明最终答案是否正确。
  • 混合检索:在这套系统里,“混合”指的是各路信号并行运行,把各自格式化后的结果拼接在一起——不做融合,也不做重新排序。信号之间没有分数归一化,也没有互惠排名融合;真正的融合只发生在 LightRAG 内部,在它自己的实体、关系和向量三条通路之间。代码里有一套重排引擎,但没有接入线上检索——不要以为“混合”意味着比“并行拼接”更复杂。
四种检索信号:向量、全文、摘要与图谱 每种信号都让同一条查询经过各自的处理步骤,随后四者被拼接——而非融合或重排序——进入同一个提示词。 向量 · 语义 查询:「RAG 课程」 将查询向量化 与已索引片段比较 按向量相似度排序 语义相近的片段 捕捉含义,而非精确用词 全文 · 词法 查询:「RAG 课程」 分词并归一化 精确词元匹配,容错 按词项相关性排序(BM25) 精确匹配的片段 捕捉编号、名称、精确拼写 摘要 查询:「RAG 课程」 将查询向量化 与各文档的摘要向量比较 按文档级匹配排序 文档级别的匹配 捕捉“这份文档讲的是什么” 图谱 · LightRAG 查询:「RAG 课程」 抽取实体与关系 遍历图谱的边(多跳) 融合实体与关系通路 跨文档关联 唯一的多跳信号 混合——拼接,而非融合 PROMPT — 向量 + 全文 + 摘要 + 图谱 不做分数融合,也不在信号之间做重排序。真正的融合 只发生在图谱信号内部,在它自己的实体与关系通路之间。
四路信号各自处理同一条查询,经过各自的步骤后,结果被拼接进同一个提示词——不融合,不重排序。

主要阅读:Qdrant《混合检索》——注意它如何组合多种搜索表示,以及为什么这种组合需要评估,不能想当然地认为一定有效。

2 · 运行一次受控实验

复用第 4 课使用的同一套隔离演示环境和评估集。检索模式会直接调用 /api/v1/search,整个过程不经过 LLM 评审,因此可以单独观察检索本身。

cd demo
python3 eval.py verify
python3 eval.py run --mode retrieval --workspace meridian_demo --tag lesson-05-experiment

这会生成两个文件:一份汇总报告和一份逐题 JSON 报告。

reports/lesson-05-experiment.md
reports/lesson-05-experiment.json

对于正在检查的每道题,查看:

  • results[].retrieval.indexes.vector.all
  • results[].retrieval.indexes.fulltext.all
  • results[].retrieval.indexes.summary.all
  • results[].retrieval.indexes.graph.all
  • results[].retrieval.cumulative["vector+fulltext"].all
  • results[].retrieval.cumulative["vector+fulltext+summary"].all
  • results[].retrieval.cumulative["vector+fulltext+summary+graph"].all

根据来源元数据判断是否命中,不要根据文本匹配判断——某个文档编号只是出现在另一份文档的正文里,并不代表该文档被检索到了。

图谱这一栏本身就是近似值,报告里也是这么说的:LightRAG 返回的是一整段扁平的上下文文字,不是文档列表,所以只要某个编号出现在这段文字里的任何位置,就算图谱命中——这个编号也可能只是从另一份文档的交叉引用里冒出来的。把它当成一个真实但更“吵”的信号。报告里把它单独列出来,从不悄悄并进另外三路里。

3 · 填写对比表

在五个结果栏中填写 allpartialmiss。当多文档问题只找到部分预期来源时,填写 partial。然后为每一行写一句解释,并给出一个具体的下一步。

问题编号查询类型预期来源向量结果全文结果摘要结果图谱结果累计并集解释下一步行动
q21参考文档查找PR-QA-MRD-010___________________________________
q24参考文档查找 / 版本修订PR-QA-MRD-009___________________________________
q32跨语言事实问题PR-EXM-MRD-003___________________________________
q46字面事实问题PR-ACH-MRD-007___________________________________
q63多跳问题PR-CLI-MRD-013 + PR-QA-MRD-009___________________________________

4 · 改代码前先解读结果

案例 A:对于 q21,向量结果是 miss,全文结果是 all,累计并集也是 all。这实际支持什么结论?

案例 B:向量检索和全文检索都得到 all,所以并集没有增加新的来源。诚实的解读是什么?

案例 C:q63 的 vector+fulltext 累计结果是 all,但最终答案仍然错误。下一步应该查哪里?

企业场景连接

受监管公司的聊天机器人必须同时做好两件事:准确处理措辞精确的程序查找,也要能理解真实用户表达的政策问题。这张表把“可靠”这个目标变成了可追踪的检索决策。

5 · 交付物与下一步

  1. 填完对比表中的五行。
  2. 写一段话:哪种信号为哪类查询增加了来源,证据是什么?
  3. 选择一个下一步行动,并写出要重新运行的指标,以检查行动是否有效。

下一步:第 6 课将讲分块和文档结构。保留这张表——它是后续分块与查询处理实验的检索基线。

报告字段、元数据匹配、查询类别,或者哪一行看不懂,随时问我。 这门课程中我就是你的老师,这正是我在这里的原因。