iT邦幫忙

0

Day 15|Skill 什麼時候該出場:用 description 劃清觸發範圍,再用 eval 驗證

  • 分享至 

  • xImage
  •  

(系列:《把 Claude 練成專家:30 天打造可驗證的 Agent Skills》)

昨日回顧

Day 14 讓來源紀錄會過期:過了 review_after 就預設降級為 UNCONFIRMED,重驗從 evidence_url 出發,撤銷用狀態表示,audit history 只能新增。到這裡,Skill 內部的判斷已經有規格、測試、eval 與維護流程。

但還有一個更前面的問題:Claude 什麼時候會載入這個 Skill?

觸發是第一道行為

Skill 的 description 不是給人看的簡介,而是 Claude 決定「要不要讀這份 SKILL.md」的主要依據。寫得太窄,使用者貼了可疑售票連結,Skill 卻沒出場;寫得太寬,使用者只是問演唱會幾點開始,Skill 也跳出來要求驗證網址。

兩種錯誤的代價不同:

  • 漏觸發(false negative):安全檢查沒有發生,使用者可能直接在假網站付款
  • 誤觸發(false positive):回答變囉嗦,使用者覺得被打擾,也會讓其他 Skill 被擠掉

所以觸發範圍也要像分類器一樣,寫清楚、可測試。

先寫出範圍,再寫 description

不要直接開始修辭。先在設計文件列出三類情境:

應該觸發(in scope)
- 使用者貼出售票或轉售連結,問能不能買
- 使用者問某個網站是不是官方售票通路
- 使用者準備在陌生網站輸入付款或登入資料

不應觸發(out of scope)
- 問演出時間、場地、交通
- 問票價或座位圖,但沒有提到要在哪個網站購買
- 一般的網址格式或 DNS 教學

邊界(near miss)
- 「這個網址打不開」:是技術問題,不是來源驗證
- 「官方說下週開賣」:提到官方,但沒有要驗證的連結
- 使用者貼的是自己公司的後台網址

near miss 最重要。它們跟應觸發的句子共用關鍵字(官方、網址、售票),但意圖不同。description 能不能分辨它們,決定了 Skill 的精準度。

description 的寫法

一個有效的 description 通常包含三個部分:做什麼、什麼時候用、什麼時候不用。

name: ticket-source-guard
description: >
  Check whether a ticketing or resale link comes from a verified official
  source before the user logs in, enters personal data, or pays. Use when
  the user shares a ticket link, asks if a ticketing site is official, or
  is about to buy from an unfamiliar site. Do not use for event times,
  venues, general URL troubleshooting, or questions with no link or site
  to verify.

幾個原則:

  • 用使用者會說的話描述情境,而不是內部術語。使用者不會說「請執行來源 registry 比對」
  • 動作要具體:「登入、輸入個資、付款前」比「涉及安全時」清楚
  • 排除條件直接寫出來,不要只靠 Claude 自己推斷
  • 不要塞滿關鍵字。關鍵字清單會讓 near miss 更容易誤觸發

description 不是 SKILL.md 的摘要

常見錯誤是把 SKILL.md 的步驟濃縮進 description:

description: >
  Normalize host, load registry, check review_after, return one of five
  statuses with evidence...

這段描述了 Skill 內部怎麼做,卻沒有說明什麼時候該用。Claude 在決定是否載入時,還沒看到使用者需要這些步驟的理由。流程細節留在 SKILL.md,description 只負責「何時出場」。

觸發 eval 的案例格式

延續 Day 11 的 JSONL,觸發 eval 另開一個檔案:

{"id": "trig-pos-resale-link", "prompt": "朋友傳了這個轉售連結 https://tix-resale.example.net/e/42 可以買嗎?", "expect": "trigger"}
{"id": "trig-pos-is-official", "prompt": "tickets.example.com 是官方售票網站嗎?", "expect": "trigger"}
{"id": "trig-neg-showtime", "prompt": "這場演唱會幾點進場?", "expect": "no_trigger"}
{"id": "trig-neg-seatmap", "prompt": "搖滾區和看台區差多少錢?", "expect": "no_trigger"}
{"id": "trig-near-broken-url", "prompt": "官方售票網址一直打不開,是不是我網路有問題?", "expect": "no_trigger"}
{"id": "trig-near-announcement", "prompt": "官方說下週五中午開賣,要先準備什麼?", "expect": "no_trigger"}

每個案例只標記期待結果,不標記「應該命中哪個關鍵字」。eval 測的是行為,不是實作。

案例比例要刻意設計

如果九成案例都是應觸發,description 寫得再寬也能拿高分。建議至少:

positive   40%
negative   30%
near miss  30%

near miss 案例要從真實使用情境收集,也要在每次誤觸發或漏觸發後補進去。就像 Day 11 的回歸案例,每個 bug 都應該留下一筆 eval。

怎麼判斷有沒有觸發

觸發 eval 需要一個可觀察的訊號。常見做法:

  • 在測試環境記錄 Skill 是否被讀取
  • 在 SKILL.md 開頭要求輸出固定的機器可讀標記,例如 skill: ticket-source-guard,eval 只檢查標記是否存在

第二種做法簡單,但要注意:標記只用在 eval 環境,不要讓正式回覆裡出現對使用者沒意義的字串。

def detect_trigger(transcript: dict) -> bool:
    return "ticket-source-guard" in transcript.get("skills_loaded", [])

判斷邏輯保持確定性,不要用另一個模型去猜「看起來有沒有用到 Skill」。

模型呼叫不是確定性的

Day 10 到 Day 12 的測試都是純函式,同樣輸入永遠同樣輸出。觸發 eval 不一樣:它要真的呼叫模型,每次結果可能有差異。

處理方式:

  • 每個案例跑多次,例如 5 次,記錄觸發率
  • 設門檻,而不是要求 100%:positive 觸發率至少 0.8,negative 與 near miss 觸發率最多 0.2
  • 報告裡保留每個案例的觸發率,而不是只有總分
def score_case(case: dict, runs: list[bool]) -> dict:
    rate = sum(runs) / len(runs)
    if case["expect"] == "trigger":
        passed = rate >= 0.8
    else:
        passed = rate <= 0.2
    return {"id": case["id"], "rate": rate, "passed": passed}

觸發 eval 不放進每次 PR 的必要門檻

Day 12 的 CI 刻意保持離線、快速、確定性。觸發 eval 需要網路、要花錢、結果有波動,如果放進每個 PR 的 branch protection,會出現「沒改 description 卻因為模型波動被擋」的情況。

所以分開:

每個 PR(必要)
  pytest、行為 eval、registry schema、freshness 規則

description 或 name 有變更的 PR(必要)
  觸發 eval,多次執行,達門檻才能合併

定期(非必要,產生報告)
  觸發 eval 全量跑一次,追蹤模型更新後的漂移

用 path filter 或檢查 SKILL.md frontmatter 的 diff,就能判斷這個 PR 是否動到觸發範圍。

修改 description 的流程

每次調整 description,都照同樣順序:

  1. 先加 eval 案例,重現這次的漏觸發或誤觸發
  2. 確認新案例在舊 description 下失敗
  3. 修改 description
  4. 全部觸發案例重跑,確認沒有把其他案例弄壞
  5. PR 說明寫出改了哪一句、對應哪個案例

第 4 步最容易被跳過。為了修一個漏觸發把 description 寫寬,往往會讓兩三個 near miss 開始誤觸發。

Skill 之間的邊界

當使用者安裝多個 Skill,範圍重疊也會造成問題。例如另一個「活動行程整理」Skill 也可能對「幫我看這場演唱會」產生反應。

檢查方式:

  • 把其他 Skill 的 positive 案例,拿來當本 Skill 的 negative 案例
  • 如果兩個 Skill 都應該處理某個情境,在 description 裡寫清楚各自負責哪一段

範圍清楚的 Skill,比什麼都想管的 Skill 更容易被信任。

今天完成的驗收標準

[ ] 設計文件列出 in scope、out of scope、near miss
[ ] description 包含做什麼、何時用、何時不用
[ ] description 不重述 SKILL.md 內部步驟
[ ] 觸發 eval 有 positive、negative、near miss 三類
[ ] near miss 至少三成
[ ] 觸發判斷用確定性訊號,不用模型評分
[ ] 每個案例多次執行,報告觸發率
[ ] description 變更時才把觸發 eval 列為必要門檻
[ ] 每次修 description 先補案例、再全量重跑
[ ] 其他 Skill 的 positive 案例納入本 Skill 的 negative

明天預告

Day 16 處理 Skill 的漸進式揭露:SKILL.md 本體要放什麼、哪些內容移到 references 與 scripts,讓 Claude 只在需要時才讀取細節。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言