編寫按需載入的技能
將模型在相關時才會拉取的封裝能力,建立並附加至代理程式。
list_skillscreate_skillupdate_agenttest_skill_trigger原則 — 保持技能數量較少。 僅附加此代理程式工作所需的內容(約 5 個或更少)。模型會根據其一行
description來選擇技能;你附加的越多,它載入錯誤或完全未載入的頻率就越高。如果兩個技能在 時機 上重疊,請將它們合併。更多資訊請參見 設計原則。
技能 是一個按需載入的功能套件:系統提示詞僅包含其 description
(「何時使用」);模型僅在判斷該技能相關時,才會拉取完整的 instructions。因此,
description 必須簡短並說明 何時 使用,否則模型將不知道去呼叫它。
list_skills() # what already exists
create_skill(
name="refund-policy",
description="Use when the user asks about refunds, cancellations or chargebacks.",
instructions="The full procedure: eligibility windows, how to word the outcome, when to escalate …",
)
update_agent(name="Support", add_skills=["refund-policy"]) # attach it (incremental — keeps existing skills)將程序保留在 instructions(載入時取得)中,而非代理程式的 soul 中(soul 在每個回合的提示詞中)。一句說明 何時 的 description 才是讓技能可被發現的關鍵——模糊的描述意味著模型永遠不會呼叫它。
工具可以隨技能附帶
技能可以攜帶其自己的工具綁定——create_skill(tools=[…]) 或
update_skill(name, add_tools=[…]),因此技能作為一個自包含的功能套件交付:程序加上它所需的工具,一次性附加。
技能的專屬工具僅在技能載入後才可用。 它們不在回合開始時的工具集中;載入技能會將它們加入其中。因此順序是固定的:閱讀程序,然後獲取工具——模型無法跳過工具並即興發揮。
此順序在程式碼中強制執行,而非在提示詞中請求,因為請求並未奏效。2026-08-22 測量結果顯示,在 "研究公司 X 的競爭對手" 任務中,將程序和工具一起提供給模型:模型呼叫了三次網路搜尋,但 從未載入技能。它憑記憶捏造競爭對手名稱,搜尋這些捏造的名稱,什麼也沒找到(因為它們不存在),並將捏造的名稱作為答案寫出——而其程序的第一步明確指出 "首先確定該公司實際上銷售什麼"。非強制性的程序不會被閱讀。
在依賴此機制之前,有兩件事需要了解:
- 技能工具不會出現在代理程式自己的
tools列表中。get_agent僅顯示代理程式直接附加的工具;主控台的「工具」標籤頁將技能綁定的工具顯示為單獨的唯讀「via skills」行。在驗證「工具 X 是否已啟用」時,請檢查這兩個地方——或者直接在測試聊天中呼叫該工具。 - 代理程式已有的工具不受影響。 如果代理程式本身攜帶
web_search,它在整個回合中仍可用;僅有 因為 技能而到達的工具才需等待該技能載入。 - 當工具僅在該程序內有意義時(例如退款技能內的退款查詢),請將工具綁定至 技能;當工具在整個回合中普遍有用時(
save_contact、web_search),請將其綁定至 代理程式。
綁定工具僅代表可用性,而非政策——指令必須說明何時呼叫它
檢查技能(或代理程式)上的工具僅使其 可呼叫。模型在每個回合都能看到工具的 schema
及其一行描述,因此它可能會 opportunistic 地使用——訪客主動提供電子郵件,save_contact 就會觸發。但 任何必須可靠發生的行為都需要寫下來,且其每個部分都有一個正確的位置:
| 你指定的內容 | 放置位置 |
|---|---|
| 何時載入此技能 | 技能的 description(每個回合都在提示詞中) |
| 程序:在何步驟呼叫哪個工具,以及使用哪些參數 | 技能的 instructions —— 明確命名工具(「在呼叫者確認興趣後,呼叫 save_contact 並提供電子郵件和電話;然後呼叫 schedule_followup 安排 1 個工作天後」) |
| 必須驅動整個對話的行為(始終捕捉潛在客戶,絕不報價) | 代理程式的 soul / task |
當指令未命名工具時的失敗模式:一切 看起來 都配置好了——工具已勾選,技能已載入——但代理程式仍從未呼叫它,或以猜測的參數呼叫它。不會報錯。將程序寫得像在簡報新員工:步驟、工具名稱、參數,以及「完成」的樣子。
強制性工具呼叫:觸發器必須位於 description 中,而不僅在 instructions 中
instructions 僅在模型呼叫 load_skill 後 對模型可見——而模型經常在不載入技能的情況下直接回答。因此,僅在 instructions 中寫入的規則(如 "當用戶提供電話號碼時,你必須呼叫 save_contact")在關鍵時刻是不可見的:工具靜默地未被呼叫,模型甚至可能聲稱已儲存聯絡資訊。這在生產環境中發生過——代理程式連續回答了幾條帶有聯絡資訊的訊息,「確認」細節已記錄,但實際上沒有任何記錄。
修復方法是在 description 中加一句話(這句話 確實 在每個回合的系統提示詞中):
update_skill(
name="consultative-sales",
description="Consultative sales: understand the case, recommend products, arrange expert callbacks. "
"When the user provides a phone number or email, call save_contact BEFORE answering anything else.",
)將詳細程序保留在 instructions 中;將任何強制性呼叫的 觸發器 放在
description 中。
兩條相關規則:
- 絕不要編造工具未產生的返回值——逐字轉發真實值。 內建的
save_contact和schedule_followup在成功時返回一個 真實的參考代碼(格式AB2C-D3EF,儲存在伺服器端,並在終端用戶的詳細頁面中對租戶可見)。指示模型逐字轉發 工具結果中的代碼 ——絕不要捏造一個或將其重新格式化為 "#12345"。對於任何其他工具,在編寫代碼前請驗證它實際上是否返回 ID:承諾但缺失的 ID 會被捏造出來。 create_skill/update_skill/get_skill現在返回一個warnings列表,用於標記這兩種模式(trigger_hidden_in_instructions、promised_tool_return_id)。警告僅供參考——儲存仍會成功——但請將其視為 linter:修復,不要忽略。
instructions 中的實例教學可顯著提高工具呼叫合規率
我們在生產後端上對此進行了基準測試(6 條難度遞增的潛在客戶捕捉訊息——數字隱藏在長問題中、帶空格的數字組、修正——按條件抽樣)。在技能載入的情況下,單純的「你必須呼叫 X」指令僅達到 3–4/6;加入一小塊實例教學後,兩個測試模型都達到了 6/6。移動指令部分的位置沒有任何作用——位置無關緊要,實例教學才重要。
一個有效的實例教學區塊包含四種條目,每條一行:
### Worked examples (follow exactly)
1. User: "I'd like to know about X, my phone is 13800138000"
→ call save_contact(phone="13800138000") first, then answer about X.
2. User: "email me the offer: li@example.com"
→ call save_contact(email="li@example.com").
3. COUNTER-EXAMPLE (forbidden): user gives a phone number and you reply
"I've noted it down" WITHOUT calling the tool — claiming success without
the call is the worst failure.
4. User: "sorry, wrong number — it's 13633334444"
→ call save_contact again with the corrected value.
5. Numbers may contain spaces ("138 0013 9000") — still a phone number;
strip the spaces and call save_contact(phone="13800139000").反例 (3) 和格式邊緣案例 (5) 關閉了大多數剩餘的遺漏——模型在 識別(「這是電話號碼嗎?」)和 壓力下的誠實(先回答豐富的領域問題並聲稱儲存已發生)上失敗,多於在意願上。保持約 5 個條目;使用精確的呼叫語法和真實的參數。
在發布前測試觸發器——不要在生產環境中計算屍體
技能是否 實際 觸發是可測量的,因此請測量它。test_skill_trigger 會針對 生產
提示詞組裝、工具 schema 和模型路由對你的訊息進行乾跑,並報告模型的決定——工具從未執行,沒有儲存任何內容,token 計入你的配額(上限:5 條訊息 × 5 個樣本)。
test_skill_trigger(
agent="advisor",
messages=[
"My phone is 555 0123, call me back", # easy
"long question about the product … oh and my number is 555 0123", # buried
"555 0123 — that's me", # implicit
"sorry, wrong number, it's 555 9999", # correction
],
expect_tool="save_contact",
samples=3,
loaded=true, # simulate post-load_skill → tests instructions quality
) # loaded=false (default) → first turn, tests the description trigger請這樣解讀結果:
hit_rate在真實訊息上低於 ~90% → 強化觸發器(description)或添加實例教學(instructions),然後重新測試。claimed_without_call> 0 是最嚴重的失敗——模型告訴用戶「已記錄!」但未呼叫工具。添加上述區塊中的反例。- 測試 兩種模式:
loaded=false證明描述本身在第一個回合觸發;loaded=true證明載入的指令沒有稀釋它(長指令確實會產生影響——這就是實例教學補償的內容)。
結果還包含一個 advice 列表:當樣本失敗或謊報時,它會告訴你確切的修復方法(將觸發器放入描述、添加實例教學區塊、添加反例或格式邊緣案例),並附上每個建議背後的基準數字——應用它並重新測試。
完整循環:create_skill → 修復任何 warnings(靜態 lint)→ test_skill_trigger(動態現實檢查)→ 應用其 advice → 重新測試直到命中率穩定。