LangChain 已經募資 1.6 億美元。開發三年。估值十億美元。他們的測試平台 LangSmith 確實很精巧:軌跡評估、trace 到 dataset 的 pipeline、LLM 擔任評審、回歸測試套件、工具的單元測試框架。該有的他們都有。功過分明。
但擁有零件,不等於擁有實務流程。
LangChain 提供的是測試 工具。它從沒告訴你該測什麼、測的順序為何、或者何時才算完成。
根本沒有一個明確的 workflow 告訴你,照這個順序來:
- 這個錯誤發生了
- 現在寫一個技能
- 現在寫確定性程式碼
- 現在寫單元測試
- 現在寫 LLM 評估
- 現在加入 resolver 觸發
- 現在評估 resolver
- 現在稽核重複項目
- 現在做冒煙測試
- 現在正確歸檔
那個循環並不存在。 你得自己從零散的基礎元件中拼湊出來。大多數 AI 使用者至今仍完全沒在測試他們的 Agent,因為他們選擇的框架,大概只給了他們一張健身房會員卡,卻沒附上訓練菜單。
大多數 AI Agent 的「可靠性」都只是憑感覺。調整提示詞。寫更長的系統訊息。念念「請不要幻覺」的咒語。這些東西,一旦對話變得複雜,功效就會遞減。那些募資數億美元來解決這個問題的框架,只給了你監控儀表板和單元測試輔助工具,然後說了聲「祝你好運」。
我的 Agent 這週搞砸了兩次。這兩次失敗都不能再發生。不是因為我好聲好氣地請求。而是因為我把每次失敗都轉化為永久性的結構修復:一個技能,附帶每天、永遠執行的測試。
我把這個做法稱為「技能化 (skillify)」。一旦你開始使用,你的 Agent 就不會一直重複犯相同的錯誤。以下是它的運作方式。
失敗 1:早就存在資料庫裡的出差行程
我問我的 OpenClaw 關於一次舊的出差,差不多是十年前的事,埋在行事曆歷史的某個角落。很簡單的問題。應該一秒鐘就能解決。
結果 Agent 卻這樣做:
- 呼叫即時行事曆 API → 被封鎖(時間太久遠)。
- 嘗試搜尋電子郵件 → 結果雜亂,沒有決定性證據。
- 用不同參數再次呼叫行事曆 API → 仍然被封鎖。
- 五分鐘後,搜尋我的本地知識庫,立刻找到了答案。
答案一直就躺在我自己的資料裡。橫跨 2013 年到 2026 年,總共 3,146 個行事曆檔案。 已經索引好。已經在本機。只要 grep 一下就有了。
Agent 只是沒有優先搜尋那裡。
在我一直撰寫的架構(thin harness, fat skills)中,需要判斷力和需要精準度的工作之間有個關鍵區別。我稱它們為 潛在 (latent) 和 確定性 (deterministic) 。搜尋行事曆是確定性的。同樣的輸入,同樣的輸出,每次都一樣。不需要模型。但 Agent 卻在潛在空間處理這件事,啟動推理、發送 API 呼叫、解讀結果,而一個三行程式的腳本就能立刻回傳答案。
這就是 bug。不是答案錯了。而是處理的 面向 錯了。
修復方式:calendar-recall(步驟 1 + 2)
在 thin harness / fat skills 中,一個 技能 (skill) 是一個 Markdown 程序,用來教導模型如何處理一項任務。不是做什麼(使用者提供要做什麼)。技能提供的是處理流程。把它想成方法呼叫:同樣的程序,根據你傳入的內容,輸出會截然不同。
以下是這次失敗產生的技能:
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 APIs are ONLY for events in the FUTURE or the LAST 48 HOURS. Everything historical goes through the local knowledge base first.
讓這一切運作的關鍵是:Agent 自己寫了確定性腳本。技能檔案(Markdown,存在潛在空間)告訴 Agent 如何 解決問題。Agent 讀取技能,理解到搜尋行事曆是確定性工作,並產生了一個腳本來處理:
$ 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 呼叫。零網路請求。純本地檔案。
這就是讓整個架構運作的關鍵循環:潛在空間建構確定性工具,然後確定性工具反過來約束潛在空間。 Agent 使用判斷力(潛在)來撰寫 calendar-recall.mjs。現在這個技能強迫 Agent 執行 那個腳本,而不是去推理行事曆資料。模型的智慧創造了約束,防止模型變笨。
舊的失敗路徑在結構上變得無法到達。技能說「先搜尋本地」。腳本執行搜尋。Agent 再也沒機會在這件事上耍小聰明或再次搞錯。
失敗 2:「28 分鐘」(再次步驟 1 + 2)
同一天。Agent 說:「你下一個會議在 28 分鐘後。」
事實:還有 88 分鐘。Agent 在腦中做了 UTC 到 PT 的時區換算,整整差了一個小時。
問題在於,早就有一個腳本(context-now.mjs)可以輸出以下內容:
{ "now": "2026-04-21T07:38:12-07:00", "upcomingEvents": [{ "summary": "App Ops Sprint Planning", "minutesUntil": 88 }] }
程式碼執行時間約 50 毫秒。完全沒有模糊空間。Agent 就只是沒執行它。
跟上次同樣的模式:在潛在空間處理確定性工作(減去時間戳)。當一個腳本就有答案時,模型卻在做心算。
修復方式:context-now,這個技能:
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 設定中,AI 會道歉、保證下次改進,然後兩週後,同樣的事情會在不同的查詢或不同的時區再次發生。Agent 沒有錯誤的記憶、沒有針對錯誤的測試,沒有任何東西能阻止它重複發生。
技能化 就是解方。每次失敗都變成一個技能。每個技能都有測試。這個 bug 在結構上變得不可能重複。
以下是當一個失敗被升級時,我會使用的 10 項檢查清單:
□ 1. SKILL.md — the contract (name, triggers, rules) □ 2. Deterministic code — scripts/*.mjs (no LLM for what code can do) □ 3. Unit tests — vitest □ 4. Integration tests — live endpoints □ 5. LLM evals — quality + correctness □ 6. Resolver trigger — entry in AGENTS.md □ 7. Resolver eval — verify the trigger actually routes □ 8. Check resolvable + DRY audit □ 9. E2E smoke test □ 10. Brain filing rules
一個功能若沒通過這十項檢查,就不是一個技能。它只是今天碰巧能運作的程式碼。
上述兩個失敗已經走過了步驟 1 和 2:撰寫 SKILL.md(合約),然後撰寫確定性程式碼(Agent 建構並使用的腳本)。但在我介紹剩下的八個步驟之前,我想先展示技能化在日常使用中的樣貌,因為它不只是對失敗的反應。它變成了一個動詞。
把技能化當作動詞
對我來說,在建立我的 OpenClaw(和 GBrain)時,這份檢查清單最初只是一個失敗應對協議。後來它變成了我建構所有東西的方式。
以下是我實際的工作流程。我用自然語言跟我的 Agent 對話。我們在對話中一起建構東西。我測試它。它成功了。然後我說一個詞:
Garry:
hot damn it worked. can you remember this as a webhook skill and skillify it, next time we need to do some webhooks? why was this so hard to get right? anyway it's good now. DRY it up too
那是個 OAuth webhook 整合。我們花了一個小時讓它運作。然後「skillify it」把這個臨時性的對話 session 變成了一個持久的技能,附帶測試、resolver 條目和文件。下次我需要 webhook 時,這個技能就存在。Agent 會讀取它。那一小時辛苦獲得的知識就變成了永久資產。
另一個例子。我們發現我們的 container 在某些任務中需要無頭瀏覽器,而在我的桌機上則需要一般瀏覽器:
Garry:
great! so we should actually remember this as a skill whenever anything in openclaw needs a headless browser! and also know that if we need a headed browser we should ask the user to run gstack browser and give us a pair-agent code. skillify it!
一句話。Agent 就寫了 skills/browser/SKILL.md,包含決策樹、確定性腳本和測試。現在每個需要瀏覽器的未來 session,都會自動路由到正確的工具。
或者這個。我注意到 Agent 老是傳 ngrok 連結給我,卻不先檢查連結是否能用:
Garry:
can we make a skill that says whenever you send me a link you have to curl it yourself to make sure the endpoint is open and the tunnel works? skillify it!
還有那個差點讓我錯過會議的行事曆重複預約:
Garry:
Here is one regular skill I need you to write. It's the calendar check skill. Tomorrow I have a double booked 11am. Make a skill, make it deterministic to check these kinds of things.
一句話。程式碼、技能、測試、resolver 條目、可觸達性稽核。整個 10 步檢查清單在一個呼吸間完成。我的 OpenClaw 知道該怎麼做,它確實做了,現在這已經變成一個習慣動作。我已經做了幾十次。我已經無法想像沒有它的生活。
模式永遠相同:在對話中建立原型,看到它成功,說聲「skillify」,原型就變成了永久基礎設施。我不寫規格書。我不開 ticket。我跟我的 Agent 對話,我們一起解決問題,然後解決方案變成一個 Agent 可以永遠使用、不需要我再插手的技能。
這就是那 1.6 億美元框架資金所忽略的。不是測試的基本元件。不是評估工具。而是工作流程。在那個關鍵時刻,當一個人說「那個有用,現在讓它變永久」時,系統確切知道「永久」是什麼意思:SKILL.md、確定性程式碼、單元測試、整合測試、LLM 評估、resolver 觸發、resolver 評估、DRY 稽核、冒煙測試、大腦歸檔規則。十個步驟。一句話。
以下是剩下的八個步驟在實務中的樣子。
步驟 3:單元測試
標準的 vitest。確定性函式,確定性斷言。calendar-recall.mjs 匯出純函式,像是 parseEventLine、eventMatchesKeyword、searchKeyword、formatJson。每個都針對 fixture 資料進行測試:暫存目錄中的合成行事曆檔案、已知輸入、已知輸出。
這類測試能抓到的 bug:parseEventLine 默默丟棄含有 Unicode 字元的地點欄位。dateFromPath 對閏年日期回傳 null。formatJson 在只有一個與會者時省略 attendees 陣列。微小、無聊、但至關重要。如果腳本產生錯誤輸出,技能就會產生錯誤答案,而 Agent 會自信地告訴我錯誤的資訊。
對於 context-now,單元測試驗證時區格式、安靜時段偵測,以及跨越 DST(日光節約時間)邊界的 minutesUntil 計算。其中一個測試輸入一個比 DST 轉換時間早 3 分鐘的時間點,並驗證輸出不會跳躍 60 分鐘。這正是導致「28 分鐘」失敗的那個 bug。現在它在結構上不可能發生了。
我在 5 個測試套件中有 179 個單元測試。它們在 2 秒內執行完畢。
步驟 4:整合測試
這些測試會打到真實的端點和真實資料。calendar-recall.mjs 真的能在真實的大腦 repo 中找到事件,而不只是在測試 fixture 中嗎?當行事曆快取過期或遺失時,context-now.mjs 還能產生有效的 JSON 嗎?整合測試能抓到單元測試遺漏的 bug,因為 fixture 資料太乾淨了。真實資料有格式錯誤的事件行、遺失的時區欄位、使用 Windows 換行符號的行事曆檔案、跨越午夜的事件。
規則是:如果你發現自己在手動檢查腳本是否在真實資料上做了正確的事情,那麼那個檢查就應該變成一個整合測試。
步驟 5:LLM 評估
這裡開始變得有趣。有些輸出需要判斷力來評估。「這個行事曆摘要有用嗎?」不是一個腳本能回答的是非題。所以我使用 LLM 擔任評審:一個模型根據評分標準評估另一個模型的輸出。
對於 context-now,每天執行 35 個評估。其中一個評估餵給 Agent 一條訊息,像是「hey, 我的航班大約在 45 分鐘後起飛,我來得及趕到 SFO 嗎?」,然後檢查 Agent 在回答前是否執行了 context-now.mjs,或者試圖用心算。如果 Agent 上鉤並自己計算時間,評估就會失敗。
另一個評估給 Agent 一個 UTC 時間戳,並問「那個時間對我來說是幾點?」正確的行為是執行腳本並引用結果。不正確的行為是自行轉換。評估會同時抓到錯誤的答案 AND 錯誤的處理過程,因為即使這次心算碰巧對了,下次還是會錯。
我發現最誠實的評估啟發法:搜尋你的對話歷史,找出你曾說過「fucking shit」或「wtf」的地方。那些就是你遺漏的測試案例。
步驟 6:Resolver 觸發
一個 resolver 是一個上下文路由表:當任務類型 X 出現時,載入技能 Y。我曾在這裡詳細介紹過 resolver。每個技能都需要在 AGENTS.md 中有一個觸發條目,這個檔案教導 Agent 有哪些技能以及何時使用它們。
Resolver 觸發只是 Markdown 表格中的幾行:

這個步驟能抓到的 bug:你寫了一個新技能,但忘了把它加到 resolver 中。技能存在。能力存在。但系統無法觸及它。這就像醫院裡有一位外科醫生,但醫院目錄裡沒有他的名字。這比完全沒有這個技能更糟,因為你 以為 系統能處理這件事。
步驟 7:Resolver 評估
這是大多數人完全忽略的一層。Resolver 觸發說「這個詞組應該路由到這個技能」。Resolver 評估 測試 它是否真的如此。
我的 resolver 評估套件有超過 50 個像這樣的測試案例:
{ intent: 'check my signatures', expectedSkill: 'executive-assistant' }, { intent: 'who is Pedro Franceschi', expectedSkill: 'brain-ops' }, { intent: 'save this article', expectedSkill: 'idea-ingest' }, { intent: 'what time is my meeting', expectedSkill: 'context-now' }, { intent: 'find my 2016 trip', expectedSkill: 'calendar-recall' },
兩種失敗模式。假陰性:技能應該觸發但沒有,因為觸發描述錯誤或遺漏。假陽性:錯誤的技能觸發了,因為兩個觸發條件重疊。「What's on my calendar tomorrow」應該路由到 calendar-check,而不是 calendar-recall 或 google-calendar。三個技能,三個不同的時間領域,一個詞組卻可能合理匹配其中任何一個。Resolver 評估能在使用者遇到之前就捕捉到這種模糊性。
我同時以確定性結構測試(AGENTS.md 表格是否包含正確的對應?)和 LLM 路由測試(給定這個意圖,模型是否真的選對了技能?)的方式執行這些評估。兩層都很重要。表格可能是對的,但模型仍然可能因為觸發描述太模糊而路由錯誤。
步驟 8:Check-resolvable + DRY 稽核
在一個月的建構之後,我有了 40 多個技能。有些是為了回應特定事件而創建的,有些則是由子 Agent 執行 cron 任務時產生的。沒有人維護 resolver 表格。技能不斷誕生,但沒有被註冊。
所以我建構了 check-resolvable。一個 meta 測試,它會遍歷整個鏈條:AGENTS.md resolver → SKILL.md → script/cron。如果一個腳本存在且能做有用的工作,但沒有來自 resolver 的路徑,它就是不可觸及的。LLM 永遠不會知道要使用它。
第一次執行發現 40 多個技能中有 6 個是不可觸及的。系統能力的百分之十五是黑暗的。
- 一個航班追蹤器,沒有人能透過詢問航班來叫用。
- 一個內容點子產生器,只在 cron 上執行,但無法手動觸發。
- 一個引用修復器,存在於技能目錄中,但根本沒列在 resolver 裡。
一小時內修復。只需在 AGENTS.md 中加入觸發條目。現在 check-resolvable 作為 gbrain doctor 的一部分每週執行一次。它檢查三件事:
- 每個包含 SKILL.md 的技能目錄都在 resolver 中有對應的條目。
- 每個技能引用的腳本都是實際可呼叫的(檔案存在,匯出正確的函式)。
- 沒有任何兩個技能的觸發描述重疊,導致路由模糊。
DRY 稽核與此同時執行。如果你不小心,最終可能會有大約十五個技能在做類似的事情,而 resolver 會根據運氣好壞選擇其中一個。以 calendar-recall 為例:

同一個領域內有四個技能。完全沒有重疊。每個都有自己的跑道。那個矩陣不是為了這篇文章而畫的圖表。它存在於 SKILL.md 內部,而稽核腳本會解析它。如果你建構了第六個行事曆技能,卻踩到別人的跑道,稽核會在技能發佈前就失敗。
步驟 9:端到端冒煙測試
完整的 pipeline,從頭到尾。
- 詢問 Agent「我什麼時候去過新加坡?」並驗證它執行了 calendar-recall.mjs,得到正確答案,並正確格式化。
- 詢問「我下一個會議是什麼時候?」並驗證它執行 context-now.mjs 而不是用心算。
冒煙測試是最後一道防線。其他所有測試都能通過,但系統仍然可能因為環節沒有連接起來而失敗。技能可以正確、腳本可以正確、resolver 可以正確,但 Agent 仍然可以選擇忽略所有這些並臨場發揮。冒煙測試能抓到這個問題。
步驟 10:大腦歸檔規則 (Brain filing rules)
每個會寫入知識庫的技能都需要知道資料該去哪裡。人物去 people/。公司去 companies/。政策分析去 civic/。我發現 10 個會寫入大腦的技能中有 13 個歸檔到了錯誤的目錄,因為它們各自硬編碼了自己的路徑,而不是諮詢 resolver。
歸檔規則文件記錄了常見的歸檔錯誤模式。來源 vs 原始檔。人物 vs 公司(當某人本身就是一家公司時)。技能在建立任何頁面之前會先讀取這些規則。從那時起,零次歸檔錯誤。
GBrain:技能化 (Skillify) 的所在,以及你應該從我的 GBrain 技能包 (Skill Pack) 中採用它
技能化模式並非 OpenClaw 或任何特定 harness 所獨有。它內建於 GBrain。GBrain 是我撰寫的開源知識引擎,它位於你使用的任何 harness 之下。它管理你的大腦 repo、執行你的評估、並強制執行使技能持久化的品質閘門。
一個 GBrain 技能包 (SkillPack) 是一個可攜帶的技能、resolver 觸發、確定性腳本和測試的捆綁包,你可以透過要求你的 OpenClaw/Hermes Agent 來將其安裝到任何 Agent 設定中。這就是我為我的 OpenClaw/Hermes Agent 撰寫的技能和能力如何被自動加入到 你的 OpenClaw 中的方式——包括完整的 10 步驟技能化輸出,打包好讓你可以直接丟進你的 OpenClaw/Hermes Agent 中,然後它就生效了。
稍早提到的 skillify 檢查清單不是一個建議。它是 gbrain doctor 實際檢查的內容。*
gbrain doctor --fix 會自動修復 DRY 違規、用慣例引用取代重複的區塊,所有操作都由 git working-tree 檢查保護,確保沒有任何東西被覆寫。
為什麼 Hermes Agent 本身還不夠
Nous Research 的 Hermes Agent 做了一件真正偉大的事:它有一個 skill_manage 工具,讓 Agent 本身可以根據它所學到的東西來創建、修補和刪除技能。當 Agent 完成一個複雜任務或從錯誤中恢復時,它會提出一個技能並將其寫入磁碟。這是 Agent 自己贏得的程序性記憶。漸進式揭露(先載入技能索引,只在選中時才拉取完整的 SKILL.md)。有界記憶(MEMORY.md 上限 2,200 字元)。條件式啟動(當所需工具不可用時,技能自動隱藏)。聰明的設計。
但 Hermes 不會測試它的技能。對確定性程式碼沒有單元測試。沒有 resolver 評估來驗證路由。沒有 check-resolvable 來找出黑暗技能。沒有 DRY 稽核來捕捉重複。沒有每日健康檢查能在發生偏移時顯示紅燈。
我在任何未經測試的技能系統中觀察到的累積失敗模式:
- Agent 在星期一創建 deploy-k8s。星期四它從另一個對話中創建了 kubernetes-deploy。兩者都存在。兩者都對相似的詞組觸發。路由模糊,而且沒有人注意到,直到錯誤的那個在不對的時機觸發。
- 技能在撰寫時完美運作。六週後上游 API 改變了形狀。技能默默地回傳垃圾資料,直到有人發現。
- 一個自主創建的技能有一個薄弱的觸發條件,永遠不會匹配。它變成了一個孤兒,消耗索引權杖,從不執行,慢慢腐朽。
這就是「沒有測試,任何程式碼庫都會腐朽」的問題,軟體工程在 2005 年就解決了這個問題。Agent 技能沒有什麼不同。Hermes 漂亮地處理了創作。GBrain 處理了驗證。你需要兩者。
核心概念
在一個健康的軟體工程團隊中,每個 bug 都會有一個測試跟隨。那個測試永遠存在。這個 bug 在結構上變得不可能重複。AI Agent 也應該以同樣的方式運作。
每次失敗都變成一個技能。每個技能都有評估。每個評估每天都執行。Agent 的判斷力會 永久地 改進,而不僅僅是為了當前 session,也不僅僅是在上下文視窗還有效時。
出差失敗不會再發生。時區失敗不會再發生。而當下一次失敗出現時(它會出現,因為這是一場對抗熵和品味的對抗遊戲),它也會被技能化。
一年後與我一起工作的 Agent,將由它在過去一年中犯下的每一個錯誤所塑造。這不是一個可有可無的功能。這是整個論點的核心。
全力以赴。讓你的 Agent 做某件事,然後 skillify it。你每天都這樣做,你就會得到一個該死的聰明 OpenClaw,能做所有你想讓它做的事。
或者你也可以直接載入 GBrain,使用我已經寫好的所有程式碼,然後更快地跳到擁有你自己的鋼鐵人賈維斯。
--
GStack to speed up in Claude Code github.com/garrytan/gstack
GBrain to build your own Jarvis from Iron Man in OpenClaw/Hermes Agent github.com/garrytan/gbrain



![成田悠輔的天才 AI 應用技巧 [保存版]](/cdn-cgi/image/width=1920,quality=90,format=auto,metadata=none/https%3A%2F%2Fcms-assets.youmind.com%2Fmedia%2F1784137658627_u4bwry_HNMS89bbsAAUPJI.jpg)

