總翻車?Harness工程給大模型應(yīng)用裝上“駕駛艙”護(hù)欄)
這幾年AI Agent很火但真正敢讓Agent自動(dòng)干活的團(tuán)隊(duì)不多不管是內(nèi)部工具還是對(duì)外服務(wù)我見過(guò)太多項(xiàng)目在Demo階段驚艷全場(chǎng)一上生產(chǎn)就翻車。原因幾乎都是同一個(gè)Agent的執(zhí)行過(guò)程是概率性的而生產(chǎn)環(huán)境要求的是確定性。你可能遇到過(guò)這種情況同一個(gè)問題讓Agent跑兩次第一次一路順暢拿到結(jié)果第二次它繞了半天還在原地打轉(zhuǎn)甚至把不該調(diào)的接口都調(diào)了一遍。這不是模型不夠強(qiáng)而是缺少一層控制與承載體系——也就是今天要聊的Harness工程。Harness這個(gè)詞直譯過(guò)來(lái)是安全帶線束用在AI Agent領(lǐng)域我更喜歡把它理解為一套駕駛艙系統(tǒng)。Agent是發(fā)動(dòng)機(jī)Harness是方向盤、儀表盤、剎車和導(dǎo)航的總和。發(fā)動(dòng)機(jī)馬力再大沒有這些輔助系統(tǒng)你也不敢讓它在真實(shí)道路上自己跑。這篇文章會(huì)從穩(wěn)定性問題拆起把Harness工程的核心機(jī)制講透再給出一套可以直接落地的架構(gòu)和代碼骨架。適合那些正在從跑通Demo走向上生產(chǎn)的工程師、技術(shù)Leader和獨(dú)立開發(fā)者。1. 先說(shuō)清楚Agent不穩(wěn)定到底卡在哪1.1 概率性執(zhí)行同一個(gè)問題兩次答案可能不一樣大模型本身是概率模型同樣的輸入溫度不為0時(shí)輸出會(huì)有隨機(jī)性。很多團(tuán)隊(duì)在搭建Agent的第一天就想用Prompt強(qiáng)行約束模型必須輸出JSON必須調(diào)用某個(gè)工具結(jié)果發(fā)現(xiàn)模型偶爾就是不聽。這不是模型不聰明而是你設(shè)計(jì)系統(tǒng)時(shí)還在用函數(shù)調(diào)用的心智模型但Agent本質(zhì)上是對(duì)話生成動(dòng)作序列的心智模型。生產(chǎn)系統(tǒng)最怕的不是出錯(cuò)而是不可復(fù)現(xiàn)。普通代碼同樣的輸入必然得到同樣的輸出但Agent不是。你需要先接受這個(gè)前提再設(shè)計(jì)一套機(jī)制來(lái)收窄不確定性。比如把溫度調(diào)到0、強(qiáng)制結(jié)構(gòu)化輸出、增加校驗(yàn)層讓模型即使胡思亂想也被攔在門外。1.2 多步任務(wù)的累積誤差一步錯(cuò)步步錯(cuò)真正復(fù)雜的Agent不是一個(gè)Prompt就能搞定的它通常要拆解成理解意圖→拆分任務(wù)→調(diào)用工具→匯總結(jié)果→生成回答多個(gè)步驟。每一步都有成功率假設(shè)單步成功率是90%五步之后整體成功率就只剩59%。也就是說(shuō)十個(gè)請(qǐng)求里有四個(gè)會(huì)失敗。這就是為什么很多Demo工具跑單步很漂亮但一旦涉及多步操作比如查一下這個(gè)月所有項(xiàng)目的支出并生成報(bào)表就頻繁出錯(cuò)。問題往往不是最后一步處理報(bào)表錯(cuò)了而是在前面的查詢項(xiàng)目列表選擇字段調(diào)用統(tǒng)計(jì)接口這些環(huán)節(jié)中某一個(gè)走了彎路。Harness工程的一個(gè)重要任務(wù)就是做累積誤差控制——每一步都要加校驗(yàn)、加補(bǔ)償、加糾錯(cuò)機(jī)制而不是把所有希望寄托在模型一次想明白。1.3 外部工具是不可控的黑盒Agent的價(jià)值在于能使用工具但工具也是最大的不穩(wěn)定源。API會(huì)超時(shí)、會(huì)限流、會(huì)返回異常結(jié)構(gòu)、會(huì)突然改字段。有時(shí)甚至不是你代碼的問題而是第三方服務(wù)在給你返回200但JSON里全是錯(cuò)誤信息。我在一個(gè)項(xiàng)目里踩過(guò)很經(jīng)典的坑Agent調(diào)用一個(gè)訂單查詢接口接口返回200但業(yè)務(wù)碼是50012表示訂單不存在或無(wú)權(quán)訪問。Agent沒有檢查業(yè)務(wù)碼直接把里面的錯(cuò)誤描述當(dāng)成正常數(shù)據(jù)寫進(jìn)了最終報(bào)告。單看日志沒有任何異常但結(jié)果一塌糊涂。工具治理的核心就是不能盲目相信HTTP狀態(tài)碼為200就代表成功必須在工具層統(tǒng)一做防御性校驗(yàn)。1.4 穩(wěn)定不是不報(bào)錯(cuò)而是可控地失敗理解穩(wěn)定性前先厘清一個(gè)誤區(qū)我們要的不是Agent永遠(yuǎn)不出錯(cuò)而是出錯(cuò)時(shí)我們能快速發(fā)現(xiàn)、快速限定影響范圍、快速恢復(fù)。就像飛機(jī)不是永遠(yuǎn)不會(huì)出故障而是有冗余系統(tǒng)和應(yīng)急預(yù)案讓故障不會(huì)導(dǎo)致機(jī)毀人亡。所以Harness工程的目標(biāo)可以用三句話概括失敗能被發(fā)現(xiàn)、失敗能被隔離、失敗后能從容恢復(fù)。這需要我們?cè)贏gent外面包一層完整的控制邏輯而不是把希望全押在Prompt上。這也是為什么單純寫Prompt技巧解決不了生產(chǎn)穩(wěn)定性問題需要從工程架構(gòu)層面下手。2. Harness工程到底解決什么問題2.1 先分清Agent和Harness不少人有困惑Harness和Agent的區(qū)別是什么我經(jīng)常用一個(gè)類比Agent是你的員工Harness是公司的規(guī)章制度和辦公系統(tǒng)。員工可以有自己的能力但如果沒有考勤、預(yù)算審批、操作日志、質(zhì)量檢查你根本不敢讓他獨(dú)立處理客戶事務(wù)。放在AI場(chǎng)景里Agent負(fù)責(zé)做什么理解任務(wù)、規(guī)劃步驟、決定調(diào)用哪個(gè)工具。Harness負(fù)責(zé)怎么做才安全控制流程、記錄軌跡、校驗(yàn)輸出、限制權(quán)限、處理異常。兩者是配合關(guān)系不是替代關(guān)系。單純有Agent很靈活但不受控單純有Harness很安全但沒有智能。2.2 Harness是駕駛艙而不是引擎引擎是Agent的核心智能駕駛艙負(fù)責(zé)讓駕駛員安全到達(dá)目的地。駕駛艙里有油門也有剎車有儀表盤也有導(dǎo)航甚至還有限速器。對(duì)應(yīng)到AI系統(tǒng)里油門是Agent的自主決策能力剎車是限流和熔斷儀表盤是可觀測(cè)性導(dǎo)航是任務(wù)路由限速是權(quán)限和資源配額。我見過(guò)一些團(tuán)隊(duì)把大量精力放在調(diào)Prompt讓模型更智能上卻不投入精力建設(shè)駕駛艙。結(jié)果模型智能上去了亂闖紅綠燈的能力也跟著上去了。真正要上生產(chǎn)反而應(yīng)該先在Harness上下功夫因?yàn)橹悄苣芰Φ牟罹嗫梢钥磕P桶姹镜a(bǔ)上但失控會(huì)造成不可逆的信任崩塌。2.3 穩(wěn)定性的四個(gè)支柱控制、可觀測(cè)、容錯(cuò)、恢復(fù)這四件事是Harness工程的核心抓手缺一不可。第一控制。Agent的決策邊界、工具權(quán)限、資源消耗都要有明確上限。比如單個(gè)任務(wù)最多調(diào)用10次工具、最多跑30秒、最多消耗50萬(wàn)token一旦觸頂就必須停下不能讓它無(wú)限跑下去。第二可觀測(cè)。每個(gè)Agent從誕生到消亡的完整軌跡都要能回放它看到了什么、想了什么、調(diào)用了什么、結(jié)果是什么、在哪個(gè)環(huán)節(jié)花了最多時(shí)間。沒有這些數(shù)據(jù)排查問題就是大海撈針。第三容錯(cuò)。請(qǐng)求超時(shí)了重試一次參數(shù)不對(duì)就重新生成工具返回異常就換個(gè)方案。Harness要把這些兜底邏輯固化下來(lái)而不是每次出問題都靠寫死分支。第四恢復(fù)。某個(gè)Agent實(shí)例掛了任務(wù)要能轉(zhuǎn)移到另一個(gè)實(shí)例繼續(xù)跑上下文丟了要有Checkpoint可以回滾到最近一個(gè)安全節(jié)點(diǎn)。2.4 為什么叫Engineering而不叫Framework叫Framework容易讓人以為裝個(gè)依賴就能解決所有問題但真實(shí)世界的穩(wěn)定性問題往往來(lái)自業(yè)務(wù)語(yǔ)義和系統(tǒng)集成不是某個(gè)庫(kù)能完全覆蓋的。叫Engineering是把它當(dāng)作一項(xiàng)持續(xù)投入的工程需要架構(gòu)設(shè)計(jì)、監(jiān)控告警、故障演練、持續(xù)優(yōu)化。比如我曾經(jīng)花了兩周時(shí)間優(yōu)化一個(gè)Agent的重試策略。最早是失敗就重試結(jié)果下游接口是冪等的還好說(shuō)碰到非冪等的扣費(fèi)接口就釀成事故。后來(lái)改成只有特定錯(cuò)誤碼才重試重試次數(shù)超過(guò)3次就進(jìn)入人工確認(rèn)隊(duì)列。這個(gè)過(guò)程沒有現(xiàn)成框架能幫我決定必須基于業(yè)務(wù)理解去設(shè)計(jì)。所以Harness Engineering本質(zhì)上是一種工程思維而不是一個(gè)安裝包。3. 核心機(jī)制拆解給Agent裝上約束與護(hù)欄3.1 狀態(tài)管理讓Agent有工作記憶而不是臨時(shí)腦Agent執(zhí)行多步任務(wù)時(shí)最怕失憶。它前面已經(jīng)查到了用戶所在城市的編碼下一步要用這個(gè)編碼查天氣結(jié)果它忘了又去問用戶你在哪個(gè)城市。這不是模型能力問題而是狀態(tài)管理缺失。我建議把Agent運(yùn)行時(shí)的狀態(tài)分成三類短期對(duì)話狀態(tài)、任務(wù)執(zhí)行狀態(tài)、長(zhǎng)期記憶。短期對(duì)話狀態(tài)就是本輪請(qǐng)求的上下文可以直接放在內(nèi)存或請(qǐng)求對(duì)象里任務(wù)執(zhí)行狀態(tài)要放進(jìn)可持久化的存儲(chǔ)比如Redis或數(shù)據(jù)庫(kù)保存到哪一步了、中間結(jié)果是什么長(zhǎng)期記憶存在向量庫(kù)里供跨會(huì)話復(fù)用。有個(gè)實(shí)戰(zhàn)經(jīng)驗(yàn)把中間結(jié)果顯式寫成一個(gè)結(jié)構(gòu)化工作區(qū)而不是全塞在自然語(yǔ)言上下文里。工作區(qū)里直接維護(hù)當(dāng)前用戶ID訂單號(hào)查詢結(jié)果這類字段。Agent在每一步都先讀工作區(qū)再?zèng)Q定下一步動(dòng)作。這樣確實(shí)能顯著減少模型忘記前面信息的毛病也讓狀態(tài)可檢查可調(diào)。3.2 工具治理注冊(cè)制、Schema校驗(yàn)、超時(shí)熔斷工具才是Agent落地時(shí)的真正風(fēng)險(xiǎn)敞口所以要像治理微服務(wù)一樣治理工具。第一步是注冊(cè)制所有Agent能調(diào)用的工具都要先在Harness里聲明比如工具名稱、用途、入?yún)⒏袷?、出參格式、?quán)限等級(jí)。Agent只能調(diào)用已注冊(cè)的工具它的自由組合能力被約束在可控范圍內(nèi)。第二步是Schema校驗(yàn)。模型輸出的工具調(diào)用參數(shù)有時(shí)候會(huì)丟字段、類型錯(cuò)誤或者缺必填項(xiàng)Harness要像API網(wǎng)關(guān)一樣做參數(shù)校驗(yàn)不通過(guò)就拒絕調(diào)用并反饋給Agent重新修正。我一般用JSON Schema做校驗(yàn)出錯(cuò)信息盡量具體比如參數(shù)customer_id是string類型你傳的是object。第三步是超時(shí)、重試和熔斷。每個(gè)工具調(diào)用都要有超時(shí)時(shí)間默認(rèn)10秒超時(shí)后返回給Agent一個(gè)明確的錯(cuò)誤。重試只對(duì)可重試的錯(cuò)誤生效比如網(wǎng)絡(luò)異常、限流而對(duì)參數(shù)被拒業(yè)務(wù)異常這類錯(cuò)誤直接終止。熔斷的意思是如果某個(gè)工具連續(xù)失敗率超過(guò)閾值比如5分鐘內(nèi)有50%請(qǐng)求失敗Harness要主動(dòng)停用這個(gè)工具一段時(shí)間防止鏈路雪崩。3.3 決策約束結(jié)構(gòu)化輸出與策略路由大部分Agent任務(wù)其實(shí)不需要模型完全自由發(fā)揮我們需要的是在給定的選項(xiàng)里做選擇。與其讓模型自由生成整個(gè)JSON不如讓它生成結(jié)構(gòu)化字段然后在Harness里做二次校驗(yàn)。舉個(gè)例子客服Agent接到用戶投訴后Harness希望它輸出一個(gè)意圖分類候選值是退款換貨物流查詢其他。這時(shí)候不應(yīng)該讓模型自由發(fā)揮寫一句話而是讓它從四個(gè)選項(xiàng)里選一個(gè)再生成補(bǔ)充參數(shù)。這個(gè)選擇策略可以放在代碼里硬校驗(yàn)?zāi)P洼敵鐾丝罹推ヅ渲形尼屃x輸出退貨也要映射到退款分類。策略路由則是把不太需要智能的流程交給確定的代碼。很多Agent編排其實(shí)可以拆成先判斷是否命中固定規(guī)則命中就走決策樹沒命中再交給LLM。這樣大部分流量走穩(wěn)定路徑只有小部分復(fù)雜場(chǎng)景才走模型推理穩(wěn)定性和成本都能兼顧。3.4 上下文治理窗口管理、壓縮、長(zhǎng)期記憶分層LLM的上下文窗口是有限資源也是最貴的資源。有一次我統(tǒng)計(jì)項(xiàng)目成本發(fā)現(xiàn)光是不斷把對(duì)話歷史全部發(fā)給模型一個(gè)月就燒掉了不少錢。后來(lái)我們做了上下文治理分三層處理。第一層是窗口管理設(shè)定最大消息長(zhǎng)度超過(guò)之后做截?cái)嗷蛱蕹蛢r(jià)值消息。有些歷史消息比如你好謝謝這種根本不重要可以直接丟掉。第二層是摘要壓縮當(dāng)輪次很多時(shí)讓模型定期把早期對(duì)話壓縮成一個(gè)摘要放到當(dāng)前上下文的頭部既保留了關(guān)鍵信息又壓縮了token。第三層是長(zhǎng)期記憶把用戶偏好、歷史結(jié)論存到向量庫(kù)按需檢索而不是把所有歷史都塞進(jìn)每次請(qǐng)求。這三層做下來(lái)平均每個(gè)請(qǐng)求的token消耗能降40%以上。上下文不再是做菜時(shí)堆得滿滿的案板而是像圖書館一樣有索引、有摘要、有書庫(kù)需要哪本取哪本。4. 實(shí)操搭建一套生產(chǎn)可用的Harness4.1 分層架構(gòu)接入層、控制層、能力層、存儲(chǔ)層我通常把一個(gè)生產(chǎn)級(jí)Harness分成四層。接入層負(fù)責(zé)接收用戶請(qǐng)求、鑒權(quán)、會(huì)話管理這是所有流量進(jìn)入的第一道閘門??刂茖邮呛诵陌瑺顟B(tài)機(jī)、路由、工具調(diào)用編排、校驗(yàn)、限流、重試、熔斷等邏輯。能力層是Agent真正使用的外部資源比如大模型API、內(nèi)部服務(wù)、數(shù)據(jù)庫(kù)、第三方系統(tǒng)。存儲(chǔ)層保存會(huì)話狀態(tài)、工具調(diào)用日志、工作區(qū)數(shù)據(jù)、長(zhǎng)期記憶等。這套分層的好處是職責(zé)清晰控制邏輯不散落在業(yè)務(wù)代碼里。比如你要在某個(gè)環(huán)節(jié)增加新的校驗(yàn)只需要改控制層不需要?jiǎng)覣gent的提示詞和工具代碼。每一層都能獨(dú)立測(cè)試、獨(dú)立擴(kuò)容不像一個(gè)巨大的Agent類那樣把所有邏輯揉在一起。4.2 最小可運(yùn)行代碼骨架Python FastAPI LangGraph我用Python生態(tài)比較順手下面給個(gè)能跑的骨架。核心思路是用LangGraph來(lái)管理狀態(tài)機(jī)和Agent的流程用FastAPI做HTTP入口外部再掛上校驗(yàn)和重試邏輯。from typing import TypedDict, Literal from langgraph.graph import StateGraph, END from pydantic import BaseModel, validator # 定義工作區(qū)狀態(tài)這是Harness的關(guān)鍵 # 所有步驟共享的結(jié)構(gòu)化狀態(tài)而不是純自然語(yǔ)言 class AgentState(TypedDict): user_id: str query: str order_id: str | None intent: str | None tool_result: dict | None retry_count: int trace_id: str # 工具調(diào)用前用Pydantic做參數(shù)校驗(yàn) class QueryOrderInput(BaseModel): order_id: str user_id: str validator(order_id) def order_id_not_empty(cls, v): if not v.strip(): raise ValueError(order_id cannot be empty) return v # 第一步解析意圖但這里我們采用策略路由 # 先嘗試規(guī)則匹配匹配不到才交給LLM def route_intent(state: AgentState) - AgentState: query state[query] if 退 in query or 退款 in query: state[intent] refund elif 訂單 in query: state[intent] query_order else: # 調(diào)用LLM做意圖識(shí)別示例省略具體實(shí)現(xiàn) state[intent] unknown return state # 第二步調(diào)用工具這里展示超時(shí)和重試骨架 def call_query_order(state: AgentState) - AgentState: if state[intent] ! query_order: return state # 入?yún)⑿r?yàn) try: params QueryOrderInput(order_idstate[order_id], user_idstate[user_id]) except ValueError as e: state[tool_result] {error: f參數(shù)校驗(yàn)失敗: {e}} state[retry_count] 1 return state # 調(diào)用內(nèi)部訂單服務(wù)帶超時(shí)邏輯 try: result query_order_api(params.order_id, params.user_id, timeout10) if result[business_code] ! 0: # 業(yè)務(wù)錯(cuò)誤不重試直接返回到可觀測(cè)日志 state[tool_result] {error: f業(yè)務(wù)失敗: {result[msg]}} else: state[tool_result] result[data] except TimeoutError: state[tool_result] {error: timeout} state[retry_count] 1 return state # 用StateGraph把這些步驟串起來(lái) graph StateGraph(AgentState) graph.add_node(route, route_intent) graph.add_node(query_order, call_query_order) graph.add_edge(route, query_order) graph.add_edge(query_order, END) app graph.compile() # FastAPI暴露HTTP接口 from fastapi import FastAPI, HTTPException server FastAPI() server.post(/agent) async def run_agent(user_id: str, query: str, order_id: str | None None): if not query: raise HTTPException(status_code400, detailquery不能為空) state AgentState( user_iduser_id, queryquery, order_idorder_id, intentNone, tool_resultNone, retry_count0, trace_idgenerate_trace_id(), ) # 每個(gè)請(qǐng)求都會(huì)淺拷貝state并發(fā)安全由LangGraph保證 final_state await app.ainvoke(state) return final_state這個(gè)骨架看起來(lái)很簡(jiǎn)略但核心思想值得注意所有決策和調(diào)用都圍繞結(jié)構(gòu)化狀態(tài)AgentState展開工具的輸入和輸出都有校驗(yàn)讓模型自由發(fā)揮的空間被壓縮到只有意圖識(shí)別這一個(gè)環(huán)節(jié)。生產(chǎn)環(huán)境里你還可以在route_intent后用一次LLM調(diào)用做多輪對(duì)話但固定流程的部分盡量不要完全交給LLM。4.3 并發(fā)與韌性限流、隊(duì)列、重試和信號(hào)量很多朋友問AI Agent怎么扛并發(fā)。Agent本身不是高并發(fā)的好手它慢、貴、占用上下文。Harness要做的是把并發(fā)沖擊擋在系統(tǒng)外把計(jì)算資源按配額分配。我的做法是三個(gè)層次。入口層做限流比如單用戶單會(huì)話的QPS限制、全局并發(fā)上限??刂茖右胄盘?hào)量限制同時(shí)運(yùn)行的最大Agent任務(wù)數(shù)假設(shè)你的下游API只能承受50個(gè)并發(fā)那Harness的并發(fā)數(shù)就控制在40留出緩沖。任務(wù)層如果流量突然飆高就把超出的請(qǐng)求放入隊(duì)列排隊(duì)返回用戶系統(tǒng)繁忙或顯示排隊(duì)進(jìn)度條而不是無(wú)腦并發(fā)把所有下游接口打死。還有一個(gè)容易忽略的點(diǎn)重試要加退避抖動(dòng)。如果100個(gè)請(qǐng)求同時(shí)超時(shí)它們同時(shí)重試會(huì)給下游造成二次峰值。我一般用指數(shù)退避第一次等1秒第二次等2秒第三次等4秒再加上一個(gè)0到1秒的隨機(jī)抖動(dòng)。這樣重試的流量會(huì)分散開來(lái)有效避免驚群效應(yīng)。4.4 可觀測(cè)性Trace、Log、Metric三件套生產(chǎn)環(huán)境沒有可觀測(cè)性等于蒙著眼睛開飛機(jī)。我在Harness里會(huì)做三件事。第一全鏈路Trace。每次Agent請(qǐng)求生成一個(gè)TraceID從入口到每次工具調(diào)用都打上這個(gè)ID。最好把模型調(diào)用的輸入輸出也塞進(jìn)低頻存儲(chǔ)里。排查問題的時(shí)候把TraceID一搜就能看到它每一步的輸入輸出比只盯著最終結(jié)果要強(qiáng)太多。第二結(jié)構(gòu)化日志。日志不是給人看的散文而是給檢索用的結(jié)構(gòu)化事件。每個(gè)事件至少包含時(shí)間戳、TraceID、AgentID、步驟名、耗時(shí)、狀態(tài)、錯(cuò)誤信息。后期任何指標(biāo)統(tǒng)計(jì)都能直接基于這些字段聚合。第三核心指標(biāo)。我最關(guān)注的四個(gè)指標(biāo)請(qǐng)求成功率、平均/中位數(shù)耗時(shí)、Token消耗、工具調(diào)用失敗率。這四個(gè)指標(biāo)可以畫在同一張Dashboard上。一旦某個(gè)版本的Prompt或新工具上線的同時(shí)成功率掉下來(lái)馬上就能發(fā)現(xiàn)。我還習(xí)慣加一個(gè)行為漂移檢測(cè)定期隨機(jī)抽取一部分請(qǐng)求比對(duì)Agent的軌跡分布。如果發(fā)現(xiàn)某個(gè)工具的調(diào)用頻率出現(xiàn)異常波動(dòng)大概率是模型行為變了。這種事用戶感知不到但會(huì)在后期體現(xiàn)成成功率下降。5. 高頻問題與排查實(shí)錄5.1 Agent陷入死循環(huán)怎么辦最常見的問題是Agent反復(fù)調(diào)用同一個(gè)工具比如它查了三遍天氣接口、又把昨天的錯(cuò)誤信息當(dāng)成新輸入去問模型。我一般用三個(gè)手段防死循環(huán)最大步數(shù)限制、循環(huán)檢測(cè)、中斷人機(jī)確認(rèn)。最大步數(shù)限制很簡(jiǎn)單比如一個(gè)任務(wù)最多20步達(dá)到后強(qiáng)制終止并給用戶一個(gè)進(jìn)入人工客服的鏈接。循環(huán)檢測(cè)稍微復(fù)雜一點(diǎn)把每次工具調(diào)用的參數(shù)和結(jié)果摘要做成hash如果發(fā)現(xiàn)同一個(gè)hash出現(xiàn)三次就判定為循環(huán)這時(shí)把Agent的思考重置一下清掉一些歷史再讓它重新規(guī)劃。如果重置了兩次還是循環(huán)那就不再硬撐讓運(yùn)營(yíng)介入。還有一個(gè)成本很低的方案給Agent設(shè)置允許的出格動(dòng)作上限比如最多調(diào)用5次風(fēng)險(xiǎn)接口超過(guò)5次就必須征求用戶確認(rèn)我這邊發(fā)現(xiàn)重復(fù)執(zhí)行了某操作確認(rèn)繼續(xù)嗎這個(gè)交互句話雖然簡(jiǎn)單但能截住很多異常。5.2 上下文越寫越長(zhǎng)成本和響應(yīng)都失控這在長(zhǎng)會(huì)話場(chǎng)景特別常見。用戶連續(xù)聊了二三十輪上下文里塞滿了原始消息模型每次推理開銷越來(lái)越大響應(yīng)也變慢。解決思路上面提過(guò)就是分層治理。我踩過(guò)的一個(gè)坑是手動(dòng)寫了個(gè)截?cái)嗯f消息的邏輯結(jié)果截?cái)嗵みM(jìn)把上上輪用戶明確要求的下午3點(diǎn)的鬧鐘給丟了鬧鐘設(shè)錯(cuò)了。后來(lái)我改成抽取關(guān)鍵信息到結(jié)構(gòu)化slot比如用戶明確表達(dá)過(guò)的日期、時(shí)間、地點(diǎn)、偏好都存到slot里而不是依賴自然語(yǔ)言歷史。上下文里可以丟自然語(yǔ)言但slot必須保留這樣就算歷史被壓縮關(guān)鍵約束也不會(huì)丟。另一個(gè)小技巧如果上下文已經(jīng)很長(zhǎng)讓模型優(yōu)先基于slot和最近兩輪來(lái)回復(fù)而不是每次都看全部歷史。你會(huì)發(fā)現(xiàn)很多場(chǎng)景根本不需要全程上下文。5.3 工具調(diào)用各種Timeout/參數(shù)錯(cuò)亂工具調(diào)用的Timeout是最穩(wěn)定的報(bào)錯(cuò)來(lái)源。我整理了三個(gè)排查方向。第一看你的HTTP客戶端是不是設(shè)置了默認(rèn)的無(wú)窮超時(shí)。有些代碼庫(kù)請(qǐng)求庫(kù)默認(rèn)超時(shí)非常長(zhǎng)一旦下游掛住Harness也一起掛住。務(wù)必給每個(gè)請(qǐng)求顯式設(shè)置超時(shí)。第二看錯(cuò)誤類型。是連接超時(shí)還是讀超時(shí)后者說(shuō)明下游已經(jīng)接收請(qǐng)求但處理太慢這時(shí)冪等請(qǐng)求可以重試非冪等請(qǐng)求要降級(jí)。第三校驗(yàn)Agent生成的參數(shù)是不是真的符合工具要求。我遇到過(guò)模型把1990-01-01這個(gè)字符串轉(zhuǎn)換成1990/01/01傳給一個(gè)只接受YYYY-MM-DD的接口結(jié)果接口解析失敗。Harness里應(yīng)該有一份參數(shù)規(guī)范表并在工具調(diào)用前做自動(dòng)轉(zhuǎn)換或校驗(yàn)。一些必須強(qiáng)調(diào)的規(guī)矩重試只適用于冪等接口。如果是扣費(fèi)、發(fā)短信、下單這類操作重試就是災(zāi)難。所以工具注冊(cè)時(shí)要聲明冪等性不聲明默認(rèn)不重試。5.4 版本升級(jí)后行為變異用黃金數(shù)據(jù)集守住回歸大模型上線和升級(jí)跟傳統(tǒng)代碼發(fā)版不一樣。模型價(jià)值升級(jí)了但行為可能會(huì)有你不知道的偏移。我見過(guò)某個(gè)Agent在GPT-4升級(jí)到新版本后突然把所有日期格式從12月25日改成了12/25內(nèi)部解析直接崩了。要攔截這類問題我會(huì)維護(hù)一個(gè)黃金數(shù)據(jù)集里面是100到200條真實(shí)且有代表性的任務(wù)每條都有期望輸出和允許的偏差范圍。每次模型版本升級(jí)、Prompt改動(dòng)、工具Schema調(diào)整都用這個(gè)數(shù)據(jù)集跑一遍回歸看通過(guò)率掉沒掉。通過(guò)率低于95%就不能上線。另外一個(gè)良心建議Agent上線前要準(zhǔn)備人工兜底開關(guān)。萬(wàn)一生產(chǎn)環(huán)境出現(xiàn)大面積異常至少能一鍵切換到人工模式不讓異常繼續(xù)擴(kuò)大。這個(gè)開關(guān)就像消防系統(tǒng)的手動(dòng)閥門寧可平時(shí)不用不能沒有。6. 我的實(shí)操體會(huì)最近這個(gè)項(xiàng)目讓我印象最深的一件事是我們把大量的Prompt工程時(shí)間抽出來(lái)做Harness之后Agent反而變笨了但整體成功率從70%左右一路穩(wěn)定到97%以上。用戶的感受不是這AI很聰明而是這AI做事靠譜。對(duì)生產(chǎn)系統(tǒng)來(lái)說(shuō)靠譜比聰明值錢得多。還有一個(gè)體會(huì)是Harness工程并不需要一步到位。你可以先做最輕量的版本在Agent外面加一層最大步數(shù)限制、工具結(jié)果校驗(yàn)和全鏈路日志這三件事三天內(nèi)就能做完但效果立竿見影。再往后逐步追加狀態(tài)管理、上下文治理、熔斷機(jī)制。不要一開始就想用最重度的方案小步快跑反而更容易沉淀出真正貼合你業(yè)務(wù)的Harness。另外建議備一個(gè)故障演練日。每個(gè)月找一個(gè)流量低峰期故意把下一個(gè)工具接口調(diào)成超時(shí)看Agent的表現(xiàn)是否正常。這個(gè)做法讓我理解了一點(diǎn)Harness不是寫出來(lái)的是不斷被事故錘煉出來(lái)的?,F(xiàn)在每次上線新工具我們都會(huì)先人為制造幾次異常場(chǎng)景確認(rèn)兜底邏輯可靠之后才會(huì)放量。如果這篇文章能給到你的團(tuán)隊(duì)一個(gè)明確的抓手pick三個(gè)最容易出問題的環(huán)節(jié)狀態(tài)管理、工具校驗(yàn)、異常兜底。把這三件套做到位你的Agent就算不能吊打GPT-5也能在業(yè)務(wù)線上穩(wěn)穩(wěn)當(dāng)當(dāng)下地干活。