ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

LangGraph框架深度解析:构建有状态多环节Agent应用的核心原理与实践

LangGraph框架深度解析:构建有状态多环节Agent应用的核心原理与实践 1. 项目概述为什么我们需要 LangGraph如果你最近在折腾大模型应用尤其是想搞点能自主决策、能串联多个步骤的智能体Agent那你大概率已经听过 LangChain 的大名也可能被它早期版本里那些略显繁琐的 Agent 实现方式搞得有点头疼。任务一复杂状态管理、循环控制、错误处理这些脏活累活就全冒出来了代码写着写着就成了“面条”。这正是 LangGraph 诞生的背景它不是来取代 LangChain 的而是 LangChain 官方推出的一个专门用于构建有状态、多环节的 Agent 应用的新框架。你可以把它理解为给 Agent 开发装上了一套精密的“流程引擎”和“中央控制器”。这一卷我们要聊的就是如何从“会用 Agent”到“能设计并实现一个健壮的 Agent 系统”。LangGraph 的核心思想很直观把你的 Agent 工作流建模成一个图Graph。图中的节点Node是一个个执行单元比如调用一次大模型、执行一个工具函数、做一个条件判断边Edge则定义了节点之间的流转逻辑。这听起来是不是有点像画流程图没错它的设计哲学就是让复杂的工作流变得可视、可控、可调试。我们将彻底拆解这个框架不光是讲怎么调用 API更要弄明白它背后的设计理念、解决的核心痛点以及在实际项目中如何避开那些新手常踩的“坑”。2. LangGraph 核心概念与设计哲学拆解在一头扎进代码之前我们必须先理解 LangGraph 的几个基石性概念。这能帮助我们在设计工作流时做出更合理的选择。2.1 状态管理一切的中心LangGraph 的核心是一个持续更新的状态State对象。这个状态对象在图的整个执行生命周期中流转每个节点读取它、修改它并决定下一步去哪里。这解决了传统链式调用中状态传递混乱的问题。状态的定义通常我们会用一个 Pydantic 的BaseModel来定义状态明确其中每个字段的类型和含义。例如一个简单的问答 Agent 状态可能包含from typing import List, Annotated from typing_extensions import TypedDict import operator class AgentState(TypedDict): question: str # 用户输入的问题 context: List[str] # 检索到的相关文档片段 reasoning: str # 模型的思考链 answer: str # 最终生成的答案 iterations: Annotated[int, operator.add] # 已执行的循环次数注意iterations字段的Annotated[int, operator.add]注解这是 LangGraph 的一个精妙设计。它声明这个字段是一个“可归约的”reducible值。当多个节点并发修改它时比如两个并行工具调用都增加了迭代次数LangGraph 知道应该用operator.add这个函数来合并归约这些修改而不是简单地覆盖。这对于计数、收集列表等场景至关重要。状态更新的机制LangGraph 采用了函数式编程中“更新器”updater的概念。节点函数不直接修改传入的状态对象而是返回一个字典其中包含要更新的字段和值。框架会自动将这些更新应用到全局状态上。这种方式保证了状态变更的可预测性和可追溯性。2.2 节点与边构建工作流的积木节点Node是工作流的基本执行单元。一个节点就是一个普通的 Python 函数或可调用对象它接收当前状态作为参数并返回对状态的更新。一个节点可以做的事情非常灵活调用一个大模型。执行一个预定义的工具如网络搜索、数据库查询。运行一段业务逻辑代码。只是一个简单的条件判断或计算。边Edge定义了工作流的控制逻辑。它决定了在当前节点执行完毕后下一步应该去哪个节点。LangGraph 提供了几种类型的边起始边Start Edge定义工作流从哪个节点开始。条件边Conditional Edge根据当前状态的某些值动态决定下一个节点。这是实现分支和循环的关键。普通边Normal Edge无条件地指向下一个节点。通过组合节点和边你可以构建出顺序、分支、循环乃至更复杂的拓扑结构比如支持自我修正的 Agent或者需要多轮工具调用的复杂任务规划器。2.3 图编译与执行从定义到运行定义好节点和边之后你需要创建一个StateGraph对象将节点和边添加进去最后调用compile()方法。这个编译过程会进行验证并生成一个可执行的、优化的计算图。编译后的图对象有一个invoke(input_state)方法这是启动工作流的入口。编译时优化compile()方法不只是做个简单的打包。它会检查图的连通性优化执行路径并为可视化做好准备。编译后的图对象还包含了所有必要的元信息使得序列化、持久化和在不同环境间迁移成为可能。执行模式invoke是同步执行。对于长时间运行的任务LangGraph 还支持异步执行ainvoke以及流式响应stream后者可以让你实时看到每个节点执行后的状态快照对于调试和构建交互式 UI 体验非常有用。3. 核心组件深度解析与实操要点理解了基本概念我们来深入看看构成 LangGraph 工作流的几个关键部分以及在实际编码时需要注意什么。3.1 状态模式设计TypedDict vs BaseModel如上所述定义状态有两种主流方式使用typing.TypedDict或pydantic.BaseModel。它们各有优劣TypedDict更轻量是 Python 的类型提示标准库的一部分无需额外依赖。它在运行时没有验证性能开销极小。适合状态结构简单、确定且你信任各个节点会正确更新字段的场景。from typing import TypedDict, List class SimpleState(TypedDict): messages: List[dict] step: intPydantic BaseModel功能强大提供运行时数据验证、序列化/反序列化如 JSON、以及更丰富的字段类型如自定义校验器。这能极大增强工作流的健壮性在节点返回意外数据时能尽早报错而不是让错误状态流传下去。from pydantic import BaseModel, Field, validator from typing import List class RobustState(BaseModel): messages: List[dict] Field(default_factorylist) step: int Field(ge0, descriptionNon-negative step counter) validator(messages) def messages_must_have_role(cls, v): for msg in v: if role not in msg or content not in msg: raise ValueError(Message must have role and content) return v实操心得在项目初期快速原型阶段可以使用TypedDict。一旦工作流逻辑稳定尤其是需要与外部系统如数据库、API交换数据时强烈建议切换到 Pydantic BaseModel。它带来的验证和文档化收益远超一点点性能开销能避免很多隐蔽的 bug。3.2 条件边与路由逻辑实现智能决策条件边是让 Agent 拥有“判断力”的核心。它通常与一个“路由函数”Router配合使用。这个函数查看当前状态返回下一个要执行的节点的名称。from langgraph.graph import StateGraph, END import operator class State(TypedDict): question: str analysis: str needs_search: bool answer: str def agent_node(state: State): # 模拟大模型分析问题 if 天气 in state[question]: return {analysis: 这是一个天气查询问题, needs_search: True} else: return {analysis: 这是一个通用知识问题, needs_search: False, answer: 我可以直接回答。} def search_node(state: State): # 模拟搜索工具 return {answer: f根据搜索{state[question]}的答案是晴天。} def route_after_analysis(state: State): # 路由函数根据 needs_search 字段决定下一步 if state.get(needs_search): return search_tool else: return END # 直接结束 # 构建图 graph StateGraph(State) graph.add_node(analyze, agent_node) graph.add_node(search_tool, search_node) graph.add_edge(analyze, route_after_analysis) # 将路由函数作为边 graph.add_edge(search_tool, END) graph.set_entry_point(analyze) app graph.compile()注意事项路由函数应该保持纯净只读状态不修改状态。它的唯一职责就是根据当前状态做决策。复杂的业务逻辑应该放在节点里。此外确保路由函数返回的节点名称一定是你已经在图中添加过的否则会在编译或运行时出错。3.3 工具集成与结构化输出扩展 Agent 能力单独的 LLM 能力有限Agent 的强大在于能使用工具。LangGraph 与 LangChain 的工具生态无缝集成。集成 LangChain Toolsfrom langchain.tools import TavilySearchResults from langgraph.prebuilt import ToolNode # 创建工具 search_tool TavilySearchResults(max_results2) # 创建工具节点可以绑定多个工具 tool_node ToolNode(tools[search_tool]) # 将 tool_node 添加到你的图中 graph.add_node(web_search, tool_node)ToolNode是一个 LangGraph 预置的节点它能自动处理工具调用格式读取状态中类似{tools: [...], tool_calls: [...]}的结构执行对应的工具并将结果以标准化格式写回状态。处理结构化输出很多时候我们需要模型输出结构化的数据如 JSON以便后续节点处理。这通常需要配合 Pydantic 和 LangChain 的with_structured_output方法。在 LangGraph 中你可以创建一个专门的“结构化解析节点”from langchain_core.pydantic_v1 import BaseModel, Field from langchain_openai import ChatOpenAI class Decision(BaseModel): reasoning: str Field(description思考过程) next_step: str Field(description下一步动作, enum[search, answer, clarify]) llm ChatOpenAI(modelgpt-4) structured_llm llm.with_structured_output(Decision) def decision_node(state: State): # 假设 state[‘messages’] 包含对话历史 decision structured_llm.invoke(state[messages]) # 将结构化的决策结果更新到状态 return {decision: decision.dict()}这样decision_node的输出就是一个清晰的Decision对象后续的路由函数可以直接根据state[‘decision’][‘next_step’]来做出判断代码非常清晰。4. 构建一个具备自我修正能力的问答 Agent完整实操让我们综合以上知识构建一个相对复杂的 Agent。这个 Agent 能回答问题如果对自己生成的答案信心不足它会主动调用搜索工具获取信息然后重新生成答案最多尝试两次。4.1 步骤一定义状态与工具首先我们定义工作流的状态。它需要记录问题、对话历史、模型生成的答案、置信度、检索到的上下文以及重试次数。from typing import TypedDict, List, Optional, Literal from typing_extensions import Annotated import operator class SelfCorrectingState(TypedDict): 自我修正Agent的状态定义 question: str # 用户原始问题 messages: Annotated[List[dict], operator.add] # 对话历史使用归约操作符 initial_answer: Optional[str] # 模型首次生成的答案 confidence: Optional[float] # 模型对答案的置信度 (0-1) search_context: Optional[List[str]] # 搜索工具返回的上下文 final_answer: Optional[str] # 最终答案 attempt: Annotated[int, operator.add] # 尝试次数计数器 phase: Literal[initial_answer, check_confidence, search, synthesize, done] # 当前阶段我们使用Literal来定义phase字段这将在路由逻辑中发挥巨大作用。Annotated用于messages和attempt确保在并发或循环场景下更新正确。接着准备工具。这里我们使用一个模拟的搜索工具和一个置信度评估工具。# 模拟一个网络搜索工具 def web_search_tool(query: str) - List[str]: print(f[工具调用] 搜索查询: {query}) # 模拟返回一些“搜到”的文档片段 return [ f关于‘{query}’的权威资料片段A。, f根据最新研究‘{query}’的相关信息B。 ] # 模拟一个置信度评估工具实际中可能用另一个LLM调用来实现 def evaluate_confidence(answer: str, question: str) - float: 简单模拟置信度评估。实际项目需要更复杂的逻辑。 keywords [可能, 也许, 据我所知, 不确定] if any(kw in answer for kw in keywords): return 0.3 # 低置信度 elif len(answer) 10: return 0.5 # 中等置信度 else: return 0.8 # 高置信度4.2 步骤二实现各个功能节点我们将工作流分解为以下几个节点生成初始答案节点调用 LLM 直接回答问题。评估置信度节点评估初始答案的置信度。搜索节点如果置信度低调用搜索工具。综合生成节点结合搜索上下文重新生成最终答案。完成节点整理最终输出。from langchain_openai import ChatOpenAI llm ChatOpenAI(modelgpt-3.5-turbo) def generate_initial_answer_node(state: SelfCorrectingState): 节点1生成初始答案 print(f[节点1] 正在生成初始答案...) # 构建给LLM的提示 prompt f请直接回答以下问题{state[question]}。请给出简洁明确的答案。 response llm.invoke(prompt) initial_answer response.content # 更新状态 new_messages [{role: assistant, content: f初始答案: {initial_answer}}] return { initial_answer: initial_answer, messages: new_messages, phase: check_confidence # 进入下一阶段 } def check_confidence_node(state: SelfCorrectingState): 节点2评估答案置信度 print(f[节点2] 正在评估答案置信度...) confidence evaluate_confidence(state[initial_answer], state[question]) print(f 置信度评分: {confidence}) next_phase search if confidence 0.6 else synthesize return { confidence: confidence, phase: next_phase # 根据置信度决定下一阶段 } def search_node(state: SelfCorrectingState): 节点3执行搜索 print(f[节点3] 置信度不足正在搜索更多信息...) search_results web_search_tool(state[question]) return { search_context: search_results, phase: synthesize # 搜索完成后进入综合阶段 } def synthesize_final_answer_node(state: SelfCorrectingState): 节点4综合信息生成最终答案 print(f[节点4] 正在生成最终答案...) attempt state.get(attempt, 0) 1 base_info f用户问题{state[question]}\n if state.get(search_context): # 如果有搜索上下文结合上下文生成 context_str \n.join(state[search_context]) prompt f{base_info}参考以下信息\n{context_str}\n请生成一个准确、全面的最终答案。 else: # 如果置信度高直接优化初始答案 prompt f{base_info}基于以下初始回答{state[initial_answer]}请将其润色为更完整、专业的最终答案。 response llm.invoke(prompt) final_answer response.content new_messages [{role: assistant, content: f最终答案 (尝试{attempt}): {final_answer}}] return { final_answer: final_answer, messages: new_messages, attempt: 1, # 增加尝试计数 phase: done } def finalize_node(state: SelfCorrectingState): 节点5完成处理整理输出 print(f[节点5] 流程结束。) # 这里可以做一些清理或格式化工作比如确保final_answer不为空 if not state.get(final_answer): return {final_answer: state.get(initial_answer, 未能生成答案。)} # 状态已更新无需返回新内容也可 return {}4.3 步骤三构建图并定义路由逻辑现在我们将节点组装起来并定义它们之间的流转逻辑。from langgraph.graph import StateGraph, END # 1. 创建图 workflow StateGraph(SelfCorrectingState) # 2. 添加所有节点 workflow.add_node(generate, generate_initial_answer_node) workflow.add_node(check_conf, check_confidence_node) workflow.add_node(search, search_node) workflow.add_node(synthesize, synthesize_final_answer_node) workflow.add_node(finalize, finalize_node) # 3. 设置入口点 workflow.set_entry_point(generate) # 4. 添加边包括条件边 workflow.add_edge(generate, check_conf) # 生成答案后必然去检查置信度 # 从 check_conf 出来的条件路由 def route_after_check(state: SelfCorrectingState): if state[phase] search: return search else: # phase synthesize return synthesize workflow.add_conditional_edges( check_conf, route_after_check, {search: search, synthesize: synthesize} ) # 搜索完成后去综合 workflow.add_edge(search, synthesize) # 综合完成后去最终化 workflow.add_edge(synthesize, finalize) # 最终化后结束 workflow.add_edge(finalize, END) # 5. 编译图 app workflow.compile()4.4 步骤四执行与验证让我们用两个不同的问题来测试这个 Agent。# 测试1一个可能置信度较低的问题 print( 测试1: 复杂问题 ) state_input1 {question: 量子计算的主要技术挑战是什么, messages: [], attempt: 0, phase: initial_answer} result1 app.invoke(state_input1) print(f\n最终答案{result1[final_answer][:200]}...) # 截断显示 print(f总尝试次数{result1[attempt]}) # 测试2一个简单直接的问题 print(\n\n 测试2: 简单问题 ) state_input2 {question: 法国的首都是哪里, messages: [], attempt: 0, phase: initial_answer} result2 app.invoke(state_input2) print(f\n最终答案{result2[final_answer]}) print(f总尝试次数{result2[attempt]})执行上述代码你会在控制台看到工作流一步步执行的日志。对于第一个复杂问题由于模拟的置信度评估较低答案中可能包含“可能”等词Agent 会走generate - check_conf - search - synthesize - finalize的路径。对于第二个简单问题置信度评估较高则会走generate - check_conf - synthesize - finalize的路径跳过了搜索环节。这个例子展示了 LangGraph 如何清晰地管理一个包含条件判断和循环通过attempt计数可以扩展为重试逻辑的复杂工作流。所有的状态流转和业务逻辑都通过图和节点直观地表达了出来。5. 高级特性与生产级考量当你掌握了基础构建方法后以下这些高级特性和考量能帮助你将 LangGraph 应用到更严肃的生产环境中。5.1 持久化检查点与人类干预LangGraph 支持**检查点Checkpoint**机制这可以说是其最强大的特性之一。它允许你将工作流的完整状态包括所有变量、执行历史保存下来之后可以从这个精确的点恢复执行。这对于以下场景至关重要长时间运行的任务任务可以暂停、恢复甚至迁移到另一台服务器。等待人工审核/输入Agent 可以在某个节点暂停生成一个待办事项发送给人类等人类回复后再继续。错误恢复与重试如果某个节点因临时错误失败可以从上一个检查点重试而不是从头开始。使用检查点通常需要配置一个持久化存储后端如内存、数据库、Redis。LangGraph 提供了接口你需要实现CheckpointSaver逻辑。from langgraph.checkpoint import MemorySaver from langgraph.graph import StateGraph # 使用内存存储检查点生产环境应用数据库 memory MemorySaver() workflow StateGraph(..., checkpointermemory) # 在调用时可以指定一个线程IDthread_id来关联同一会话 config {configurable: {thread_id: user_123_session_1}} # 首次调用会创建检查点 result1 app.invoke({question: ...}, configconfig) # 假设在这里任务被暂停了... # 之后可以从同一个thread_id恢复并传入新的输入或继续执行 # 例如模拟人类输入后继续 result2 app.invoke({human_feedback: 请再解释一下第一步。}, configconfig)通过检查点你可以构建出真正能与人类协作、支持断点续传的复杂 Agent 应用。5.2 子图与模块化设计对于非常复杂的工作流你可以使用子图Subgraph来模块化你的设计。子图允许你将一个完整的图作为一个节点嵌入到另一个更大的图中。这带来了几个好处代码复用将通用的功能如“检索增强生成RAG模块”、“代码审查模块”封装成子图在不同主图中重复使用。逻辑清晰将大问题分解为小问题每个子图负责一个相对独立的子任务。简化主图主图只需要关注高层的流程控制细节隐藏在子图中。创建与使用子图from langgraph.graph import StateGraph # 1. 定义一个子图例如一个专门的RAG检索子图 def build_rag_subgraph(): rag_graph StateGraph(...) # ... 添加检索、重排、生成等节点 rag_graph.add_node(...) rag_graph.add_edge(...) return rag_graph.compile() # 2. 在主图中将这个编译好的子图作为一个节点添加 main_graph StateGraph(...) rag_app build_rag_subgraph() main_graph.add_node(rag_module, rag_app) # 将子图作为节点添加 # 在主图的其他节点中可以调用这个子图节点它会接收和返回符合子图状态定义的数据。5.3 并发执行与优化LangGraph 支持在条件允许的情况下并发执行多个节点。这通过State定义中的Annotated归约操作符来实现。当框架检测到两个节点不依赖于对方的输出即它们修改的状态字段是独立的它可能会尝试并发执行它们以提升效率。设计并发友好的状态为了最大化并发潜力在设计状态 Schema 时尽量让不同的任务修改不同的字段。例如一个节点负责更新search_results另一个节点负责更新user_profile它们之间没有依赖就可以并发。注意事项并发不是银弹。如果节点之间有严格的先后顺序依赖比如必须先检索才能生成强行并发会导致错误。你需要仔细设计工作流的依赖关系。可视化工具后面会提到可以帮助你分析节点间的依赖。5.4 监控、日志与可视化在生产环境中对 Agent 工作流进行监控和调试是必须的。结构化日志在每个节点的函数中使用结构化的日志记录如 Python 的logging模块并输出 JSON 格式。记录关键信息如节点开始/结束时间、输入状态摘要、输出状态摘要、工具调用详情、LLM 的请求与响应注意脱敏等。这有助于后续的问题追踪和性能分析。LangGraph 可视化编译后的图对象有一个get_graph()方法可以输出图的 Mermaid 格式定义。你可以将其复制到 Mermaid Live Editor 中立即生成可视化的流程图。这是理解和沟通工作流设计的绝佳工具。# 生成图的Mermaid文本表示 graph_diagram app.get_graph().draw_mermaid() print(graph_diagram)将输出的文本粘贴到支持 Mermaid 的 Markdown 编辑器或在线工具中就能看到一张清晰的工作流图。追踪与可观测性考虑集成像 LangSmith 这样的 LLM 应用追踪平台。LangSmith 与 LangGraph 有很好的集成可以记录每一次invoke的完整执行轨迹包括每个节点的输入输出、耗时、LLM 调用成本等是进行调试、优化和评估的利器。6. 常见问题、调试技巧与避坑指南在实际开发中你一定会遇到各种问题。下面是一些常见坑点和解决思路。6.1 状态更新不生效或覆盖问题现象节点返回了更新字典但状态没有变化或者后一个节点的更新覆盖了前一个节点的。排查与解决检查状态 Schema 定义确保你返回的字典键名与状态 Schema 中定义的字段名完全一致。Python 是大小写敏感的。理解归约操作符对于使用Annotated声明了归约操作符的字段如列表、计数器节点返回的应该是增量值而不是完整值。例如对于Annotated[List, operator.add]你应该返回{messages: [new_message]}而不是{messages: all_messages}。框架会自动帮你合并。检查节点执行顺序如果两个节点并发执行且修改了同一个非归约字段后完成的一个会覆盖前一个。你需要通过设计工作流如添加边来避免这种竞争条件或者将该字段改为归约字段如果业务逻辑允许。6.2 条件边路由错误或进入死循环问题现象工作流没有按预期分支或者一直在某几个节点间循环无法结束。排查与解决打印调试路由函数在路由函数内部添加print语句输出当前状态的关键字段和它决定返回的节点名称。确保你的逻辑条件 (if/else) 覆盖了所有可能的情况并且最终一定能返回一个有效的节点名或END。检查phase或标志字段像我们例子中使用phase字段来显式控制流程是一个好习惯。确保每个节点在更新状态时都正确设置了下一个phase。避免无限循环对于可能循环的路径比如重试逻辑一定要设置一个“逃生阀”。在我们的例子中attempt计数器可以用于限制重试次数。可以在路由函数中检查if state[‘attempt’] MAX_ATTEMPTS: return “finalize”。使用可视化工具将图可视化检查边的连接是否正确是否存在形成闭环循环但缺少退出条件的情况。6.3 工具调用失败或格式错误问题现象集成 LangChain Tools 时节点报错提示工具调用格式不正确。排查与解决确保状态格式匹配ToolNode期望状态中包含特定的键来获取工具调用指令通常是tools和tool_calls。你需要确保上一个节点通常是 LLM 节点的输出格式符合这个要求。使用bind_tools方法可以帮助 LLM 格式化输出。from langchain_core.messages import HumanMessage llm_with_tools llm.bind_tools([search_tool]) # 当调用 llm_with_tools 时如果模型决定调用工具其返回的消息会包含标准的 tool_calls 结构。检查工具 Schema确保传递给ToolNode的工具列表与 LLM 绑定的工具列表一致。工具名称、描述、参数 Schema 必须匹配否则 LLM 可能生成无法解析的调用。处理工具错误工具执行可能会失败网络超时、API 错误等。考虑在ToolNode外围包裹一层错误处理逻辑或者使用自定义节点来更精细地控制工具调用和错误回退。6.4 性能优化与成本控制问题复杂工作流调用 LLM 次数多响应慢成本高。优化策略缓存对频繁且结果不变的 LLM 调用或工具调用如某些知识查询实施缓存。可以使用langchain.cache或外部缓存如 Redis。精简上下文传递给 LLM 的messages或context要尽可能相关和精简。在 RAG 场景中做好检索结果的重排和过滤只保留最相关的片段。模型选型并非所有节点都需要最强大的模型。对于路由判断、简单分类等任务可以使用更小、更快的模型如gpt-3.5-turbo只在需要深度推理或生成的节点使用大模型如gpt-4。这被称为“混合模型”策略。异步与流式如果前端允许使用astream进行流式响应可以提升用户体验。对于批量处理任务使用异步调用 (ainvoke) 来并发执行多个独立的工作流实例。设置超时与重试为 LLM 调用和工具调用配置合理的超时时间和重试策略避免单个故障阻塞整个工作流。6.5 测试策略测试 Agent 工作流比测试普通函数更复杂因为涉及状态流转和外部调用。单元测试节点函数将每个节点函数当作纯函数尽可能进行测试。使用模拟Mock对象来替代 LLM 和工具调用验证给定输入状态时函数是否返回了预期的状态更新字典。集成测试子图对编译好的子图进行测试使用模拟的 LLM 和工具验证整个子流程的输入输出是否符合预期。端到端测试针对关键用户旅程进行少量的端到端测试使用真实的 LLM 和工具但可能使用沙箱环境或测试密钥确保整个工作流能跑通。这类测试速度慢、成本高应作为验收测试。利用 LangSmithLangSmith 的追踪功能不仅可以用于调试也可以用于测试。你可以录制一次成功的运行轨迹作为“黄金标准”在后续的测试中将新的运行轨迹与它进行对比检查关键节点的输入输出是否有重大偏离。LangGraph 将一个复杂的 Agent 系统设计问题转化为了一个相对直观的“构图”问题。它通过清晰的状态管理和显式的控制流让多步骤、有状态、带条件的 LLM 应用变得可维护、可调试。从简单的线性链到复杂的、带循环和人工干预的工作流它都能提供良好的支持。掌握它的核心概念——状态、节点、边、条件路由并善用检查点、子图等高级特性你就能设计出强大而稳健的智能体应用。
返回列表