什麼時候該把 agent 換成一張流程圖(AI Agent 架構全解析 · 加映)
八篇走完,我們把一個 AI Agent 的 harness 從第 0 層拆到第 7 層,最後停在一台會自己轉的機器上。系列本來就收官了——這篇是加映,因為原書在 2026-07-30 又長出了一個新章節。
Layer 7 原本只有一個 section(21 · Loop engineering,也就是第 8 篇的內容)。作者在 7/30 補上了 22 · Graph engineering,34 個檔案、+2,871 行,隔天 merge 進 main。它開頭第一句話是:「第 21 章在一個 agent 外面堆疊 loop。這一章整理的是 model 呼叫和呼叫之間的流程。」——擺明就是第 8 篇的續集,那就把它補完。
一句話講完這章在幹嘛:別再問 model 下一步跑什麼。把你已經知道的流程寫進程式碼,model 只用在需要判斷的地方。
你早就知道流程長怎樣,卻每次都讓 model 重新猜一遍
很多任務的流程,你在還沒呼叫 model 之前就已經知道了:先分類工單再處理、先 review diff 再 commit、先拿到核准才做對外的動作。這些不是「要不要這樣做」的選擇題,是規定。
但普通的 agent loop 不知道這件事。它每跑一次,都要問 model「下一步做什麼」,把一套你早就背得出來的流程重新摸索一遍。代價有三個:慢(多一趟 round trip)、貴(連 routing 都要算 token)、而且每次跑都不一樣(同樣的輸入,這次先 review、下次先 commit)。
Graph engineering 的處方很直接:把已知的流程用程式碼寫成一張有向圖(directed graph),只有真的需要判斷的地方才留給 model。
四個零件:node、edge、cycle、state
可以先拿捷運路網圖來對。node 是站、edge 是軌道、cycle 是環狀線,而 state 是你手上那張一路刷過去的悠遊卡——每站都讀它,也都往上寫東西。
- Node 負責做事。 一個 node 可以是純程式碼、一次 model 呼叫,或一整趟 agent 執行。
- Edge 決定下一個 node。 由 harness 用程式碼判斷,不用 model 呼叫。
- Cycle 是允許的。 重試、review 後修改、人工暫停,都需要一條往回走的路。
- State 是一筆在圖上流動的紀錄。 每個 node 讀它,再把自己的更新寫回去。
第 8 篇那個驗證 loop,其實就是這種圖的最小版本:兩個 node(worker 和 checker)加一條往回的 edge。這一章做的事,是把「兩站的環狀線」擴展成一整張路網。
整套機制只有 12 行
最簡單的版本只需要三樣東西:一個 dict 把 node 名稱對到要跑的函式,另一個 dict 記著每個 node 跑完接誰,再加一個一路傳下去的 state。
1 | def run_graph(nodes, edges, state, start, budget=20): # src/graph.py |
四個值得看的細節:
nodes是一張 dispatch map,就是第 2 篇那個工具分派表的同一招。node 讀 state,只回傳自己改動的 key,不是整份紀錄。- edge 有兩種寫法:固定的 node 名字(決定性的),或一個吃 state 的函式(條件式的)。兩種都是 harness 用程式碼判斷,routing 不花任何 token。
- 沒有 edge 的 node 就是圖的終點。
budget是第 8 篇那個上限:cycle 撞到上限就停,回傳ok: False交給人。 trace依序記下跑過哪些 node,就是這趟執行留給可觀測性的紀錄。哪些 edge 從來沒 fire 過,一看就知道——那是死掉的分支。
真正該停下來看一眼的是這行:node = step(state) if callable(step) else step。整章的重點都在這裡——決定下一步的是 Python 的三元運算子,不是一次 API 呼叫。
Node 的光譜:從純程式碼到一整隻 agent
每個 node 都在「純程式碼」和「完整 agent」之間挑一個位置站:
| 類型 | 是什麼 | 判斷力 | 成本 |
|---|---|---|---|
| Code node | 解析、驗證、固定的 API 呼叫 | 決定性的,沒有判斷 | 不花 token |
| Model node | 一次 LLM 呼叫,例如分類器 | 有限度的判斷 | 一次呼叫 |
| Agent node | 一整個第 2 篇的 agent loop,帶著 tool | 開放式判斷,但被釘在一個位置上 | 一整趟執行 |
Agent node 是這三個裡面最有意思的。agent_node 把內層 loop 掛成圖上的一個 node,每次經過都用 state 組出 prompt,在全新的 messages[] 上跑一次 run_turn:
1 | def agent_node(build_prompt, model, registry, key="output"): |
這個「只看得到別人餵給它的部分」正是第 3 篇 subagent 的 context 隔離,換個地方用而已。整章新增的元件其實只有 edge map 一個,其餘全是前面幾層零件的重新排列。
怎麼決定一個 node 要放在光譜的哪裡?原則只有一句:分支條件寫得出來的,就交給程式碼;model 呼叫只留給真的需要判斷的 node。
你叫得出名字的那些 workflow pattern,其實都是圖
- Prompt chaining:一串 node 排成一條路,中間用程式碼把關。
- Routing:一條條件式 edge,分流到各個專門的 node。
- Parallelization:幾條同時跑的分支在一個 node 會合。可以是拆工作(sectioning),也可以是同一件事跑多次投票(voting)。
- Orchestrator-workers:一個 node 在執行時決定要派出多少工作,再由另一個 node 收攏。edge 是動態的,但形狀仍然是圖。
- Evaluator-optimizer:一個 worker node、一個 checker node,加一條往回的 edge——這就是第 8 篇的驗證 loop,放進圖裡就變成一個子圖。
這五個名字如果你讀過 Anthropic 那篇 Building effective agents 應該都不陌生。這一章的貢獻是指出它們不是五種各自獨立的架構,而是同一個資料結構的五種接法。
什麼時候不要畫圖
這節在原文裡是獨立的一節,我認為它比前面所有內容都值錢。
開放式的工作沒辦法預先定好流程。深度研究、難查的 bug,都得邊跑邊規劃;事先畫死的圖,反而擋住解法真正需要走的那條路。你以為自己在加結構,其實是在砍掉搜尋空間。
原書給的判準有兩條,都很緊:只把你本來就要強制執行的結構寫進圖裡(先分類再處理、先 review 再 commit、先核准再送出),而且只在確實改善結果時才加。其他一律交給普通的 loop,讓 model 自己規劃。
實務上最常見的是混合式:把 agent 當成固定圖裡的一個 node。圖負責保證 review 一定會發生,agent 負責決定在自己那一格裡怎麼把事做完。該硬的地方硬,該軟的地方軟:
1 | nodes = { # src/demo.py |
四個 node、四條 edge,就把「先分類、分流給對的 agent、一定要過檢查、沒過帶著 feedback 繞回去」這套規矩焊死在程式碼裡。model 只在 math 和 prose 這兩格裡有發言權。
三套系統怎麼決定下一步
| 面向 | Claude Code | Hermes Agent | mini-swe-agent |
|---|---|---|---|
| 怎麼選路 | 階段之間用普通的 script 程式碼:條件、迴圈、pipeline、平行分派 | model 用 tool call 選路,沒有寫在程式碼裡的 edge | 一個固定的 cycle,跑到 model 提交或 budget 用完 |
| node 是什麼 | 一個 node 一個 subagent,回傳通過 schema 驗證的結構化輸出 | 委派出去的 subagent,深度和並行數都有上限 | 兩個:一個 model step、一個 environment step |
| state 怎麼流 | 階段的回傳值往下傳;journal 記下每個 node 的輸出供續跑 | 結果經過 completion queue 回到呼叫端 | message list 就是全部的 state |
| 代價 | 圖活在單次執行的 script 裡,不是可重用的宣告式圖 | routing 花 model 的 token,每次跑可能不一樣 | 所有任務共用同一個形狀,沒有分支可以特化 |
順帶一提,mini-swe-agent 是原書在 7 月下旬才加進來的第三個對照系統,前面幾篇還沒提到它。它的定位是 baseline:整張圖只有兩個 node 加一個固定 cycle,所有選擇都留在 model 裡。拿它跟 Claude Code 對照特別清楚——一個把編排全寫進程式碼,一個把編排全交給 model,中間那條光譜就是這一章在講的東西。
六個會翻車的地方
- Model 當 router:把選路交給 model,燒 token、增加延遲,而且每次跑不一樣。最上游選錯一次,後面全部跟著錯。→ 轉移改用程式碼判斷,model 呼叫只留給需要判斷的 node。
- 過度畫圖:需要探索的任務被固定的圖框住,解法要走的路被擋掉。→ 只把本來就要強制執行的結構寫進圖裡。
- 沒有失敗的路:檢查用的 node 判了 FAIL 卻無路可送,爛輸出就一路流到下游。→ 每個檢查 node 都要配一條帶 budget 的往回 edge。
- 沒有上限的 cycle:往回的 edge 沒有上限,就會永遠繞下去。→ harness 強制執行的 step budget,用完就交給人。
- State 膨脹:每個 node 都把完整輸出倒進共用的 state,後面的 node 被淹沒。→ 嚴格的 state 邊界,node 只讀需要的子集、只回傳自己的更新(第 3 篇的 context 管理)。
- 跑到一半掛掉:一張長圖在第七個 node 掛掉,重來卻從第一個 node 開始。→ 記下每個 node 的輸出,續跑時跑完的 node 從紀錄重放(第 4、5 篇)。
⚠️ 前兩個是選型錯誤,後四個是工程細節。真正讓專案翻車的通常是前兩個——它們在架構定案的那一刻就決定了,後面再怎麼補都補不回來。「這個流程到底該不該畫成圖」值得你在寫第一行程式之前先想清楚。
動手跑
1 | # 離線檢查,不用金鑰:驗串接順序、state 合併、程式碼 routing、cycle 撞 budget 會停 |
這章的 src/ 一樣是接著第 21 章長出來的,loop.py 完全沒動——什麼時候輪到它跑,改由圖決定。想確認「多一張圖」在程式碼裡長什麼樣,diff 這兩章的 src/ 就看得到,新增的實質上只有 graph.py 一個檔。
收尾
第 8 篇的結論是:別再想下一句 prompt 要打什麼,去設計那個不需要你也能把 agent 跑起來的 loop。這一篇是那句話的下半段——loop 設計好之後,下一個問題是「loop 和 loop 之間的順序,要交給誰決定」。
答案不是全部交給 model,也不是全部寫死。是把你已經知道的部分寫進程式碼、把你不知道的部分留給 model,然後很小心地別把「不知道」的那部分也一起寫死了。
原文與可執行程式碼在這裡:hardness1020/awesome-agent-architecture 的 sections/22-graph-engineering/,有繁體中文版。這一章的三個出處也值得直接讀:LangChain · 3 years of graph engineering with LangGraph、Anthropic · Building effective agents、Google · Why we built ADK 2.0。
















