LangGraph 中断、工具调用与部署从 Human-in-the-loop 到 Agent 工程落地前面几篇已经整理了 LangGraph 的基础、控制流、持久化与记忆管理。这一篇继续往工程实践走重点看三个非常实用的能力中断让图暂停等待人工输入或审批 工具调用让模型调用外部函数或服务 部署把本地图运行成可调试、可访问的 Agent 服务这三个能力结合起来LangGraph 就不只是“本地跑一个流程”而是可以做更接近真实业务的 Agent 系统。一、为什么需要中断在很多 Agent 场景里图不能一直自动跑到底。比如模型生成了操作计划需要人工确认工具调用前需要用户批准Agent 写好了内容需要用户审核修改工作流跑到关键步骤需要人工补充信息某个高风险动作比如删除文件、发邮件、提交订单需要确认这类场景就叫Human-in-the-loop人在回路中LangGraph 的中断机制就是为这种场景准备的。二、动态中断 interrupt()动态中断是指图运行到某个节点内部时代码主动调用interrupt()让图暂停。可以理解成节点执行到这里先别继续了等人给一个输入。基础形式大概是fromlanggraph.typesimportinterrupt,Commanddefreview_node(state):user_feedbackinterrupt({question:是否批准继续执行,content:state[draft]})return{feedback:user_feedback}执行到interrupt()时图会暂停并把中断信息返回给外部。外部拿到用户输入后再用Command(resume...)恢复。三、恢复中断Command(resume…)恢复中断时通常会重新调用图并传入Command(resume用户输入)比如graph.invoke(Command(resume同意继续),configconfig)这里的意思是把“同意继续”作为 interrupt() 的返回值继续执行原来的节点。所以中断和恢复可以这样理解interrupt()暂停并向外要数据 Command(resume...)把外部数据送回来让图继续执行四、基础 HITL 模式基础 Human-in-the-loop 流程一般是节点生成内容 ↓ interrupt 暂停等待人工确认 ↓ 用户输入确认结果 ↓ Command(resume...) 恢复 ↓ 节点继续执行适合内容审核审批确认人工补充信息任务执行前确认可以记住一句话interrupt 不是报错而是一次有意识的暂停。五、多个并行中断如果图里有多个并行节点它们都可能触发中断。比如node_a 需要人工确认 node_b 也需要人工确认这时可能会产生多个 interrupt。恢复时通常需要构建中断 ID - 恢复值也就是给不同中断分别提供不同答案。可以理解成多个暂停点就要分别告诉每个暂停点怎么继续。六、审批模式审批模式是中断机制最常见的用法。流程一般是Agent 生成计划 ↓ interrupt 等待审批 ↓ 如果批准继续执行 如果拒绝终止或改走其他节点比如decisioninterrupt({type:approval,message:是否允许执行工具调用})ifdecisionapprove:return{approved:True}else:return{approved:False}这种模式适合高风险动作发邮件执行 SQL删除数据调用付费接口提交订单七、审核与编辑模式有时候用户不是简单同意或拒绝而是想改一下内容。比如模型生成了一段文案请审核并修改这段内容。用户可以返回修改后的文本。流程就是模型生成 draft ↓ interrupt 把 draft 给用户 ↓ 用户修改 ↓ resume 返回修改后的内容 ↓ 后续节点使用修改版内容这适合博客草稿审核合同条款修改邮件发送前编辑报告内容确认八、工具执行审批模式工具调用前审批是 Agent 系统里很重要的安全设计。比如模型想调用工具delete_file(pathxxx)不能直接执行应该先中断模型请求工具调用 ↓ interrupt 请求用户批准 ↓ 批准后执行工具 ↓ 拒绝则返回拒绝信息或终止这类模式可以避免 Agent 擅自执行危险操作。九、单节点串行中断一个节点内部也可以多次调用interrupt()。比如先问姓名 再问年龄 再问是否确认这种叫单节点串行中断。但是要注意同一个节点内的interrupt()调用顺序非常重要。恢复时LangGraph 会按照原来的调用顺序匹配中断。所以不要随便改变节点内部interrupt()的顺序。十、interrupt 使用规范1. 不要用 try/except 包裹 interrupt()interrupt()本身依赖特殊的中断机制不是普通业务异常。如果用try/except把它捕获了可能导致中断机制失效。不推荐try:valueinterrupt(请输入内容)exceptException:...2. 不要更改单节点内 interrupt 顺序比如原来是nameinterrupt(请输入姓名)ageinterrupt(请输入年龄)后面不要随便改成ageinterrupt(请输入年龄)nameinterrupt(请输入姓名)否则恢复时可能对不上。3. 不要传递复杂类型interrupt()中传递的数据尽量简单比如字符串数字布尔值简单字典简单列表不要传复杂对象、函数、数据库连接等。4. 中断前的副作用要幂等副作用指写数据库发请求发邮件创建文件扣费如果节点在中断前做了副作用操作恢复时可能会重新执行这段逻辑。所以中断前的副作用最好是幂等的。幂等就是执行一次和执行多次结果一致。十一、静态断点除了在代码里主动interrupt()LangGraph 还支持静态断点。静态断点更像调试器里的断点。你可以在编译时设置graphbuilder.compile(checkpointercheckpointer,interrupt_before[node_a])意思是执行 node_a 之前暂停。也可以设置interrupt_after[node_a]意思是执行 node_a 之后暂停。静态断点适合调试不一定需要写进业务节点代码。十二、动态中断和静态断点的区别对比点动态中断interrupt()静态断点位置写在节点代码内部编译或调用时配置目的业务暂停等待人工输入调试暂停是否需要节点代码配合需要不一定常见场景审批、编辑、人工确认本地调试、观察状态简单记业务中断用 interrupt() 调试断点用 interrupt_before / interrupt_after十三、本地部署并对接 LangSmithLangGraph 项目可以本地部署成 Agent Server并对接 LangSmith 做调试和追踪。常见流程是准备项目结构 编写图代码 配置 langgraph.json 启动本地服务 在 LangSmith / Studio 中调试典型项目结构project/ agent.py langgraph.json .env requirements.txtlanggraph.json一般用来声明图入口。示意{graphs:{agent:./agent.py:graph}}意思是agent 这张图来自 agent.py 文件里的 graph 对象。十四、启动本地服务安装相关依赖后可以用 LangGraph CLI 启动本地服务。常见命令类似langgraph dev启动后本地会运行一个 Agent Server。这样你就可以通过接口、Studio 或前端 UI 去调用这张图。十五、对接 AgentChatUIAgentChatUI 是一个聊天前端用来和 LangGraph Agent Server 交互。整体流程LangGraph 图代码 ↓ langgraph dev 启动服务 ↓ AgentChatUI 连接服务地址 ↓ 在网页里聊天、触发工具、查看历史适合测试多轮对话工具调用历史记录中断恢复Agent UI 体验十六、工具调用节点手动处理工具调用工具调用是 Agent 的核心能力。最基础的做法是手动处理tool_calls。流程一般是llm_node 调用绑定工具的模型 ↓ 模型返回 tool_calls ↓ tool_node 读取 tool_calls ↓ 根据工具名执行对应工具 ↓ 把结果包装成 ToolMessage ↓ 返回给 LLM 继续推理手动处理的优点是灵活。比如可以自己控制哪些工具允许执行工具失败怎么处理是否需要人工审批工具结果怎么包装是否记录日志缺点是代码更繁琐。十七、ToolNode自动处理工具调用LangGraph 提供了ToolNode可以帮你自动执行工具调用。大概用法fromlanggraph.prebuiltimportToolNode tools[get_weather,get_news]tool_nodeToolNode(tools)然后注册builder.add_node(tools,tool_node)当模型返回tool_calls后ToolNode会根据工具名自动调用对应工具并返回ToolMessage。适合标准工具调用场景。如果你不需要特别复杂的审批、缓存、异常处理ToolNode会比手写tool_node简洁很多。十八、手动工具节点和 ToolNode 的区别对比点手动 tool_nodeToolNode灵活性高中等代码量多少审批逻辑好插入需要额外设计错误处理完全自定义框架默认处理为主适合场景复杂业务工具流标准工具调用可以这样选学习阶段先手写理解原理 项目常规工具调用用 ToolNode 复杂审批/安全控制手写或封装自己的 ToolNode十九、ToolRuntime 是什么ToolRuntime可以让工具在执行时访问更多运行时信息。比如当前状态上下文配置信息存储器这意味着工具不只是“输入参数 - 返回字符串”还可以参与更复杂的图状态管理。比如工具可以读取当前用户根据 user_id 查询数据库或者结合上下文VIP 用户返回更详细结果二十、在工具中更新状态有些工具不只是返回结果还希望更新图状态。比如查询天气工具执行后把 weather 字段写入 State或者搜索工具执行后把 documents 写入 State这种场景下工具就不只是“给模型一个观察结果”还会影响后续节点的状态。实际开发时要注意工具更新状态时要清楚这个字段由谁写、谁读、是否需要 Reducer。二十一、工具节点容错重试机制工具调用经常会失败比如网络波动API 限流第三方服务超时工具参数错误可以给工具节点增加重试机制。思路是工具失败 ↓ 判断是否是可重试错误 ↓ 等待一段时间 ↓ 重新调用 ↓ 超过最大次数后返回失败信息适合重试的错误网络超时临时服务不可用限流后稍等可恢复不适合重试的错误参数格式错误工具名称错误权限不足明确的业务拒绝二十二、工具节点缓存工具缓存可以减少重复调用。适合天气查询新闻查询文档解析搜索结果用户资料查询比如同一个问题短时间重复问北京今天天气怎么样不一定每次都要重新调 API可以先查缓存。缓存时要考虑两个点缓存 key什么输入算同一次请求 ttl缓存多久过期二十三、中断 工具调用的组合真正项目里中断和工具调用经常一起用。比如模型决定要调用 send_email 工具 ↓ 工具执行前 interrupt请用户审批 ↓ 用户同意 ↓ 执行 send_email ↓ 返回 ToolMessage ↓ 模型总结执行结果这就是一个更安全的 Agent 工具调用流程。对于危险工具可以加审批。对于普通工具可以直接执行。二十四、学习时最容易混的点1. interrupt 不是异常它是 LangGraph 的中断机制不是普通raise Exception。所以不要用普通异常思维理解它。2. resume 是把值送回 interruptCommand(resume同意)这个同意会成为之前interrupt()的返回值。3. 静态断点更适合调试如果只是想观察节点前后的状态用静态断点。如果业务上需要用户输入用动态中断。4. ToolNode 是标准工具执行器简单工具调用可以用ToolNode。但如果你要审批、复杂容错、状态更新可能要手写工具节点。5. 工具调用后通常要回到 LLM工具只是返回观察结果。最终答案通常还是由 LLM 结合工具结果生成。所以典型流程是LLM - Tool - LLM总结这篇主要整理了 LangGraph 里更偏工程实践的部分动态中断 interrupt() 恢复中断 Command(resume...) 审批模式 审核与编辑模式 工具执行审批 静态断点 本地部署 AgentChatUI 对接 手动工具节点 ToolNode ToolRuntime 工具状态更新 工具重试与缓存可以用一句话串起来中断让 Agent 能等人工具让 Agent 能做事部署让 Agent 能真正被调用。学到这里LangGraph 就已经从“流程编排框架”进入了“Agent 工程框架”的范围。后面真正做项目时重点就是把检查点、记忆、中断、工具调用和部署组合起来做出稳定、可控、可恢复的 Agent 应用。