构建LangChain应用程序的示例代码:37、基于LangGraph的文档检索与答案生成系统教程

这示例它实现了一个基于LangGraph的系统,用于处理文档检索和生成答案的过程。


! pip install langchain_community tiktoken langchain-openai langchainhub chromadb langchain langgraph tavily-python

CRAG

Corrective-RAG 是一篇最新的论文,介绍了一种有趣的主动 RAG 方法。

该框架根据问题对检索到的文档进行评分:

  1. 正确的文档 -

    • 如果至少有一个文档超过了相关性的阈值,则继续生成。
    • 在生成之前,它会进行知识细化。
    • 这会将文档分成“知识条带”。
    • 它对每个条带进行评分,并过滤掉无关的条带。
  2. 含糊或错误的文档 -

    • 如果所有文档都低于相关性阈值或评分器不确定,则框架会寻找额外的数据源。
    • 它会使用网络搜索来补充检索。
    • 论文中的图表还表明,这里使用了查询重写。

在这里插入图片描述

论文链接:https://arxiv.org/pdf/2401.15884.pdf


让我们使用 LangGraph 从头开始实现这一点。

我们可以做一些简化:

  • 作为初步尝试,让我们跳过知识细化阶段。如果需要,可以将其添加回节点中。
  • 如果任何文档不相关,我们选择使用网络搜索来补充检索。
  • 我们将使用 Tavily Search 进行网络搜索。
  • 我们将使用查询重写来优化网络搜索查询。

设置 TAVILY_API_KEY

检索器

让我们索引3篇博客文章。

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

urls = [
    "https://lilianweng.github.io/posts/2023-06-23-agent/",
    "https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/",
    "https://lilianweng.github.io/posts/2023-10-25-adv-attack-llm/",
]

docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]

text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=250, chunk_overlap=0
)
doc_splits = text_splitter.split_documents(docs_list)

# Add to vectorDB
vectorstore = Chroma.from_documents(
    documents=doc_splits,
    collection_name="rag-chroma",
    embedding=OpenAIEmbeddings(),
)
retriever = vectorstore.as_retriever()

状态

我们将定义一个图。
我们的状态将是 dict 。
我们可以从任何图形节点 state[‘keys’] 访问它。

from typing import Dict, TypedDict

from langchain_core.messages import BaseMessage


class GraphState(TypedDict):
    """
    Represents the state of an agent in the conversation.

    Attributes:
        keys: A dictionary where each key is a string and the value is expected to be a list or another structure
              that supports addition with `operator.add`. This could be used, for instance, to accumulate messages
              or other pieces of data throughout the graph.
    """

    keys: Dict[str, any]

节点和边

每个 node 将简单地修改 state 。
每个 edge 将选择接下来调用哪个 node 。
它将遵循上面显示的图表。
在这里插入图片描述

import json
import operator
from typing import Annotated, Sequence, TypedDict

# 导入langchain相关模块
from langchain import hub
from langchain.output_parsers import PydanticOutputParser
from langchain.output_parsers.openai_tools import PydanticToolsParser
from langchain.prompts import PromptTemplate
from langchain.schema import Document
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.vectorstores import Chroma
from langchain_core.messages import BaseMessage, FunctionMessage
from langchain_core.output_parsers 
<think>我们被要求解释Langchain Chain、Langchain Agent和LangGraph之间的区别。根据引用内容,我们可以这样分析: 1. **Langchain Chain**:是LangChain中的基本构建块,用于将多个组件(如模型、提示、其他链)连接起来形成线性工作流。它按照预定义的顺序执行任务,适合确定性任务(如RAG流程)。引用[3]提到Router Chain是Chain的一种,用于根据输入将任务路由到不同的子链[^3]。 2. **Langchain Agent**:代理(Agent)是更高级的抽象,能够根据输入动态决定调用哪些工具(如搜索、计算、API等)。它通过循环的“思考-行动”过程处理复杂任务,但成本不可预测(引用[2])[^2]。Agent适合需要动态决策的场景。 3. **LangGraph**:是LangChain生态系统中的新成员,专注于构建有状态的、基于图的执行流程。它允许节点之间有任意连接,支持循环、分支和并行处理。引用[1]强调LangGraph完全集成到LangChain生态中,可利用LangSmith进行观测[^1]。引用[2]指出LangGraph在处理复杂状态(如多轮对话)时更灵活[^2]。 ### 核心区别总结: | **特性** | **LangChain Chain** | **LangChain Agent** | **LangGraph** | |------------------------|----------------------------|----------------------------|----------------------------| | **架构** | 线性顺序执行 | 代理循环(思考-行动) | 有状态图(节点+边) | | **决策能力** | 固定流程 | 动态选择工具 | 支持循环、分支、并行 | | **适用场景** | 确定性任务(如RAG) | 需要动态工具调用的任务 | 复杂状态管理(如多轮对话) | | **状态管理** | 无状态(每次执行独立) | 有状态(通过记忆机制) | 内置状态管理 | | **LangChain集成** | 核心组件 | 核心组件 | 完全集成(LangSmith等)[^1]| | **复杂度** | 低(简单链)到中(组合链) | 中到高(依赖工具调用) | 高(需设计图结构) | ### 详细说明: 1. **LangChain Chain**: - 设计思想:通过组合预定义组件(如LLM调用、数据检索)形成**线性流程**。例如,一个典型的RAG链包括:检索文档生成提示 → 调用LLM → 输出结果。 - 优势:执行高效、成本可控。 - 局限:缺乏灵活性,无法根据中间结果动态调整流程。 - 典型应用:引用[3]中的Router Chain,它根据输入将任务分配给不同的子链(如“数学问题”路由到数学链,“历史问题”路由到历史链)[^3]。 2. **LangChain Agent**: - 设计思想:代理通过**ReAct模式**(Reasoning and Acting)循环执行:解析输入 → 选择工具 → 执行工具 → 分析结果 → 决定下一步[^2]。 - 优势:动态适应复杂场景(如多工具协作)。 - 局限:工具调用次数不可预测,可能增加延迟和成本。 - 示例:用户查询“特斯拉老板的年龄”,代理可能先搜索“特斯拉老板是谁”,再搜索“埃隆·马斯克的年龄”。 3. **LangGraph**: - 设计思想:将工作流建模为**有向图**,节点代表操作(如调用LLM、工具),边定义状态流转逻辑。支持循环(如持续对话直到满足条件)和分支(如错误重试)[^1][^2]。 - 优势:处理**长期运行、有状态的任务**(如客服机器人)。 - 关键特性:状态(State)在节点间传递,可存储中间结果。 - 集成优势:无缝使用LangChain工具和LangSmith监控。 ### 何时选择? - **用Chain**:任务流程固定且无需动态决策(如文档摘要、翻译)。 - **用Agent**:需要动态调用外部工具(如实时搜索、API集成)。 - **用LangGraph**:任务涉及复杂状态流转(如多轮审批、游戏AI)或需要并行/重试逻辑[^2]。 ### 代码示例对比 #### LangChain Chain(线性RAG流程): ```python from langchain.chains import RetrievalQA from langchain_community.vectorstores import Chroma # 固定流程:检索生成 qa_chain = RetrievalQA.from_chain_type( llm=ChatOpenAI(), retriever=Chroma.from_texts(["特斯拉老板是埃隆·马斯克"]).as_retriever() ) result = qa_chain.invoke("特斯拉老板是谁?") # 输出固定答案 ``` #### LangChain Agent(动态工具调用): ```python from langchain.agents import AgentExecutor, create_openai_tools_agent # 代理决定何时调用搜索工具 agent = create_openai_tools_agent(ChatOpenAI(), [TavilySearchTools()]) agent_executor = AgentExecutor(agent=agent, tools=tools) result = agent_executor.invoke("特斯拉老板的年龄?") # 可能调用两次搜索工具 ``` #### LangGraph(有状态对话): ```python from langgraph.graph import StateGraph # 定义状态和节点 class AgentState(TypedDict): input: str history: list[str] def llm_node(state: AgentState): return {"response": ChatOpenAI().invoke(state["input"])} # 构建图 → 支持循环 graph = StateGraph(AgentState) graph.add_node("llm", llm_node) graph.add_edge("llm", END) # 可添加条件分支 app = graph.compile() ``` --- ### 总结 - **Chain**:线性管道,高效处理确定性任务。 - **Agent**:动态代理,灵活调用工具解决开放性问题。 - **LangGraph**:图引擎,管理复杂状态和流程(如循环对话)[^1][^2]。 --- §§相关问题§§ 1. 如何根据任务复杂度选择Chain、Agent或LangGraph? 2. LangGraph在哪些场景下比传统Agent更有优势? 3. 如何将现有的LangChain Chain迁移到LangGraph? [^1]: Autogen 和 LangGraph 之间的另一个关键区别是 LangGraph 完全集成到 LangChain 生态系统中... [^2]: 一文彻底搞懂LangChainLangGraph该怎么选?何时选?... [^3]:AI大模型学习路线】第三阶段之RAGLangChain——第十五章(LangChainChain组件)Router Chain详解...</think>### LangChain Chain、LangChain Agent LangGraph 的区别详解 以下是三者的核心区别对比,基于引用内容整理: | **特性** | **LangChain Chain** | **LangChain Agent** | **LangGraph** | |-------------------------|----------------------------------------|----------------------------------------|----------------------------------------| | **架构核心** | 线性执行流程 | 动态工具调用循环 | 有状态图结构(节点+边) | | **决策机制** | 预定义顺序执行 | 基于LLM的实时工具选择 | 支持循环/分支/并行处理[^2] | | **状态管理** | 无状态(每次执行独立) | 有限状态(通过记忆机制) | 内置状态管理(跨节点传递) | | **适用场景** | 确定性任务(如RAG)[^3] | 动态工具调用(如搜索/计算) | 复杂工作流(如多轮对话/审批) | | **错误处理** | 简单异常捕获 | 有限重试逻辑 | 内置重试和错误路由[^2] | | **LangChain集成** | 核心组件 | 核心组件 | 完全集成生态(含LangSmith)[^1] | | **典型组件** | `SequentialChain`, `RouterChain`[^3] | `ReAct Agent`, `OpenAI Functions` | 状态图(StateGraph) | --- ### 详细解析 #### 1. **LangChain Chain:线性执行引擎** - **设计思想**:通过预定义组件(LLM、工具、提示模板)构建**确定性工作流** - **核心特征**: - 固定执行顺序:`输入 → 组件A → 组件B → 输出` - 支持条件路由:如`RouterChain`根据输入选择子链[^3] - 适用场景: ```python # 示例:顺序链(文档摘要 → 翻译) chain = SequentialChain( chains=[summary_chain, translate_chain], input_variables=["document"] ) ``` - **局限**:无法动态调整流程,缺乏复杂状态管理 #### 2. **LangChain Agent:动态决策代理** - **设计思想**:基于LLM的**思考-行动循环**(ReAct模式) - **核心特征**: - 动态工具选择:根据输入实时调用工具(搜索/API/计算) - 记忆机制:维护短期对话历史 - 执行流程: ```mermaid graph LR A[用户输入] --> B{LLM决策} B -->|选择工具| C[工具执行] C --> D{是否完成?} D -->|否| B D -->|是| E[输出结果] ``` - **优势**:处理开放性问题(如“特斯拉老板的年龄?”需先查身份再查年龄) - **局限**:复杂状态处理困难,循环逻辑实现复杂[^2] #### 3. **LangGraph:图工作流引擎** - **设计思想**:**有向图结构**管理状态流转 - **核心突破**: - 节点(Node):执行单元(LLM/工具/条件判断) - 边(Edge):定义状态转移逻辑 - 状态(State):跨节点传递数据 - **关键能力**: - 循环处理:`聊天机器人`持续对话直到满足退出条件 - 并行执行:同时调用多个API - 错误重试:自动路由失败任务[^2] - **代码示例**: ```python from langgraph.graph import StateGraph class AgentState(TypedDict): user_query: str search_results: list # 构建图 graph = StateGraph(AgentState) graph.add_node("search", search_tool) graph.add_node("llm", llm_processor) graph.add_edge("search", "llm") # 搜索完成后转LLM处理 graph.set_entry_point("search") ``` --- ### 何时选择? | **场景** | **推荐方案** | **原因** | |---------------------------|---------------------|---------------------------------------| | 固定流程(如文档处理) | Chain | 高效且成本可控 | | 需动态工具调用 | Agent | 实时决策能力强大 | | 多轮对话/复杂审批流 | LangGraph | 状态管理和循环支持完善[^2] | | 需要LangSmith监控 | LangGraph | 深度集成可观测性工具[^1] | > 关键洞察:LangGraph不是替代Chain/Agent,而是**扩展**——它可封装Chain和Agent作为节点,构建更复杂的工作流[^2]。 --- ### 典型应用案例 1. **Chain**: - RAG流水线:`检索生成 → 格式化输出`[^3] - 分类路由:`RouterChain`将数学问题/历史问题分发给专用链 2. **Agent**: - 实时数据分析:调用搜索引擎 + 计算工具 + 图表生成API - 客服机器人:根据问题类型选择知识库/订单系统工具 3. **LangGraph**: - 保险理赔系统: ``` 用户提交 → 文件审核 → (通过)支付 | (失败)转人工 → 通知用户 ``` - 多角色协作:销售Agent、技术Agent、审批Agent通过状态图协同[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hugo_Hoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值