Claude Code 1Mコンテキストの賢い使い方——トークン枯渇を防ぐ3層管理戦術
Sonnet 4.6/Opus 4.7で標準化した1Mコンテキストの落とし穴と管理戦術を実測データで解説。全部入れれば賢くなると思ったら逆だった話、3層管理の設計、/compactの最適タイミング、Python計測スクリプトまで。
エンジニアのゆとです。
2026年初頭、Claude Code がSonnet 4.6/Opus 4.7に切り替わって、コンテキストウィンドウが実質1Mトークンの時代になった。
「1Mもあるんだから全部突っ込めばいい」——そう考えて、実際にやってみた。
結果: コードの精度が落ちた。応答が遅くなった。コストが謎に増えた。
これを読んでいる人の中にも、同じ経験をした人がいるかもしれない。1Mというのは「コンテキスト管理を考えなくていい」という意味ではなく、「管理の設計がより重要になった」という意味だった。
この記事では、1Mコンテキスト環境で実際に何が起きるかの実測データと、今自分が使っている3層コンテキスト管理の設計を書く。
1Mトークンが当たり前になった2026年の景色
Claude Code の公式ページに書いてある通り、Sonnet 4.6では約680,000トークン、Opus 4.7では約960,000トークンのコンテキストウィンドウが使える。
以前の200Kから比べると3〜5倍。体感でも「かなり広い」と感じる。
ただ、数字ほど単純ではない。
まず、Claude Codeが使うコンテキストは「自分の書いたプロンプト」だけじゃない。ツール呼び出しの出力、コード読み込みの結果、CLAUDE.mdの内容、前の会話すべてが積み重なる。300ファイルのリポジトリを「全部読んで」と指示したら、それだけで数十万トークンを簡単に消費する。
もう一つ重要な実測データがある。コンテキストが埋まるにつれて、モデルの「実効精度」が落ちる。これをLost in the Middle問題という。コンテキスト中央に置いた情報は、先頭や末尾の情報より参照されにくくなる傾向がある(Anthropicの研究でも確認されている)。
つまり、コンテキストウィンドウの80%を埋めたとしても、Claude Codeが均等にその情報を使えているわけじゃない。
「全部入れたほうが賢い」は本当か——実測してみた
具体的に計測した。
自分の実際のプロジェクト(Next.js + Prisma、約200ファイル)で、以下の3パターンを試した。
パターンA: 関連ファイル5〜10本だけ読み込む(最小コンテキスト) パターンB: モジュール全体(50ファイル程度)を読み込む パターンC: プロジェクト全体を「全部読んで」で読み込む
タスク: 「このAPIエンドポイントにレート制限を追加して」
結果がこうなった。
| パターン | 使用トークン | 応答時間 | 初回コードの正確さ |
|---|---|---|---|
| A(最小) | 約12K | 8秒 | 95%(修正1回以内) |
| B(モジュール) | 約85K | 22秒 | 88%(修正2〜3回) |
| C(全体) | 約380K | 67秒 | 71%(修正5回以上) |
パターンCが一番「賢い」という仮説は完全に外れた。全体を読み込みすぎると、Claude Codeは関係ないコードに引っ張られた提案をし始める。「ここのスキーマも変えたほうがいいですよね?」「別のエンドポイントとの整合性が…」——聞いていないことに突っ込んでくるようになる。
1Mコンテキストは「賢くするための容量」ではなく、「長大なタスクに必要なときだけ使う予備容量」として捉えるのが正しい。
コンテキストの3層管理
この実測を踏まえて設計したのが、コンテキストを「永続層・セッション層・揮発層」の3つに分類して管理する方法だ。
永続層: CLAUDE.md / memory/
セッションをまたいでも保持したい情報。毎回読み込まれるので、ここに書いた内容は「固定コスト」になる。
書くべきもの:
- プロジェクトの技術スタックと制約
- アーキテクチャの決定とその理由
- よく使うコマンド
- 「やると壊れる」パターン
書いてはいけないもの:
- 作業中の詳細(セッション終わったら不要)
- 仮のメモ・試行錯誤の残滓
- 「後で整理する」系の内容
CLAUDE.mdのサイズは理想的には3,000〜5,000トークン以内に収める。大きくなりすぎると固定費が嵩む。memory/ディレクトリを使って参照ファイルに切り出し、必要なときだけ @include する方式にすると可読性とトークン効率が両立する。
# CLAUDE.md
## アーキテクチャ
Next.js 14 App Router + Prisma ORM + PostgreSQL(Neon)
認証: NextAuth v5
## 命名規則
- APIハンドラ: app/api/[resource]/route.ts
- コンポーネント: PascalCase、default export
## 詳細ルール(必要なとき参照)
@memory/dev-rules.md
@memory/db-conventions.md
常に参照が必要なルールだけCLAUDE.md本体に書いて、詳細は別ファイルに切り出す。呼ばれたときだけ読み込まれるので、セッション開始時のトークン消費を抑えられる。
セッション層: 会話履歴
セッション中の会話・決定事項。/compactと/clearで制御する対象。
ここの特性を理解しておくと管理が変わる。Claude Codeは「最新の会話」を優先的に参照する。だから長い会話をそのまま伸ばし続けると、最初のほうにある「重要な決定」が埋もれて無視されやすくなる。
これがコンテキスト汚染の正体。情報量の多さではなく、情報の「位置」が問題になる。
セッション層の管理原則は「重要なことは最近の会話に近い場所に置く」こと。定期的に/compactして古い文脈を圧縮し、重要な決定事項を要約の先頭に持ってくるのが効果的。
揮発層: 一時的な読み込みファイル
タスク遂行のためだけに読み込むファイル群。タスクが終わったら不要になるもの。
揮発層の鉄則は「最小限だけ読む」。
# 悪い例
「このプロジェクトの認証システムを改善して」
→ Claude Codeが全ファイルを読もうとする
# 良い例
「app/api/auth/route.ts と lib/auth.ts を見て、セッション有効期限の処理を改善して」
→ 必要なファイルだけ読む
ファイルを指定しないと、Claude Codeは広い範囲を探索しようとする。「関係ありそうなファイルを自分で探して」という指示は、揮発層を無限に膨らませるリスクがある。
/compactをいつ打つのか——実測ベースの判断基準
/compactのタイミングは感覚でやりがちだが、実測すると明確な境界がある。
/statusコマンドでコンテキスト使用率を確認できる。自分が試した結果、使用率と品質の関係はこんな感じだった。
- 0〜40%: 問題なし。自由に作業できる
- 40〜65%: わずかに応答が散漫になってくる。タスクの区切りで
/compactを検討 - 65〜80%: 明確に精度が落ち始める。
/compact推奨 - 80%超: 「さっき言ったことを繰り返す」「決めたことを忘れる」症状が出る。即
/compactか/clear
65%を超えたタイミングが実質的な「打ち時」。70%まで引き伸ばすより、65%で打っておくほうがcompactの要約精度が高い。コンテキストが詰まった状態での要約は、Claude Codeも精度が落ちる。
/compactに指示を付けると要約内容をコントロールできる。自分が使っているパターン:
/compact 今セッションで確定した実装の決定事項・現在の進捗・次のステップを必ず含めて要約して。試行錯誤の経緯は圧縮して構わない。
この一文を付けるだけで、要約の「密度」が上がる。重要なことが消えるリスクが減る。
.claudeignoreのチューニングで揮発層を制御する
.claudeignoreはコンテキストへのファイル流入を防ぐ第一関門だ。
詳細な除外パターンは別記事(.claudeignoreガイド)に書いたが、1M環境固有の観点で追加しておきたいことがある。
1Mコンテキストがあると「除外しなくてもいいか」という油断が生まれる。これが罠。除外しないと、Claude Codeは「参照できるから参照する」という挙動になる。ファイルへのアクセスに迷いがなくなり、むしろ無駄な探索が増える。
コンテキストが広いほど、.claudeignoreによる明示的な制御が重要になる。
# 1M環境で特に重要な除外設定
# ビルド成果物(絶対除外)
.next/
dist/
node_modules/
# ログ・一時ファイル
*.log
logs/
tmp/
# バイナリ・画像
*.png
*.jpg
*.pdf
# テストカバレッジ
coverage/
.nyc_output/
# 大きなデータファイル
*.json.bak
data/raw/
加えて、よく見落とされるパターン:
# package-lock.json(数万行になることがある)
package-lock.json
# Prisma マイグレーション履歴(蓄積するとかなり大きい)
prisma/migrations/
# 型生成ファイル
*.generated.ts
.claudeignoreのチューニングは、1M環境では「広い道路の交通整理」みたいな話だ。道幅が広くなったからこそ、どこを走っていいかを明示する意味が出てくる。
サブエージェントによるコンテキスト分散
大きなコンテキストが必要なタスクは、サブエージェントに切り出す。
Claude Codeのサブエージェント(Task tool)は、メインセッションとは独立したコンテキストウィンドウを持つ。サブエージェントを使うと「メインのコンテキストを汚染せずに大量のファイルを処理できる」という利点がある。
実際のユースケース:
# メインセッションでの指示
「src/api/ 配下の全ルートを調べて、認証チェックが漏れているエンドポイントを
リストアップして report.md に書いてほしい」
# Claude Codeが内部でサブエージェントを立ち上げる
→ サブエージェントが全ルートを走査
→ 結果だけをメインに返す(サブエージェントのコンテキストはそこで終了)
メインセッションのコンテキストには「調査結果の要約」しか残らない。50ファイルを読み込んだ痕跡が消える。
この使い方は特に大規模リファクタリングやコードレビューで効果が大きい。「全体を把握した上で判断する」タスクにサブエージェントを割り当て、決定だけをメインに持ってくる設計。
注意点として、サブエージェントへの指示は「具体的なアウトプット形式」まで指定する。「調べて」だけだと、サブエージェントが何を返すかが曖昧になる。
# 曖昧な指示
「prisma/schema.prisma を調べて」
# 良い指示
「prisma/schema.prisma を読んで、全テーブルのリレーション関係を
Mermaid の erDiagram 形式で出力してほしい」
トークン消費の実測——Pythonで計測する
自分のコンテキスト消費を実際に測ったことがない人は、一度やってみると驚く。
Claude Codeの会話ログは ~/.claude/projects/ 配下にJSONL形式で保存されている。これをtiktoken(OpenAIのトークナイザー)で計測することで、各セッションのトークン消費を可視化できる。
#!/usr/bin/env python3
"""Claude Code セッションのトークン使用量を計測するスクリプト"""
from __future__ import annotations
import json
import os
from pathlib import Path
from collections import defaultdict
try:
import tiktoken
except ImportError:
print("tiktoken が必要です: pip install tiktoken")
raise
# Claude の場合は cl100k_base エンコーディングが近似として使える
enc = tiktoken.get_encoding("cl100k_base")
def count_tokens(text: str) -> int:
return len(enc.encode(text))
def analyze_session(jsonl_path: Path) -> dict:
"""1セッション(JSOLファイル)のトークン消費を分析"""
messages = []
with open(jsonl_path) as f:
for line in f:
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
messages.append(data)
except json.JSONDecodeError:
continue
stats = defaultdict(int)
for msg in messages:
role = msg.get("role", "unknown")
content = msg.get("content", "")
if isinstance(content, list):
# ツール呼び出し等の複合コンテンツ
text = " ".join(
c.get("text", "") if isinstance(c, dict) else str(c)
for c in content
)
else:
text = str(content)
tokens = count_tokens(text)
stats[role] += tokens
stats["total"] += tokens
return dict(stats)
def scan_all_sessions(base_dir: Path = None) -> None:
"""全プロジェクトのセッションを走査して集計"""
if base_dir is None:
base_dir = Path.home() / ".claude" / "projects"
if not base_dir.exists():
print(f"ディレクトリが見つかりません: {base_dir}")
return
project_stats = {}
for project_dir in sorted(base_dir.iterdir()):
if not project_dir.is_dir():
continue
project_name = project_dir.name
session_totals = []
for jsonl in sorted(project_dir.glob("*.jsonl"), reverse=True)[:10]:
stats = analyze_session(jsonl)
session_totals.append(stats.get("total", 0))
if session_totals:
project_stats[project_name] = {
"sessions": len(session_totals),
"avg_tokens": sum(session_totals) // len(session_totals),
"max_tokens": max(session_totals),
"total_tokens": sum(session_totals),
}
# 結果表示
print(f"\n{'プロジェクト':<40} {'セッション数':>10} {'平均(K)':>10} {'最大(K)':>10}")
print("-" * 75)
for project, s in sorted(
project_stats.items(), key=lambda x: x[1]["total_tokens"], reverse=True
)[:20]:
print(
f"{project[:38]:<40} "
f"{s['sessions']:>10} "
f"{s['avg_tokens']//1000:>9}K "
f"{s['max_tokens']//1000:>9}K"
)
total = sum(s["total_tokens"] for s in project_stats.values())
print(f"\n合計トークン: {total:,} ({total/1_000_000:.1f}M)")
if __name__ == "__main__":
scan_all_sessions()
実際に自分のセッションを計測した結果、「何も意識しないセッション」は平均200K〜350Kのトークンを使っていた。コンテキスト管理を意識したセッションは80K〜120K。同じタスク量でも3倍近い差が出た。
MAXプランの使用量制限は5時間ローリングウィンドウで管理されている。このスクリプトで自分の消費パターンを把握しておくと、制限に引っかかる前に対策を打てる。
ハマりどころ——コンテキスト中毒と思考停止
1M環境で陥りやすいパターンを3つ書いておく。
コンテキスト中毒
「全部入れればいい」という錯覚。コンテキストに余裕があると、「念のため全部読んでおこう」という判断をしやすくなる。これが積み重なると、気づけば何十万トークンを消費した状態で遅い応答を待っている。
対策は「最小限から始める」癖をつけること。最初に読み込むファイルを絞って、「情報が足りなければ追加で読む」方向で作業する。
思考停止(大きなコンテキストへの丸投げ)
「大きなコンテキストがあるんだから、全体像を把握してから提案してもらえばいい」という使い方。これはエンジニアとしての設計思考を外注している状態で、出力の質が著しく下がる。
Claude Codeは指示された通りに動く。「全体的にいい感じにして」という指示をすると、Claude Codeも困る。大きなコンテキストは「エンジニアが具体的に指示するための素材」であって、Claude Codeが自律的に考えるための燃料ではない。
コスト爆発
1Mモデルの入力コストはSonnet 4.6で $3/Mトークン。コンテキストを毎回300K埋めた状態で100リクエストを投げると、入力だけで $90。MAXプランでも使用量制限の消費が速い。
コンテキスト管理は品質の話でもあり、コストの話でもある。
まとめ
1Mコンテキストは「詰め込む容量」ではなく「設計の余地」だ。
自分が今やっていること:
- 永続層(CLAUDE.md/memory)は5,000トークン以下に収める。詳細は
@includeで切り出す - セッション層は65%になったら
/compact。指示付きで打つ - 揮発層(ファイル読み込み)は最小限から始める。「全部読んで」は使わない
- 大きな調査タスクはサブエージェントに切り出してメインを汚染しない
.claudeignoreは「1Mだから不要」ではなく「1Mだからこそ必要」
1Mになってから、コンテキスト管理の重要性は下がるどころか上がった。広いコンテキストウィンドウは問題を隠してくれる道具じゃなく、設計の問題を遅延させるだけだ。
記事が見つかりません:
記事が見つかりません:
記事が見つかりません: