核心结论: Agent Loop 解决的是“一个节点内如何迭代”,Graph Engineer 解决的是“节点之间如何流转”。生产级 Agent 的稳定性不取决于模型能力,而取决于是否用显式状态图约束循环边界、隔离上下文、控制回边次数。
LLM 是无状态的:输出 = 模型(系统提示 + 工具 + 会话历史 + 用户指令)。Agent Loop 在此基础上引入“思考—行动—观察”循环,使模型能多步完成任务。但裸 Loop 在生产环境中存在三个结构性问题:
Graph Engineer 的核心是将 Agent 执行过程建模为有向图:节点按工作性质分类,边由条件驱动,状态结构化传递。
from dataclasses import dataclass, field
from enum import Enum
class NodeType(Enum):
COLLECT = "collect" # 信息收集
REASON = "reason" # 推理决策
ACT = "act" # 执行动作
VERIFY = "verify" # 验证结果
@dataclass
class Node:
id: str
type: NodeType
prompt: str
tools: list[str] = field(default_factory=list)
next_nodes: dict[str, str | None] = field(default_factory=dict)
max_iter: int = 5
@dataclass
class GraphState:
task: str
collected: list = field(default_factory=list)
hypotheses: list = field(default_factory=list)
action_log: list = field(default_factory=list)
verified: bool = False
error: str | None = None每个节点只承担一种工作性质。COLLECT 节点只读数据,REASON 节点只做推理,ACT 节点只执行动作,VERIFY 节点只校验结果。节点之间通过 next_nodes 的条件边流转。
Graph 管宏观流转,Loop 管节点内部迭代。每个节点内部可以有一个小循环,但必须有明确退出条件。
class Graph:
def __init__(self, nodes: dict[str, Node], entry: str, max_steps: int = 20):
self.nodes, self.entry, self.max_steps = nodes, entry, max_steps
def run(self, state: GraphState, llm, tools, permission):
cur = self.entry
for _ in range(self.max_steps):
node = self.nodes[cur]
result = self._execute_node(node, state, llm, tools, permission)
state.action_log.append((node.id, result))
cond = self._route(node, state, result)
cur = node.next_nodes.get(cond)
if cur is None:
break
return state
def _execute_node(self, node, state, llm, tools, permission):
for _ in range(node.max_iter):
action = llm.decide(node, state)
if action.kind == "done":
return action.output
if not permission.allow(action.tool, action.args):
return {"error": "permission denied"}
out = tools[action.tool](**action.args)
self._update_state(node.type, state, out)
return {"error": "max_iter reached"}
def _update_state(self, node_type, state, out):
if node_type == NodeType.COLLECT:
state.collected.append(out)
elif node_type == NodeType.ACT:
state.action_log.append(out)
elif node_type == NodeType.VERIFY:
state.verified = out.get("ok", False)
def _route(self, node, state, result):
if isinstance(result, dict) and result.get("error"):
return "error"
if node.type == NodeType.VERIFY:
return "done" if state.verified else "retry"
return "ok"关键设计有三点。第一,节点内循环有上限:max_iter 防止某个节点无限迭代。第二,回边有约束:VERIFY 失败可回到 REASON,但整体 max_steps 限制总轮数。第三,状态结构化:每个节点只写自己负责的字段,下一节点只读所需字段,避免全量上下文传递。
上下文隔离。 推理节点看到的是收集节点整理后的结构化摘要,而非原始日志;执行节点看到的是明确指令,而非全部对话历史。这是 Graph 比裸 Loop 节省 token 的根本原因。
权限边界。 在 _execute_node 中插入 permission.allow 检查,只读模式仅允许 read/search/glob,工作空间模式限制路径范围。权限检查应在工具执行前完成。
状态持久化。 GraphState 可序列化存储,支持中断恢复。每个节点的输出写入对应字段,而非混入对话历史。
可观测性。 action_log 记录每个节点的执行结果与路由条件,便于回溯“为什么走了这条边”。
Agent Loop 是执行单元,Graph Engineer 是编排框架。前者解决单节点内的“再来一次”,后者解决跨节点的“下一步去哪”。生产级 Agent 的工程重点不在于让模型更聪明,而在于用状态图把循环限制在可控边界内。没有 Graph 约束的 Loop 是实验;有 Graph 约束的 Loop 才是系统。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。