0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeのトークンが突然10倍消えた——原因はキャッシュバグだった

0
Last updated at Posted at 2026-04-01

Claude Codeを使っていて、突然トークン消費が跳ね上がった経験はありませんか?

GitHub Issueには195件以上のリアクションが集まり、「5時間分のquotaが15分で消えた」「300Kトークンのスパイクが発生する」という報告が相次いでいます。

この記事では、トークン消費が爆発する主な原因と、Claude Codeのhook機能を使って事前に検知・防止する方法を、実際のhookコードとともに解説します。

この「気づいたら枠が溶けていた」型の費用の事故は、Claude Code に任せると起きうる取り返しのつかない事故の一つだ。原因と対策はこの記事で全部無料で説明するので、まずは下を読んでほしい。そのうえで、同じ費用やデータの取り返しのつかない事故を起きる前に設定で先回りして防ぐ全体像は、Claude Code 事故防止ガイド(第3章まで無料)に章ごとにまとめている。

なぜトークン消費が突然爆発するのか

Claude Codeはプロンプトキャッシュを使って、会話履歴の再送信コストを削減しています。通常、キャッシュヒット率は89〜99%程度です。

しかし、キャッシュが無効化されると、すべての会話履歴を毎ターン再送信することになり、トークン消費が10〜20倍に膨れ上がります。

コミュニティの調査(@jmarianski氏の分析)によると、主な原因は以下の3つです。

原因1: セッションファイルの読み取りによるキャッシュ汚染

Claude Codeが自分自身の会話履歴ファイル(.jsonl)を読み取ると、CLIが内部的にbilling hashを書き換えます。これによりキャッシュのプレフィックスが変わり、以降のすべてのターンでキャッシュが効かなくなります。

実測値:キャッシュ読み取り率が 89% → 4.3% に暴落し、1ターンあたりのトークン消費が約20倍になったケースが報告されています。

原因2: セッション再開時のキャッシュミス

claude --resume でセッションを再開すると、最初の1〜2ターンでキャッシュが再構築されます。この間、通常より多くのトークンを消費します。通常は2ターン目以降に回復しますが、他の原因と組み合わさると回復しないケースがあります。

原因3: 並列サブエージェントのキャッシュ競合

複数のサブエージェントを同時に起動すると、それぞれが個別のキャッシュエントリを作成するため、親セッションのキャッシュが押し出される可能性があります。7つのサブエージェントを同時起動したところ、一部でキャッシュミスが発生したという報告があります。

hookで防ぐ:実践的な対策5選

Claude Codeのhook機能を使えば、これらの問題を自動的に検知・防止できます。

対策1: セッションファイル読み取りブロック(最重要)

最も効果が大きい対策です。Claudeが自分の会話履歴を読めないようにします。

// ~/.claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Read",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/conversation-history-guard.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# conversation-history-guard.sh
# Claudeが自分の会話履歴を読むとキャッシュが壊れるのを防ぐ

INPUT=$(cat)

# Bashコマンドのチェック
CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
if [ -n "$CMD" ]; then
    if printf '%s' "$CMD" | grep -qE '\.(jsonl|log)' && \
       printf '%s' "$CMD" | grep -qiE '(claude|session|billing|transcript)'; then
        cat <<'EOF'
{"decision": "block", "reason": "⚠️ セッションファイルの読み取りはキャッシュを破壊します。外部ターミナルで確認してください。"}
EOF
        exit 0
    fi
fi

# Readツールのチェック
FILE=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
if [ -n "$FILE" ]; then
    if printf '%s' "$FILE" | grep -qE '\.claude/projects/.+\.jsonl$'; then
        cat <<'EOF'
{"decision": "block", "reason": "⚠️ 会話履歴ファイルの読み取りはキャッシュを20倍悪化させます。"}
EOF
        exit 0
    fi
fi

exit 0

対策2: コンテキスト使用量モニター

コンテキストウィンドウの残量を段階的に警告します。3%まで気づかず使い切る事故を防ぎます。

#!/bin/bash
# context-monitor.sh — 4段階警告でコンテキスト枯渇を防止
# PostToolUse で空matcherに設定(全ツール実行後に発火)

STATE_FILE="/tmp/cc-context-state"
COUNTER_FILE="/tmp/cc-context-monitor-count"

COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
COUNT=$((COUNT + 1))
echo "$COUNT" > "$COUNTER_FILE"

# 3回に1回チェック(オーバーヘッド軽減)
[ $((COUNT % 3)) -ne 0 ] && exit 0

# デバッグログからトークン使用量を読み取り
DEBUG_DIR="$HOME/.claude/debug"
if [ -d "$DEBUG_DIR" ]; then
    LATEST=$(find "$DEBUG_DIR" -maxdepth 1 -name '*.txt' -printf '%T@ %p\n' 2>/dev/null \
             | sort -rn | head -1 | cut -d' ' -f2)
    if [ -n "$LATEST" ]; then
        LINE=$(grep 'autocompact:' "$LATEST" 2>/dev/null | tail -1)
        if [ -n "$LINE" ]; then
            TOKENS=$(echo "$LINE" | sed 's/.*tokens=\([0-9]*\).*/\1/')
            WINDOW=$(echo "$LINE" | sed 's/.*effectiveWindow=\([0-9]*\).*/\1/')
            if [ -n "$TOKENS" ] && [ -n "$WINDOW" ] && [ "$WINDOW" -gt 0 ] 2>/dev/null; then
                PCT=$(( (WINDOW - TOKENS) * 100 / WINDOW ))
                if [ "$PCT" -le 15 ]; then
                    echo "🚨 EMERGENCY: コンテキスト残り${PCT}%。即座に/compactを実行してください" >&2
                elif [ "$PCT" -le 20 ]; then
                    echo "⛔ CRITICAL: コンテキスト残り${PCT}%。/compactを推奨します" >&2
                elif [ "$PCT" -le 25 ]; then
                    echo "⚠️ WARNING: コンテキスト残り${PCT}%。現在のタスクを完了させてください" >&2
                fi
            fi
        fi
    fi
fi

exit 0

対策3: トークン予算ガード

セッション全体のトークン消費量を推定し、設定した予算を超えたら警告・ブロックします。

#!/bin/bash
# token-budget-guard.sh — セッションのトークンコスト上限を設定
# PostToolUse で空matcherに設定

WARN_BUDGET="${CC_TOKEN_BUDGET:-10}"   # $10で警告
BLOCK_BUDGET="${CC_TOKEN_BLOCK:-50}"   # $50でブロック
STATE="/tmp/cc-token-budget-$$"

# ツール出力サイズからトークン数を推定
INPUT=$(cat)
OUTPUT=$(echo "$INPUT" | jq -r '.tool_result // empty' 2>/dev/null)
OUTPUT_LEN=${#OUTPUT}

# 概算: 4文字 ≈ 1トークン, Opus入力$15/M + 出力$75/M
EST_TOKENS=$((OUTPUT_LEN / 4))
PREV=$(cat "$STATE" 2>/dev/null || echo 0)
TOTAL=$((PREV + EST_TOKENS))
echo "$TOTAL" > "$STATE"

# ドル換算(概算)
COST_CENTS=$(( TOTAL * 75 / 10000 ))  # $75/M output tokens

if [ "$COST_CENTS" -ge "$((BLOCK_BUDGET * 100))" ]; then
    echo "⛔ セッション推定コスト: \$${COST_CENTS}超。上限\$${BLOCK_BUDGET}に到達。" >&2
    echo '{"decision": "block", "reason": "Token budget exceeded. Start a new session."}'
    exit 0
elif [ "$COST_CENTS" -ge "$((WARN_BUDGET * 100))" ]; then
    echo "⚠️ セッション推定コスト: 約\$${COST_CENTS}。予算\$${WARN_BUDGET}に接近中。" >&2
fi

exit 0

対策4: compaction検知アラート

自動compactionが発火したことを検知して通知します。compactionの連鎖(compact→再構築→compact)はトークン消費の大きな原因です。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'INPUT=$(cat); if echo \"$INPUT\" | grep -qi compact; then echo \"⚠️ Auto-compaction検知。トークン消費が増加する可能性があります\" >&2; fi; exit 0'"
          }
        ]
      }
    ]
  }
}

対策5: compaction前のバックアップ

compactionで会話が要約されると、元の情報は失われます。事前にバックアップしておけば、何を失ったか確認できます。

#!/bin/bash
# pre-compact-transcript-backup.sh — compaction前に全文保存
# Notification hookで設定

INPUT=$(cat)
if echo "$INPUT" | grep -qi "compact"; then
    BACKUP_DIR="$HOME/.claude/backups"
    mkdir -p "$BACKUP_DIR"
    TIMESTAMP=$(date +%Y%m%d-%H%M%S)

    # 直近のセッションファイルをバックアップ
    LATEST=$(find "$HOME/.claude/projects" -name "*.jsonl" -newer /tmp/cc-last-compact 2>/dev/null | head -1)
    if [ -n "$LATEST" ]; then
        cp "$LATEST" "$BACKUP_DIR/pre-compact-${TIMESTAMP}.jsonl"
        echo "📦 Compaction前バックアップ: $BACKUP_DIR/pre-compact-${TIMESTAMP}.jsonl" >&2
    fi
    touch /tmp/cc-last-compact
fi

exit 0

環境設定での追加対策

hookに加えて、環境変数でもトークン消費を抑制できます。

// ~/.claude/settings.json
{
  "env": {
    "ENABLE_TOOL_SEARCH": "false"
  }
}

ENABLE_TOOL_SEARCH=falseは、動的なツール検索を無効化します。ツール定義の変更がキャッシュ無効化の一因になるケースが報告されており(#34629)、これを無効にすることでキャッシュの安定性が向上する可能性があります。

効果の実測

700時間以上のClaude Code運用で、これらのhookを導入した前後の変化:

指標 導入前 導入後
キャッシュ無効化によるセッション喪失 月2-3回 月0回
コンテキスト枯渇による作業喪失 月1-2回 月0回(15%で警告が出る)
予期しない高額セッション 発生あり 予算ガードで事前検知

まとめ

トークン消費の爆発は、主にプロンプトキャッシュの無効化が原因です。hookで防げる範囲と、プラットフォーム側の問題を正直に分けると:

hookで防げるもの:

  • セッションファイル読み取りによるキャッシュ汚染 → conversation-history-guard
  • コンテキスト枯渇の見逃し → context-monitor
  • 予算超過の検知 → token-budget-guard

hookでは防げないもの(プラットフォーム側の問題):

  • セッション再開時のキャッシュ再構築コスト
  • 並列リクエストのキャッシュ競合
  • サーバー側のキャッシュ管理

hookは万能ではありませんが、「防げる事故を確実に防ぐ」ことで、不必要なトークン消費を大幅に減らせます。

すべてのhookはcc-safe-setupで公開しています(698個のhook例を収録、MIT License)。


トークンの急な10倍は、多くがこの記事の hook で止められます。止めたあとに残る「定常的に費用を半分にする」設計——CLAUDE.md の最適化、AGENTS.md の重複の除去、hook によるトークン浪費の自動カット、ワークフロー設計、cache TTL の不告知の変更(#46829、1時間→5分で20〜32%の費用増)を含む費用の事故の整理——は、別の本に20章を超える構成でまとめています。2026年6月15日に予告された課金分離(claude -p・CI・SDK の自動運用を別枠 Pool 2 の標準 API 料金へ分離する変更)は、施行当日に一時停止され、今のところ従来どおりです。ただし公式には予告のまま残り再実施の可能性があり、もし施行されれば自動運用が多い人ほど費用が増えるため、定常の費用設計の効きが大きくなります。

まず、自分のトークン消費がどこで膨らんでいるかは、無料のトークン消費の詳しい診断で確かめられます。/cost の出力を貼るだけで、キャッシュの効き方と CLAUDE.md の常駐コストまで内訳が出ます。ブラウザの中だけで動くので、貼った内容はどこにも送信されません。自分の浪費を確かめてから、下の本で全手順を読むのが早いです。

Claude Codeトークン節約ガイド(¥2,500、はじめにと第1章は無料で試し読みできます)。hook の事例の集まりは cc-safe-setup(MIT、698個のhook例)で配布中。

トークンが急に10倍になる事故と地続きで、無断の課金や暴走した操作で API の料金が膨らむ事故を、実行の前で止める側の手順は、Anthropic 公式ガイドにない事故防止本(第3章まで無料の試し読み)に、800時間の自律運用の全手順としてまとめています。¥2,500 の節約ガイドの前に置ける、摩擦の低い入口です。


ほかにも、800時間の運用データから、トークン消費の削減・複数ベンダー(Claude / Codex / Gemini / Copilot)の並行運用・サブエージェントの沈黙の失敗対策など、テーマ別の手引きを公開しています。気になる人は著者の本の一覧から、価格と評価を見て選べます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?