1. 内容讲解
在入门章节中,我们使用 VectorStoreIndex
构建了一个基础的 RAG 系统。然而,现实世界中的知识库往往是复杂和多样的。为了应对这些挑战,LlamaIndex 提供了丰富的进阶功能,允许我们构建更强大、更灵活的查询引擎。
1.1 索引结构进阶:SummaryIndex
与 KeywordTableIndex
VectorStoreIndex
擅长基于语义相似性进行检索,但它并非唯一的索引类型。LlamaIndex 提供了多种索引结构,以适应不同的数据和查询场景。
-
SummaryIndex
(摘要索引):- 工作原理: 它会将每个文档(或文档块)都进行一次摘要,然后将这些摘要存储起来。当用户提问时,它会先在摘要层面进行检索,找到相关的文档,然后再根据需要将这些文档的内容(或它们的摘要)喂给 LLM 来生成最终答案。
- 适用场景: 当你需要对大量文档进行高层次的、概括性的提问时非常有用。例如,“请总结一下这份财报的核心要点?”
- 与
VectorStoreIndex
的区别:VectorStoreIndex
关注的是“关键词”和“语义”的匹配,而SummaryIndex
关注的是“主题”和“大意”的匹配。
-
KeywordTableIndex
(关键词表索引):- 工作原理: 它会从每个文档中提取出关键词,并构建一个从关键词到文档的映射表。当用户提问时,它会先从问题中提取关键词,然后利用这个映射表快速定位到包含这些关键词的文档。
- 适用场景: 当你的查询高度依赖于特定的术语、实体名或关键词时,这种索引非常高效。例如,“关于‘Transformer架构’的文档有哪些?”
- 与
VectorStoreIndex
的区别:KeywordTableIndex
是基于精确的词匹配,而VectorStoreIndex
是基于模糊的语义匹配。
1.2 SubQuestionQueryEngine
:分解复杂问题
用户的问题往往不是单一的、原子性的,而是复杂的、包含多个子问题的。例如,“请比较一下 LlamaIndex 和 LangChain 在构建 RAG 应用方面的优缺点?”
要回答这个问题,一个简单的 RAG 系统可能会感到吃力。SubQuestionQueryEngine
(子问题查询引擎) 正是为了解决这类问题而设计的。
- 工作原理:
- 问题分解: 当接收到一个复杂问题时,它首先会利用 LLM 将这个问题分解成多个更简单的、可以独立回答的子问题。
- “LlamaIndex 在构建 RAG 应用方面有哪些优点?”
- “LlamaIndex 在构建 RAG 应用方面有哪些缺点?”
- “LangChain 在构建 RAG 应用方面有哪些优点?”
- “LangChain 在构建 RAG 应用方面有哪些缺点?”
- 独立查询: 它会针对每一个子问题,分别在底层的查询引擎(例如,一个
VectorStoreIndex
的查询引擎)上执行查询,并得到各自的答案。 - 答案合成: 最后,它会将所有子问题的答案汇总起来,再次利用 LLM 进行一次综合、提炼和润色,形成一个连贯的、全面的最终答案。
- 问题分解: 当接收到一个复杂问题时,它首先会利用 LLM 将这个问题分解成多个更简单的、可以独立回答的子问题。
通过这种“分而治之”的策略,SubQuestionQueryEngine
能够显著提升对复杂问题的理解和回答质量。
1.3 RouterQueryEngine
:智能路由到最佳知识源
在企业环境中,知识往往分散在不同的地方:一些在 PDF 文档里,一些在数据库里,还有一些可能在 Confluence 页面上。我们可能需要为每一种数据源构建不同的索引(例如,为 PDF 文档构建 VectorStoreIndex
,为数据库构建一个 SQLTableIndex
)。
当用户提问时,我们如何知道应该去哪个索引里查找答案呢?RouterQueryEngine
(路由查询引擎) 就是这个问题的答案。
- 工作原理:
- 注册工具: 你可以创建多个查询引擎(我们称之为“工具”),每个工具都与一个特定的索引相关联,并给每个工具一个清晰的描述。例如:
- 工具A: “用于查询2023年公司财务报告的详细数据。” (关联
SummaryIndex
) - 工具B: “用于查询产品技术文档和 API 参考。” (关联
VectorStoreIndex
)
- 工具A: “用于查询2023年公司财务报告的详细数据。” (关联
- 智能路由: 当用户提问时,
RouterQueryEngine
会利用 LLM 分析问题的意图,并根据工具的描述来选择一个或多个最合适的工具来执行查询。 - 执行与返回: 它会将问题转发给被选中的工具,并返回其查询结果。
- 注册工具: 你可以创建多个查询引擎(我们称之为“工具”),每个工具都与一个特定的索引相关联,并给每个工具一个清晰的描述。例如:
RouterQueryEngine
就像一个智能的“总调度员”,能够根据问题的类型,自动地将其分发到最合适的“知识专家”那里,从而实现对异构数据源的统一查询。
2. 代码示例
我们将扩展之前的 RAG 功能,构建一个能够处理更复杂查询的系统。我们将创建一个 SubQuestionQueryEngine
,让它能够分解用户的复杂问题,并在我们之前创建的文档索引上进行查询。
2.1 安装依赖
本章不需要新的依赖库。
2.2 更新 AI 服务层
app/services/ai.py
(修改 AIService
类)
我们将重构 query_rag
方法,使其能够处理更复杂的查询。为了简单起见,我们将索引的加载和查询引擎的构建都放在这个方法里。在生产环境中,索引的构建和加载应该是一个独立且持久化的过程。
# ... exi