跳到主要內容

【2026 最新】Claude Code Ultracode 防爆量:4 道派工煞車教學

最後更新: ·
Claude Code Ultracode 四道派工煞車教學首圖

2026 年 9 月 2 日,Reddit 出現兩則 Claude Code 使用者回報:第一位使用者自述,Ultracode 處理一個大型專案時約產生 300 個 Fable 5.1 agents,且 5-hour allocation 在一分多鐘後耗盡;第二位使用者自述同一個登入流程 i18n 稽核執行兩次,兩張截圖各顯示相同 workflow ID、126 agents,以及約 460 萬與 380 萬 tokens。這些社群自述使用者截圖只支持貼文敘述與 UI 統計,沒有 Anthropic 工程團隊公開確認根因的證據。本文截至 2026 年 9 月 5 日查核時取得的公開材料,仍未包含可核對的 Claude Code 精確版本、完整 workflow JavaScript 與 transcript,以及第三方可重跑環境和結果。

無論兩案根因為何,prompt 裡的「最多 6 個」都不是執行環境的硬上限。本文不靠燒掉一個付費額度來製造戲劇效果,而是教你建立可驗證的四道閘門:准入、原生邊界、原子配額、腳本與預算。截至 2026 年 9 月 5 日,以下設定以 Claude Code 2.1.261 的官方 changelog與現行文件為準。

先搞懂:Ultracode 不是模型,也不是單一「努力等級」

Ultracode 是 Claude Code 的工作模式:依官方 Ultracode 說明,它把 xhigh 推理 effort 與自動 Dynamic Workflow 編排綁在一起。開啟後,Claude 會為有份量的任務規劃 workflow,而且一個請求可能連續產生理解、執行、驗證等多個 workflow。它可以使用Claude Fable 5.1,但「Ultracode」本身不是 Fable 的別名。

把 workflow 想成餐廳的出餐單:同一時間廚房也許只有 16 位廚師,整張單卻能排 126 道菜。官方 runtime 限制目前是單一 Dynamic Workflow 最多同時跑 16 個 agents、單次 parallel()pipeline() 最多放 4,096 個項目、每次 run 累計最多 1,000 個 agents。「同時執行量」與「整次累計派工量」是兩個數字,所以看到 126 或 300 累計 agents,不能解讀成同一秒有 126 或 300 個在跑。

還有兩個看似安全、其實只是提示的數字:使用內建預設 guideline 時,官方在 workflow 超過 25 個 agents 或預估超過 150 萬 tokens 時顯示 Large workflow 警告;若你自行選了 size guideline,其 agent 數會取代 25 這個門檻。警告不會暫停工作,Ultracode 開啟時也不顯示。workflowSizeGuideline=small 代表「目標少於 5 個」,本身仍只是給模型的建議。這就是為什麼你需要多層控制,而不是只改 prompt。若你想先補齊代理概念,可讀Claude Code 子代理與團隊教學

為什麼「小任務」也可能出現大扇出?

可能原因之一,不是檔案數,而是編排腳本裡的乘法。假設第一階段用 4 位掃描者,各自找出一些候選問題;第二階段把去重後的 30 個候選交給兩位獨立 verifier;最後再請 1 位 critic 統整。即使只掃幾個檔案,算術也已是 4 + 30 × 2 + 1 = 65 個 agents。這只是說明機制的假設例子,不是對兩則 Reddit 案例的逆向鑑定。

另一個混淆來自「重試」與「再派工」。官方錯誤文件有記載 API 重試行為,但它在個別 run 的實際計費與 UI 計數,應以該次用量收據核對;同一 subagent 的後續 turns、resume 與建立全新 agent 也不是同一種事件。因此只設定總 agents 仍不夠:數量可以不變,但每位 worker 的 context 很大、回合很多,費用照樣攀升;反過來,很多短小 Haiku workers 也可能仍在可接受預算內。安全策略必須同時回答四題:誰能啟動、最多幾個、每個多貴、最後如何對帳。

Claude Code Ultracode 四道派工閘門流程圖
普通 Agent 與 Dynamic Workflow 走不同控制面;安全方案必須分層。

動手前:先做不啟動 Agent 的基線

先選一個可丟棄的測試 repo,記下 /usage 畫面、目前 effort、模型與 Claude Code 版本。執行:

claude --version
claude update  # 原生安裝版;其他安裝方式請走相應更新渠道
shasum -a 256 .claude/workflows/your-workflow.js  # macOS
# Linux 可改用:sha256sum .claude/workflows/your-workflow.js

更新後重開 session,再用一個只讀、只掃 1 個目錄的小任務驗路徑。不要用正式 repo、不要一開始就給自動寫入權限,也不要把「看起來有停」當成收據;你最後要保存版本、workflow hash、agent 數、token 總量與停止原因。這與AI Agent 可觀測性的核心相同:沒有可追溯事件,就沒有辦法分辨正常扇出、重試與失控。

第一道閘門:不需要 Workflow,就先關閉准入

痛點:日常只改一個檔案時,通常不需要讓 Ultracode 自行編排。解法:回到 /effort high;若專案完全不應啟動 workflow,就設定真正的停用開關。

{
  "disableWorkflows": true
}

你也可在啟動前設 CLAUDE_CODE_DISABLE_WORKFLOWS=1。需要 workflow 的專案則保持開啟,但用後面第三道閘門把每次 Workflow 呼叫改成人工確認。驗收方式很直接:重新開 session 後,ultracode 不再出現在 /effort 選單,workflow 指令也無法啟動。官方完整行為見Dynamic Workflow 停用說明

第二道閘門:用原生設定限制深度、單價與單一 worker

痛點:代理還能再派代理,形成不容易察覺的樹狀擴張。解法:官方 nested subagent 設定,先把巢狀深度降到 1;對不該再派工的 worker,直接從 frontmatter 移除 Agent,或放進 disallowedTools。目前預設可到主對話以下 3 層;設為 1 才是關閉巢狀。

{
  "workflowSizeGuideline": "small",
  "env": {
    "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
    "CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "4",
    "CLAUDE_CODE_SUBAGENT_MODEL": "haiku",
    "CLAUDE_CODE_SUBAGENT_MODEL_FORCE": "1",
    "CLAUDE_AGENT_SESSION_BUDGET": "6"
  }
}

這裡有四個容易踩錯的地方。第一,CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=4 只管普通 Agent 的同時執行數,不是整個 session 的累計上限;官方對普通 Agent 沒有 session 總數上限。Ultracode session 不受此限制,workflow agents 也走自己的限制;/subtask fork 不會被它擋下,resume 既有 subagent 也不先檢查此上限。第二,只設 CLAUDE_CODE_SUBAGENT_MODEL 是預設值,單次呼叫或 agent 定義可以蓋過它;2.1.257 以上搭配 CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 才能強制一般 subagents、teammates 與 workflow agents 使用指定模型,但 fork 與 model: inherit 的 skill worker 仍有官方列出的例外。第三,maxTurns 只限制單一 worker 的 agentic turns,達標後仍可能被 resume;它不是總派工上限。第四,CLAUDE_AGENT_SESSION_BUDGET 與後面測試用的 CLAUDE_AGENT_LEDGER_DB 是本文 hook 自訂變數,不是 Anthropic 內建設定。

---
name: bounded-reviewer
description: 只讀檢查一個檔案並回傳摘要
model: haiku
tools: Read, Grep, Glob
disallowedTools: Agent, Workflow, Write, Edit, Bash
maxTurns: 6
---

只處理交付給你的單一檔案,不再委派。

把它存成 .claude/agents/bounded-reviewer.md,再用 claude plugin validate .claude/agents 檢查 YAML/frontmatter 是否可解析,並另行確認 namedescription 都存在。若你正在做subagent prompt injection 防護,同一個「最小工具權限」原則也能縮小被誘導再派工的範圍。

第三道閘門:PreToolUse Hook 建立直接 Agent 原子配額

痛點:20 個 Agent 呼叫可能同時通過「讀取目前數字,再加一」的文字檔檢查。解法:同步執行 PreToolUse hook,以 session_id 分帳、tool_use_id 去重,並用 SQLite 的 BEGIN IMMEDIATE 做原子預留;第 7 次直接回傳 deny。對 Workflow 則一律回傳 ask,強制進入人工確認,並提示核准者先看 raw script。

#!/usr/bin/env python3
"""為單一 Claude Code session 保守預留直接 Agent 啟動次數。"""
import json
import os
import sqlite3
import sys
from pathlib import Path

def emit(decision: str, reason: str) -> None:
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": decision,
            "permissionDecisionReason": reason,
        }
    }, ensure_ascii=False))

def deny(reason: str) -> None:
    emit("deny", reason)

try:
    payload = json.load(sys.stdin)
    if payload.get("hook_event_name") != "PreToolUse":
        raise ValueError("unexpected hook event")

    tool_name = payload.get("tool_name")
    if tool_name == "Workflow":
        emit("ask", "Workflow 可能在內部派生大量代理;先檢查 raw script、邏輯配額與 SHA-256。")
        raise SystemExit(0)
    if tool_name != "Agent":
        raise SystemExit(0)

    session_id = payload.get("session_id")
    tool_use_id = payload.get("tool_use_id")
    if not isinstance(session_id, str) or not session_id:
        raise ValueError("missing session_id")
    if not isinstance(tool_use_id, str) or not tool_use_id:
        raise ValueError("missing tool_use_id")

    limit = int(os.environ.get("CLAUDE_AGENT_SESSION_BUDGET", "6"))
    if limit < 1:
        raise ValueError("CLAUDE_AGENT_SESSION_BUDGET must be positive")

    override = os.environ.get("CLAUDE_AGENT_LEDGER_DB")
    if override:
        db_path = Path(override)
    else:
        project_dir = os.environ.get("CLAUDE_PROJECT_DIR") or payload.get("cwd")
        if not project_dir:
            raise ValueError("missing project directory")
        db_path = Path(project_dir) / ".claude" / "state" / "agent-budget.sqlite3"
    db_path.parent.mkdir(parents=True, exist_ok=True)

    connection = sqlite3.connect(str(db_path), timeout=2.0, isolation_level=None)
    try:
        connection.execute("PRAGMA busy_timeout=2000")
        connection.execute("BEGIN IMMEDIATE")
        connection.execute(
            "CREATE TABLE IF NOT EXISTS sessions "
            "(session_id TEXT PRIMARY KEY, reserved INTEGER NOT NULL)"
        )
        connection.execute(
            "CREATE TABLE IF NOT EXISTS events "
            "(session_id TEXT NOT NULL, tool_use_id TEXT NOT NULL, "
            " decision TEXT NOT NULL, PRIMARY KEY(session_id, tool_use_id))"
        )

        previous = connection.execute(
            "SELECT decision FROM events WHERE session_id=? AND tool_use_id=?",
            (session_id, tool_use_id),
        ).fetchone()
        if previous:
            connection.commit()
            if previous[0] == "deny":
                deny(f"本次 session 的 Agent 配額 {limit} 已用完。")
            raise SystemExit(0)

        row = connection.execute(
            "SELECT reserved FROM sessions WHERE session_id=?", (session_id,)
        ).fetchone()
        reserved = int(row[0]) if row else 0
        if reserved >= limit:
            connection.execute(
                "INSERT INTO events(session_id, tool_use_id, decision) VALUES(?,?,?)",
                (session_id, tool_use_id, "deny"),
            )
            connection.commit()
            deny(f"本次 session 的 Agent 配額 {limit} 已用完。")
            raise SystemExit(0)

        next_reserved = reserved + 1
        connection.execute(
            "INSERT INTO sessions(session_id, reserved) VALUES(?,?) "
            "ON CONFLICT(session_id) DO UPDATE SET reserved=excluded.reserved",
            (session_id, next_reserved),
        )
        connection.execute(
            "INSERT INTO events(session_id, tool_use_id, decision) VALUES(?,?,?)",
            (session_id, tool_use_id, "pass"),
        )
        connection.commit()
        # 空 stdout:保留 Claude Code 原本的權限判定流程。
    finally:
        connection.close()
except SystemExit:
    raise
except Exception as error:
    # 可解析錯誤回傳 deny;但 command hook 逾時或 Python 不存在仍可能 fail open。
    deny(f"Agent 配額 hook 無法安全判定:{type(error).__name__}")

存成 .claude/hooks/agent_budget.py,再把 hook 加到專案的 .claude/settings.json

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Agent|Workflow",
      "hooks": [{
        "type": "command",
        "command": "/absolute/path/to/python3",
        "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/agent_budget.py"],
        "timeout": 5
      }]
    }]
  }
}

先執行 command -v python3,把上面的 placeholder 換成這台 macOS/Linux 主機實際的 Python 3 絕對路徑,再用 /hooks 確認它來自 Project Settings。這套 ledger 只計算可見的直接 Agent tool calls;目前官方 PreToolUse 規格能證明它可攔 AgentWorkflow 外層呼叫,卻不能據此推定 workflow 腳本內每個 agent() 都會逐一經過同一個 Agent hook。因此它會把未知 workflow 改為人工核准,不會宣稱能單獨封死 workflow 內部扇出。想先熟悉 hook 基礎,可搭配Claude Code Hooks 入門

第四道閘門:Workflow 先預留總量,再核對 hash 與用量

痛點:你核准的是外層 Workflow,真正派幾個 agents 由裡面的 JavaScript 決定。解法:官方 saved workflow 結構,只執行存進 .claude/workflows/、讀過原始碼且 hash 固定的腳本;每次 pipeline() 前,先同步預留完整陣列長度,而不是進 callback 後才慢慢加。

export const meta = {
  name: 'bounded-file-audit',
  description: '最多用 6 個 Haiku agents 稽核指定檔案'
}

const MAX_AGENTS = 6
let reserved = 0

function reserve(count) {
  if (!Number.isInteger(count) || count < 0 || reserved + count > MAX_AGENTS) {
    throw new Error(`agent budget exceeded: ${reserved}+${count}/${MAX_AGENTS}`)
  }
  reserved += count
}

const files = Array.isArray(args?.files) ? args.files : []
reserve(files.length)

const reports = await pipeline(files, file =>
  agent(`只讀稽核 ${file},回傳問題與行號,不得再委派。`, {
    label: file,
    model: 'haiku'
  })
)

return { reserved, completed: reports.filter(Boolean).length, reports }

這個 MAX_AGENTS 是腳本的邏輯配額,能避免前面假設的「30 個發現 × 每項 2 位 verifier」在不知不覺間展開;它不等於 token 或美元上限,也不會把模型 API 內部重試當成新 agent。核准前執行 shasum -a 256;若核准畫面提供 View raw script 就查看,否則直接開啟 Claude Code 回報的 session script path,確認陣列來源、迴圈、agent() 次數與 hash。

若你用 API 計費的非互動模式,可加 claude -p --max-budget-usd 5.00 "你的任務";官方說 subagent 花費會計入,達到門檻後後續派工失敗並停止背景 agents。不過 -p 不會顯示 terminal 核准畫面,因此本文 hook 對 Workflow 回傳的 ask 不能在無人值守時完成核准。只跑普通 Agent 的 job 可直接停用 workflow;確實需要 workflow 自動化時,應由 --permission-prompt-tool 或 Agent SDK host 驗證已保存的名稱、內容與 hash,再對該次呼叫核准,不能把所有 Workflow 一律 allow。這個美元門檻是在花費到達後執行停止,也不是預先凍結 5 美元的精準儲值卡。

訂閱制互動使用者則以 /workflows 觀察每階段 agent 數、tokens 與時間,異常時按 x 停止,完成後截取 /usage。更多降低單次工作的做法可看Claude Code 省 token 指南

故障注入:不燒模型額度,也能先驗決策層

我們在 2026 年 9 月 5 日以合成 PreToolUse JSON 對上述完整版 hook 做離線測試,沒有啟動 Claude agents,也沒有聲稱重現社群的 126/300 個案例。20 個執行緒同時競爭同一 session,SQLite ledger 原子保留 6 次、拒絕 14 次;重送相同 tool_use_id 不重複扣額;Workflow 得到 ask;缺欄位與損毀 ledger 都得到 deny。測試腳本與收據分別以 SHA-256 固定,讓結果可稽核,而不是靠截圖印象。

Claude Code PreToolUse Hook 離線故障注入收據
離線只驗證 hook 決策與原子計數;不等同實際啟動 126 或 300 個 agents。

上線前再依序注入四種故障:第一,讓 20 個直接 Agent 呼叫競爭,確認取得配額者不超過 6 個,正常無錯誤路徑應為 6 個;第二,要求 bounded worker 再派工,確認深度與工具清單擋下;第三,讓 workflow 輸入陣列超過 6,確認腳本在任何 agent() 前拋錯;第四,停止一個進行中的 workflow 再 relaunch,核對哪些工作被重跑。官方 resume 說明指出:停止整個 run 時仍在執行的 agents 會重新開始;已完成結果通常會沿用,但腳本或前序結果改變時,該點之後也會重跑。若單獨停止/失敗一個 agent,該 agent 與之後啟動的 agents 會再跑。因此收據應記「每次 run」與「跨 run 累計」兩組數字。

每次核准前後,留下同一張用量收據

真正能讓團隊重跑與追責的,不是一句「應該只有 6 個」,而是一份結構固定的紀錄。核准前保存 claude --version、effort、主模型、workflowSizeGuideline、測試 repo commit、workflow 路徑與 SHA-256;執行時記錄 run ID、人工核准者、邏輯預留數與停止條件;完成後從 /workflows 留下各階段 agent 數、token 總量、耗時、失敗與重啟事件,再以 /usage 比對前後差額。

若實際數字超過腳本宣告的預留量,先停,不要立刻 relaunch。依序比對執行中的 raw script 是否仍與核准 hash 相同、是否有另一個 workflow run、是否是既有 agent resume,以及強制模型有沒有被組織 allowlist 替換。這份收據讓你把「模型感覺失控」拆成可以定位的控制面差異,也避免在沒有版本與腳本的情況下把責任先歸到某個模型。

這套做法仍有哪幾個洞?

  • Command hook 可能失效:逾時、執行檔不存在或輸出格式錯誤時,不應把它當唯一安全邊界。官方文件明確指出 PreToolUse 的 Agent SDK callback 逾時會阻擋,但一般 command hook 的錯誤路徑不同;因此深度、工具權限、workflow 腳本配額與預算要先兜底。
  • Resume 不一定產生新的 Agent 呼叫:既有 subagent 的後續訊息與恢復工作,不能只靠「啟動次數」代表完整 token 成本。
  • 配額資料庫要有生命週期:本文用 session_id 分帳,不應靠手動刪檔重設。團隊環境要加入保留期限、權限與磁碟監控。
  • 模型便宜不代表任務便宜:代理數、每個 agent 的 turns、context 大小、重試與 cache 行為都影響總用量。要同時限制數量、單價與工作範圍。

所以最實用的心法不是「找到一個神奇環境變數」,而是:安全派工 = 先准入 × 再配額 × 限單價 × 留收據。這也正是AI Agent Harness的工程思維:模型負責提出行動,執行層負責決定它能不能發生。

常見問題

1. Prompt 寫「最多 6 個 agents」夠嗎?

不夠。那是模型應遵循的意圖,不是 runtime 的確定性配額。至少再加 workflow 腳本預留或直接 Agent 的原子 ledger。

2. workflowSizeGuideline=small 是硬上限嗎?

不是。官方把它定義為寫 workflow 時的建議;small 目標少於 5 個,但任務提示仍可讓模型選擇不同規模。

3. CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS 能擋 Ultracode 嗎?

不能當作 Ultracode 總閘門。官方文件說 Ultracode session 豁免這個普通 Agent 同時執行限制,workflow agents 另走 workflow runtime。

4. maxTurns 能限制總 agent 數嗎?

不能。它限制單一 subagent 在回傳 partial 前的 agentic turns;該 agent 之後還可能 resume。

5. 直接把所有 subagents 指到 Haiku 就安全了嗎?

只能降單價,不能限制數量。請用 /tasks 核對實際 resolved model,並保留數量與 turns 閘門。

6. PreToolUse Hook 能逐一計算 Workflow 裡的 agents 嗎?

不要這樣假設。目前官方文件足以支持攔截外層 Workflow,但本文沒有找到可證明內部每個 agent() 都映射成同一條可阻擋 Agent hook 的規格;因此內部總量要寫在腳本。

7. 停止 Workflow 後再重開,會從零開始嗎?

不一定。同一 session 可沿用已保存結果,但失敗或當時仍在跑的 agents 可能重跑;腳本或前序結果改變也會使後續工作重跑。

8. Reddit 的 126/300 agents 證明 Fable 5.1 有 bug 嗎?

不能證明。它們是值得追查的原始使用者回報,但本文截至 2026 年 9 月 5 日查核時取得的公開材料,未包含可核對的精確版本、完整 workflow JavaScript/transcript 與第三方重跑證據。可採取的工程結論是:不要把成本安全寄託在模型自行節制,而不是先替故障來源定罪。

接著閱讀

左右滑動查看更多推薦

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

每週最多三封:一封 Weekly 週報與最多兩封關鍵 Alpha Signal。

我們不會 spam,隨時可退訂。