跳到正文
从 Loop 到 Graph:Agent 开始学习如何协作
从 Loop 到 Graph:Agent 开始学习如何协作

从 Loop 到 Graph:Agent 开始学习如何协作

Graph Engineering 不是又一个框架名,而是一种组织复杂 Agent 任务的方式:把任务拆成节点,用边决定顺序和分支,用状态保存进度、产物和失败位置。

速读#

最近开始流行的 Graph Engineering,听起来像是在给 AI 工程再造一个新词。把它拆开看,其实没有那么神秘:一个复杂任务先被拆成几个有边界的节点,再用边表达依赖、并行、条件分支和回退,最后用状态记录流程走到哪里、留下了什么。

它和单 Agent 的区别,不是多开几个聊天窗口,而是把「下一步做什么」从一段不断变长的对话里拿出来,变成可以观察、暂停、重试和恢复的流程。

Loop 是最小的 Graph#

Loop Engineering 解决的是一个 Agent 内部的问题:模型调用工具,得到结果,发现不对,再修正,然后继续调用。它本质上是一条会回到前面节点的图。

当任务只有一个执行者,而且每一步都必须依赖上一步的结果时,Loop 已经够用。比如:

  1. 读取文件。
  2. 修改代码。
  3. 跑测试。
  4. 测试失败,回到修改代码。
  5. 测试通过,结束。

真正让流程变复杂的,是任务开始出现多个相对独立的角色:后端、前端和测试可以同时推进;集成后要根据测试结果决定是交付还是回到某个模块;中间还可能需要人确认。此时,单条 Loop 会把所有事情重新压成串行对话,调度本身就成了瓶颈。

所以我对两个词的区分是:Loop 是一个执行单元内部的循环,Graph 是多个执行单元之间的协作结构。

Graph 的三个基本对象#

Node:只负责一件事#

节点可以是一个 Agent,也可以是普通代码、脚本、测试命令,甚至是等待人确认的暂停点。节点边界越清楚,流程越容易替换和重试。

一个节点不应该同时负责「理解需求、写接口、改页面、跑测试、决定是否上线」。这样做只是把一串职责塞进一个函数名里,出了问题仍然不知道是哪一步出了问题。

更好的拆分是:

  • plan:分析需求并确定任务边界
  • backend:实现后端接口
  • frontend:实现页面
  • tests:编写和执行测试
  • integrate:合并产物并做全局检查
  • approval:等待人工确认

Edge:决定下一步走哪里#

边不是简单的箭头,它表达了流程规则。

  • 确定性边plan -> backend,每次都这样走。
  • 模型决策边:由 Agent 根据上下文选择下一步,例如先查文档还是先读代码。
  • 条件边:测试通过就进入验收,测试失败就回到对应模块。

条件边尤其重要。没有它,失败只能从头再跑;有了它,流程可以把状态里的失败信息送回正确的节点,已经完成的分支继续保留。

State:流程的可恢复记录#

状态是整个 Graph 的记忆,不只是「最近一条消息」。它可以是结构化对象:

{
"backend": { "status": "done", "artifact": "api/export.js" },
"frontend": { "status": "running" },
"tests": { "status": "pending" },
"tokens_used": 12000
}

状态至少应该能回答四个问题:当前在哪个节点、每个节点产出了什么、哪条路径失败了、已经消耗了多少资源。只要状态被可靠地保存,流程中断后就可以从最近的检查点继续,而不是把整段聊天记录再翻一遍。

Graph 解决了什么问题#

并行:把等待时间拿回来#

如果后端、前端和测试可以依据同一份 API 契约独立工作,就没有必要按「后端完成后前端开始,前端完成后测试开始」的顺序排队。

可以先由规划节点确定共享契约,再分出三条支线:

+--> backend --+
plan ------------+--> frontend -+--> integrate --> approval
+--> tests ----+ \
+--> rework

这里的关键不是「开三个 Agent 就会变快」,而是三条支线必须拥有清楚的输入、互不覆盖的工作区和明确的汇合条件。没有契约的并行,只会把冲突更早制造出来。

暂停:把人放在真正需要判断的位置#

有些节点不适合自动执行,例如修改生产配置、合并高风险变更、确认研究结论。Graph 可以在这里停住,等待人确认后再继续。

这比让 Agent 自己在对话里说「我认为可以上线」更可靠,因为暂停点是流程的一部分,能被记录、审计和重复执行。

失败回退:只重做坏的那一段#

集成测试失败时,流程应该携带具体结果回到后端、前端或测试节点,而不是无条件从规划开始。其他节点已经生成的产物和状态可以保留,减少重复调用,也减少回退时引入的新变量。

这要求节点产物可定位、状态可序列化,而且每次重试都要知道自己使用的是哪一个版本的输入。否则「可恢复」只是看起来像恢复,实际上是在旧对话上继续猜。

一个开发需求怎么画成图#

假设需求是「给记账站增加数据导出功能」。串行做法通常是先写后端,再写前端,再补测试。中间任何一步的理解偏差,都会拖到后面才暴露。

Graph 的做法可以是:

  1. plan 明确导出格式、接口契约和验收条件。
  2. backendfrontendtests 按契约并行推进。
  3. integrate 合并三条分支,执行全局测试。
  4. 测试通过进入 approval;失败则根据失败模块回退。
  5. 人工确认后合入主分支。

用 LangGraph 表达时,骨架大致是这样:

from langgraph.graph import END, START, StateGraph
graph = StateGraph(DevState)
graph.add_node("plan", plan_task)
graph.add_node("backend", backend_task)
graph.add_node("frontend", frontend_task)
graph.add_node("tests", tests_task)
graph.add_node("integrate", integrate_task)
graph.add_node("rework", rework_task)
graph.add_node("approval", human_approval)
graph.add_edge(START, "plan")
graph.add_edge("plan", "backend")
graph.add_edge("plan", "frontend")
graph.add_edge("plan", "tests")
graph.add_edge(["backend", "frontend", "tests"], "integrate")
graph.add_conditional_edges(
"integrate",
check_tests,
{"pass": "approval", "fail": "rework"},
)
graph.add_edge("rework", "integrate")
graph.add_edge("approval", END)
app = graph.compile()

这里最值得注意的不是 API,而是代码和流程图能互相对照:规划、分支、汇合、条件回退和人工确认都在明面上。每个节点的具体实现可以更换,但流程关系不会藏在一段长 prompt 里。

不用 LangGraph 也能做 Graph Engineering#

Graph Engineering 是设计方法,不等于 LangGraph。LangGraph 提供了节点、边、状态和检查点等实现;也可以使用 AutoGen、Google ADK、Claude Code workflow,甚至自己写一段足够小的调度代码。

在 Claude Code 里,可以这样理解已有能力的对应关系:

Graph 概念Claude Code 中的对应物
Node一个 subagent 或一个明确的工作阶段
Deterministic Edgeworkflow 脚本中的固定顺序
Conditional Edge测试结果、hook 或脚本分支
State脚本变量、文件产物、任务进度和检查记录
Human-in-the-loop等待确认的阶段或显式停点

例如,「拆成后端、前端、测试三块并行开发,完成后合并并跑全量测试,失败就回到对应模块,最后等我确认」这句话,本身已经是在描述一个 Graph。workflow 做的事情,是把这段描述变成可执行的节点和边。

另一个典型例子是深度研究:先拆分问题,再同时搜索国内动态、海外公司、基准数据等角度,之后抓取来源、交叉验证,最后综合成带引用的报告。主 Agent 负责拆解和汇总,具体搜索放在独立节点中,既能并行,也避免主对话被大量中间过程塞满。

什么时候不要用 Graph#

Graph 不是复杂任务的默认答案。以下任务直接用一个 Agent 的 Loop 更合适:

  • 能按固定顺序在几分钟内完成的小脚本或小 bug。
  • 每一步都强依赖上一步,拆分后没有实际并行空间。
  • 没有明确的产物、验收条件和失败回退路径。
  • 任务本身还在探索,先用对话把问题定义清楚更重要。

我会在出现下面三类信号时再引入 Graph:任务能拆出相互独立的分支;不同环节需要不同工具、权限或模型;流程中有必须人工确认、长期等待或中断恢复的节点。再加一条:流程足够长,值得记录每个分支的进度和成本。

如果这些条件一个都没有,画出来的 Graph 只是在给一条直线加装饰性的节点名。

最后:新词会变,边界不会#

Graph Engineering 的价值不在于把 Agent 数量堆上去,而在于把协作关系写清楚:谁负责什么,什么时候可以并行,什么结果允许继续,失败回到哪里,状态存在哪里,最终哪一步必须由人确认。

Loop 解决单个执行者如何持续行动,Graph 解决多个执行者如何共同完成一条流程。LangGraph 和 Claude Code workflow 让这套设计更容易落地,但它们都不能替代任务拆解、契约设计和终止条件。

这个词以后可能会被另一个新词替代,节点、边、状态和调度却不会凭空消失。真正值得留下的不是名词,而是把复杂协作从一段不可检索的聊天记录,变成一条能观察、能恢复、能解释的工程流程。

延伸阅读#

版权许可

CC BY-NC-SA 4.0 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

相关文章

s1oopX

登录 s1oopX