# 背景 agent 的狀態摘要花多少：按 query_source 歸因模型呼叫的 token 與費用

> 一份公開量測回報 Claude Code 背景摘要佔估算費用 16.4%、request 數 19.7%。本文示範按用途歸因 OTel 事件，並說明量測期間與分母不同時，佔比為何不能直接比較。

原文：https://sheng.page/posts/background-agent-summary-cost/ · 發布：2026-11-03 · 作者：Sheng

十月底一份 gist 在 HN 上引起討論，作者回報 Claude Code 約每 30 秒把互動模式下正在工作的背景 agent transcript 送回模型，產生由 3 到 5 個詞組成的狀態文字。在他的一週資料裡，這類呼叫佔估算費用 16.4%、API request 數 19.7%，停用方法的測試版本涵蓋 2.1.257 到 2.1.312。數字來自該作者的 OpenTelemetry 匯出，適用於其他環境與版本之前，仍需驗證。

要查自己的工作流有多少摘要開銷，得先按用途分類模型 request，再分別計算 request 數、token 與估算費用，帳單也要另外對照。若量測期間或工作量不同，佔比就不能直接比較。後面的合成資料會示範計算方式，以及換時間窗後數字會怎麼變。

本站〈[估 AI prototype 的時程要拆兩段](/posts/ai-prototype-to-production-cost/)〉和〈[AI code review 的帳怎麼算](/posts/ai-code-review-cost-benefit/)〉列為 AI 工作流總成本的延伸閱讀，頁面目前無法讀取，內容仍需驗證；這篇將總額按用途拆開。

## 一、公開量測說了什麼

gist 的標題是「Claude Code burns ~15–20% of your tokens on a 3-word status line」，作者 flamerix-ai，在 Linux 上測，版本 2.1.257 到 2.1.312。他描述的行為是：互動模式下正在工作的背景 agent 約每 30 秒被要求「describe your most recent action in 3-5 words」，每次都把該 agent 的完整 transcript 送給它自己用的模型。他將結果描述為只用來更新 agents 面板上的狀態列；是否也供其他流程使用，仍需驗證。他說這個行為從 2.1.232 起對互動模式下正在工作的背景 agent 預設開啟，間隔由伺服器端調整，範圍 30 到 240 秒，預設就是最小值。

他的數字是一張前後對照表，「裝 hook 前一週」與「裝 hook 後兩天」：

- 佔 Claude Code 總估算費用：前 16.4%（主對話是 15.7%），後 0%。
- 佔全部 API request：前 19.7%，後 0%。
- 這些摘要 request 的 input 對 output 比約 9,000 比 1，96% 的費用花在 Opus。
- 週佔比的歷史：七月 3.5% 到 7%，升到 2.1.233 後 7.3% 再到 11.8%，十月中約 16%。

這份量測有幾個限制。費用是 Claude Code 每個 request 自己估的 `cost_usd`，不是帳單；它對訂閱方案的額度與實際支出有何影響，還得依方案另行確認。作者也回報這些 request 未出現在磁碟上的 session log，是靠 OpenTelemetry 匯出才看見的，所以他是把 `claude_code.api_request` 事件按 `query_source` 分組後，才發現 `agent_summary` 這一類比主對話還貴。

gist 提出的停用方法是一支 Bun `--preload` 腳本，只包住全域的 `setTimeout`，callback 原始碼裡含有「[AgentSummary] Timer fired」這類錨點字串就回一個 2³¹−1 毫秒的閒置計時器，其他計時器照常。Claude Code 的執行檔沒有被改，裝法是設 `BUN_OPTIONS=--preload=<path>` 再 `claude daemon stop --any`。作者自己列的風險是 fail-open：比對靠的是原始碼文字，改個 log 字串、搬個函式、或計時器不再走全域 `setTimeout`，摘要就會無聲地回來，所以他要求裝完要驗證。這是作者提出的非官方攔截方式；他回報當時沒有專用的關閉設定，現行版本需驗證。作者另稱 `CLAUDE_CODE_FORK_SUBAGENT=0` 和 `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` 也能停掉摘要，代價是 fork subagent 或背景 agent 一起沒了。

gist 另外描述 SDK 的行為：摘要可用 `agentProgressSummaries: true` 或環境變數 `CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES` 開啟，開了之後摘要以 `task_progress` 的 stream-json 事件送出，所以你要是有程式在吃這個事件，關摘要之前得先查清楚誰在用。作者未測 ACP adapter，SDK 的現行行為也需驗證。

gist 裡引用了 GitHub issue #86879，說那裡集了四份獨立量測，落在 18% 到 26%。打開 issue 看，本文是一個 4 小時的 session，2.1.233、macOS、27 個 subagent、1,496 個 request，`agent_summary` 佔 request 數 22.7%、原始 token 22.2%、按費率加權後的 token 18.0%。底下一則留言是 2.1.276、Linux、1 小時 45 分的互動 session，報的是「佔 session cache-read token 的 26%」。所以那個 18 到 26 的範圍，兩端用的是不同分母，一端是加權 token，另一端是 cache-read token，中間還夾著 request 佔比，版本和時長也都不同。這些量測的分母不同，不能合併成一個通用的成本區間。

本文沿用的 HN 討論串快照記錄了 562 點、227 則留言，擷取時間需驗證。有人依程式碼判讀，稱摘要呼叫是對話的暫時分支，可以使用 prompt cache，約每 30 秒一次；另一位 20x Max 使用者估算的佔比約為 16%，但註明是依 30 秒計時器推估。這些數字只能當使用者回報，能否對上帳單仍需驗證。

## 二、統計單位先定好

要自己量，第一件事是決定什麼算一個單位。合理的單位是一個模型 request，也就是一筆 `claude_code.api_request` 事件，按它的用途歸類。工具執行和 agent 之間傳訊息不一定各自對應一次 request，若混用 tool call、訊息與 request 數，統計單位就不一致，也可能重複計算。

第二件事是四個量分開報，不互相代換：

- request 數：看的是頻率。摘要若每 30 秒呼叫一次，可能佔不少 request，但仍要看其他工作的呼叫頻率。
- token 數：還要再分 `input_tokens`、`output_tokens`、`cache_read_tokens`、`cache_creation_tokens`。若摘要送出整份 transcript 並大量命中 cache read，原始 token 佔比可能較高，費用佔比則受 cache read 費率影響，不能只看 token 總數。
- 估算費用：`cost_usd` 是工具按模型費率算的估計，模型不同、cache 命中與否都會讓它和 token 不同步。
- 帳單：實際支出要依付費方式確認，API 用量計價與訂閱額度的意義不同，不能直接拿估算費用當作扣款。

上面 issue 裡那組數字正好是例子，同一個 session 裡 request 佔比 22.7%、原始 token 22.2%、加權 token 18.0%，這是該作者回報的不同指標，不能互換。

失敗與重試的計法也要先定。重試算一個 request 還是兩個，`api_error` 事件要不要併進去，先定好再分組，不然前後兩次量測會對不起來。

## 三、怎麼量

Claude Code 的 Monitoring usage 文件寫了怎麼開 OpenTelemetry，設 `CLAUDE_CODE_ENABLE_TELEMETRY=1`，再用 `OTEL_LOGS_EXPORTER` 和 `OTEL_METRICS_EXPORTER` 選 exporter。事件名稱是 `claude_code.<event>`，和這篇有關的是 `api_request`，文件列的屬性包括 `model`、`cost_usd`、`cost_usd_micros`、`duration_ms`、`input_tokens`、`output_tokens`、`cache_read_tokens`、`cache_creation_tokens`、`request_id`、`speed`、`effort`，以及 `query_source`，文件給的例子是 `"repl_main_thread"`、`"compact"`，或者一個 subagent 的名字。另外有彙總的 metrics，`claude_code.token.usage` 帶 `type` 屬性（`input`、`output`、`cacheRead`、`cacheCreation`）和 `model`，`claude_code.cost.usage` 帶 `model`，兩者也都帶 `query_source`，但目前文件中的 metrics 分類較粗，不能直接拿來區分摘要呼叫。本文按逐筆事件歸因，使用 metrics 前仍須確認分類粒度。

`input_tokens` 在文件裡不含 cache read 與 cache creation。若要算整筆 request 的輸入與輸出 token 總量，才把四個欄位相加；這個總和包含輸出，不能稱作送入模型的 token。只看 `input_tokens`，則會漏掉快取相關的輸入。

沒有 `query_source` 可用時（舊版本，或別的工具），用間隔固定、prompt 越來越長這種特徵去找候選 request，只能當線索。gist 作者是靠 `query_source` 分組才確定的，用特徵猜出來的那一堆，裡面混了什麼沒人知道，費用算出來也只能標成「疑似」。找不到歸類的 request 另外列一行「未知」，別硬塞進某一類。

下面是用合成資料做的示範，欄位名沿用文件的 `api_request` 事件，記錄格式經過簡化，數字與費率都是示範用的假設值，只用來示範計算方式，不能把真實匯出檔直接套入。先產生七天的紀錄：主對話每天 4 小時，約每 60 秒一個 request；每天開 0 到 6 個背景 agent，各跑 1 小時，約每 45 秒一個 request；每個 agent 另外每 30 秒一筆 `agent_summary`，input 很小、output 很小、`cache_read_tokens` 隨 transcript 長大。seed 固定為 42。

```python
# 產生合成的 api_request 紀錄（欄位名照 Claude Code OTel 文件），寫成 JSONL
import json, random
random.seed(42)
RATE = {"in": 5.0, "out": 25.0, "cr": 0.5, "cc": 6.25}   # USD / 1M tokens，假設值，不是牌價
DAY = 86400
PLAN = [3, 1, 1, 0, 2, 6, 5]   # 七天，每天開幾個背景 agent（各跑 1 小時）

def req(t, source, inp, out, cr, cc):
    cost = (inp*RATE["in"] + out*RATE["out"] + cr*RATE["cr"] + cc*RATE["cc"]) / 1e6
    return {"event.name": "api_request", "event.timestamp": t, "model": "synthetic-model",
            "query_source": source, "input_tokens": inp, "output_tokens": out,
            "cache_read_tokens": cr, "cache_creation_tokens": cc, "cost_usd": round(cost, 6)}

rows = []
for day, n_agents in enumerate(PLAN):
    t0 = day * DAY + 9 * 3600
    for k in range(240):                                   # 主對話：約每 60 秒一次，4 小時
        rows.append(req(t0 + k*60 + random.randint(0, 20), "repl_main_thread",
                        random.randint(500, 3000), random.randint(100, 800),
                        100000 + 300*k, random.randint(0, 4000)))
    for a in range(n_agents):
        ta = t0 + 600 + a * 300
        ctx = 20000
        for k in range(80):                                # agent 本身：約每 45 秒一次，1 小時
            ctx += random.randint(1500, 4000)
            rows.append(req(ta + k*45, f"agent-{a}", random.randint(300, 2000),
                            random.randint(100, 600), ctx, random.randint(0, 3000)))
        for k in range(120):                               # 狀態摘要：每 30 秒一次，讀整份 transcript
            rows.append(req(ta + k*30 + 5, "agent_summary", 60, random.randint(5, 20),
                            15000 + k * 1000, 0))
rows.sort(key=lambda r: r["event.timestamp"])
with open("requests.jsonl", "w") as f:
    for r in rows:
        f.write(json.dumps(r) + "\n")
print(len(rows), "requests written")
```

```text
5280 requests written
```

接著按 `query_source` 分組，subagent 本身的 request（`agent-0`、`agent-1`⋯）併成一類，算 request 數、各類 token 和估算費用，最後把三種佔比並排：

```python
# 按 query_source 分組：request 數、各類 token、估算費用，三種佔比並排
import json, collections
agg = collections.defaultdict(lambda: collections.Counter())
for line in open("requests.jsonl"):
    r = json.loads(line)
    src = "subagent" if r["query_source"].startswith("agent-") else r["query_source"]
    c = agg[src]
    c["requests"] += 1
    c["input"] += r["input_tokens"]; c["output"] += r["output_tokens"]
    c["cache_read"] += r["cache_read_tokens"]; c["cache_creation"] += r["cache_creation_tokens"]
    c["cost_usd"] += r["cost_usd"]
total = collections.Counter()
for c in agg.values():
    total.update(c)
total["tokens"] = total["input"] + total["output"] + total["cache_read"] + total["cache_creation"]
print(f"{'query_source':17}{'requests':>9}{'input':>10}{'output':>9}{'cache_read':>13}{'cost_usd':>10}")
for src, c in sorted(agg.items(), key=lambda kv: -kv[1]["cost_usd"]):
    print(f"{src:17}{c['requests']:9}{c['input']:10}{c['output']:9}{c['cache_read']:13}{c['cost_usd']:10.2f}")
print()
for src, c in agg.items():
    tokens = c["input"] + c["output"] + c["cache_read"] + c["cache_creation"]
    print(f"{src:17} requests {c['requests']/total['requests']:6.1%}   "
          f"tokens {tokens/total['tokens']:6.1%}   cost_usd {c['cost_usd']/total['cost_usd']:6.1%}")
```

```text
query_source      requests     input   output   cache_read  cost_usd
repl_main_thread      1680   2973883   748500    228228000    168.62
subagent              1440   1629914   506539    188531520    129.02
agent_summary         2160    129600    26923    160920000     81.78

repl_main_thread  requests  31.8%   tokens  39.9%   cost_usd  44.4%
subagent          requests  27.3%   tokens  32.7%   cost_usd  34.0%
agent_summary     requests  40.9%   tokens  27.3%   cost_usd  21.6%
```

同一類 request，三種佔比是 40.9%、27.3%、21.6%。在這份資料裡，摘要呼叫較頻繁，但每筆 token 量較少，token 又以 cache read 為主，因此費用佔比更低。這是合成資料的結果，只用來示範不同分母會得到不同數字，不能據此預測其他工作流的開銷。

## 四、分母不同，佔比就不能比

gist 比較「一週」與「兩天」的資料，作者回報停用後摘要佔比為 0%。這個 0 代表那段量測中沒有記到摘要呼叫，還不能直接推出「總費用省了 16.4%」。兩段期間的工作量、背景 agent 用量與 cache 情況是否可比，都需驗證。

用同一份合成資料換三個時間窗算一次：

```python
# 同一份紀錄，量測期間不同，agent_summary 的佔比會差很多
import json, collections
DAY = 86400
rows = [json.loads(l) for l in open("requests.jsonl")]

def share(lo_day, hi_day):
    win = [r for r in rows if lo_day*DAY <= r["event.timestamp"] < hi_day*DAY]
    cost = sum(r["cost_usd"] for r in win)
    summ = sum(r["cost_usd"] for r in win if r["query_source"] == "agent_summary")
    agent_hours = sum(1 for r in win if r["query_source"].startswith("agent-")) * 45 / 3600
    return cost, summ, agent_hours

for name, lo, hi in [("第 1 到 7 天", 0, 7), ("第 3 到 4 天", 2, 4), ("第 6 到 7 天", 5, 7)]:
    cost, summ, ah = share(lo, hi)
    per_day = cost / (hi - lo)
    per_ah = summ / ah if ah else float("nan")
    print(f"{name}: 總費用 {cost:7.2f}  每天 {per_day:6.2f}  摘要佔比 {summ/cost:6.1%}"
          f"  agent 小時 {ah:5.1f}  摘要費用/agent 小時 {per_ah:5.2f}")
```

```text
第 1 到 7 天: 總費用  379.43  每天  54.20  摘要佔比  21.6%  agent 小時  18.0  摘要費用/agent 小時  4.54
第 3 到 4 天: 總費用   59.55  每天  29.77  摘要佔比   7.6%  agent 小時   1.0  摘要費用/agent 小時  4.54
第 6 到 7 天: 總費用  176.83  每天  88.41  摘要佔比  28.3%  agent 小時  11.0  摘要費用/agent 小時  4.54
```

這份合成資料裡，摘要固定每個 agent 每 30 秒一筆，但第 3 到 4 天的佔比是 7.6%，第 6 到 7 天是 28.3%，整週則為 21.6%，差別來自各天的 agent 用量。即使假設第 3 天停掉摘要，再拿第 6 到 7 天的總費用比較，也不能只憑總額判斷停用是否有效；這些時間窗原本就有不同工作量。

最右邊是摘要費用除以背景 agent 執行小時，在這份合成資料的三個時間窗都約為 4.54，因為每個 agent 套用相同的摘要頻率與 token 模型。實際工作流是否也能用這個比率估算，需驗證，不能直接套用別人的 16.4%。量測時可以記錄同時存活的 agent 數與各自執行時間，並分清楚累計建立數和同時存活數；計時器的觸發條件也要依工具版本確認。

## 五、關掉之前要比對什麼

就算量到了，決定關不關之前還有幾件事：

- 固定條件多跑幾次。同一份任務、同一個模型、同一版工具，各跑幾輪再比，單次重跑會被 prompt cache 命中率和執行路徑的差異蓋過去。
- 除了費用，也記完成品質和執行時間。摘要是否只用來顯示狀態需驗證；若確實不供其他流程使用，可能不影響結果，但 gist 的關法改的是計時器，有沒有副作用要自己驗。
- 先查狀態顯示有沒有其他消費端。終端面板只是其中一個，SDK 的 `task_progress` 事件是另一個，若有自動化流程依賴它，停用就可能影響其他工作。
- agent 讀過哪些檔案，不等於那些檔案整份都送出去了。摘要 request 送的是 transcript，可先檢查 `api_request_body` 事件（要開 `OTEL_LOG_RAW_API_BODIES`），但匯出內容本身也可能截斷或遮蔽，不能一律當成完整 payload；issue 作者回報使用這項功能擷取資料。

收件端也要依實際設定確認。按公開量測的描述，摘要送往處理該 agent 的模型 API；即使服務提供者相同，也不能據此排除資料處理上的影響。實際送出的 transcript、截斷方式與接收端是否符合預期，仍需驗證。

## 補充筆記

- 公開量測來自單一作者，其停用方法測試涵蓋版本 2.1.257 到 2.1.312：`agent_summary` 佔估算費用 16.4%、request 數 19.7%，費用是工具自估的 `cost_usd`，不是帳單。
- GitHub issue 裡的 18% 到 26% 分別是加權 token 佔比與 cache-read token 佔比，分母不同，版本與時長也不同，不是同一個量。
- 以 `claude_code.api_request` 事件為單位、按 `query_source` 歸因；request 數、token、估算費用、帳單四個分開報。
- 合成資料裡同一類 request 的 request、token、費用佔比是 40.9%、27.3%、21.6%，差距來自頻率高與 cache read 便宜。
- 量測期間不同，佔比從 7.6% 到 28.3% 都算得出來；每 agent 執行小時的摘要費用只在這個合成模型裡近似固定，實際是否適用仍需驗證。
- 關掉前固定條件多跑幾次，也記品質與時間，並先查 SDK 的 `task_progress` 有沒有人在用。

## 延伸閱讀

- flamerix-ai〈[Claude Code burns ~15–20% of your tokens on a 3-word status line. Here's how to turn it off](https://gist.github.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce)〉：該作者量測數字、測試版本範圍、量測期間與 Bun preload 關法的出處；issue 回報與本文合成資料另行區分。
- Claude Code 文件〈[Monitoring usage](https://code.claude.com/docs/en/monitoring-usage)〉：OpenTelemetry 的啟用方式、`api_request` 事件的屬性名稱、`token.usage` 與 `cost.usage` metrics，本文欄位名都照這份。
- GitHub issue〈[Feature request: a supported way to disable the agent_summary spinner](https://github.com/anthropics/claude-code/issues/86879)〉：另一份 4 小時 session 的量測（22.7% request、18.0% 加權 token）與留言裡的 26% cache-read token。
- HN 討論串〈[Claude Code regularly sends each background agent's transcript to its model](https://news.ycombinator.com/item?id=50284255)〉：其他使用者的回報與對 prompt cache 的討論，參考用，沒有帳單層級的證實。
- 本站〈[估 AI prototype 的時程要拆兩段：從零到可展示，從可展示到上線](/posts/ai-prototype-to-production-cost/)〉：原稿列為 AI 工作流總成本估算的參考，頁面目前無法讀取，內容仍需驗證。
- 本站〈[AI code review 的帳怎麼算：找到的 bug、誤報和人的時間](/posts/ai-code-review-cost-benefit/)〉：原稿列為多 agent review 成本估算的參考，頁面目前無法讀取，內容仍需驗證。

> 想法與技術判斷出自 Sheng，和 Claude 一起起草 · 題目由 Sheng 選定，內文、案例整理與範例由 Claude 撰寫，範例在 Linux 上以 Python 3.13.18 實測。