在 Perplexity 設計、完善和維護代理技能
了解 Perplexity 如何編寫、審查和維護代理技能,以及我們的工程師用來構建它們的指南。
Perplexity 的前沿代理產品建立在封裝於模組化 技能 (Agent Skills) 中的專有技術和領域專業知識基礎之上。我們在各個技術環境中維護著一個經過精心策劃的技能庫。這些技能包括驅動 Perplexity Computer 的許多通用公用程式;金融、法律和健康等領域的垂直領域專用能力;以及用於滿足用戶需求的大量模組。有些技能平時很少調用,但在調用 時 至關重要。為了確保始終如一的卓越用戶體驗,Perplexity 的代理團隊對技能品質的重視程度與對程式碼品質的重視程度不相上下。
開發高品質技能所需的直覺和最佳實踐,與構建傳統軟體所需的內容有顯著差異。代理團隊會審查許多優秀工程師在工作過程中開發的技能提交的請求。結果幾乎總是有大量的意見和修改建議。這是因為許多編寫程式碼的實用模式在創建技能時反而成為了反模式。
例如,如果您參考 PEP20 – Python 之禪 (The Zen of Python) 中的某些格言,很快就會發現編寫優秀的 Python 程式碼與編寫優秀的技能是完全不同的。在這 20 條智慧中,至少有一半在編寫技能時是完全錯誤的或具有誤導性的。以下是其中五條:
Python 之禪 | 技能之禪 |
簡單優於複雜 | 技能是一個資料夾,而非檔案。複雜性即特徵。 |
顯式優於隱式 | 激活是隱式模式匹配。漸進式揭露。 |
稀疏優於密集 | 上下文十分昂貴。每個 token 的最大訊號量。 |
特殊情況不足以破壞規則 | 陷阱才是特殊情況(它們是價值最高的內容)。 |
如果實現方式容易解釋,這可能是一個好主意 | 如果容易解釋,模型已經知道了。刪除它。 |
Python 的《The Zen of Python》與本文對撰寫技能的指導之間的五項對照。
本指南是 Perplexity 的工程師在開發和審查技能時使用的文件。我們也向大眾公開發布本指南,以便我們的發現和學習成果能造福更廣大的社群。無論您是日常工作中設計生產環境技能的工程師,還是希望在您最擅長的領域開發自己技能的 Computer 用戶,亦或是兩者兼具,本指南都適合您。
什麼是技能?
當您編寫技能時,您並不是在編寫普通的舊軟體(儘管技能現在是代理系統主要邏輯引擎的一部分)。相反,您是在為模型及其環境構建上下文。技能具有不同的約束條件和不同的設計原則。如果您像寫程式碼一樣編寫技能,您將會失敗。
技能至少包含四個面向,特別是在我們於 Perplexity 構建它們的背景下。
技能是一個目錄
技能不只是一個單一的 SKILL.md 檔案。在許多情況下,技能包含多個檔案。在以您的技能命名的目錄下,您可能會擁有:
SKILL.md:前端物質 (frontmatter) 和說明
scripts/:代理運行的程式碼,而非重新發明
references/:繁重的文件,按條件載入
assets/:模板、模式和資料
config.json:首次運行的用戶設置
這種輪輻式模式使您能夠保持技能的專注和緊湊,並且人們可以以非常有創意的方式使用資料夾結構。有時,特別複雜的技能受益於多層次的層級結構,以幫助模型更好地導航。假設一個技能需要跨越 300 個主題的知識,這些知識可分組為 20 個學科領域。即使對於當今最好的前沿模型來說,在 300 個主題中可靠地選擇正確的主題也是一個未解決的挑戰。對於模型來說,聚焦於 20 個領域之一,比在該領域內的 15 個主題中進行選擇,是一個容易得多的選擇問題。
作為多層次層級結構如何提供價值的例子,我們的團隊在上一個稅務季節中,在驅動 Computer 美國所得稅能力的技能中採用了三層主題嵌套。鑑於稅法的複雜性,這種層級結構絕對是不可或缺的:在我們的早期測試中,向模型呈現包含美國國內稅收法規所有 1,945 條的單一資料夾,導致的性能比完全不載入技能更差。將資訊組織成邏輯分區,對於確保高精確度的讀取操作至關重要。
然而,這種層級結構並非免費獲得。層級結構層次的增加,需要資訊架構中各層級的策劃工作量相應增加,以管理由此產生的間接性。我們設計了快速參考指南、自定義搜尋公用程式和其他工具,以支援模型以最小的間接性定位資訊。在這種情況下,進行艱苦的策劃工作最終產生了積極的結果:一種允許模型執行稅務相關任務的能力,比單獨使用通用工具要強得多。
技能是一種格式
技能是一種格式。核心根目錄 SKILL.md 檔案必須同時具有名稱和描述。此外,技能需要精確對應到技能所在的目錄名稱。名稱必須全部為小寫字母,不得包含空間,並且可以使用連字號。描述是路由觸發器。這是一個常見的失敗點:描述不是關於技能做什麼的內部文件。它相當於對模型何時載入技能的說明。因此,您會經常看到“Load when”(載入時),而不是“This Skill does”(本技能執行)。由於大多數實現將描述注入到模型上下文中,這一點非常重要。
在前端物質中,還有“depends:”,它允許您創建層級化的技能依賴關係,以及“metadata:”,用於審查和評估。不同的代理系統甚至可以定義自己的前端物質欄位,以特定於這些系統的方式使用。作為替代方案,技能專用的元資料可以封裝在輔助 JSON 或 YAML 設定檔中。當構建需要為每個技能促進不同類型運行時行為的代理系統時,而不將微小的細節污染到模型上下文中,這是非常理想的。最後,類似的行為可以通過在讀取時剝離技能前端物質來實現。Computer 採用了這種方法,這允許配置保留在根目錄 SKILL.md 檔案中。解析邏輯中需要特別注意細節,並且如果存在某些在模型上下文中很有用的欄位,您可能希望實現條件剝離。
技能是可調用的
技能是可調用的。代理在運行時載入技能。重要的是,技能並不總是打包在上下文中。默認情況下,大多數代理系統根據特定需要逐步展開技能。
在我們於 Computer 中實現技能的方式中,至少有三種層級的上下文成本。流程如下:
Computer 調用 load_skill(name="...")
Computer 將技能目錄複製到隔離的執行沙箱中
Computer 遞迴地自動載入“depends:”標籤中的依賴項
Computer 然後剝離前端物質,因此代理只看到正文和附加檔案
不同的代理系統可以選擇以不同的方式公開技能內容。例如,有些系統可能選擇根本不公開檔案層級結構,而將其留給模型通過檔案系統操作來發現層級結構。其他系統可能選擇給模型提供整個檔案樹的對映,直到某個截斷和/或深度限制。為了保持上下文清潔,Computer 會在調用上下文中省略完整的檔案層級結構;然而,這可以在每個技能的基礎上進行覆蓋。
技能是漸進式的
技能是漸進式的。在 Computer 中,有三種不同的上下文成本層級,我們在不同階段會產生所有這三種成本:
層級 | 載入內容 | 預算 | 付款時間 |
索引 | 名稱:每個非隱藏技能的描述 | 每個技能約 100 個 token | 每個工作階段,每個用戶,始終付費 |
載入 | 完整的 SKILL.md 正文 | 約 5,000 個 token | 約 5,000 個 token |
運行時 | scripts/、references/、assets/、subskills、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)
先編寫一些評估。您可以從以下來源獲取評估案例:
真實用戶查詢:從生產環境或您的專家智庫中抽樣
已知失敗:代理失敗是因為該技能不存在
鄰近混淆:接近您的領域邊界,但路由到了另一個技能
至少,您應該確保測試技能在需要時是否載入。理想情況下,您對其中一些進行抽樣,也許是從生產環境中。您也可以考慮已知的錯誤情況:也許您著手編寫技能的全部原因是您注意到了一個特定的失敗,或者您正在重構,並且一個技能涵蓋的兩個接近的領域中存在一些混淆。
從類似的負面和正面範例開始。負面範例極其強大,並且可能比正面範例更重要。
步驟 1:描述
這是技能中最難的一行。它是一個路由觸發器,而不是文件。要使名稱和描述正確,您不必關心技能的內容。您只關心技能是否在正確的點被載入和注入,並且沒有目標外的副作用,這是第一大失敗模式。每次您添加額外的技能時,您都會冒著讓其他 所有 技能稍微變差的風險,因此您需要確保正在最小化迴歸。
同樣,糟糕的描述會描述技能做什麼或為什麼它有用。好的描述說明代理何時應該載入該技能。例如,假設您有一些用於監控 PR 的東西。不要寫技能做什麼。寫下工程師在感到沮喪並希望您確保他們的 PR 正常運作時所說的話,例如“babysit”(代管)、“watch CI”(監控 CI)或“make sure this lands”(確保此 PR 合併)。
這是一個快速檢查清單:
以“Load when...”開頭
目標 50 個單字或更少
描述用戶的意圖,最好來自真實查詢
不總結工作流程
真實查詢是您可以在 80-20 原則中涵蓋的內容。通常,兩到三個例子運作良好。準確且僅添加您需要的量並不容易。
步驟 2:編寫正文
接下來,編寫技能本身的內容。請注意,這不是步驟 0 或步驟 1。
向 LLM 傳達工作流程與向同事甚至您的運行時系統傳達工作流程完全不同。學習新軟體工具時,工程師可能需要閱讀文件,從有經驗的人那裡獲取演示,並學習如何使用該工具。同時,對於幾乎任何存在至少一年的軟體工具,您只需要提到它的名字,LLM 就擁有了它所需的所有資訊。
編寫正文時,跳過顯而易見的事情。許多工程師有豐富的編寫 readme.md 檔案的經驗,其中列出了某人需要執行的每個命令。編寫技能時很容易陷入這種情況,因為這感覺像是在寫文件,但如果您這樣做,您的技能將是垃圾。因此,不要寫出一系列命令。
例如,您不需要寫:“git log # find the commit; git checkout main; git checkout -b <clean-branch>; git cherry-pick <commit>;”
相反,請寫:“將提交 cherry-pick 到乾淨的分支上。解決保留意圖的衝突。如果它不能乾淨地合併,請解釋原因。”
模型會以後者做得比前者過於規定性的命令序列好得多,尤其是在出錯時。不要鐵路式或過於規定性,這是脆弱的,相反,要在多種方法可以運作的地方保持靈活。同樣,對人類來說好的文件通常對模型來說是壞文件。
接下來,關注陷阱或負面範例。這些是訊號含量極高的內容,因為它們通常在指導模型方面起到指導作用,告訴模型不要做什麼。如果您每次代理出錯時都添加一行,您將通過運行它來學習,並且陷阱會有機地增長。
最後,如果有任何部分是條件性的或內容極其繁重的,請將其從作為樞紐的 SKILL.md 中取出,並放入輻條之一。將其放入可以漸進式載入的附件檔案中,我們接下來將深入探討這一點。
步驟 3:使用層級結構
當您有腳本、參考資料或正在使用某些特定工具時,請利用技能層級結構:
scripts/ 代理每次運行都會重新發明的確定性邏輯 | 給它要組成的程式碼,而不是重建 |
references/ 僅在滿足條件時載入的繁重文件 | "如果 API 返回非 200,則讀取 api-errors.md" |
assets/ 代理複製並填寫的輸出模板 | report-template.md,輸出模式 |
config.json 首次運行的用戶設置 | 詢問 Slack 頻道,儲存,並在下次重複使用 |
技能中腳本、參考資料、資產與設定的建議用途。
對於任何來自主要技能的條件性或分支內容,將其分解到一個資料夾中。另外請記住,多層次層級結構可用於特別複雜的技能。對於這些,您需要仔細考慮功能是應該單體實現還是作為技能集合(可能具有基於 depends: 的載入關係)。
步驟 4:迭代
接下來,在分支上進行多次迭代。在沒有技能的主分支上開始,進行一些迭代,構建您的主要查詢集,並運行大量評估。任何審查您的技能程式碼的人都會感謝您提交一個完整的變更集和評估集。審查連續的增量更改(除了新的陷阱)非常困難,所以嘗試最小化它。
您可能會進行許多小的單字更改。描述中的小單字更改可能會對路由產生巨大的影響(包括對其他技能的溢出效應),因此在步驟 5 之前完成所有這些工作。
步驟 5:發布
發布它。
如何維護技能
現在您已經編寫了一個技能,您必須維護它。
陷阱飛輪
從這一點開始,您的陷阱列表往往會增長或變化很大。例如,我們經常看到工程師提交未經評估的 PR,更改描述。如果您的技能合併後您正在更改描述,那麼您就偏離了軌道。如果您正在更改決定是否路由您的技能的事物,您需要編寫一些支持這些更改的評估。
技能主要是追加式的。陷阱部分隨著時間的推移積累了最多的價值:
代理在某件事上失敗 → 添加一個陷阱
代理載入了目標外的技能 → 收緊描述並添加負面評估
代理未在應該載入時載入該技能 → 添加關鍵字和正面評估
系統提示更改 → 檢查是否存在爭用或重複
在內部測試或生產中注意到單個失敗案例並添加陷阱很容易。這是一個負面範例,所以它並沒有真正改變明確的指導,但它讓模型知道,“嘿,有這個已知的失敗。”
當您從 80-20 原則邁向 99.9% 或 99.99% 的成功率時,增加這個陷阱列表很容易。當您看到這些負面範例時,您應該主要向陷阱部分追加內容。您不應該添加更長的說明或更改描述。
評估套件 (Eval Suites)
在 Perplexity,我們運行許多評估套件來檢查不同的事物。有技能載入和技能檔案讀取,這檢查了技能載入本身的精確度、召回率和禁止檢查。代理會在應該的時候路由您的技能嗎?這些確保了新技能不會破壞現有的邊界。
還有一些評估可以檢查正確的漸進式載入。代理可能會載入該技能,但它會讀取附件檔案嗎?例如,如果您有一個用於財務查詢的財務技能,它會讀取特殊的 FORMATTING.md 檔案嗎?
還有針對領域內端到端任務完成情況進行測試的技能評估。我們運行完整的代理迴圈並使用 LLM 評審員根據定義明確的準則對結果進行評分。
最後,針對不同的模型運行這些評估很重要。Computer 支援至少三種不同的編排模型系列:GPT、Claude Opus 和 Claude Sonnet。您希望針對這些不同的代理編排器運行您的技能載入和領域技能,以確保您不會獲得不同的行為。在技能方面,Sonnet 和 GPT 的行為大不相同。
最後的想法和要點
您構建的技能越多,您在構建它們方面就會越熟練。如果您沒有使用技能自動化或試圖讓您每天執行的任務更具可重現性,請立即開始。
構建技能的行為讓您更善於構建更多技能,而且,它們在自動化業務流程方面非常出色。如果您能描述您每週在站會前、每次衝刺結束時所做的任何事情,或者任何您作為工程師在每天、每週甚至每季度基礎上所做的事情,您都應該編寫一個技能來買回您的時間。
您可以自動化事後總結嗎?您可以審查 PR 嗎?您能做的任何任務,至少都可以讓第一次嘗試成為一個代理技能。這將為您節省大量時間。
話雖如此,請記住技能並不簡單,甚至並不總是必要的。少即是多。另外幾個要點:
在技能之前編寫評估。包括針對相鄰但不同技能的負面範例和禁止載入。
描述是困難的部分。“Load when...” (每個字都要消耗注意力)。
陷阱是價值極高的內容。從小處著手,隨著代理失敗而成長。
請記住,添加新技能很容易破壞其他預先存在的技能,即使您沒有觸摸它(要小心遠距離作用)。
每次您編寫和維護技能時,請使用所有可用的工具。如果您想了解更多資訊,Agent Skills 網站上有大量好的例子,而且我們的內部儲存庫和公共生態系統都包含許多設計良好的技能範例。
引用
@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}
}