聊到能干活:AI Skills讓Agent真正落地業(yè)務(wù))
這幾個(gè)月我一直在忙一件事把一個(gè)只會(huì)“嘴上答應(yīng)”的 Agent練成一個(gè)真能接手具體任務(wù)的“全能打工人”。聊天、檢索、任務(wù)規(guī)劃這些能力模型早就給得很足了真正卡住項(xiàng)目進(jìn)度的從來不是“模型會(huì)不會(huì)聊”而是“Agent 能不能把活兒干完”。我見過不少團(tuán)隊(duì)在 Demo 階段表現(xiàn)得頭頭是道一接真實(shí)業(yè)務(wù)就露怯讓它查個(gè)訂單它只會(huì)說“我可以幫你查”讓它改個(gè)配置它能現(xiàn)場編一套不存在的 API。最后把整個(gè)項(xiàng)目撈起來的不是更聰明的模型而是一層不起眼但極其關(guān)鍵的東西——AI Skills。這篇我把在騰訊云上從“只會(huì)聊”到“能干活”的完整養(yǎng)成過程梳理一遍包括 Skill 的定位設(shè)計(jì)、服務(wù)端托管選型、Agent 側(cè)集成、上線后的運(yùn)維與安全以及幾處實(shí)測踩出來的坑。想自己搭 Agent、把智能體真正落到業(yè)務(wù)里的開發(fā)者這應(yīng)該是一份可以直接參考的實(shí)戰(zhàn)記錄。1. 先想清楚一件事Skill 到底在替 Agent 干什么很多人一上來就急著寫工具函數(shù)、接 API結(jié)果做出來的東西不叫 Agent叫“套了層對話外殼的接口文檔”。所以在動(dòng)手之前我想先把 Skill 的定位掰扯清楚。1.1 Skill、Workflow、Function Calling 三者是什么關(guān)系我在社區(qū)里看到不少人在搜“skill和agent的區(qū)別”“harness和agent區(qū)別”“agent框架與編排”這類問題說明大家對這些概念其實(shí)還是模糊的。不把概念拆干凈后面設(shè)計(jì)接口、寫提示詞、做編排都會(huì)跑偏。用最直白的話講Function Calling是模型的一種底層能力讓模型在對話中決定“要不要調(diào)用某個(gè)函數(shù)”并輸出結(jié)構(gòu)化的調(diào)用參數(shù)。它解決的是“模型怎么開口”的問題。Workflow是預(yù)先編排好的流程節(jié)點(diǎn)固定、分支確定適合業(yè)務(wù)流程穩(wěn)定的場景比如“先查庫存再算價(jià)格最后生成訂單”。它解決的是“事情按什么順序做”的問題。Skill是給 Agent 準(zhǔn)備的一組“可復(fù)用的能力單元”每個(gè) Skill 封裝了特定任務(wù)的完整處理邏輯可以是單個(gè)函數(shù)也可以是多個(gè)工具的聯(lián)動(dòng)加提示詞模板。它解決的是“Agent 遇到這類事該找誰、怎么干”的問題。這三者的關(guān)系在我看來是這樣的Skill 在更高層面對能力做了封裝Function Calling 是模型觸達(dá)能力的手段Workflow 則可以在 Skill 內(nèi)部作為實(shí)現(xiàn)方式之一。打個(gè)比方一個(gè)剛?cè)肼毜膶?shí)習(xí)生Agent什么都不會(huì)你教他各種工作技能Skill他需要打電話訂會(huì)議室、發(fā)郵件確認(rèn)日程、提交報(bào)銷單。他每一次“開口辦事”的能力是 Function Calling而“訂會(huì)議室”這件事該先做什么、后做什么的固定流程就是 Workflow。沒有 Skill 的 Agent 就像一個(gè)只有通訊錄但沒有辦事能力的實(shí)習(xí)生——什么都能問什么都辦不成。1.2 為什么 Skill 值得單獨(dú)沉淀一層我見過不少項(xiàng)目第一版把工具函數(shù)直接寫死在提示詞里或者一股腦全塞給模型。前幾次跑通 Demo 很爽等到要加業(yè)務(wù)邏輯、要復(fù)用、要給別人調(diào)用的時(shí)候痛點(diǎn)全來了重復(fù)勞動(dòng)接單、查庫存、發(fā)通知這些基礎(chǔ)能力每個(gè) Agent 項(xiàng)目都要重寫一遍。上下文爆炸所有工具的說明都塞給模型一次對話光工具描述就占兩三千 token模型反而不知道該用哪個(gè)。能力邊界模糊同一個(gè)動(dòng)作這個(gè) Agent 里叫query_order那個(gè) Agent 里叫g(shù)etOrderInfo維護(hù)的人直接崩潰。沒法灰度改一個(gè)工具的實(shí)現(xiàn)所有依賴它的 Agent 全部受影響上線前要全部回歸。把 Skill 單獨(dú)抽出來本質(zhì)上是在“模型”和“業(yè)務(wù)能力”之間加了一層標(biāo)準(zhǔn)化的中間層。模型不需要理解訂單系統(tǒng)底層是 MySQL 還是 Redis也不需要知道下發(fā)工單走的是 HTTP 還是消息隊(duì)列它只需要知道“這個(gè) Skill 能干什么、需要什么參數(shù)、返回什么結(jié)果”。這樣 Agent 和 Skill 之間就變成了一個(gè)相對穩(wěn)定的契約關(guān)系業(yè)務(wù)代碼怎么改都不會(huì)影響 Agent 的“認(rèn)知”。這也是為什么我在騰訊云上做這套東西時(shí)寧可前期多花一點(diǎn)時(shí)間把 Skill 的接口定義清楚也不愿意圖快塞一堆臨時(shí)函數(shù)進(jìn)去。后面所有項(xiàng)目都能復(fù)用這套能力這筆賬是算得過來的。2. 服務(wù)端 Skill 的接口契約把“干活”變成可調(diào)用的服務(wù)想清楚了 Skill 的定位接下來最核心的事就是把“干活”這件事定義成一個(gè)可調(diào)用的服務(wù)。這里不是簡單寫個(gè)接口就行接口契約沒定好模型再聰明也會(huì)用錯(cuò)工具。2.1 輸入?yún)?shù)與 Schema 設(shè)計(jì)AI Skills 的消費(fèi)方不是瀏覽器里的前端頁面而是模型。這決定了接口的輸入輸出設(shè)計(jì)天然面向“機(jī)器可理解”而非“人可閱讀”。我自己常用的一個(gè)設(shè)計(jì)范式是三步第一步給 Skill 起一個(gè)極有辨識度的名字和一句話描述。模型是靠這個(gè)名字在工具列表里做匹配的命名含糊等于沒命名。比如query_order_status就比getData好一百倍描述里要寫明“根據(jù)訂單號查詢當(dāng)前訂單的處理狀態(tài)適用于用戶催單、訂單跟蹤場景”這種明確的描述能顯著降低模型誤調(diào)用的概率。第二步用 JSON Schema 嚴(yán)格定義入?yún)?。參?shù)名要可讀類型要嚴(yán)格描述要完整。比如{ name: query_order_status, description: 根據(jù)訂單號查詢訂單當(dāng)前狀態(tài)適用于訂單跟蹤、催單處理等場景, parameters: { type: object, properties: { order_id: { type: string, description: 訂單號格式為 14 位數(shù)字例如 20250101000123 }, include_detail: { type: boolean, description: 是否返回商品明細(xì)默認(rèn)為 false } }, required: [order_id] } }這里有個(gè)很容易踩的坑參數(shù)的 description 寫得越具體模型的參數(shù)提取準(zhǔn)確率越高。如果你只寫“訂單號”三個(gè)字模型面對用戶那句“幫我看看我前天買的那單到哪了”很可能不知道把“前天買的那單”化約成哪個(gè)訂單號。但如果你說明“訂單號格式為 14 位數(shù)字用戶通常能在短信或訂單列表中找到”模型就多了一個(gè)推理依據(jù)。第三步設(shè)計(jì)統(tǒng)一的響應(yīng)結(jié)構(gòu)。我習(xí)慣用這樣的格式{ code: 0, message: success, data: { order_id: 20250101000123, status: shipping, tracking: SF1234567890 } }不管底層邏輯多復(fù)雜返回結(jié)構(gòu)必須統(tǒng)一。這樣 Agent 側(cè)解析結(jié)果時(shí)只需要寫一個(gè)通用解析器而不是每個(gè) Skill 寫一套。2.2 冪等、超時(shí)與錯(cuò)誤碼定義模型調(diào)用 Skill 和人在瀏覽器里點(diǎn)按鈕有一個(gè)本質(zhì)區(qū)別模型在拿不到明確結(jié)果時(shí)會(huì)傾向于“再試一次”。這是大模型的通病。所以 Skill 服務(wù)端必須把冪等性和超時(shí)策略設(shè)計(jì)好不然一個(gè)重復(fù)提交就能讓你的訂單系統(tǒng)多出幾筆臟數(shù)據(jù)。冪等性最簡單的做法是在參數(shù)里加一個(gè)request_id服務(wù)端收到請求時(shí)先查這個(gè) ID 是否處理過處理過就直接返回上一次的結(jié)果。這個(gè)字段由 Agent 側(cè)在發(fā)起調(diào)用時(shí)生成保證每次模型重復(fù)調(diào)用傳遞的是同一個(gè) ID 即可。超時(shí)策略上我給 Skill 設(shè)定的經(jīng)驗(yàn)值是普通查詢類操作控制在 3 秒以內(nèi)返回寫操作可以放寬到 5 到 10 秒。模型側(cè)的超時(shí)應(yīng)設(shè)置得略長于服務(wù)端留出網(wǎng)絡(luò)和排隊(duì)的時(shí)間。如果服務(wù)端超時(shí)了必須返回一個(gè)明確的“超時(shí)”錯(cuò)誤碼而不是返回一段讓人摸不著頭腦的異常文本否則模型會(huì)把異常文本當(dāng)作正常結(jié)果拿去做下一步推理。錯(cuò)誤碼設(shè)計(jì)有一個(gè)原則寧可多分幾個(gè)不要一碼通吃。我至少會(huì)定義這幾個(gè)錯(cuò)誤碼含義Agent 側(cè)建議處理方式0成功直接使用 data40001參數(shù)校驗(yàn)失敗提取缺失參數(shù)向用戶追問40002業(yè)務(wù)校驗(yàn)失敗直接向用戶說明原因50001服務(wù)內(nèi)部異常重新調(diào)用一次若仍失敗則升級為人工50002上游依賴超時(shí)延遲后重試連續(xù)兩次失敗轉(zhuǎn)人工這套設(shè)計(jì)在第一次上線時(shí)可能看不出多大優(yōu)勢等到模型在長鏈路任務(wù)中多次調(diào)用 Skill、或者并發(fā)量上來之后它的價(jià)值會(huì)非常明顯。排查問題的速度、模型的自愈能力全靠這些細(xì)粒度錯(cuò)誤碼撐著。3. 騰訊云上的 Skill 托管選型云函數(shù)、容器還是網(wǎng)關(guān)Skill 本質(zhì)上是無狀態(tài)的服務(wù)托管在哪、怎么暴露給外部調(diào)用是整個(gè)方案里最需要結(jié)合自身情況做選擇的部分。騰訊云上常見的路線有三條云函數(shù)SCF、容器服務(wù)TKE 或 CVM Docker、API 網(wǎng)關(guān)。我三條都實(shí)測過各自特點(diǎn)非常明顯。3.1 三種托管方式的對比與選型我根據(jù)自己的項(xiàng)目經(jīng)驗(yàn)整理了一個(gè)對比表維度云函數(shù) SCF容器服務(wù)CVM / TKEAPI 網(wǎng)關(guān)啟動(dòng)速度冷啟動(dòng)一般幾百毫秒到 1 秒熱啟動(dòng)毫秒級取決于容器鏡像和實(shí)例規(guī)格取決于后端服務(wù)擴(kuò)縮容自動(dòng)擴(kuò)縮按調(diào)用次數(shù)計(jì)費(fèi)手動(dòng)或配置 HPA按資源計(jì)費(fèi)可做限流、轉(zhuǎn)發(fā)不算計(jì)算資源適用場景輕量接口、簡單聚合、低頻調(diào)用復(fù)雜業(yè)務(wù)邏輯、長連接、有狀態(tài)服務(wù)統(tǒng)一入口、鑒權(quán)、限流、多后端路由運(yùn)維成本低幾乎不用管服務(wù)器需要管理鏡像、節(jié)點(diǎn)、網(wǎng)絡(luò)中低需要管理路由配置典型費(fèi)用結(jié)構(gòu)按調(diào)用次數(shù) 資源使用量按實(shí)例規(guī)格 運(yùn)行時(shí)長按調(diào)用量 流量我的建議很簡單Skill 是輕量查詢類、邏輯不復(fù)雜選云函數(shù)。比如查訂單、查天氣、查庫存這種云函數(shù)跑起來毫無壓力還省去了運(yùn)維服務(wù)器的精力。Skill 依賴了復(fù)雜的運(yùn)行環(huán)境比如需要特定 Python 包、模型推理、音視頻處理選容器。把依賴全部打包進(jìn)鏡像環(huán)境一致性好不會(huì)出現(xiàn)“本地能跑、服務(wù)器跑不了”的玄學(xué)問題。多個(gè) Skill 需要統(tǒng)一入口、統(tǒng)一鑒權(quán)、統(tǒng)一限流前面掛一層 API 網(wǎng)關(guān)。網(wǎng)關(guān)本身不跑業(yè)務(wù)邏輯它把請求路由到不同的后端服務(wù)上相當(dāng)于給整套 Agent 能力做了一個(gè)統(tǒng)一門面。我在實(shí)際項(xiàng)目里最常用的組合是“API 網(wǎng)關(guān) 云函數(shù)”或者“API 網(wǎng)關(guān) 容器服務(wù)”。Agent 側(cè)只面對一個(gè)網(wǎng)關(guān)地址網(wǎng)關(guān)根據(jù) path 或 header 把請求轉(zhuǎn)發(fā)給對應(yīng)的 Skill 實(shí)現(xiàn)。這樣后續(xù)加新的 Skill只是多一條路由的事。3.2 Docker 鏡像推送與配置一次完整的踩坑記錄說到容器就繞不開把本地構(gòu)建好的鏡像推到騰訊云容器鏡像服務(wù)TCR這一步。我最早在這一步上折騰了小半天問題都不是什么高深原理全是細(xì)節(jié)。流程本身不算復(fù)雜# 1. 本地給鏡像打上騰訊云倉庫的 tag docker tag my-skill-image:latest ccr.ccs.tencentyun.com/my-namespace/my-skill:latest # 2. 登錄鏡像倉庫 docker login ccr.ccs.tencentyun.com --username 你的騰訊云賬號ID # 3. 推送 docker push ccr.ccs.tencentyun.com/my-namespace/my-skill:latest看起來很簡單對吧但我第一次推的時(shí)候踩了三個(gè)坑每一個(gè)都讓人頭大第一個(gè)坑登錄用戶名不是你的登錄郵箱也不是你的昵稱而是騰訊云賬號 ID。很多人在這里卡住拿注冊郵箱登錄一直報(bào)認(rèn)證失敗。實(shí)際上控制臺里把鼠標(biāo)懸停在右上角頭像上能看到那串?dāng)?shù)字賬號 ID那才是docker login要的用戶名密碼用的是賬號關(guān)聯(lián)的 API 密鑰或臨時(shí)密鑰。第二個(gè)坑命名空間要先在控制臺創(chuàng)建。你本地 tag 里的my-namespace必須是在 TCR 控制臺里已經(jīng)創(chuàng)建好的命名空間不能隨便編一個(gè)。我見過有人直接寫項(xiàng)目名push 的時(shí)候報(bào)namespace not found又回去翻文檔。第三個(gè)坑內(nèi)網(wǎng)環(huán)境和公網(wǎng)環(huán)境的鏡像倉庫地址不一樣。如果你的 CVM 和鏡像倉庫在同一個(gè)地域建議用內(nèi)網(wǎng)域名推送速度快、還免流量費(fèi)。公網(wǎng)域名在本地推送沒問題但到了服務(wù)器上有時(shí)會(huì)因?yàn)榫W(wǎng)絡(luò)策略走不通。這三個(gè)坑屬于那種“知道了一次之后就再也不會(huì)踩”但第一次踩的時(shí)候確實(shí)能消耗掉大量耐心。我之后的做法是把docker login和docker push寫進(jìn)部署腳本參數(shù)自動(dòng)從環(huán)境變量讀取盡量減少手敲命令出錯(cuò)的機(jī)會(huì)。3.3 域名、端口與安全組配置的細(xì)節(jié)Skill 服務(wù)起來之后要讓 Agent 能訪問到就繞不開域名解析和端口開放的問題。很多人在騰訊云服務(wù)器上部署完服務(wù)發(fā)現(xiàn)從外部訪問不了第一反應(yīng)是“防火墻是不是有問題”然后去控制臺把安全組端口全部放通。這里我要給一個(gè)明確的建議別開放所有端口務(wù)必按需放行。騰訊云服務(wù)器本身默認(rèn)的安全組策略是只放行常用端口比如 22、80、443這是好事。Skill 服務(wù)的 HTTP 端口比如 8080、9090默認(rèn)是不通的需要自己在安全組規(guī)則里加一條“放行 TCP 端口 8080”的規(guī)則。站在安全角度我一般建議如果 Skill 只給 Agent 調(diào)用不直接暴露給公網(wǎng)用戶那最好通過 API 網(wǎng)關(guān)轉(zhuǎn)發(fā)安全組只放行來自網(wǎng)關(guān)所在網(wǎng)段的流量。如果有公網(wǎng)訪問需求建議用 HTTPS 域名而不是裸 IP端口。申請一個(gè)二級域名子域名并在 DNS 解析里加一條 A 記錄指到服務(wù)器公網(wǎng) IP再用 Nginx 或網(wǎng)關(guān)層做 TLS 終結(jié)比直接公網(wǎng)裸奔穩(wěn)得多。云服務(wù)器安全組里的“來源”不要填0.0.0.0/0讓全網(wǎng)都能訪問能限定 IP 就限定 IP哪怕先限定為自己的出口 IP 或網(wǎng)關(guān) IP 也好。這件事上我吃過一次教訓(xùn)順手把安全組配成全部放通結(jié)果服務(wù)上線第二天日志里就全是掃描器的探測記錄。后來嚴(yán)格收斂到朗指定源之后干凈多了。4. Agent 側(cè)集成讓模型真正會(huì)用這套 SkillSkill 服務(wù)端準(zhǔn)備好了并不意味著 Agent 就能用得好。模型怎么知道什么場景用哪個(gè) Skill、怎么把用戶的話轉(zhuǎn)成正確的參數(shù)、拿到了結(jié)果怎么組織成回復(fù)這中間還有一道關(guān)鍵的集成工程。4.1 工具描述與上下文裁剪給模型一份精準(zhǔn)的“使用手冊”大多數(shù) Agent 框架在接工具時(shí)都會(huì)要求開發(fā)者提供工具名、工具描述和參數(shù) Schema。這個(gè)環(huán)節(jié)看似簡單恰恰是決定“模型會(huì)不會(huì)用錯(cuò)工具”的分水嶺。我的經(jīng)驗(yàn)是描述里要寫清楚三件事這個(gè)工具解決什么問題、什么場景下調(diào)用、什么情況下不要調(diào)用。反面教材是只寫一句“查詢訂單信息”正面教材是下面這樣查詢訂單狀態(tài)。當(dāng)用戶詢問訂單進(jìn)度、物流信息、發(fā)貨狀態(tài)、簽收情況時(shí)調(diào)用。 僅在用戶提供明確訂單號時(shí)適合直接調(diào)用若用戶只提供了模糊信息如前天下的單 應(yīng)先用對話引導(dǎo)確認(rèn)訂單號不要調(diào)用此工具。加了“不要調(diào)用”的邊界之后模型在模糊場景下的表現(xiàn)會(huì)好很多。因?yàn)榇竽P驮诓淮_定時(shí)傾向于調(diào)用工具“證明自己能干”但你明確告訴它“這種情況不該調(diào)”它反而會(huì)收斂到先追問用戶。上下文裁剪是另一個(gè)容易忽略的點(diǎn)。模型上下文窗口再大也不能把所有 Skill 的描述一股腦全塞進(jìn)去。我現(xiàn)在會(huì)先給模型按命名空間或業(yè)務(wù)域分組在對話前根據(jù)用戶消息的關(guān)鍵意圖做一次粗篩只把可能相關(guān)的 Skill 描述掛到工具列表里。比如用戶問的是訂單問題那就只掛訂單相關(guān)的 3 到 5 個(gè) Skill而不是把庫存、支付、售后、物流的所有工具全部掛上去。這一步能顯著降低模型的誤調(diào)率同時(shí)省下大量 token。4.2 多 Skill 編排從單工具調(diào)用到組合執(zhí)行單個(gè) Skill 可以解決一件事但真實(shí)業(yè)務(wù)往往是一個(gè)流程。在接收到“幫我取消昨天買的那個(gè)藍(lán)牙耳機(jī)訂單”這種需求時(shí)Agent 至少需要拆成三步先定位訂單再查詢訂單狀態(tài)最后如果訂單還沒發(fā)貨才允許取消。這就涉及到多 Skill 的編排。這里我踩過一個(gè)大坑早期把編排邏輯寫在提示詞里讓模型自己“看著辦”。模型確實(shí)有編排能力但穩(wěn)定性差同一個(gè)請求可能今天是“先查訂單再取消”明天就變成“直接調(diào)取消接口”。后來我把編排分成兩層硬流程有嚴(yán)格順序和依賴關(guān)系的步驟放在 Agent 的編排層用代碼固定。比如“先查單確認(rèn)狀態(tài)為待發(fā)貨才能調(diào)取消接口”這一步不允許模型自由發(fā)揮。軟決策多條路線都合理的時(shí)候才交給模型根據(jù)上下文選擇。比如查詢訂單既可以用訂單號也可以用手機(jī)號讓模型根據(jù)已有的信息決定用哪個(gè)參數(shù)。這個(gè)“硬編碼 軟決策”的混合編排模式是我在多次試錯(cuò)后覺得最穩(wěn)的方案。全軟全靠模型結(jié)果不可控全硬寫死又失去了 Agent 的靈活性。另外多 Skill 協(xié)作時(shí)還有一個(gè)細(xì)節(jié)后一個(gè) Skill 的參數(shù)可能來自前一個(gè) Skill 的響應(yīng)。這時(shí)候要給模型明確的字段映射指引。比如取消訂單需要 order_id而這個(gè) order_id 恰好是上一個(gè)查詢接口返回結(jié)構(gòu)里的data.order_id我會(huì)在 Skill 描述里標(biāo)注“該參數(shù)來源于 query_order_status 的返回字段 data.order_id”模型順著這個(gè)提示幾乎不會(huì)搭錯(cuò)線。4.3 結(jié)果回流別讓模型把結(jié)構(gòu)化數(shù)據(jù)原樣甩給用戶Skill 返回的是結(jié)構(gòu)化 JSON用戶看到的不應(yīng)該是這段 JSON。模型拿到結(jié)果之后還需要做一層“翻譯工作”把數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)成自然語言。比如查詢接口返回{ code: 0, data: { status: shipping, tracking_company: SF, tracking_no: SF1234567890, estimated_arrival: 2025-02-02 } }好的回復(fù)是“您的訂單已經(jīng)發(fā)貨啦用的順豐單號是 SF1234567890預(yù)計(jì) 2 月 2 日送達(dá)?!倍皇撬o你一個(gè) JSON 塊。這段轉(zhuǎn)化提示詞也要寫得具體包括哪些字段直接告訴用戶status、tracking_no哪些字段要在特定條件下才展示estimated_arrival 只有在下單當(dāng)天到送達(dá)前展示什么情況下需要引導(dǎo)用戶做下一步動(dòng)作訂單狀態(tài)是 signed可追問是否需要售后模型在這方面的表現(xiàn)直接決定了用戶體感。同樣一個(gè) Skill有的 Agent 用起來像專業(yè)客服有的像接口調(diào)試工具差別全在這層回流設(shè)計(jì)上。5. 上線之后的運(yùn)維與安全從能用到好用Skill 部署上去、Agent 跑通了項(xiàng)目才完成了一半。另一半在于上線之后怎么保證它穩(wěn)定、安全、可排查。這部分的經(jīng)驗(yàn)是我在被真實(shí)流量毒打之后一點(diǎn)點(diǎn)攢下的。5.1 日志與鏈路追蹤不然出問題只能靠瞎猜Agent 調(diào) Skill 是一次典型的跨系統(tǒng)調(diào)用用戶輸入 → 模型推理 → 框架調(diào)度 → 網(wǎng)關(guān)轉(zhuǎn)發(fā) → 云函數(shù)/容器執(zhí)行 → 返回結(jié)果。任意一環(huán)出問題都可能表現(xiàn)為“Agent 回答得不對勁”。如果沒有鏈路追蹤排查一個(gè)異??赡芤奈鍌€(gè)系統(tǒng)的日志而且彼此之間完全對不上時(shí)間線。我的做法是在 Agent 側(cè)生成一個(gè)trace_id隨 HTTP Header 傳給 Skill 服務(wù)端。Skill 側(cè)的所有日志都帶上這個(gè) IDtrace_id8f3a9c1b 2025-01-20 14:23:01 INFO 參數(shù)校驗(yàn)通過 order_id20250101000123 trace_id8f3a9c1b 2025-01-20 14:23:02 INFO 上游訂單系統(tǒng)返回 statusshipping trace_id8f3a9c1b 2025-01-20 14:23:02 INFO 響應(yīng)耗時(shí) 120ms這樣不管問題出現(xiàn)在哪個(gè)環(huán)節(jié)只要有個(gè) trace_id就能把整條鏈路的日志串起來。成本很低收益極高。騰訊云上云函數(shù)本身自帶日志查詢?nèi)萜鞣?wù)也能接日志服務(wù)。我習(xí)慣把所有 Skill 的日志統(tǒng)一投遞到一個(gè)日志主題里按trace_id建索引。排查問題的時(shí)候直接在日志平臺里搜一個(gè) trace_id從頭到尾的調(diào)用過程一目了然效率比從前翻服務(wù)器的/var/log高多了。另外日志中不要打印敏感信息。身份證號、手機(jī)號、支付賬號這類字段能脫敏就脫敏。既是為了合規(guī)也是防止日志泄露造成安全問題。5.2 限流、密鑰管理與安全邊界Agent 一旦面向真實(shí)用戶Skill 就處于“不可信流量”的前沿。防刷、防濫用、防越權(quán)這些事不能等出事了再想。限流是第一個(gè)要做的。API 網(wǎng)關(guān)層我一般會(huì)配置兩檔限流一是按調(diào)用方維度限制 QPS防止某個(gè)異常用戶把后端打爆二是按 Skill 維度限制總流量防止某個(gè) Skill 成為熱點(diǎn)后拖垮整個(gè)系統(tǒng)。騰訊云 API 網(wǎng)關(guān)自帶限流插件配置好之后后端服務(wù)基本不用關(guān)心流量洪峰的問題。密鑰管理是另一個(gè)重點(diǎn)。Skill 服務(wù)里經(jīng)常要調(diào)用第三方 API、訪問數(shù)據(jù)庫免不了要存密碼和密鑰。我見過最危險(xiǎn)的做法是把密鑰寫死在代碼里或者放在配置文件的明文里鏡像一打包全帶出去了。在騰訊云上我現(xiàn)在的標(biāo)準(zhǔn)做法是數(shù)據(jù)庫密碼、第三方 API Key 全部放在密鑰管理服務(wù)里運(yùn)行時(shí)通過 API 讀取。云函數(shù)或容器運(yùn)行時(shí)關(guān)聯(lián)一個(gè)有最小權(quán)限的服務(wù)角色而不是在代碼里保存長期密鑰。所有密鑰定期輪換輪換時(shí)只改密鑰管理里的版本不重新發(fā)版。安全邊界上還要考慮一件事Skill 服務(wù)不應(yīng)該默認(rèn)信任調(diào)用者傳過來的數(shù)據(jù)。參數(shù)校驗(yàn)要嚴(yán)格該鑒權(quán)的必須鑒權(quán)該校驗(yàn)歸屬的必須校驗(yàn)歸屬。比如取消訂單的 Skill只校驗(yàn)“這個(gè)訂單號存在”是不夠的還要校驗(yàn)“這個(gè)訂單屬于當(dāng)前這個(gè)用戶”否則就是一個(gè)越權(quán)漏洞。模型只是幫你生成參數(shù)它可不會(huì)幫你做權(quán)限判斷這個(gè)責(zé)任得靠業(yè)務(wù)代碼扛。5.3 一個(gè)典型的坑Redis 改完密碼重啟后服務(wù)起不來說到密鑰和基礎(chǔ)服務(wù)分享一個(gè)我在騰訊云服務(wù)器上真實(shí)遇到過的坑。本身跟 AI Skills 沒有直接關(guān)系但它是整套服務(wù)鏈路里最容易卡住部署的環(huán)節(jié)。當(dāng)時(shí)我在云服務(wù)器上裝了 Redis準(zhǔn)備給 Skill 服務(wù)做緩存。裝好后修改了redis.conf里的requirepass設(shè)置了新密碼然后執(zhí)行redis-server restart。結(jié)果 Redis 一直啟動(dòng)失敗或者啟動(dòng)了但日志里報(bào)NOAUTH Authentication required。更奇怪的是明明改了配置文件redis-cli連上去之后跑CONFIG GET requirepass顯示的仍然是舊密碼。排查了半天才發(fā)現(xiàn)原因Redis 啟動(dòng)時(shí)加載的配置文件不是我以為的那個(gè)或者 systemd 服務(wù)腳本里指定了另一個(gè)配置路徑。你在/etc/redis/redis.conf里改了requirepass但 systemd 啟動(dòng)的 Redis 實(shí)際加載的是/etc/redis/redis.conf.bak或者壓根沒有顯式指定配置文件導(dǎo)致 Redis 以默認(rèn)配置無密碼啟動(dòng)。這個(gè)問題排查鏈路其實(shí)不復(fù)雜但需要對 Linux 服務(wù)管理有一定了解# 先看 Redis 進(jìn)程的實(shí)際啟動(dòng)參數(shù) ps aux | grep redis-server # 看 systemd 服務(wù)文件里指定的配置路徑 systemctl cat redis # 用命令行驗(yàn)證是否真的加載了目標(biāo)配置 redis-cli -a 新密碼 CONFIG GET requirepass看到實(shí)際加載路徑之后把修改寫到正確的配置文件中再重啟問題解決。這個(gè)坑我和不少同行都踩過核心教訓(xùn)是不要憑直覺以為“我改了配置文件”要用命令驗(yàn)證進(jìn)程到底加載了哪個(gè)配置。這類基礎(chǔ)服務(wù)的坑平時(shí)看起來跟 AI 關(guān)系不大但在真正落地部署 Agent 服務(wù)鏈路時(shí)往往會(huì)成為最耗時(shí)的攔路虎。我后來養(yǎng)成的習(xí)慣是所有基礎(chǔ)組件Redis、MySQL、Nginx的配置文件統(tǒng)一管理啟動(dòng)命令統(tǒng)一進(jìn)腳本每次部署后跑一輪排查命令驗(yàn)證狀態(tài)而不是“看著似乎起來了就行”。6. 一次 0 到 1 的落地復(fù)盤可以照搬的最小閉環(huán)最后把整個(gè)從零到一的過程串一下算是我個(gè)人認(rèn)為比較省力的一套最小閉環(huán)路徑。這套路徑適合第一次在騰訊云上從零搭 Agent AI Skills 的團(tuán)隊(duì)我后來好幾個(gè)項(xiàng)目都沿用了這個(gè)節(jié)奏。6.1 最小閉環(huán)的七個(gè)步驟第一步選一個(gè)具體業(yè)務(wù)場景不要貪多。比如“查訂單狀態(tài)”就比“做一整套售后服務(wù)機(jī)器人”好落地得多。場景越聚焦Skill 的邊界越清晰模型越容易用對。第二步定義 Skill 的接口契約。按照前面說的 Schema 規(guī)范把輸入?yún)?shù)、輸出結(jié)構(gòu)、錯(cuò)誤碼定義好。這個(gè)步驟一定要寫文檔不然后面接 Agent 框架時(shí)會(huì)來回扯皮。第三步在騰訊云上部署 Skill 服務(wù)。輕量場景直接云函數(shù)復(fù)雜場景用容器。先保證通過 Postman 或者 curl 能直接調(diào)用通再進(jìn)下一步。第四步把 Skill 描述接入 Agent 框架。用框架提供的工具注冊機(jī)制把 Skill 的名字、描述、參數(shù) Schema 掛上去先用簡單對話驗(yàn)證模型能不能正確調(diào)用。第五步逐個(gè)打磨模型對 Skill 的使用效果。測試不同問法下模型的參數(shù)提取能力調(diào)整 Skill 描述直到模型在絕大多數(shù)情況下都能給出正確參數(shù)。第六步加入多 Skill 編排。從兩個(gè) Skill 開始先把硬流程用代碼固定再把軟決策交給模型。第七步上線前補(bǔ)上運(yùn)維三件套日志鏈路、限流配置、密鑰管理。把安全邊界的最后一塊補(bǔ)上然后再放流量。這套路徑走下來通常一到兩周就能看到一個(gè)能真實(shí)干活的 Agent。我自己的體會(huì)是最難的不是寫代碼而是克制住“再加一個(gè)功能”的沖動(dòng)。每多塞一個(gè) Skill模型的調(diào)度難度就上一點(diǎn)后續(xù)的回歸測試工作量也大一截。Skill 的邊界守得住Agent 的穩(wěn)定性才守得住。6.2 關(guān)于 Skill 持續(xù)演進(jìn)的幾條建議等第一版跑起來之后Skill 的運(yùn)營才真正開始。我自己總結(jié)了幾條經(jīng)驗(yàn)給每個(gè) Skill 加版本號。更新時(shí)先灰度一部分流量確認(rèn)無誤再全量。模型面向的是真實(shí)用戶一個(gè) Skill 的故障會(huì)直接表現(xiàn)為 Agent 胡說八道。建立 Skill 效果評估集。拿一批真實(shí)用戶問題每次改完 Skill 描述或?qū)崿F(xiàn)之后跑一遍回歸對比正確調(diào)用率。這個(gè)數(shù)據(jù)集會(huì)越攢越值錢。關(guān)注模型誤調(diào)用的日志。如果模型經(jīng)常在不需要查詢的時(shí)候調(diào)了查詢 Skill或者反復(fù)傳錯(cuò)參數(shù)說明 Skill 描述里的邊界寫得不夠清楚需要回爐優(yōu)化。Skill 之間盡量解耦。不要讓一個(gè) Skill 內(nèi)部去調(diào)另一個(gè) Skill 的接口這種跨層調(diào)用會(huì)形成隱式依賴出問題的時(shí)候排查鏈路會(huì)變得很長。項(xiàng)目前期這種設(shè)計(jì)看起來省事到了后期都是技術(shù)債。在這種模式下Agent 本身反而有點(diǎn)像一張“會(huì)思考的嘴”真正干活的是那幾只不斷打磨的“手”。把手上的肌肉練扎實(shí)了嘴才能說到做到。最后再分享一個(gè)我在實(shí)際使用中建立的習(xí)慣每當(dāng)遇到模型調(diào)用 Skill 出錯(cuò)我不急著去改提示詞碰運(yùn)氣而是先把整條鏈路的日志翻出來定位到底是模型理解錯(cuò)了、參數(shù)傳錯(cuò)了、還是服務(wù)端返回有問題。把每次出錯(cuò)的根因記下來攢一段時(shí)間再回頭看你會(huì)發(fā)現(xiàn)模型行為規(guī)律其實(shí)很清晰改起來也更有方向。這套“以日志為老師”的辦法比拍腦袋調(diào)參靠譜得多。