# Day 18 - 一輪對話要花多少錢

> 從 API 回傳的 usage 計算每輪 input、output token 與累計費用，再用實際對話觀察 context 變長時，stateless API 如何讓每一次請求的成本跟著增加。

Published: 2026-10-02
URL: https://kaochenlong.com/measure-agent-token-costs

---

前面好幾天一直在講「這個很花錢」，但 KeSi 本身到現在都還不知道自己會花多少錢。今天幫 KeSi 裝一個電表，每跑完一輪就把這一輪的花費印出來，再實際跑一場八輪的對話，看看帳單長什麼樣子。

GitHub Repo：[&lt;u&gt;https://github.com/kaochenlong/KeSi&lt;/u&gt;](https://github.com/kaochenlong/KeSi)

## **token 怎麼算？**

API 的費用是照 token 算的，模型讀文字的時候不是一個字一個字讀，而是先把文字切成一小塊一小塊，每一塊就是一個 token，負責切的那個東西叫做 tokenizer。例如 `Hello, how are you today?` 這句英文，Claude 的 tokenizer 會算成 7 個 token，跟 5 個單字加 2 個標點的數量剛好一樣，不過 Anthropic 沒有公開它實際切在哪裡，我們只量得到總數。中文也不是一個字就是一個 token，我用同樣的方法單獨量了幾個字，扣掉每個請求固定會有的 token 之後：

| 內容 | 字數 | token |
| --- | --- | --- |
| 你 | 1 | 2 |
| 檔 | 1 | 3 |
| 鑰 | 1 | 4 |
| 你好 | 2 | 3 |
| 檔案 | 2 | 4 |
| 你好，你今天過得如何？ | 11 | 12 |
| 請讀取這個檔案並告訴我它在做什麼。 | 17 | 22 |

單獨一個字就可能算成 2 到 4 個 token，每個字不一樣。而且 token 數不能一個字一個字加起來，「你」跟「好」單獨量都是 2，合在一起的「你好」卻只有 3，tokenizer 會看前後文決定怎麼切。整句來看，這兩句的 token 數都比字數多一些，但多多少要看句子裡是哪些字。

你送進去的內容算 input token，模型寫出來的回答算 output token，兩種 token 的計價方式不一樣。以待會跑的第一輪為例，我問 KeSi「這個專案在做什麼？」，它開了幾次工具讀檔案才回答，這一輪送出去的 system prompt、工具說明書、我的問題跟讀進來的檔案內容，加起來是 16,227 個 input token，KeSi 寫出來的回答跟工具呼叫是 530 個 output token。照 Haiku 4.5 的價錢，input 每百萬 token 1 美元、output 每百萬 token 5 美元，這一輪就是 0.0162 加 0.0027，大約 0.0189 美元。

同樣的意思，換一種語言寫，切出來的 token 數可能就不一樣。我在 `examples/day18/demo.py` 用官方免費的 [&lt;u&gt;Token Counting API&lt;/u&gt;](https://platform.claude.com/docs/en/build-with-claude/token-counting) 量了三組中英文，這支程式的後半段也會拿來跑整場八輪對話：

```
uv run --env-file .env examples/day18/demo.py
```

```
# 1. 同樣的意思，中文跟英文各算幾個 token
​
  每個請求的包裝：7
  [英] Hello, how are you today?  →  7
  [中] 你好，你今天過得如何？  →  12
​
  [英] Please read the file and tell me what it does.  →  11
  [中] 請讀取這個檔案並告訴我它在做什麼。  →  22
​
  [英] def add(a, b):\n    return a + b  →  13
  [中] def 相加(甲, 乙):\n    return 甲 + 乙  →  23
```

第一行的 7 是不管內容是什麼，每個請求都會多出來的固定 token，只送一個字母 `x` 也要算 8 個 token，扣掉 `x` 本身就是 7，後面每一組都已經先扣掉這 7 個。在這三組短句裡，中文大約是英文的 1.7 到 2 倍。第三組是同一段程式碼，只是把函式名稱跟參數名稱從英文換成中文，token 就從 13 變成 23。

不過這個倍數不用背，換成長一點的文件或是程式碼，比例都可能不一樣。要估某一份 system prompt 或某一段程式碼要花多少 token，最準的做法還是拿實際的內容去量。

量的時候，不要拿別家的 tokenizer 來算。OpenAI 出的 token 計算套件 `tiktoken` 很方便，但它切字的方式跟 Claude 不一樣，算出來的數字對不上。Claude 的話就用官方的 Token Counting API，[&lt;u&gt;文件&lt;/u&gt;](https://platform.claude.com/docs/en/build-with-claude/token-counting#pricing-and-rate-limits)是這樣寫的：

&gt; *Token counting is free to use but subject to requests per minute rate limits based on your usage tier.*

也就是用它量 token 不用錢，只是每分鐘能呼叫的次數有限制。

不過它算出來的是估計值，[&lt;u&gt;文件&lt;/u&gt;](https://platform.claude.com/docs/en/build-with-claude/token-counting#how-to-count-message-tokens)裡有這一段：

&gt; *Token counts may include tokens added automatically by Anthropic for system optimizations. You are not billed for system-added tokens. Billing reflects only your content.*

意思是量出來的數字裡，可能包含 Anthropic 自動加上的 token，這些 token 不收錢，所以量出來的數字可能比實際收費多一點。真正的帳要看每次 API 回應裡附的用量紀錄 `usage`，後面裝電表就是用它。

另外，在不同的模型下，一樣的內容 token 數不一定一樣。[&lt;u&gt;官方定價頁&lt;/u&gt;](https://platform.claude.com/docs/en/about-claude/pricing#model-pricing)有這一段：

&gt; *Claude 4.7 and later models and Claude Mythos Preview use a newer tokenizer that contributes to their improved performance on a wide range of tasks. This tokenizer produces approximately 30% more tokens for the same text. The exact increase depends on the content and workload shape. Claude Sonnet 4.6 and earlier models use the previous tokenizer.*

這段是說，Claude 4.7 之後的模型換了一套新的 tokenizer，同樣一段文字交給新的 tokenizer 切，切出來的 token 大約會多三成，但實際多多少要看內容。KeSi 用的 Haiku 4.5 是比 4.7 還早的模型，不在這段說的範圍裡。

token 多了，就算每百萬 token 的單價一樣，同一段內容要付的錢也跟著變多。我拿同樣的內容，分別用 Haiku 4.5 跟用新 tokenizer 的 Claude Opus 5 去量：

&lt;table class=&quot;tiptap-table&quot; style=&quot;min-width: 100px;&quot;&gt;
&lt;colgroup&gt;&lt;col style=&quot;min-width: 25px;&quot;&gt;&lt;col style=&quot;min-width: 25px;&quot;&gt;&lt;col style=&quot;min-width: 25px;&quot;&gt;&lt;col style=&quot;min-width: 25px;&quot;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;內容&lt;/th&gt;&lt;th colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;Haiku 4.5&lt;/th&gt;&lt;th colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;Opus 5&lt;/th&gt;&lt;th colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;差多少&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;code&gt;kesi.py&lt;/code&gt; 原始碼&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;17,734&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;21,046&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;+18.7%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;KeSi 的 &lt;code&gt;README.md&lt;/code&gt;&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;813&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;941&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;+15.7%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;第 17 天的文章（中文為主）&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;8,416&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;8,977&lt;/td&gt;&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;+6.7%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;
&lt;/table&gt;

三份內容都變多了，但沒有一份剛好是三成，程式碼多了將近兩成，中文為主的文章只多了不到一成，這就是文件說的 `The exact increase depends on the content`。所以前面量的那些數字只適用 Haiku 4.5，換了模型就得重新量過，不能直接拿來套。

## **價目表**

截至 2026 年 10 月，KeSi 一路在用的 Claude Haiku 4.5 在[&lt;u&gt;官方定價頁&lt;/u&gt;](https://platform.claude.com/docs/en/about-claude/pricing#model-pricing)上是這個價：

| 項目 | 每百萬 token |
| --- | --- |
| input | 1 美元 |
| output | 5 美元 |
| 5 分鐘快取寫入 | 1.25 美元 |
| 1 小時快取寫入 | 2 美元 |
| 快取命中 | 0.1 美元 |

表格下面那三項跟 prompt caching 有關，不過今天還用不到。prompt caching 是把每次都一樣的開頭內容先存在 Anthropic 那邊一段時間，5 分鐘或 1 小時，在這段時間裡再送一樣的內容就叫命中，算比較便宜的價錢，細節等幫 KeSi 裝快取那天再講。我把價格寫進程式：

```
# Claude Haiku 4.5 的費率（美元 / 百萬 token），價格會變，用之前先查官方定價頁
PRICE = {
    &quot;input&quot;: 1.0,
    &quot;output&quot;: 5.0,
    &quot;cache_write&quot;: 1.25,  # 5 分鐘的快取寫入，是 input 的 1.25 倍
    &quot;cache_read&quot;: 0.1,    # 快取命中，是 input 的一折
}
```

價格會變，所以註解裡寫了要先去查官方定價頁。程式裡只放了 5 分鐘的快取寫入價，因為之後要用的就是這一種。

## **每一輪花了多少？**

每一次 API 回應都會帶著一份 `usage`，裡面寫著這次用了多少 input 跟 output token。我寫了一個 `Meter` 類別當 KeSi 的電表，做的事很簡單，就是把每一份 `usage` 記下來，需要的時候照價目表算錢：

```
class Meter:
    &quot;&quot;&quot;記帳用的電表，每一次 API 請求的 usage 都記一筆。&quot;&quot;&quot;
​
    def __init__(self):
        self.calls = []
​
    def record(self, usage, *, partial=False):
        if usage is None:
            return
        self.calls.append({
            &quot;input&quot;: usage.input_tokens or 0,
            &quot;output&quot;: usage.output_tokens or 0,
            &quot;cache_write&quot;: getattr(usage, &quot;cache_creation_input_tokens&quot;, 0) or 0,
            &quot;cache_read&quot;: getattr(usage, &quot;cache_read_input_tokens&quot;, 0) or 0,
            &quot;partial&quot;: partial,
        })
​
    def totals(self, since=0):
        total = {key: 0 for key in PRICE}
        for call in self.calls[since:]:
            for key in PRICE:
                total[key] += call[key]
        return total
​
    def cost(self, since=0):
        total = self.totals(since)
        return sum(total[key] / 1e6 * PRICE[key] for key in PRICE)
​
    def report(self, since=0):
        total = self.totals(since)
        requests = len(self.calls) - since
        partial = sum(call[&quot;partial&quot;] for call in self.calls[since:])
        parts = [f&quot;input {total[&#39;input&#39;]:,}&quot;, f&quot;output {total[&#39;output&#39;]:,}&quot;]
        if total[&quot;cache_read&quot;] or total[&quot;cache_write&quot;]:
            parts.append(f&quot;快取讀 {total[&#39;cache_read&#39;]:,}&quot;)
            parts.append(f&quot;快取寫 {total[&#39;cache_write&#39;]:,}&quot;)
        note = f&quot;，其中 {partial} 次只算到中斷前收到的部分&quot; if partial else &quot;&quot;
        return (
            f&quot;（本輪 {requests} 次請求，{&#39;、&#39;.join(parts)}，&quot;
            f&quot;${self.cost(since):.4f}{note}；累計 ${self.cost():.4f}）&quot;
        )
​
​
METER = Meter()
```

這裡要注意的是，電表記的是「一次 API 請求」，不是「一輪對話」。你按一次 Enter 是一輪，但模型如果先開工具、看完結果再回答，這一輪裡面就會送出好幾次請求，每一次都是一筆帳。`since` 參數就是為了這件事，`main()` 函式在送出問題之前，先記下電表目前已經記了幾筆（`len(METER.calls)`），跑完之後從那個位置開始算，就是「這一輪花了多少」。

`usage` 從哪裡來？第 17 天改成串流之後，`stream_turn()` 函式在收完整則回應時會呼叫 `get_final_message()`，帳就從它回傳的那則訊息的 `usage` 拿：

```
final = active.get_final_message()
METER.record(final.usage)
return final, finished, False
```

不過如果回答印到一半按下 Ctrl-C，就拿不到完整的回應了。[&lt;u&gt;串流文件&lt;/u&gt;](https://platform.claude.com/docs/en/build-with-claude/streaming#event-types)有提到：

&gt; *The token counts shown in the* `usage` *field of the* `message_delta` *event are cumulative.*

意思是 `message_delta` 帶的是累計到那時候的總數，而這個事件要到回應快結束才會來，中途按下 Ctrl-C 就收不到了。所以這時候只能記快照裡目前的數字，並標成 `partial`，`report()` 會在那一行補一句「其中 1 次只算到中斷前收到的部分」。至於伺服器最後實際算了多少，電表不會知道，要對正式的帳還是得到 Anthropic 的網頁後台 Claude Console 看。

`main()` 把 `run_agent()` 包在 `try/finally` 裡，不管這一輪是正常結束還是被中斷，只要有收到 `usage`，最後都會把這一輪的帳印出來：

```
before = len(METER.calls)
try:
    # 顯示全部交給 run_agent，正常回應在串流時就已經印出來了
    run_agent(client, history)
except KeyboardInterrupt:
    seal_dangling_tool_use(history)
    print(&quot;\n（已中斷，可以接著問下一句）&quot;)
finally:
    # 這一輪有收到 usage 才印，請求在拿到 usage 之前就失敗的話不會多記一筆
    if len(METER.calls) &gt; before:
        print(f&quot;  {METER.report(before)}&quot;)
```

這樣每一輪的最後就會多一行帳單，下面是 `demo.py` 跑的第一輪，回答內容省略：

```
你 &gt; 這個專案在做什麼？
KeSi &gt; 我先看一下這個專案的結構。
  [執行工具] list_files({})
KeSi &gt; 讓我看看 README 和主要的 Python 檔案。
  [執行工具] read_file({&#39;file_path&#39;: &#39;README.md&#39;})
  [執行工具] read_file({&#39;file_path&#39;: &#39;pricing.py&#39;})
  [執行工具] read_file({&#39;file_path&#39;: &#39;rules.py&#39;})
KeSi &gt; ## 專案概況 ...
  （本輪 3 次請求，input 16,227、output 530，$0.0189；累計 $0.0189）
```

每輪一行帳單只看得到這一輪，想看整場加起來花了多少，就得自己往上捲去加。所以我在 `main()` 函式裡，跟 `/reset`、`/permissions` 這些指令放在一起，多加了一個 `/cost` 指令，輸入之後會印出這個 session 到目前為止的請求次數、token 數跟總金額，名字是照 Claude Code 看帳單的指令取的，後面會講到：

```
if user == &quot;/cost&quot;:
    total = METER.totals()
    print(f&quot;  這個 session 共 {len(METER.calls)} 次請求&quot;)
    print(f&quot;  input {total[&#39;input&#39;]:,}、output {total[&#39;output&#39;]:,}&quot;)
    if total[&quot;cache_read&quot;] or total[&quot;cache_write&quot;]:
        print(
            f&quot;  快取讀 {total[&#39;cache_read&#39;]:,}、&quot;
            f&quot;快取寫 {total[&#39;cache_write&#39;]:,}&quot;
        )
    print(f&quot;  合計 ${METER.cost():.4f}&quot;)
    continue
```

`METER.totals()` 不給 `since` 就是從第一筆算起，也就是整個 session 的總帳。快取那兩項現在都是 0，所以不會印出來。下面是接上第 12 天的假 API server 跑的，數字是 mock 固定回的 100 跟 20，不是真的用量：

```
你 &gt; /cost
  這個 session 共 1 次請求
  input 100、output 20
  合計 $0.0002
```

## **跑到一半斷線了？**

第一次跑八輪對話的時候，第一輪順利跑完，但後面某一輪在串流途中，整個程式就當掉了，最後一行錯誤訊息是：

```
httpx2.ReadError: [Errno 54] Connection reset by peer
```

這行的意思是 API 那一端把連線切斷了。網路連線偶爾斷掉是很正常的事，比較好的處理方式是告訴使用者連線斷了，然後讓他可以接著問下一句，在第 17 天處理 API 錯誤的時候就是這樣做的。但這次 KeSi 沒有處理到這個錯誤，整個程式直接結束，前面累積的對話日記也跟著不見了。第 17 天的 `stream_turn()` 只處理 `anthropic.AnthropicError`，但串流已經開始之後才斷線，丟出來的是 SDK 底層負責連線的 `httpx2` 套件的錯誤（`httpx2.ReadError`），SDK 沒有把它包成自己的錯誤，於是一路往上丟到程式外面。

所以我改了 `stream_turn()` 處理錯誤的那一段。原本它只接 `anthropic.AnthropicError` 這一種錯誤，現在改成不管是哪一種錯誤都接下來，也就是 `except Exception`。只要串流已經開始，就照第 17 天的做法處理：已經印完的文字留在日記裡，還沒收完的部分丟掉，再告訴使用者發生了什麼錯誤，然後回到等你輸入下一句的地方：

```
    except Exception as exc:
        # 串流開始之後斷線，丟出來的是底層 HTTP 套件的錯誤，不是 AnthropicError
        if stream is None:
            raise
        # 後面跟第 17 天一樣，包成 StreamFailure 往外丟
```

如果是串流還沒開始就失敗，例如一開始就連不上，`stream` 還是 `None`，錯誤會照舊往上丟給 `run_agent()` 處理。

改完之後要驗證它有沒有用，但網路什麼時候會斷線沒辦法控制，不能等它剛好斷給我看，所以我另外寫了 `examples/day18/check.py`，用一個假的串流在第一段文字收完之後丟出錯誤。這裡用 Python 內建的 `ConnectionResetError` 代替，重點是它跟 `httpx2.ReadError` 一樣都不是 `AnthropicError`。這支程式順便也驗電表的加總跟價錢，下面只節錄斷線那一段：

```
uv run examples/day18/check.py
```

```
# 3. 串流途中斷線，KeSi 不會當掉
KeSi &gt; 我來讀一下
KeSi &gt; 錯誤：ConnectionResetError：[Errno 54] Connection reset by peer
PASS 沒有往外丟錯誤
PASS 日記只留下完成的文字  留下 1 塊
PASS 最後一則告訴使用者斷線了  錯誤：ConnectionResetError：[Errno 54] Connection reset by peer
PASS 斷線前收到的 usage 有記下來，標成 partial  1 筆
​
# 9/9 通過
```

這支不會呼叫真的 API，不花錢。改完之後重新跑一次八輪對話，這次沒有斷線，八輪都跑完了，下面的數字就是這一次的結果。

## **八輪對話的帳單**

這是 `demo.py` 的後半段，這裡我用第 13 天那個訂單試算專案，連續問八個問題，問題寫在 `QUESTIONS` 裡，從「這個專案在做什麼？」問到「整理一下你到目前為止看到的東西。」，模型要不要開工具由它自己決定：

```
 輪  請求     input   output       本輪       累計
  1     3    16,227      530  $  0.0189  $  0.0189
  2     2    12,873      543  $  0.0156  $  0.0345
  3     2    14,612      316  $  0.0162  $  0.0507
  4     1     7,757      414  $  0.0098  $  0.0605
  5     2    16,588      434  $  0.0188  $  0.0792
  6     2    17,860      317  $  0.0194  $  0.0987
  7     1     9,354      418  $  0.0114  $  0.1101
  8     1     9,792      584  $  0.0127  $  0.1228
```

日記一輪比一輪厚，照理每一輪的 input 應該越來越多，可是第 6 輪是 17,860，第 7 輪反而只剩 9,354。這是因為 input 那一欄是「這一輪所有請求加起來」，而每一輪的請求次數不一樣。第 6 輪送了兩次請求，模型先開工具、看完結果再回答，兩次請求各自都帶著當時整本日記。第 7 輪模型直接回答，只送了一次。

要看出日記越來越厚，得拿請求次數一樣的輪次來比。只送一次請求的是第 4、7、8 輪，input 從 7,757、9,354 漲到 9,792；送兩次的是第 2、3、5、6 輪，從 12,873、14,612、16,588 漲到 17,860。請求次數一樣，每一輪都比前一輪多一點，因為日記一直在變厚。

在這場對話裡，某一輪特別貴，是因為那一輪多送了請求，模型每多開一次工具，就多送一次整本日記。

## **錢花在哪裡？**

整場算下來的錢錢差不多是這樣：

```
# 總計
​
  日記 28 則，API 請求 14 次
  input 105,063 token、output 3,556 token
  費用 $0.1228
    其中 input $0.1051（86%）、output $0.0178（14%）
  最後一次請求的 input：9,792
  固定開銷 5,092 × 14 次 = 71,288，佔全部 input 的 67.9%
```

input 佔了帳單的 86%。output 的單價是 input 的五倍，照理說應該是 output 比較貴，但是這場對話送出去的 input 有 105,063 個 token，output 只有 3,556 個，數量差了將近 30 倍，所以就算單價貴五倍也追不上。

最後一次請求的 input 是 9,792，這是送出第 8 題時模型收到的全部內容，包含 system prompt、工具說明書跟當時的整本日記。而整場累計送出去的 input 是 105,063，大約是它的 10.7 倍。如果每段內容只付一次錢，整場大約只要付 9,792 個 token 的 input，但每一次請求都要把當時的整本日記重新送一次，就變成十倍多。

這 105,063 裡面有一大塊是固定的。我用 Token Counting API 量了工具說明書加上 system prompt，是 5,092 個 token，不管問什麼，每一次請求都要帶。這是估計值，而且 system prompt 裡有日期跟作業系統，你量出來的數字會有一點不同。14 次請求就是 71,288 個 token，佔全部 input 的 67.9%，換算成錢是 0.0713 美元，佔整張帳單的 58%。

之後要裝的 prompt caching，處理的就是這一塊。照價目表粗估，第一次寫入快取要付 1.25 倍，之後 13 次命中都只要一折，`5,092 × 1.25 + 5,092 × 13 × 0.1` 等於大約 12,985 個 token 的 input 價，也就是 0.013 美元左右，前提是每次請求都在 5 分鐘內送出，快取還沒過期。這樣比原本的 0.0713 美元少了 0.058 美元，差不多是整張帳單的 47%。這只是照這次的數字算出來的估計，實際能省多少，等真的裝上快取再量。

剩下 input 的 32% 是一直在變的日記，讀進來的檔案內容、指令的輸出都在裡面，全部都會留在日記裡，每一次請求都跟著重送一次。

這兩節的數字是我在 2026 年 10 月 1 日同一次實際跑的結果，八輪加起來大約 0.12 美元。模型每次要不要開工具、回答多長都不一樣，你自己跑的請求次數跟金額都可能跟我的不同。

## **這樣算便宜嗎？**

八輪對話 0.12 美元，聽起來很便宜，但這是很理想的情況，因為 KeSi 用的是比較便宜的 Haiku、專案只有幾個小檔案、八輪就結束了。

同樣的 token 數換成 Claude Opus 5（[&lt;u&gt;定價頁&lt;/u&gt;](https://platform.claude.com/docs/en/about-claude/pricing#model-pricing)上 input 每百萬 5 美元、output 25 美元）來算就是大約 0.61 美元，而且 Opus 5 用的是前面講的新 tokenizer，同樣的內容 token 數還會再多一些。真實的專案檔案大得多，讀一個檔案就可能好幾千個 token，對話也不會八輪就結束。

KeSi 目前不會刪減或整理日記，每一次請求都帶著當時整本日記，日記會一直變長，所以每一次請求都會比前一次再貴一點。Claude Code 就不是這樣，[&lt;u&gt;文件&lt;/u&gt;](https://code.claude.com/docs/en/how-claude-code-works#when-context-fills-up)有提到：

&gt; *Claude Code manages context automatically as you approach the limit. It clears older tool outputs first, then summarizes the conversation if needed.*

也就是 context window（模型一次讀得下的上限）快滿的時候，會先清掉比較舊的工具輸出，需要的話再把對話整理成摘要。

## **正版怎麼看帳單？**

Claude Code 是用 `/usage` 指令看目前這個 session 用了多少 token，`/cost` 是它的別名。[&lt;u&gt;文件&lt;/u&gt;](https://code.claude.com/docs/en/costs#using-the-usage-command)對裡面的金額有一段說明：

&gt; *The Session block in* `/usage` *shows API token usage and is intended for API users. Claude Max and Pro subscribers have usage included in their subscription, so the session cost figure isn&#39;t relevant for billing purposes.*

意思是那個金額是給用 API 計費的人看的，如果你是用 Max 或 Pro 訂閱，用量已經包含在訂閱裡，那個數字跟你實際付的錢沒有關係。同一頁還寫著：

&gt; *Claude Code computes the dollar figure locally from token counts at list price, unless a* `modelPricing` *table is in effect.*

也就是那個金額是在你的電腦上照定價算出來的，除非你自己設定了另一張價目表，要對正式的帳還是要回 Claude Console 看。

另外社群也有像 [&lt;u&gt;ccusage&lt;/u&gt;](https://github.com/ryoppippi/ccusage) 這樣的工具，直接讀 Claude Code 存在 `~/.claude/projects/` 底下的 `.jsonl` 檔，也就是一行一筆 JSON 的對話紀錄，整理出每天、每個 session 的用量跟估算金額。這些紀錄就放在你自己的硬碟上，可以自己拿來整理，只是算出來的一樣是估計值，不是正式帳單。

## **小結**

今天幫 KeSi 裝上了電表，每一次 API 請求的 `usage` 都會記下來，每一輪結束印一行帳單，`/cost` 可以看整場的總帳。也順便把串流中途斷線會讓程式當掉的問題補起來了。

這場 0.12 美元的對話看得出三件事：

1. input 佔了 86%。output 單價貴五倍，但 input 的量多了將近 30 倍。

2. 整場送出去的 input 是最後一次請求的 10.7 倍，因為每一次請求都要重送整本日記。

3. input 裡有 67.9% 是每次都一樣的工具說明書跟 system prompt。

明天先處理日記裡的工具結果，讀進來的檔案內容會一直留在日記裡跟著重送，看看能不能讓它小一點。

咱們下集見 :)

