Eric TechBlog
AIAI Assistant

Agent Orchestration

Agent 編排設計,涵蓋 Tool Loop、多 Agent 協作、System Prompt 設計,以及錯誤恢復機制。

設計問題

用戶說:「幫我查一下 John 上週寄的那封關於合約的信,然後把裡面的截止日期加到我的行事曆。」

這不是一個 API 呼叫能搞定的事。Agent 需要:

  1. 搜尋 email(可能要嘗試不同的關鍵字)
  2. 篩選結果,找到正確的信
  3. 讀取完整內容,提取截止日期
  4. 呼叫行事曆 API 建立事件(需要用戶確認)

每一步的結果決定下一步怎麼做。這就是 Agent 編排的問題。

核心問題:如何設計一個 Agent 系統,讓 LLM 能安全、高效地完成多步驟任務?

這篇建立在前面兩個模組之上

你可以把這篇看成把 檢索HITL 串起來的那一層。前者解決「找資料」,後者解決「安全執行」,而 Agent 編排負責決定整體順序。


工具循環(Tool Loop)

基本模式

Agent 的核心是一個 Think → Act → Observe 循環:

While (未完成 AND 步數未超限):
  1. Think: LLM 根據上下文決定下一步
     → 直接回答(結束)
     → 呼叫某個工具

  2. Act: 執行工具,取得結果

  3. Observe: 把工具結果加入上下文

  4. 回到 Think

每一輪循環,LLM 都能看到之前所有工具呼叫的結果,基於這些資訊做出下一個決定。

停止條件

停止條件:stepCountIs(10)

為什麼需要限制步數?

  1. 成本控制:每一步都消耗 token。10 步大約是 $0.01-0.05
  2. 防止無限循環:LLM 偶爾會陷入重複嘗試的死循環
  3. 延遲控制:每步 1-3 秒,10 步就是 10-30 秒
  4. 實務觀察:絕大多數任務在 3-5 步內就能完成

超過步數限制怎麼辦?

Agent 在步數耗盡時會被迫生成一個回應。它可能會說:「我找到了一些線索但需要更多資訊。你能告訴我...嗎?」這比無限循環好得多。


工具設計

工具的結構

每個工具需要定義:

Tool {
  name: string           ← 工具名稱
  description: string    ← 何時使用這個工具(給 LLM 看)
  inputSchema: ZodSchema ← 參數的型別定義
  execute: (input) → output ← 實際執行的函式
}

description 是最關鍵的部分

它決定了 LLM 何時選擇使用這個工具。

壞的 description:

"Search emails"

好的 description:

"Search emails using both keyword and semantic search.
Returns metadata with snippets only — use getEmails tool
to fetch full content of specific emails."

好的 description 告訴 LLM:

  1. 這個工具做什麼
  2. 它返回什麼(snippet,不是全文)
  3. 下一步該做什麼(用 getEmails 取全文)

工具集的合併

Agent 同時擁有多種來源的工具:

最終工具集 = 內建工具(email 搜尋等)+ MCP 工具(Calendar、Tasks)

合併時需要注意命名衝突。如果兩個來源都有一個叫 search 的工具,就需要重命名或建立命名空間。


多 Agent 協作

為什麼不只用一個 Agent?

考慮 HITL 流程。如果主 Agent 先搜尋了 5 分鐘 email,最後才決定要建立行事曆事件,這時候暫停等用戶確認,前面的搜尋工作就白費了(因為用戶可能拒絕,導致整個請求重來)。

更好的做法:先快速判斷是否需要 HITL,再開始主要工作。

Approval Agent(HITL 前置判斷)

主流程:
  1. Approval Agent(1 步)→ 需要 HITL 嗎?
     YES → 立即送出確認請求 → 結束請求
     NO  → 繼續
  2. 執行已批准的工具(如果有)
  3. Main Agent(≤10 步)→ 完成任務

Approval Agent 的設計:

角色:HITL 規劃者
工具:只有需要人工介入的 MCP 工具(被 HITL 包裝過的版本)
步數限制:1 步
規則:
  - 如果需要外部工具 → 呼叫(觸發 ApprovalRequiredError)
  - 如果不需要 → 返回 "NO_TOOL"
  - 不要回答用戶的問題
  - 不要解釋推理過程

為什麼限制 1 步?它的任務很簡單,只要判斷「這個請求是否涉及外部操作」即可。一步就夠了。

Agent 間的資料流


System Prompt 設計

工具選擇策略

在 system prompt 中明確指引 Agent 何時使用什麼工具:

工具選擇規則:
  - Email 相關 → search / filterEmails / getEmails
  - 行事曆相關 → findCalendarEvents / MCP tools
  - 任務相關 → MCP tools
  - 一般問答 → 不用工具,直接回答

為什麼要明確指引?

LLM 有時候會「過度使用」工具(明明可以直接回答卻去搜尋),或「使用錯誤」的工具(該用語意搜尋卻用了精確篩選)。明確的規則減少這些錯誤。

工作流指引

告訴 Agent 具體的工作流程,而非讓它自己摸索:

Email 搜尋的三步工作流:

STEP 1 - 瀏覽:
  USE 'filterEmails' when: 條件明確(特定人、日期、關鍵字)
  USE 'search' when: 語意搜尋(概念、問題、主題)

STEP 2 - 審查:
  看 snippet 是否足夠回答
  判斷哪些需要全文

STEP 3 - 深入:
  USE 'getEmails' 取需要的全文

這像是給新員工的操作手冊。它不是在限制能力,而是用經過驗證的流程提高效率。

動態 System Prompt

System prompt 不是靜態的。它根據可用的工具動態調整:

if calendarToolAvailable:
  → 正常的行事曆指引

else:
  → "Calendar integration is not configured.
     If the user asks, explain it's unavailable."

這避免了 Agent 嘗試呼叫不存在的工具,或對用戶做出無法兌現的承諾。


錯誤恢復

工具執行失敗

工具可能因為各種原因失敗(API 超時、資料格式錯誤等)。Agent 應該能看到錯誤並調整策略。

工具的失敗會作為 output-error 狀態返回:

Tool result: { state: "output-error", errorText: "API timeout" }

Agent 看到這個後可能:

  • 重試(用不同的參數)
  • 換一個工具
  • 告訴用戶「暫時無法查詢」

ApprovalRequiredError

這不是真正的「錯誤」,而是一個控制流信號:

HITL 包裝的工具被呼叫
  → 不執行真正的邏輯
  → 記錄工具名稱和參數
  → 拋出 ApprovalRequiredError
  → 被上層捕獲
  → 轉為確認請求串流給前端

用 Error 作為控制流有爭議,但在這個場景中很合適,因為它利用了 Agent 框架的錯誤處理管道,不需要額外的中斷機制。


生產考量

可觀測性

Agent 的多步驟執行很難調試。你需要能看到:

  • 每一步 Agent 的思考過程
  • 每個工具呼叫的輸入和輸出
  • 每步的 token 消耗
  • 總的延遲分佈

工具如 Langfuse、LangSmith、OpenTelemetry 可以提供這種可視性。

成本控制

  • Per-step cost cap:如果單次呼叫超過 X token,警告或終止
  • Per-conversation cap:整個對話的總 token 不超過 Y
  • Rate limiting:每用戶每分鐘 / 每天的請求限制

Agent 評估

評估 Agent 的品質比評估普通 LLM 更難,因為涉及工具選擇和多步驟推理:

  • 端到端評估:給定問題,Agent 最終的答案是否正確
  • 工具選擇評估:Agent 是否選了對的工具
  • 效率評估:Agent 用了幾步完成任務(越少越好)
  • 失敗模式分析:Agent 在什麼類型的問題上出錯

重點總結

設計決策選擇原因
循環模式Think → Act → Observe標準的 Agent 架構
步數限制10 步平衡能力和成本
多 AgentApproval + Main前置 HITL 判斷,避免浪費
工具指引System prompt 中明確規則減少工具選擇錯誤
錯誤恢復Agent 自己看到錯誤並調整利用 LLM 的靈活性
動態 prompt根據可用工具調整避免幻覺

Last updated on

On this page