[技术札记] 图工程:从单智能体循环到可恢复的 Agent 执行系统 #25
leecyang
started this conversation in
Engineering Notes
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
主题
架构设计
摘要
正文
许多 Agent 系统在原型阶段表现良好,却会在任务复杂度、并发规模和运行时间上升后迅速暴露问题。
一个常见原因并不在于模型能力,也不完全在于 Prompt,而在于任务本身的执行结构。
大量 Agent 系统实际上仍然遵循一种隐式的线性流程:
后一个步骤默认等待前一个步骤完成,所有信息不断进入同一个上下文,失败则往往意味着从某个大循环重新开始。
当系统规模扩大后,这种结构通常会带来几个直接问题:
这也是为什么生产级 Agent 系统最终需要从 Loop Engineering(循环工程) 进一步走向 Graph Engineering(图工程)。
一、图工程的核心不是“画流程图”
图工程不是把原来的 Prompt Chain 换成一张节点图。
真正的变化是:
一个最基本的 Agent Graph 可以抽象为五类核心元素。
1. Node:节点
一个边界明确的工作单元。
节点可以是:
一个节点最好只承担一个主要职责。
2. Edge:边
边不应该仅仅表达:
更准确的定义是:
这是图工程非常重要的设计原则。
执行顺序不等于依赖关系。
3. State:状态
状态记录整个任务执行过程中需要跨节点持续存在的信息,例如:
没有可靠状态管理的 Graph,很容易退化为另一种形式的 Prompt Chain。
4. Router:路由器
Router 根据当前状态决定下一条合法路径。
模型可以参与判断,但模型的判断结果与系统允许执行的路径应当分离。
例如:
分类可以是概率性的,但系统允许进入哪些路径应该是明确且可检查的。
5. Gate:门控
Gate 决定某项工作是否有资格继续向下游传播。
典型 Gate 包括:
很多生产系统中,价值最高的节点甚至不是“产生新内容”的节点,而是阻止错误结果继续传播的节点。
二、不要把所有“然后”都建模成依赖
线性 Agent 工作流经常来自自然语言本身。
人很容易写:
但图工程首先应该问:
如果答案是否定的,那么
A → B这条边通常就不应该存在。例如一个技术调研任务:
三个研究任务如果互不依赖,就应该并行执行,而不是人为排列成:
这条原则看起来简单,却往往是 Agent 系统降低端到端延迟最有效的方式之一。
三、节点必须拥有清晰的执行契约
如果一个节点无法被精确定义,它通常也很难:
一个可靠节点至少应该明确四件事:
{ "node": "source_researcher", "input": { "topic": "string", "source_type": "primary" }, "output": { "claim": "string", "source": "string", "confidence": "high | medium | low" }, "failure": "no_primary_source_found" }也就是说,一个节点至少应明确:
尤其值得注意的是:节点之间应尽可能传递结构化结果,而不是任意自然语言。
自由文本会迫使下一个 Agent 再次解释:
结构化数据则让 Graph 能直接判断:
节点契约稳定之后,底层模型、Prompt 甚至工具都可以被替换,而不必重新设计整个工作流。
四、不要让 Agent 承担普通程序应该完成的工作
Agent Graph 中一个常见的反模式是:
实际上,大量工作根本不需要推理。
例如:
这些任务应该优先使用确定性代码完成。
例如:
一个非常实用的工程原则是:
如果一个 Graph 的每一次数据搬运都需要调用另一个 Agent,那么系统实际上是在为自己的“连线”支付 Token 成本。
五、绝大多数 Agent Graph 都可以拆成几种基本拓扑
复杂系统看起来可能拥有几十甚至几百个节点,但其拓扑往往是几个基本结构的组合。
1. Chain
适用于后一个步骤确实依赖前一个步骤完整结果的情况。
优点:
缺点:
2. Fan-out / Fan-in
一个任务拆成多个独立分支,并行执行后统一汇总。
非常适合:
这是生产级 Agent 系统中非常重要的一种结构。
3. Router
根据任务状态、风险、规模或用户意图选择不同执行路径。
它允许:
因此,系统不再需要对所有请求支付同样昂贵的计算成本。
4. Controlled Cycle
循环本身并不是问题。
真正危险的是:
这种没有明确停止条件的 Agent Loop。
任何生产级循环都应该拥有:
六、并行并不天然意味着更快
如果五个节点互相独立,那么让它们并行通常是合理的。
但 Graph 中真正决定性能的不是“有没有并发”,而是:
例如:
只有在 C 确实需要 B1、B2、B3 的完整结果时,这个 Join 才是必要的。
典型场景包括:
如果每个结果可以独立进入后续流程,就没有必要人为加入 Barrier。
因此:
七、验证应该成为独立的系统边界
不要让同一个 Agent 在同一上下文中同时负责:
更可靠的结构是:
Verifier 可以独立验证:
这里的关键不是简单地“多调用一个模型”,而是形成:
生成者负责生成。
检查者负责判断是否允许继续。
八、状态管理决定 Graph 是否真正进入生产阶段
很多 Agent 架构图只强调节点和边,却忽略最重要的部分之一:
State。
真正运行数小时甚至数天的 Agent 系统必须能够回答:
因此,重要节点执行完成后应该产生持久化 Checkpoint。
同时,不建议在所有节点之间不断传递越来越长的完整 Transcript。
更合理的方式是:
节点之间尽可能传递:
而不是反复转述上一阶段生成的全部内容。
这样既减少上下文损耗,也使整个执行过程更容易:
九、失败应该是局部事件,而不是系统级事故
在线性 Chain 中,一个步骤失败经常意味着整个流程停止。
Graph Engineering 的目标之一,是把失败限制在尽可能小的范围内。
不同节点可以具有不同失败策略:
同时应尽可能保证写操作具有:
否则一次简单的 Retry 就可能:
可靠性并不意味着“保证每一个节点永不失败”。
可靠性意味着:
参考资料
本文参考自:
All reactions