Day 5 把 ticket-guard 寫成可驗收需求:三種分類、固定判斷順序、資料證據、護欄與六個驗收案例。今天開始實作,但只做最薄的一層:建立目錄骨架,讓 agent 知道何時啟動、按什麼順序工作、何時必須停下來。
先建立四個位置:
ticket-guard/
├── SKILL.md
├── references/
│ └── sources.md
├── scripts/
│ └── check_domain.py
└── tests/
└── cases.yaml
每個檔案都對應昨天的一項需求:
SKILL.md:觸發條件、工作流程、護欄與輸出格式references/sources.md:有證據的官方來源紀錄scripts/check_domain.py:確定性 URL 解析與域名分類tests/cases.yaml:把驗收案例保存成可重跑測資今天先完成 SKILL.md。另外三個檔案先建立空殼,後面逐日補上。
---
name: ticket-guard
description: 檢查演唱會售票網址是否屬於已驗證的官方來源。當使用者貼出售票或購票網址、詢問連結是否官方或真實、或提到假售票連結與票務詐騙時使用。不要用於只問活動日期、座位或票價的問題。
---
這段 description 做三件事:
負面邊界很重要。如果只有「演唱會」就觸發,這支 skill 會攔截大量不需要安全檢查的問題。
SKILL.md 的本文先寫執行順序:
# Ticket Guard
## Workflow
1. Extract every complete HTTP(S) URL from the user's message.
2. If no complete URL exists, return `INSUFFICIENT_INPUT` and ask only for the full link.
3. Run `scripts/check_domain.py` for each URL. Do not classify a domain from memory.
4. Read the matching record from `references/sources.md` when the script returns `OFFICIAL`.
5. When the script returns `UNCONFIRMED`, report its risk signals without calling the site a scam.
6. Render the result using the required output schema.
這裡故意把「抽取網址」和「分類域名」分開。前者需要理解使用者訊息,後者必須交給腳本。模型可以處理語言,但不能把確定性判斷拿回來自由發揮。
腳本今天還沒實作,但 SKILL.md 先規定它必須輸入與輸出什麼:
## Script contract
Run:
python scripts/check_domain.py "<url>"
The script returns JSON only:
{
"status": "OFFICIAL | UNCONFIRMED | INSUFFICIENT_INPUT",
"checked_url": "...",
"normalized_host": "... | null",
"evidence": ["..."],
"next_step": "..."
}
先寫契約的好處是,明天實作腳本時不必猜 agent 期待什麼;後面寫 eval runner 時,也有穩定介面可以驗證。
護欄不要只放在文件最後。越接近風險動作,越不容易被忽略:
## Guardrails
- Never classify from page appearance, search ranking, ads, or the HTTPS lock icon.
- Never enter credentials, verification codes, or payment data.
- Never buy tickets or recommend an unverified resale source.
- `UNCONFIRMED` must never be paraphrased as safe, official, or definitely fraudulent.
- If source evidence is stale or conflicting, return that it cannot be confirmed.
其中第四條是輸出護欄。即使腳本給對分類,模型在改寫成自然語言時也可能把語氣變得過度肯定,所以必須約束轉譯。
## Response format
判斷:<status>
檢查網址:<checked_url>
正規化域名:<normalized_host>
依據:<evidence>
下一步:<next_step>
固定模板不代表回答必須僵硬。它保證五個必要欄位不會因語氣或上下文而消失。
把上面合起來,今天的成品是:
---
name: ticket-guard
description: 檢查演唱會售票網址是否屬於已驗證的官方來源。當使用者貼出售票或購票網址、詢問連結是否官方或真實、或提到假售票連結與票務詐騙時使用。不要用於只問活動日期、座位或票價的問題。
---
# Ticket Guard
## Workflow
1. Extract every complete HTTP(S) URL.
2. If none exists, return `INSUFFICIENT_INPUT` and ask for the full link.
3. Run `scripts/check_domain.py` for each URL. Never classify from memory.
4. For `OFFICIAL`, read the matching record in `references/sources.md`.
5. For `UNCONFIRMED`, list risk signals without making an accusation.
6. Use the required response format.
## Script contract
Run `python scripts/check_domain.py "<url>"` and preserve its JSON classification.
## Guardrails
- Never classify from appearance, search rank, ads, or HTTPS alone.
- Never enter credentials, codes, or payment data.
- Never buy tickets or recommend unverified resale sources.
- Never soften or strengthen the script's classification.
- Return unknown when evidence is stale or conflicting.
## Response format
判斷:<status>
檢查網址:<checked_url>
正規化域名:<normalized_host>
依據:<evidence>
下一步:<next_step>
這還不能真正判斷網址,因為腳本與來源清單尚未完成。但它已經能回答三個工程問題:何時觸發、要呼叫什麼、哪些事情絕對不做。
在真正跑案例前,先做五個便宜檢查:
name 與 description。靜態檢查不能證明 skill 有效,但能在測試前抓到最基本的結構錯誤。
Day 7 來寫 references/sources.md:官方來源不是一串域名,而是帶證據、日期與適用範圍的可維護資料。