:Agent技能系統(tǒng)的設(shè)計(jì)與落地復(fù)盤)
如果你正在做一個(gè)Agent項(xiàng)目大概率會(huì)遇到那個(gè)經(jīng)典瓶頸功能越堆越多工具函數(shù)越加越復(fù)雜但大模型選擇工具的準(zhǔn)確率反而越來越差。我們一度被“工具函數(shù)越加越多、調(diào)用準(zhǔn)確率越來越差”這個(gè)問題卡了很久直到把思路從“堆工具”換成“搭技能體系”——也就是給Agent配置一套可注冊(cè)、可檢索、可組合的skills庫(kù)讓模型不再面對(duì)龐大的工具海而是按需選擇當(dāng)前任務(wù)真正需要的能力單元。這篇文章是我在項(xiàng)目里把a(bǔ)gent-skills落到生產(chǎn)環(huán)境后的一些完整復(fù)盤包括為什么需要它、技能清單怎么設(shè)計(jì)、注冊(cè)與檢索機(jī)制怎么做、描述怎么寫得讓模型更準(zhǔn)確以及我們踩過的幾個(gè)坑。如果你也在做Agent應(yīng)用、AI工作流或者正準(zhǔn)備給助手類產(chǎn)品加“技能擴(kuò)展”能力這篇應(yīng)該能給你一些實(shí)際參考。1. 從“工具堆”到“技能庫(kù)”這一步為什么繞不開1.1 二十個(gè)工具函數(shù)塞進(jìn)System Prompt之后發(fā)生了什么先說說我最開始的做法。早前某Agent項(xiàng)目只有幾個(gè)固定功能比如查天氣、設(shè)提醒、算個(gè)算術(shù)模型調(diào)用得挺準(zhǔn)。后來業(yè)務(wù)一擴(kuò)張功能漲到二三十個(gè)我把所有工具定義全部序列化后塞進(jìn)System Prompt里讓大模型自己挑。結(jié)果很快就出問題了。首先是Prompt膨脹。每個(gè)工具定義都帶名稱、描述、參數(shù)Schema和示例二十個(gè)工具加起來接近上萬token模型在長(zhǎng)上下文里做“選擇”的難度成倍上升token成本和響應(yīng)延遲也跟著漲。其次是選擇準(zhǔn)確率下降。明明用戶問的是“明天出門要不要帶傘”Agent先調(diào)了“查詢待辦事項(xiàng)”又調(diào)了“查詢?nèi)諝v”最后才調(diào)用天氣類工具。原因不難理解工具之間描述相似、邊界模糊模型在幾十個(gè)選項(xiàng)里做決策天然容易受干擾。后來我做過一次統(tǒng)計(jì)在有近三十個(gè)工具定義同時(shí)注入的情況下工具選擇的正確率只有六成多部分低頻工具幾乎永遠(yuǎn)不被選中哪怕用戶的需求和它完全匹配。說到底傳統(tǒng)工具函數(shù)是“被動(dòng)等待調(diào)用”的它不知道當(dāng)前對(duì)話上下文也不知道自己的能力邊界只是一堆平鋪的函數(shù)簽名。功能少的時(shí)候沒問題功能一多這個(gè)模型必然崩。1.2 技能系統(tǒng)和工具系統(tǒng)到底差在哪工具和技能的差別我用生活里的話說工具就像一把螺絲刀技能不是螺絲刀是怎么換好一顆螺絲釘?shù)耐暾ば颉x什么刀頭、用多大力度、怎么防滑、怎么知道擰緊了。技能系統(tǒng)本質(zhì)上做了一次“能力抽象”工具系統(tǒng)只提供一個(gè)函數(shù)入口技能系統(tǒng)則提供完整的“能力單元”包含觸發(fā)條件、前置檢查、執(zhí)行步驟、失敗處理方式、依賴關(guān)系和輸出約定。工具系統(tǒng)把所有函數(shù)一次性暴露給模型技能系統(tǒng)則通過注冊(cè)中心和檢索器每次只暴露當(dāng)前場(chǎng)景需要的一小部分能力。工具往往是原子操作技能可以組合和嵌套。例如“生成周報(bào)”這個(gè)技能內(nèi)部可以依賴“拉取項(xiàng)目進(jìn)度”“匯總會(huì)議記錄”“格式化Markdown”三個(gè)子技能。工具系統(tǒng)的可測(cè)試性一般聚焦在單函數(shù)邏輯技能系統(tǒng)則在“模型是否會(huì)正確選擇該技能”這個(gè)層面也需要測(cè)試。下面這張對(duì)比表可以直觀說明維度普通工具函數(shù)技能系統(tǒng)暴露方式全部注入Prompt按需檢索后注入上下文占用隨數(shù)量線性增長(zhǎng)相對(duì)可控能力邊界不清晰顯式聲明觸發(fā)條件和禁用條件復(fù)用與組合單函數(shù)復(fù)用支持技能間依賴與編排失敗處理由外層代碼處理技能內(nèi)部自帶降級(jí)邏輯可測(cè)試性單測(cè)函數(shù)調(diào)用決策執(zhí)行結(jié)果雙層測(cè)試從工具到技能的轉(zhuǎn)變其實(shí)是一次分層設(shè)計(jì)。最底層是具體執(zhí)行代碼中間層是技能注冊(cè)中心上層是決策層也就是讓大模型面對(duì)“能力地圖”而不是“源代碼”。這個(gè)分層非常關(guān)鍵它直接決定了Agent能不能做“大而全”的功能擴(kuò)展。2. 技能的最小可用形態(tài)清單、運(yùn)行器與邊界約定2.1 一份技能清單里需要寫哪些字段我們把每個(gè)技能都放在一個(gè)獨(dú)立目錄里目錄下必有一個(gè)清單文件skill.yaml用來告訴注冊(cè)中心“我是什么、什么時(shí)候該用我、怎么調(diào)用我”。這是我們項(xiàng)目里實(shí)際用的一個(gè)最小清單id: meeting-minutes name: 生成會(huì)議紀(jì)要 summary: 根據(jù)會(huì)議轉(zhuǎn)寫文本生成結(jié)構(gòu)化會(huì)議紀(jì)要 tags: - meeting - minutes - summarize description: | # 何時(shí)使用 當(dāng)用戶提供會(huì)議錄音轉(zhuǎn)寫、會(huì)議筆記或聊天記錄要求輸出會(huì)議紀(jì)要、行動(dòng)項(xiàng)、決策記錄時(shí)使用。 # 何時(shí)不要使用 如果用戶只是提到會(huì)議但并沒有要求整理紀(jì)要不要調(diào)用本技能。 如果用戶要求的內(nèi)容和會(huì)議無關(guān)屬于普通文本摘要請(qǐng)考慮使用通用摘要技能。 inputs: - name: transcript type: string required: true description: 會(huì)議轉(zhuǎn)寫文本或會(huì)議筆記原始內(nèi)容 - name: language type: string required: false default: zh description: 輸出語言zh/en outputs: - name: meeting_minutes type: string description: Markdown格式的會(huì)議紀(jì)要 dependencies: - calendar-reader # 可選依賴用于自動(dòng)讀取關(guān)聯(lián)日程 run: mode: prompt template: templates/meeting_minutes.jinja2 fallback: | 如果無法生成紀(jì)要先嘗試精簡(jiǎn)輸入仍然失敗則返回錯(cuò)誤碼MM_001。這個(gè)清單里有兩個(gè)特別容易忽略的字段一個(gè)是summary一個(gè)是description里的“何時(shí)不要使用”。前者用來做快速檢索后者用來約束模型的行為邊界。我們后來發(fā)現(xiàn)很多“亂調(diào)用”問題根因就是技能描述里只寫了“我擅長(zhǎng)什么”沒有寫“我不該什么時(shí)候出現(xiàn)”。2.2 技能不只有Prompt代碼、流程與混合實(shí)現(xiàn)很多人以為一個(gè)技能就是一段提示詞模板實(shí)際遠(yuǎn)遠(yuǎn)不夠。在項(xiàng)目里我們把運(yùn)行模式分成了四種prompt模式純模板生成能力適合“改寫、總結(jié)、抽取”等任務(wù)。code模式直接執(zhí)行Python函數(shù)或外部API調(diào)用適合強(qiáng)邏輯操作比如發(fā)請(qǐng)求、算數(shù)據(jù)。flow模式編排多個(gè)子技能每個(gè)子技能完成后進(jìn)入下一步適合業(yè)務(wù)流程。hybrid模式先用代碼獲取數(shù)據(jù)再用Prompt整理結(jié)果例如先拉取報(bào)表數(shù)據(jù)再生成解讀結(jié)論。不同模式對(duì)應(yīng)不同的執(zhí)行器。代碼模式需要聲明入口函數(shù)和參數(shù)映射Prompt模式需要聲明模板路徑Flow模式則要聲明子技能列表和流轉(zhuǎn)條件。這樣設(shè)計(jì)的好處是技能的元數(shù)據(jù)足夠完整注冊(cè)中心可以提前做靜態(tài)校驗(yàn)而不是等運(yùn)行時(shí)才發(fā)現(xiàn)配置錯(cuò)誤。2.3 一個(gè)可直接抄的會(huì)議紀(jì)要技能樣例上面那個(gè)YAML已經(jīng)比較完整了。對(duì)應(yīng)的目錄結(jié)構(gòu)通常是skills/ meeting-minutes/ skill.yaml templates/ meeting_minutes.jinja2 assets/ output_schema.json calendar-reader/ skill.yaml run.py weekly-report/ skill.yaml flow.yaml run.py schema.json實(shí)際編寫時(shí)建議給每個(gè)技能配一個(gè)assets/output_schema.json輸出Schema會(huì)被嵌入到模型調(diào)用約束里保證技能返回格式穩(wěn)定后續(xù)解析不容易出錯(cuò)。這個(gè)“輸出Schema”是小成本大收益的設(shè)計(jì)尤其是當(dāng)技能會(huì)被其他技能依賴的時(shí)候穩(wěn)定的輸出格式就是技能之間協(xié)作的基礎(chǔ)。3. 注冊(cè)、檢索、按需加載把技能系統(tǒng)真正跑起來3.1 基于目錄約定的注冊(cè)中心掃描與校驗(yàn)技能系統(tǒng)第一步是注冊(cè)中心。我們選擇目錄約定大于配置也就是固定規(guī)則掃描skills/下的每個(gè)子目錄解析skill.yaml做靜態(tài)校驗(yàn)后建立索引。注冊(cè)中心的加載邏輯大概是這樣的import yaml from pathlib import Path def load_skill_from_dir(skill_dir: Path): manifest yaml.safe_load((skill_dir / skill.yaml).read_text(encodingutf-8)) required_fields {id, name, summary, description, run} missing required_fields - set(manifest.keys()) if missing: raise ValueError(f技能清單缺少字段: {missing}) run_mode manifest[run][mode] if run_mode prompt: template_path skill_dir / manifest[run][template] if not template_path.exists(): raise FileNotFoundError(fPrompt模板不存在: {template_path}) elif run_mode code: entry_file skill_dir / manifest[run][entry] if not entry_file.exists(): raise FileNotFoundError(f技能入口文件不存在: {entry_file}) manifest[_dir] skill_dir return manifest def load_all_skills(skills_root: Path) - dict: registry {} for skill_dir in skills_root.iterdir(): if not skill_dir.is_dir(): continue manifest_file skill_dir / skill.yaml if not manifest_file.exists(): continue skill load_skill_from_dir(skill_dir) if skill[id] in registry: raise ValueError(f技能ID沖突: {skill[id]}) registry[skill[id]] skill return registry注意兩點(diǎn)第一校驗(yàn)依賴閉環(huán)比如A技能依賴BB又依賴A需要報(bào)警第二校驗(yàn)字段沖突不同技能的ID和名稱都不能重復(fù)。這些靜態(tài)檢查雖然簡(jiǎn)單但能避免后面發(fā)布階段很多詭異問題。3.2 兩層召回策略關(guān)鍵詞粗篩與語義精排注冊(cè)中心構(gòu)建好之后最核心的問題是怎么把技能按需加載給模型。我們沒有用單一檢索方式而是用兩層召回關(guān)鍵詞粗篩對(duì)用戶當(dāng)前消息和摘要做關(guān)鍵詞匹配匹配技能名稱、summary、tags、aliases召回一批候選保證“確定性”。語義精排把用戶當(dāng)前意圖和歷史對(duì)話摘要拼成一個(gè)查詢向量對(duì)所有候選技能的描述做embedding相似度計(jì)算把最相似的若干技能排到前面。為什么需要兩層純向量檢索對(duì)代碼類技能名稱不敏感比如“待辦”和“todo”這類語義向量不一定拉得近純關(guān)鍵詞匹配又覆蓋不了“幫我記一下明天下午三點(diǎn)開會(huì)”這種自然語言表達(dá)。兩層一結(jié)合穩(wěn)定性和泛化性都有了。def retrieve_skills(query: str, history_summary: str, top_k: int 5): combined f{history_summary} [SEP] {query} keyword_candidates keyword_recall(combined, k20) vector_candidates semantic_recall(combined, k20) merged merge_candidates(keyword_candidates, vector_candidates) ranked rerank(combined, merged) return ranked[:top_k], ranked合并候選的時(shí)候關(guān)鍵詞命中的技能可以加權(quán)0.2語義相似的分?jǐn)?shù)保持原值最終按綜合分?jǐn)?shù)排序。我在項(xiàng)目里實(shí)測(cè)過四十多個(gè)技能全部暴露給模型時(shí)選擇正確率不到七成改成按需加載到五到八個(gè)技能后正確率能明顯提升。這個(gè)提升不是模型變強(qiáng)了而是決策面變小了。3.3 上下文組裝給模型看的不是全部技能檢索完成之后還有一個(gè)容易被忽略的步驟如何把技能信息組裝成模型能讀懂的輸入。我們不是把整個(gè)skill.yaml全量塞給模型而是裁剪成類似工具的JSON Schema保持輕量[ { name: meeting-minutes, description: 根據(jù)會(huì)議轉(zhuǎn)寫生成結(jié)構(gòu)化會(huì)議紀(jì)要。適用于用戶要求整理會(huì)議內(nèi)容、產(chǎn)出行動(dòng)項(xiàng)時(shí)。, parameters: { type: object, properties: { transcript: {type: string, description: 會(huì)議轉(zhuǎn)寫內(nèi)容}, language: {type: string, enum: [zh, en], default: zh} }, required: [transcript] } } ]至于技能內(nèi)部更詳細(xì)的Prompt模板、執(zhí)行步驟、依賴關(guān)系、失敗處理策略都不進(jìn)入模型上下文而是保存在技能執(zhí)行器里等模型決定調(diào)用之后再由執(zhí)行器加載。這個(gè)設(shè)計(jì)保持了Prompt的輕量也讓技能內(nèi)部細(xì)節(jié)可以隨時(shí)修改而不影響決策層。4. 描述質(zhì)量才是調(diào)用準(zhǔn)確率的隱藏杠桿4.1 同樣的技能兩種描述兩種效果技能描述是模型決定“要不要調(diào)用它”的唯一依據(jù)很多時(shí)候準(zhǔn)確率上不去的瓶頸不在模型而在描述寫得太敷衍。同樣是“創(chuàng)建待辦”這個(gè)技能差描述是這樣用于創(chuàng)建待辦事項(xiàng)參數(shù)內(nèi)容、時(shí)間。模型看到這種描述很難判斷“明天下午提醒我交報(bào)告”是不是應(yīng)該調(diào)它。好描述是這樣當(dāng)用戶提出要在任務(wù)管理、日歷、待辦清單中記錄一件事或者要求設(shè)置提醒、安排后續(xù)動(dòng)作時(shí)使用。 適用場(chǎng)景記錄任務(wù)、創(chuàng)建提醒、預(yù)約安排。 不適用場(chǎng)景用戶只是口頭討論計(jì)劃但沒有明確表示要記錄時(shí)不要調(diào)用。 參數(shù)content為待辦內(nèi)容due_time為ISO8601格式截止時(shí)間priority可選low/medium/high。 輸出創(chuàng)建成功后的待辦ID。后者包含了三層信息觸發(fā)場(chǎng)景、邊界條件、參數(shù)約束。這就是“給模型看的描述”和“給開發(fā)者看的注釋”之間的核心區(qū)別——描述不是在解釋函數(shù)邏輯而是在幫模型做決策。4.2 讓Alias替描述分擔(dān)口語化的表達(dá)我們接入了很多口語化表達(dá)的用戶。用戶可能說“記一下”“安排一下”“提醒我”這些都不帶“待辦”二字。為了解決這個(gè)問題我們?cè)诩寄芮鍐卫镌黾恿薬liases字段aliases: - 記錄 - 安排 - 提醒 - 待辦 - to-do - remind me這個(gè)字段不只是給關(guān)鍵詞召回用的在給模型的描述里也會(huì)出現(xiàn)類似“別名記錄/安排/提醒”的說法幫助模型把口語化表達(dá)映射到技能。aliases怎么來我們沒有完全靠人工維護(hù)而是定期從線上日志里抽取“模型未調(diào)用任何技能但用戶明顯有需求”的對(duì)話總結(jié)高頻表達(dá)再回流到這個(gè)字段里。4.3 描述顆粒度怎么對(duì)齊模型的決策能力描述寫得太粗或太細(xì)都會(huì)出問題。太粗的例子是“提供全面信息處理功能”模型根本不知道什么時(shí)候該選它太細(xì)的例子是“先用JSON解析器將字符串轉(zhuǎn)為對(duì)象再遍歷數(shù)組調(diào)用API”把執(zhí)行邏輯寫在描述里不僅占token還容易讓模型產(chǎn)生誤解。我們內(nèi)部的控制原則是描述里只保留“什么時(shí)候用、傳什么參數(shù)、得到什么結(jié)果”三層信息執(zhí)行細(xì)節(jié)全部放到技能內(nèi)部。另外所有描述盡量控制在100到300字太長(zhǎng)的描述在檢索排序和模型讀取時(shí)都會(huì)產(chǎn)生干擾。寫完描述后我們還會(huì)做一個(gè)自查如果一個(gè)新來的工程師只讀description不看代碼能不能準(zhǔn)確判斷調(diào)用場(chǎng)景如果不能說明描述還需要改。5. 實(shí)測(cè)踩坑五個(gè)問題對(duì)應(yīng)五套解法5.1 技能在庫(kù)里卻找不到的“沉默失敗”最讓人頭疼的問題不是模型亂調(diào)用而是該調(diào)用的技能它不調(diào)用而且不帶任何報(bào)錯(cuò)靜默失敗。我做排查時(shí)發(fā)現(xiàn)這類問題基本都出在檢索召回環(huán)節(jié)要么關(guān)鍵詞沒匹配上要么語義相似度排序太低候選里壓根沒有這個(gè)技能。后來我養(yǎng)成了一個(gè)調(diào)試習(xí)慣每次請(qǐng)求都把“用戶問題、檢索返回的前十候選、最終注入給模型的技能列表”完整打進(jìn)日志。查看時(shí)先看候選列表里有沒有目標(biāo)技能再去看模型到底選了哪個(gè)最后看執(zhí)行結(jié)果。這樣一步步定位而不是上來就懷疑模型能力。排查鏈路固定為檢索結(jié)果 - 模型決策 - 執(zhí)行狀態(tài)三個(gè)環(huán)節(jié)逐層看。5.2 相似技能互相打架不如合并接口項(xiàng)目里有個(gè)場(chǎng)景特別典型郵件類功能拆成了“發(fā)送郵件”“回復(fù)郵件”“創(chuàng)建郵件草稿”三個(gè)技能。這三個(gè)技能描述高度重疊模型經(jīng)常選錯(cuò)比如用戶說“把草稿發(fā)給小張”模型先去調(diào)“創(chuàng)建郵件草稿”再調(diào)“發(fā)送郵件”白白多跑幾輪。我們的解法不是把描述改得更細(xì)而是把三個(gè)技能合并成一個(gè)“郵件操作”技能把具體動(dòng)作移到參數(shù)里id: email-operation name: 郵件操作 description: 處理郵件創(chuàng)建、發(fā)送、回復(fù)、草稿保存等操作。通過action參數(shù)區(qū)分具體行為。 inputs: - name: action type: string enum: [draft, send, reply, save] - name: email_data type: object合并不是萬能的但接口語義相近、無法清晰切分邊界的技能合并成“一個(gè)技能一個(gè)動(dòng)作參數(shù)”往往比硬拆三個(gè)更好。反之如果兩個(gè)技能的輸入輸出差異很大、適用場(chǎng)景判若鴻溝那還是要拆開。5.3 技能內(nèi)部子步驟失敗不能拖垮主線技能內(nèi)部的子步驟很容易失敗比如“生成會(huì)議紀(jì)要”依賴“讀取日歷”這個(gè)子技能如果日歷接口超時(shí)整個(gè)紀(jì)要技能就崩了外層Agent直接報(bào)錯(cuò)。這暴露了一個(gè)問題技能執(zhí)行器缺少局部降級(jí)能力。我們的改進(jìn)方式是給執(zhí)行器加了兩層容錯(cuò)第一層是局部重試對(duì)可重試的子步驟最多重試兩次第二層是降級(jí)邏輯在技能清單的run.fallback里聲明備用方案。比如日歷讀取失敗時(shí)可以利用會(huì)議轉(zhuǎn)寫文本里的時(shí)間信息生成紀(jì)要并標(biāo)記“日歷部分未驗(yàn)證”。這樣主流程還能繼續(xù)走只是質(zhì)量打了折扣而不是整個(gè)鏈路斷掉。5.4 長(zhǎng)對(duì)話下檢索漂移需要意圖快照對(duì)話超過十幾輪之后我們用歷史摘要拼出來的檢索Query會(huì)變得越來越“飄”包含了太多無關(guān)信息經(jīng)常召回一些和當(dāng)前意圖完全無關(guān)的技能比如用戶正在聊天氣檢索結(jié)果里卻出現(xiàn)“排班表”技能。后來我們改成了維護(hù)一個(gè)“意圖快照”而不是每輪都用整段歷史做檢索。具體做法是每一輪結(jié)束后用一個(gè)小模型對(duì)“當(dāng)前正在執(zhí)行的任務(wù)棧”做增量更新下一輪檢索時(shí)用任務(wù)棧 最新一條用戶消息組合成Query。這個(gè)改動(dòng)之后長(zhǎng)對(duì)話的召回準(zhǔn)確率穩(wěn)定了很多也不容易被歷史噪聲帶偏。5.5 熱更新不生效版本快照與緩存失效技能系統(tǒng)的迭代頻率很高但我們最初遇到過“配置改了線上完全沒生效”的情況排查了一圈發(fā)現(xiàn)是技能元數(shù)據(jù)緩存沒有及時(shí)失效。后來我們給注冊(cè)中心增加了版本管理每個(gè)技能清單里加version字段執(zhí)行器按版本號(hào)綁定同時(shí)支持兩種失效策略一種是TTL定期刷新另一種是文件系統(tǒng)監(jiān)聽變更后主動(dòng)通知。更保險(xiǎn)的是“發(fā)布快照”機(jī)制新版本通過審批后才發(fā)布到生產(chǎn)當(dāng)前請(qǐng)求固定引用某個(gè)版本快照避免請(qǐng)求處理過程中技能配置被中途替換導(dǎo)致行為不一致。6. 下一步組合編排、自動(dòng)生成與回歸評(píng)測(cè)6.1 用Workflow把技能編排成完整工序當(dāng)技能數(shù)量多了之后單個(gè)技能完成一個(gè)任務(wù)的情況越來越少更多時(shí)候是幾個(gè)技能串成一條流程。我們的做法是在技能清單里增加flow字段id: weekly-report name: 生成周報(bào) run: mode: flow steps: - skill: event-collector input_map: start_time: 上周一 00:00 end_time: 本周日 23:59 - skill: progress-summarizer input_map: events: {{ steps.event-collector.output }} - skill: markdown-formatter input_map: content: {{ steps.progress-summarizer.output }}這種編排的價(jià)值在于每個(gè)步驟獨(dú)立、可復(fù)用、可測(cè)試中間任何一步失敗了都能定位到具體的子技能。相比把整個(gè)流程寫死在一個(gè)代碼文件里編排方式更靈活也更貼近業(yè)務(wù)邏輯。6.2 從調(diào)用技能到生成技能漸進(jìn)式玩法我們還在嘗試讓Agent自己生成新技能。做法是定期分析線上日志里“模型檢索了但候選為空且用戶問題反復(fù)出現(xiàn)”的失敗樣本把這些樣本聚類嘗試讓大模型根據(jù)歷史對(duì)話生成候選的skill.yaml和run.py骨架再由工程師審核上線。目前這個(gè)流程還不能完全無人化但已經(jīng)能明顯縮短新技能的開發(fā)時(shí)間。之前拉一個(gè)技能可能要半天現(xiàn)在只要人工確認(rèn)描述、補(bǔ)兩個(gè)邊界分支就能發(fā)布。這個(gè)方向讓我覺得“技能系統(tǒng)”最終會(huì)從“手寫技能庫(kù)”走向“技能生態(tài)”由Agent自己擴(kuò)展能力邊界。6.3 技能也有回歸測(cè)試建立調(diào)用預(yù)期樣本集技能系統(tǒng)上線久了最怕的就是“改了一個(gè)技能描述另一個(gè)場(chǎng)景的調(diào)用全亂了”。我們?yōu)榇私⒘艘粋€(gè)技能級(jí)回歸測(cè)試集每條樣本包含三部分用戶輸入、期望調(diào)用的技能ID、期望的關(guān)鍵參數(shù)。每次技能配置變更或模型升級(jí)都會(huì)批量跑一遍這個(gè)樣本集統(tǒng)計(jì)調(diào)用準(zhǔn)確率和參數(shù)正確率。這個(gè)做法本質(zhì)上有點(diǎn)像接口自動(dòng)化測(cè)試只是被測(cè)對(duì)象換成了“模型的調(diào)用決策”。它能很好地兜住技能系統(tǒng)的底讓我們每次改描述的時(shí)候都有一個(gè)量化標(biāo)準(zhǔn)而不是靠感覺說“應(yīng)該更準(zhǔn)了”。回到開頭那個(gè)項(xiàng)目現(xiàn)在這套技能系統(tǒng)已經(jīng)穩(wěn)定跑了一段時(shí)間最直觀的感受是新功能接入成本降下來了模型選錯(cuò)工具的case也少了而且每個(gè)技能都可以被獨(dú)立追蹤和優(yōu)化。如果你也正在經(jīng)歷“工具越加越多、準(zhǔn)確率越來越差”的困局建議先從盤點(diǎn)已有工具開始把它們拆成帶邊界、帶依賴、帶降級(jí)方案的技能單元再搭一個(gè)簡(jiǎn)單的注冊(cè)和檢索層你會(huì)明顯感覺到Agent的行為從“碰運(yùn)氣”變成了“有章法”。