LangChain与LangGraph深度解析:从链式编排到图计算工作流

📅 2026/8/15 6:16:36
LangChain与LangGraph深度解析:从链式编排到图计算工作流
1. 从“链”到“图”LangChain与LangGraph的设计哲学演进如果你在过去一年里接触过AI应用开发那么“LangChain”这个名字大概率不会陌生。它几乎成了用大语言模型LLM构建智能应用的代名词。但当你开始构建稍微复杂一点的流程比如一个需要多轮决策、状态回溯或并行处理的客服机器人时你可能会发现单纯用“链”Chain来组织逻辑就像试图用一根绳子去编织一张网有些力不从心。这正是LangGraph诞生的背景。今天我们不谈那些浮于表面的概念而是深入骨髓拆解LangChain和LangGraph这两个框架的设计理念、核心架构以及内部那些真正决定你开发效率的组件。理解这些你才能判断何时该用Chain何时必须上Graph以及如何高效地组合它们而不是被各种新概念牵着鼻子走。LangChain的核心设计理念是“组合性”。它认为一个复杂的AI应用可以由一系列更小、更专注的“链接”组成。每个链接如一个LLM调用、一个工具调用、一个数据检索都是一个独立的单元通过标准化的接口输入/输出连接起来形成一条线性的执行流水线。这非常符合我们最初对AI工作流的直觉先做A再做B然后得到C。它的框架结构是围绕Chain、Agent、Memory、Retrieval这些核心抽象搭建的目标是降低开发门槛提供丰富的“乐高积木”。而LangGraph的设计理念则更进一步它拥抱的是“状态机”和“图计算”。它承认现实世界中的智能流程很少是纯粹线性的更多是带有分支、循环、并行和状态依赖的网络。LangGraph将整个应用定义为一个有向图节点是任意的函数或工具边则定义了控制流基于节点的输出决定下一步走到哪里。它的框架核心是StateGraph和compile()方法通过编译将一个静态的图定义转化为一个可以逐步执行、状态可持久化的运行时。简单说LangChain帮你组装一辆在固定轨道上跑的火车而LangGraph给你一张地图和一套交通规则让你能动态规划路径甚至同时派出多辆车去探索。2. LangChain框架深度拆解不只是“链”的集合很多人把LangChain简单理解为一堆预置链如LLMChainSequentialChain的合集这大大低估了它的价值。它的框架结构是一个分层、模块化的系统旨在提供从底层操作到高层编排的完整支持。2.1 核心抽象层构建应用的原子单位这一层定义了最基本的操作单元是框架的基石。1. LLMs / Chat Models这是与大脑对话的接口。LLMs封装了文本补全模型如GPT-3而ChatModels封装了对话模型如GPT-4 Claude它们处理消息列表SystemMessage,HumanMessage,AIMessage。关键不在于调用invoke方法而在于理解它们的“标准化”。无论底层是OpenAI、Anthropic还是本地部署的模型上层的调用方式几乎一致。这带来了巨大的灵活性比如你可以写一个程序通过环境变量轻松在GPT-4和Claude 3之间切换而无需重写业务逻辑。2. Prompts Output ParsersPrompt是给模型的“工作说明书”。LangChain提供了PromptTemplate允许你创建带有变量的模板如“请总结{text}”。但更深层的价值在于FewShotPromptTemplate、ChatPromptTemplate等它们能帮你系统化地管理复杂的提示工程。OutputParsers则负责把模型天马行空的文本输出解析成结构化的数据如Pydantic对象、列表、JSON。这是连接非结构化语言和结构化程序逻辑的关键桥梁。我个人的经验是花时间设计一个好的OutputParser远比事后用正则表达式去“抠”输出要可靠得多。3. Document Loaders Text Splitters这是连接私有数据的关键。DocumentLoaders从各种源PDF、网页、Notion、数据库加载数据并统一成Document对象包含页面内容和元数据。TextSplitters则负责将长文档切割成适合模型上下文窗口的小块。这里最大的坑不是怎么切而是怎么切才能保持语义连贯。简单的按字符或token数切割很可能会把一个完整的句子或概念拦腰斩断。RecursiveCharacterTextSplitter是常用选择它会优先按段落、句子、单词等层级递归切割但针对代码、Markdown等特定格式你需要自定义分割符列表。一个实用的技巧是切割后让相邻的块之间有少量重叠例如100-200个字符这能有效防止上下文信息在块边界丢失。4. Vector Stores Retrievers这是实现“记忆”和“知识”的组件。VectorStores如Chroma Pinecone Weaviate负责存储文档块的向量嵌入Embedding并提供相似性搜索。Retrievers是查询向量库的抽象接口。核心在于理解“检索”的不同策略相似性搜索Similarity Search最基础根据问题向量找最相似的文档块。最大边际相关性MMR在保证相关性的同时增加返回结果的多样性避免内容重复。自查询Self-Query Retriever让LLM自动从用户问题中提取过滤条件如“2023年之后的报告”再同时进行元数据过滤和向量搜索。这在处理带有时效、作者等标签的文档时极其有用。2.2 编排层从链到智能体这一层决定了你的应用逻辑如何流动。1. Chains链是LangChain的招牌。最基本的LLMChain组合了一个PromptTemplate、一个LLM和一个可选的OutputParser。但真正的力量来自链的组合。SequentialChain允许你线性串联多个链前一个链的输出作为后一个链的输入。TransformChain则允许你插入纯Python函数对数据进行转换。我常用的一个模式是检索链 - 精炼问题链 - 回答链。检索链先找到相关文档精炼问题链利用检索到的上下文将用户的原始模糊问题重构成一个更精准的问题最后回答链基于精炼后的问题和上下文生成最终答案。这比一次性把检索结果和原始问题扔给模型效果通常更好。2. Agents Tools当任务无法仅靠LLM的知识和一次检索完成时就需要智能体。智能体的核心是一个循环思考 - 选择工具 - 执行工具 - 观察结果 - 再思考...。Tools是对外功能的封装可以是搜索API、计算器、数据库查询甚至是另一个链。LangChain提供了多种AgentType如ZERO_SHOT_REACT_DESCRIPTION,OPENAI_FUNCTIONS其本质是定义了驱动这个循环的提示词Prompt和解析逻辑。开发智能体最大的挑战在于工具设计的清晰度。工具的描述必须足够精确让LLM能准确理解其功能和输入格式。一个模糊的工具描述会导致智能体频繁调用错误工具或传入错误参数。3. Memory让对话拥有上下文记忆。ConversationBufferMemory简单地将所有历史对话存入缓冲区ConversationSummaryMemory则用LLM定期总结长对话以节省tokenVectorStoreRetrieverMemory将历史对话存入向量库实现基于语义的相关记忆检索。选择哪种Memory取决于你的场景短且需精确引用的客服场景可用Buffer长程对话管理可用Summary需要从大量历史中灵活回忆片段时Retriever是更好的选择。3. LangGraph架构揭秘用“图”思维重塑复杂工作流当你的智能体需要处理嵌套子任务、支持并行执行、或者在失败后回溯到特定步骤重试时单纯的链或智能体循环就显得捉襟见肘。LangGraph通过引入“图”和“状态”的概念来解决这些问题。3.1 核心概念State Node EdgeState这是一个贯穿整个图执行过程的、共享的可变数据结构。通常用一个TypedDict或Pydantic模型来定义包含了执行所需的所有信息例如messages对话历史intermediate_steps工具调用记录documents检索结果等。State在节点间传递和修改是LangGraph协调全局的“中央情报局”。Node节点是一个函数它接收当前的完整State执行一些操作如调用LLM、运行工具然后返回一个包含对State所做更新的字典。例如一个“调用模型”的节点会读取State中的messages调用ChatModel然后将新的AIMessage追加到messages中并返回。关键点是节点只返回它修改了的那部分State而不是整个新State。LangGraph会自动将其与旧State合并。Edge边决定了控制流。它连接两个节点并根据条件决定是否要走这条边。边分为两种普通边直接连接无条件执行。条件边Conditional Edge基于一个路由函数Router的返回值决定下一步走到哪个节点。这是实现分支逻辑的核心。路由函数同样接收State作为输入。3.2 构建图的工作流一个审批流程的实例假设我们要构建一个智能合同审批助手用户提交合同先进行合规性检查如果合规则发送给法务如果不合规则让用户修改法务审核后可能通过、驳回或要求补充材料。用LangGraph构建这个流程非常直观定义Statefrom typing import TypedDict, List, Literal, Optional from langgraph.graph import END class State(TypedDict): contract_text: str compliance_status: Optional[Literal[compliant, non_compliant]] legal_review: Optional[Literal[approved, rejected, needs_clarification]] messages: List # 用于记录和用户的对话 current_step: str创建节点def compliance_check_node(state: State) - dict: # 模拟合规检查逻辑实际中会调用LLM或规则引擎 if 风险条款 in state[contract_text]: new_status non_compliant msg 合同包含高风险条款需修改。 else: new_status compliant msg 合同基础合规转法务审核。 return {compliance_status: new_status, messages: state[messages] [{role: system, content: msg}], current_step: compliance_checked} def legal_review_node(state: State) - dict: # 模拟法务审核 return {legal_review: approved, current_step: legal_reviewed} # 简化处理构建图并添加边from langgraph.graph import StateGraph, START workflow StateGraph(State) # 添加节点 workflow.add_node(compliance_check, compliance_check_node) workflow.add_node(legal_review, legal_review_node) workflow.add_node(request_revision, lambda state: {messages: state[messages] [{role: assistant, content: 请根据合规意见修改合同。}]}) # 设置入口 workflow.add_edge(START, compliance_check) # 添加条件边根据合规结果路由 def route_after_compliance(state: State): if state[compliance_status] compliant: return legal_review else: return request_revision workflow.add_conditional_edges( compliance_check, route_after_compliance, {legal_review: legal_review, request_revision: request_revision} ) # 法务审核后直接结束简化 workflow.add_edge(legal_review, END) workflow.add_edge(request_revision, END) # 用户修改后理论上应重新进入流程这里简化为结束 # 编译图 app workflow.compile()执行与检查# 初始化状态 initial_state {contract_text: 这是一份包含风险条款的合同..., messages: [], current_step: start} # 执行图 final_state app.invoke(initial_state) print(final_state[current_step], final_state[messages])这个例子展示了LangGraph如何清晰地将复杂的、带有分支的业务流程可视化为一幅图。add_conditional_edges是灵魂所在它让基于状态的动态路由变得异常简单。3.3 高级特性并行、中断与持久化并行执行graph_node装饰器与CONCURRENT对于彼此独立的任务LangGraph支持并发执行。你可以将多个节点标记为并发它们会同时接收相同的State执行后各自返回更新LangGraph会将这些更新安全地合并。这在需要同时查询多个数据源或执行多个计算时非常高效。中断与人工介入Interrupt这是LangGraph用于实现“人工在环”Human-in-the-loop的关键机制。你可以在图中预定义一些“中断点”。当执行到这些节点时图会暂停并返回当前状态和一个标识符。你的外部系统如一个Web界面可以展示信息给用户等待用户输入或决策然后将结果和标识符一起传回让图从断点处继续执行。这对于需要人工审核、确认的严肃业务流程至关重要。状态持久化Checkpointer对于长时间运行或可能失败的工作流状态持久化是必须的。LangGraph提供了Checkpointer抽象可以将图的状态保存到数据库或文件中。当应用重启或从故障中恢复时可以从检查点Checkpoint加载状态并继续执行而不是从头开始。这对于处理耗时数小时的文档处理流水线来说是可靠性的保障。4. 内部组件协作与选型实战指南理解了各自的结构我们来看看它们如何协作以及在具体场景下如何选型。4.1 协作模式LangGraph作为“超级协调器”一种强大且常见的模式是在LangGraph的节点内部使用LangChain的组件来执行具体任务。LangGraph负责宏观的、状态驱动的流程控制而LangChain负责微观的、功能性的单元操作。例如在一个智能研究助手的图中检索节点内部使用LangChain的RetrievalChain从知识库获取相关资料将结果写入State的documents字段。分析节点读取State中的documents使用LangChain的LLMChain配合一个复杂的分析Prompt生成初步报告写入State的draft_report。验证节点调用一个LangChainAgent该Agent拥有“联网搜索”和“事实核查”工具对draft_report中的关键陈述进行验证将验证结果和修正建议更新到State。编排逻辑由LangGraph的边来控制比如如果验证节点发现太多错误则路由回“分析节点”重新生成如果验证通过则进入“格式化节点”。这样LangChain提供了强大的、经过验证的“战术武器库”而LangGraph则提供了灵活、可靠的“战略指挥系统”。4.2 选型决策树何时用Chain何时必须上Graph不要为了用新技术而用新技术。根据你的需求复杂度来选择选择 LangChainChain/Agent 当你的工作流是线性或简单循环的。例如问答检索-生成、文本总结、简单数据提取。你需要快速原型验证LangChain大量的集成和模板能让你“开箱即用”。任务逻辑简单用SequentialChain或一个Agent就能清晰表达。你不需要复杂的状态管理或持久化。选择 LangGraph 当你的工作流包含复杂分支和条件路由。例如多轮审批、诊断系统是/否问题树、游戏剧情引擎。你需要并行执行多个独立任务以提升效率。流程中需要**“人工在环”**进行审核、确认或输入。工作流耗时很长或可能中断需要状态持久化和从检查点恢复的能力。你希望将业务流程清晰地可视化为一幅图便于设计、沟通和调试。一个简单的判断方法如果你发现你在用一个Agent的tool_calls里嵌套另一个Agent或者用复杂的if-else和状态变量来控制一个Chain的执行流那么你很可能已经走到了需要LangGraph的境地。4.3 性能与调试心法性能LangChain注意链的冗余调用。一个常见的低效模式是在链的每个步骤都重复检索相同的内容。合理设计Chain的输入输出利用TransformChain进行预处理避免不必要的LLM或检索调用。LangGraph图的编译compile是一次性开销。执行时每个节点调用都有开销。对于高性能场景要审视图中节点的粒度避免过多细小的节点。对于State只存储和传递必要的数据过大的State会影响序列化和传递效率。调试LangChain充分利用langchain.debug True模式它会打印出每个步骤的输入输出是追踪Prompt构造和结果解析问题的利器。对于Agent观察其intermediate_steps输出看它的“思考过程”是否合理。LangGraph这是LangGraph的一大优势。编译后的图对象有一个get_graph()方法可以输出Mermaid图表或可视化文件让你直观地看到整个流程。在执行时通过stream模式或检查返回的State可以清晰地看到执行路径和每个节点对State的修改。Interrupt机制本身也是一个强大的调试工具让你能在任意节点暂停并检查状态。从LangChain到LangGraph代表了AI应用开发从“组装线性管道”到“编排动态网络”的范式升级。LangChain以其丰富的组件生态和低门槛的链式抽象成为了入门和构建简单应用的首选。而当你面对真实世界中那些错综复杂、充满不确定性的业务流程时LangGraph提供的基于状态和图的编程模型提供了更强的表达力、控制力和可维护性。掌握两者的核心设计理解其组件如何各司其职又协同工作你就能像一位熟练的架构师根据不同的战场地形灵活选用最合适的武器与战术构建出真正 robust 且智能的应用系统。