Agent工程化 · 第六篇:Agent從本地跑通到生產上線,差了什麼
整理版優先睇
Agent從本地到生產存在系統性鴻溝,需處理七大差異同五項防護機制先可以平穩上線
呢篇文章係由專注AI Agent實踐嘅努力撞蘑菇AI所寫。佢想解決嘅問題係:好多開發者喺本地成功跑通Agent,但一部署到生產環境就出現超時、無限循環、Token賬單爆升等問題。作者指出呢啲問題唔係寫得唔好,而係本地同生產環境之間存在系統性鴻溝。整體結論係要正視七個核心差異,並針對五個關鍵問題做好防護機制,先可以平穩上線。
七個差異包括併發、輸入多樣性、外部服務不穩定性、狀態管理、資源限制、監控缺失同部署環境差異。作者逐一解釋每個差異點解會導致問題,例如本地一次跑一個任務,但生產同時有50個用戶,工具同Token配額會馬上撞牆。
五個必須解決嘅問題係:工具調用容錯機制、無限循環防護、併發控制同速率限制、狀態隔離同會話管理,同埋優雅降級策略。每個問題作者都提供具體程式碼實現同真實踩坑案例。最後仲有一個部署檢查清單同兩週上線磨合期嘅時間線,提醒開發者上線前唔好承諾一定穩定,出問題都唔使自我懷疑。
- 本地與生產環境有七個核心差異:併發、輸入多樣性、外部服務不穩定性、狀態管理、資源限制、監控缺失、部署環境差異,每個都會引發唔同類型嘅生產故障。
- 工具調用必須加上超時保護(建議30秒)、重試機制(最多3次,指數退避)同錯誤分類(超時vs失敗),避免單個工具拖垮整個任務。
- 必須設置工具調用次數上限(建議P99嘅2倍)同模型推理次數上限,防止無限循環導致Token浪費同服務掛起。
- 使用信號量限制併發任務數(如同時最多10個),用速率限制平滑TPM消耗,可以大幅提升成功率(從61%到99.3%)。
- 多用戶場景下要用session_id隔離對話歷史,並定期清理過期Session(例如TTL=3600秒),避免內存洩漏同狀態污染。
部署檢查清單
對照清單過一遍基礎穩定性、併發與資源、狀態管理、可觀測性、容災與降級五個範疇,確保Agent生產部署穩妥。
生產防護程式碼模板
包含工具調用容錯(超時、重試、錯誤分類)、無限循環防護(調用次數上限)、併發控制(信號量+速率限制)、狀態隔離(Session管理器)嘅Python程式碼片段。
本地跑通嘅陷阱
喺本地跑通Agent,測咗二十個case都冇問題,但一上線就出事:用戶反饋卡住、日誌出現超時、服務重啟、無限循環、Token賬單爆升。呢個唔係你寫得唔好,而係本地同生產之間存在一道系統性鴻溝,每個做Agent的人都會踩中。
本地與生產嘅七個核心差異
理解呢啲差異係平穩上線嘅前提。以下七點係本地永遠模擬唔到嘅生產現實:
- 1 併發:本地一次一個任務;生產可能同時50個用戶,工具、Token配額、數據庫連接都會撞牆。
- 2 輸入多樣性:本地精心準備case;真實用戶輸入超長文本、特殊字符、惡意內容,Prompt可能完全失常。
- 3 外部服務不穩定性:本地網絡正常;生產有延遲、限流、版本變更,Agent要有重試同降級。
- 4 狀態管理:本地每次新進程;生產要維護會話、多輪上下文,崩潰後要恢復。
- 5 資源限制:本地資源任食;生產實例有配額,Token有RPM/TPM限制,超咗就OOM或429。
- 6 監控缺失:本地即刻睇到終端輸出;生產冇可觀測性系統嘅話,幾個鐘先發現問題。
- 7 部署環境差異:依賴版本、環境變數、密鑰配置可能唔同,細微差異就會導致行為改變。
五個部署前必須解決嘅問題
以下五個問題一定要喺上線前處理好,每個都附有具體程式碼同真實踩坑案例。
3.1 工具調用嘅容錯機制
呢個係最容易忽略但最易出事嘅位。每個外部工具調用都要加三樣嘢:超時保護、重試機制同錯誤分類。下面係一個Python實現:
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(min=1, max=10)
)
async def call_tool_with_protection(tool_name, args, timeout=30):
try:
result = await asyncio.wait_for(
call_tool(tool_name, args),
timeout=timeout
)
return result
except asyncio.TimeoutError:
raise ToolTimeoutError(f"{tool_name} timed out after {timeout}s")
except Exception as e:
raise ToolCallError(f"{tool_name} failed: {e}")
真實案例:某數據查詢工具響應時間由200ms變成80秒,冇超時保護會佔住線程最終令服務冇反應。加咗30秒超時後,呢類請求快速失敗,唔影響其他任務。
3.2 無限循環嘅防護
呢個係Agent特有、最危險嘅生產問題。要設置工具調用次數上限同模型推理次數上限,閾值建議由正常任務嘅P99乘2定出嚟。
class AgentExecutor:
MAX_TOOL_CALLS = 20
MAX_MODEL_CALLS = 10
def __init__(self):
self.tool_call_count = 0
self.model_call_count = 0
def check_limits(self):
if self.tool_call_count >= self.MAX_TOOL_CALLS:
raise AgentLoopError(f"工具調用次數超限({self.MAX_TOOL_CALLS}),任務強制終止")
if self.model_call_count >= self.MAX_MODEL_CALLS:
raise AgentLoopError(f"模型推理次數超限({self.MAX_MODEL_CALLS}),任務強制終止")
真實案例:報告生成Agent遇到某類輸入,模型不斷查數據,冇限制嘅話單個任務用咗4700 Token,係正常嘅20倍,直接爆預算。
3.3 併發控制同速率限制
要同時做併發控制(如信號量限制同時任務數)同速率限制(如Throttler限制每分鐘請求數),避免撞API限流。
import asyncio
from asyncio import Semaphore
semaphore = Semaphore(10)
async def run_agent_task(task):
async with semaphore:
return await execute_agent(task)
# 速率限制
from asyncio_throttle import Throttler
throttler = Throttler(rate_limit=1000, period=60)
async def call_model_with_rate_limit(prompt):
async with throttler:
return await model.call(prompt)
真實案例:一次提交200個任務,前30秒快之後大量429,成功率得61%。加咗併發控制同指數退避後成功率升到99.3%,雖然慢咗但全部跑完。
3.4 狀態隔離同會話管理
多用戶場景下一定要用session_id隔離狀態,每用戶獨立conversation_history,仲要定期清理過期Session避免內存洩漏。
class AgentSession:
def __init__(self, session_id: str, user_id: str):
self.session_id = session_id
self.user_id = user_id
self.conversation_history = []
self.created_at = time.time()
self.last_active = time.time()
def add_message(self, msg):
self.conversation_history.append(msg)
self.last_active = time.time()
class SessionManager:
def __init__(self, ttl_seconds=3600):
self.sessions = {}
self.ttl = ttl_seconds
def get_or_create(self, session_id, user_id):
if session_id not in self.sessions:
self.sessions[session_id] = AgentSession(session_id, user_id)
return self.sessions[session_id]
def cleanup_expired(self):
now = time.time()
expired = [sid for sid, s in self.sessions.items()
if now - s.last_active > self.ttl]
for sid in expired:
del self.sessions[sid]
真實案例:用戶反映結果包含其他人歷史,發現係全局狀態污染,修復後正常。
3.5 優雅降級策略
生產唔係所有錯誤都要直接報俾用戶。要有降級策略:主模型故障→備用模型;工具失敗→記錄繼續;任務超時→返回部分結果。核心原則係:失敗要可見,但唔好令單點失敗導致整體不可用。
部署檢查清單與真實時間線
上線前對照呢個部署檢查清單過一遍:
- 基礎穩定性:所有外部工具調用有超時保護(30s)同重試機制(3次);Agent有工具調用次數上限同執行時長上限。
- 併發與資源:設咗併發任務數上限同API速率限制;測試P90併發資源消耗;Token用量喺安全範圍。
- 狀態管理:多用戶Session完全隔離;過期Session有清理機制;崩潰重啓後狀態可恢復。
- 可觀測性:結構化日誌已接入;關鍵指標有告警閾值;失敗任務有完整Trace。
- 容災與降級:主模型有備用;關鍵工具失敗有降級處理;整體服務有熔斷機制。
一、本地跑通嗰個下晝
你喺本地跑通咗Agent,測咗二十個case,結果都啱曬,心情好靚。
然後你將佢部署到生產環境。
第一日,用戶反饋間唔中會卡住冇反應。第三日,日誌裏面開始出現大量超時錯誤。第五日,某個用戶嘅請求令到成個服務重啟咗一次。第七日,你發現某啲場景下Agent會無限循環調用工具,Token賬單翻咗五倍。
本地明明冇問題。
呢個唔係你寫得唔好,而係本地環境同生產環境之間存在一道系統性嘅鴻溝,每個做Agent嘅人都會跌入去。
呢篇會將呢道鴻溝裏面嘅陷阱,提早話畀你知。

二、本地同生產嘅七個核心差異
理解呢啲差異,係你可以平穩上線嘅前提。
差異1:併發本地你一次跑一個任務。生產入面,可能同一時間有50個用戶喺度觸發Agent,每個都係調用同樣嘅工具、消耗同樣嘅Token配額、佔用同樣嘅數據庫連接。你喺本地從來冇測過並發,所以你唔知你嘅工具喺並發場景下會唔會有競爭條件,你嘅Token用量會唔會超速率限制,你嘅數據庫連接池會唔會被打爆。
差異2:輸入多樣性本地測試嘅二十個case,係你精心準備嘅,代表你認為嘅「典型輸入」。真實用戶嘅輸入係一個你完全冇辦法預測嘅分佈:有人會輸入超長文本,有人會輸入特殊字符,有人會輸入同你預期完全無關嘅內容,有人會故意嘗試令Agent做佢唔應該做嘅事。你嘅Prompt喺呢啲邊界case上會發生咩事,本地根本測唔出嚟。
差異3:外部服務嘅不穩定性本地調用工具,基本上都成功,因為你喺一個網絡好、服務正常嘅環境入面。生產入面,外部API有延遲、有間中失敗、有限流、有版本變更。你嘅Agent有冇重試機制、有冇降級策略、有冇超時保護?本地感覺唔到呢啲問題。
差異4:狀態管理本地每次跑都係全新嘅進程,冇狀態殘留。生產入面,Agent可能需要維護會話狀態、多輪對話上下文、用戶嘅歷史操作記錄。呢啲狀態存在邊度、點樣隔離、崩潰後點樣恢復——呢啲問題喺本地都唔存在。
差異5:資源限制本地你有成部機器嘅資源,內存、CPU隨便用。生產入面,你嘅Agent實例通常有資源配額,超咗就會OOM或者俾人限流。更關鍵嘅係,Token配額都係有限嘅——你嘅大模型API通常有RPM(每分鐘請求數)同TPM(每分鐘Token數)嘅限制,本地跑十個任務感覺唔到,並發五十個就會撞牆。
差異6:監控同告警缺失本地出咗問題,你可以即刻睇到終端輸出。生產入面,出咗問題你可能幾個鐘頭之後先發現——如果你冇上一篇講嘅可觀測性體系嘅話。
差異7:部署環境差異本地嘅依賴版本、環境變量、模型API密鑰配置,同生產可能唔完全一樣。有時一個細微嘅庫版本差異,就可以令行為完全唔同。
三、五個部署前必須解決嘅問題
3.1 工具調用嘅容錯機制
呢個係最容易被忽略、亦都最容易出事嘅地方。
一定要俾每個外部工具調用加三件事:
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3), # 最多重試3次
wait=wait_exponential(min=1, max=10) # 指數退避,避免打爆下游
)
asyncdef call_tool_with_protection(tool_name, args, timeout=30):
try:
result = await asyncio.wait_for(
call_tool(tool_name, args),
timeout=timeout # 超時保護,不讓單個工具拖垮整個任務
)
return result
except asyncio.TimeoutError:
raise ToolTimeoutError(f"{tool_name} timed out after {timeout}s")
except Exception as e:
raise ToolCallError(f"{tool_name} failed: {e}")
三件事:超時保護(唔俾工具無限等)、重試機制(間中失敗自動恢復)、錯誤分類(超時同失敗要區分,處理方式唔同)。
真實踩坑案例:某個數據查詢工具,喺數據量大的時候響應時間會由200ms升到80秒。冇超時保護嘅情況下,呢個請求會一直掛住,佔用線程資源,最終令服務冇反應。加咗30秒超時之後,呢類請求會快速失敗並返回錯誤,唔影響其他任務,用戶都可以睇到明確嘅錯誤提示。
3.2 無限循環嘅防護
呢個係Agent特有嘅、最危險嘅生產問題。
咩情況下會出現無限循環:
工具返回嘅結果令模型覺得「仲需要再查一次」 模型對某個中間結果唔滿意,不斷重試 兩個工具互相調用,形成環路 任務條件永遠冇辦法滿足,模型一直嘗試
防護方案:
class AgentExecutor:
MAX_TOOL_CALLS = 20 # 單任務最大工具調用次數
MAX_MODEL_CALLS = 10 # 單任務最大模型推理次數
def __init__(self):
self.tool_call_count = 0
self.model_call_count = 0
def check_limits(self):
if self.tool_call_count >= self.MAX_TOOL_CALLS:
raise AgentLoopError(f"工具調用次數超限({self.MAX_TOOL_CALLS}),任務強制終止")
if self.model_call_count >= self.MAX_MODEL_CALLS:
raise AgentLoopError(f"模型推理次數超限({self.MAX_MODEL_CALLS}),任務強制終止")
閾值點樣定: 先跑100個正常任務,統計工具調用次數嘅P99值,將上限設為P99嘅2倍。咁樣正常任務唔受影響,異常任務可以被及時截斷。
真實踩坑案例:一個報告生成Agent,遇到某類輸入時,模型會不斷調用數據查詢工具補充細節,覺得「仲唔夠完整」。冇調用次數限制嘅情況下,單個任務消耗咗4700個Token,係正常任務嘅20倍,直接導致當月Token賬單超預算。
3.3 並發控制同速率限制
Token速率限制嘅處理:
大模型API通常有TPM限制(例如GPT-5.5嘅限制係200萬TPM)。並發請求多咗,好容易撞到限流返回429錯誤。
import asyncio
from asyncio import Semaphore
# 併發限制:同時最多10個Agent任務
semaphore = Semaphore(10)
asyncdef run_agent_task(task):
asyncwith semaphore:
returnawait execute_agent(task)
# 速率限制:每分鐘最多處理1000個請求
from asyncio_throttle import Throttler
throttler = Throttler(rate_limit=1000, period=60)
asyncdef call_model_with_rate_limit(prompt):
asyncwith throttler:
returnawait model.call(prompt)
唔好只係限制並發數,仲要限制速率。 10個並發任務如果每個都好重,瞬間TPM消耗可能超限,用速率限制嚟平滑流量。
真實踩坑案例:批量任務場景,一次提交咗200個任務,用線程池並發執行。前30秒跑得好快,然後開始大量報429,剩餘任務全部失敗。加咗並發控制(同時最多15個)同指數退避重試之後,200個任務嘅成功率由61%提升到99.3%,總耗時由3分鐘變成8分鐘——慢咗,但係全部跑完咗。
3.4 狀態隔離同會話管理
多用戶場景下,狀態隔離係基本要求。
最常見嘅狀態污染問題:
# 危險寫法:全局狀態,多用戶共享
class AgentState:
conversation_history = [] # 所有用戶共享同一個歷史!
def add_message(self, msg):
self.conversation_history.append(msg)
# 正確寫法:用session_id隔離
class AgentSession:
def __init__(self, session_id: str, user_id: str):
self.session_id = session_id
self.user_id = user_id
self.conversation_history = [] # 每個session獨立的歷史
self.created_at = time.time()
self.last_active = time.time()
def add_message(self, msg):
self.conversation_history.append(msg)
self.last_active = time.time()
# Session管理器:負責創建、獲取、清理
class SessionManager:
def __init__(self, ttl_seconds=3600):
self.sessions = {}
self.ttl = ttl_seconds
def get_or_create(self, session_id, user_id):
if session_id notin self.sessions:
self.sessions[session_id] = AgentSession(session_id, user_id)
return self.sessions[session_id]
def cleanup_expired(self):
now = time.time()
expired = [sid for sid, s in self.sessions.items()
if now - s.last_active > self.ttl]
for sid in expired:
del self.sessions[sid]
唔好唔記得清理過期Session。 一個活躍用戶嘅對話歷史可能有幾十條消息,唔清理嘅話內存會一直升。
3.5 優雅降級策略
生產環境入面,唔係所有錯誤都應該直接報畀用戶。你需要一套降級策略:
主模型不可用(如GPT-5.5 API故障)
→ 降級到備用模型(如DeepSeek V4)
→ 告知用戶"當前使用備用服務,質量可能略有差異"
關鍵工具調用失敗(重試3次仍失敗)
→ 記錄失敗,繼續執行其他步驟
→ 在輸出中標註"部分數據獲取失敗,結果可能不完整"
整個任務超時(超過最大執行時間)
→ 返回已完成的部分結果
→ 告知用戶"任務未完全執行,已返回已處理部分"
核心原則:失敗要可見,但唔好令單點失敗導致整體唔可以用。
四、部署檢查清單
上線之前,對照呢個清單過一次:
基礎穩定性
[ ] 所有外部工具調用有超時保護(建議30s) [ ] 所有外部工具調用有重試機制(建議3次,指數退避) [ ] Agent有工具調用次數上限(防無限循環) [ ] Agent有總執行時長上限(防任務掛起)
並發與資源
[ ] 設置咗並發任務數上限 [ ] 設置咗模型API速率限制 [ ] 測試咗P90並發場景下嘅資源消耗 [ ] 確認Token用量喺API限制嘅安全範圍內
狀態管理
[ ] 多用戶場景下Session完全隔離 [ ] 過期Session有清理機制 [ ] 崩潰重啟後狀態可恢復(或可接受重置)
可觀測性(對照第五篇)
[ ] 結構化日誌已接入 [ ] 關鍵指標有告警閾值 [ ] 失敗任務有完整嘅Trace可查
容災與降級
[ ] 主模型有備用模型 [ ] 關鍵工具失敗有降級處理 [ ] 整體服務有熔斷機制
五、一個完整嘅踩坑時間線
最後分享一個真實嘅上線過程,幫你建立預期:
D1 本地跑通,信心滿滿,準備上線
D2 上線第一天,偶發超時,加了超時保護
D3 發現某類輸入觸發無限循環,加了調用次數限制
D5 併發壓測,發現Rate Limit問題,加了併發控制
D7 用戶反映結果有時候包含其他用戶的歷史,
定位到Session污染問題,花了半天修復
D10 Token賬單比預期高3倍,分析日誌發現
某個邊界case會觸發大量重試,修復後正常
D14 服務趨於穩定,開始正常迭代功能
呢個係一個典型嘅兩星期上線磨合期。唔係你做得唔好,而係呢啲問題喺本地就係測唔出嚟。
瞭解呢個時間線嘅意義係:上線前唔好承諾「一定穩定」,上線後唔好因為出問題就懷疑自己。 呢啲坑每個做Agent生產部署嘅人都踩過,分別只係有冇提前知道。
一、本地跑通的那個下午
你在本地跑通了Agent,測了二十個case,結果都對,心情很好。
然後你把它部署到生產環境。
第一天,用戶反饋偶爾會卡住沒響應。 第三天,日誌裏開始出現大量超時錯誤。 第五天,某個用戶的請求導致整個服務重啓了一次。 第七天,你發現某些場景下Agent會無限循環調用工具,Token賬單翻了五倍。
本地明明沒問題。
這不是你寫得不好,這是本地環境和生產環境之間存在一道系統性的鴻溝,每個做Agent的人都會掉進去。
這篇把這道鴻溝裏的坑,提前告訴你。

二、本地和生產的七個核心差異
理解這些差異,是你能平穩上線的前提。
差異1:併發本地你一次跑一個任務。生產裏,可能同時有50個用戶在觸發Agent,每個都在調用同樣的工具、消耗同樣的Token配額、佔用同樣的數據庫連接。 你在本地從來沒測過併發,所以你不知道你的工具在併發場景下會不會有競爭條件,你的Token用量會不會超速率限制,你的數據庫連接池會不會被打滿。
差異2:輸入多樣性本地測試的二十個case,是你精心準備的,代表你認為的"典型輸入"。 真實用戶的輸入是一個你完全無法預測的分佈:有人會輸入超長文本,有人會輸入特殊字符,有人會輸入跟你預期完全無關的內容,有人會故意嘗試讓Agent做它不該做的事。 你的Prompt在這些邊界case上會發生什麼,本地根本測不出來。
差異3:外部服務的不穩定性本地調工具,基本都成功,因為你在一個網絡好、服務正常的環境裏。 生產裏,外部API有延遲、有偶發失敗、有限流、有版本變更。你的Agent有沒有重試機制、有沒有降級策略、有沒有超時保護?本地感知不到這些問題。
差異4:狀態管理本地每次跑都是全新的進程,沒有狀態殘留。 生產裏,Agent可能需要維護會話狀態、多輪對話上下文、用戶的歷史操作記錄。這些狀態存在哪、怎麼隔離、崩潰後怎麼恢復——這些問題在本地都不存在。
差異5:資源限制本地你有整台機器的資源,內存、CPU隨便用。 生產裏,你的Agent實例通常有資源配額,超了就OOM或被限流。更關鍵的是,Token配額也是有限的——你的大模型API通常有RPM(每分鐘請求數)和TPM(每分鐘Token數)的限制,本地跑十個任務感知不到,併發五十個就會撞牆。
差異6:監控和告警缺失本地出了問題,你能立刻看到終端輸出。 生產裏,出了問題你可能幾個小時後才發現——如果你沒有上一篇講的可觀測性體系的話。
差異7:部署環境差異本地的依賴版本、環境變量、模型API密鑰配置,和生產可能不完全一樣。有時候一個細微的庫版本差異,就能讓行為完全不同。
三、五個部署前必須解決的問題
3.1 工具調用的容錯機制
這是最容易被忽視、也是最容易出事的地方。
必須給每個外部工具調用加三件事:
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3), # 最多重試3次
wait=wait_exponential(min=1, max=10) # 指數退避,避免打爆下游
)
asyncdef call_tool_with_protection(tool_name, args, timeout=30):
try:
result = await asyncio.wait_for(
call_tool(tool_name, args),
timeout=timeout # 超時保護,不讓單個工具拖垮整個任務
)
return result
except asyncio.TimeoutError:
raise ToolTimeoutError(f"{tool_name} timed out after {timeout}s")
except Exception as e:
raise ToolCallError(f"{tool_name} failed: {e}")
三件事:超時保護(不讓工具無限等)、重試機制(偶發失敗自動恢復)、錯誤分類(超時和失敗要區分,處理方式不同)。
真實踩坑案例:某個數據查詢工具,在數據量大的時候響應時間會從200ms漲到80秒。沒有超時保護的情況下,這個請求會一直掛着,佔用線程資源,最終導致服務無響應。 加了30秒超時後,這類請求會快速失敗並返回錯誤,不影響其他任務,用戶也能看到明確的錯誤提示。
3.2 無限循環的防護
這是Agent特有的、最危險的生產問題。
什麼情況下會出現無限循環:
工具返回的結果讓模型覺得"還需要再查一次" 模型對某個中間結果不滿意,不斷重試 兩個工具互相調用,形成環路 任務條件永遠無法滿足,模型一直嘗試
防護方案:
class AgentExecutor:
MAX_TOOL_CALLS = 20 # 單任務最大工具調用次數
MAX_MODEL_CALLS = 10 # 單任務最大模型推理次數
def __init__(self):
self.tool_call_count = 0
self.model_call_count = 0
def check_limits(self):
if self.tool_call_count >= self.MAX_TOOL_CALLS:
raise AgentLoopError(f"工具調用次數超限({self.MAX_TOOL_CALLS}),任務強制終止")
if self.model_call_count >= self.MAX_MODEL_CALLS:
raise AgentLoopError(f"模型推理次數超限({self.MAX_MODEL_CALLS}),任務強制終止")
閾值怎麼定: 先跑100個正常任務,統計工具調用次數的P99值,把上限設為P99的2倍。這樣正常任務不受影響,異常任務能被及時截斷。
真實踩坑案例:一個報告生成Agent,遇到某類輸入時,模型會不斷調用數據查詢工具補充細節,覺得"還不夠完整"。沒有調用次數限制的情況下,單個任務消耗了4700個Token,是正常任務的20倍,直接導致當月Token賬單超預算。
3.3 併發控制和速率限制
Token速率限制的處理:
大模型API通常有TPM限制(比如GPT-5.5的限制是200萬TPM)。併發請求多了,很容易撞到限流返回429錯誤。
import asyncio
from asyncio import Semaphore
# 併發限制:同時最多10個Agent任務
semaphore = Semaphore(10)
asyncdef run_agent_task(task):
asyncwith semaphore:
returnawait execute_agent(task)
# 速率限制:每分鐘最多處理1000個請求
from asyncio_throttle import Throttler
throttler = Throttler(rate_limit=1000, period=60)
asyncdef call_model_with_rate_limit(prompt):
asyncwith throttler:
returnawait model.call(prompt)
不要只限制併發數,還要限制速率。 10個併發任務如果每個都很重,瞬間TPM消耗可能超限,用速率限制來平滑流量。
真實踩坑案例:批量任務場景,一次提交了200個任務,用線程池併發執行。前30秒跑得很快,然後開始大量報429,剩餘任務全部失敗。 加了併發控制(同時最多15個)和指數退避重試後,200個任務的成功率從61%提升到99.3%,總耗時從3分鐘變成8分鐘——慢了,但全跑完了。
3.4 狀態隔離和會話管理
多用戶場景下,狀態隔離是基本要求。
最常見的狀態污染問題:
# 危險寫法:全局狀態,多用戶共享
class AgentState:
conversation_history = [] # 所有用戶共享同一個歷史!
def add_message(self, msg):
self.conversation_history.append(msg)
# 正確寫法:用session_id隔離
class AgentSession:
def __init__(self, session_id: str, user_id: str):
self.session_id = session_id
self.user_id = user_id
self.conversation_history = [] # 每個session獨立的歷史
self.created_at = time.time()
self.last_active = time.time()
def add_message(self, msg):
self.conversation_history.append(msg)
self.last_active = time.time()
# Session管理器:負責創建、獲取、清理
class SessionManager:
def __init__(self, ttl_seconds=3600):
self.sessions = {}
self.ttl = ttl_seconds
def get_or_create(self, session_id, user_id):
if session_id notin self.sessions:
self.sessions[session_id] = AgentSession(session_id, user_id)
return self.sessions[session_id]
def cleanup_expired(self):
now = time.time()
expired = [sid for sid, s in self.sessions.items()
if now - s.last_active > self.ttl]
for sid in expired:
del self.sessions[sid]
別忘了清理過期Session。 一個活躍用戶的對話歷史可能有幾十條消息,不清理的話內存會一直漲。
3.5 優雅降級策略
生產環境裏,不是所有錯誤都應該直接報給用戶。你需要一套降級策略:
主模型不可用(如GPT-5.5 API故障)
→ 降級到備用模型(如DeepSeek V4)
→ 告知用戶"當前使用備用服務,質量可能略有差異"
關鍵工具調用失敗(重試3次仍失敗)
→ 記錄失敗,繼續執行其他步驟
→ 在輸出中標註"部分數據獲取失敗,結果可能不完整"
整個任務超時(超過最大執行時間)
→ 返回已完成的部分結果
→ 告知用戶"任務未完全執行,已返回已處理部分"
核心原則:失敗要可見,但不要讓單點失敗導致整體不可用。
四、部署檢查清單
上線之前,對照這個清單過一遍:
基礎穩定性
[ ] 所有外部工具調用有超時保護(建議30s) [ ] 所有外部工具調用有重試機制(建議3次,指數退避) [ ] Agent有工具調用次數上限(防無限循環) [ ] Agent有總執行時長上限(防任務掛起)
併發與資源
[ ] 設置了併發任務數上限 [ ] 設置了模型API速率限制 [ ] 測試了P90併發場景下的資源消耗 [ ] 確認Token用量在API限制的安全範圍內
狀態管理
[ ] 多用戶場景下Session完全隔離 [ ] 過期Session有清理機制 [ ] 崩潰重啓後狀態可恢復(或可接受重置)
可觀測性(對照第五篇)
[ ] 結構化日誌已接入 [ ] 關鍵指標有告警閾值 [ ] 失敗任務有完整的Trace可查
容災與降級
[ ] 主模型有備用模型 [ ] 關鍵工具失敗有降級處理 [ ] 整體服務有熔斷機制
五、一個完整的踩坑時間線
最後分享一個真實的上線過程,幫你建立預期:
D1 本地跑通,信心滿滿,準備上線
D2 上線第一天,偶發超時,加了超時保護
D3 發現某類輸入觸發無限循環,加了調用次數限制
D5 併發壓測,發現Rate Limit問題,加了併發控制
D7 用戶反映結果有時候包含其他用戶的歷史,
定位到Session污染問題,花了半天修復
D10 Token賬單比預期高3倍,分析日誌發現
某個邊界case會觸發大量重試,修復後正常
D14 服務趨於穩定,開始正常迭代功能
這是一個典型的兩週上線磨合期。不是你做得不好,是這些問題在本地就是測不出來。
瞭解這個時間線的意義是:上線前不要承諾"一定穩定",上線後不要因為出問題就懷疑自己。 這些坑每個做Agent生產部署的人都踩過,區別只是有沒有提前知道。