在 Perplexity 設計、精進與維護 Agent 技能

Perplexity 如何編寫、審查與維護 Agent 技能,以及我們工程師用來建構它們的指南。

作者Perplexity Engineering

Perplexity 的前沿代理產品建構於模組化 Agent 技能中封裝的know-how與領域專業知識之上。我們在技術環境中維護了一個精心策劃的技能庫。這些技能包含驅動 Perplexity Computer 的許多通用公用程式、財務、法律與健康等領域的垂直特定功能,以及用於滿足使用者需求的極長尾模組。部分技能雖不常被呼叫,但在被呼叫時至關重要。當為了確保始終如一的卓越使用者體驗,Perplexity 的代理團隊對技能品質的重視程度與程式碼品質不相上下。

開發高品質技能所需的直覺與最佳實務,與建構傳統軟體所需的直覺和實務有很大差異。代理團隊會審查來自優秀工程師的許多 Pull Request,這些工程師在工作過程中開發技能。其結果幾乎總是會產生大量評論與修改建議。這是因為許多撰寫程式碼的有益模式,在建立技能時反而變成了反模式。

舉例來說,如果您借鑑 PEP20 – Python 之禪 中的某些格言,就會很快發現編寫優秀的 Python 程式碼與編寫優秀的技能截然不同。在這 20 條智慧中,至少有一半在編寫技能時是完全錯誤或具有主動誤導性的。以下其中五條為:

Python 之禪

技能之禪

簡單比複雜好

技能是一個資料夾,而不是一個檔案。複雜性就是特色。

明確比隱含好

啟用是隱含的模式匹配。逐步揭露。

稀疏比密集好

上下文成本高昂。每個 Token 的信號最大化。

特殊情況不足以打破常規

陷阱(Gotchas)確實是特殊情況(它們是價值最高的内容)。

如果實作容易解釋,那可能是一個好主意

如果很容易解釋,模型已經知道了。刪除它。

Python 的 Zen 與文章中關於撰寫技能的指引之間的五個對照。

本指南是 Perplexity 各地的工程師在開發與審查技能時所使用的文件。我們也將本指南公開發布,以便我們的發現與學習成果能造福更廣大的社群。無論您是日常工作中設計正式環境技能的工程師、尋求在最熟悉的領域中開發自己的技能的 Computer 使用者,或是兩者兼具,本指南都非常適合您。

什麼是技能?

當您編寫技能時,您並不是在編寫普通的舊軟體(儘管技能現在是代理系統主要邏輯引擎的一部分)。相反地,您是在為模型及其環境建構上下文。技能有不同的限制與不同的設計原則。如果您像寫程式碼一樣寫技能,您將會失敗。

技能至少包含四個事項,特別是在我們於 Perplexity 建構技能的上下文中。

技能是一個目錄

技能不只是單一的 SKILL.md 檔案。在許多情況下,技能包含多個檔案。在以您的技能命名的目錄下,您可能會擁有:

SKILL.md:frontmatter 與指令

scripts/:代理執行的程式碼,而非重新發明

references/:大型文件,有條件地載入

assets/:範本、Schema 與資料

config.json:首次執行使用者設定

這種中樞與輪輻模式可讓您保持技能高度專注與緊湊,並且可以非常具創意地使用資料夾結構。有時候,特別複雜的技能會受益於多層次的階層架構,以協助模型更好地導航。假設一項技能需要跨越 300 個主題的知識,這些主題可以分組為 20 個主題領域。對於當今最好的前沿模型來說,在 300 個主題中可靠地選擇正確的主題仍然是一個未解的挑戰。對模型而言,從 20 個領域中鎖定其中一個,要比在該領域內的 15 個主題中選擇來得容易得多。

作為多層次階層架構如何提供價值的其中一個例子,在過去的報稅季中,我們的團隊在驅動 Computer 美國所得稅功能的技能中採用了三層主題巢狀結構。鑑於稅法的複雜性,這種階層架構絕對不可或缺:在我們的早期測試中,向模型呈現包含美國國內稅收法規所有 1,945 條文的單一資料夾,其效能甚至比完全不載入技能還要糟糕。將資訊組織成邏輯細分對於確保高精度讀取操作至關重要。

然而,這種階層架構並非沒有代價。不斷增加的階層層級需要在資訊架構中進行不斷增加的策劃級別,以管理由此產生的間接性。我們設計了快速參考指南、自訂搜尋公用程式以及其他工具,以支援模型以最少的間接性來定位資訊。在這種情況下,進行艱巨的策劃工作最終產生了積極的成果:一項技能讓模型能夠執行與稅務相關的任務,其能力遠遠超過單獨使用通用工具。

以 Computer 的稅務相關技能製作的 Schedule C 稅務計算機。

技能是一種格式

技能是一種格式。核心根目錄 SKILL.md 檔案必須同時具有名稱和描述。此外,技能需要與技能所在的目錄名稱完全對應。名稱必須全部為小寫字元、沒有空格,且可以使用連字號。描述是路由觸發器。這是一個常見的失敗點:描述不是關於該技能做什麼的内部文件。它相當於給模型的指令,說明何時載入該技能。因此,您會經常看到「Load when...」(何時載入),而不是「This Skill does...」(此技能執行...)。這之所以重要,是因為大多數實作將描述注入模型上下文的方式。

在 frontmatter 中,還有「depends:」,可讓你建立階層式的 Skill 相依關係,以及「metadata:」,用於審閱和評估。不同的 Agent 系統甚至可以定義自己的 frontmatter 欄位,並以該等系統特有的方式加以使用。作為替代方案,特定 Skill 的中繼資料可以封裝在附屬的 JSON 或 YAML 設定檔中。當建立需要針對每個 Skill 區分不同執行階段行為的 Agent 系統,而又不想讓模型的上下文被瑣碎細節污染時,這種做法很理想。最後,也可以透過在讀取時移除 Skill frontmatter 來達成類似行為。Computer 採用這種方法,因此設定可保留在根目錄的 SKILL.md 檔案中。解析邏輯需要非常仔細地處理細節,而在某些欄位對模型上下文而言有其用途時,也可能需要實作條件式移除。

技能是可以呼叫的

技能是可以呼叫的。代理在執行期載入技能。重要的是,技能並不總是打包到上下文中。預設情況下,大多數代理系統會根據特定需求逐步展開技能。

我們在 Computer 中實作技能的方式中,至少有三個層級的上下文成本。過程如下:

Computer 呼叫 load_skill(name="...")

Computer 將技能目錄複製到隔離的執行沙箱中

Computer 遞迴地自動載入「depends:」標籤中的相依性

然後 Computer 會剝除 frontmatter,因此代理程式只會看到主體與額外的檔案

不同的代理系統可以選擇以不同的方式公開技能内容。舉例來說,某些系統可能會選擇完全不公開檔案階層,而是由模型透過檔案系統操作來探索階層。其他系統可能會選擇向模型提供達到特定截斷和/或深度限制的整個檔案樹的對應。為了保持上下文乾淨,Computer 從呼叫上下文中省略了完整的檔案階層;不過,這可以根據每個技能進行覆寫。

技能是漸進的

技能是漸進的。在 Computer 中,有三個不同的上下文成本層級,我們會在各種階段承擔所有這三個層級:

層級

載入内容

預算

何時付費

索引

名稱:每個非隱藏技能的描述

每個技能約 100 個 Token

每個工作階段、每個使用者,總是付費

載入

完整的 SKILL.md 主體

約 5,000 個 Token

約 5,000 個 Token

執行期

scripts/、references/、assets/、子技能、FORMATTING.md、SPECIAL_CASES.md 中的檔案

無限制

僅在代理讀取它們時

技能內容的三個層級:索引、完整技能載入,以及執行階段參考檔案。

Computer 建構了一個技能索引,其中包含每個可用技能的名稱與描述。這部分的預算大約是每個技能 100 個 Token(越短越好)。之所以如此嚴格,是因為您在每個工作階段、針對每個使用者都要支付這項成本。這會在對話剛開始時注入到系統提示詞中。模型可以存取一堆具名技能與描述,以便它可以決定是否呼叫「load_skill()」。進入這個索引的門檻極高。您的技能需要非常有用,且描述需要極度密集和簡潔,因為每個人隨時都在支付這項成本。

在代理系統載入技能之後,便是完整的 SKILL.md 主體。理想情況下,主體文字不超過 5,000 個 Token。即便如此,您也會希望每個句子都發揮作用,因為一旦您載入技能,在達到壓縮邊界之前,其餘的對話都必須支付這項成本。許多執行緒會載入三到五個不同的技能,從而將這項成本乘以數倍。充滿冗言贅字的技能幾乎肯定會降低其他技能以及整體代理能力。簡而言之,如果您的技能載入了卻沒有做對的事,那就是浪費上下文。

漸進的最後一個層級是腳本或特殊情況,例如子技能或格式化。這是您想要放置無限制條件分支邏輯的地方。代理只會在需要時才使用它,這意味著您想要放在這裡的内容的門檻要低得多。

在索引中,每個 Token 都很重要。已載入的技能主體較為放鬆,而執行期則是最放鬆的。這可以是 20,000 個 Token 或零個Token。這是您可能會考慮以漸進方式擴展模型上下文的層級。

什麼時候需要技能?

代理團隊經常被要求就某個領域或使用案例是否真的需要技能發表意見。我們極少能從第一原理單獨得出確切的答案。真正找出答案的唯一方法是從沒有技能的代理開始,執行幾個主要查詢,然後判斷代理的表現是否良好。

當您需要技能時

有許多任務是在已訓練模型的分佈範圍之內的。只有當您想以某種特定方式改變該行為,而無法透過提示詞中的一句話來達成時,您才需要套用技能。因此,當代理在沒有特殊上下文的情況下會出錯,或者如果您需要確保跨執行的高度一致性而存在某些不一致性或非決定性時,您就需要技能。

這可能是因為你的知識很持久,但不在訓練資料中。這可能是由於時間截止點或企業專屬工作流程,也可能只是個人喜好的問題。例如,我們在 Computer 中有幾個由 Henry Modisett(我們的設計主管)所撰寫的設計相關「技能」。這些「技能」中之所以存在每一個 Token,是因為 Henry 在設計網站和 PDF 方面擁有極佳的品味。Henry 指定了要使用哪些字型、不該使用哪些字型、這些字型給人什麼樣的 感覺,以及其他模型無法單從訓練資料中學習的判斷標準。

當您不需要技能時

我們看到許多技能,其中的工程師寫了一系列需要依序執行的 git 指令。這是沒必要的,因為模型已經知道如何做到這一點,這意味著它造就了優秀的文件,卻是不佳的技能。

我們看到一些範例,其中的技能重申了來自系統提示詞的指令。您不需要為此使用技能。與大多數請求相關的知識應該包含在全域上下文中,而不是在有條件載入的技能中。

如果有某個東西變化的速度快過您維護它的速度,您就不需要技能。舉例來說,如果您正在存取某些遠端 MCP 端點,且其工具或這些工具的版本頻繁變更,您就不應該將這些注入技能中。如果您這樣做,最終只會導致飄移,且模型會犯錯。

每個技能都是一筆稅

這裡有一個您可以套用到技能中每一個句子的實用測試:「如果沒有這個指令,代理會弄錯嗎?」如果句子不需要存在,它就負擔不起存在的代價,因為每個人每次都在支付這項成本。當您在決定是否要新增技能時,請記住這項稅,其中每個工作階段和每個使用者都要花費 Token。

以下這句著名的名言(用法文聽起來好聽得多)大致翻譯為:「我這封信之所以寫得這麼長,是因為我沒有時間把它寫短。」

« Je n’ai fait celle-ci plus longue que parce que je n’ai pas eu le loisir de la faire plus courte. » — Blaise Pascal, Lettres Provinciales, 1657

就像 Pascal 一樣,您需要在每個技能上投入時間。編寫簡短的技能很難。如果您的技能很容易編寫,它可能太長了,或者根本不該存在。一個好的技能應該要盡可能簡短。

如果您發現自己試圖一次性產生技能並在五分鐘內送出 PR,其結果幾乎肯定是次標準的。事實上,早期研究顯示,如果您使用 LLM 來編寫技能,LLM 可能不會從中受益:「自主產生的技能平均無法提供好處,這表明模型無法可靠地編寫它們從中受益的程序性知識。」

如何建構技能

換句話說,您需要在您編寫的任何技能中注入您的意見。請遵循以下步驟。

步驟 0:編寫評估(Evals)

先編寫一些評估。您可以從以下來源取得評估案例:

真實使用者查詢:從正式環境或您的智囊團中進行取樣

已知失敗:代理失敗是因為技能不存在

鄰近混淆:接近您的領域邊界,但路由至另一個技能

至少,您應該確保測試該技能是否在需要時載入。理想情況下,您可以對其中一些進行取樣,或許從正式環境中取樣。您也可以考慮已知的錯誤案例:也許您著手編寫技能的整個原因是因為您注意到的特定失敗,或者您正在進行重構,而由一個技能涵蓋的兩個相近領域中存在一些混淆。

最後,針對不同的模型執行這些評估是很重要的。Computer 支援至少三個不同的協調模型系列:GPT、Claude Opus 與 Claude Sonnet。您會希望針對這些不同的代理協調器執行您的技能載入與領域技能,以確保您不會得到不同的行為。Sonnet 和 GPT 在處理技能時表現相當不同。

步驟 1:描述

這是 Skill 中最難的一行。這是一個路由觸發器,不是文件說明。要把名稱和描述寫對,你不需要在意 Skill 的內容。你只需要在意 Skill 是否在正確的時間點被載入並注入,以及是否沒有產生偏離目標的副作用,這是頭號失敗模式。每當你新增一個額外的 Skill,你都會有讓每個其他 Skill 稍微變差的風險,所以你需要確保自己把回歸降到最低。

再次強調,糟糕的描述描述了技能做什麼或為什麼有用。好的描述則說明代理何時應該載入該技能。舉例來說,假設您有一些用於監控 Pull Request 的東西。不要寫該技能做什麼。寫下工程師在感到沮喪並希望您確保他們的 PR 正常運作時所說的話,例如「babysit」(照顧)、「watch CI」(監視 CI)或「make sure this lands」(確保這能合併)。

以下是快速檢查清單:

以 "Load when..." 開頭

目標為 50 個字或更少

描述使用者的意圖,理想情況下來自真實查詢

不摘要工作流程

真實查詢是您可以在 80-20 法則中涵蓋的内容。通常,兩到三個範例運作良好。要精確且僅僅新增您需要的數量並不容易。

步驟 2:編寫主體

接下來,編寫技能本身的內容。請注意,這不是步驟 0 或步驟 1。

將工作流程傳達給 LLM,與將工作流程傳達給同事、甚至傳達給您的執行期系統完全不同。在學習新的軟體工具時,工程師可能需要閱讀文件、由有經驗的人進行逐步解說,並學習如何使用該工具。同時,對於存在至少一年的幾乎任何軟體工具,您只需要提及它的名稱,LLM 就擁有它所需的所有資訊。

當您在編寫主體時,請跳過顯而易見的事情。許多工程師有豐富的經驗來編寫 readme.md 檔案,列出某人需要執行的每個指令。當您在編寫技能時,很容易退回到這種狀態,因為感覺就像是在寫文件,但如果您這樣做,您的技能將會是垃圾。因此,請勿寫出一系列指令。

舉例來說,您不需要寫:「git log # 尋找 commit;git checkout main;git checkout -b <clean-branch>;git cherry-pick <commit>;」

相反地,請寫:「將 commit 挑選(cherry-pick)到乾淨的分支上。解決衝突同時保持意圖。如果無法順利合併,請解釋原因。」

模型使用後者的表現會比前者過於處方的指令系列好得多,特別是在事情出錯時。不要獨裁,也不要過於處方(這很脆弱),而是在多種方法都能行得通時保持彈性。再次強調,對人類而言好的文件,對模型而言通常是糟糕的文件。

接下來,聚焦於陷阱或負面範例。這些是極高信號的內容,因為它們通常在不該做什麼方面引導模型。如果您在代理出錯時每次都新增一行,您將透過執行它來學習,並且陷阱將以有機方式成長。

最後,如果有任何部分是具條件的或是內容極為繁重,請將它從作為中樞的 SKILL.md 中移除,並將其放入其中一個輪輻中。將其放入可以逐步載入的輔助檔案中,我們接下來將深入探討。

步驟 3:使用階層架構

當您擁有腳本、參考資料或正在使用某些特定工具時,請善用技能階層架構:

scripts/ 代理每次執行都會重新發明的決定性邏輯

給它程式碼來組合,而不是重建

references/ 僅在滿足條件時載入的大型文件

"如果 API 傳回非 200,請讀取 api-errors.md"

assets/ 代理複製並填寫的輸出範本

report-template.md、輸出 Schema

config.json 首次執行使用者設定

詢問 Slack 頻道、儲存並在下次重複使用

技能內指令碼、參考資料、資產與組態的建議用途。

對於從主技能延伸出的任何具條件或分支的内容,請將其拆分到資料夾中。同時請記住,多層次階層架構可用於特別複雜的技能。對於這些,您需要仔細考慮該功能應該以單體方式實作,還是作為技能集合來實作(可能透過基於 depends: 的載入關係)。

步驟 4:迭代

接下來,在分支上進行一堆迭代。從沒有技能的主分支開始,進行一些迭代,建構您的主要查詢集,並執行一連串評估。任何審查您技能程式碼的人都會感謝您提交包含評估集的單一變更集。審查連續的增量變更(新的陷阱除外)非常困難,因此請盡量將其減到最少。

您可能會進行許多小的字詞更改。描述中的小字詞更改可能會對路由產生巨大影響(包括對其他技能的溢出效應),因此請在步驟 5 之前完成所有這些工作。

步驟 5:發布

發布它。

如何維護技能

既然您已經編寫了技能,您就必須維護它。

陷阱飛輪

從這一點開始,您的陷阱清單往往會大量增長或變更。我們經常看到工程師提交未經評估的 PR,例如變更描述。如果您在技能合併後才變更描述,您就走偏了。如果您正在對決定是否路由您技能的東西進行變更,您需要編寫一些支援這些變更的評估。

技能主要是附加式的。陷阱區段隨著時間累積最多價值:

代理在某事上失敗 → 新增陷阱

代理偏離目標載入技能 → 收緊描述並新增負面評估

代理未能在應該載入時載入技能 → 新增關鍵字與正面評估

系統提示詞變更 → 檢查衝突或重複

在内部測試或正式環境中注意到單一失敗案例並新增陷阱是很簡單的。這是一個負面範例,所以它並不是真的在變更明確的指引,但它讓模型知道:「嘿,這裡有這個已知的失敗。」

當您從 80-20 法則邁向達到 99.9% 或 99.99% 的成功率時,增長這個陷阱清單是很容易的。當您看到這些負面範例時,您應該主要是附加到陷阱區段。您不應該新增更長的指令或變更描述。

評估套件

在 Perplexity,我們執行許多評估套件來檢查不同的事項。有技能載入與技能檔案讀取,這會檢查技能載入本身的精確度、召回率與禁止檢查。當代理應該路由您的技能時,它會這樣做嗎?這些確保了新的技能不會破壞現有的邊界。

也有可以檢查適當漸進式載入的評估。代理可能會載入技能,但它會讀取輔助檔案嗎?舉例來說,如果您有針對財務查詢的財務技能,它會讀取特殊的 FORMATTING.md 檔案嗎?

也有針對技能的評估,用於測試領域內的端到端任務完成度。我們執行完整的代理迴圈,並使用 LLM 評審員根據明確定義的標準評分表對結果進行評分。

最後,針對不同的模型執行這些評估非常重要。Computer 支援至少三個不同的編排模型系列:GPT、Claude Opus 和 Claude Sonnet。你應該針對這些不同的代理程式編排工具執行「技能」載入與領域「技能」,以確保不會產生不同的行為。Sonnet 和 GPT 在處理「技能」時,其行為表現有很大的差異。

最後的想法與重點整理

您建構的技能越多,您建構它們的技術就會越好。如果您沒有使用技能來自動化或嘗試使您日常執行的任務更具可重複性,請立即開始。

建構技能的行為能讓您更擅長建構更多技能,此外,它們在自動化業務流程方面也非常出色。如果您可以描述您每週在站立會議前、每次衝刺結束時所做的任何事情,或者您作為工程師每天、每週甚至每季執行的任何事情,您都應該編寫技能來買回您的時間。

您可以自動化事後檢討嗎?您可以審查 Pull Request 嗎?您可以執行的任何任務,至少可以讓第一次嘗試成為代理技能。這將為您節省大量時間。

話雖如此,請記住,技能並不簡單,甚至不總是必要的。少即是多。其他一些重點整理:

在技能之前編寫評估。包含相鄰但不同技能的負面範例和禁止載入。

描述是困難的部分。「Load when...」(每個字都需要注意力)。

陷阱是極高價值的內容。從精簡開始,隨著代理失敗而成長。

請記住,透過新增新的技能,很容易破壞其他預先存在的技能,即使您沒有觸碰它(提防遠距作用)。

每當您編寫和維護技能時,請使用所有可用的工具。如果您想了解更多資訊,Agent 技能網站上有許多優秀的範例,而且我們的內部儲存庫和公開生態系統都包含許多設計良好的技能範例。

引用

BibTeX
@online{perplexity2026DesigningRefiningAndMaintainingAgentSkillsAtPerplexity,
  author = {{Perplexity} and Marshall Kiely and Daisy Lee and Jerry Ma and Lauren Kolm},
  title = {{Designing, refining, and maintaining agent skills at Perplexity}},
  date = {2026-05-01},
  url = {https://perplexity.coolkeypoint.com/hub/blog/designing-refining-and-maintaining-agent-skills-at-perplexity}
}