Skip to main content

概述

在本教程中,我们将使用 LangGraph 构建一个检索代理。 LangChain 提供了内置的代理实现,这些实现使用了 LangGraph 原语。如果需要更深层次的定制,可以直接在 LangGraph 中实现代理。本指南演示了一个检索代理的实现示例。检索代理在您希望 LLM 决定是从向量存储中检索上下文还是直接响应用户时非常有用。 在本教程结束时,我们将完成以下工作:
  1. 获取并预处理将用于检索的文档。
  2. 为这些文档建立语义搜索索引,并为代理创建一个检索器工具。
  3. 构建一个代理式 RAG 系统,该系统可以决定何时使用检索器工具。
混合 RAG

概念

我们将涵盖以下概念:

设置

让我们下载所需的包并设置 API 密钥:
注册 LangSmith 以快速发现问题并提升 LangGraph 项目的性能。LangSmith 允许您使用跟踪数据来调试、测试和监控使用 LangGraph 构建的 LLM 应用。

1. 预处理文档

  1. 获取将用于我们 RAG 系统的文档。我们将使用 Lilian Weng 优秀博客 中最近的三篇文章。我们将首先使用 WebBaseLoader 工具获取页面内容:
  1. 将获取的文档分割成更小的块,以便索引到我们的向量存储中:

2. 创建检索器工具

现在我们有了分割后的文档,可以将它们索引到向量存储中,用于语义搜索。
  1. 使用内存向量存储和 OpenAI 嵌入:
  1. 使用 @tool 装饰器创建检索器工具:
  1. 测试该工具:

3. 生成查询

现在我们将开始构建代理式 RAG 图的组件(节点)。 请注意,这些组件将操作于 MessagesState——一种包含 messages 键(其值为聊天消息列表)的图状态。
  1. 构建一个 generate_query_or_respond 节点。它将调用 LLM 根据当前图状态(消息列表)生成响应。根据输入消息,它将决定使用检索器工具进行检索,还是直接响应用户。请注意,我们通过 .bind_tools 让聊天模型可以访问我们之前创建的 retriever_tool
  1. 在随机输入上尝试:
输出:
  1. 询问一个需要语义搜索的问题:
输出:

4. 评估文档

  1. 添加一个条件边——grade_documents——以确定检索到的文档是否与问题相关。我们将使用一个具有结构化输出模式 GradeDocuments 的模型进行文档评分。grade_documents 函数将根据评分决策(generate_answerrewrite_question)返回要前往的节点名称:
  1. 在工具响应中包含不相关文档的情况下运行此函数:
  1. 确认相关文档被正确分类:

5. 重写问题

  1. 构建 rewrite_question 节点。检索器工具可能返回潜在的不相关文档,这表明需要改进原始用户问题。为此,我们将调用 rewrite_question 节点:
  1. 尝试一下:
输出:

6. 生成答案

  1. 构建 generate_answer 节点:如果我们通过了评分器检查,就可以根据原始问题和检索到的上下文生成最终答案:
  1. 尝试一下:
输出:

7. 组装图

现在我们将所有节点和边组装成一个完整的图:
  • generate_query_or_respond 开始,确定是否需要调用 retriever_tool
  • 使用 tools_condition 路由到下一步:
    • 如果 generate_query_or_respond 返回了 tool_calls,则调用 retriever_tool 检索上下文
    • 否则,直接响应用户
  • 评估检索到的文档内容与问题的相关性(grade_documents)并路由到下一步:
    • 如果不相关,使用 rewrite_question 重写问题,然后再次调用 generate_query_or_respond
    • 如果相关,则进入 generate_answer,并使用包含检索到的文档上下文的 ToolMessage 生成最终响应
可视化图:
SQL 代理图

8. 运行代理式 RAG

现在让我们通过用一个问题运行它来测试完整的图:
输出: