把「即興組 agent team 寫文章」固化成一個 skill
上一篇文章是我臨時湊一組 agent 寫出來的,寫完才想到該把這套流程存下來。這篇記錄我怎麼把它拆成一個 skill 加七個 custom agent,過程中抓出「規格會偷偷漂移」的設計漏洞,也補上了自己漏掉的架構取捨。
- AI coding
- Claude Code
- Workflow
- Agent
上一篇文章寫完之後,我盯著那篇稿子想了一下:這篇是怎麼生出來的?答案是——我臨時湊了一組 agent,讓它們分工蒐集素材、寫初稿、互相審查,中間再手動修了好幾輪格式跟語氣,最後才 commit。整個流程能用,但完全是即興的,沒有存下來。
會想寫這篇,是因為我不想每次寫文章都重新發明一次這套分工。更精確地說,我不只想存一份 prompt 筆記,而是想把「蒐集素材、寫初稿、多角度審查」這個流程真的變成一個可重複呼叫的工具。
起因:一百多篇筆記,不可能自己一篇篇寫
背景要往前拉一點。過去三個月我用 Claude Code 學 Web 全端轉職,累積下來的學習對話都靠一套 note-record/note-digest 系統存了下來(這套追蹤系統我在另一篇文章寫過)。這些對話跟筆記攤開來讓 Claude 掃過一輪,抓出了一百多篇有潛力寫成 blog 的素材。
一百多篇,不可能自己坐下來一篇篇寫——那份工作量遠超過我願意投入的時間。但轉念一想,我在寫 code 的時候已經全面在用 AI 了,寫 blog 內容沒道理是例外。問題不是「要不要用 AI 寫」,而是「怎麼把這件事做得穩定」。
規劃思路:先手動調,再把調整固化下來
我的規劃分兩層。
第一層,先讓 AI 寫幾篇,我自己手動調整語氣、格式、段落結構這些細節——就像上一篇文章那樣。第二層,再回頭比對「AI 的第一版」跟「我調整過的版本」,歸納出哪些修正是每次都會重複做的,把它們固定下來,不要每次都從一個空白 session、重新下一輪 prompt 開始。
固化的方式,我決定用一個 skill 當 orchestrator,底下掛一組 custom agent。格式規格、語氣指紋、寫作、審查各自拆成獨立 agent,orchestrator 只負責編排執行順序、傳遞產出,不自己動筆。
用工具造工具:建這套 team 本身也是 agent 分工做的
這裡有個遞迴感很重的細節,值得記一筆:建置這組 agent team 的過程,本身就是拆給多個 agent 並行處理的。
大致分工是這樣:
- 一組 agent 並行寫「輸入類」檔案——素材蒐集、style guide 規格;另一組 agent 同時並行寫「審查類」檔案——editor、reader-advocate、citation reviewer、mdx checker。
- 再由一個 agent 統一把所有分工寫成一份 SKILL.md,當作 orchestrator 的編排文件。
- 最後一個 agent 做全篇一致性審查,逐檔比對彼此有沒有互相矛盾的地方。
最後這道一致性審查真的抓到東西:其中一份文件寫「description 可以留空」,另一份卻寫死「description 必填」——兩邊各自為政,沒人注意到彼此打架。用 agent 分工造出來的系統,得再用一個 agent 去抓分工留下的縫,這種「用工具造工具」的感覺,寫的當下覺得挺有意思的。
一段誠實的自剖:orchestrator 還是 agent teams
規劃架構的時候我問了自己一個問題:Claude Code 原生就有 agent teams 這種模式——多個 teammate 各自獨立 context、透過共享 task list 與訊息互相協作,比我這套 orchestrator 更接近「即時協作」。不過這是預設關閉的實驗性功能,得手動開一個環境旗標才會啟用——為什麼我選的是 orchestrator 派 agent 出去做完再彙整,而不是這種模式?
老實說,答案有點難堪:我一開始其實沒有真的把兩條路攤開來比較,就預設選了 orchestrator。理由站得住腳沒錯,但那個「站得住腳」是事後才補上的完整分析,不是一開始想清楚才做的決定。這是我這次覺得該老實記下來的一點——敢承認自己是先做了選擇、後補理由,比假裝一開始就想通了更有價值。
補上的分析大致是這樣:orchestrator 適合「有固定階段順序、上一步的結果明確餵給下一步」的線性流程;agent teams 適合「需要長時間探索、teammate 要即時反應彼此中間發現、甚至可能要中途插話」的協作型任務。寫一篇 blog post——蒐集素材、寫初稿、審查、收斂——本質上就是線性流程,一步接一步,不需要 agent 之間即時交互。所以 orchestrator 是對的選擇。
晚上實測:抓到一個貫穿全場的問題——規格漂移
上午把第一版建完,晚上我實際拿它跑了一輪(就是拿去處理前一篇 worktree 文章那次)。跑完發現一個問題,而且這個問題不是單一 agent 寫錯,而是整套設計裡貫穿好幾個 agent 的共同毛病。
問題就出在這裡:好幾個 agent 原本的做法是「每次重讀當前最新一篇文章,從裡面歸納格式跟語氣該長怎樣」。聽起來合理,其實是個陷阱——這樣一來,規格不是穩定的,而是會隨著每次新寫出來的文章持續漂移。今天寫的文章帶著一點小走樣,明天的 agent 讀到這篇走樣的文章當範本,又生出更走樣的下一篇。規格不會收斂,只會越漂越遠。
修法是做一次徹底的 provider/consumer 分離:把格式與語氣規格「烘死」寫進一個專責 agent(blog-style-guide)裡固定下來,變成全站唯一的權威來源。其他所有 agent——不管是寫初稿的還是審查的——一律只能消費這份規格,不准自己再回頭讀最新文章歸納一份。規格只有一個出處,不會再有第二份野生版本悄悄長出來。
一個具體的自打臉案例:所有指令都標 bash
抓漏過程裡有一個很有畫面感的例子。早期版本裡,agent 對 code block 語言標籤的規則是「所有 shell 指令一律標 bash」——聽起來像是圖方便的通則,實際上是個通則化錯誤。
我平常會在兩種 shell 之間切換:PowerShell 跟一般常見的 bash。這兩種 shell 的指令語法不完全相通——例如設定環境變數,PowerShell 寫 $env:NAME = "value",bash 寫 export NAME=value——照抄錯一邊,指令直接噴錯給你看。而我自己在寫某些指令時,其實是鎖定在特定 shell 下才會用的。如果 agent 硬把這類指令標成 bash,讀者照抄貼到 bash 裡執行,會直接出錯。這不是「哪個 shell 比較潮」的品味問題,而是把「我自己習慣用的環境」當成了放諸四海皆準的預設——正是這次重構最想抓的那類漏洞的縮影。
不只是紙上談兵:真的動了 build gate
先補個背景:每一篇文章都是一個 Markdown 檔案(正確地說是 MDX,但寫法基本上跟 Markdown 一樣),檔案開頭有一段 frontmatter,用來寫 title、date、description、tags 這些欄位的中繼資料。這些欄位該長什麼樣子,我是用 Zod 定義成一份 schema,build 的時候會拿這份 schema 去驗證每篇文章的 frontmatter,格式不對就直接擋下來、不讓它上線。
這次重構也不全是調整 agent 的說明文字。frontmatter 裡的 description 欄位,我把它從選填改成必填非空——這個改動真的動到這份 Zod schema 本身,也就是 build 期會擋文章的那道關卡,不是只改 agent 讀的文件而已。改完我也補了幾個對應的防護測試,確認這條規則真的會在漏填時擋下來,而不是只在 agent 的敘述裡看起來很嚴格。
使用者才是最終決策者:一個我否決掉的提案
重構過程裡也有一次我主動踩了煞車。當時負責審查的一個 agent 順手提案:不如把 tag 的大小寫收斂統一,例如把 AI coding 跟 AI Coding 這類寫法併成一種。我否決了——理由是不該幫使用者過度規範他刻意留彈性的東西。tag 大小寫要不要統一,是我自己的品味決定,不該被一套自動化流程悄悄「幫」我做掉。
目前的執行順序
固化完的 skill,實際跑起來是這樣一條線:
- 收需求:釐清主題,把使用者提供的素材歸類成帶類型的來源——本機檔、GitHub issue/PR、外部連結、或僅 prompt 內容——不預設每一種都一定存在。
- 階段一:並行 spawn
blog-material-researcher(依來源類型讀素材、產出結構化摘要)與blog-style-guide(產出格式與語氣規格,並即時核對 schema 有沒有漂移、slug 有沒有撞名)。 - 階段二:spawn
blog-post-writer,一次把素材摘要、style guide 規格、決定好的 slug/date/檔名交清,直接寫入正式 MDX 檔。 - 階段三:並行 spawn 四個只審不改的 agent,交叉檢查初稿。
- 收斂:orchestrator 親自彙整四份審查清單,用 Edit 套修正,不叫 writer 重寫全文。
- 驗證:跑 schema 驗證,確認 frontmatter 合規、slug 唯一。
- 呈現收尾:向使用者總結成品,不自動 commit。
七個 agent 各自的職責
拆出來的七個 custom agent,職責分工大致是這樣:
| Agent | 職責 |
|---|---|
blog-material-researcher | 依來源類型採對應讀法研讀素材,產出區分「事實 vs 推測」的結構化摘要,只審不寫文章。 |
blog-style-guide | 全站格式與語氣的單一權威來源,規格固定寫死在 agent 內,只做兩項即時核對——比對 schema.ts 有無漂移、掃現有 slug 避免撞名。 |
blog-post-writer | 拿素材摘要+style guide 規格+指定的 slug/date,直接寫入正式 MDX 檔,語氣格式一律照 style guide、不自己歸納。 |
blog-post-editor | 審查 frontmatter 正確性、脈絡流暢度、段落結構、風格一致性(對照 style guide)、事實正確性,只審不改。 |
blog-reader-advocate | 扮演素昧平生的路人讀者,揪出干擾閱讀的專案內部指涉(issue/PR 編號、私有路徑、commit hash 等),只審不改。 |
blog-source-citation-reviewer | 實查外部事實宣稱並補正確來源連結,揪出「把專案特有行為講成業界通則」的句子,只審不改。 |
blog-mdx-convention-checker | 逐項檢查語意化 markdown 慣例——清單、blockquote、站內連結、無 H1、無 JSX、code block 語言標籤,只審不改。 |
四個審查 agent 全都是「只審不改」,這是刻意的設計:改動一律收斂回 orchestrator 這一層手動套用,不讓每個審查 agent 各自去動稿子,避免四個 agent 的修改彼此打架。
回頭看:這篇文章本身就是第一次實測
寫到這裡,這篇文章本身正好是這套 skill 第一次拿來處理「別的主題」的實測——上一篇 worktree 文章某種程度上是建置過程的副產品,這篇才是它蓋完之後第一次被正式派去做原本設計的工作。
我預期接下來會持續用這組 skill 整理筆記,但篩選「哪些主題值得寫」這件事還是我自己來,skill 負責的是把定案的素材拋光成一篇結構完整的文章。品質會不會隨時間穩定,我還沒有把握,得持續觀察生成內容,再決定要不要回頭修 agent 或 skill 本身。
至於 orchestrator 還是 agent teams 這個問題,我現在的判準是:只要任務還是「素材→寫作→審查」這種線性流程,orchestrator 就是對的選擇;哪天真的遇到需要長時間探索、agent 間得即時交互反應的協作型任務,才會認真考慮換一套模式。不是所有多 agent 的問題都該用同一種架構解——選對線性還是協作,比選哪個工具更重要。