問題:SKILL.md 靠人工調校太慢

OpenClaw 的 skill 系統靠 SKILL.md 指引 agent 行為——什麼時候觸發、怎麼執行、輸出什麼格式。寫得好,agent 就穩定;寫得差,每次跑出來的品質都不一樣。

我的 workspace 裝了二十多個 skill,平時靠「出問題 → 改一行 → 觀察幾天 → 再改」的方式迭代。這種人工調校有兩個問題:

  1. 回饋週期太長。 改了一行要等幾天才知道有沒有效果。
  2. 靠直覺不靠數據。 改完「感覺比較好」,但沒有量化指標。

如果能讓 LLM 自己評估 SKILL.md 的效果,再自動改進,迭代速度會快很多。


靈感:GEPA(ICLR 2026)

逛 GitHub 時發現 NousResearch 的 hermes-agent,裡面有一套 self-evolution 機制,核心引用了 GEPA 這篇論文(Genetic Prompt Evolution with NL Reflection,ICLR 2026 Oral)。

GEPA 的概念不複雜:

  1. 評估:用 LLM 打分(而不是人類標註)
  2. 反思:讓 LLM 自己分析「哪裡扣分了、為什麼」
  3. 變異:根據反思結果修改 prompt
  4. 選擇:保留最高分的版本,淘汰退步的

跟 RLHF 不同,整個過程只需要 API call,不需要 GPU 做 gradient update。論文宣稱比 GRPO 少 35 倍 rollouts。

我不需要 GEPA 的完整框架(DSPy + Pareto selection),但「LLM 評估 → LLM 反思 → LLM 改進」這個循環可以直接搬過來。


第一關:API 認證踩坑

決定用 MiniMax M2.5 當演化引擎——便宜、有 thinking 模式、我的 Coding Plan 已經在用。

一開始想用 DSPy + litellm 接 MiniMax:

import dspy
lm = dspy.LM("anthropic/MiniMax-M2.5", api_base="https://api.minimax.io/anthropic")

跑不起來。litellm 堅持走 OpenAI chat endpoint(api.minimax.chat/v1),而 MiniMax Coding Plan key 只接受 Anthropic Messages endpoint(api.minimax.io/anthropic)。兩個端點,同一把 key,一個能用一個不能。

放棄 DSPy,改用 httpx 直接打 Anthropic Messages API:

resp = httpx.post(
    "https://api.minimax.io/anthropic/v1/messages",
    headers={"x-api-key": API_KEY, "anthropic-version": "2023-06-01"},
    json={
        "model": "MiniMax-M2.5",
        "max_tokens": 4000,
        "thinking": {"type": "enabled", "budget_tokens": 4000},
        "messages": [{"role": "user", "content": prompt}]
    },
    timeout=300
)

這條路通了。教訓:遇到多層抽象(DSPy → litellm → provider),不如直接打 HTTP。


Pipeline 設計

最終的演化流程分三步:

1. 生成評估集

讓 LLM 讀原始 SKILL.md,自動產生 5 個測試案例。每個案例包含:

  • 場景描述:模擬一個使用情境
  • 好信號(good signals):預期輸出應該包含的內容
  • 壞信號(bad signals):預期輸出不應該包含的內容

例如 blog-writer 的一個案例:

{
  "scenario": "寫一篇 Docker Compose 初學者教學",
  "good_signals": ["繁體中文", "frontmatter 包含 title/date/tags", "段落不超過 4 行"],
  "bad_signals": ["超級簡單", "一步到位", "必備"]
}

2. 評估

把 SKILL.md 和每個測試案例一起送給 LLM,讓它打 0-100 分:「如果一個 agent 讀了這份 SKILL.md,它能在這個場景下正確執行嗎?」

打分不只看分數,還要求附上理由——哪些好信號被涵蓋了、哪些壞信號沒被擋住。

3. 演化

把低分案例的扣分理由彙總,要求 LLM 重寫整份 SKILL.md,改善弱點,保留已有優勢。

重複 2-3 輪,保留最高分版本。

原始 SKILL.md → 評估(84) → 反思 → 改寫 → 評估(95) → 反思 → 改寫 → 評估(93)
                                                 ↑ 最高分,保留這個版本

blog-writer 實驗結果

用 blog-writer SKILL.md 做第一次實驗:

輪次平均分差異
0(原版)84-90
195.6+5~12
295.0+5~11

第 1 輪就拉上去了,第 2 輪略降。最終採用第 1 輪的版本。

具體改了什麼?LLM 自己加了兩個東西:

禁止詞彙表(原版只有一句「不誇飾」,太模糊):

類型禁用詞彙
誇大形容詞驚人的、革命性的、碾壓、極致、秒懂
絕對化表述一步到位、必備、必讀、不可或缺的
自我吹捧輕鬆搞定、輕鬆學會、輕鬆上手
煽動語句學會這招再也、從此不用

問題排查文結構(原版沒有明確指導排查類文章怎麼寫):

  1. 問題描述:什麼錯誤?環境?
  2. 排查過程:嘗試了什麼?為何失敗?
  3. 解決方法:最終怎麼解?為何有效?

這兩個改動合理,都被合併進了正式的 SKILL.md。


擴大到三個 skill

確認 pipeline 可用後,跑了另外兩個 skill:

SkillBaselineBestDelta
blog-writer84-9095-97+5~12
yt-notes88.097.0+9.0
coding-agent62.078.0+16.0
github86.686.60

幾個觀察:

coding-agent 提升最大(+16),因為原版比較粗糙。演化後加了 PTY 規則表、Quick Start 流程、Task Workflow 分類。這些都是原版缺少但有價值的結構。

github skill 沒有改善——原版已經寫得很好了,LLM 嘗試修改的版本反而降分。系統正確地保留了原版。這是一個重要的特性:演化不是強制改變,如果原版已經是最優解,它會被保留。

yt-notes 的改動大多是格式化:把散文式的規則改成表格、加 checklist。內容沒有大變化,但結構更清晰,LLM 讀起來更容易遵循。


演化也會產生垃圾

不是每個改動都好。blog-writer 的第 2 輪演化裡出現了:

  • categoriescover.image 改成必填——原版標為選填是有原因的
  • 把「經驗分享」改稱「教學」——定位錯誤
  • 夾帶了一段日文——MiniMax 的多語言訓練有時會洩漏

coding-agent 演化後有些規則太死板(強制要求每個 task 都跑測試),在實際使用中會拖慢速度。

所以 human-in-the-loop 不能省。pipeline 生成 diff,人審核後才合併。自動演化 + 自動部署的風險太高。


工具

最終的 pipeline 是兩個檔案:

  • evolve_skill.py(278 行):通用演化腳本,httpx 直打 MiniMax Anthropic endpoint
  • skill-evolve.sh:wrapper,掃描所有 skill 目錄,依次跑演化

每個 skill 跑完會產出:

tmp/skill-evolution/<skill>/
├── eval_cases.json   # 自動生成的測試案例
├── results.json      # 每輪分數
├── best_skill.md     # 最高分版本
└── diff.patch        # 與原版的差異

設計上做了幾個防護:

  • per-task timeout:評估 90 秒、演化 300 秒。MiniMax thinking 模式需要時間,但不能無限等
  • crash-safe:每輪結果即時寫入 JSON,中途斷電不會丟失
  • retry + backoff:API 偶爾超時,自動重試 2 次
  • 保留原版的能力:如果演化版低於原版,diff 是空的

計畫每週日凌晨自動跑一次,Telegram 通知結果,人工決定是否合併。


幾個教訓

MiniMax thinking 模式需要足夠的 token 預算。 一開始為了省 token 把 max_tokens 縮到 2000,演化品質很差。改成 4000 後才正常。thinking 模式的 token 是花在推理上,不是浪費。

timeout 比 max_tokens 更重要。 原本 eval 和 evolve 用同一個 timeout(60 秒),evolve 總是超時。拆成 eval=90s、evolve=300s 後就穩了。不同任務需要不同的時間預算。

API endpoint 選擇是隱形坑。 MiniMax Coding Plan key 能用 Anthropic endpoint,不能用 OpenAI endpoint。同一個 provider 的兩個 endpoint,key 的權限不同。文件裡沒寫清楚。

演化結果的 content 結構要注意。 MiniMax 有時回傳的 content 只有 thinking block 沒有 text block,需要遍歷 response.contenttype == "text" 的那個。不能直接取 content[0].text


下一步

目前只在 SKILL.md 層面做演化(GEPA 的 Tier 1)。更高風險的層級——Tool Description(Tier 2)、System Prompt(Tier 3)、Agent Code(Tier 4)——暫時不碰。

Skill 演化帶來的改善是溫和的:結構更清晰、邊界更明確、壞模式被顯式列出。不是 10 倍提升,但讓 agent 行為的一致性上了一個台階。

最大的收穫可能不是分數,而是「用 LLM 評估 LLM 的 prompt」這個方法本身。以前改 SKILL.md 靠的是直覺和偶爾的踩坑,現在有了量化的回饋循環。