作中的觸達編排與治理實踐)
1. 為什么我做了 Agent-Reach多智能體協(xié)作里最容易被低估的“觸達”問題先說個真實場景。上個月我們內(nèi)部搞了一次多智能體聯(lián)調(diào)三個 Agent 分別負責(zé)查庫存、生成報價、執(zhí)行訂單。單拿出來每一個都跑得好好的結(jié)果串起來之后第一個 Agent 在對話歷史里翻到了三個月前一條已經(jīng)失效的折扣信息第二個 Agent 拿著這個信息直接算錯了價格第三個 Agent 還想當(dāng)然地調(diào)了一個已經(jīng)被下線的接口。排查到最后問題根本不在模型能力而是在 Agent 之間“怎么找到對方、怎么傳上下文、怎么控制調(diào)用邊界”這一整條鏈路。那段時間我每晚都在想同一個問題能不能把“觸達”這件事做成一種可配置、可觀測、可管控的通用能力這就是 Agent-Reach 的起點。Agent-Reach 不是一個模型也不是某個具體的 Agent 應(yīng)用而是一套面向多智能體協(xié)作場景的觸達編排方案。它要管的事情很具體當(dāng)一個 Agent 需要調(diào)用另一個 Agent 的能力時消息該走哪條路由、上下文該帶多少、能調(diào)用哪些工具、不能越過哪些邊界、失敗了怎么重試、整條調(diào)用鏈怎么追蹤。簡單說單 Agent 的能力決定它“聰明不聰明”Agent-Reach 決定一群 Agent 在一起時“找不找得到人、傳不傳得對話、控不控得住邊界”。這篇文章主要聊三部分Agent-Reach 的設(shè)計思路、核心代碼實現(xiàn)、我在實際部署和聯(lián)調(diào)中踩過的坑。適合三類人看正在搭多 Agent 平臺的架構(gòu)師、做 AI 自動化流程的開發(fā)者以及因為 Agent 互相亂調(diào)而頭疼的運維同學(xué)。如果你只是剛接觸多智能體也沒關(guān)系我會把里面的關(guān)鍵概念都用大白話拆開講。1.1 一次差點讓項目翻車的聯(lián)調(diào)事故先把這個事故完整還原一下因為它是整個 Agent-Reach 的起源。我們當(dāng)時的架構(gòu)很簡單用戶輸入先進主 AgentRouter主 Agent 根據(jù)語義把請求分發(fā)給子 Agent子 Agent 再調(diào)用各自的工具??雌饋頉]什么問題實際跑起來全是洞。第一個洞是“調(diào)用風(fēng)暴”。某個子 Agent 在處理退款請求時因為拿不到足夠的用戶信息連續(xù)向主 Agent 發(fā)起了三次回傳請求主 Agent 又把它當(dāng)成新任務(wù)重新分發(fā)結(jié)果同一筆退款在幾分鐘內(nèi)被重復(fù)處理了兩遍。第二個洞是“上下文越界”。子 Agent 之間傳消息時默認把整段對話歷史都帶上一個負責(zé)寫文案的 Agent 被塞進了大量數(shù)據(jù)庫查詢?nèi)罩据敵鲑|(zhì)量明顯下降還白白浪費了幾萬 token。第三個洞是“幽靈接口調(diào)用”。有 Agent 基于訓(xùn)練語料中的舊接口格式生成調(diào)用請求但真實環(huán)境里那個接口早就換路徑了失敗后它不報錯反而嘗試了三種參數(shù)變體把日志刷得亂七八糟。這三個洞其實指向同一個根因我們沒有對 Agent 之間的觸達行為做任何約束。每個 Agent 都像一臺可以隨意踩油門的車但沒有車道、沒有紅綠燈、沒有限速牌。Agent-Reach 要補的就是基礎(chǔ)設(shè)施這一層。1.2 Agent-Reach 到底解決什么四種“觸達”我把多智能體協(xié)作里的核心問題歸納成四種觸達Agent-Reach 的所有設(shè)計都是圍繞這四種觸達展開的。觸達類型核心問題失控時的典型表現(xiàn)路由觸達一個 Agent 怎么找到有能力處理該請求的另一個 Agent請求被錯誤轉(zhuǎn)發(fā)、重復(fù)分發(fā)、找不到處理者上下文觸達消息在傳遞時應(yīng)該攜帶哪些有效信息上下文爆炸、無效信息污染、token 超限資源觸達Agent 能調(diào)用哪些工具、接口、數(shù)據(jù)庫調(diào)用已下線接口、越權(quán)訪問、副作用不可控權(quán)限觸達不同 Agent 之間允許什么粒度的互相調(diào)用子 Agent 反向觸發(fā)高危操作、繞過審批鏈四種觸達不是平級的。資源觸達和權(quán)限觸達是底座路由觸達和上下文觸達是表現(xiàn)層。Agent-Reach 的做法是把這四類規(guī)則統(tǒng)一描述、統(tǒng)一執(zhí)行、統(tǒng)一觀測而不是像以前那樣散落在每個 Agent 的 prompt 里碰運氣。1.3 什么場景需要它什么人適合讀誠實說如果你的項目只有一個 Agent、只調(diào)幾個外部 API那 Agent-Reach 是過度設(shè)計你直接寫個工具函數(shù)就行。但一旦你的系統(tǒng)開始出現(xiàn)這些信號就該考慮它了主 Agent 的 prompt 越來越臃腫、子 Agent 之間互相調(diào)用沒有規(guī)律可循、一次用戶請求會觸發(fā)十幾跳內(nèi)部消息、出了問題只能靠翻日志猜鏈路。具體來說Agent-Reach 比較適合這幾類場景企業(yè)內(nèi)部的多 Agent 自動化中臺、客服和銷售場景的 Agent 協(xié)作流、代碼生成與執(zhí)行沙箱需要有嚴格的資源邊界、以及由多個垂直領(lǐng)域 Agent 組成的內(nèi)容生產(chǎn)系統(tǒng)。讀這篇文章的人我假設(shè)你至少有一個跑通的多 Agent demo或者正在設(shè)計這樣的系統(tǒng)不然后面代碼部分的體感會弱一些。2. Agent-Reach 的架構(gòu)設(shè)計把觸達控制做成平臺能力Agent-Reach 在設(shè)計上堅持一個原則觸達控制不應(yīng)該是每個 Agent 自己的“自覺”而應(yīng)該下沉成平臺層的強制約束。好比一個公司的跨部門協(xié)作不能指望著每個員工都主動守規(guī)矩得有統(tǒng)一的 OA 流程、權(quán)限系統(tǒng)和審計日志。所以 Agent-Reach 沒有做成 SDK 讓你在每個 Agent 里手動埋點而是做成了一個代理層所有 Agent 之間的通信都從它這里經(jīng)過。這樣做有兩個直接好處第一新接入一個 Agent 不需要改它的內(nèi)部邏輯只需要聲明它“能干什么、不能干什么”第二所有觸達行為都會留下結(jié)構(gòu)化日志排查問題的時候不用再靠猜。2.1 六個層級的分工Agent-Reach 的內(nèi)部結(jié)構(gòu)從下往上分成六層每一層只解決一種觸達問題。接入層負責(zé)把不同類型的 AgentOpenAI 接口、自研模型、純規(guī)則腳本統(tǒng)一成標準的消息格式屏蔽底層差異。編排層負責(zé)處理外部進來的用戶請求決定要不要拆分成子任務(wù)、按什么順序分發(fā)這是整個系統(tǒng)的入口。路由層根據(jù)路由表把消息送到目標 Agent路由表支持精確匹配、模糊匹配和兜底策略。觸達協(xié)議層這是 Agent-Reach 比較核心的一層。它定義了消息中允許攜帶什么元信息、上下文的裁剪規(guī)則、同步還是異步、以及超時和重試預(yù)算。策略層負責(zé)加載權(quán)限和資源邊界規(guī)則比如某個 Agent 不允許調(diào)用支付接口某些外部工具只能在特定時間段訪問??捎^測層把每一次觸達包括成功、失敗、被攔截記錄為一條 reach trace包含鏈路 ID、跳數(shù)、耗時、調(diào)用來源和目標。這么分層的好處是你想改某一個維度的規(guī)則時不用動其他層。比如要調(diào)整上下文裁剪策略只需要改觸達協(xié)議層的配置路由和權(quán)限完全不受影響。2.2 路由與覆蓋范圍白名單不是限制是安全網(wǎng)很多人剛接觸 Agent-Reach 時對“白名單路由”這個設(shè)計有點抵觸覺得把 Agent 之間的調(diào)用限制死了會影響靈活性。我的觀點恰恰相反在多智能體系統(tǒng)里自由度越高出事故的概率越大白名單看起來是限制其實是安全網(wǎng)。Agent-Reach 路由層不搞“Agent 自己決定找誰”的分布式自主調(diào)用而是統(tǒng)一維護一張路由表。路由表里有三種條目精確路由task_type 完全匹配時走指定 Agent、模糊路由用關(guān)鍵詞權(quán)重匹配比如“退款”命中客服 Agent 的概率設(shè)為 0.9、拒絕路由明確禁止某些 task_type 出現(xiàn)在某些 Agent 之間比如“刪除數(shù)據(jù)庫”這種任務(wù)禁止從低權(quán)限 Agent 轉(zhuǎn)發(fā)。我見過很多失敗的多智能體項目問題都出在“讓 Agent 自己找伙伴”。模型在開放環(huán)境下做工具選擇已經(jīng)不夠穩(wěn)定再讓它做跨 Agent 路由選擇錯誤率會疊加。所以 Agent-Reach 把路由決策從模型手里拿回來交給確定性的規(guī)則引擎。模型負責(zé)理解語義、提取參數(shù)Agent-Reach 負責(zé)決定把參數(shù)交給誰。這和微服務(wù)架構(gòu)里的 API 網(wǎng)關(guān)是一個道理如果每個服務(wù)都自己去服務(wù)發(fā)現(xiàn)、自己決定調(diào)用誰那系統(tǒng)離雪崩就不遠了。2.3 觸達半徑上下文不是傳得越多越好上下文觸達是 Agent-Reach 里我個人認為最有價值的設(shè)計。大多數(shù)多智能體系統(tǒng)傳上下文的方式是“整段復(fù)制”A 把用戶原始輸入 自己的思考 工具返回結(jié)果 歷史消息全部塞給 B。結(jié)果就是 B 收到的信息里至少有一半是噪聲模型要在噪聲里找關(guān)鍵信息既慢又容易出錯。Agent-Reach 引入了一個叫“觸達半徑”的概念。每個 Agent 在注冊時聲明自己的上下文偏好處理這個類型的任務(wù)最多需要多少 token、需要什么類型的上下文用戶摘要、工具返回、歷史決策、哪些信息明確不需要。當(dāng) A 要向 B 傳消息時觸達協(xié)議層會根據(jù) B 的偏好對上下文做一次裁剪和摘要而不是直接轉(zhuǎn)發(fā)原文。我舉一個具體例子。用戶要求“把上周的銷售數(shù)據(jù)整理成周報并發(fā)送給管理層”主 Agent 手里有整整 5 萬 token 的原始數(shù)據(jù)。如果直接傳給寫周報的 Agent成本高不說模型還容易抓錯重點。Agent-Reach 的做法是先讓一個輕量的聚合組件把數(shù)據(jù)加工成“核心結(jié)論 關(guān)鍵圖表 異常標注”再把這份摘要傳給寫周報的 Agenttoken 直接降到 3000質(zhì)量反而更穩(wěn)定。后續(xù)第四節(jié)我會給出具體的實現(xiàn)代碼。3. 核心代碼實現(xiàn)路由策略、退避重試與上下文裁剪理論講得再多不如直接看代碼。Agent-Reach 的核心實現(xiàn)不算復(fù)雜它的聰明之處在于把策略與執(zhí)行分離。我用 Python 寫了最小的可運行版本大家可以直接照著搭。3.1 路由策略配置用 DSL 表達觸達規(guī)則Agent-Reach 使用 YAML 作為策略描述語言原因很簡單可讀性好非技術(shù)人員也能維護。下面是系統(tǒng)里一份典型的配置routes: - name: refund_flow match: type: keyword_weight keywords: [退款, 退貨, refund] min_score: 0.6 target: agent:refund_service fallback: agent:human_handoff allowed_hops: 3 - name: report_flow match: type: exact task_type: generate_weekly_report target: agent:report_writer required_context: template: summary max_tokens: 4096 include_fields: [conclusion, key_metrics, anomalies] reach_policy: default_timeout_ms: 5000 retry_budget: 3 backoff_base_ms: 200 max_parallel_calls: 8 blocklist: - from: agent:report_writer to: agent:payment_executor reason: 寫周報的 Agent 不允許觸發(fā)支付操作路由配置里有個關(guān)鍵的allowed_hops字段這是防循環(huán)觸達的核心。每次消息經(jīng)過一個 Agent跳數(shù)就加一超過上限直接丟棄并告警。required_context則聲明了上下文觸達的要求目標 Agent 不需要原始數(shù)據(jù)只需要summary模板、最多 4096 token、只要結(jié)論和異常字段。這部分的設(shè)計思路是把“該找誰”和“該帶什么”都變成可聲明的配置而不是寫死在代碼里。這樣即便系統(tǒng)里有幾十個 Agent運維同學(xué)也能在開會時打開 YAML 直接討論某個流程該不該加白名單而不是去翻代碼。3.2 路由執(zhí)行器匹配、轉(zhuǎn)發(fā)與退避重試配置是靜態(tài)的真正干活的是路由執(zhí)行器。核心代碼如下import asyncio import random import yaml from dataclasses import dataclass from typing import Any, Optional dataclass class ReachContext: trace_id: str source: str target: str hops: int payload: dict policy: dict class ReachRouter: def __init__(self, config_path: str): with open(config_path, r, encodingutf-8) as f: self.config yaml.safe_load(f) self.routes {r[name]: r for r in self.config[routes]} self.policy self.config[reach_policy] def match_route(self, task_type: str, keywords: list[str]) - Optional[dict]: for route in self.routes.values(): matcher route[match] if matcher[type] exact: if task_type matcher[task_type]: return route elif matcher[type] keyword_weight: score sum(1 for kw in matcher[keywords] if kw in keywords) score score / len(matcher[keywords]) if score matcher.get(min_score, 0.5): return route return None async def forward(self, ctx: ReachContext, agent_client: Any) - dict: if ctx.hops ctx.policy[max_hops]: raise RuntimeError(freach hops exceeded: {ctx.trace_id}) max_retry ctx.policy[retry_budget] base_backoff ctx.policy[backoff_base_ms] for attempt in range(max_retry 1): try: result await agent_client.invoke(ctx.payload) ctx.payload[result] result return ctx.payload except Exception as e: if attempt max_retry: raise delay base_backoff * (2 ** attempt) random.uniform(0, 50) await asyncio.sleep(delay / 1000) return {}這里有兩個值得說明的設(shè)計點。第一重試不是無限重試retry_budget等于 3 時總共最多嘗試 4 次而且退避時間按指數(shù)增長200ms、400ms、800ms 再加一點隨機抖動。隨機抖動是為了避免多個 Agent 同時失敗后在同一個時間點集體重試把系統(tǒng)打出一個新的峰值。第二重試只覆蓋“調(diào)用 Agent 過程”的異常如果上一次調(diào)用已經(jīng)成功執(zhí)行但響應(yīng)丟失重試可能會造成重復(fù)操作。這個問題我在第五節(jié)會專門講怎么用冪等鍵處理。3.3 上下文裁剪器按觸達半徑壓縮信息再來看上下文裁剪器的實現(xiàn)。很多剛接觸 Agent-Reach 的讀者想當(dāng)然地以為“裁剪就是把文本截斷”其實不是最有效的裁剪是按照接收方 Agent 的偏好做結(jié)構(gòu)化抽取。class ContextTrimmer: def __init__(self, token_estimatorNone): if token_estimator is None: self.token_estimator lambda text: len(text) // 3 else: self.token_estimator token_estimator def trim(self, raw_context: dict, route: dict) - dict: required route.get(required_context, {}) template required.get(template, full) max_tokens required.get(max_tokens, 4096) include_fields required.get(include_fields, []) if template summary: # 只提取關(guān)鍵字段priority 字段在前 trimmed {} for field in include_fields: if field in raw_context: trimmed[field] raw_context[field] # 如果還是超出預(yù)算則對最長的字段做遞歸摘要 while self._estimate_tokens(trimmed) max_tokens: longest_key max(trimmed, keylambda k: self._estimate_tokens(trimmed[k])) trimmed[longest_key] self._summarize(trimmed[longest_key]) trimmed[_trim_note] auto-trimmed by Agent-Reach return trimmed # full 模板原樣傳出但會記錄警告 if self._estimate_tokens(raw_context) max_tokens: return { **raw_context, _trim_warning: fcontext exceeds {max_tokens} tokens, } return raw_context def _estimate_tokens(self, data): if isinstance(data, str): return self.token_estimator(data) return sum(self._estimate_tokens(v) for v in data.values()) def _summarize(self, text: str) - str: # 生產(chǎn)環(huán)境可以接 LLM 或抽取式摘要 if len(text) 500: return text return text[:500] ...[truncated by Agent-Reach]_summarize里我故意留了簡化的截斷邏輯實際生產(chǎn)環(huán)境可以替換成 LLM 摘要調(diào)用。不過要注意摘要本身也是有成本的如果每一次消息傳遞都調(diào)一次 LLM 做摘要整體延遲和費用都會上去。建議的做法是對高頻觸達的 Agent預(yù)先把原始數(shù)據(jù)處理成多級摘要緩存按需取用不同精度的版本。3.4 可觀測性reach trace 怎么記才有效最后是觸達鏈路的可觀測性。Agent-Reach 里每一條消息都會生成一個結(jié)構(gòu)化的 trace 日志字段如下{ reach_trace_id: rt_8f2a91c, source_agent: main_router, target_agent: refund_service, route_name: refund_flow, hops: 2, context_tokens_before: 48200, context_tokens_after: 3800, decision: allowed, duration_ms: 1240, retry_count: 1 }這個日志的價值在于它能直接回答“一個問題卡在哪一跳”。比如你看到duration_ms在某條路由上突然飆升同時retry_count從 0 變成 3基本可以斷定目標 Agent 出現(xiàn)了性能問題。又比如context_tokens_before和after的差距很小說明觸達協(xié)議層沒有正確裁剪需要檢查路由配置里的required_context是否被目標 Agent 正確聲明。4. 從零到一一次完整的 Agent-Reach 聯(lián)調(diào)實錄理論代碼都有了接下來走一遍實際聯(lián)調(diào)過程。我盡量按真實操作的順序來包括配置、啟動、壓測、調(diào)參方便你照著復(fù)現(xiàn)。4.1 最小拓撲與角色劃分這次聯(lián)調(diào)我用了三個 Agent 組成的最小系統(tǒng)場景是“用戶申請退款系統(tǒng)判斷是否符合政策符合則退款不符合則轉(zhuǎn)人工”。main_router主路由 Agent接收用戶輸入負責(zé)語義識別與任務(wù)分發(fā)。refund_checker退款校驗 Agent查詢訂單狀態(tài)、退款政策輸出是否可退以及退款金額。payment_executor支付執(zhí)行 Agent負責(zé)實際發(fā)起退款轉(zhuǎn)賬屬于高風(fēng)險 Agent必須嚴格保護。按照第五節(jié)的權(quán)限原則payment_executor只允許被refund_checker在特定條件下調(diào)用主路由不能直接觸達它。這個限制寫在路由配置里即便模型胡說八道想跨級調(diào)用Agent-Reach 也會在策略層攔下來。4.2 完整配置與啟動流程routes: - name: parse_refund_request match: type: keyword_weight keywords: [退款, 退錢, refund] min_score: 0.7 target: agent:refund_checker allowed_hops: 3 - name: execute_refund match: type: exact task_type: refund_approved target: agent:payment_executor allowed_hops: 2 # 必須具備 refund_checker 的簽名才允許執(zhí)行 required_claims: - role: refund_checker action: approve_refund reach_policy: max_hops: 5 default_timeout_ms: 3000 retry_budget: 2 backoff_base_ms: 150 blocklist: - from: agent:main_router to: agent:payment_executor reason: 主路由不允許直接觸達支付執(zhí)行器啟動流程很簡單先啟動三個 Agent 服務(wù)再啟動 Agent-Reach 代理層然后把三個 Agent 的注冊信息名稱、能力描述、上下文偏好、回調(diào)地址寫進 Agent-Reach 的服務(wù)目錄。聯(lián)調(diào)時所有的消息都不直接走 Agent 之間的點對點連接而是統(tǒng)一發(fā)給 Agent-Reach 的入口由它做路由分發(fā)。這樣一個小時后整個系統(tǒng)的觸達路徑就全部處于可觀測狀態(tài)了。4.3 壓測與參數(shù)調(diào)整記錄我做了兩輪壓測第一輪用默認參數(shù)第二輪根據(jù)結(jié)果調(diào)參。測試場景是模擬 1000 個退款請求觀察三類指標正確路由率、平均端到端耗時、越權(quán)攔截次數(shù)。參數(shù)版本正確路由率P95 耗時被攔截的越權(quán)調(diào)用上下文裁剪后平均 token默認超時 5s重試 392.4%4120ms374200調(diào)參后超時 3s重試 297.8%1860ms413850第一輪正確路由率不高的原因很有代表性refund_checker在處理部分請求時響應(yīng)超過了 3 秒觸發(fā)了重試但重試后的重復(fù)請求又把隊列堵住形成連鎖延遲。把超時從 5 秒降到 3 秒、重試預(yù)算從 3 降到 2 之后反而因為系統(tǒng)更早地放棄了“慢請求”整體吞吐反而上去了。越權(quán)攔截次數(shù)從 37 升到 41看起來變差了其實不是。調(diào)參前主路由有更多機會直接觸達支付執(zhí)行器部分請求因為路由混亂在早期就失敗了壓根輪不到策略層攔截。調(diào)參后路由更準確真正到達支付環(huán)節(jié)的請求更多被攔截的絕對次數(shù)自然上升。這里要看的指標是“攔截率”實際上從 3.7% 降到了 4.1% 的假象背后高風(fēng)險操作總數(shù)從 1000 次降至 980 次攔截率實際是上升的。所以排查問題時一定要結(jié)合總量看比例不能只看絕對值。5. 線上踩過的坑常見問題與排查技巧說到底Agent-Reach 不是裝了就能一勞永逸。上線兩個月我這邊遇到過不少奇怪的問題挑幾個典型的說說順帶整理成速查表方便你遇到同類問題時快速定位。5.1 Agent 循環(huán)調(diào)用與幽靈消息這是多 Agent 系統(tǒng)里最經(jīng)典的事故?,F(xiàn)象是某條消息在幾個 Agent 之間來回傳遞日志里全是“轉(zhuǎn)發(fā)成功”但沒有任何一個 Agent 真正在做有效輸出直到allowed_hops耗盡才被攔截。我遇到的具體場景是主路由把一個退款請求轉(zhuǎn)給refund_checkerrefund_checker覺得信息不足把消息回傳給主路由補充請求主路由又沒有把消息標記為“來自子 Agent 的回傳”而是當(dāng)成全新任務(wù)重新分發(fā)于是又轉(zhuǎn)回refund_checker形成死循環(huán)。解決辦法有兩層第一層是嚴格規(guī)范消息類型回傳消息必須帶parent_trace_id和callback_typerequest_more_info路由層遇到這類消息只做信息合并不再走分發(fā)邏輯第二層是保留allowed_hops限制讓系統(tǒng)在失控時能夠兜底熔斷。5.2 上下文越過觸達半徑模型開始“拼接幻覺”有一次我發(fā)現(xiàn)負責(zé)生成日報的 Agent 在輸出里混進了一條不該出現(xiàn)的舊訂單數(shù)據(jù)。追查 trace 后發(fā)現(xiàn)主路由把整段用戶對話歷史原樣傳給了日報 Agent其中包含三個月前的一次訂單查詢記錄日報 Agent 把這個歷史信息當(dāng)成了本周數(shù)據(jù)直接寫進了總結(jié)。這不是模型的問題是上下文觸達失控。解決方式是嚴格執(zhí)行required_context模板并且在模板里聲明include_fields白名單沒有出現(xiàn)在白名單里的字段一律丟棄。同時建議在消息里加一個_trim_note標記我在代碼里就是這么做的讓下游 Agent 知道自己收到的是裁剪后的摘要而不是完整原始數(shù)據(jù)。這個標記雖然不起眼但能顯著減少模型把摘要當(dāng)成完整數(shù)據(jù)的概率。5.3 權(quán)限邊界失效的三種典型路徑第一種是配置覆蓋。后加的路由規(guī)則把payment_executor的required_claims漏掉了等于開了個后門。我的建議是每次配置變更都跑一遍靜態(tài)校驗?zāi)_本檢查每個高風(fēng)險 Agent 是否仍然有完整的權(quán)限聲明。第二種是錯誤地在 Agent 的 prompt 里寫“你可以調(diào)用任何工具”模型在生成函數(shù)調(diào)用時繞過了 Agent-Reach 的 API直接直連底層 HTTP 接口。這個問題得靠網(wǎng)絡(luò)層封禁解決Agent-Reach 的策略層管不到繞過它的流量。第三種是回傳消息里攜帶了額外的工具調(diào)用意圖目標 Agent 在解析時把這個意圖當(dāng)成用戶指令執(zhí)行了。解決方案是解析消息時只能讀取payload里白名單字段其他字段一律忽略。5.4 排查工具箱一頁紙速查表癥狀可能原因排查步驟修復(fù)方案請求在多個 Agent 之間反復(fù)橫跳回傳消息被當(dāng)成新任務(wù)分發(fā)查 reach trace 的 hops 和 route_name規(guī)范 callback_type分發(fā)表里增加回傳攔截下游 Agent 輸出包含無關(guān)歷史信息上下文未按模板裁剪對比 context_tokens_before 和 after配置 required_context 白名單某條路由耗時突然變長目標 Agent 響應(yīng)慢觸發(fā)多次重試看 retry_count 與 duration_ms縮短超時時間降低重試預(yù)算高風(fēng)險 Agent 被異常調(diào)用配置缺失或直連繞過查攔截日志和網(wǎng)絡(luò)訪問日志補 claims網(wǎng)絡(luò)層加白名單 ACL重復(fù)執(zhí)行業(yè)務(wù)操作首次調(diào)用成功但響應(yīng)丟失重試導(dǎo)致重復(fù)檢查業(yè)務(wù)側(cè)對賬日志引入冪等鍵Agent-Reach 重試時攜帶相同冪等 ID老實說Agent-Reach 這套方案并不驚艷它的價值在于把很多人默認“靠模型自覺”的事情變成了一套強制機制。我實際部署中體會最深的有三點第一路由決策一定要從模型手里拿回來模型理解語義就夠了別讓它做網(wǎng)絡(luò)拓撲層面的選擇第二上下文裁剪的收益比想象中還要大不僅省錢還直接提升了下游 Agent 的準確率第三可觀測性是一切排障的前提沒有 reach trace上面這些問題每一個都要靠瞎猜浪費大半天。另外還有一個非常實用的建議如果你剛開始搭不要一上來就追求全自動的 Agent 自主協(xié)作先把路由、權(quán)限、上下文模板這些確定性部分搞扎實再逐步放開自由度。這個順序走下來系統(tǒng)穩(wěn)定性會肉眼可見地提升。