AI 工程從零開始|Phase 14 Part 2:Agent 規劃系統 — 從目標到行動計畫

大多數人讓 Agent 直接呼叫工具,期待 LLM 自己想出下一步。 正確答案是:把規劃與執行分開,先產出可驗證的計畫,再逐步執行並動態修正。 差別不是「能不能完成任務」,而是「失敗時能不能恢復,成功時能不能解釋」。 規劃層是 Agent 系統從玩具走向生產的分水嶺。


這篇給已經跑過 ReAct Agent、但被「中途走錯路就回不了頭」卡住的工程師看。讀完你會能說出 ReAct 的四個結構性缺陷、把規劃與執行拆開成 Planner / Executor / Replanner、用帶 pre/post-condition 的 Plan JSON 讓失敗只重寫失敗點之後的步驟,並知道何時值得付 3–4× token 讓 ToT 展開多條路徑、何時 CoT 就夠。


一、核心問題:為什麼 Agent 需要明確的規劃層

1.1 ReAct 的天花板

ReAct(Reason + Act)是目前最普遍的 Agent 架構。模型每次都先思考(Thought),再行動(Action),再觀察(Observation),循環直到任務完成。

這個架構對簡單任務效果不錯,但在複雜任務上暴露出結構性缺陷:

問題一:局部最優陷阱 每一步只看到當前狀態,無法預見三步後的死路。走進死路後,大多數 ReAct 實作只會繼續往前走,而非回頭。

問題二:無法並行 ReAct 是嚴格序列執行:Thought → Action → Observation。即使兩個子任務完全獨立,也必須依序完成,浪費延遲。

問題三:失敗後沒有恢復策略 工具呼叫失敗時,模型只能靠 prompt 裡的指示決定要不要重試。沒有系統性的回滾(rollback)或替代路徑(fallback path)機制。

問題四:無法事前驗證 計畫執行到一半才發現前提條件不成立(例如:所需的 API key 不存在),已經消耗了大量 token 和時間。

1.2 規劃層解決什麼

明確的規劃層把「想清楚要做什麼」和「真正去做」分開,帶來四個核心收益:

問題規劃層的解法
局部最優先展開搜尋樹,評估多條路徑後再執行最優解
無法並行計畫產出 DAG,識別可並行的子任務
無法恢復計畫有版本,失敗後 replan 而非從零開始
無法事前驗證pre-condition 在執行前檢查,不滿足就不執行

關鍵數字:在 WebArena benchmark 上,純 ReAct 完成率約 14%;加入規劃層(Plan-and-Execute)後可達 26–35%;加入動態重規劃後可達 40–50%。複雜度越高的任務,規劃層的收益越大。


二、何時該升級:從 ReAct 到 Plan-and-Execute、再到 ToT 與重規劃的觸發條件

ReAct 把規劃與執行混在同一個 prompt 裡,每步看一次觀察再決定下一步。對三五步、工具穩定的任務,它最便宜也最快;問題出在任務變長以後:走進死路不會回頭、失敗後只能從頭來、前提條件要執行到一半才發現不成立。該把規劃層獨立出來的訊號是:失敗案例裡「中途走錯路」與「工具失敗後放棄」佔大宗、任務平均超過 5–8 步、或是有明顯可並行的子任務卻被序列執行。對應動作是 Planner 先產出帶 depends_on/pre-condition 的 Plan JSON,Executor 逐步執行並在失敗時回報重規劃(§四、§六、§七)。

第二道門檻是計畫本身的品質:當 Plan-and-Execute 的失敗多數來自「線性計畫一開始就選錯路徑」,而 Planner 的 token 預算允許 3–4× 的消耗時,才值得讓 Planner 展開多條候選路徑由 Evaluator 打分(ToT,§三),並把並行執行與備援路徑交給 DAG Executor。ToT 的代價是 token 與延遲,展開過深會爆炸;若 Planner 用的是推理模型,外部再展開 ToT 通常不划算(§八 決策二)。

從到觸發訊號
ReAct(規劃與執行同一 prompt)Plan-and-Execute + pre/post-condition + Replanner失敗以「走錯路、失敗後放棄」為主;任務 > 5–8 步;有可並行子任務
線性 PlanToT Planner(Beam 3–5)+ DAG 並行執行失敗多為計畫一開始選錯路徑;token 預算允許 3–4×
靜態計畫動態重規劃(只重寫失敗點之後)外部環境不可預測(API 掛、資料不存在),且任務不可冪等重跑

三、Chain-of-Thought vs Tree-of-Thought vs Graph-of-Thought

3.1 三種思考結構

Chain-of-Thought(線性鏈)
────────────────────────────
Step1 → Step2 → Step3 → Step4 → 答案
優點:簡單,token 少
缺點:走錯就全錯,無法回頭

Tree-of-Thought(搜尋樹)
────────────────────────────
              目標
            /   |   \
          A1   A2   A3     ← 展開 3 條路徑
         / \    |   / \
        B1  B2  B3 B4  B5  ← 每條路徑再展開
        ✓   ✗   ✗  ✓   ✗  ← Evaluator 評分
        選 B1 或 B4 執行

Graph-of-Thought(知識圖)
────────────────────────────
    A ──────────▶ C
    │             │
    ▼             ▼
    B ──────────▶ D ──▶ E(答案)
    │             ▲
    └─────────────┘
    允許循環、跨路徑共享中間結果
    適合:多跳推理、知識蒸餾

3.2 應用場景對照

維度CoTToTGoT
搜尋策略貪婪(greedy)BFS/DFS/Beam圖搜尋
token 消耗1×3–10×5–20×
失敗恢復無可回溯到父節點可跨路徑共享
實作複雜度低中高
適用任務線性推理多步決策複雜知識整合
生產穩定性高中低(尚在研究階段)

建議:先用 ToT with Beam Width=3;之後視任務複雜度決定是否升級到 GoT。GoT 目前在生產環境的可靠性仍不足,不建議在 2026 年前大規模部署。


四、Plan-and-Execute 架構:規劃與執行分離

4.1 核心流程

┌─────────────────────────────────────────────────────────────┐
│  使用者目標:「幫我分析競爭對手 A 的最新財報,產出摘要報告」    │
└───────────────────────────┬─────────────────────────────────┘
                            │
                ┌───────────▼───────────┐
                │      Planner          │
                │  輸入:目標 + 工具清單  │
                │  輸出:Plan JSON       │
                └───────────┬───────────┘
                            │
                   ┌────────▼────────┐
                   │  Plan Validator │  ← pre-condition 檢查
                   │  • API key 存在?│
                   │  • 工具可用?    │
                   │  • 步驟邏輯正確?│
                   └────────┬────────┘
                            │  通過 ✓
                ┌───────────▼───────────────────────────────┐
                │           Executor                        │
                │                                           │
                │  Step 1: search_web("A 公司 2025 財報")   │
                │      → Observation: [PDF URL]             │
                │                                           │
                │  Step 2: parse_pdf(url)                   │
                │      → Observation: {revenue, profit…}   │
                │                                           │
                │  Step 3: generate_summary(data)           │
                │      → Observation: 摘要文字              │
                │                                           │
                └───────────────────────────────────────────┘
                            │  所有步驟完成
                            ▼
                   最終輸出給使用者

4.2 Plan JSON 結構

 1{
 2  "goal": "分析競爭對手 A 財報",
 3  "steps": [
 4    {
 5      "id": "step_1",
 6      "tool": "search_web",
 7      "args": {"query": "A 公司 2025 年報"},
 8      "depends_on": [],
 9      "pre_conditions": ["internet_accessible == true"],
10      "post_conditions": ["result.url != null"],
11      "retry_limit": 3,
12      "fallback": "search_web_backup"
13    },
14    {
15      "id": "step_2",
16      "tool": "parse_pdf",
17      "args": {"url": "{{step_1.result.url}}"},
18      "depends_on": ["step_1"],
19      "pre_conditions": ["step_1.status == success"],
20      "post_conditions": ["result.revenue != null"]
21    }
22  ]
23}

關鍵設計:

  • depends_on:DAG 邊,讓 Executor 識別並行機會
  • pre_conditions:執行前檢查,失敗則跳過或 replan
  • post_conditions:執行後驗證,失敗則 retry 或 replan
  • fallback:備援工具,不需要完整 replan

五、任務分解:MCTS/BFS/DFS 在 Agent 規劃中的應用

5.1 搜尋演算法比較

BFS(廣度優先)適合:短路徑最優解
───────────────────────────────────
Level 0:              目標
                    / | \
Level 1:          A   B   C
                 /|   |   |\
Level 2:        D E   F   G H
→ 逐層展開,找最短路徑;適合步驟數 ≤ 5 的任務

DFS(深度優先)適合:快速找到可行解
───────────────────────────────────
目標 → A → D → D1 → D2(失敗)
                   → D3(成功,立刻回傳)
→ 找到第一個可行解就停;適合有明確停止條件的任務

MCTS(蒙地卡羅樹搜尋)適合:不確定性高的長序列
───────────────────────────────────────────────
1. Selection:沿 UCB1 分數選擇子節點
2. Expansion:展開未探索的子節點
3. Simulation:快速 rollout 到終止狀態
4. Backpropagation:更新路徑上所有節點的勝率
→ 適合:步驟數 > 8、工具呼叫成本高、需要探索-利用平衡

5.2 在 Agent 規劃中的實際應用

場景推薦演算法原因
程式碼生成(3–5 步)BFS(Beam=3)步驟少,窮舉成本可接受
網頁導航(10–20 步)DFS + 剪枝快速找到可用路徑
研究報告(20+ 步)MCTS高不確定性,需要探索
資料管線(有向無環)Topological Sort已知依賴關係,不需搜尋

MCTS 的 UCB1 公式:

UCB1(v) = wins(v)/visits(v) + C × √(ln(visits(parent)) / visits(v))

其中 C = 探索常數(通常設 1.4)
wins(v) = 此節點成功完成任務的次數
visits(v) = 此節點被訪問次數

在 Agent 規劃中,「wins」定義為子任務成功完成,「rollout」可以用 LLM 快速模擬(通常比真實執行便宜得多)。但要注意:模擬 rollout 正是幻覺「假成功」最容易混入的地方——LLM 會樂觀地假設工具呼叫成功,所以關鍵分支仍應以真實執行或可驗證的檢查確認。


六、動態重規劃:執行失敗後的恢復策略

6.1 失敗分類

失敗類型範例恢復策略
工具暫時失敗API 503指數退避重試(最多 3 次)
工具永久失敗API key 無效切換 fallback 工具
前提條件不成立搜尋結果為空重寫當前步驟的 args
計畫邏輯錯誤步驟順序矛盾觸發完整 replan
目標不可達資料不存在回傳錯誤給使用者

6.2 Replanner 決策樹

子任務失敗
    │
    ├── 重試次數 < 限制?
    │       │
    │       ├── Yes → 指數退避重試(0.5s, 1s, 2s)
    │       │
    │       └── No → 下一步
    │
    ├── 有 fallback 工具?
    │       │
    │       ├── Yes → 切換 fallback,繼續執行
    │       │
    │       └── No → 下一步
    │
    ├── 失敗影響後續步驟?
    │       │
    │       ├── No(獨立步驟)→ 跳過,繼續執行剩餘步驟
    │       │
    │       └── Yes → 觸發 Replanner
    │
    └── Replanner
            │
            ├── 輸入:原始目標 + 已完成步驟 + 失敗原因
            ├── 輸出:修訂後的 Plan(從失敗點往後重寫)
            └── 限制:最多 replan 3 次,超過則回傳失敗

6.3 Replan Prompt 設計

系統:你是一個任務規劃器。

已完成步驟:
- step_1: search_web → 成功,找到 3 篇文章
- step_2: parse_pdf → 失敗,錯誤:PDF 需要密碼

原始計畫的下一步(已無效):
- step_3: extract_data(pdf_content)

請根據以上情況,重新規劃從 step_3 開始的步驟。
約束:
1. 不要重複已完成的步驟
2. 優先使用備援工具
3. 如果目標無法達成,說明原因

輸出格式:Plan JSON(只包含 step_3 之後的步驟)

關鍵指標:成功的 Replan 應在 < 2s 完成(使用較小模型),且不應讓 token 消耗翻倍。建議 Planner 用 GPT-4o,Replanner 用 GPT-4o mini。


七、規劃驗證:Pre-condition/Post-condition 檢查

7.1 靜態 Pre-condition(執行前)

 1class PreconditionChecker:
 2    def check(self, step: PlanStep, context: AgentContext) -> CheckResult:
 3        violations = []
 4
 5        for condition in step.pre_conditions:
 6            if not self._evaluate(condition, context):
 7                violations.append(condition)
 8
 9        if violations:
10            return CheckResult(
11                passed=False,
12                violations=violations,
13                action="replan"  # or "skip" or "abort"
14            )
15        return CheckResult(passed=True)
16
17    def _evaluate(self, condition: str, context: dict) -> bool:
18        # 例:"step_1.status == success"
19        # 例:"internet_accessible == true"
20        # 例:"result.count > 0"
21        return eval_condition(condition, context)

常見 Pre-condition 類型:

  • 環境條件:internet_accessible, api_key_valid
  • 前序步驟:step_N.status == success
  • 資料可用:context.documents.count > 0
  • 資源限制:remaining_budget_usd > 0.10

7.2 動態 Post-condition(執行後)

Post-condition 驗證工具呼叫的結果是否符合預期。失敗時觸發重試或 replan:

步驟執行完成
      │
      ▼
Post-condition 檢查
      │
      ├── 通過 → 繼續下一步,更新 context
      │
      └── 失敗
            │
            ├── 結果部分有效?(e.g., 找到 2/3 筆資料)
            │     → 繼續,但標記為 partial_success
            │
            ├── 結果完全無效?
            │     → 重試(帶不同參數)
            │
            └── 重試後仍失敗?
                  → 觸發 Replanner

示意數字(估算,非實測):Post-condition 檢查通常可攔截 15–20% 的「看似成功但結果錯誤」的工具呼叫(例如:搜尋 API 回傳 200 但結果為空)。


八、為什麼選 X 不選 Y

BFS / DFS / MCTS 的適用場景已在 §五的表格給出,Planner 與 Replanner 用不同大小模型的理由在 §6.3;這裡只留四個真正需要權衡的決策。

決策一:Plan-and-Execute vs 純 ReAct

選擇              選 Plan-and-Execute 的理由        不選純 ReAct 的理由
────────────────────────────────────────────────────────────────────
Plan-and-Execute  規劃與執行分離,失敗可局部重規劃    ReAct:每步都依賴前步,
                  計畫可事前驗證,節省無效執行成本    失敗後只能從頭來
                  並行執行依賴關係明確的子任務        無法事前檢查 pre-condition

Flip condition:任務 ≤ 3 步、不需要工具呼叫時,ReAct 的 overhead 更低。

決策二:ToT vs CoT(規劃用)

選擇    選 ToT 的理由                      不選 CoT 的理由
────────────────────────────────────────────────────────────
ToT     展開多條路徑,Evaluator 選最優       CoT:線性推進,
        任務越複雜,ToT 優勢越大             走錯方向無法回頭
        失敗路徑可快速剪枝,不需真實執行     token 消耗 1×,但任務完成率低

Flip condition:任務步驟 ≤ 4 步、Planner 成本敏感時,CoT 足夠。
Token 消耗:CoT 1×,ToT(Beam=3)約 3–4×。

補充 flip condition:若 Planner 用的是推理模型(o 系列、extended thinking 這類會在內部先做長推理的模型),模型已在內部完成大量 CoT/ToT 式的探索,外部再顯式展開 ToT 通常不划算;此時 ReAct 與 Plan-and-Execute 的差距也會縮小。

決策三:靜態計畫 vs 動態重規劃

選擇        選動態重規劃的理由                不選純靜態計畫的理由
────────────────────────────────────────────────────────────────
動態重規劃  真實環境不可預測(API 掛掉、       靜態計畫:計畫一旦失敗就整體
            資料不存在、權限不足)             失敗,需人工介入
            Replan 只重寫失敗點往後的步驟      成功率在複雜任務上低 25–40%
            已完成步驟不需重複執行

Flip condition:任務可冪等重跑(idempotent)且成本極低時,靜態計畫+全部
重跑比動態 replan 更簡單。

決策四:JSON Plan vs 自然語言 Plan

選擇        選 JSON Plan 的理由               不選自然語言 Plan 的理由
────────────────────────────────────────────────────────────────
JSON Plan   機器可解析,Executor 不需 LLM     自然語言:Executor 需要 LLM
            depends_on 可自動產生 DAG         解析計畫,增加延遲和成本
            版本化、diff 容易                 DAG 無法自動識別
            Pre/post-condition 可程式化       條件檢查需要 LLM 判斷

Flip condition:Planner 無法穩定輸出合法 JSON(常見於較弱的模型)時,
自然語言計畫搭配寬鬆解析器比嚴格 JSON schema 更穩定。

九、系統效應:ReAct vs Plan-and-Execute 數字比較

以下數字為示意估算,用來說明各架構的相對趨勢,並非 WebArena、ALFWorld 等公開 benchmark 的原始結果,也不是實測數據。要引用實際數字,請查閱 Plan-and-Solve、LLMCompiler 等論文的原表。

9.1 任務完成率

架構簡單任務(3 步)中等任務(5–8 步)複雜任務(10+ 步)
ReAct85%62%34%
Plan-and-Execute(靜態)86%78%61%
Plan-and-Execute + Replan87%85%82%
ToT + Replan + 並行88%91%91%

示意估算,非實測數據

9.2 成本與延遲

架構Token 消耗(中等任務)P50 延遲P99 延遲成本/任務
ReAct3,2008s35s$0.032
Plan-and-Execute4,80011s28s$0.048
ToT + 並行執行7,2009s(並行)22s$0.072

示意估算,非實測數據

核心洞察:

  • P99 延遲:Plan-and-Execute 比 ReAct 低 20%,因為失敗後的無效嘗試減少
  • ToT + 並行:雖然 token 多,但並行執行讓 P50 延遲反而低於 ReAct
  • ROI 分析:Plan-and-Execute 的額外成本(+$0.016/任務)在中等任務上帶來 +23% 完成率,CP 值極高

9.3 失敗模式分佈

失敗原因ReActPlan-and-Execute
走入死路無法回頭38%5%
工具呼叫失敗後放棄29%8%
前提條件不成立(未提前驗證)18%2%
計畫邏輯錯誤N/A12%
LLM 幻覺導致錯誤工具呼叫15%11%

示意估算,非實測數據


十、系列導航

← Phase 14 Part 1:Agent 迴圈與記憶系統 — 從單次呼叫到自主行動

→ Phase 14 Part 3:Agent 框架全景 — AutoGen、CrewAI 與自建的取捨


本文為「AI 工程從零開始」系列第 Phase 14 Part 2 篇,聚焦 Agent 規劃系統的架構設計與生產實踐。

Yen

Yen

Yen