實戰(zhàn):從工具調(diào)用到能力沉淀)
做AI Agent開發(fā)的朋友應(yīng)該都有這種體會剛把工具函數(shù)接入大模型時效果挺驚艷可一旦場景復(fù)雜起來代碼就變成一團(tuán)亂麻——幾十個函數(shù)堆在一起模型經(jīng)常選錯目標(biāo)參數(shù)格式寫錯一次就要返工一小時。我接觸agent-skills這個概念大概半年多前前后后在幾個不同的模擬項目X里試過好幾套方案今天把其中一套比較成熟的架構(gòu)思路整理出來希望能給正在做Agent落地的朋友一些參考。agent-skills說白了就是給智能體準(zhǔn)備的一套“技能庫”。它跟單純的函數(shù)列表不太一樣重點是把一個能力按標(biāo)準(zhǔn)格式封裝起來包含技能的名稱、描述、輸入輸出Schema、執(zhí)行邏輯、依賴資源甚至可以包含一組完整的工具調(diào)用序列。Agent在運行時會根據(jù)當(dāng)前任務(wù)主動去技能庫中檢索和匹配選中最合適的技能來執(zhí)行。這樣一來Agent不再只是一個會說話的回答機(jī)器而是變成了一個有工具箱、有操作規(guī)范、能持續(xù)沉淀能力的執(zhí)行者。這篇內(nèi)容適合誰看正在做AI助手、自動化助手、智能客服、工作流引擎的開發(fā)者都能用得上。哪怕你的Agent還沒上生產(chǎn)只是在學(xué)校內(nèi)部項目或企業(yè)內(nèi)部驗證階段這套思路也能幫你把系統(tǒng)搭得更穩(wěn)。我會盡量把設(shè)計思路、踩坑過程和完整代碼骨架都寫出來希望能真正幫到你。1. 為什么Agent需要技能庫而不是純靠Prompt1.1 從“會調(diào)用工具”到“具備技能”的轉(zhuǎn)變很多人最開始做Agent的時候習(xí)慣把所有能力都塞進(jìn)System Prompt里比如“你可以使用以下工具get_weather、book_hotel……”然后讓模型自己去拼。這種做法在小規(guī)模、工具數(shù)量少于五個的時候是可以接受的我也這么做過圖省事。但一旦超過十個工具問題就開始暴露Prompt太長導(dǎo)致模型注意力分散描述寫得不仔細(xì)就會選錯增加新工具還得頻繁改提示詞而且不同工具的輸入輸出風(fēng)格五花八門Agent內(nèi)部要針對每個工具寫適配代碼。這就是單純“工具接入”階段最大的痛點。技能庫的思路是把“工具”再往上升一層。工具是最小執(zhí)行單元比如一個查詢接口、一個計算函數(shù)技能則是一個“完整動作”它可能只依賴一個工具也可能串聯(lián)好幾個工具并且自帶規(guī)則和邊界條件。比如“查詢天氣并給出穿衣建議”單看工具層需要至少兩個能力天氣查詢和知識推理。但作為技能它應(yīng)該是一個整體先查天氣再根據(jù)溫度范圍、降水概率組織建議文案。模型只需要做一次選擇執(zhí)行細(xì)節(jié)全部封裝在技能內(nèi)部。這個抽象層面的提升非常關(guān)鍵。它讓Agent的決策面變小了——不是讓模型去編排每一步工具調(diào)用而是讓模型在有限的技能菜單里做選擇。菜單里的每項技能都經(jīng)過測試和驗證執(zhí)行結(jié)果可控。我在實際項目中體會最深的一點是Agent系統(tǒng)的可靠性往往不是靠模型聰明而是靠決策范圍收窄。模型需要做的判斷越少出錯率就越低。1.2 技能庫到底解決了什么核心問題技能庫不是花架子它解決的是三個核心問題。第一是復(fù)用。同樣一個“內(nèi)容安全審核”技能可以在內(nèi)容生成Agent里面用也可以在用戶反饋處理Agent里面用只要接口定義一致?lián)Q一個Agent實例就能直接掛載。做過多個Agent的人應(yīng)該都有經(jīng)驗如果沒有統(tǒng)一的技能層同一套邏輯就得在每個Agent里重新實現(xiàn)一遍維護(hù)成本直接翻倍。這里說的復(fù)用還不只是代碼復(fù)用更重要的是能力沉淀。一個技能被驗證有效它就能成為團(tuán)隊的基礎(chǔ)資產(chǎn)后面開發(fā)新Agent時可以直接調(diào)用不用每次從頭設(shè)計。第二是管理。技能庫把每個能力的版本、依賴、測試用例都固化下來能單獨升級、單獨回滾。我在某跨平臺系統(tǒng)里遇到過一種情況某個匯報生成技能改了一版Prompt之后其他Agent的對話質(zhì)量集體下降排查了半天才發(fā)現(xiàn)是因為技能庫是共享的有人直接改了原文件。后來改成版本隔離每個Agent鎖定技能的某個版本問題才徹底解決。這個坑讓我意識到技能庫必須做版本管理不能只有一坨最新文件否則牽一發(fā)而動全身。第三是可驗證。技能庫里的技能是可以單獨測試的不需要跑到完整Agent鏈路里才能驗證。這一點在工程實踐里非常有價值。我經(jīng)常用一套固定的測試用例去回歸技能庫改一行代碼就能知道會不會影響到其他調(diào)用方。這種確定性讓人很安心也是技能庫跟散亂工具函數(shù)最本質(zhì)的區(qū)別之一。1.3 技能、工具、插件、工作流的邊界很多人對這幾個概念是混著用的我在團(tuán)隊評審時也經(jīng)常被問“這跟插件有什么區(qū)別”。我的理解是工具是最底層它不關(guān)心業(yè)務(wù)就是一個能完成某個原子操作的函數(shù)或接口比如“發(fā)送郵件”“解析PDF”。技能是工具的封裝它有明確的業(yè)務(wù)目標(biāo)和輸入輸出契約比如“生成會議紀(jì)要并發(fā)送給指定參會人”內(nèi)部可能用到了語音轉(zhuǎn)文字、摘要、格式化、發(fā)送郵件四個工具。插件是技能的集合和分發(fā)單元通常包含一組相關(guān)技能再加上自己的界面或配置入口可以整體安裝卸載有點像一個技能包。工作流則是技能之上的編排層它表達(dá)的是“先做A再做B如果條件C成立就做D”的流程邏輯偏業(yè)務(wù)層面。把這一層理清楚之后你會發(fā)現(xiàn)設(shè)計技能庫時不會糾結(jié)“這個能力該放在哪兒”。比如一個純粹的PDF解析功能它應(yīng)該是一個工具不占技能庫名額而“從PDF中提取表格并整理成結(jié)構(gòu)化數(shù)據(jù)”就是一個技能因為它有明確的目標(biāo)描述和輸出規(guī)范甚至可以內(nèi)部選擇用哪個解析工具。這種邊界感讓我在設(shè)計新Agent時省了很多不必要的爭論。2. 技能庫設(shè)計的三個核心原則2.1 原則一統(tǒng)一接口讓輸入輸出都有Schema約束技能庫如果想讓不同Agent都能調(diào)用第一件要做的事就是統(tǒng)一接口格式。最通用的做法是給每個技能定義輸入?yún)?shù)和輸出結(jié)果的JSON Schema用類型、必填、描述、默認(rèn)值來約束輸入用固定結(jié)構(gòu)描述輸出。這里有一個容易被忽視的點不僅輸入要校驗輸出也要有結(jié)構(gòu)化的Schema。如果技能返回的是自由文本模型的后續(xù)決策就缺少確定性的抓手很難穩(wěn)定地做下一步操作。舉個例子一個“分析用戶評論情感”的技能輸出如果只是一個字符串“比較滿意”下游技能根本沒法做數(shù)值判斷。更好的輸出是{sentiment: positive, confidence: 0.93, summary: 用戶對物流速度滿意}這樣即使不依賴大模型普通代碼也能處理還能把置信度數(shù)值直接用在下游統(tǒng)計里。我覺得這一步是整個技能庫的地基。Schema定義得越清晰后面做參數(shù)校驗、自動補(bǔ)全、接口測試都會越順。我見過不少團(tuán)隊先寫執(zhí)行邏輯回頭補(bǔ)Schema結(jié)果發(fā)現(xiàn)邏輯里的輸入輸出跟契約對不上返工量大得嚇人。所以我的建議是任何技能的Schema設(shè)計都要跟執(zhí)行邏輯開發(fā)同步推進(jìn)哪怕先草草寫一版也要讓契約先立起來再圍繞它實現(xiàn)。2.2 原則二描述語料要寫給模型看不只給人看技能的描述字段往往決定了模型能不能在正確的時候選中這個技能。這里說的描述不是功能文檔而是給大模型看的“使用說明書”。它需要包含幾個關(guān)鍵信息這個技能是干什么的、適合在什么場景下用、什么情況下不要用、輸入輸出分別是什么。描述寫得太簡單比如只寫“獲取天氣”模型很容易在需要穿衣建議的時候去調(diào)用天氣技能而不是去調(diào)用更高層的穿衣建議技能描述寫得太啰嗦又會稀釋模型注意力導(dǎo)致技能檢索效率下降。我常用的寫法是幾個固定的段落一句話總結(jié)然后寫適用場景再寫不適用場景最后給一個典型調(diào)用例子。句子盡量短動詞明確避免模糊詞匯。比如一個“訂單取消”技能描述可以是“當(dāng)用戶要求取消尚未發(fā)貨的訂單時使用。不適用于已發(fā)貨訂單已發(fā)貨訂單請使用‘售后申請’技能。典型輸入訂單ID、取消原因?!睂崪y下來這種結(jié)構(gòu)化描述能讓技能選錯率明顯下降。我還在元數(shù)據(jù)文件里加了一個examples字段里面放兩三條真實的輸入輸出對效果比單純寫描述更穩(wěn)定。之前看過一份評測報告說模型對示例的敏感度其實高于對描述文字的敏感度這點我在實際項目中也深有體會。與其花大量時間打磨描述措辭不如先把高質(zhì)量示例補(bǔ)上。2.3 原則三技能粒度要收放有度技能粒度這個東西我一開始也控制不好走了不少彎路。粒度太細(xì)比如寫了一個“發(fā)送HTTP請求”技能結(jié)果Agent每個動作都要繞一圈又慢又瑣碎等于是把工具列表換了個名字并沒有解決決策負(fù)擔(dān)的問題。粒度太粗比如寫了一個“完成整個營銷方案”技能模型幾乎沒法復(fù)用稍微換一個需求場景就失效了等于寫死了一個一次性業(yè)務(wù)腳本。我的經(jīng)驗是利用“可復(fù)用邊界”來判斷如果一個技能能被兩個以上不同的任務(wù)用到粒度就是合適的如果只能被一個特定任務(wù)用到要么繼續(xù)拆分出通用子技能要么接受它就是一個獨立業(yè)務(wù)腳本不進(jìn)技能庫。寫技能的時候多問自己一句除了當(dāng)前需求還有誰會用到這個技能如果答案是沒人那就把它設(shè)計成通用技能的組合調(diào)用而不是單獨建一個獨占技能。還有一個實操技巧同一業(yè)務(wù)域里盡量保證技能水平一致。如果“生成文案”和“生成文案并配圖并定時發(fā)布”同時存在模型很容易混淆不知道該選哪個。我的建議是只保留粗粒度技能把細(xì)粒度能力作為內(nèi)部工具隱藏起來讓技能庫的條目總數(shù)保持在幾十個以內(nèi)。這樣模型選擇壓力小維護(hù)成本也低很多。3. 從零搭建一個最小可用的技能庫3.1 目錄結(jié)構(gòu)與技能元數(shù)據(jù)設(shè)計先看目錄結(jié)構(gòu)。我比較喜歡用扁平化加標(biāo)簽的方式而不是深層嵌套。每個技能占一個目錄目錄名就是技能ID里面至少包含元數(shù)據(jù)文件skill.yaml、執(zhí)行腳本exec.py和可選的依賴聲明文件。目錄結(jié)構(gòu)如下skills/ email_reply/ skill.yaml exec.py tests/ cases.json meeting_summary/ skill.yaml exec.py requirements.txt review_sentiment/ skill.yaml exec.py目錄名用snake_case或kebab-case都可以但全庫必須統(tǒng)一。我建議用snake_case方便Python類庫直接映射。這里順便說一下技能ID一定不要隨便改因為ID會被寫進(jìn)各種編排配置和接口日志里改名會導(dǎo)致歷史數(shù)據(jù)對不上。skill.yaml的核心字段可以這樣設(shè)計id: meeting_summary name: 會議紀(jì)要生成與要點整理 version: 1.2.0 description: | 當(dāng)用戶提供會議錄音或文字稿時使用能夠生成結(jié)構(gòu)化會議紀(jì)要包含議題、結(jié)論、待辦事項。 不適用于純閑聊或需要翻譯的內(nèi)容。 典型輸入會議文字稿或錄音文件路徑。 examples: - input: 會議記錄關(guān)于Q3目標(biāo)、預(yù)算…… output: 議題Q3目標(biāo)確認(rèn)結(jié)論預(yù)算需壓縮10% input_schema: type: object required: - transcript properties: transcript: type: string description: 會議文字稿內(nèi)容長度不超過20000字 include_action_items: type: boolean description: 是否輸出待辦事項清單默認(rèn)為true output_schema: type: object required: - summary - action_items properties: summary: type: string action_items: type: array items: type: string dependencies: - llm_sdk - pydantic注意一點不要在skill.yaml里寫具體的執(zhí)行邏輯細(xì)節(jié)也不要放過于冗長的Prompt模板那些東西歸類到exec.py或獨立的prompt文件里。元數(shù)據(jù)本身要保持輕量這樣模型和代碼讀取時才會快維護(hù)的人一眼也能看明白這個技能到底是干什么的。3.2 技能注冊與動態(tài)加載技能庫在代碼層面要做的一個重要事情是動態(tài)注冊。你不能在系統(tǒng)里寫死一個技能字典否則每次新增技能都要改主程序。更合理的做法是在進(jìn)程啟動時掃描技能目錄讀取每個目錄的skill.yaml構(gòu)建索引然后按需加載執(zhí)行模塊。下面是一個用Python實現(xiàn)的簡化加載器import yaml from pathlib import Path from importlib import import_util class SkillRegistry: def __init__(self, base_dir: str skills): self.base_dir Path(base_dir) self.skills {} self.modules {} def scan(self): for skill_dir in self.base_dir.iterdir(): meta_path skill_dir / skill.yaml if not meta_path.is_file(): continue with open(meta_path, r, encodingutf-8) as f: meta yaml.safe_load(f) skill_id meta.get(id, skill_dir.name) self.skills[skill_id] { meta: meta, dir: str(skill_dir), } def load(self, skill_id: str): if skill_id in self.modules: return self.modules[skill_id] spec import_util.spec_from_file_location( fskill_{skill_id}, Path(self.skills[skill_id][dir]) / exec.py, ) module import_util.module_from_spec(spec) spec.loader.exec_module(module) self.modules[skill_id] module return module def execute(self, skill_id: str, **kwargs): module self.load(skill_id) validate_input(self.skills[skill_id][meta], kwargs) result module.run(**kwargs) validate_output(self.skills[skill_id][meta], result) return result def list_skills(self): return [ {id: sid, name: meta[meta][name], description: meta[meta][description]} for sid, meta in self.skills.items() ]這個設(shè)計的關(guān)鍵點是元數(shù)據(jù)在啟動時就全部加載執(zhí)行模塊在真正被選中后才動態(tài)加載。這樣啟動速度快內(nèi)存占用也低。另外validate_input和validate_output兩個函數(shù)一定不要跳過它們實際上是在執(zhí)行邊界上做契約校驗?zāi)軘r截大量臟數(shù)據(jù)。我在一個項目里就靠這兩行校驗函數(shù)擋住了模型傳錯字段的情況不然錯誤會一路傳導(dǎo)到下游排查起來痛苦得多。3.3 一個完整技能的編寫示例我們來實現(xiàn)一個比較有代表性的技能把一段產(chǎn)品反饋整理成結(jié)構(gòu)化問題清單。這個技能在很多Agent場景里都通用比如客服系統(tǒng)、需求收集助手。先看技能元數(shù)據(jù)的輸入輸出契約再看exec.py的實現(xiàn)骨架。import re from typing import List, Optional from pydantic import BaseModel class FeedbackItem(BaseModel): category: str content: str priority: str medium class RunResult(BaseModel): items: List[FeedbackItem] raw_count: int def run(feedback_text: str, categories: Optional[List[str]] None) - dict: segments split_feedback(feedback_text) items [] for seg in segments: if len(seg.strip()) 5: continue category classify(seg, categories) priority estimate_priority(seg) items.append( FeedbackItem( categorycategory, contentseg.strip(), prioritypriority, ) ) return RunResult(itemsitems, raw_countlen(segments)).model_dump() def split_feedback(text: str) - List[str]: parts re.split(r[。!?.\n], text) return [p for p in parts if p.strip()] def classify(seg: str, categories: Optional[List[str]]) - str: if categories: for cat in categories: if cat in seg: return cat return 其他 def estimate_priority(seg: str) - str: if re.search(r崩潰|閃退|無法|嚴(yán)重|緊急|賠償, seg): return high if re.search(r建議|希望|可以優(yōu)化, seg): return low return medium這個技能實際運行時Agent只需要傳feedback_text剩下的拆分、分類、優(yōu)先級估計全部在內(nèi)部完成輸出結(jié)果是結(jié)構(gòu)化JSON。這就是技能封裝的意義對外暴露的是簡單契約對內(nèi)可以自由混合規(guī)則和模型調(diào)用。上面示例用的是純規(guī)則實現(xiàn)實際項目中如果分類準(zhǔn)確率不夠可以在classify函數(shù)里換成調(diào)用大模型接口但要注意把超時、重試、模型名等配置放在技能目錄下的config.json里由加載器統(tǒng)一注入不要散落在代碼里。3.4 執(zhí)行包裝與統(tǒng)一異常處理技能執(zhí)行時會遇到各種問題網(wǎng)絡(luò)超時、模型接口報錯、輸入字段缺失、輸出格式非法。如果不做統(tǒng)一包裝Agent主循環(huán)的異常處理會被各種技能錯誤淹沒。我建議每個技能模塊統(tǒng)一暴露run作為入口而注冊中心在執(zhí)行時包一層異常處理和重試策略。重試策略要區(qū)分錯誤類型網(wǎng)絡(luò)類錯誤可以重試兩到三次業(yè)務(wù)校驗類錯誤不要重試直接返回參數(shù)錯誤原因。可以在注冊中心里加一個簡單的重試邏輯import time def execute_with_retry(self, skill_id: str, max_retries: int 2, **kwargs): last_error None for attempt in range(max_retries 1): try: return self.execute(skill_id, **kwargs) except NetworkError as exc: last_error exc time.sleep(1.5 * (attempt 1)) except (SchemaError, ValueError) as exc: raise RuntimeError(f技能參數(shù)錯誤: {exc}) from exc raise RuntimeError(f技能執(zhí)行多次重試仍失敗: {last_error})這個方法看起來簡單但在實際項目里非常管用。我在某實時數(shù)據(jù)處理Agent里用上這套后因為第三方接口不穩(wěn)定導(dǎo)致的會話中斷少了大概一半。記住一個原則技能內(nèi)部不要自己加無限重試重試邏輯放在統(tǒng)一層避免一個卡住的技能占住線程資源不放。另外錯誤信息一定要寫得足夠詳細(xì)尤其是參數(shù)校驗失敗時最好把期望格式和實際收到的值都列出來這樣模型自己才有可能在下一次調(diào)用前修正。4. 技能編排讓多個技能協(xié)作干活4.1 順序流水線怎么設(shè)計單個技能解決的是單點問題但真實業(yè)務(wù)里往往需要把多個技能串起來。最基礎(chǔ)的是順序流水線。比如一個“輿情分析日報”場景需要依次做數(shù)據(jù)抓取、文本清洗、情感分析、聚合統(tǒng)計、生成報告。如果拆成五個技能來做每次Agent都在大模型側(cè)決策下一步效率低且不穩(wěn)定。更好的做法是把這些技能放到一條編排配置里由編排層按固定順序執(zhí)行模型只需要在入口觸發(fā)一個“生成輿情日報”的總控技能。編排配置可以是一份JSON{ id: report_workflow, trigger_skill: parse_user_request, steps: [ { skill: fetch_data, inputs: {source: {{request.source}}} }, { skill: text_clean, inputs: {documents: {{steps.fetch_data.output}}} }, { skill: sentiment_analysis, inputs: {texts: {{steps.text_clean.output}}} }, { skill: aggregate_stats, inputs: {items: {{steps.sentiment_analysis.output}}} }, { skill: generate_report, inputs: {stats: {{steps.aggregate_stats.output}}} } ] }這里的變量引用語法是{{steps.xxx.output}}本質(zhì)上就是讓編排引擎把上一步的輸出結(jié)構(gòu)體傳給下一步。實現(xiàn)這個機(jī)制并不復(fù)雜關(guān)鍵是要在每一步執(zhí)行后緩存output對象并提供一套模板替換能力。我自己用Python實現(xiàn)時只寫了一個簡單的遞歸替換函數(shù)大概一百多行完全夠用。順序流水線的價值在于穩(wěn)定性固定流程不會受到模型發(fā)揮波動的影響該先做的不會跳過去。它適合那些步驟明確、順序強(qiáng)依賴的業(yè)務(wù)比如數(shù)據(jù)處理類任務(wù)。4.2 條件路由與技能回退很多場景不是簡單的順序線而是有分支的。比如“根據(jù)訂單狀態(tài)決定后續(xù)動作”已發(fā)貨走物流查詢未發(fā)貨走改地址退款中走售后催辦。這套邏輯如果全部靠Agent自由發(fā)揮狀態(tài)判斷容易出錯。我一般推薦把條件路由寫在編排層用顯式的if條件控制分支。條件路由的一個常見誤區(qū)是把JSON條件表達(dá)式寫得過于復(fù)雜實際上你只需要支持等于、不等于、包含、正則匹配這幾種基礎(chǔ)算子就夠用了。我統(tǒng)計過自己搭建的十幾個編排流程百分之九十的分支邏輯都能用這些基礎(chǔ)算子覆蓋。把條件寫清楚以后代碼調(diào)試起來非常直觀任何一個分支的走向都能提前預(yù)判到。另外技能回退也很重要。比如查詢訂單狀態(tài)失敗了是直接告訴用戶失敗還是嘗試調(diào)用備用接口如果在編排層給技能配置了fallback字段主技能拋異常時自動切換到備選技能用戶側(cè)基本無感知。我在線上環(huán)境里遇到過主鏈路接口連續(xù)抖動的情況如果沒有回退機(jī)制那段時間所有相關(guān)Agent都會跟著一起不可用加上回退之后影響范圍縮小了不少。4.3 技能間的數(shù)據(jù)契約與上下文傳遞多技能協(xié)作最大的坑就是數(shù)據(jù)格式不對齊。技能A輸出customer_id技能B期望的是user_id如果沒有統(tǒng)一的數(shù)據(jù)契約只能靠寫膠水代碼編排一復(fù)雜就維護(hù)不下去。我的做法是引入一個“技能上下文對象”在每個技能執(zhí)行前根據(jù)其input_schema自動截取上下文里需要的字段。如果技能輸出字段名跟下一個技能不一致就在編排層配置一個顯式的字段映射{ skill: get_user_profile, inputs: {user_id: {{steps.query_order.output.customer_id}}} }把這種映射放到配置里而不是寫在代碼里好處是業(yè)務(wù)調(diào)整時不用改主程序。這個模式我用了一段時間后發(fā)現(xiàn)很多成熟的開源編排工具也是同樣的思路算是行業(yè)里的通用實踐。再提醒一點上下文傳遞時盡量傳遞值對象或ID而不是傳遞龐大的中間文本。我之前踩過幾次坑一個文本清洗技能把整篇大文檔往下傳結(jié)果后續(xù)技能越跑越慢一度以為是模型速度問題最后發(fā)現(xiàn)是上下文里積累了太多冗余文本。后來我讓每個技能在輸出時主動做一次字段精簡只保留下游真正需要的數(shù)據(jù)整體token消耗和延遲都降下來了。5. 常見問題與排查技巧實錄5.1 模型總選錯技能怎么辦這是使用技能庫后最常遇到的問題表現(xiàn)為該調(diào)用A技能的時候模型調(diào)用了B技能或者干脆回答“我沒有這個能力”。我排查時一般按三條線走。第一條看技能描述是否包含明確的“適用/不適用”邊界。如果只寫了一句話功能描述優(yōu)先補(bǔ)場景邊界和典型示例。第二條看技能ID和名稱是否太長或者太抽象。比如某個技能叫“handle_order_exception”另一個叫“process_refund_request”模型很難區(qū)分改成“處理退款申請”“處理訂單異?!边@種業(yè)務(wù)化名稱會更穩(wěn)妥。第三條檢查技能庫里是否存在語義高度重疊的條目比如同時有“生成摘要”和“總結(jié)要點”模型不知道選哪個那就合并或者刪掉一個。如果以上都做完了還是選錯可以考慮在模型側(cè)的System Prompt里加一個簡短的技能索引列出技能ID和一句話說明讓模型在決策前先掃一眼菜單。我也見過一些項目用向量檢索先召回候選技能再把候選列表塞給模型做選擇效果不錯但整體復(fù)雜度明顯更高適合技能條目超過五十個的情況。如果你的技能庫還比較小先把描述和示例質(zhì)量搞上去收益最大。5.2 技能Schema校驗不過多半是類型和必填沒對齊跟大模型打交道輸入字段的格式問題幾乎不可避免。模型自己生成的參數(shù)有時候會是字符串而不是數(shù)組有時候缺了必填字段。我的經(jīng)驗是Schema校驗失敗時一定要把原始錯誤信息原樣返回給Agent讓它自己修正參數(shù)后重新調(diào)用。這里有個細(xì)節(jié)錯誤信息里不要只寫“參數(shù)錯誤”要寫明“缺少字段user_id字段tags期望類型是數(shù)組實際收到字符串”。大模型對清晰錯誤信息的修正能力很強(qiáng)很多情況下一個來回就能自動解決。如果反復(fù)修正還是不行多半是技能的描述里沒有寫清楚參數(shù)格式。此時要在description里加一句更具體的說明比如“tags是一個字符串?dāng)?shù)組每一項是用戶的標(biāo)簽內(nèi)容”。這種提示比單純的Schema定義對模型更友好。我甚至?xí)ㄗh在元數(shù)據(jù)里放一個parameter_examples字段把每個參數(shù)的合法示例都寫出來這樣能在根本上降低模型生成錯誤參數(shù)的概率。5.3 技能加載慢、內(nèi)存占用高技能庫條目多了以后進(jìn)程啟動時掃描全部元數(shù)據(jù)一般也就幾十毫秒不至于有瓶頸。真正容易出問題的是有些人在注冊中心里把每個技能的執(zhí)行模塊都在啟動時就import這會拖慢啟動速度還會占內(nèi)存。我的建議是采用懶加載也就是真正執(zhí)行一個技能時才import它。另外有些技能內(nèi)部依賴一些體積較大的庫比如PDF解析、圖像識別如果十個技能都依賴同一個庫加載器可以做一個模塊復(fù)用的緩存池不要讓每個技能重復(fù)掛一份同樣的依賴對象。還有一個隱藏問題技能模塊里的全局狀態(tài)。如果某個技能在模塊內(nèi)定義了一個全局緩存字典多次執(zhí)行之后內(nèi)存會一直漲。排查時可以定期打印技能模塊對象的數(shù)量如果發(fā)現(xiàn)同一個技能被加載了兩份要檢查import路徑是否不一致。我之前就遇到過因為目錄大小寫不一致導(dǎo)致模塊被重復(fù)加載的情況看起來是小問題實際會讓內(nèi)存占用翻倍。5.4 技能更新后老Agent卻報錯這個跟版本管理有關(guān)。技能庫是共享的你更新了技能文件所有引用它的Agent都會受影響。有些Agent依賴舊版本的輸出格式更新后自然就出問題。我目前的做法是每個Agent實例在初始化時記錄自己依賴的技能版本集合注冊中心提供一個按版本隔離的獲取接口。元數(shù)據(jù)文件里加version字段同一份技能可以有多個版本目錄共存比如meeting_summary_v1、meeting_summary_v2。發(fā)布新版本時不要刪舊版本等所有Agent都遷移完成后再清理。這個流程看起來繁瑣但能避免不少線上事故。另外技能測試文件應(yīng)該跟技能同目錄存放每次改動后跑一遍tests/cases.json里的用例確認(rèn)輸出Schema和示例數(shù)據(jù)都一致再考慮發(fā)布。我自己就因為偷懶跳過測試吃過虧那之后所有技能都強(qiáng)制要求附帶至少三個輸入輸出用例。特別是涉及大模型輸出的技能很容易出現(xiàn)結(jié)構(gòu)不穩(wěn)定只有靠固定用例回歸才能保證升級安全。5.5 調(diào)試技能庫的實用小工具最后分享一個調(diào)試技巧。我給技能庫加了一個“單技能命令行執(zhí)行器”可以直接在終端跑一個技能傳參并查看輸出不需要把整個Agent跑起來。python -m skill_runner run meeting_summary --transcript 會議內(nèi)容...這個工具本質(zhì)上就是注冊中心的一個薄封裝執(zhí)行時傳入技能ID和JSON參數(shù)最后格式化打印輸出。這樣調(diào)試效率會高很多尤其在排查某個技能單獨報錯的時候不用再動其他部分。我一度調(diào)試Agent鏈路要反復(fù)改Prompt和參數(shù)加上這個小工具后至少省了三分之一的時間。我建議每個團(tuán)隊做技能庫的時候都順手把這個工具加上成本很低日常收益卻很大。做技術(shù)選型的時候我一直喜歡那些能在真實場景里扛住壓力的方案而不是演示時看著炫酷的玩法。技能庫這套架構(gòu)在好幾個生產(chǎn)級Agent里幫我扛過了流量壓力也給后續(xù)擴(kuò)展留了空間。如果你剛開始接觸agent-skills不用急著把所有能力都封裝成技能先從兩三個高頻業(yè)務(wù)動作入手把接口、描述、測試這三件事做扎實跑通之后再逐步擴(kuò)充會比一開始就鋪一個大而全的庫穩(wěn)妥得多。等你的技能庫真正被多個Agent復(fù)用時你會發(fā)現(xiàn)之前在設(shè)計和規(guī)范上花的時間都是值得的。