5.1 复杂 Agentic 工作流设计


5.1 复杂 Agentic 工作流设计

单智能体怎么循环决策

本节在全册位置:把前四章零件拼成智能体。经典 ReAct 模式就是「思考-行动-观察」循环:模型决定调工具,工具结果回到状态,模型再思考,直到给出最终答案。循环用条件边表达。我们提醒:循环没有退出条件,等于给模型一张无限信用卡。

设计:思考-行动-观察环

一个 agent 节点调用模型并选择动作;条件边判断是否还要调工具(tools_condition);若调,去 tool 节点,工具结果回状态,再回到 agent;否则去 END。状态用 MessagesState 累积消息。循环上限由另一个条件边防死循环。类比游戏:像回合制战斗,每回合模型选招,环境给反馈。退出条件要写在路由里,而不是靠模型自觉停。

from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI from langchain_core.tools import tool @tool def search(q: str): """检索""" return "天气晴" model = ChatOpenAI(model="gpt-4o-mini") agent = create_react_agent(model, [search]) # 5.1 复杂 Agentic 工作流设计 res = agent.invoke({"messages": [("user", "今天天气?")]}) print(res["messages"][-1].content)
# 自己实现同样循环,看清结构 from langgraph.graph import StateGraph, START, END, MessagesState from langgraph.prebuilt import ToolNode, tools_condition def call_model(s: MessagesState): return {"messages": [model.invoke(s["messages"])]} b = StateGraph(MessagesState) b.add_node("agent", call_model) b.add_node("tools", ToolNode([search])) b.add_edge(START, "agent") b.add_conditional_edges("agent", tools_condition) b.add_edge("tools", "agent") b.add_edge("agent", END) # 这个显式版让你能在 agent 后插入计数守卫

案例:带上限的研究循环

背景:研究助手可能陷入「检索-还不够-再检索」死循环,账单失控。

操作:在 routes 里加步数计数,超过 N 强制去 END。

结果:成本可控,必有终局,用户总能拿到一版答案。

解读:循环必须配退出条件,这是图式编排的基本纪律,也是和纯 prompt 循环最大的工程差别。

变式:把上限设为动态(模型自报「还需几步」)做弹性收敛,但硬上限永远兜底。

05-01-fig01

工程清单

  • ReAct 即思考-行动-观察循环,循环用条件边表达,tools_condition 检测是否还要调工具。

  • 状态用 MessagesState 累积消息,退出由另一个条件边防死循环,硬上限永远兜底。

  • 显式版比预置智能体多出的价值,是能在 agent 后插入计数守卫与审计节点。

常见误区

不设这个上限,模型陷入检索-还不够-再检索的死循环,成本与延迟双双失控;循环必须配退出条件,这是和纯 prompt 循环最大的工程差别。

循环守卫的两种实现

给循环套上限,最常用的是「计数 + 硬上限」,另一种是「软上限 + 硬兜底」的组合:

from typing import TypedDict, Annotated import operator class AgentState(MessagesState): loop_count: Annotated[int, operator.add] # 计数通道必须用累加 def route(s): # 硬上限:超过 5 轮强制收尾 if s["loop_count"] >= 5: return END # 软上限:模型自报「够了」就走 END,否则继续 return "agent" if s["messages"][-1].tool_calls else END
# 软上限让模型自报所需轮数,写入状态 # 但硬上限永远兜底,防止自报不可靠

计数通道两个细节:必须 operator.add 累加,覆盖式计数在循环里永远停在 1;计数节点和路由节点分开写,条件边只做判断。软上限降低「差一步就好」的截断,硬上限保证成本边界,两者叠加是循环设计的标准形态。

create_react_agent 的内部结构

预置智能体不是魔法,它内部就是一张 ReAct 循环图。了解它的节点名才能正确扩展:

from langgraph.prebuilt import create_react_agent agent = create_react_agent(model, tools, prompt="你是助手") # 查看内部结构,确认节点名再扩展 print(agent.get_graph().draw_mermaid())

预置图的标准形态是 agent 节点(调模型)与 tools 节点(执行工具)互相回环,tools_condition 控制是否继续。想插入「计数守卫」或「审计节点」,就把它 add_node 进图,再调整条件边的路由目标。两个常见扩展:在 agent 之后加 step 计数节点;在 tools 之后加结果校验节点。改之前先打结构,别凭印象接边。

预置与显式的对照

维度 create_react_agent 显式手写
代码量 少,一行起步 多,全部自写
可定制点 节点内部可改,结构固定 结构完全自由
调试透明 低一些 高,每步可见
升级风险 依赖预置行为 全部自己掌控
适用 标准 ReAct 够用 需要自定义循环/分支

选择建议:先跑通预置版,确认业务需要额外控制流时再转显式版。显式版不是重写预置版,而是保留同样的节点语义、放开结构定制,过渡成本主要在理解节点命名与 tools_condition 的行为。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U