unlazy skill 的 Depth Tree 方法與安裝指南
了解 unlazy skill 如何防止 agent 過早宣告完成,包含 Depth Tree、gates files、PLAN.md contract、安裝步驟,以及 version 2 每層深度的實際成本。
unlazy skill 的作用
unlazy skill 是一項 agent skill,用來防止一種失敗情況:coding agent 在工作尚未完成前,就回報工作已完成。它的核心是 Depth Tree,會將工作拆分成多個層級,並只將最底層視為實際工作。Version 2 將強制執行機制從文字說明移至檔案中,因此 agent 必須根據一份可執行命令清單證明工作已完成,而不能只自行宣稱完成。
此 skill 由 Leonxlnx 以 MIT license 發布於 github.com/Leonxlnx/unlazy。本指南以 2.0.0 版為基準,該版本於 2026-08-10 發布。這類 skill 的變動很快,因此請先閱讀儲存庫中的 CHANGELOG,再將其中內容複製到持續執行的設定中。
此處所說的 skill,是指通常的定義:一個 SKILL.md 檔案,當任務符合其說明時,由 harness 載入 model 的 context。如果你不熟悉這項機制,請先閱讀什麼是 agent skill,以及 harness 如何載入它。unlazy 是純 markdown 搭配少量 Node scripts,不需要伺服器,也不需要自己的 API key。
為什麼 agents 會在 80% 停止,漏掉你的第 3 項指令
這種行為有可辨識的模式。你要求 4 件事。回覆涵蓋第 1、第 2 和第 4 件。結尾摘要卻將 4 件事全部列為已完成。過程中沒有發生錯誤,因此也沒有任何機制標記問題,而你在 1 週後才發現遺漏。
unlazy README 將此現象與已發表的 model laziness 研究連結,並引用「回覆過早截斷,以及對多部分請求僅部分遵從」(引用來源為 arXiv 2512.20662)。同一份 README 也明確說明其設計前提:文字無法強制文字。要求 agent 更加努力,只是增加更多文字,放入產生缺漏的相同 context 中。
因此,version 2 將狀態保存在檔案中。GATES.md 中的核取方塊不受 model 自行決定。方塊下方要嘛有證據行,要嘛沒有,而 script 不必詢問 agent,就能告訴你是哪一種情況。
Depth Tree:逐層說明
Depth Tree 是一種分解方法,並規定工作可以在哪個層級執行。方法參考文件指出:
在自然接點進行拆分;自然接點允許時採用二元拆分;深度為 N 層。
只有葉節點會執行實際工作;其上每一層都負責分解與整合。
葉節點不只是條列項目。參考文件設定了最低規模:
葉節點是實際的工作單位。需要投入 10 分鐘以上的專注工作,產出一項一致的交付成果,並具備一個 gates 檔案。
這個最低規模可避免深層樹狀結構變成無意義的忙碌。如果葉節點的內容只是「重新命名變數」,就不符合這項標準,表示上層拆分多了一層。
每個葉節點都會執行 4 個階段:完整實作,不留下 placeholder;以領域專家的方式重新閱讀;尋找缺陷;最後在成本低廉時進行潤飾。這些階段也是葉節點需要最低規模的另一個原因。對 2 分鐘的變更執行 4 個階段,只是在做表面工作。
呼叫 skill 時決定深度:
/unlazy tree 5 refactor the payment module也可以使用一般語言,因為 skill 的說明是依照意圖比對,而不是依照 slash command:
tree 3 build the landing page and do not stop until every gate is checked參考文件提供了深度範圍。tree 2 或 3 適合功能、錯誤搜尋或文件,通常由單人於一個工作階段完成,分成 2 到 4 個葉節點。tree 4 或 5 適合子系統、重構或正式審查,通常包含 8 到 16 個葉節點;此時已經「超出單一 context 能妥善掌握的範圍」。tree 6 或 7 適合整個專案,需以 orchestrated mode 執行,並將葉節點對應到彼此不重疊的工作單位。
未指定深度時,skill 會被要求「選擇葉節點符合工作自然部分的最小 N」,並明確要求預設不要再多拆一層。深度應反映工作的規模,因此提高數字不會提升品質。
gates 檔案的格式
在開始任何工作前,代理程式會將驗收條件寫入 gates 檔案。每個 gate 都是核取方塊,下面列出一個命令。
# Gates: pricing section
- [ ] G1: three tiers render with real copy
CHECK: node check.js pricing --tiers
EXPECT: 3/3 tiers ok
EVIDENCE: pending
- [ ] G2: annual toggle changes both price and label
CHECK: node check.js pricing --toggle
EXPECT: toggle ok
EVIDENCE: pendingCHECK 是命令。EXPECT 是代表通過的輸出。EVIDENCE 從 pending 開始,必須替換為命令實際輸出的內容。此 skill 提供 scripts/gate-check.mjs,可掃描這些檔案並回報哪些 gate 仍未關閉。這樣一來,您不必閱讀逐字記錄,也能稽核一次執行結果。
這項原則可以濃縮成一句話,SKILL.md 也將其寫成一句話:
報告是由帳冊支持的一組主張,絕不是完成工作的主觀感覺。
接續的規則是「帳冊填滿前不得提交報告」。此外,報告規則要求最終摘要中的每個數字都必須在報告時重新測量,或標示為未驗證。gate 不能因代理程式覺得工作已完成而關閉,因為關閉 gate 代表貼上符合 EXPECT 或不符合 EXPECT 的輸出。
請撰寫讓陌生人也能執行的 gates。「看起來沒問題」不是檢查。test -s dist/index.html && echo ok 顯示 ok 才是檢查,因為檔案為空或不存在時,命令會明確失敗。
在任何平行工作開始前,先定義 PLAN.md 契約
當樹狀工作展開到足以讓葉節點在不同內容中執行時,這些葉節點便不再共享相同的假設。方法參考要求在分工前先建立契約:
分工前先定義契約。介面、資料擁有權、命名方式及錯誤慣例,都必須在任何葉節點開始前寫入 PLAN.md。
原因很明確。若分別要求兩個子代理程式「加入錯誤處理」,它們會建立兩種不同的錯誤格式,而且兩個葉節點都能通過各自的檢查,因為各自的實作在本地都是正確的。只有在兩者整合時,問題才會出現。分支檢查就是為了處理這種情況:分支的檢查必須證明「子節點已合併、介面一致、端對端行為正常,且沒有造成同層回歸問題」。
在協調模式中,驅動程式會將 PLAN.md 的契約區段交給每個子代理程式,而不是整份檔案或驅動程式本身的歷程;同時也會原封不動地提供該葉節點的 gates 檔案。子代理程式返回後,驅動程式會自行重新執行檢查。若子代理程式「在沒有證據的情況下自行勾選完成項目」,驅動程式會指出未滿足的具體檢查,要求其重新處理。
協調工作有最低門檻。若實際工作時間大約少於 30 分鐘,參考方法建議維持單獨作業,因為每個子代理程式都必須從頭建立對工作的理解,而這項準備成本通常高於額外專注力所帶來的效益。
如何安裝 unlazy skill?
支援的方式是使用 skills CLI:
npx skills add Leonxlnx/unlazy手動安裝時,請將儲存庫複製到 agent 的 skills 目錄:
git clone https://github.com/Leonxlnx/unlazy ~/.claude/skills/unlazygit clone https://github.com/Leonxlnx/unlazy ~/.codex/skills/unlazy接著確認檔案已正確放置:
ls ~/.claude/skills/unlazy/SKILL.md輸出的路徑表示檔案已存在於磁碟上。No such file or directory 表示複製到了其他位置,通常是因為 skills 目錄不存在於你假定的名稱下,導致 git 建立了新的目錄。也不要只相信 agent 的回覆。README 自己的安裝提示最後也會顯示相同警告:「除非你已實際確認檔案存在於磁碟上,否則不要告訴我它已安裝。」
如果 harness 沒有 skill loader,請將 SKILL.md 的內容貼到 system prompt 或規則檔案中。這是文件記載的替代方式,因此此方法可在 Claude Code、Codex、Cursor,以及任何能讀取純 markdown 指示檔案的工具上執行。如果你想了解 SKILL.md 一開始要如何可靠載入,撰寫自己的 agent skill 會說明決定它是否能觸發的 frontmatter 與描述比對方式。
Stop hook 能在 Claude Code 以外的環境中運作嗎?
不能。這一點必須說清楚。上文全部都是指示,而指示可能被忽略。唯一提供結構性強制機制的是 Stop hook,而 Stop hook 是 Claude Code 的功能。
node <path-to-skill>/scripts/install-hooks.mjs # this project only (settings.local.json)
node <path-to-skill>/scripts/install-hooks.mjs --global # every project
node <path-to-skill>/scripts/install-hooks.mjs --uninstallStop hook 會在代理程式嘗試結束回合時執行。此 hook 會掃描 gates 檔案;只要仍有未滿足的 gate,就會阻止停止。因此,尚未勾選的項目會讓回合無法結束。它只會讀取檔案,不會呼叫模型,所以 README 才會說它不耗用任何 token。如需瞭解這項機制,以及可附加 hook 的其他事件,請參閱 Claude Code hook 如何在回合前後觸發。
它設有釋放機制,這項設計比表面上更重要。如果代理程式連續六次遭到阻止停止,且 gate 都沒有進展,hook 會顯示警告後放行,而不是讓代理程式陷入循環。只要出現 ABANDON: <gate> <reason> 行,就一定會視為正常結束。若沒有這兩個退出機制,環境中無法完成的 gate 可能會持續耗用 token,直到你親自終止工作階段。
在 Codex、Cursor 或其他 harness 上,install-hooks.mjs 沒有可安裝 hook 的位置。你仍然會取得 gates 檔案與可執行的檢查,但沒有結構性機制阻止模型提前結束回合。在這些環境中,gates 檔案就是一份必須由你自行閱讀的文件。
unlazy 還是 ponytail:你需要哪一個?
這兩項技能在同一個時期受到關注,而且在工作量上方向相反,因此很容易混淆。
ponytail 會讓代理程式表現得像資深開發者,先確認程式碼是否根本不需要存在。它會縮小範圍、優先使用標準函式庫,並減少差異內容。unlazy 則假設範圍已經確認,持續投入工作,直到範圍內的每個部分都完成並經過驗證。
因此,請根據你實際遇到的失敗情況選擇。如果代理程式把小型功能做成一套 framework,你需要 ponytail 技能及其懶惰資深開發者角色。如果代理程式遺漏四部分請求中的第三項,卻回報成功,你需要 unlazy。
兩者可以同時使用,而且順序很重要。先用 ponytail 的問題確定範圍,再將確認後的範圍交給 unlazy 的關卡處理。反過來做,會先為 ponytail 原本會刪除的工作建立一棵葉節點樹,接著再為全部工作付出深度乘數的成本。這個順序是我的建議,不代表兩個專案之間有已記錄的整合方式。
VPS 託管代理程式的深度成本是多少?
深度會放大工作量,而工作量會轉化為 token。若 VPS 上的代理程式使用你自己的 API key 執行,這個乘數也會轉化為費用。
The data behind this chart
[
{
"label": "Skill run vs no skill, output tokens",
"low_multiplier": 1.6,
"high_multiplier": 3.9
},
{
"label": "tree 6 vs tree 3, total cost",
"low_multiplier": 1.0,
"high_multiplier": 1.5
}
]以上數據來自作者於 2026-08-10 進行的測試。我們尚未重現這些結果,因此應將其視為趨勢,而不是預測。單獨執行時,輸出量約為基準的 1.6 至 3.9 倍;但在同一個 context 中將樹深度從 3 增加至 6,只增加了 1.0 至 1.5 倍,遠低於多進行 3 次二元分割所預期的 8 倍。
深度增加不會按比例提高成本,因為深度是在重新分配工作量,而不是增加 context。token 經濟性的參考資料明確指出,真正的成本乘數來自協調流程:「會使成本倍增的是協調流程,而且本來就應該倍增,因為每個葉節點都會建立一個新的 context。」單獨模式只會在同一個 context 中增加輸出 token。協調模式則會增加 context,而每個新的 context 在執行任何有效工作前,都會重新讀取契約與 gates 檔案。
另一項容易忽略的成本也由同一份參考資料指出。其測試中的一次單體式深度執行,「消耗了約 58 million 個 cached input token」,因為單一且持續增長的 context 承載了所有內容。cached input 的單位 token 費用較低,但達到這種用量後,仍會反映在帳單上。
以下 4 項設定可由此推導:
- 選擇葉節點能代表實際工作單位的最小深度,然後停止。用不到的深度,就是不需要支出的費用。
- 工作時間少於 half an hour 時,維持 solo mode,因為在這種情況下,建立 subagent 的成本高於新 context 帶來的效益。
- 如果使用 Claude Code,請安裝 Stop hook。這是其中唯一免費執行的部分。
- 在開始任何長時間工作前,先於帳戶層級設定明確的費用上限。
最後一點最值得直接說明。設計為拒絕提早停止的 skill,本來就會持續工作。預算與警示是獨立於提示設計之外的工作,而 在 VPS 上控制代理程式的成本說明了應優先設定的上限。
作者測量了什麼,以及這證明了什麼
該儲存庫發布了自己的測試,這種做法比應有的情況少見。README 中引用的測試設定如下:「兩項從零開始建置的任務(行銷網站和 three.js 太陽系)、每項任務各有三種條件(無 skill、tree 3、tree 6),每次執行都使用新的資料夾與新的工作階段,模型相同,提示本文相同。每個輸出都由獨立代理程式進行程式碼審查,再以對抗方式重新驗證,並在瀏覽器中進行即時測試。」
The data behind this chart
[
{
"label": "Self-found defects fixed, skill runs",
"low_count": 4,
"high_count": 10
},
{
"label": "Wrong numbers in report, skill runs",
"low_count": 1,
"high_count": 3
},
{
"label": "Wrong numbers in report, baseline runs",
"low_count": 0,
"high_count": 0
}
]請把中間那一列讀兩次。在作者自己的測試中,使用 skill 時,代理程式會在交付前自行找出固定 4 到 10 個缺陷;但每次執行 skill 後產生的最終報告,仍含有 1 到 3 個錯誤數字,而基準執行中則是 0 個。投入更多工作後,建置結果更好,但摘要更差。這就是分類帳規則的依據,也是為什麼指示要求在報告產生時重新測量每個數字,否則就標記為未驗證。
他們的另一項結果也值得保留:「唯一一次嚴重的即時失敗發生在基準建置,而其報告卻聲稱該案例已處理。」在損壞的建置上方放置一份看似可靠的摘要,正是各項閘門要防止的情況。
接著說明限制。共有 6 次執行、2 項建置任務、1 個模型,而且由該 skill 的作者自行執行並回報。這些結果都不是獨立複製的研究;截至 2026-08-10,我們引用的只是作者的聲稱。請改在自己的工作上測試:將相同任務執行 2 次,一次不使用額外設定,另一次使用 gates 檔案,然後計算有多少個閘門以你自己能重新執行的證據完成關閉。這個數字才是這個領域中真正屬於你的唯一數字。
FAQ
unlazy skill 中的 Depth Tree 是什麼?
這是一種分解方法。任務會沿著自然分界拆分成 N 層,只有最底層的葉節點才算工作。此 skill 將葉節點定義為至少投入 10 分鐘的專注工作,並產出一項一致的交付成果與一個 gates 檔案。因此,如果某個葉節點只需 2 分鐘即可完成,表示拆分多深入了一層。葉節點以上的每一層都屬於分解與整合;每個分支也都有自己的 gates,用來證明子項目已合併且介面相符。呼叫此 skill 時可指定深度,例如 tree 5;文件記載的預設值,是能讓葉節點成為實際工作單位的最小深度。
unlazy skill 能在 Claude Code 以外的環境運作嗎?
部分可以。此 skill 是純 Markdown,因此 Codex、Cursor,以及任何能讀取 SKILL.md 或 system prompt 的工具,都能使用 Depth Tree、gates 檔案、可執行檢查與每個葉節點的 4 次處理流程。但強制執行方式不同。當 gates 尚未達成時,會阻止回合結束的 Stop hook 是 Claude Code 的功能,透過 node <path-to-skill>/scripts/install-hooks.mjs 安裝。在其他環境中,沒有任何結構能阻止模型提早結束回合,因此必須由你讀取 gates 檔案,再將其傳回模型。
unlazy skill 會增加多少 token 費用?
作者回報,在單獨模式下,使用此 skill 的輸出 token 數量約為無 skill 執行的 1.6 至 3.9 倍,另外 gates 檔案本身會增加幾百個 token 的額外負擔。在同一個 context 中加深層級,相較之下幾乎不需額外成本;從 tree 3 提升到 tree 6 時,約為 1.0 至 1.5 倍。編排模式的成本較高,因為每個葉節點都會建立新的 context,並在開始工作前重新讀取契約與 gates。Stop hook 不會增加成本,因為它只會掃描檔案。以上是作者截至 2026-08-10 提供的數據,不是我們重新測量的結果。
我應該使用 unlazy 還是 ponytail?
請依目前的失敗模式選擇 skill。ponytail 適合寫得過多的 agent,因為它會扮演資深開發者,先確認程式碼是否確實需要存在,並優先使用標準函式庫。unlazy 適合未完成你所要求工作內容的 agent,因為它會強制進行分解,且沒有證據就不會關閉 gate。如果兩者都要使用,先用 ponytail 確定範圍,再將該範圍交給 unlazy。這樣就不會為原本應刪除的工作支付 effort multiplier。
為什麼安裝 unlazy 後,我的 agent 仍然會提早停止?
請檢查 4 件事。第一,使用 ls ~/.claude/skills/unlazy/SKILL.md 確認 skill 已存在於磁碟上,因為 clone 到不存在的目錄是最常見的遺漏。第二,確認工作開始前已寫入 gates 檔案,因為 hook 會掃描 gates 檔案,而缺少 GATES.md 時就沒有可阻擋的項目。第三,確認 hook 的安裝位置:單純執行 install-hooks.mjs 只會將 hook 寫入此專案的 settings.local.json,因此其他專案需要使用 --global。第四,請記住,release valve 的行為是設計如此:如果連續 6 次被阻擋的停止都沒有 gates 進度,agent 會在顯示警告後繼續執行;而 ABANDON: <gate> <reason> 行則會刻意結束此次嘗試。