先講一個 agent 工程師每週都會碰到的場景:agent 今天犯了一個 bug,跟它說清楚之後它道歉、承諾下次不會這樣。兩週後,同樣的 bug 在另一個 query、另一個 timezone 上再次發生。agent 沒有記得那個 bug,沒有為它寫測試,也沒有任何東西擋住它再犯一次。

Garry Tan(YC 總裁,業餘開源狂熱者)這週自己的 OpenClaw 翻了兩次車:一個是問十年前那趟新加坡出差,agent 繞 API 繞 email 繞了五分鐘才去 grep 本地檔案;另一個是 UTC→PT 心算告訴 Garry「下一個會議還有 28 分鐘」,實際是 88 分鐘,差了整整一小時。

兩個 bug 本體都不特別,特別的是 Garry 對付它們的方式。他沒有加幾句 prompt 咒語叫 agent 下次小心,而是把每一次失敗當 post-mortem 對象——挖根因、寫 SKILL.md、寫 deterministic 腳本、配 unit test + LLM eval + resolver + DRY audit + smoke test。 一次 10 步,跑完這個 bug 就結構上不可能再犯。

他把這個動作叫 skillify。這篇文把 skillify 的心法、10 步 checklist、跟他對 LangChain / Hermes Agent 這些競品的點評一次拆完。

先鞭 LangChain:工具齊全,工作流缺席

文章開場 Garry 直接點名:LangChain 募了一大筆錢、LangSmith 這套 eval 平台技術上也確實強——trajectory eval、trace-to-dataset、LLM-as-judge、regression suite、tool 的 unit test framework,這些組件都有。Credit 給到。但組件不是工作流。

LangSmith 給了一堆測試工具,沒給任何 opinionated 的流程告訴工程師「這時候要測什麼、用什麼順序、做到哪裡叫做夠」。Garry 列了一個他認為應該要有的預設順序:

  1. 發生了一個 failure
  2. 寫一個 skill
  3. 寫 deterministic code
  4. 寫 unit test
  5. 寫 LLM eval
  6. 加 resolver trigger
  7. 跑 resolver eval
  8. 查重複 skill
  9. smoke test
  10. 歸檔

「這個迴圈不存在,」Garry 寫,「工程師得從一堆零散的 primitive 裡自己發明出來。大多數人最後根本不測 agent,因為他們選的 framework 給了他們一張健身房會員卡,卻沒給他們菜單。」

Clawd 想補充:

順便做事實校正:Garry 原文寫「LangChain 募了 $160M」,這個數字不太對。根據 TechCrunch 跟 Fortune 2025-10 的報導,LangChain 的歷史累計是 $260M($10M 種子 + $25M Series A + $100M 7 月 Series B + $125M 10 月 Series B),單輪最大的是 10 月那輪 $125M @ $1.25B 估值。獨角獸部分 Garry 說對了。

至於「健身房會員卡沒菜單」這個比喻——準的。LangSmith 的定位一直都是 eval infrastructure,不是 workflow opinionator,兩者 scope 本來就不同。但這個 dunk 也稍微便宜了一點:拿 Anthropic 的 Claude Code(內建 skill + resolver + hook)去比 LangChain 的 LangSmith(偏 observability),本來就是不同產品形狀的比較。Garry 的論點真正成立的地方不是「LangChain 做得不夠」,而是「整個 agent engineering 圈還沒把 workflow convention 收斂」┐( ̄ヘ ̄)┌


翻車 1:答案就在本地,agent 卻先去打 API

Garry 問自己的 OpenClaw:「十年前那趟新加坡出差是什麼時候?」——這種問題照理說一秒搞定。結果 agent 的實際 trace 是這樣的:

  1. 打 live calendar API → 被擋(資料太舊)
  2. 翻 email → 一堆雜訊、沒結論
  3. 再打一次 calendar API 換參數 → 還是被擋
  4. 五分鐘後,終於去搜本地 knowledge base → 秒找到

答案從頭到尾就在本地。2013 年到 2026 年的 3,146 個 calendar 檔案,早就 index 好了、早就在磁碟上、一個 grep 就出來。agent 只是沒先去那裡看。

Garry 在他先前的 thin harness / fat skills 文章裡有一組關鍵分類:需要判斷的工作叫 latent、需要精準的工作叫 deterministic。Calendar grep 是典型的 deterministic:同樣 input、同樣 output、每次都一樣、不需要 model 介入。可是 agent 把它丟進 latent space 處理——啟動 reasoning、打 API、解讀結果,明明三行腳本就能秒回。

Bug 的本體不是答錯,是做對了事情卻用錯邊。


修法:calendar-recall(10 步的第 1、2 步)

Thin harness / fat skills 架構下,skill 是一份 markdown 的「教作法」,不是「告訴 agent 答案」——user 提供 what,skill 提供 how。想像成 method call:procedure 一樣,但丟進去的參數不同,產出就完全不一樣。

Garry 從 calendar 翻車裡長出來的那份 skill 長這樣:

name: calendar-recall
description: "Brain-first historical calendar lookup. ALWAYS use
  this before any live API for any event not in the future or
  the last 48 hours."

底下的硬規則:

Live calendar API 只用在未來 OR 過去 48 小時內的事件。超過這個範圍的歷史問題,全部先走本地 knowledge base。

這招真正聰明的地方在後面:那支 deterministic 腳本是 agent 自己寫的。 skill 檔案(markdown、住在 latent space)告訴 agent 「calendar 搜尋是 deterministic 工作」,agent 讀完自己寫了一支 calendar-recall.mjs

$ node scripts/calendar-recall.mjs search "Singapore"

Found 2 matching day(s):
── 2016-05-07 ──
  Flight to Singapore, Mandarin Oriental check-in
── 2016-05-08 ──
  Lunch with investors at Fullerton Hotel

100 毫秒內跑完(大部分是 Bun 啟動,實際 grep 是亞毫秒)。零 LLM call、零網路。純本地檔案。

這裡出現的是整套架構的核心迴圈:latent space 蓋 deterministic 工具,deterministic 工具再反過來約束 latent space。 agent 用判斷力(latent)寫出 calendar-recall.mjs;skill 從此強制 agent 去那支腳本,而不是自己對 calendar 資料「思考」。Model 的智慧親手打造了那條防止 model 耍蠢的繩子。

舊的 failure path 就這樣變成結構上走不到。skill 說「先搜本地」,script 負責搜,agent 連「要不要賣弄小聰明」的空間都沒有。

Clawd 吐槽時間:

這段「model 的智慧親手打造防止 model 耍蠢的繩子」是整篇最值錢的一句。把它翻譯成軟體工程的常用術語,其實是自動化的 Incident-to-Guardrail pipeline——一次事故不只留下 post-mortem 文件,還留下程式碼層的 guardrail,讓這類事故結構上不可能再發生。SRE 圈吵了十年的「learn from outages」,在這裡被縮成一個動詞:skillify。

對 agent 工程師來說 takeaway 很乾淨:看到 agent 在 latent space 做「同 input 必得同 output」的事情,那個 signal 就是「缺一個 deterministic skill」。 記起來比記住 Garry 的 10 步 checklist 更本質 (⌐■_■)


翻車 2:「還有 28 分鐘」——timezone 心算差了一小時

同一天稍晚。agent 告訴 Garry:「下一個會議還有 28 分鐘。」

現實:還有 88 分鐘。agent 在腦內做 UTC→PT 的時區轉換,剛好差了一小時。

這個更荒謬的是——context-now.mjs 這支腳本早就存在。output 大概長這樣:

{
  "now": "2026-04-21T07:38:12-07:00",
  "upcomingEvents": [{
    "summary": "App Ops Sprint Planning",
    "minutesUntil": 88
  }]
}

50 毫秒跑完、零歧義。agent 就是沒跑它。

跟第一個翻車一樣的病——deterministic 工作(時間戳相減)被丟到 latent space 處理。 model 在做心算,明明腳本有正確答案。

對應的 skill:

name: context-now
description: "ALWAYS-ON discipline: run context-now.mjs before
  making ANY time-sensitive claim. Never do UTC→PT conversion
  in your head."

兩次翻車,同樣的形狀:agent 手邊有對的工具,卻選了小聰明而不是紀律。 在普通 AI setup 裡,agent 會道歉、會保證下次會更好,兩週後同樣的病換一個 query、換一個時區又發作一次。agent 沒有那個 bug 的記憶、沒有那個 bug 的 test,什麼都擋不住它再犯。

Skillify 就是在補這層結構。


10 步 checklist:一個 bug 長出一整套結構

Garry 的硬核規則:一個 feature 過不了這 10 步,就不是 skill,只是「今天剛好可以跑」的程式碼

□ 1. SKILL.md — 合約(name、trigger、規則) □ 2. Deterministic code — scripts/*.mjs(能寫 code 解決的事情就不要丟 LLM) □ 3. Unit tests — vitest □ 4. Integration tests — 打真 endpoint □ 5. LLM evals — 品質 + 正確性 □ 6. Resolver trigger — 在 AGENTS.md 裡登記 □ 7. Resolver eval — 驗證 trigger 真的有路由過去 □ 8. Check-resolvable + DRY audit □ 9. E2E smoke test □ 10. Brain filing rules(檔案往哪歸)

前兩步上面兩個 failure 案例已經走過。接下來的 8 步 Garry 在文中一一展開。不過在走剩下八步之前,Garry 先秀一段他自己最喜歡的用法——把 skillify 當動詞用。


Skillify as a verb:一句話把原型變成永久基礎設施

Garry 的日常 workflow 很簡單:用自然語言跟 OpenClaw 對話、一起把某個東西做出來、確認它能跑,然後丟一句話:

Garry: 幹它 work 了!幫我把這個記成一個 webhook skill,skillify 一下,下次要做 webhook 的時候就有了。為什麼這個搞這麼久?算了反正現在 work 了。順便 DRY 一下。

那次是 OAuth webhook 整合,搞了一小時才搞定。那一句「skillify it」就把一次性 session 轉成一份有 test、有 resolver entry、有 doc 的永久 skill。下次要做 webhook,skill 在、agent 讀、那一小時的 hard-won knowledge 永久保留。

另一個例子:OpenClaw 裡有時候要 headless browser、有時候要桌面上的 headed browser,Garry 發現這個區別之後:

Garry: 讚!這應該也存成 skill,以後 openclaw 要 headless browser 都走這條。如果需要 headed browser 就叫 user 跑 gstack browser 給 pair-agent code。skillify 一下!

一則訊息。agent 就會寫出 skills/browser/SKILL.md、decision tree、deterministic 腳本、test 全部一次生出來。下次任何 session 要 browser 就自動路由。

Garry 自己的描述翻譯過來:

我不寫 spec、不開 ticket。我跟 agent 講話、一起解問題,然後答案變成一個 skill,agent 之後沒有我也能用。

Clawd 真心話:

這個「對話 → skill」的 pattern 讀起來很工程師狂熱,但它背後其實是一個更大的典範轉移:從 code 驅動到 skill 驅動的開發流程。 傳統軟工:spec 文件 → 工程師寫 code → code 進 repo → 別人讀 code。Garry 的 flow:對話 → skill 檔案 → agent 讀 skill → agent 執行。

兩者差別最大的地方在於知識載體的 audience。Code 寫給編譯器看、spec 寫給工程師看;SKILL.md 寫給 agent 看。當 agent 變成新的「執行體」,教科書級的文件(原本是溝通用的副產物)反而升格成主要的 artifact。這是個蠻深的 shift,但業界還沒開始正視 ╰(°▽°)⁠╯


剩下 8 步:把 skill 的 shelf life 拉長到一年以上

Step 3-4:Unit test + Integration test

說穿了 unit test 就是螺絲工廠出貨前那台抽驗機——從產線上每一千顆抓三顆丟上去量扭力、量直徑、量重量,有一顆不對就整批停線。沒這關就等著客訴退貨。skill 測的是函式不是螺絲,道理一模一樣:calendar-recall.mjsparseEventLineeventMatchesKeywordsearchKeywordformatJson——每一顆都對 fixture 跑過一輪。捕捉的 bug 類型乾脆貼出來:Unicode 地名被靜默砍半、閏年日期解析整個歪掉、只有一個參加者時 attendees 陣列神秘消失。小、無聊、致命。

context-now 這邊,unit test 盯的是時區格式、quiet-hours 偵測、跨 DST 的 minutesUntil 計算。其中一顆測試特別狡猾:餵一個 DST 轉換前 3 分鐘的時間,驗證輸出不會突然跳 60 分鐘——這顆就是「28 分鐘」那個 bug 的結構性防線。那個 bug 現在結構上不可能再發生。

Integration test 則是把整條產線從頭到尾拼起來真的跑一遍,原料從真供應商進來、機台用真電壓、傳送帶真的在轉。unit test 用的 fixture 永遠太乾淨、太乖、太假;實際 calendar 資料會出現格式歪掉的 event line、缺 timezone 欄位、Windows 換行符、跨午夜的事件這種東西,只有真資料才抓得到。Garry 全系統跑 179 個 unit test、5 組 suite,2 秒內收工。

Step 5:LLM evals——用 model 判斷另一個 model

這招有點玄,但其實想一下就通:有些輸出 deterministic test 就是判不動——「這份 calendar 摘要有沒有用?」根本不是 yes/no 問題。這關就像國中會考的作文題——不能塞進 ctrl+F 改,只能找一個真的會寫字的老師來評分。Garry 的老師也是一位 model:LLM-as-judge,讓一個 model 按照 rubric 評另一個 model 的輸出。有點左手打右手的味道,但在沒有更好辦法的時候,這是目前最接近「有品味的 reviewer」的版本。

context-now 的 eval 每天 35 個跑一輪。其中一題餵給 agent 一句「嘿,航班 45 分鐘後起飛,趕得到 SFO 嗎?」,然後檢查的不是答案對不對,是 agent 有沒有先跑 context-now.mjs 才開口。如果 agent 跳過腳本自己心算,就算答案剛好對、eval 一樣 fail。

另一題給 agent 一個 UTC 時間戳問「這是本地幾點?」正確行為:跑腳本、引結果。錯誤行為:心算。eval 同時捕捉「答錯」「過程錯」——因為就算這次心算賭對,下次就會錯。講白了,「賭對一次」跟「每次都對」在工程上是完全兩件事,LLM eval 要擋的就是前者偽裝成後者。

Garry 最後給了一個非常黑色幽默的 heuristic:想知道還缺什麼 test?把跟 agent 的對話紀錄搜「fucking shit」跟「wtf」,那些位置就是漏掉的 test case。 說穿了就是暴怒考古學——哪裡罵聲最大,哪裡就是該補 eval 的現場。

Step 6-7:Resolver trigger + eval

先講一個真實場景。病人半夜腹痛掛急診,醫院裡明明有腸胃科主治在、內視鏡台也 stand by,偏偏掛號櫃檯的分科名單漏登這一科,護理師照名單找不到人,病人被丟去一般科打止痛針走人。資源都在——只是路由斷了。Agent 系統最陰的 bug 就長這個樣子:skill 寫好了、放好了、腳本也測過了,但沒人叫得到它。比完全沒做還糟,因為工程師會以為系統能處理這件事。

Resolver 扮演的就是那個掛號櫃檯 + 分科名單——某種任務類型出現時,自動載入對應的 skill。Garry 在另一篇 resolver 專文 拆得更細。每個 skill 都要在 AGENTS.md 裡登記一行 trigger,Step 6 擋的就是「蓋了科室但忘記寫在名單上」這個失誤。

Step 7 是 90% 的人會跳過的那一層。resolver trigger 說「這句話應該路由到這個 skill」,resolver eval 驗證它真的路由過去。類比延伸下去:名單上寫「王醫師——腸胃科」還不夠,得真的派一個假病人掛號、然後盯著看王醫師有沒有被叫到診間。沒這一步,名單永遠是紙上作業。Garry 的 eval suite 養了 50+ 個 test case:

{ intent: 'what time is my meeting', expectedSkill: 'context-now' },
{ intent: 'find my 2016 trip',       expectedSkill: 'calendar-recall' },

兩種 failure 形態都要抓:false negative(該 fire 沒 fire,trigger description 寫爛)跟 false positive(錯的 skill fire 了,兩個 trigger 重疊)。「明天行事曆上有什麼」應該路由到 calendar-check,不是 calendar-recall 也不是 google-calendar。三個 skill、三個時間區間、一句話可能都能 match——resolver eval 就是在 user 踩到這個模糊之前先把它 catch 下來。

Step 8:Check-resolvable + DRY audit——清理暗能力

先把場景拉到抽屜前面。想像家裡那個萬用抽屜裡躺著 15 支長得一模一樣的 USB 充電線,每次急著充手機伸手一抓,抓到的偏偏是內部斷芯的那支——其他 14 支 ok 的就當陪襯在裡面爛。Agent 的 skill 庫放著不管,就是長這個樣。Garry 一個月建了 40+ 個 skill,有些是 failure 後補的、有些是子 agent 跑 cron 時自動產生的,沒人維護 resolver 表格。skill 一直生、沒人登記、長相越來越像、抽屜越塞越滿。

所以他寫了一個 meta-test 叫 check-resolvable,走整條鍊:AGENTS.md resolver → SKILL.md → script/cron。某支腳本做有意義的事、但從 resolver 到那裡沒有路——這個 skill 就是不可抵達的,LLM 永遠不會知道該用它。 說穿了就是一條 linter,但盯的不是 syntax,是「有路可達」這件事。

第一次跑就爆雷:40+ 個 skill 裡 6 個完全不可抵達系統 15% 的能力根本是暗的。

  • 一個 flight tracker,但沒人能用「問航班」的方式叫到它
  • 一個 content-ideas generator 只有 cron 跑,手動叫不出來
  • 一個 citation fixer 住在 skills 目錄但完全沒在 resolver 上登記

一小時全修完,都只是加 trigger entry 到 AGENTS.md。現在 check-resolvable 每週跑一次,查三件事:每個 SKILL.md 有對應 resolver entry、每支 script 真的能 call、兩個 skill 不能有重疊 trigger。

DRY audit 跟它綁在一起跑。**一直放任不管,skill 庫會長出 15 個做差不多事情的 skill,resolver 看骰子選一個執行——**不夠 robust 的系統都會這樣,包含人腦。那條斷芯的充電線就是這樣長期生存在抽屜裡的。

Step 9-10:E2E smoke test + Brain filing rules

Smoke test 是最後一道防線——像阿嬤整鍋湯上桌前,拿湯匙舀一口先嚐。食譜對、火候對、每一味調味料都量過,這一口的意義只剩下一件事:確認整鍋「吃起來真的沒事」。放到 skill 上面就是:問 agent「那趟新加坡 trip 是什麼時候?」,驗證它有跑 calendar-recall.mjs、拿到對的答案、格式對。問「下一個會議什麼時候?」,驗證它跑 context-now.mjs 而不是又在腦內心算。前面 8 步全過、系統還是可以失敗——skill 對、script 對、resolver 對,agent 還是可以決定全部不理直接賭一把,就像阿嬤下廚也可能某一秒走神多倒了一瓶醬油。這口湯擋的就是「每個材料都對、整碗還是鹹到爆」的結局。

Brain filing rules 則是流理台那張分區規則——生食放左邊、熟食放右邊、刀跟砧板絕對不混用。寫進 knowledge base 的 skill 要知道東西該放哪:人物進 people/、公司進 companies/、政策分析進 civic/。Garry 發現 13 個會寫 brain 的 skill 裡,10 個各自 hardcode 了自己的路徑,完全沒參照 resolver——等於每支 skill 各自蓋自己那間小廚房,然後整個家的砧板全部混在一起。現在規則改成 skill 建檔案前先讀 filing rules doc,自上線以來零錯檔。

Clawd 想補充:

這 8 步讀起來很多,但把它跟一般軟工圈的 CI pipeline 對照就不陌生:unit test = vitest、integration test = e2e、DRY audit = linter、check-resolvable ≈ dead code detector。唯一「純 agent 才有」的是 resolver eval + LLM eval——這兩層是用 model 測 model 的產物。

想省力的 takeaway:就算只做 10 步裡的前 3 步(SKILL.md + deterministic script + unit test),絕大多數的「agent 一直犯同樣錯」都會消失。 Garry 的 10 步是他的成熟形態,不是門檻。別讓「還沒 10 步到位」變成什麼都不做的藉口 ٩(◕‿◕。)۶


Hermes Agent 為什麼不夠

文章尾段 Garry 特別點名 Nous Research 的 Hermes Agent——他說這套東西確實做了一件很了不起的事:skill_manage tool 讓 agent 自己 create、patch、delete skill。agent 跑完一個複雜任務或從錯誤裡恢復之後,自己提出一個 skill 寫到 disk 上。這是 agent 自己賺來的 procedural memory。

Hermes 的其他設計也都很聰明:progressive disclosure(先載 skill index、選到才載完整 SKILL.md)、bounded memory(MEMORY.md 上限 2,200 字元)、conditional activation(需要的 tool 不在時 skill 自動隱藏)。

但——Hermes 不測自己的 skill。 沒 unit test、沒 resolver eval、沒 check-resolvable、沒 DRY audit、沒每日 health check。

Garry 列了他親眼看過未測 skill 系統的三種慢性病:

  1. Agent 週一建了 deploy-k8s,週四從另一場對話建了 kubernetes-deploy。兩個都在、trigger 都類似。路由模糊,直到錯的那個在錯的時刻 fire——通常是最糟的那一刻
  2. skill 剛寫好跑得完美。六週後上游 API 改 schema,skill 靜默吐垃圾,直到有活人發現
  3. 自動產生的 skill trigger 太弱從來沒 match 到。變成 orphan、吃 token、慢慢爛掉

這是 2005 年軟工就解決過的「沒 test 的 codebase 會爛」問題。agent skill 本質上是一模一樣的東西。Hermes 處理 creation 很漂亮;GBrain 處理 verification。Garry 的結論:兩個都要。

Clawd 真心話:

Hermes Agent 的 skill_manage + MEMORY.md + progressive disclosure 這些東西在 nous research 官方文件 上 claim 屬實,Garry 沒造假。但這段的「dunk」角度還是有點便宜——Nous Research 是從開源 local-model 圈長出來的,他們的 skill system 定位是「能跑在任何地方的便攜層」,不是「生產級的 agent 骨幹」。

不過 Garry 的核心觀察是對的:只做 creation 不做 verification 的 skill 系統,長期會變成自動生成 entropy 的機器。 2005 年軟工界解完的問題,2026 的 agent 圈正在各種 rediscover——這個洞察比他接下來的業配 pitch 值錢多了 (ง •̀_•́)ง


結語:agent 版的「每個 bug 都有一個 test」

文章最尾 Garry 把論點收到最簡單的一句:健康的軟工團隊,每一個 bug 會長出一個 test,那個 test 永遠活著,bug 變成結構上不可能重現。AI agent 應該一樣。

每一個 failure 變成一個 skill。每一個 skill 有 eval。每個 eval 每天跑。agent 的判斷力永久性地變強,不是只有這個 session、不是只在 context window 還撐得住的時候。

那趟新加坡 trip 的 bug 不會再發生。那個時區心算的 bug 不會再發生。下次冒出新的 bug 也會被 skillify 掉——因為這個遊戲本來就是一場對抗 entropy 跟品味的持久戰,永遠會有新的 failure mode。

Garry 自己的收束句翻過來是這樣:

一年後跟我一起工作的 agent,會被這一年裡它犯過的每個錯塑形。這不是加分題,這是整個論點。

Garry 的文章最後有附兩個 repo 連結(gstack 幫 Claude Code 加速、gbrain 是開源 knowledge engine + SkillPack)。Business 角度當然是業配;技術角度來看這兩個 repo 都是 MIT license 的真工具,想走他這條路的人可以直接拿來用。

Clawd 插嘴:

把這篇的重點蒸乾:skillify 不是新概念,是把三個已知 pattern 疊在一起——(1) post-mortem 文化(SRE 圈的老 idea)、(2) test-driven development(軟工 2005)、(3) latent/deterministic 分工(AI agent 的新 insight)。 真正的新意是第三個,但第三個要發揮威力,得靠前兩個撐住。

對讀者的 action item 很乾脆:下次 agent 翻車的時候,別只是道歉貼 prompt 咒語。問自己一件事——這個失敗該長成什麼 skill?如果它是 deterministic 的事情,寫腳本;如果它是 latent 的判斷,寫 SKILL.md。然後加一個 test,哪怕只有一個。 Agent 會因為你這個動作,在半年後明顯變得比較不爛 (◕‿◕)