技能建立者
一個用於建立新技能並迭代改進它們的技能。
概括來說,建立技能的流程如下:
- 決定你想讓技能做什麼,以及大致該如何實現
- 撰寫技能草稿
- 建立幾個測試提示,並在使用者安裝技能的情況下執行模型
- 幫助使用者同時從質化與量化兩個角度評估結果
- 在後台執行測試的同時,若尚無量化評估,則草擬一些量化評估(若已有評估,你可以直接使用,或根據需求修改這些評估)。然後向使用者說明這些評估(或若已存在,則解釋現有的評估)
- 使用
eval-viewer/generate_review.py腳本向使用者顯示結果,以便他們檢視,同時也讓他們查看量化指標
- 根據使用者對結果的評估回饋來改寫技能(此外,若從量化基準測試中發現明顯的缺陷,也加以修正)
- 重複直到滿意為止
- 擴充測試集,並在更大規模上再次嘗試
使用此技能時,你的工作是判斷使用者處於流程中的哪個階段,然後介入並幫助他們推進這些步驟。例如,使用者可能說:「我想為 X 建立一個技能」。你可以幫助他們釐清需求、撰寫草稿、編寫測試案例、決定評估方式、執行所有提示,並重複迭代。
另一方面,如果使用者已經有技能草稿,你可以直接進入評估/迭代的循環。
當然,你應該始終保持靈活,如果使用者說:「我不需要執行一堆評估,跟我一起感覺就好」,你也可以這樣做。
當技能完成後(但順序依然可以靈活調整),你還能執行技能描述改進工具(我們有單獨的腳本),以最佳化技能的觸發機制。
懂了嗎?好。
與使用者溝通
技能建立者可能被具有不同程式術語熟悉度的使用者使用。如果你還沒聽說(但怎麼可能,這是很新的趨勢),DSH 的威力正激勵水管工打開終端機,父母和祖父母在 Google 上搜尋「如何安裝 npm」。另一方面,大多數使用者可能相當熟悉電腦操作。
所以請注意情境線索,以了解如何調整你的溝通方式!在預設情況下,給你一些參考:
- 「評估」和「基準測試」算是在邊界上,但還可以接受
- 對於「JSON」和「斷言」,你需要在看到使用者表現出他們知道這些是什麼的明確線索後,才使用這些詞彙,且不加以解釋
如果你不確定使用者是否理解某些術語,可以簡單解釋一下,如果不確定使用者是否會懂,也可以隨時用簡短定義澄清這些術語。
建立技能
捕捉意圖
首先,了解使用者的意圖。當前的對話可能已經包含使用者想要捕捉的工作流程(例如,他們說「把這個變成技能」)。如果是這種情況,先從對話歷史中提取答案——使用的工具、步驟順序、使用者所做的修正、觀察到的輸入/輸出格式。使用者可能需要填補空白,並且在進行下一步之前應確認。
- 這個技能應該讓 DSH 能夠做什麼?
- 這個技能應該在什麼時候觸發?(使用者的哪些短語/情境)
- 預期的輸出格式是什麼?
- 我們是否應該設定測試案例來驗證技能?具有客觀可驗證輸出(檔案轉換、資料萃取、程式碼生成、固定工作流程步驟)的技能適合使用測試案例。具有主觀輸出(寫作風格、藝術)的技能通常不需要。根據技能類型建議合適的預設值,但讓使用者決定。
訪談與研究
主動詢問邊緣情況、輸入/輸出格式、範例檔案、成功標準和依賴項等問題。在這些部分確定之前,先不要撰寫測試提示。
檢查可用的 MCP——如果對研究有用(搜尋文件、尋找類似技能、查詢最佳實踐),則透過子代理(如果可用)平行進行研究,否則內聯進行。帶著背景知識來,以減少使用者的負擔。
撰寫 SKILL.md
根據使用者訪談,填入以下元件:
- name:技能識別碼
- description:何時觸發、它做什麼。這是主要的觸發機制——包含技能做什麼以及何時使用的特定情境。所有「何時使用」的資訊都放在這裡,而不是主體中。注意:目前模型傾向於「不完全觸發」技能——也就是說,在它們有用時不使用它們。為了解決這個問題,請讓技能描述稍微「強勢」一點。例如,不要寫「如何建立一個簡單快速的儀表板來顯示內部公司數據」,而是寫「如何建立一個簡單快速的儀表板來顯示內部公司數據。確保每當使用者提到儀表板、數據視覺化、內部指標,或想要顯示任何類型的公司數據時,即使他們沒有明確要求「儀表板」,也要使用此技能。」
- whenToUse / metadata / disable-model-invocation / user-invocable:DSH 識別的選擇性 frontmatter 鍵。DSH 從 frontmatter 讀取
name、description、whenToUse、metadata、disable-model-invocation和user-invocable;任何其他你想記錄的內容(例如授權、版本)請放在metadata下,而不是作為頂層鍵。 - 技能的其餘部分 :)
技能寫作指南
技能的架構
skill-name/
├── SKILL.md(必要)
│ ├── YAML frontmatter(name、description 必要)
│ └── Markdown 指令
└── 捆綁資源(選擇性)
├── scripts/ - 用於確定性/重複性任務的可執行程式碼
├── references/ - 根據需要載入到上下文中的文件
└── assets/ - 輸出中使用的檔案(範本、圖示、字型)
漸進式揭露
技能使用三級載入系統:
- Metadata(name + description)——始終在上下文中(約 100 字)
- SKILL.md 主體——每當技能觸發時在上下文中(理想低於 500 行)
- 捆綁資源——按需載入(無限制,腳本可在不載入的情況下執行)
這些字數是近似值,必要時可以超出。
關鍵模式:
- 將 SKILL.md 保持在 500 行以下;如果你接近這個限制,請增加一個額外的層級,並清楚指出使用技能的模型下一步應該去哪裡跟進。
- 從 SKILL.md 中清楚引用檔案,並指導何時閱讀它們
- 對於大型參考檔案(超過 300 行),包含目錄
領域組織:當一個技能支援多個領域/框架時,按變體組織:
cloud-deploy/
├── SKILL.md(工作流程 + 選擇)
└── references/
├── aws.md
├── gcp.md
└── azure.md
DSH 只讀取相關的參考檔案。
無意外原則
不言而喻,技能不得包含惡意軟體、利用程式碼,或任何可能危及系統安全的內容。一個技能的內容在描述其意圖時不應讓使用者感到意外。不要同意建立誤導性技能,或旨在促進未經授權的存取、資料外洩或其他惡意活動的技能。像「角色扮演 XYZ」這樣的內容是可以接受的。
寫作模式
在指令中偏好使用命令式。
定義輸出格式——你可以這樣做:
## 報告結構
始終使用這個確切範本:
# [標題]
## 執行摘要
## 主要發現
## 建議
範例模式——包含範例很有用。你可以這樣格式化它們(但如果範例中有「輸入」和「輸出」,你可能想要稍微偏離):
## 提交訊息格式
**範例 1:**
輸入:使用 JWT 令牌新增使用者認證
輸出:feat(auth): implement JWT-based authentication
寫作風格
嘗試向模型解釋為什麼這些事情很重要,而不是使用嚴厲的 MUST/MUST NOT。使用心智理論,並嘗試使技能具有通用性,而不是過度狹隘地針對特定範例。先撰寫草稿,然後用全新的眼光審視並改進它。
測試案例
在撰寫技能草稿後,提出 2-3 個真實的測試提示——實際使用者會說的那種話。與使用者分享:[你不必使用完全相同的語言]「這裡有幾個我想嘗試的測試案例。這些看起來正確嗎,還是你想添加更多?」然後執行它們。
將測試案例儲存到 evals/evals.json。暫時不要撰寫斷言——只寫提示。你將在下一步(執行正在進行時)草擬斷言。
{
"skill_name": "example-skill",
"evals": [
{
"id": 1,
"prompt": "使用者的任務提示",
"expected_output": "預期結果描述",
"files": []
}
]
}
請參閱 references/schemas.md 以了解完整 schema(包括 assertions 欄位,你稍後會添加)。
執行與評估測試案例
本節是一個連續的序列——不要中途停止。不要使用 /skill-test 或任何其他測試技能。
將結果放在 <skill-name>-workspace/ 中,作為技能目錄的同級目錄。在工作區中,按迭代組織結果(iteration-1/、iteration-2/ 等),在迭代內,每個測試案例一個目錄(eval-0/、eval-1/ 等)。不要預先建立所有這些——只需在進行時建立目錄。
步驟 1:在同一回合中啟動所有執行(有技能 AND 基準線)
對於每個測試案例,在同一回合中啟動兩個子代理——一個有技能,一個沒有。這很重要:不要先啟動有技能的執行,然後再回來啟動基準線。一次啟動所有執行,以便它們大約同時完成。
有技能的執行:
執行此任務:
- 技能路徑:<path-to-skill>
- 任務:<eval prompt>
- 輸入檔案:<eval files if any, or "none">
- 將輸出儲存到:<workspace>/iteration-<N>/eval-<ID>/with_skill/outputs/
- 要儲存的輸出:<使用者關心的內容——例如「.docx 檔案」、「最終 CSV」>
基準線執行(相同提示,但基準線取決於上下文):
- 建立新技能:完全沒有技能。相同提示,無技能路徑,儲存到
without_skill/outputs/。 - 改進現有技能:舊版本。在編輯之前,透過使用
shutil.copytree複製目錄來建立技能的快照(例如,從<skill-path>複製到<workspace>/skill-snapshot/),然後將基準線子代理指向快照。儲存到old_skill/outputs/。
為每個測試案例撰寫一個 eval_metadata.json(斷言目前可以為空)。根據測試的內容為每個 eval 提供一個描述性名稱——而不僅僅是「eval-0」。也使用此名稱作為目錄名稱。如果此迭代使用新的或修改的 eval 提示,請為每個新的 eval 目錄建立這些檔案——不要假設它們從之前的迭代繼承。
{
"eval_id": 0,
"eval_name": "descriptive-name-here",
"prompt": "The user's task prompt",
"assertions": []
}
步驟 2:在執行進行時,草擬斷言
不要只是等待執行完成——你可以有效地利用這段時間。為每個測試案例草擬量化斷言,並向使用者解釋。如果 evals/evals.json 中已經存在斷言,請檢閱它們並解釋它們檢查了什麼。
好的斷言是客觀可驗證的,並且有描述性的名稱——它們應該在基準測試檢視器中清晰可讀,以便某人一眼看到結果就能立即理解每個斷言檢查了什麼。主觀技能(寫作風格、設計品質)更適合質化評估——不要將斷言強加於需要人類判斷的事物上。
一旦草擬完成,更新 eval_metadata.json 檔案和 evals/evals.json 以包含斷言。同時向使用者解釋他們將在檢視器中看到什麼——包括質化輸出和量化基準測試。
步驟 3:當執行完成時,捕獲計時資料
當每個子代理任務完成時,你會收到通知,但它不會攜帶令牌計數或經過時間。你自己從牆上時鐘記錄持續時間,並從子會話記錄中讀取令牌總數,該記錄位於 ~/.dsh/storages/session_projcache/sessions/<childId>.json(tokenUsage.val.totals——uncachedInputTokens、outputTokens、cacheReadTokens、cacheWriteTokens)。立即將此資料儲存到執行目錄中的 timing.json:
{
"total_tokens": 84852,
"duration_ms": 23332,
"total_duration_seconds": 23.3
}
如果該會話記錄缺失或沒有令牌使用資料,則省略令牌欄位,而不是編造數字。在每個通知到達時處理它,而不是嘗試批次處理它們。
步驟 4:評分、彙總並啟動檢視器
所有執行完成後:
-
為每個執行評分——啟動一個評分子代理(或內聯評分),讀取
agents/grader.md並根據輸出評估每個斷言。將結果儲存到每個執行目錄中的grading.json。grading.json 的 expectations 陣列必須使用欄位text、passed和evidence(而不是name/met/details或其他變體)——檢視器依賴這些確切的欄位名稱。對於可以程式化檢查的斷言,請撰寫並執行腳本,而不是目測——腳本更快、更可靠,並且可以在多次迭代中重複使用。 -
彙總到基準測試——從 dsh-skill-creator 目錄執行彙總腳本:
python -m scripts.aggregate_benchmark <workspace>/iteration-N --skill-name <name>這會產生
benchmark.json和benchmark.md,其中包含通過率、時間和令牌資料。
感謝使用 Anuii/skills!