最近花了幾個通宵重構手上 AI Agent 的 Skill 系統,過程中踩了一些很噁心的坑,也因此想通了一些架構上的事情。這篇不是教學文,比較像是一份踩坑實錄加上事後的設計反思。
先說背景
我日常用 AI Agent 處理不少自動化任務——晨報整理、技術新聞摘要、投資資訊彙整等等。這些任務原本是用一個「大 Skill」統包處理,裡面塞了十幾個報告模板、觸發邏輯、還有建立新報告的流程。
聽起來很方便對吧?一個 Skill 搞定所有事。
然後災難就開始了。
第一個坑:併發限制的靜默丟棄
事情是這樣的。我有大約十個定時任務,分散在早上不同時段執行。原本的做法是一個排程觸發後,由一個 dispatcher 去 spawn 多個 sub-agent,每個負責一份報告。
結果有些報告就是不會產出。沒有錯誤訊息、沒有 log、就是靜悄悄地消失了。
查了好一陣子才搞懂:sub-agent 有併發上限,超過的 spawn 請求會被靜默丟棄。不排隊、不報錯、不通知。就像你在餐廳點了六道菜,廚房只收到四張單,但沒人跟你說另外兩張掉了。
這個行為設計上可能有它的道理(避免無限排隊拖垮系統),但對使用者來說真的很陰險。你以為任務都跑了,其實有些根本沒啟動。
解法:每個報告獨立跑,不靠 dispatcher。
既然併發 spawn 不可靠,那就不要 spawn。每個報告各自是一個獨立的排程任務,各自啟動一個隔離的 session 來執行。彼此不依賴、不共享、不搶資源。
1 | # 之前(災難版) |
代價是排程設定變多了,但換來的是每個任務都保證會跑。這個 trade-off 完全值得。
第二個頓悟:讀寫分離,Skill 也要
解決併發問題後,我開始重構 Skill 本身的結構。原本那個大 Skill 有個根本性的問題:執行邏輯和建立邏輯混在一起。
什麼意思?同一個 Skill 檔案裡,既有「如何執行報告」的指令,也有「如何建立新報告模板」的流程。當排程觸發時,Agent 讀到的 Skill 裡包含了建立流程的描述,偶爾就會搞混——明明該去執行現有報告,結果跑去嘗試建立新的。
這跟軟體工程裡的 CQRS(Command Query Responsibility Segregation)其實是同一個道理:
- 執行 Skill(Read/Query):排程專用,只負責讀取模板、產出報告。SKILL.md 裡零建立邏輯,Agent 看到的指令就是「找到模板 → 執行 → 輸出」,沒有任何分岔。
- 建立 Skill(Write/Command):手動觸發,只負責新增報告模板。有完整的互動流程、欄位驗證、模板生成。
兩個 Skill 完全隔離。排程觸發的 Agent 永遠不會看到建立流程的描述,自然不會走歪。
flowchart LR
subgraph 排程觸發
C1[Cron Job] --> E1[執行 Skill]
E1 --> R1[讀取模板]
R1 --> O1[產出報告]
end
subgraph 手動觸發
U1[使用者] --> E2[建立 Skill]
E2 --> R2[互動問答]
R2 --> O2[新增模板]
end
這個設計看似多此一舉——不就是拆成兩個檔案嗎?但對 AI Agent 來說,context 裡有什麼,就可能做什麼。減少不相關的指令,等於減少 Agent 走歪的機率。
第三個發現:讓 Agent 自己學
這是最讓我興奮的部分。
傳統的做法是:Agent 犯錯 → 人類修正 → 人類事後去更新文件 → 下次 Agent 才不會再犯。問題是「人類事後去更新文件」這步,十次有八次會忘記。然後同樣的錯誤就會一犯再犯。
新的做法是把「自我學習」寫進 Agent 的核心行為規範裡:
執行任何任務時,如果收到人類的修正或回饋,當下就更新對應的參考文件。不需要人類額外說「記下來」,修正本身就是更新的觸發條件。
具體的判斷邏輯:
- 如果修正的是某個 Skill 內的寫法慣例(比如「Dialog 不要直接用 antd Modal,要用封裝好的元件」)→ 更新那個 Skill 的 reference 文件
- 如果修正的是專案知識(比如「這個 API 的回傳格式其實是⋯⋯」)→ 更新專案的 knowledge 文件
- 如果修正的是通用行為(比如「回信不要亂保證時間」)→ 更新行為規範
flowchart TD
A[收到人類修正] --> B{修正類型?}
B -->|Skill 寫法慣例| C[更新 Skill Reference]
B -->|專案知識| D[更新 Knowledge 文件]
B -->|通用行為| E[更新行為規範]
C --> F[下次執行自動套用]
D --> F
E --> F
這樣做的效果很明顯:同樣的錯不太會犯第二次。Agent 每次被修正後,知識庫就更完整一點,下次遇到類似情境就會做對。
說實話,看著 Agent 自己更新文件的時候,有一種奇妙的感覺——它不是在「學習」,更像是在「長記性」。
第四個教訓:文件也要讀者分層
最後一個心得跟文件撰寫有關。
在重新設計技術文件的結構時,我意識到一份文件通常有很多種讀者:架構師想看全局設計、PM 想看驗收條件、測試想看操作流程、開發想看 API 規格、AI Agent 想看機器可讀的結構化資訊。
以前的做法是全部混在一起,每個人都要自己從頭到尾掃一遍,找到跟自己相關的部分。這很浪費時間,對 AI Agent 來說更是災難——它會把所有資訊都當成同等重要,結果什麼都想處理。
新的做法很簡單:用分隔線把文件分成上下兩半。
- 分隔線上方 = 非技術內容(需求描述、驗收條件、操作流程圖)
- 分隔線下方 = 技術規格(資料模型、API 設計、目錄結構、實作細節)
PM 看到分隔線就可以停了。開發通常直接跳到下半部。AI Agent 可以根據任務類型決定要讀哪一段——如果是做 code review 就專注下半部,如果是寫測試案例就專注上半部。
這不是什麼革命性的創新,就是很基本的資訊架構。但在 AI Agent 的 context 管理上,這種分層特別有價值,因為你能餵給 Agent 的 token 數是有限的,讓它只讀需要的部分,效率差很多。
整體回顧
把這幾天的重構經驗整理一下:
- 併發控制:不要假設 spawn 一定成功,尤其是有上限的系統。寧可多跑幾個獨立任務,也不要靠一個 dispatcher 統包
- 讀寫分離:AI Agent 的 Skill 跟程式碼一樣,職責要單一。執行就只管執行,建立就只管建立
- 自我學習:把「收到修正就更新文件」寫進 Agent 的行為規範,比事後人工更新可靠一百倍
- 讀者分層:文件不是寫給所有人的,用結構化的方式讓不同讀者(包括 AI)快速找到需要的資訊
這些原則其實都不新。併發控制、讀寫分離、自我修正、資訊架構——都是軟體工程裡老掉牙的概念。但當你把它們套用到 AI Agent 的設計上,會發現意外地契合。
畢竟,好的架構不分物種。不管是人寫的程式還是 AI 跑的工作流,乾淨的邊界、單一的職責、自動的回饋迴路,永遠是對的方向。
如果你也在折騰 AI Agent 的自動化流程,希望這篇踩坑紀錄能幫你少走一些彎路。畢竟我的黑眼圈已經替你扛過了 😂