:從原理到生產(chǎn)環(huán)境落地)
1. 為什么“會調(diào)API”和“能跑Agent”之間隔了一整個Runtime這兩年做大模型應(yīng)用的人都有一個共同感受寫一個能對話的Demo半天就夠了但要讓一個Agent在真實業(yè)務(wù)里連續(xù)跑上幾十步、調(diào)用七八個工具、中途還能自我糾錯最后穩(wěn)定交付結(jié)果難度直接上兩個數(shù)量級。問題不在于模型不夠聰明而在于大多數(shù)團隊把“Agent”當成了一個Prompt問題而它本質(zhì)上是一個Runtime問題。我見過太多項目卡在同一個地方單輪對話效果驚艷一旦進入多步任務(wù)就開始“發(fā)瘋”——工具調(diào)用參數(shù)漂移、上下文越滾越長導(dǎo)致關(guān)鍵信息被淹沒、某一步失敗后整個流程直接崩掉、并發(fā)一上來狀態(tài)就串了。這些都不是靠改幾句提示詞能解決的它們屬于編排層和運行時層的工程問題。所謂Agent Runtime你可以把它理解成Agent的“操作系統(tǒng)”。模型是CPU負責(zé)推理和決策工具是外設(shè)負責(zé)和外部世界交互而Runtime負責(zé)調(diào)度、內(nèi)存管理、錯誤恢復(fù)、狀態(tài)持久化、并發(fā)控制。沒有這層你的Agent就是一個裸奔的while循環(huán)能跑通一次是運氣跑通一萬次才是工程。這篇文章我想把Agent編排這件事從底層原理到工程落地完整拆一遍。核心回答三個問題編排到底在編排什么、一個真正好用的Runtime需要哪些核心模塊、以及在實際落地時那些文檔里不會寫的坑。適合已經(jīng)寫過基礎(chǔ)Agent、正準備把它推向生產(chǎn)環(huán)境的開發(fā)者也適合想理解這層抽象到底解決什么問題的人。全文會給出可參考的模塊劃分、參數(shù)設(shè)計思路和排查方法你可以直接對照自己的項目做體檢。2. 編排的本質(zhì)把“不確定性”關(guān)進“確定性”的籠子里2.1 編排到底在編排什么很多人對“Agent編排”的理解停留在“把幾個步驟串起來”。這個理解太淺了。編排真正要處理的是模型輸出的不確定性與業(yè)務(wù)流程的確定性要求之間的矛盾。模型每次輸出都是概率采樣同一個輸入可能給出不同的工具選擇、不同的參數(shù)格式、不同的推理路徑。但業(yè)務(wù)要求是確定的這筆訂單必須查到、這個文件必須生成、這個審批必須走完。編排層的全部工作就是在這兩者之間架一座橋——用確定性的控制流去包裹不確定性的模型調(diào)用。具體來說編排要管四件事控制流下一步做什么是繼續(xù)推理、調(diào)用工具、還是終止。這對應(yīng)循環(huán)、分支、并行、條件跳轉(zhuǎn)。數(shù)據(jù)流上一步的輸出怎么傳給下一步哪些進上下文、哪些落盤、哪些丟棄。這對應(yīng)狀態(tài)管理和上下文工程。錯誤流某一步失敗了怎么辦是重試、降級、換路徑、還是上報人工。這對應(yīng)容錯策略。資源流Token預(yù)算、時間預(yù)算、工具調(diào)用次數(shù)、并發(fā)額度怎么分配。這對應(yīng)成本與限流控制。把這四件事想清楚你的編排設(shè)計就成型了一半。剩下的才是選框架、寫代碼。2.2 三種主流編排范式的取舍目前工程上主流的編排范式大致三類各有明確的適用邊界選錯了會非常痛苦。范式核心機制優(yōu)勢代價適用場景固定流程編排預(yù)定義DAG/狀態(tài)機可控、可測、可審計靈活性差流程穩(wěn)定的業(yè)務(wù)自動化自主循環(huán)編排ReAct式思考-行動循環(huán)靈活、能處理開放任務(wù)易跑偏、成本不可控探索型、研究型任務(wù)混合編排外層流程內(nèi)層自主兼顧可控與靈活設(shè)計復(fù)雜度高生產(chǎn)級Agent系統(tǒng)我個人的經(jīng)驗是生產(chǎn)環(huán)境里純自主循環(huán)幾乎不可用。原因很簡單你沒法給一個完全自主的循環(huán)做SLA承諾。它可能三步搞定也可能三十步還在繞圈成本和延遲都不可預(yù)測。真正能上線的基本都是混合編排——外層用狀態(tài)機框住關(guān)鍵節(jié)點內(nèi)層在單個節(jié)點里允許模型自主決策。舉個具體例子。一個“合同審核Agent”外層流程是確定的讀取合同→提取條款→比對規(guī)則庫→生成風(fēng)險報告→人工復(fù)核。這五步用狀態(tài)機固定死。但“提取條款”這一步內(nèi)部模型可以自主決定先看哪部分、要不要調(diào)用OCR、要不要二次確認。這樣既保證了流程可控又保留了處理復(fù)雜文檔的靈活性。2.3 狀態(tài)機為什么比“鏈式調(diào)用”更適合生產(chǎn)早期大家喜歡用LangChain那種鏈式Chain結(jié)構(gòu)A的輸出喂給BB的輸出喂給C。簡單任務(wù)沒問題但一旦涉及分支和回退就露餡了。鏈式結(jié)構(gòu)的致命傷是沒有全局狀態(tài)。每一步只能看到上一步的輸出看不到整個任務(wù)的進展。當Agent需要“回到第三步重新做”時鏈式結(jié)構(gòu)根本表達不了這個語義。而狀態(tài)機天然支持當前處于哪個狀態(tài)、可以從哪些狀態(tài)跳轉(zhuǎn)過來、失敗后回到哪個檢查點。更關(guān)鍵的是狀態(tài)機讓可觀測性成為可能。你可以清楚地知道Agent現(xiàn)在卡在哪個狀態(tài)、這個狀態(tài)已經(jīng)停留了多久、歷史上走過哪些路徑。這些信息在排查問題時價值巨大。鏈式結(jié)構(gòu)下你只能看到一串日志根本不知道整體進度。所以我的建議很直接只要你的Agent任務(wù)超過三步且可能失敗重試就上狀態(tài)機。別圖省事用鏈式后面重構(gòu)的成本遠高于一開始就設(shè)計好。3. Runtime的六大核心模塊拆解一個能扛住生產(chǎn)流量的Agent Runtime我傾向于拆成六個模塊。這不是標準答案但經(jīng)過幾個項目驗證這個劃分的邊界比較清晰模塊間耦合低便于獨立演進。3.1 調(diào)度器Agent的大腦皮層調(diào)度器負責(zé)決定“下一步執(zhí)行什么”。它接收當前狀態(tài)和模型輸出輸出下一個動作指令。聽起來簡單但這里藏著幾個關(guān)鍵設(shè)計決策。第一個決策是調(diào)度邏輯放模型里還是放代碼里。放模型里就是讓模型輸出“下一步調(diào)用XX工具”放代碼里就是用規(guī)則判斷。我的做法是關(guān)鍵路徑用代碼邊緣路徑用模型。比如“必須調(diào)用支付接口”這種硬性步驟用代碼強制而“要不要先查一下用戶歷史”這種軟性判斷交給模型。第二個決策是單步還是批量。有些Runtime允許模型一次輸出多個動作并行執(zhí)行這能提速但會帶來狀態(tài)沖突。我的經(jīng)驗是只讀操作可以并行寫操作必須串行。查詢類工具并行調(diào)用沒問題但涉及狀態(tài)變更的必須排隊否則會出現(xiàn)競態(tài)。調(diào)度器還需要一個步數(shù)上限保護。我一般設(shè)成任務(wù)預(yù)期步數(shù)的3倍。比如一個任務(wù)正常5步完成上限設(shè)15步。超過就強制終止并上報避免Agent陷入死循環(huán)燒錢。3.2 上下文管理器最容易被低估的模塊如果說調(diào)度器是大腦上下文管理器就是記憶系統(tǒng)而且是最容易出問題的那個。我見過太多Agent跑著跑著就“失憶”或者“精神分裂”根子都在這里。上下文管理的核心矛盾是模型需要足夠的信息做決策但上下文窗口有限塞太多反而降低效果。這不是簡單的截斷問題而是信息優(yōu)先級排序問題。我的做法是分層管理系統(tǒng)層角色定義、核心規(guī)則、工具清單。這部分永遠保留不參與裁剪。任務(wù)層當前任務(wù)目標、關(guān)鍵約束、已完成步驟摘要。用滾動摘要維護保留最近N步的詳細內(nèi)容更早的壓縮成一句話。臨時層工具返回的原始數(shù)據(jù)、中間結(jié)果。這部分最容易膨脹我的策略是用完即棄只保留結(jié)論。比如查數(shù)據(jù)庫返回100行上下文里只留“查到3條符合條件的記錄ID分別是...”原始數(shù)據(jù)落盤備查。這里有個反直覺的經(jīng)驗上下文不是越長越好。實測下來當上下文超過窗口的60%時模型的指令遵循能力會明顯下降容易忽略系統(tǒng)提示里的關(guān)鍵約束。所以我會主動控制上下文水位寧可多輪摘要也不讓窗口塞滿。3.3 工具網(wǎng)關(guān)Agent的手腳和安全閥工具調(diào)用是Agent和外部世界交互的唯一通道也是風(fēng)險最集中的地方。工具網(wǎng)關(guān)要解決三個問題怎么調(diào)、調(diào)得對不對、調(diào)出問題怎么辦。“怎么調(diào)”是協(xié)議問題?,F(xiàn)在主流是用JSON Schema描述工具模型輸出結(jié)構(gòu)化參數(shù)。但這里有個坑模型輸出的參數(shù)經(jīng)常不符合Schema比如該傳數(shù)字傳了字符串、該傳數(shù)組傳了單個值。網(wǎng)關(guān)必須做參數(shù)校驗和類型轉(zhuǎn)換不能直接透傳給下游?!罢{(diào)得對不對”是權(quán)限問題。不是所有工具在任何狀態(tài)下都能調(diào)。比如“刪除數(shù)據(jù)”這種危險操作必須要求前置狀態(tài)是“已確認”。網(wǎng)關(guān)要維護一張狀態(tài)-工具權(quán)限矩陣在調(diào)用前做檢查?!罢{(diào)出問題怎么辦”是容錯問題。工具調(diào)用失敗分三類可重試的網(wǎng)絡(luò)超時、不可重試的參數(shù)錯誤、需要降級的依賴服務(wù)掛了。網(wǎng)關(guān)要根據(jù)錯誤類型走不同策略。我的默認配置是網(wǎng)絡(luò)類錯誤重試2次間隔指數(shù)退避參數(shù)類錯誤直接把錯誤信息回灌給模型讓它修正依賴類錯誤觸發(fā)降級路徑。提示工具網(wǎng)關(guān)一定要做調(diào)用審計。每次調(diào)用記錄誰調(diào)的、什么參數(shù)、返回什么、耗時多少。出問題時這是唯一的真相來源。3.4 記憶系統(tǒng)短期、長期與工作記憶記憶系統(tǒng)經(jīng)常和上下文管理器混為一談但它們是兩個層次的東西。上下文管理器管的是“當前這次推理能看到什么”記憶系統(tǒng)管的是“跨任務(wù)、跨會話能記住什么”。我把它分成三類工作記憶當前任務(wù)內(nèi)的臨時狀態(tài)任務(wù)結(jié)束即銷毀。存在內(nèi)存里追求快。短期記憶最近幾次會話的摘要用于保持對話連貫。存Redis之類的高速存儲帶TTL。長期記憶用戶偏好、歷史決策、領(lǐng)域知識。存向量庫或關(guān)系庫需要檢索。這里的關(guān)鍵設(shè)計是寫入策略。不是所有信息都值得記。我的原則是只記結(jié)論和偏好不記過程。比如“用戶偏好簡潔回復(fù)”值得記“用戶第三次問天氣”不值得記。寫入前讓模型做一次“是否值得記憶”的判斷能大幅降低記憶庫的噪音。檢索策略同樣重要。長期記憶檢索不能只靠向量相似度還要結(jié)合時間衰減和重要性權(quán)重。一個三個月前的偏好權(quán)重應(yīng)該低于昨天的。我一般用score 相似度 * 0.7 時間衰減 * 0.2 重要性 * 0.1這樣的加權(quán)公式具體系數(shù)根據(jù)業(yè)務(wù)調(diào)。3.5 可觀測性沒有它等于閉眼開車Agent的可觀測性和傳統(tǒng)服務(wù)完全不同。傳統(tǒng)服務(wù)你看QPS、延遲、錯誤率就夠了Agent你得看推理鏈路每一步的輸入輸出、工具調(diào)用序列、Token消耗、決策依據(jù)。我要求所有Agent項目必須埋三類數(shù)據(jù)Trace完整的執(zhí)行鏈路每個span對應(yīng)一個步驟包含輸入輸出和耗時。這是排查問題的骨架。Metric聚合指標比如平均步數(shù)、工具調(diào)用成功率、Token消耗分布、任務(wù)完成率。這是監(jiān)控告警的依據(jù)。Log詳細日志包括模型的原始輸出、工具的原始返回。這是深度排查的素材。特別強調(diào)一點模型的原始輸出一定要存。很多人只存解析后的結(jié)構(gòu)化結(jié)果出問題時根本不知道模型到底說了什么。我吃過這個虧后來強制要求原始輸出落盤保留至少7天。3.6 安全與護欄最后一道防線Agent能自主調(diào)用工具就意味著它能自主造成破壞。護欄模塊負責(zé)在關(guān)鍵時刻踩剎車。護欄分三層輸入護欄用戶輸入進來先過一遍攔截明顯惡意的指令。過程護欄每一步執(zhí)行前檢查比如“這個工具在當前狀態(tài)允許調(diào)用嗎”“參數(shù)在合理范圍內(nèi)嗎”。輸出護欄結(jié)果返回給用戶前檢查比如“有沒有泄露敏感信息”“格式是否符合要求”。過程護欄里最實用的是預(yù)算護欄。給每個任務(wù)設(shè)Token預(yù)算、時間預(yù)算、工具調(diào)用次數(shù)預(yù)算任一超限就終止。這個簡單機制能攔住絕大多數(shù)失控的Agent。我一般設(shè)Token預(yù)算按任務(wù)復(fù)雜度給時間預(yù)算5分鐘工具調(diào)用上限20次。4. 從零搭一個最小可用Runtime的實操路徑理論講完了這部分講怎么落地。我不會給一個完整的代碼倉庫而是給出關(guān)鍵模塊的實現(xiàn)思路和參數(shù)設(shè)計你可以對照自己的技術(shù)棧實現(xiàn)。4.1 狀態(tài)定義與持久化設(shè)計第一步是定義狀態(tài)結(jié)構(gòu)。一個Agent任務(wù)的狀態(tài)至少包含class AgentState: task_id: str status: str # pending/running/waiting_human/completed/failed current_step: str # 當前狀態(tài)機節(jié)點 step_history: list # 走過的路徑 context: dict # 上下文數(shù)據(jù) budget: dict # 剩余預(yù)算 created_at: float updated_at: float持久化選型上我的建議是開發(fā)期用SQLite生產(chǎn)期用PostgreSQL。別一上來就上復(fù)雜的分布式存儲狀態(tài)數(shù)據(jù)量沒那么大關(guān)系庫完全夠用而且事務(wù)支持好狀態(tài)更新不會丟。關(guān)鍵設(shè)計是狀態(tài)快照。每完成一個步驟就存一次快照這樣失敗后可以從最近的快照恢復(fù)不用從頭跑??煺疹l率別太高否則寫放大嚴重也別太低否則恢復(fù)代價大。我的經(jīng)驗是每個狀態(tài)轉(zhuǎn)換存一次這個粒度剛好。4.2 調(diào)度循環(huán)的骨架實現(xiàn)調(diào)度循環(huán)是整個Runtime的心臟骨架大概長這樣def run_agent(state): while state.status running: if check_budget(state) is False: state.status failed break # 1. 構(gòu)建上下文 context build_context(state) # 2. 調(diào)用模型 response call_model(context) # 3. 解析動作 action parse_action(response) # 4. 護欄檢查 if not guard_check(action, state): state.context[last_error] guard rejected continue # 5. 執(zhí)行動作 result execute_action(action, state) # 6. 更新狀態(tài) state update_state(state, action, result) save_snapshot(state) return state這個骨架看著簡單但每一步都有講究。比如第2步調(diào)用模型要處理超時和重試第3步解析動作要處理格式錯誤第5步執(zhí)行動作要處理工具異常。這些細節(jié)決定了Runtime的健壯性。4.3 工具注冊與參數(shù)校驗的落地工具注冊我推薦用裝飾器模式把Schema定義和實現(xiàn)綁在一起tool( namequery_order, description根據(jù)訂單號查詢訂單狀態(tài), params{ order_id: {type: string, required: True}, fields: {type: array, items: string, default: []} } ) def query_order(order_id, fieldsNone): # 實現(xiàn) pass參數(shù)校驗用JSON Schema庫自動做別手寫if-else。校驗失敗時把具體的錯誤信息哪個字段、期望什么類型、實際什么類型回灌給模型讓它重新生成。實測這樣比直接報錯讓模型重試的成功率高很多。這里有個細節(jié)參數(shù)默認值要顯式聲明。模型經(jīng)常漏傳可選參數(shù)如果你在Schema里寫了default校驗層能自動補上省一輪交互。4.4 上下文壓縮的具體策略上下文壓縮是門手藝。我的策略是分級壓縮最近3步完整保留包括工具返回的原始數(shù)據(jù)。4到10步保留動作和結(jié)論工具原始數(shù)據(jù)替換成摘要。10步以上只保留一句話總結(jié)比如“已完成訂單查詢和庫存校驗”。壓縮用模型做但要用一個專門的壓縮提示詞明確要求“保留關(guān)鍵實體和數(shù)值丟棄過程性描述”。壓縮后的Token數(shù)控制在原來的20%以內(nèi)。注意壓縮會丟信息所以關(guān)鍵數(shù)值必須單獨存一份結(jié)構(gòu)化數(shù)據(jù)不能只存在上下文里。比如訂單號、金額這些壓縮時可能被模型“概括”掉但后續(xù)步驟還要用。我的做法是維護一個key_facts字典專門存這類硬信息不參與壓縮。4.5 錯誤恢復(fù)與重試的工程細節(jié)錯誤恢復(fù)的核心是分類處理。我一般把錯誤分成四類錯誤類型典型場景處理策略瞬時錯誤網(wǎng)絡(luò)抖動、限流指數(shù)退避重試最多3次參數(shù)錯誤Schema校驗失敗錯誤回灌模型重新生成邏輯錯誤工具返回業(yè)務(wù)異常觸發(fā)降級路徑或上報系統(tǒng)錯誤依賴服務(wù)宕機熔斷轉(zhuǎn)人工重試要設(shè)總預(yù)算不能無限重試。我的配置是單個工具調(diào)用最多重試3次整個任務(wù)的重試總次數(shù)不超過10次。超過就判定任務(wù)失敗。還有個容易忽略的點重試要冪等。如果工具調(diào)用有副作用比如發(fā)消息、扣款重試前必須確認上一次是否真的失敗了。我的做法是給每個寫操作帶一個冪等鍵下游根據(jù)冪等鍵去重。5. 生產(chǎn)環(huán)境踩過的坑與排查手冊這部分是全文最值錢的部分。下面這些坑每一個都是我或身邊同行真實踩過的文檔里基本不會寫。5.1 上下文污染Agent為什么會“精神分裂”現(xiàn)象Agent跑到第8步突然開始重復(fù)第3步的操作或者引用了根本不存在的“之前查到的數(shù)據(jù)”。根因上下文里混入了過期的中間結(jié)果。比如第3步查到的庫存是100第6步庫存已經(jīng)變成50了但上下文里還留著100模型基于舊數(shù)據(jù)做決策。排查方法把每一步的上下文快照打出來對比模型實際看到的內(nèi)容和它引用的內(nèi)容。如果發(fā)現(xiàn)它引用了不該存在的數(shù)據(jù)就是污染。解決給上下文數(shù)據(jù)打時間戳和版本號。同一類數(shù)據(jù)只保留最新版本舊版本主動清理。工具返回數(shù)據(jù)時帶上as_of時間模型決策時優(yōu)先用最新的。5.2 工具幻覺模型編造不存在的工具和參數(shù)現(xiàn)象模型調(diào)用了一個你沒注冊的工具或者給工具傳了一個Schema里沒有的參數(shù)。根因工具描述寫得不夠清晰或者工具數(shù)量太多導(dǎo)致模型混淆。排查看Trace里模型輸出的原始動作對比注冊的工具清單。解決三個措施。第一工具描述要寫清楚“什么時候用”和“什么時候不用”光寫功能不夠。第二工具數(shù)量控制在15個以內(nèi)超過就分組用兩級選擇。第三在系統(tǒng)提示里明確列出可用工具名并強調(diào)“只能調(diào)用列表中的工具”。5.3 死循環(huán)Agent在兩步之間反復(fù)橫跳現(xiàn)象Agent在“查詢→發(fā)現(xiàn)數(shù)據(jù)不對→重新查詢”之間無限循環(huán)。根因沒有進展檢測機制。Agent不知道自己在原地打轉(zhuǎn)。排查看step_history如果發(fā)現(xiàn)最近5步的動作模式高度重復(fù)就是死循環(huán)。解決加一個狀態(tài)指紋機制。每步計算一個指紋動作類型關(guān)鍵參數(shù)如果連續(xù)3步指紋相同強制中斷并上報。另外給每個狀態(tài)設(shè)最大停留次數(shù)比如“查詢狀態(tài)”最多進入3次超過就換路徑。5.4 并發(fā)下的狀態(tài)串擾現(xiàn)象兩個用戶同時用AgentA的結(jié)果串到了B的會話里。根因狀態(tài)沒有按會話隔離或者用了全局變量。排查檢查狀態(tài)存儲的key是否包含會話ID檢查有沒有共享的可變對象。解決所有狀態(tài)必須帶會話ID作為命名空間。存儲key用{session_id}:{task_id}格式。代碼里禁止使用模塊級可變變量所有狀態(tài)通過參數(shù)傳遞。這個坑一旦踩了排查起來極其痛苦因為它是概率性的本地測試根本復(fù)現(xiàn)不了。5.5 Token消耗失控的排查思路現(xiàn)象賬單突然暴漲或者單個任務(wù)消耗了幾十萬Token。排查順序先看單步Token分布找出消耗最大的步驟。通常是工具返回數(shù)據(jù)太長或者上下文沒壓縮。再看步數(shù)分布找出異常長的任務(wù)。通常是死循環(huán)或反復(fù)重試。最后看并發(fā)數(shù)確認是不是流量突增。解決設(shè)硬預(yù)算單任務(wù)Token上限、單用戶日Token上限。超限直接拒絕別心軟。另外工具返回數(shù)據(jù)在進上下文前先做一次長度截斷超過2000字符的只保留摘要。5.6 常見問題速查表癥狀可能原因快速驗證處理重復(fù)執(zhí)行同一步狀態(tài)未更新/死循環(huán)看step_history加狀態(tài)指紋檢測引用錯誤數(shù)據(jù)上下文污染對比上下文快照數(shù)據(jù)加版本號調(diào)用不存在的工具工具描述不清看原始輸出精簡工具列表任務(wù)卡住不動工具超時無處理看工具調(diào)用耗時加超時和重試結(jié)果串會話狀態(tài)未隔離檢查存儲key加會話命名空間Token暴漲上下文膨脹看單步Token加壓縮和預(yù)算6. 編排框架選型自研還是用現(xiàn)成的6.1 現(xiàn)成框架的能力邊界市面上主流的Agent框架能力大致分三檔基礎(chǔ)檔提供工具調(diào)用和簡單循環(huán)適合做Demo。這類框架的問題是缺乏狀態(tài)管理和錯誤恢復(fù)上生產(chǎn)要自己補很多。中間檔提供狀態(tài)機、持久化、可觀測性能支撐中等復(fù)雜度應(yīng)用。選這類要看它的抽象是否合理會不會限制你的定制。重型檔提供完整的編排、部署、監(jiān)控能力適合大團隊。代價是學(xué)習(xí)曲線陡且容易被框架綁定。我的判斷標準很簡單如果你的Agent邏輯能用狀態(tài)機清晰表達且不需要復(fù)雜的分布式協(xié)調(diào)中間檔框架夠用。如果邏輯高度動態(tài)、需要運行時生成流程那可能得自研調(diào)度層。6.2 什么情況下必須自研三種情況我建議自研第一業(yè)務(wù)邏輯高度定制。比如你的Agent需要和內(nèi)部十幾個系統(tǒng)深度集成每個系統(tǒng)有特殊的鑒權(quán)和數(shù)據(jù)格式用通用框架反而處處受限。第二性能要求極高。通用框架為了兼容性做了很多抽象這些抽象在高并發(fā)下會成為瓶頸。如果你的Agent要支撐每秒上千次調(diào)用自研精簡版更合適。第三需要深度可觀測。通用框架的埋點粒度可能不夠你需要精確到每次模型調(diào)用的Token分布、每個工具的P99延遲自研能完全掌控。自研不等于從零寫。我的做法是核心調(diào)度自研周邊能力用開源。比如狀態(tài)存儲用現(xiàn)成的數(shù)據(jù)庫可觀測性用OpenTelemetry只把調(diào)度循環(huán)和上下文管理自己寫。這樣既保證核心可控又不重復(fù)造輪子。6.3 混合架構(gòu)的實踐建議大多數(shù)團隊的最優(yōu)解是混合用框架搭骨架用自研補關(guān)鍵模塊。具體來說框架負責(zé)工具注冊、基礎(chǔ)循環(huán)、日志輸出這些標準化程度高的部分。自研負責(zé)上下文壓縮策略、錯誤恢復(fù)邏輯、預(yù)算控制這些和業(yè)務(wù)強相關(guān)的部分。這樣做的關(guān)鍵是定義好接口邊界??蚣芎妥匝心K之間通過明確的數(shù)據(jù)結(jié)構(gòu)通信比如狀態(tài)對象、動作對象、結(jié)果對象。接口定好了兩邊可以獨立演進將來換框架也不用重寫自研部分。7. 性能與成本優(yōu)化的實戰(zhàn)參數(shù)7.1 延遲優(yōu)化的三個杠桿Agent的延遲主要來自三塊模型推理、工具調(diào)用、狀態(tài)讀寫。優(yōu)化要分清楚瓶頸在哪。模型推理通常是大頭。優(yōu)化手段用更小的模型做簡單決策只在關(guān)鍵步驟用大模型開啟流式輸出讓用戶先看到部分結(jié)果緩存常見決策的結(jié)果。工具調(diào)用的優(yōu)化在于并行。只讀工具能并行就并行我實測過三個查詢并行能把這一步的延遲從3秒降到1.2秒。但要注意并行度別太高否則下游服務(wù)扛不住。狀態(tài)讀寫容易被忽略。如果每步都同步寫數(shù)據(jù)庫延遲會累積。我的做法是異步寫定期快照關(guān)鍵狀態(tài)同步寫非關(guān)鍵狀態(tài)異步寫。7.2 Token成本控制的硬手段Token成本是Agent規(guī)?;畲蟮臄r路虎。幾個硬手段上下文壓縮前面講過能省30%到50%的輸入Token。結(jié)果緩存相同或相似的查詢直接返回緩存省掉模型調(diào)用。模型分級簡單任務(wù)用小模型復(fù)雜任務(wù)才用大模型。我一般設(shè)一個路由規(guī)則按任務(wù)類型分流。輸出限制給模型設(shè)max_tokens別讓它無限輸出。工具調(diào)用的輸出尤其要限制很多模型喜歡在調(diào)用工具前長篇大論。實測下來這幾招組合能把單任務(wù)成本壓到原來的三分之一左右。7.3 并發(fā)與限流的配置參考并發(fā)配置沒有萬能值但有個估算方法先測單任務(wù)的P95延遲再用目標QPS反推需要的并發(fā)數(shù)。比如單任務(wù)P95是10秒目標QPS是5那至少需要50個并發(fā)槽位。限流要分層用戶級限制單用戶并發(fā)防止一個用戶占滿資源任務(wù)級限制單任務(wù)步數(shù)防止死循環(huán)系統(tǒng)級限制總并發(fā)保護下游。我的默認配置供參考單用戶并發(fā)3單任務(wù)最大步數(shù)20系統(tǒng)總并發(fā)按下游承載能力的70%設(shè)置。留30%余量應(yīng)對突發(fā)。8. 寫在最后一些不那么技術(shù)但很重要的體會做了幾個Agent項目之后我最大的體會是Agent的工程質(zhì)量80%取決于你對失敗的處理而不是對成功的處理。Demo演示的是成功路徑生產(chǎn)考驗的是失敗路徑。你的重試策略、降級方案、人工兜底這些才是決定Agent能不能上線的關(guān)鍵。另一個體會是別追求全自主。很多團隊一開始都想做一個“什么都能干”的通用Agent結(jié)果做出來什么都不精。反而是那些把邊界劃得很清楚、在特定場景里做深做透的Agent真正產(chǎn)生了價值。編排的意義不是讓Agent無所不能而是讓它在該自主的地方自主該受控的地方受控。最后一個實操建議從最簡單的狀態(tài)機開始別一上來就搞復(fù)雜架構(gòu)。我見過太多項目在架構(gòu)設(shè)計上花了兩個月結(jié)果核心業(yè)務(wù)邏輯還沒跑通。先用最樸素的方式把主流程跑通遇到具體問題再針對性加模塊。Runtime是長出來的不是設(shè)計出來的。