iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0

Day 9 今日地圖:今天在整條閉環的位置、承接與產出

I. 前言:規劃能力是可以被設計的

在 Agent 的四個難點中,難點 ① 與難點 ③ 有一個共通特徵:它們都要求模型在動手之前,先想清楚執行順序。

「先查詢再修改」是順序問題,「狀態逐級推進」也是順序問題。而模型之所以容易在這裡出錯,往往不是因為不懂規則,而是因為它傾向於用最短路徑直接達成目標 —— 使用者說了要核准,那就直接改成 approved。

針對這個問題,Google ADK 提供了 Planner 機制,讓模型在執行工具之前先產生執行計畫。而其中的選擇,會影響到後續的評測與訓練。

以下的內容,將會比較兩種 Planner 的差異、說明為什麼這個系列選擇其中一種,以及如何透過工具的錯誤訊息設計來支援模型的自我修正(Self-Correction)。

II. 兩種 Planner

BuiltInPlanner 與 PlanReActPlanner 的差異

Google ADK 提供了兩種 Planner,而它們採取的路線截然不同 —— 一個依賴模型自身的思考能力,另一個則強制模型輸出結構化的計畫。

BuiltInPlanner:用模型自己的思考能力

from google.adk.planners import BuiltInPlanner
from google.genai import types

planner = BuiltInPlanner(
    thinking_config=types.ThinkingConfig(
        include_thoughts=True,
        thinking_budget=1024,
    )
)

這個 Planner 把規劃工作交給模型內建的思考能力(也就是 Gemini 的 thinking 功能),主要透過兩個參數控制:

  • include_thoughts——要不要把模型的內部推理放進回應
  • thinking_budget——建議模型用多少 thinking token

它的優點是不必額外設計輸出格式,模型如何推理由它自行決定;缺點則是開發者拿不到結構化的計畫,能取得的只有一段自由形式的思考文字。

PlanReActPlanner:強制結構化輸出

from google.adk.planners import PlanReActPlanner

planner = PlanReActPlanner()

它要求模型依固定格式輸出。以「把我那張家庭旅遊的特休直接核准」為例:

/*PLANNING*/
1. 先用 search_leaves 找出那張「家庭旅遊」的特休假單
2. 確認該假單目前狀態
3. 依狀態機規則決定下一個合法狀態
4. 呼叫 update_leave_status

/*ACTION*/
(工具呼叫)

/*REASONING*/
假單目前為 draft,依規則下一個合法狀態是 submitted,
使用者要求「核准」但不能直接跳到 approved。

/*FINAL_ANSWER*/
已將假單送出審核。若要核准,需先由簽核人完成審核。

還有第五個區段 /*REPLANNING*/。它不會出現在順利的流程裡,只有當原本的計畫執行失敗、模型需要重新擬定計畫時才會用到 —— 下一節就會看到它的作用。

對 Leave Copilot 該選哪個

這個系列選 PlanReActPlanner,理由跟後面幾個 Phase 直接相關:

/*PLANNING*/ 區段是可解析的文字。這代表:

  • 評測階段評估時,可以分辨「計畫就錯了」和「計畫對但執行錯了」。這兩種失敗的修法完全不同——前者要改 Instruction,後者可能要改 tool description。
  • 訓練資料階段萃取訓練資料時PLANNINGREASONING 正好對應 Agentic Data 的 Thought 部分。模型不只學「呼叫什麼」,還學「為什麼這樣呼叫」。

如果用 BuiltInPlanner,思考過程雖然也能透過 include_thoughts 拿到,但格式由模型決定,解析起來不穩定。

代價則是 Token 消耗。強制結構化輸出會讓每次回應的長度增加,而 /*PLANNING*/ 區段的內容實際上並不需要呈現給使用者。這筆開銷會在系列尾聲的成本分析中被計入。

III. 自我修正:讓錯誤訊息做工

Day 3 的 update_leave_status 有這樣一段:

raise ValueError(
    f"狀態不可從 {leave['status']} 跳至 {status},"
    f"下一個合法狀態為 {STATUS_ORDER[current_idx + 1]}"
)

當時提到那是刻意的設計,原因就在這裡:工具的錯誤訊息會回到模型手上,因此它有機會讀懂內容並自行修正。

比較兩種寫法:

表格:錯誤訊息、模型能做什麼

第二種寫法讓模型能一次修正。這是用工具設計補償模型能力的典型例子,而且成本極低——就是多寫幾個字。

PlanReActPlanner 在這裡剛好接得上。它注入給模型的指令裡有這麼一句:

If the initial plan cannot be successfully executed, you should learn from previous execution results and revise your plan. The revised plan should be under /*REPLANNING*/. Then use tools to follow the new plan.

也就是說,工具丟回來的錯誤訊息不只是讓模型改一個參數重試,而是讓它把整個計畫重擬一次 —— 而且重擬的內容一樣落在可解析的區段裡。這是選 PlanReActPlanner 的另一個好處:/*REPLANNING*/ 出現幾次,等於這一輪撞了幾次牆,而這個數字是數得出來的。

實測時值得記錄一個數字:同一個錯誤,模型平均需要幾次嘗試才能修正? 這個數字在最後的驗收會有對照組——微調後應該要接近 0,因為正確行為已經內化了。

IV. 重試上限與失敗的分類

自我修正不能無限進行。三個現實理由:

  • 每次重試都是一次完整的模型呼叫,有成本
  • 有些錯誤重試一百次也不會好(例如假單根本不存在)
  • 破壞性操作的重試可能造成實際傷害

實務上要區分可重試不可重試的失敗:

表格:失敗類型、可重試、處理

最後一項是安全問題,不只是效率問題。

使用者拒絕了 cancel_approved_leave,模型如果「換個方式再試一次」——例如改用 update_leave_status 把狀態推回去——那就是用重試機制繞過了使用者的拒絕

這種行為在 Instruction 裡寫了也未必有用(Day 6 已經寫了)。評測階段的基準線會量出它的實際發生率,訓練資料階段會專門為它準備負面訓練樣本。

V. 一個容易忽略的互動

Planner 和 Elicitation 有個微妙的關係。

模型在 /*PLANNING*/ 階段擬定了四步計畫,執行到第三步時使用者 decline 了。這時模型面對的張力是:它有一個未完成的計畫,而計畫的存在本身就是繼續執行的壓力。

實測時要特別留意這個場景,因為它比「單一工具被拒絕」更容易出錯。這也是評測階段設計測試案例時,要刻意安排「多步驟計畫中途被拒絕」的原因。

VI. 結語

Planner 的引入,讓 Agent 從「直接反應」進化為「先規劃再執行」。而這個看似只影響準確率的選擇,實際上會延伸到後續兩個階段。

總結來說,今天有三個重點值得帶走:

  • 選擇 PlanReActPlanner 是為了可解析性: /*PLANNING*/ 區段是結構化的文字,這讓評測階段能夠分辨「計畫本身就錯了」與「計畫正確但執行偏離」—— 這兩種失敗的修正方式完全不同。同時,這些計畫文字正好對應 Agentic Data 中的 Thought,訓練資料階段會直接用到。
  • 錯誤訊息的品質會影響模型的修正能力: 「Invalid status transition」只告訴模型錯了;「狀態不可從 draft 跳至 approved,下一個合法狀態為 submitted」則同時告訴它該怎麼改。這是用工具設計補償模型能力的典型手法,成本極低。
  • 並非所有失敗都適合重試: 參數格式錯誤可以讓模型依錯誤訊息修正,但 Elicitation 被拒絕之後絕對不能重試 —— 那不是效率問題,而是用重試機制繞過了使用者的拒絕,屬於安全事故。

明天處理單一 Agent 的極限,並用權限分離的架構收束這七天。屆時會看到,最可靠的安全防線並不是寫在 Prompt 裡的叮嚀。

Day 9 Cheat Sheet:指令、參數與容易踩的地方


參考來源

  • Google ADK・LLM Agents——BuiltInPlannerThinkingConfiginclude_thoughts / thinking_budget)、PlanReActPlanner 的輸出區段
  • google/adk/planners/plan_re_act_planner.py(google-adk 2.7.1)——五個區段常數,以及 /*REPLANNING*/ 的注入指令原文

查證日期:2026-09-08。本篇兩段 Planner 程式碼與五個輸出區段,都在 google-adk 2.7.1 / google-genai 2.22.0 / Python 3.13 的環境實際建構並比對過原始碼。


I am Simon

大家好,我是 Simon 劉育維,是一位 AI 領域解決方案專家,目前也擔任 Google Cloud AI 領域開發者專家 (GDE),期待能夠幫助企業導入人工智慧相關技術解決問題。如果這篇文章對您有幫助,歡迎在我的 Linkedin 上留言提供意見,並與我一起討論有關人工智慧的主題,期待能夠對大家有所幫助!

我的個人部落格資訊:https://medium.com/@simon3458


上一篇
[ AI Agent ] Day 8 — Session、State 與 Memory:跨呼叫依賴的狀態管理
下一篇
[ AI Agent ] Day 10 — Multi-Agent 協作與權限分離:權限邊界該畫在哪裡
系列文
從 MCP 到專屬 Agentic 模型:30 天走完一條可評測、可微調、可自架的 AI Agent 模型與服務製作流程10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言