Graph Engineering:把单一循环拆成多智能体编排图
单 agent 循环在复杂任务上会因上下文塞满而退化,作者主张把工作拆成各管一件事的专业节点,再用确定性边路由、用共享 state 跨 run 记忆、用硬闸门验收。全文以 CI 失败分诊系统为实例,给出可直接复制的分类器与修 bug 节点定义、edge 规则、STATE.md 结构、测试闸门 prompt,以及从手动 /goal 到 /loop 再到云端 Routine 的三级放权路径。作者也承认多数团队尚不需要 graph:循环没跑通就上图,只是把复杂度组织得更好看。适合已在用 coding agent、正被单 agent 误判与 token 浪费困扰的工程师。

A single AI agent in a loop can plan, code, test, and review. But the moment the task gets complex, it chokes. The context window fills up, reasoning degrades, and you're back in the chair reading every diff.
The people shipping faster in 2026 stopped giving one agent five jobs. They split the work into specialists: one agent codes, another reviews, a third tests. Then they wired them into a system that routes work, shares state, and verifies output without a human in the chair.
That system is a graph. And in July 2026, the AI engineering community gave the practice a name:
Graph engineering: designing the organization your agents run in.

一个跑在循环里的 AI agent 能规划、写代码、测试、审查。可任务一复杂,它立刻卡死:上下文窗口被塞满,推理开始退化,你又一次坐回椅子上逐行读 diff。
2026 年跑得更快的那批人,不再让一个 agent 干五份活。他们把工作拆给专才:一个 agent 写代码,一个负责审查,第三个做测试。然后把这些 agent 接进一个系统——由它派活、共享状态、验证产出,全程不用人盯着。
这个系统就是图(graph)。2026 年 7 月,AI 工程社区给这种做法起了名字:
图工程(graph engineering):为你的 agent 设计它们运转其中的组织。

Each layer built on the last. None replaced the one before it. Graph engineering is the fourth layer.

每一层都建立在上一层之上,没有哪一层取代了前一层。图工程是第四层。
This article is 90% how-to. We'll build one real graph from scratch: a CI failure triage system that classifies broken builds, routes them to specialist agents, fixes what it can, and escalates what it can't. Every prompt is filled in and ready to copy. By the end, you'll have a working system you can adapt to your own codebase.
Two short sections explain what graph engineering is and when you need it. Everything else is the build.
这篇文章九成是实操。我们会从零搭出一张真实的图:一个 CI 故障分诊系统,它给挂掉的构建分类,把故障路由给对应的专才 agent,能修的就修,修不了的就升级给人。所有 prompt 都已填好,可以直接复制。读完之后,你会得到一个改改就能用到自己代码库上的可用系统。
只有两个小节讲图工程是什么、什么时候需要它。其余全是动手。
Nodes do the work. Each node is one specialized agent with one job. A planner, a coder, a reviewer, a test runner. Each gets its own context window, its own instructions, its own set of tools. What it can't see, it can't break.
节点负责干活。每个节点就是一个专才 agent,只担一个职责:规划、写码、审查、跑测试。每个节点有自己的上下文窗口、自己的指令、自己的工具集。它看不见的东西,它也就弄不坏。
Edges route between them. An edge is the rule that decides what happens after a node finishes. "If the classifier says bug, send to the fixer. If it says flake, send to the retry agent." Edges can be unconditional (always go here next) or conditional (check a value, then choose a path).
边负责在节点之间路由。一条边就是「某个节点跑完之后下一步做什么」的规则。「分类器说是 bug,就送去修复者;说是 flake,就送去重试 agent。」边可以是无条件的(永远走这一步),也可以是有条件的(先看某个值,再选路径)。
State is what flows along the edges. A shared data object that carries what's been done, what failed, and what comes next. Each node reads the slice it needs, does its work, writes its output back to the state, and the next node picks it up.
状态沿着边流动。它是一个共享的数据对象,携带着已经做了什么、哪里失败了、接下来该做什么。每个节点只读自己需要的那一片,干完活把输出写回状态,下一个节点接着取用。

A loop is the smallest possible graph: one node with an edge back to itself. So graph engineering does not replace loop engineering. It's the layer directly above. You learn loops first. When one agent doing five jobs becomes the bottleneck, you split the jobs into a graph.

循环本身就是最小的图:一个节点,加一条指回自己的边。所以图工程并不取代循环工程,它就在循环的上一层。先学会写循环;当一个 agent 干五份活成为瓶颈时,再把这几份活拆成一张图。
Most tasks do not need a graph. A single well-built loop handles the majority of real work. The people dismissing graph engineering as a buzzword have a point you should take seriously: unnecessary complexity is not engineering. It's overhead.
Before you build anything, answer four questions. If any answer is no, keep the loop.

CI failure triage passes all four. The failures repeat nightly. Different failure types need different handling (a missing env secret is not the same as a real bug). The agent that writes the fix should not be the one approving the fix. And if you've been running a single-agent loop for CI fixes, you already know it misclassifies half the failures and wastes tokens retrying things it can't fix.
If your loop works, don't break it with a graph. If your loop is the bottleneck, the graph is the fix.
大多数任务并不需要图。一个写得好的循环就能应付现实中的大部分工作。那些把图工程斥为 buzzword 的人,有一点值得你认真对待:不必要的复杂度不是工程,是开销。
动手之前,先回答四个问题。只要有一个答案是否,就继续用循环。

CI 故障分诊四个问题全过。故障每晚都在重复。不同故障类型需要不同的处理方式(少了一个环境变量 secret,和真正的 bug 不是一回事)。写修复的 agent 不该同时是批准修复的那个。而如果你一直在用单 agent 循环处理 CI 修复,你早就知道它会误判一半的故障,还浪费 token 去重试那些它根本修不了的东西。
循环好用,就别用图去破坏它。循环成了瓶颈,图才是解药。
From here on, we're building one real system: a CI failure triage graph. It reads a failing GitHub Actions log, classifies the failure, routes it to the right specialist agent, fixes what it can, and escalates what it can't. Every prompt is filled in. Every file is real. Adapt the names to your codebase and it runs.
从这里开始,我们只搭一个真实系统:一张 CI 故障分诊图。它读一份失败的 GitHub Actions 日志,给故障分类,路由给对应的专才 agent,能修就修,修不了就升级。每个 prompt 都已填好,每个文件都是真的。把名字改成你代码库里的,它就能跑。
The mistake most people make with graphs: they open Claude Code and start building agents before knowing what the graph should look like. That's writing functions before knowing what the program does.
Start with three questions on paper:
-
What is the final output? Be specific. "Fixed CI" is weak. "All tests pass, lint clean, PR opened with summary of what failed and what was changed" is a target the graph can verify against.
-
Which subtasks are independent? Draw them side by side. If the env-secret fix and the flaky-test retry don't share any input, they can run at the same time. If the fixer needs the classifier's output, draw an arrow.
-
Where does quality get checked? Every path through the graph should hit at least one gate before reaching the output. No gate means no verification. You'll have a fan of agents that all say "looks good" to their own work.
Start on paper. Boxes for agents. Arrows for routing. This sketch becomes your blueprint. Don't skip it. The 10 minutes you spend here saves hours of rewiring later.
大多数人搭图时犯的错是:打开 Claude Code 就开始造 agent,根本不知道这张图该长什么样。这相当于还不知道程序要干什么,就先写函数。
先在纸上回答三个问题:
-
最终产出是什么?要具体。「CI 修好了」太虚。「所有测试通过、lint 干净、开出一个 PR 并说明哪里坏了、改了什么」——这才是图能拿去验证的目标。
-
哪些子任务彼此独立?把它们并排画出来。如果补环境变量 secret 和重试 flaky 测试不共享任何输入,它们就能同时跑。如果修复者要用分类器的输出,就画一条箭头。
-
质量在哪里被检查?穿过图的每一条路径,在抵达输出之前都该至少撞上一道闸门。没有闸门就没有验证,你只会得到一群 agent,各自对自己的活都说「看着不错」。
从纸上开始。方框代表 agent,箭头代表路由。这张草图就是你的蓝图,别跳过它。在这里花掉的 10 分钟,能省下后面几个小时的重新接线。
Here's the prompt that creates the sketch for our CI triage system:
prompt
I need to design an agent graph for CI failure triage.
FINAL OUTPUT:
For fixable failures: a draft PR with the fix,
all tests passing, lint clean, summary of root cause.
For unfixable failures: a Slack message to #dev-alerts
with classification, logs, and suggested next steps.
SUBTASKS:
1. Read the CI log and classify the failure type
(env, flake, bug, dependency, infra)
2. For env failures: check if the secret exists in
vault, add it or flag the gap
3. For flake failures: retry the test once. If it
passes on retry, file a flaky-test issue. If not,
reclassify as bug.
4. For bug failures: read the failing test, read the
code it tests, draft a fix, run the suite.
5. For dependency failures: check which version broke,
propose a rollback or pin, run the suite.
6. For infra failures (timeout, OOM, runner issue):
escalate to humans. Do not attempt to fix.
QUESTIONS TO ANSWER:
- Which subtasks are independent?
- Where do results converge?
- Where is the verification gate?
- Which model should each node use?
Output a node-edge list. Do not build anything yet.
这是给我们的 CI 分诊系统生成草图用的 prompt:
prompt
I need to design an agent graph for CI failure triage.
FINAL OUTPUT:
For fixable failures: a draft PR with the fix,
all tests passing, lint clean, summary of root cause.
For unfixable failures: a Slack message to #dev-alerts
with classification, logs, and suggested next steps.
SUBTASKS:
1. Read the CI log and classify the failure type
(env, flake, bug, dependency, infra)
2. For env failures: check if the secret exists in
vault, add it or flag the gap
3. For flake failures: retry the test once. If it
passes on retry, file a flaky-test issue. If not,
reclassify as bug.
4. For bug failures: read the failing test, read the
code it tests, draft a fix, run the suite.
5. For dependency failures: check which version broke,
propose a rollback or pin, run the suite.
6. For infra failures (timeout, OOM, runner issue):
escalate to humans. Do not attempt to fix.
QUESTIONS TO ANSWER:
- Which subtasks are independent?
- Where do results converge?
- Where is the verification gate?
- Which model should each node use?
Output a node-edge list. Do not build anything yet.
The output of this prompt is your graph sketch. Here's what ours looks like:

Five specialist nodes, one classifier at the entry, one gate before shipping. The escalation path skips the gate entirely and goes straight to humans. That's the sketch. Now we build each piece.
这条 prompt 的输出就是你的图草图。我们这张长这样:

五个专才节点,入口一个分类器,交付前一道闸门。升级路径直接跳过闸门,一路走到人。草图到此为止,接下来逐个把零件造出来。
Each node in the graph is one agent with one job. Not a generalist that does everything. A specialist that does one thing well.
Why this matters: a generalist agent loads the full context of the entire task into one window. When the window fills up (and it always fills up on complex tasks), reasoning degrades. The model starts losing track of what it was doing. Outputs get worse even as the conversation gets longer.
A specialist gets a scoped context window with only the information it needs. It sees less, but it sees clearly. Anthropic's own multi-agent research confirmed this: splitting agents into specialists with isolated contexts showed a 90.2% improvement over a single-agent baseline on internal research benchmarks.
图里的每个节点都是一个 agent、一份职责。不是什么都干的通才,而是把一件事做好的专才。
为什么重要:通才 agent 会把整个任务的完整上下文塞进同一个窗口。窗口一满(复杂任务上它必然会满),推理就开始退化。模型逐渐跟不上自己刚才在干什么,对话越长,输出反而越差。
专才拿到的是一个收窄过的上下文窗口,里面只有它需要的信息。它看到的东西更少,但看得清楚。Anthropic 自己的多 agent 研究证实了这一点:把 agent 拆成上下文相互隔离的专才之后,在内部研究基准上比单 agent 基线提升了 90.2%。
Three rules for every node:
-
One node, one verb. "Classify." "Fix." "Review." "Retry." If a node description has two verbs, it's two nodes. The classifier classifies. It doesn't fix. The fixer fixes. It doesn't review its own fix.
-
Scope the tools. A reviewer node should not have access to write files. A fixer node should not have access to merge PRs. Scoped tools prevent a specialist from stepping outside its lane, which is especially important when the graph runs unattended.
-
Match model to task. The classifier routes failures and needs to be fast. Use a cheap model (Haiku, or Sonnet at low effort). The bug fixer needs to read test failures, understand the code, and write a targeted patch. Use a frontier model at high effort. A loop gives every task the same model. A graph matches cost to difficulty.

每个节点都要守三条规矩:
-
一个节点,一个动词。「分类」「修」「审」「重试」。如果一个节点的描述里出现了两个动词,那它其实是两个节点。分类器只分类,不修;修复者只修,不审自己的修复。
-
收窄工具权限。审查节点不该有写文件的权限,修复节点不该有合并 PR 的权限。收窄工具能挡住专才越界,在图无人值守地跑起来时,这一点尤其重要。
-
模型匹配任务。分类器负责给故障分派路径,要快,用便宜模型(Haiku,或低 effort 的 Sonnet)。bug 修复者要读懂测试失败、理解代码、写出精准补丁,用高 effort 的前沿模型。循环给每个任务同一个模型;图让成本跟着难度走。

In Claude Code, you define nodes as agent files inside .claude/agents/. Each file is a markdown document with the agent's role, instructions, and allowed tools. Here's what the classifier and fixer look like for our CI triage graph:
.claude/agents/classifier.md
# CI Failure Classifier
You are a CI failure classifier.
Your only job: read a failing CI log and decide
what kind of failure it is.
CATEGORIES:
- env: missing secret, wrong env variable, infra
not provisioned. Clue: "secret not found",
"variable not set", "connection refused to vault"
- flake: test passed before, no code changed.
Clue: intermittent timeout, race condition,
network-dependent assertion
- bug: deterministic failure tied to a recent commit.
Clue: assertion error in test, type error, logic
failure that reproduces consistently
- dependency: failure appeared after a version bump.
Clue: "module not found", breaking change in
changelog, pinned version mismatch
- infra: runner-level issue. Timeout, OOM, disk full.
Clue: "killed", "out of memory", "no space left"
OUTPUT: JSON with category, confidence (0-1),
reasoning (one sentence), and the relevant
log lines that led to the classification.
RULES:
- If confidence is below 0.7, flag for human review
- Never guess. If the log is ambiguous, say so.
- Do not attempt to fix anything. Only classify.
在 Claude Code 里,节点就是 .claude/agents/ 下的 agent 文件。每个文件是一份 markdown 文档,写着这个 agent 的角色、指令和可用工具。下面是我们的 CI 分诊图里分类器和修复者的样子:
.claude/agents/classifier.md
# CI Failure Classifier
You are a CI failure classifier.
Your only job: read a failing CI log and decide
what kind of failure it is.
CATEGORIES:
- env: missing secret, wrong env variable, infra
not provisioned. Clue: "secret not found",
"variable not set", "connection refused to vault"
- flake: test passed before, no code changed.
Clue: intermittent timeout, race condition,
network-dependent assertion
- bug: deterministic failure tied to a recent commit.
Clue: assertion error in test, type error, logic
failure that reproduces consistently
- dependency: failure appeared after a version bump.
Clue: "module not found", breaking change in
changelog, pinned version mismatch
- infra: runner-level issue. Timeout, OOM, disk full.
Clue: "killed", "out of memory", "no space left"
OUTPUT: JSON with category, confidence (0-1),
reasoning (one sentence), and the relevant
log lines that led to the classification.
RULES:
- If confidence is below 0.7, flag for human review
- Never guess. If the log is ambiguous, say so.
- Do not attempt to fix anything. Only classify.
.claude/agents/bug-fixer.md
# Bug Fixer
You are a bug fix agent.
Your only job: fix deterministic test failures
caused by recent code changes.
INPUT: the failing test name, the error message,
and the git diff of the most recent commit.
PROCESS:
1. Read the failing test to understand what it expects
2. Read the code the test covers
3. Read the recent diff to find what changed
4. Write the smallest fix that makes the test pass
5. Run the test suite to verify
OUTPUT: the fix as a git diff, plus a one-paragraph
explanation of root cause and what was changed.
RULES:
- Smallest fix wins. Do not refactor.
- Do not modify the test to make it pass.
- Do not touch files outside src/ and lib/
- If the fix requires changing more than 3 files,
escalate instead of fixing.
.claude/agents/bug-fixer.md
# Bug Fixer
You are a bug fix agent.
Your only job: fix deterministic test failures
caused by recent code changes.
INPUT: the failing test name, the error message,
and the git diff of the most recent commit.
PROCESS:
1. Read the failing test to understand what it expects
2. Read the code the test covers
3. Read the recent diff to find what changed
4. Write the smallest fix that makes the test pass
5. Run the test suite to verify
OUTPUT: the fix as a git diff, plus a one-paragraph
explanation of root cause and what was changed.
RULES:
- Smallest fix wins. Do not refactor.
- Do not modify the test to make it pass.
- Do not touch files outside src/ and lib/
- If the fix requires changing more than 3 files,
escalate instead of fixing.
Notice the boundaries. The classifier can't write files. The fixer can't modify tests. The fixer can't touch files outside src/ and lib/. These constraints are not suggestions. They're hard walls. When the graph runs overnight without you, these walls are the reason you wake up to clean PRs instead of chaos.
注意这些边界。分类器不能写文件。修复者不能改测试。修复者碰不到 src/ 和 lib/ 之外的文件。这些约束不是建议,是硬墙。图在你睡觉时跑一整晚,第二天早上你看到的是一堆干净的 PR 而不是一团乱麻,靠的就是这几堵墙。
Edges are the routing rules that connect nodes. They decide three things: who gets the output next, under what condition, and what data travels along the edge.
There are three types of edges. Every graph uses at least two.

边是连接节点的路由规则。它决定三件事:输出接下来归谁、在什么条件下、以及哪些数据跟着这条边一起走。
边有三种类型。任何一张图至少会用到其中两种。

Our CI triage graph uses conditional routing at the classifier. The classifier reads the log, assigns a category, and the edge logic sends it down the right path. This is deterministic code, not a model decision. The classifier picks the category. The edge logic enforces the route.
The key insight: hard constraints should not live inside prompts. If a routing rule is critical ("never send payment-related failures to the auto-fixer"), enforce it in the edge logic, not in the agent's instructions. Prompts are advisory. Edges are deterministic. A prompt might be ignored on turn 47 of a long session. An edge is code. It doesn't forget.
prompt - routing logic for CI triage
Here is the graph for CI failure triage.
NODES:
- Classifier (reads log, outputs category)
- Env Agent (handles missing secrets/vars)
- Flake Agent (retries, files flaky-test issue)
- Bug Fixer (reads test + code, drafts fix)
- Dep Agent (rollback or pin version)
- Escalator (sends Slack alert to humans)
- Test Gate (runs full test suite, lint)
EDGE RULES:
Classifier outputs category:
env -> Env Agent
flake -> Flake Agent
bug -> Bug Fixer
dep -> Dep Agent
infra -> Escalator (skip gate, alert humans)
All fix agents -> Test Gate
Test Gate pass -> open PR
Test Gate fail -> retry (max 3), then escalate
HARD CONSTRAINTS (enforce in code, not prompts):
- Never auto-fix files in src/auth/ or src/billing/
- Never modify CI config without human approval
- If classifier confidence < 0.7, escalate
我们的 CI 分诊图在分类器这一层用的是条件路由。分类器读日志、给出类别,边逻辑把它送进对应的路径。这是确定性的代码,不是模型在拍板。分类器负责选类别,边逻辑负责执行路由。
关键认知:硬约束不该住在 prompt 里。如果某条路由规则很关键(「支付相关的故障永远不许送进自动修复」),就把它写进边逻辑,而不是 agent 的指令里。prompt 是建议性的,边是确定性的。一场长会话跑到第 47 轮时,prompt 可能被忽略;边是代码,它不会忘。
prompt - CI 分诊的路由逻辑
Here is the graph for CI failure triage.
NODES:
- Classifier (reads log, outputs category)
- Env Agent (handles missing secrets/vars)
- Flake Agent (retries, files flaky-test issue)
- Bug Fixer (reads test + code, drafts fix)
- Dep Agent (rollback or pin version)
- Escalator (sends Slack alert to humans)
- Test Gate (runs full test suite, lint)
EDGE RULES:
Classifier outputs category:
env -> Env Agent
flake -> Flake Agent
bug -> Bug Fixer
dep -> Dep Agent
infra -> Escalator (skip gate, alert humans)
All fix agents -> Test Gate
Test Gate pass -> open PR
Test Gate fail -> retry (max 3), then escalate
HARD CONSTRAINTS (enforce in code, not prompts):
- Never auto-fix files in src/auth/ or src/billing/
- Never modify CI config without human approval
- If classifier confidence < 0.7, escalate
State is the memory of the graph. Without it, each node starts from zero and each run forgets what happened before. With state, nodes pick up where the last one left off, and tomorrow's run knows what today's run already tried.
The state object is a shared data structure that flows along the edges. Each node reads the slice of state it needs, does its work, writes its output back, and the next node picks up the updated state.

Design rule: whitelist, don't broadcast. Each node receives only the slice of state it needs. The classifier gets the raw log. The fixer gets the classification, the failing test name, and the recent diff. It doesn't need the full log. If every node reads all of the state, you don't have a graph. You have one bloated context window with extra steps.
状态是图的记忆。没有它,每个节点都从零开始,每次运行都忘掉上一次发生过什么。有了它,节点能接着上一个节点留下的进度往下干,明天的运行知道今天的运行已经试过什么。
状态对象是一个共享数据结构,沿着边流动。每个节点读取自己需要的那一片,干完活把输出写回去,下一个节点取到的是更新后的状态。

设计原则:白名单,别广播。每个节点只拿到自己需要的那一片状态。分类器拿原始日志;修复者拿分类结果、失败的测试名和最近的 diff,它不需要整份日志。如果每个节点都能读到全部状态,那你手里就没有图了——你只是把一个臃肿的上下文窗口多绕了几道手续。
Here's what the state file looks like after one full run of our CI triage graph:
STATE.md - after run #1
# CI Triage State
## Last run
2026-08-04 03:30 UTC
## Current run
workflow: ci-main #4821
trigger: push to main by @david
status: completed
## Classification
category: bug
confidence: 0.94
reasoning: assertion error in test_checkout_flow,
deterministic, tied to commit a3f7b2c
## Fix
diff: +2 lines in src/cart/checkout.ts
root_cause: price rounding used Math.floor
instead of Math.round, off-by-one on
totals ending in .5
## Gate
tests: 142/142 passing
lint: clean
verdict: pass
## Output
pr: #482 "fix: rounding in checkout total"
escalations: none
## Lessons learned
2026-08-04: checkout price tests are brittle
around .5 boundaries. Added to watch list.
Tomorrow's run reads this file. It knows what was already fixed, which lessons were learned, and what's on the watch list. The graph doesn't re-derive project context from zero every cycle. State is what turns a one-time run into a compounding system.
The graph forgets every run. The state file does not. A graph without state restarts. A graph with state resumes.
这是我们的 CI 分诊图完整跑完一次之后,状态文件的样子:
STATE.md - 第 1 次运行后
# CI Triage State
## Last run
2026-08-04 03:30 UTC
## Current run
workflow: ci-main #4821
trigger: push to main by @david
status: completed
## Classification
category: bug
confidence: 0.94
reasoning: assertion error in test_checkout_flow,
deterministic, tied to commit a3f7b2c
## Fix
diff: +2 lines in src/cart/checkout.ts
root_cause: price rounding used Math.floor
instead of Math.round, off-by-one on
totals ending in .5
## Gate
tests: 142/142 passing
lint: clean
verdict: pass
## Output
pr: #482 "fix: rounding in checkout total"
escalations: none
## Lessons learned
2026-08-04: checkout price tests are brittle
around .5 boundaries. Added to watch list.
明天的运行会读这份文件。它知道什么已经修过、学到了哪些教训、观察名单上有谁。图不必每个周期都从零重建项目上下文。状态,正是把一次性的运行变成会复利的系统的东西。
图每次运行都会忘。状态文件不会。没有状态的图只能重启,有状态的图可以续跑。
This is the piece that separates a working graph from an expensive fan of unverified agents agreeing with each other.
Without a gate, the graph produces output and calls it done. With a gate, the graph produces output and then something objective checks whether the output is actually correct. The gate is the only node that decides "done" or "not done." Every other node does work. The gate judges work.
Karpathy's rule applies directly here: if a task is verifiable, it is optimizable. The gate is where you make the task verifiable. If you can't define a gate, the task probably shouldn't be in a graph.

正是这一块,把一张能用的图和一群只会互相点头的昂贵 agent 区分开来。
没有闸门,图产出结果,然后自称干完了。有闸门,图产出结果,再由某个客观的东西检查这份结果到底对不对。闸门是唯一有权判定「完成」或「没完成」的节点。其他节点负责干活,闸门负责判定活干得怎么样。
Karpathy 那条规则在这里正好适用:可验证的任务才可优化。闸门,就是你让任务变得可验证的地方。如果你定义不出闸门,这个任务大概不该放进图里。

Three types of gates, from strongest to weakest:
Hard gate. A test suite, a type checker, a linter, a build. It passes or fails. No opinion, no judgment, no bias. This is the strongest gate. Use it wherever you can. Our CI triage graph uses this: the full test suite runs after every fix. 142 tests pass or they don't.
Soft gate. A second model asked to review the output. Better than no gate, but weaker than a test suite. The reviewer model has its own biases and blind spots. Use as a supplement on top of a hard gate, not as a replacement for one.
Human gate. A human reviews before merge, deploy, or any irreversible action. The graph surfaces the work. The human makes the final call. For our CI triage graph, the human gate is the PR review: the graph opens a draft PR, a human approves and merges.
Cherny shared a concrete data point: giving Claude effective verification methods typically improves final output quality by 2-3x. That number alone is the argument for never skipping the gate.
闸门分三种,从最强到最弱:
硬闸门。测试套件、类型检查、linter、构建。过就是过,挂就是挂,没有观点、没有判断、没有偏见。这是最强的闸门,能用就一定要用。我们的 CI 分诊图用的就是它:每次修复后跑完整测试套件,142 个测试要么全过,要么不过。
软闸门。让第二个模型来审查输出。比没有闸门好,但不如测试套件。审查模型有自己的偏见和盲区,它只能叠在硬闸门之上做补充,不能替代硬闸门。
人闸门。合并、部署或任何不可逆动作之前,由人来审。图把工作摆到台面上,人做最终决定。在我们的 CI 分诊图里,人闸门就是 PR 审查:图开一个 draft PR,人批准并合并。
Cherny 给过一个具体数据:给 Claude 配上有效的验证手段,最终输出质量通常能提升 2-3 倍。光这一个数字,就足以说明闸门不能省。
prompt - test gate for CI triage
You are the test gate for the CI triage graph.
Your only job: verify the fix is correct.
RUN THESE CHECKS IN ORDER:
1. Run the full test suite: bun test
2. Run the type checker: bun run typecheck
3. Run the linter: bun run lint
4. Verify only files in src/ and lib/ were modified
5. Verify no files in src/auth/ or src/billing/
were touched (hard constraint)
OUTPUT:
verdict: "pass" or "fail"
tests: 142/142 passing (or which failed)
lint: clean (or list of issues)
scope_check: pass (or list of out-of-scope files)
suggestion: if fail, what to fix first on retry
RULES:
- Be strict. A false pass costs more than a false fail.
- Do not fix the code. Only verify.
- If all checks pass but something feels wrong,
add a warning to the output. Don't block on it.
prompt - CI 分诊的测试闸门
You are the test gate for the CI triage graph.
Your only job: verify the fix is correct.
RUN THESE CHECKS IN ORDER:
1. Run the full test suite: bun test
2. Run the type checker: bun run typecheck
3. Run the linter: bun run lint
4. Verify only files in src/ and lib/ were modified
5. Verify no files in src/auth/ or src/billing/
were touched (hard constraint)
OUTPUT:
verdict: "pass" or "fail"
tests: 142/142 passing (or which failed)
lint: clean (or list of issues)
scope_check: pass (or list of out-of-scope files)
suggestion: if fail, what to fix first on retry
RULES:
- Be strict. A false pass costs more than a false fail.
- Do not fix the code. Only verify.
- If all checks pass but something feels wrong,
add a warning to the output. Don't block on it.
Gates rot. A test suite that was good six months ago might not catch today's failure modes. Periodically pick a few PRs the graph approved and manually verify the gate actually caught what it was supposed to catch. If it didn't, update the tests before running the graph again.
闸门会腐烂。半年前好用的测试套件,未必抓得住今天的故障模式。定期挑几个图批准过的 PR,手动核对闸门是不是真的拦住了它该拦的东西。如果没拦住,先把测试更新掉,再让图继续跑。
Every graph you will ever build is assembled from five composable patterns. Anthropic documented them in their engineering guides. Cherny built Claude Code's tooling around them. They compose freely: chain two of them together, nest one inside another, wire three in parallel.

Our CI triage graph composes three of these: Route at the entry (classifier sends each failure type down a different path), Chain within each path (fix, then verify), and Evaluate on retry (gate critiques, fixer iterates). That's it. Three patterns, one graph.
The cheapest structural win in most graphs is routing. A single classifier at the entry that sends easy tasks to a cheap model and hard tasks to a frontier model can cut your token bill in half without changing output quality.
你这辈子要搭的每一张图,都由五种可组合的模式拼成。Anthropic 在工程指南里写过它们,Cherny 围绕它们造了 Claude Code 的工具链。它们可以自由组合:两个串起来、一个套进另一个、三个并行接上。

我们的 CI 分诊图用了其中三种:入口处 Route(分类器把每种故障类型送进不同路径)、每条路径内 Chain(先修,再验)、重试时 Evaluate(闸门给意见,修复者迭代)。就这些。三种模式,一张图。
大多数图里最便宜的结构性收益来自路由。入口放一个分类器,简单任务交给便宜模型,难题交给前沿模型,token 账单能砍掉一半,输出质量还不受影响。
prompt - composing patterns
Build the CI triage graph using these patterns:
PATTERNS USED:
1. Route at entry: classifier sends each failure
type to the right specialist
2. Chain within each path: specialist fixes,
then gate verifies
3. Evaluate on retry: if gate fails, fixer gets
feedback and iterates (max 3 rounds)
COMPOSITION:
CI Log -> Route(Classifier)
-> env: Chain(Env Agent -> Gate)
-> flake: Chain(Flake Agent -> Gate)
-> bug: Evaluate(Bug Fixer <-> Gate, max 3)
-> dep: Chain(Dep Agent -> Gate)
-> infra: Escalate (skip gate)
Gate pass -> open PR
Gate fail after 3 rounds -> escalate
prompt - 组合模式
Build the CI triage graph using these patterns:
PATTERNS USED:
1. Route at entry: classifier sends each failure
type to the right specialist
2. Chain within each path: specialist fixes,
then gate verifies
3. Evaluate on retry: if gate fails, fixer gets
feedback and iterates (max 3 rounds)
COMPOSITION:
CI Log -> Route(Classifier)
-> env: Chain(Env Agent -> Gate)
-> flake: Chain(Flake Agent -> Gate)
-> bug: Evaluate(Bug Fixer <-> Gate, max 3)
-> dep: Chain(Dep Agent -> Gate)
-> infra: Escalate (skip gate)
Gate pass -> open PR
Gate fail after 3 rounds -> escalate
The graph is designed. The nodes are built. The edges are wired. The gate is set. Now run it.
There are three levels of autonomy. Each one removes you further from the loop. Start at level one. Only promote when you trust the graph.

图设计好了,节点造完了,边接上了,闸门也设好了。现在让它跑起来。
自主度分三级,每升一级,你就离循环更远一点。从第一级开始,只有当你信任这张图时,才往上提。

Level 1: Manual run with /goal. You type the command once. The graph runs until the condition you set is met. A separate evaluator model checks completion, so the agent that wrote the fix isn't the one deciding if it's done.
prompt - first run with /goal
/goal all tests pass and lint is clean
CI workflow ci-main #4821 just failed.
The log is at .github/logs/ci-main-4821.log
Run the CI triage graph:
1. Read the failing log
2. Classify the failure type
3. Route to the right specialist:
env -> check secrets, add if missing
flake -> retry once, file issue if flaky
bug -> read test + code, draft smallest fix
dep -> find breaking version, propose rollback
infra -> skip fix, alert #dev-alerts on Slack
4. Run the test gate: bun test, typecheck, lint
5. If gate passes: open draft PR with summary
6. If gate fails: retry with gate feedback (max 3)
7. If still failing after 3: escalate to humans
Update STATE.md after each step.
Watch this run end to end the first time. Read every diff. Verify the gate actually caught what you expected it to catch. Only move to level 2 once you trust the graph on at least 5 manual runs.
第一级:用 /goal 手动跑。你敲一次命令,图就一直跑到你设定的条件满足为止。是否完成由一个独立的评估模型判断,所以写修复的那个 agent 并不是判定它是否完成的那一个。
prompt - 第一次用 /goal 运行
/goal all tests pass and lint is clean
CI workflow ci-main #4821 just failed.
The log is at .github/logs/ci-main-4821.log
Run the CI triage graph:
1. Read the failing log
2. Classify the failure type
3. Route to the right specialist:
env -> check secrets, add if missing
flake -> retry once, file issue if flaky
bug -> read test + code, draft smallest fix
dep -> find breaking version, propose rollback
infra -> skip fix, alert #dev-alerts on Slack
4. Run the test gate: bun test, typecheck, lint
5. If gate passes: open draft PR with summary
6. If gate fails: retry with gate feedback (max 3)
7. If still failing after 3: escalate to humans
Update STATE.md after each step.
第一次运行时,从头到尾盯着它跑完。每个 diff 都读一遍。确认闸门真的拦住了你以为它会拦的东西。至少在 5 次手动运行上都信得过这张图了,再升到第二级。
Level 2: Scheduled runs with /loop. The graph checks for new failures on a cadence. You're no longer the trigger.
prompt - scheduled triage with /loop
/loop every 30 minutes, check the CI dashboard.
If any workflow failed in the last 30 minutes:
1. Pull the failing log
2. Run the CI triage graph (same steps as above)
3. Open a draft PR for fixable issues
4. Escalate unfixable issues to #dev-alerts
If nothing failed, log "all green" to STATE.md
and wait for the next cycle.
Stop after 8 hours or when I say stop.
Update STATE.md after every cycle.
第二级:用 /loop 定时跑。图按固定节奏检查有没有新故障,你不再是触发器。
prompt - 用 /loop 定时分诊
/loop every 30 minutes, check the CI dashboard.
If any workflow failed in the last 30 minutes:
1. Pull the failing log
2. Run the CI triage graph (same steps as above)
3. Open a draft PR for fixable issues
4. Escalate unfixable issues to #dev-alerts
If nothing failed, log "all green" to STATE.md
and wait for the next cycle.
Stop after 8 hours or when I say stop.
Update STATE.md after every cycle.
Level 3: Routines. /loop dies when you close the terminal. Routines run in the cloud on Anthropic's infrastructure. Your laptop can be off. Three trigger types: schedule (cron), API call (webhook), GitHub event (PR opened, push to main).
prompt - promoting to a Routine
Run the CI triage graph as a Routine.
Trigger: GitHub webhook on workflow_run.completed
where conclusion == "failure"
Schedule: also run at 6am daily as a sweep
for any failures missed by the webhook
On each trigger:
1. Pull the failing log
2. Run the full triage graph
3. Update STATE.md
4. Open draft PR or escalate
Alerts:
- Ping #dev-alerts only for escalations
- Weekly summary every Monday 9am to #ci-health
Limits:
- Max 3 retries per failure
- Never touch src/auth/ or src/billing/
- If token spend exceeds $5 in one run, stop and alert
第三级:Routines。你一关终端,/loop 就死了。Routines 跑在 Anthropic 的云端基础设施上,笔记本关机也不影响。触发方式有三种:定时(cron)、API 调用(webhook)、GitHub 事件(PR 打开、push 到 main)。
prompt - 升级成 Routine
Run the CI triage graph as a Routine.
Trigger: GitHub webhook on workflow_run.completed
where conclusion == "failure"
Schedule: also run at 6am daily as a sweep
for any failures missed by the webhook
On each trigger:
1. Pull the failing log
2. Run the full triage graph
3. Update STATE.md
4. Open draft PR or escalate
Alerts:
- Ping #dev-alerts only for escalations
- Weekly summary every Monday 9am to #ci-health
Limits:
- Max 3 retries per failure
- Never touch src/auth/ or src/billing/
- If token spend exceeds $5 in one run, stop and alert

Order matters. Get one manual run reliable first. Watch it work. Read the diffs. Trust the gate. Then schedule it. Then promote it to a Routine. Skipping steps is how graphs fail quietly and expensively in production.

顺序很重要。先让一次手动运行稳定下来。看着它干活,读它的 diff,信任它的闸门。然后再定时跑,最后才升级成 Routine。跳过这些步骤,图就会在生产环境里安静而昂贵地失败。
You don't need Claude Code or any special tooling to feel how this works. Paste this prompt into any LLM and watch it build a graph in one conversation:
prompt - paste this into any LLM
You will work as a graph of specialized agents.
TASK: review this code for bugs, security issues,
and style problems.
GRAPH:
You will simulate 3 specialist agents, one at a time.
Each agent sees only its own instructions and the code.
Each agent produces a typed report.
AGENT 1 - Bug Hunter:
Read the code. Find logic errors, edge cases,
off-by-one mistakes. Output a JSON list of findings
with file, line, severity, description.
AGENT 2 - Security Reviewer:
Read the code. Find hardcoded secrets, injection
vulnerabilities, missing input validation.
Output same JSON format.
AGENT 3 - Style Checker:
Read the code. Find naming inconsistencies,
dead code, missing error handling.
Output same JSON format.
GATE:
After all 3 agents finish, merge their findings.
Remove duplicates. Rank by severity.
Output a final report with:
- total findings by severity
- top 3 issues to fix first
- overall verdict: "ship", "fix first", or "rewrite"
RULES:
- Each agent works independently.
- No agent sees another agent's findings.
- The gate sees all findings but doesn't add its own.
- Be specific. File names, line numbers, examples.
CODE TO REVIEW:
[paste your code here]
Begin. Run each agent in order, then the gate.
你不需要 Claude Code,也不需要任何特殊工具,就能体会到它是怎么运作的。把这段 prompt 粘进任何一个 LLM,看它在一场对话里搭出一张图:
prompt - 粘进任意 LLM
You will work as a graph of specialized agents.
TASK: review this code for bugs, security issues,
and style problems.
GRAPH:
You will simulate 3 specialist agents, one at a time.
Each agent sees only its own instructions and the code.
Each agent produces a typed report.
AGENT 1 - Bug Hunter:
Read the code. Find logic errors, edge cases,
off-by-one mistakes. Output a JSON list of findings
with file, line, severity, description.
AGENT 2 - Security Reviewer:
Read the code. Find hardcoded secrets, injection
vulnerabilities, missing input validation.
Output same JSON format.
AGENT 3 - Style Checker:
Read the code. Find naming inconsistencies,
dead code, missing error handling.
Output same JSON format.
GATE:
After all 3 agents finish, merge their findings.
Remove duplicates. Rank by severity.
Output a final report with:
- total findings by severity
- top 3 issues to fix first
- overall verdict: "ship", "fix first", or "rewrite"
RULES:
- Each agent works independently.
- No agent sees another agent's findings.
- The gate sees all findings but doesn't add its own.
- Be specific. File names, line numbers, examples.
CODE TO REVIEW:
[paste your code here]
Begin. Run each agent in order, then the gate.
This is a graph built inside a single conversation. It's limited: you're still the trigger, there's no persistent state, no real parallelism. But it shows the core mechanic. Three specialists, each with scoped instructions, routing to a gate that merges and judges.
The jump from this to a full autonomous graph is adding the four things this toy version lacks: persistent state (STATE.md), real parallelism (subagents), automation (/loop, Routines), and hard verification (a test suite instead of a model's opinion).
这是一张在一场对话内部搭起来的图。它有明显的局限:触发器还是你,没有持久状态,也没有真正的并行。但它把核心机制演示清楚了——三个专才,各自拿着收窄的指令,路由到一道负责合并与判定的闸门。
从玩具版跨到完全自主的图,无非是补上它缺的四样东西:持久状态(STATE.md)、真正的并行(subagents)、自动化(/loop、Routines),以及硬验证(用测试套件取代模型的意见)。
Two problems get sharper as the graph gets better. Not easier. Both scale with success.

图越强,两个问题反而越尖锐,不会变轻松。两者都随成功一起放大。

Comprehension debt grows every time the graph ships code you didn't write. A smooth running graph is quiet. Quiet feels like progress. But the gap between what exists in your repository and what you actually understand charges compound interest. The day you have to debug a system no one on the team has read will cost more than all the tokens ever did.
图每交付一次你没写过的代码,理解债就多一分。一张跑得顺的图很安静,而安静容易被误当成进展。但仓库里存在的东西和你真正理解的东西之间的差距,是按复利计息的。等到有一天你要去调试一个团队里没人读过的系统,那一天付出的代价,会比所有 token 费用加起来还高。
Cognitive surrender is subtler. When the graph runs itself, it's tempting to stop forming an opinion and accept whatever comes back. Designing the graph is the cure when you do it with judgment. It's the accelerant when you do it to avoid thinking. Same action, opposite result. Two engineers can build the exact same graph. One uses it to move faster on work they understand. The other uses it to avoid understanding the work at all. The graph doesn't know the difference.
认知投降(cognitive surrender)更隐蔽。图自己跑起来之后,人很容易不再形成判断,来什么就接受什么。带着判断去设计图,它是解药;为了逃避思考去设计图,它是助燃剂。同样的动作,相反的结果。两个工程师可以搭出一模一样的图:一个用它在自己懂的事情上跑得更快,另一个用它来彻底绕开理解。图分不出这两者的区别。
The mitigations are not technical. No framework solves them:
- Read the diffs. Every single one. If you don't read what the graph ships, you're renting comprehension debt at compound interest.
- Spot-check the gate. Pick a few PRs the graph approved and manually verify the tests actually catch the failure mode you care about. Gates rot over time.
- Keep the graph on small, machine-checkable tasks. CI triage, dependency bumps, lint fixes, flaky test reproduction. The moment the graph touches architecture decisions, auth logic, or anything where "done" is a judgment call, comprehension debt accelerates.
- Pair-design the graph with a teammate. A second pair of eyes when designing catches blind spots the graph will exploit forever once running.
缓解手段都不靠技术,没有哪个框架能解决:
- 读 diff,每一个都读。你不读图交付的东西,就等于按复利租着理解债。
- 抽查闸门。挑几个图批准过的 PR,手动确认测试真的抓住了你在意的故障模式。闸门会随时间腐烂。
- 让图只碰小而可机器校验的任务。CI 分诊、依赖升级、lint 修复、flake 测试复现。一旦图开始碰架构决策、鉴权逻辑,或者任何「完成」要靠人判断的事情,理解债就会加速累积。
- 和队友一起设计图。设计阶段多一双眼睛,能发现那些图一旦跑起来就会一直利用下去的盲区。
Karpathy showed us the context window is the programming surface. Cherny showed us the loop automates the context engineering. Steinberger asked the question that moved the frame one more level: what happens when many loops connect into one system?
But the honest version of this story is the same one every article in this space eventually tells: most developers don't need a graph yet. Not until the loop hits a ceiling, the task breaks into parallel subtasks, and the maker-checker split needs structural enforcement. If you haven't built a working loop, go build one first. A graph without a working loop underneath it is just organized complexity.
If your loop works and the task is simple, keep the loop.
If your loop is the bottleneck, now you know how to build the graph.
Karpathy 让我们看到,上下文窗口就是编程界面。Cherny 让我们看到,循环把上下文工程自动化了。Steinberger 提出的那个问题,又把框架往上抬了一层:当许多循环连成一个系统,会发生什么?
但这个故事诚实的那一面,也是这个领域每篇文章最后都会讲的:大多数人现在还不需要图。要等到循环撞上天花板、任务能拆成并行的子任务、写与审的分离需要结构性保障时,才需要。如果你连一个能跑的循环都还没搭出来,先去搭那个。底下一层没有能跑的循环,图只是被整理过的复杂度。
循环好用、任务又简单,就留着循环。
循环成了瓶颈,现在你知道图该怎么搭了。
Start with the sketch. Build the nodes. Wire the edges. Add the gate. Run it manually. Read the diffs. Trust it slowly. Then let it run.
Design the nodes. Wire the edges. Set the gate. Let the system ship.
从草图开始。造节点。接边。加闸门。手动跑起来。读 diff。慢慢建立信任。然后再放手让它跑。
设计节点,接好边,设好闸门,让系统去交付。