跳到內容

進階★★★★10 分鐘閱讀

Debug 一個行為怪怪的多步驟 agent

第 4 步歪掉但你不知道為什麼。這是系統化 playbook。

登入以收藏

多步驟 agent 失敗的方式跟單一 prompt LLM 應用不一樣。模型前三步都對,第四步突然出包 —— 呼叫錯工具、幻覺出參數、卡在重複同一個動作。你重跑 prompt 沒辦法重現,因為 prompt 已經不一樣了(歷史更多、中間結果不同)。

這是系統化 playbook,找出真正出錯的地方,而不是亂槍打鳥。

開始之前:先拿到 trace

下面所有東西都假設你看得到完整 trace。如果你沒有 observability(Langfuse、LangSmith、自製 log),停下來先加。花兩小時加 trace log 會省下二十小時的「我猜是 prompt?改改看」。

好 trace 會顯示:

  • 每次 LLM 呼叫的完整輸入跟輸出
  • 每次工具呼叫跟結果
  • 步驟之間傳遞的狀態
  • 每步的 token 數跟延遲

7 種失敗模式(按頻率排序)

我 debug agent 的經驗,所有怪行為都歸到這七種 pattern 之一。按順序走 —— 最常見的在前面。

1. Context 溢出

「agent 第 5+ 步抓狂」最常見的原因。message 歷史已經長到 context window 80%,模型現在忽略 system 指示,優先吃最近的工具輸出。

症狀: 前幾輪正常,第 4-6 輪變怪,第 8 輪以後完全壞掉。

修法:

  • 每輪印總 token 數。
  • 長太快就摘要舊輪次或丟掉它們的工具結果。
  • 用 prompt caching 讓 system prompt 不必每輪重送(部分廠商)。
  • max_model_len,強迫 agent 簡潔。

2. 過時工具結果污染 context

agent 早期搜了一下,搜尋回了 5000 token 的垃圾。這堆垃圾現在在每後續輪的 context 裡,模型一直想把新問題跟它連起來。

症狀: agent 卡在對話早期某個無關的東西上,放不下錯的前提。

修法:

  • 把工具結果截斷到 N tokens。
  • 工具結果消費過後,在歷史裡換成摘要:「[step 2 對 'X' 的搜尋,完整輸出見原步驟,摘要:Y]」。
  • 讓 agent 可以用 forget(step_id) 工具明確丟掉舊 context。

3. Schema 漂移

模型應該呼叫 update_user(id: int, name: str) 但它打了 update_user(user_id: "123", new_name: "Alice")。agent 以為成功了,工具實際上錯誤或做錯事。

症狀: Log 顯示工具被呼叫,DB 沒反映變化。或工具錯誤但沒回傳上去,agent 以為一切順利。

修法:

  • 工具輸入 schema 寫嚴格(additionalProperties: false、enum、精確欄位名)。
  • 在 server 端驗證 agent 的工具參數,驗證失敗回明確錯誤。
  • 確認工具錯誤有當 tool_result content 回給 agent,不是被吞掉。
  • 廠商支援的話,用 structured outputs / strict mode。

4. 模型以為它答完了其實沒

agent 的工具回了一個錯誤,錯誤字串裡有「user's email is empty」之類的文字。模型把那段文字當成你問題的答案就停了。

症狀: agent 沒做有用的事就終止。輸出看起來合理但裡面有明顯來自工具錯誤的片段文字。

修法:

  • 工具錯誤格式加明確前綴:"ERROR: <原因>",不要只給 <原因>
  • system prompt 寫:「收到 ERROR 開頭的工具結果,不要把錯誤文字放進最終答案。試別的方法或回報失敗。」
  • 把意外的 stop_reason 當 bug,不是正常完成。

5. 工具呼叫迴圈

agent 一直呼叫同一個工具,參數略有不同,從來不收斂。要嘛它拿不到對的答案又不肯放棄,要嘛每次工具結果都讓它更困惑。

症狀: 撞 maxSteps。trace 顯示 8 次搜尋,query 都類似。成本飆升。

修法:

  • 在你的 loop 邏輯裡偵測重複呼叫。同一工具用類似 input 呼叫兩次,攔下來強迫 agent 試別的。
  • 改善工具描述:「如果回了空結果,代表使用者資料不存在;不要用變體重試。」
  • system prompt 加步數計數:「你在第 5 步,共 10 步。第 8 步以後必須給最終答案或承認失敗。」

6. Reasoning 區塊沒用 / 用錯

對 reasoning 模型(o3、開 extended thinking 的 Claude、DeepSeek R1),模型有時會忽略自己的推理、最終答案跟推理矛盾、或推理被中途切掉時想到一半失去脈絡。

症狀: 推理 trace 寫「答案是 42」但最終回應寫 47。或模型生 4000 token 思考,然後一個簡短又無關的最終答案。

修法:

  • 撞推理 token 上限就調高預算。
  • 把最終答案那步分開做明確 prompt:「根據你前面的推理,用一句話給最終答案。」
  • Claude extended thinking:確認 thinking 跟 response 兩邊預算都夠。

7. 非決定性 + temperature

你跑同樣 prompt 兩次拿到不同結果,一次成功一次失敗。bug 重現不了。

症狀: 沒辦法可靠重現失敗。昨天壞掉的 trace 跟今天的不一樣。

修法:

  • debug 時設 temperature=0top_p=1,鎖定模型版本。
  • 即使 temperature 0,現代模型因為 GPU 非決定性也不是完全決定性 —— 但接近夠了。
  • 真要決定性:把已知壞 run 的精確 response 存到 fixture 檔,重播 agent loop 用 fixture 不打活 API,這樣可以用 debugger 一步一步走。

系統化流程

出包時按這個順序走:

  1. 拿到一次失敗的乾淨 trace。 能重現最好。
  2. 找出事情走歪的精確步驟。 讀每步的 input/output,不要跳。
  3. 對到上面 7 種失敗模式之一。
  4. 形成單一假設。 「我認為是模式 3,因為工具參數跟我的 schema 不對。」
  5. 只改一件事。 不要同時改 prompt、工具 schema、跟模型。
  6. 重跑同一個輸入。 改動修了症狀嗎?
  7. 再跑 5 個其他輸入。 改動有沒有破壞別的東西?
  8. 還壞就回第 4 步換個假設。

這裡的反模式是同時改六件事,不知道是哪個修的(或哪個弄壞了新東西)。

反模式:換模型

agent 出包時誘惑就是換模型。「來試 Claude 4.7 替換 Sonnet 4.6」。有時這樣有用。常常只是把底層 bug 蓋住 —— agent 還是脆,你只是這個模型運氣好。下次 prompt 一改它又會冒出來。

先搞清楚 agent 為什麼失敗。然後再決定要不要換更強模型。

一個很有用的 debug 技巧

agent 失敗時,把整個 trace 複製到 Claude 或 GPT-5,問:「這個 agent 應該做 X,在第 N 步出包輸出是 Y。走過 trace 告訴我模型在哪裡走錯,為什麼。」

LLM 在這方面意外地強。它能讀 5000 token 的 trace,點出觸發連鎖反應的那一步。把它當你人工 walk-through 之前的第一個 reviewer。

什麼時候不要 debug

同一個 bug 卡 3 小時以上,停下 debug 重新考慮架構。agent 重複出怪行為通常代表任務對模型太開放,拆解可能比再改一次 prompt 有用。

具體:agent 有超過 5 個不同工具加開放任務定義,考慮拆成 planner agent(決定工具順序)跟 executor agent(呼叫工具)。較小的決策空間失敗較少。

下一步

  • 本 Learn 庫裡的「從零寫 agent loop」那篇。
  • LangSmith 跟 Langfuse trace 範例。
  • Building effective agents —— Anthropic 2024 年 12 月。
  • 查這些詞:chain-of-thought failure mode、agent decomposition、structured outputs、eval-driven prompt iteration。

最後更新: 2026-04-29

We use cookies

Anonymous analytics help us improve the site. You can opt out anytime. Learn more