AI Workflow · 2026-09-25 · 20 分鐘閱讀
我原本以為問題是模型,後來發現是交接:Ai-agent 架構拆解
多模型工作流真正的問題不是模型不夠強,是規則在各個 AI 客戶端之間漂移。這篇拆解 Ai-agent 的架構:用 adapter pattern 收斂共用規則、用 skill contract 定義交接、用 script 驗證而不是靠模型感覺,並談這套治理在什麼規模以下其實是過度設計。判斷一套 AI workflow 成不成熟,看的是 prompt 有沒有變薄、contract 有沒有變厚。
Tags: AI Agent, PM, 工作流, 系統架構, 複雜服務, 設計
我一開始以為 AI Agent 的問題是模型不夠強。
後來發現不是。
真正卡住我的,是每個 AI 都各自很強,但放進同一條工作流之後,彼此之間沒有共同語言。Claude 可以幫我做規劃,Codex 可以進 repo 改檔,Gemini 可以讀大量脈絡,Ollama 可以在本地做 fallback。單看每個工具都合理,但真的要讓它們接力工作時,問題就會冒出來:上一棒做了什麼,下一棒要怎麼接?任務做到哪個階段?哪些檔案可以碰?什麼時候要停?如果額度用完,要降級還是中止?
這些問題一開始看起來像使用習慣問題,但越用越覺得它其實是系統設計問題。AI 不是不會做事,而是做完之後很難被接續、驗證、降級與恢復。
所以我開始把 Ai-agent 從一組 prompt,整理成一層個人 AI operating layer。它不是要再做一個新的聊天機器人,而是把 Claude、Codex、Gemini、OpenAI、Ollama、Hermes 這些不同 AI runtime,收斂到同一套 adapter、skills、memory、scripts、handoff artifact 與 run-state schema 上。
這件事其實很貼近我在複雜軟體服務裡常遇到的問題。專案不是缺少單一能力,而是缺少穩定交接:需求從 PM 到設計會漏,設計到開發會失真,開發到驗收又會變成另一套語言。AI workflow 如果也複製這種斷裂,只會讓混亂變快。所以我做 Ai-agent,不是為了展示我有很多 AI 工具,而是想把工作流裡的脈絡、邊界、驗收和交接做成可治理的系統。
我想解的問題不是「怎麼讓一個模型更聰明」,而是這件事:
How to make many AI clients execute the same contract safely?
AI 變快之後,瓶頸不再只是生成能力,而是對齊、邊界、恢復、驗證與交接。
我先處理的不是模型,而是規則漂移
不同 AI 客戶端的能力其實很不一樣。Claude Code 很適合做 orchestration,Codex 適合 repo edits、terminal execution 與測試迴圈,Gemini 適合 large-context ingest,OpenAI / ChatGPT 適合工具化分析,Ollama 可以當成本地 fallback,Hermes 則比較像自主代理與 capability-fenced toolsets 的實驗場。
如果每個 AI 都各自維護一份完整規則,很快就會失控。同一條限制在 Claude 裡改了,Codex 裡忘記改;Gemini 的入口文件有一版,OpenAI 的入口文件又是另一版。表面上是多模型,實際上是多份規則開始漂移。
這個現象其實有個更早的名字。Melvin Conway 在 1968 年提出的 Conway 定律說:組織設計出來的系統,結構會鏡射組織內部的溝通結構。放在這裡幾乎是字面上的事實——每個 AI 客戶端原本各自維護一份入口文件,就是「溝通管道各自為政」的直接後果,於是規則系統也理所當然地長成了各自為政的樣子。反過來說,如果我想要一套統一治理的規則系統,就不能只改規則本身,得先改「規則被寫在哪裡、由誰維護」這個溝通結構——這也是後來被稱為 Inverse Conway Maneuver(反向運用 Conway 定律)的做法:先設計你想要的架構,再讓維護方式去配合這個架構,而不是任由既有的維護習慣決定架構長什麼樣。
所以 Ai-agent 的入口設計採用 adapter pattern。每個 AI 有自己的薄 adapter,但真正共用的規則要往 shared core 收斂。
AI client adapter
-> shared generated core
-> skills/INDEX.md
-> selected SKILL.md
-> deterministic scripts
-> artifacts / run-state / memory
root config 只描述各 runtime 的限制與能力。共通規則放在 shared core,可重複程序放進 skills,可驗證的機械動作交給 scripts。這樣做之後,維護 prompt 就不再只是改文字,而比較像在做 configuration management——你是在管理一個溝通結構,而不是管理一堆散落的文件。
後來我把 AI 行為拆成三層
我原本也會直覺地把很多規則塞在入口 prompt 裡,因為這樣最方便。但入口越厚,後面越難維護。只要任務一複雜,AI 就會同時背著太多規則,最後不知道哪一條才是當下最重要的約束。
這其實是同一個問題的另一種樣貌:組織學習理論裡,Chris Argyris 區分過「單迴圈學習」和「雙迴圈學習」。單迴圈學習是發現錯誤後修正行動,但不去質疑那個產生錯誤的假設本身;雙迴圈學習則是回頭修正那個假設或規則本身。我一開始「把規則塞進入口 prompt」的做法,本質上是單迴圈——每次任務出錯就往 prompt 裡加一條補丁,但從來沒問過「這件事本來就不該用 prompt 文字去承載」。真正的轉折,是我開始質疑「規則應該長什麼樣子」這個更上層的假設,而不只是修補症狀。
所以 .claude/ 的協作層被我拆成三段:
commands/ -> Intent layer
agents/ -> Decision layer
skills/ -> Execution layer
commands/ 只做很薄的路由。它不應該理解太多業務邏輯,只要把意圖導到正確入口。agents/ 負責比較像判斷層的工作,例如拆解任務、派工、判斷是否升級或停下。真正保存執行規則的是 skills/。
我後來覺得,skill 不應該只是 prompt template,而應該是一份 executable policy。每個 SKILL.md 都需要明確寫出它吃什麼 input、產出什麼 output、執行前要滿足哪些條件、可以用哪些工具、遇到什麼情況必須停止。
## Interface
### Inputs
### Outputs
### Preconditions
### Tool Permissions
### Stop Conditions
這個 Interface block 讓 AI 的行動邊界變清楚。AI 可以判斷,但不能無限制行動;agent 可以派工,但 skill 才是執行時真正的約束。一旦某個 skill 被選中,它的規則就應該高於 agent 的自由裁量——這是雙迴圈學習落地之後的樣子:不是規則變多,是規則被放在對的層次。
上下文不能每次都全部載入
另一個踩過的坑是上下文膨脹。剛開始會很想讓 AI 讀越多越好,好像只要規則全塞進去,它就會比較穩。但實際上,規則越多,衝突越多,模型也越容易被不相干的內容干擾。
我借用 Herbert Simon 的「有限理性(bounded rationality)」來理解這個設計取捨:人的決策受資訊、時間與計算能力限制;模型雖不是 Simon 原本的研究對象,同樣也不會因為 context window 變大,就保證相關規則都被同等穩定地運用。把所有規則同時攤開,不必然讓判斷更準,反而可能增加衝突與干擾。
所以 Ai-agent 不會讓每次任務載入所有 skills。它先讀短索引,再選最小可用的 skill,最後只讀那份完整 SKILL.md。
read skills/INDEX.md
-> select smallest relevant skill
-> read selected SKILL.md
-> execute by declared interface
我把 skills/INDEX.md 當成 routing table,SKILL.md 當成 policy module,scripts/ 當成 deterministic primitives。這個設計不是為了看起來乾淨,而是為了降低 context bloat、規則衝突與跨 AI 行為漂移——先幫模型把有限的注意力預算,花在真正相關的那一小段規則上。
記憶也需要分層,不然很快會污染
AI 記憶很容易被高估。只要什麼都想記,最後就會變成什麼都不可靠。短期任務狀態、terminal logs、commit hash、一次性的測試成功,如果全都進長期記憶,AI 之後反而會被雜訊拖累。
所以我把記憶分成 canonical source 與 runtime copy。
ObsidianBook / 90_System / AI共用記憶
-> canonical source
-> sync / generate
-> .memoria/shared/
-> runtime memory layer
ObsidianBook 是 source of truth,.memoria/shared/ 是各 AI 客戶端讀取的 runtime copy。這樣做的好處是,長期知識庫不會被短期工作流污染,各 AI runtime 又能讀到一致的工作記憶。
這裡真正重要的是 promotion policy。不是所有事情都應該被提升成 durable memory。真正值得留下的,通常是會改變未來 AI 行為的穩定偏好、可重用的踩坑、source-of-truth decision、專案交接,或已經穩定下來的 workflow contract。
沒有分層時的代價,我們真的付過:六個 repo 同時由我和另一個 AI 協作者維護,兩邊用同一組 git identity,git log 的作者欄看不出是誰做的。曾經同一小時內發生三次,本地已編輯但尚未 commit 的檔案,被對方的 git add -A 掃進它的 commit——內容沒有遺失,但寫好的 commit message 沒送出,改動被歸到不相干的事情底下,事後 git log 完全追不出當初為什麼改。這就是把「暫存區裡還沒外顯的狀態」當成可靠記憶的下場:一旦有第二個維護者同時在動,沒有落地的東西就會被別人的動作悄悄吞掉。
長任務一定要能接回來
做 AI 工作流時,最痛的不是模型失敗,而是任務中斷後不知道怎麼接。尤其當一個任務跨過規劃、改檔、驗證、收尾,還可能中間遇到額度限制或工具失敗,如果狀態只存在聊天裡,下一個 session 幾乎等於重新來過。
所以 ops:sprint-agent 把長任務切成四個階段。
planning -> execution -> verification -> wrapup
每個階段的節奏固定下來:先讀契約,再讓 model-router 決定路由,接著宣告會碰哪些檔案,交給協作者執行,然後跑 gate,通過後 checkpoint,最後產生 handoff pack。
讀契約 -> model-router 決策 -> 宣告檔案 -> collab 執行 -> gate -> checkpoint -> handoff pack
這裡最重要的不是自動化有多炫,而是狀態有沒有落地。.memoria/hot/agent/run-state.json 會記錄 change、goal、phase、chunks、artifacts、events、declared_files、route_decisions、opus_budget、token_ledger、provider_status、downgraded 與 halted。
下一個 agent 不需要完整聊天紀錄。它只要讀 files、run-state 與 handoff,就應該知道任務走到哪裡、哪些 chunk 完成了、哪些檔案被宣告過、目前是否降級、是否因為 breaker 停下。
conversation is interface, not state.
run-state is resume point, not report.
events are observability, not final artifact.
這句話後來變成我設計 AI workflow 的核心判斷。對話只是互動介面,不應該承擔狀態儲存的責任。
能用 script 驗證,就不要靠模型感覺
如果每一層都能自己問 LLM,整套系統很快會變成 recursive agent soup。你會不知道到底是誰做了決策、誰改了狀態、誰應該為失敗負責。
這裡藏著一個很容易忽略的風險:如果驗收的方式是「讓模型自己說完成了沒有」,自我報告就同時成了表現與驗收依據。這符合 Goodhart 定律常見的轉述:「當一個衡量指標成為目標,它就不再是好的衡量指標。」把「模型自評成功」當成 gate,會讓文字上的完成與事情真的完成混在一起;壓力越大,兩者越可能分家。
這不是假設性的風險。有一次跨 repo 的交接文件同時寫了三件事:某分支已有提交、某個服務的檔案已測過數個、另一邊的測試覆蓋率是 100%。重新核對後三件事都不成立——那個分支其實零 commit,宣稱測過的檔案根本不存在,覆蓋率則是行覆蓋 100% 但分支覆蓋只有 98.07%。交接文件寫得完整、語氣確定,讀起來像事實,但文字本身從來不是證據。
所以 scripts/agent-pipeline.sh 被設計成 deterministic mechanics layer。它負責 init、resume、checkpoint、declare、event、route、chunk、gate、breaker、classify、on-fail,但它刻意不呼叫模型。
skill / agent -> orchestration decisions
agent-pipeline.sh -> deterministic mechanics
scripts/lib/*.sh -> reusable primitives
LLM 做判斷與生成,scripts 做狀態變更、schema validation、gate 與 fallback classification。Gate 不相信模型自評,只相信可執行結果。這個分工看起來保守,但它讓整套工作流更像工程 pipeline,而不是一群 agent 在互相猜測誰做得比較好。
多模型不是互聊,而是接力
我現在對 multi-agent 的看法比一開始保守很多。真正有用的不是讓多個 agent 自動聊天,而是讓它們交換可驗收的 artifact。
model-router.sh 做的事情不是永遠找最強模型,而是看任務性質選最高 CP 的路由。大量上下文先交給 Gemini,PM framing、寫作與一般規劃多數時候 Claude Sonnet 就夠,repo edits、tests、coding loop 適合 Codex Plus,高風險架構、root cause 或 final review 才值得短暫動用 Claude Opus;如果任務需要本地、隱私或零額度,就讓 Ollama 成為 fallback。
跨模型接力時,我不希望下一棒收到一整段聊天紀錄。它應該收到一個小而完整的 handoff artifact。
task: "one-line imperative task"
effort: low | medium | high
thinking: true | false
criteria:
- "verifiable done criterion"
files:
- "path/to/source-artifact"
做完之後,也不應該回一篇散文式心得,而是回一份 compact summary。
status: done | partial | failed
result:
- "completed fact"
artifacts:
- "created-or-modified-path"
gaps:
- "remaining issue"
這樣下一棒不是在讀上一棒的情緒與推理,而是在讀任務、驗收標準、檔案與缺口。這才比較接近工程上的交接。
可靠性不是一直跑,而是知道何時停
很多 agent demo 看起來很厲害,是因為它會一直往下做。但真實工作流裡,可靠性不來自一直跑,而是來自知道何時不能再跑。
sprint-agent 裡我放了幾個防線。Planning 階段不能偷寫實作碼,verification 要優先跑 deterministic tests,失敗時不能一律降級,而是要先分類成 retry、switch、halt 或 surface。Opus 與 token 都要有 breaker;如果整段流程曾經 downgraded,wrapup 階段就不能省略高階模型複審。
這些設計不是為了讓系統看起來複雜,而是為了控制 AI workflow 的 blast radius。模型很會補洞,但也可能在錯誤方向補得更完整。所以停止條件必須是一等公民。
Autonomy without gates is unsupervised drift.
這套治理什麼時候是過度設計
這裡要老實說一件容易被忽略的代價:gate、checkpoint、handoff schema、breaker 全部都是額外的處理步驟,而額外的步驟本身也有成本。Donald Reinertsen 在談產品開發流動效率時提醒,佇列與大批次的延遲成本常被低估;如果關卡需要等待別人處理,交接越多,等待時間就可能越長。任務本身很小、風險很低、一次做錯的代價可以忽略時,把它塞進四階段的 planning、execution、verification、wrapup,可能只是在製造延遲,而不是降低風險。
這套治理值得投入,前提通常是:一次交接失敗的代價夠高(會動到真實資料、會影響其他協作者、會需要重新調查才能定位問題),或者同類任務的量夠大(值得攤提設計 schema 與 gate 的固定成本)。反過來,單次、低風險、後果可逆的小任務,直接讓一個 AI 做完就好,硬套完整的 sprint-agent 流程只是把 Reinertsen 說的排隊成本,換成另一種形式的浪費。
環境層和知識庫要分開
Ai-agent 和 ObsidianBook 的邊界也是後來慢慢整理出來的。Ai-agent 是環境層,負責跨機器同步 settings、skills、memory,以及那些在任何 repo 都可能用到的橫向 workflow。ObsidianBook 是應用層,負責知識庫、INGEST、COMPILE、WRITE、PUBLISH,以及 AI 共用記憶的 canonical source。
我的判斷方式很簡單。如果一個 skill 在任意 git repo 都能合理使用,例如寫文章、code review、commit、model routing,它應該放在 Ai-agent。如果它依賴 vault 裡的語義,例如 00_Inbox、30_Sources、20_Knowledge、概念、問題、知識圖譜,那就應該留在 ObsidianBook。
兩者之間只透過 vaults.json、to-obs、from-obs 做最小橋接。橋接可以讓對話寫入 vault,也可以讓 AI 唯讀搜尋 vault,但它不應該把整個 vault domain logic 搬進環境層。這個邊界劃分本身,其實也是 Conway 定律的另一次應用:兩種完全不同性質的維護節奏(環境層要跨機器同步、知識層要人工審核)如果混在同一套治理結構裡,遲早會互相干擾。
我會把它放回交付現場看
Ai-agent 想解的不是「我有很多 AI 可以用」,而是把 AI 工作流裡最容易失控的部分工程化:上下文、能力、程序、狀態、交接、驗證、成本與停止條件。
如果 prompt collection 是第一階段,AI execution system 會是下一階段。真正有價值的不是讓模型一直往下跑,而是讓每次 AI 行動都能被定位、被限制、被驗證、被交接,必要時還能停下來。
我現在比較會把它放回交付現場看。複雜服務能不能做成,不只看某個人能力多強,而是看需求、設計、開發、驗收和維運之間有沒有清楚的契約。Ai-agent 只是把這套交付思維搬到 AI 工作流裡:把隱性的判斷寫成 skill,把容易失真的交接寫成 artifact,把看似順利的產出放進 gate 裡檢查。
所以我現在判斷一個 AI workflow 是否成熟,不會先看它用了多少模型,而會看幾件事:prompt 有沒有變薄,contract 有沒有變厚;agent 能不能判斷,但不會無限制行動;能不能用 script 驗證,而不是靠模型感覺;多模型是不是在接力,而不是互相聊天;狀態是不是落地,而不是藏在對話裡;以及,這套治理的成本,是不是配得上它要防的那種失敗。
AI Agent 的下一步不是更會聊天,而是更像可治理的執行環境——但治理本身也要付出代價,值不值得,要看任務規模,不是看它能不能做到。
參考結構
Ai-agent
├── root AI adapters
├── docs: AI-ENTRYPOINTS / SKILL-CONTRACT / WORKFLOW-ARCHITECTURE / AGENT-HANDOFF-STANDARD
├── skills: INDEX.md + domain SKILL.md
├── scripts: agent-pipeline.sh / model-router.sh
├── schemas: run-state.schema.json
└── .memoria: shared / hot / cold