ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【LangGraph—4—Workflows+Agents】

【LangGraph—4—Workflows+Agents】 LangGraph 架构模式的「总菜单」——建议按「基础层 → 六大模式 → 两套 API → 下一步」的线索来读。我先给出梳理最后附上一张模式全景图。一句话核心Workflow 预定义代码路径节点与顺序在写代码时就定死Agent 动态自主流程LLM 自己决定调用哪些工具、怎么解决问题在循环中演进。文档里所有模式都是「LLM 增强」的组合区别只在于谁在什么时候做决定。基础层Augmented LLM所有模式的地基是同一个东西——给 LLM 加三件套增强API作用工具调用llm.bind_tools([...])让 LLM 能发起动作结构化输出llm.with_structured_output(Schema)把 LLM 输出锁进 Pydantic 模型供路由/评估/规划使用短时记忆State / MessagesState跨节点传递状态注意文档里一个通用技巧路由、规划、评估全用with_structured_output配合 Pydantic SchemaRoute、Sections、Feedback而不是让 LLM 返回自由文本再去解析——这是 LangGraph 官方强烈推荐的写法。五种 Workflow Agent对照速查模式结构特征典型场景Graph API 关键点Prompt chaining提示链顺序链 门控翻译、内容一致性校验add_conditional_edges做 Pass/Fail 门?“或”!判断笑点Parallelization并行化扇出 → 聚合独立子任务提速多次评分提高置信度多条add_edge(START, n) 一个聚合节点Routing路由分类 → 分支客服问题分流定价/退款/退货with_structured_output(Route)产出决策条件边返回节点名Orchestrator-worker编排-工人规划 → 动态工人 → 综合子任务数量未知如跨多个文件改写SendAPI动态生成 worker共享 key 用Annotated[list, operator.add]Evaluator-optimizer评估-优化生成 ↔ 评估回环有明确标准但需迭代如翻译结构化Feedback 条件边把不合格反馈送回生成器AgentLLM ⇄ 工具循环问题与解法不可预测MessagesStateshould_continue检查tool_calls选型时最关键的区分子任务是否能预先确定。能确定 → Parallelization固定扇出不能确定、由数据驱动 → Orchestrator-workerSend动态扇出。这是文档里特意强调的一点。值得细读的两个技术点SendAPIOrchestrator-worker 的灵魂assign_workers不是返回单个节点名而是返回[Send(llm_call, {section: s}) for s in sections]列表——每个 worker 有自己的独立状态结果都写入共享的completed_sectionsoperator.add保证并行追加不覆盖。ToolNode 与 ToolRuntimeToolNode自动处理并行工具执行、错误处理和状态注入。一个容易踩坑的细节——工具里要读 graph state如user_idPython 侧通过注入的ToolRuntime[Context, State]参数访问runtime.state/runtime.context且ToolNode直接挂为节点时拿到的就是当前 graph state但如果从其他节点手动invoke它必须传完整 state只传{messages: ...}就读不到其他字段。Graph API vs Functional API文档每个模式都给了两版等价写法Graph API 显式声明节点/边适合复杂拓扑、看得清结构Functional API 用task/entrypoint装饰器更贴近普通 Python 顺序思维靠future.result()等待并行任务。两者生成的是同一种执行语义按项目可读性选即可。学习衔接建议这页是「模式菜单」属于架构层。接下来建议按文档提到的收益点推进persistence状态持久化断点续跑→ streaming流式输出→ interruptshuman-in-the-loop正好对应评估-优化里人工介入的注脚→ deployment。另外文档推荐用 LangSmith 对每个模式打 trace 对比数据流配合chain.get_graph().draw_mermaid_png()看结构是这套文档最有效的学法。下面是全景图图里虚线即「条件边/回环」——这也是理解这套文档的钥匙Workflow 的智能全部集中在条件边上判断函数节点的智能全部来自增强型 LLM。补充ToolNode 完整讲解一句话ToolNode 是 LangGraph 官方预制好的节点专门用来执行 LLM 输出的工具调用tool_calls。LLM 只负责决定要调用哪个工具、传什么参数真正跑 Python 函数、拿到结果这件事交给 ToolNode。它等价于你手动写的循环解析AIMessage的tool_calls→ 匹配函数 → 调用函数 → 包装成ToolMessage放回消息列表。1. 核心背景消息类型非常关键LangGraph Agent 循环里 3 种核心消息HumanMessage用户输入AIMessage大模型输出。如果模型要调用工具AIMessage 会带上.tool_calls字段这是一个列表里面包含工具名称、参数、tool_call_idToolMessage工具执行后的返回结果必须绑定对应的tool_call_id让大模型知道这是哪一次工具调用的返回⚠️ 重点LLM 不会执行任何代码它只输出工具调用的结构化描述。执行代码必须交给 ToolNode。2. ToolNode 内部自动做的4件事fromlanggraph.prebuiltimportToolNode tool_nodeToolNode(tools[tool1,tool2])当状态流入 ToolNode读取状态里的 messages拿最后一条消息提取里面的tool_calls根据工具名字在你传入的工具列表里找到对应的函数并行执行所有工具调用一次返回多个tool_call会并发跑把每个函数返回值包装成ToolMessage返回{messages: [ToolMessage(...)]}State 里的 messages 一般用Annotated[list, operator.add]所以新的 ToolMessage 会追加进消息历史不会覆盖旧消息。3. 标准 ReAct 流程图ToolNode 位置START → LLM节点带bind_tools ↓ 【条件路由判断】 ├─ 如果 AIMessage 有 tool_calls → 进入 ToolNode └─ 没有 tool_calls → END直接回答用户 ↓ ToolNode执行工具生成ToolMessage ↓ 回到 LLM节点把工具结果喂给大模型继续思考循环往复直到模型不再生成tool_calls直接输出自然语言答案。4. 最小可运行完整示例结合你之前的代码风格fromtyping_extensionsimportTypedDictfromlangchain_core.messagesimportHumanMessage,AIMessage,ToolMessagefromlangchain_core.toolsimporttoolfromlanggraph.graphimportStateGraph,START,ENDfromlanggraph.prebuiltimportToolNodefromlangchain_openaiimportChatOpenAIimportos llmChatOpenAI(modelqwen3.7-flash,api_keyos.environ[DASHSCOPE_API_KEY],base_url[https://dashscope.aliyuncs.com/compatible-mode/v1](https://dashscope.aliyuncs.com/compatible-mode/v1),temperature0,)# 1. 定义工具tooldefget_weather(city:str)-str:查询城市天气 Args: city: 城市名称 ifcity北京:return北京今天 28℃晴天returnf{city}多云25℃tools[get_weather]# 绑定工具到模型让模型知道可以调用哪些函数llm_with_toolsllm.bind_tools(tools)# 2. 定义状态classState(TypedDict):messages:list# 3. LLM节点defllm_agent(state:State):respllm_with_tools.invoke(state[messages])return{messages:[resp]}# 4. 实例化ToolNode传入工具列表tool_nodeToolNode(tools)# 5. 路由函数判断是否要调用工具defroute(state:State):last_msgstate[messages][-1]# 如果存在tool_calls就去tool_node否则结束ifisinstance(last_msg,AIMessage)andlast_msg.tool_calls:returntool_nodeelse:returnEND# 构建图builderStateGraph(State)builder.add_node(llm_agent,llm_agent)builder.add_node(tool_node,tool_node)builder.add_edge(START,llm_agent)builder.add_conditional_edges(llm_agent,route)builder.add_edge(tool_node,llm_agent)# 工具跑完回到大模型graphbuilder.compile()# 调用resgraph.invoke({messages:[HumanMessage(北京今天天气怎么样)]})print(res[messages][-1].content)5. 关键细节拆解5.1 ToolNode 输入输出输入state默认读取state里messages键找到最后一条AIMessage的tool_calls输出{messages: [ToolMessage, ...]}工具执行结果消息列表参数messages_key如果你的状态里消息不叫messages可以自定义例如ToolNode(tools, messages_keymsg_list)5.2 支持并行工具调用如果模型一次返回多个tool_calls同时调用多个工具ToolNode自动并行执行不需要你手动写Send。和你最开始那个报告例子的Send并行不是一回事Send是图层面并行启动多个节点ToolNode内部并行同一个ToolNode节点内部并行执行多个工具函数5.3 错误处理ToolNode 默认捕获工具抛出的异常自动包装成带错误信息的ToolMessage返回给LLM不会直接让整个图崩溃。你可以通过handle_tool_errors自定义异常策略。6. 和你前面两个例子对比例子模式节点角色报告生成Send并行多workerorchestrator生成计划Send派发多个llm_call并行写章节没有工具调用笑话迭代LLM自评估循环LLM生成笑话 → LLM评估循环没有工具调用ToolNode AgentReAct工具调用循环LLM思考并输出tool_calls →ToolNode执行外部函数→ 返回结果再交给LLM前两个例子所有逻辑都是LLM生成文本ToolNode场景大模型可以调用外部Python函数、API、数据库这就是Agent最核心的能力。7. 常见坑忘记调用llm.bind_tools(tools)模型不会生成tool_callsToolNode永远不会触发。State的messages没有用operator.add新ToolMessage会直接覆盖旧消息上下文丢失。Tool缺少文档字符串模型不知道工具用途不会调用。tool装饰器会自动解析函数签名和docstring生成工具schema。ToolMessage必须携带tool_call_idToolNode内部自动处理你手写工具节点时才需要手动处理。8. 手动实现ToolNode看懂底层原理下面这个就是ToolNode简化手写版本看懂这个你就完全理解ToolNode在干什么fromlangchain_core.messagesimportToolMessagefromlanggraph.typesimportCommanddefmy_manual_tool_node(state:State):messagesstate[messages]last_msgmessages[-1]tool_map{t.name:tfortintools}tool_msgs[]forcallinlast_msg.tool_calls:tooltool_map[call[name]]resulttool.invoke(call[args])tool_msgs.append(ToolMessage(contentresult,tool_call_idcall[id]))return{messages:tool_msgs}ToolNode本质就是帮你封装了上面这段代码还加上并行执行、异常捕获。
返回列表