こんにちは、木川です!
SIerの開発現場でClaude Codeを活用する機会が増えてきました。特に、設計からテストまでの各工程の工数が大幅に削減されている現場が増えていると思います。
ですが、その陰で我々が戦わなければならないのが「コンテキストウィンドウ」による制限です。
本日は、実際の既存システム改修案件でClaude Codeを使用した際に効果があったコンテキストウィンドウの削減方法をご紹介します。
なぜコンテキストが問題になった?
新規プロジェクトで使用する際はまだ問題なく使用できていましたが、
既存のレガシーシステムの改修作業に持ち込んだときに、Claudeの様子が変わりました。
具体的には、
- コンテキストの枯渇が早い
- 指示の一貫性がセッション(タスク)をまたぐとブレる
という問題が起きました。
何がコンテキストを食うのか
対策を講じる前にコンテキストを消費している犯人を特定しました。
要因は主に以下の4つです。
| 要因 | 具体例 |
|---|---|
| 不要なファイル群の読み込み | プロンプトによる指定が甘いと、ログ・バイナリ・自動生成コード・テスト成果物など関係ないファイルも読み込まれる |
| メッセージ履歴の蓄積 | 1つのエージェントにおけるセッションが長引くと、すべての会話がコンテキストに積みあがる |
| 業務の流れの口頭説明 | 無意識に実施している業務などの暗黙知を口頭説明するたびにコンテキストに積みあがる |
上記について、解決策はシンプルで、「最初から読み込ませない」「各タスクを外出しする」「知識をファイルに外出しする」の三つの軸で考えます。
具体的な対策
対策① settings.json でメモリへの読み込みを遮断する
プロンプトの指定が甘いと、本来インプットとして必要ないファイルまで読み込みます。
たとえば、ビルド成果物、ログ、依存パッケージ、バイナリファイルなどは思考に要らないことがほとんどです。そうした不要なファイルを読み込まないようにするために、「settings.json」を使用します。
.claude/settings.json(または ~/.claude/settings.json)を以下のように書くことで、不要なファイルやディレクトリの読み込みを制御できます。
.claude/settings.json はプロジェクトルートに配置してチーム全体で使用し、~/.claude/settings.json は個人の好みで使用できます。
{
"permissions": {
"deny": [
"Read(./dist/**)",
"Read(./build/**)",
"Read(./coverage/**)",
"Read(./logs/**)",
"Read(./**/*.log)",
"Read(./node_modules/**)",
"Read(./.venv/**)",
"Read(./vendor/**)",
"Read(./.git/**)",
"Read(./**/*.class)",
"Read(./**/*.jar)",
"Read(./**/*.war)",
"Read(./**/*.ear)",
"Read(./**/*.min.js)",
"Read(./**/*.min.css)",
"Read(./**/*.png)",
"Read(./**/*.jpg)",
"Read(./**/*.gif)"
]
}
}ただし、pdfやdocファイルなどの設計書に使用されそうなファイル形式については注意が必要です。
インプットとして必要な可能性がある場合はdenyブロックに含めないのが確実です。
まず /context コマンドでカテゴリ別のコンテキスト消費量を確認し、何がトークンを食っているか把握してから除外リストを作ると効率的です。やみくもに除外すると Claude が必要な情報にアクセスできなくなるので注意してください。
対策② サブエージェントで担当エリアを分割する
1つのエージェントで「調査→設計→実装→レビュー」のようなタスクをすべてこなそうとすると、コンテキストに全てが積み上がってしまいます。
これを防ぐために、サブエージェントを使ってタスクを委譲すると、サブエージェントは独立したコンテキストウィンドウで動くため、メインセッションのコンテキストに読まれません。
例えば、レガシーシステムの調査フェーズで使用するパターンとしては、以下のようなエージェントをMDファイルで定義しておき、メインエージェントから呼ぶ形です。
ファイル名、およびパスは仮に「調査専用サブエージェント(.claude/agents/investigator.md)」とします。
---
name: investigator
description: 既存コードの調査・解析を担当するサブエージェント。
呼び出し例: "investigator を使って payment モジュールの依存関係を調べて"
tools:
- Read
- Grep
- Glob
# Write 系ツールは与えない(調査専用)
---
あなたはコードベース調査の専門エージェントです。
指示されたモジュールやファイル群を読み込み、
以下の観点で簡潔に報告してください:
1. 主要なクラス・関数と責務
2. 外部依存(ライブラリ・API 呼び出し)
3. 呼び出し元・呼び出し先の関係
4. 気になる技術的負債の箇所
報告は箇条書きで簡潔にまとめること。上記のサブエージェントを定義した際、メインエージェントでは例えば以下のような指示を書きます。
investigator を使って src/payment/ ディレクトリの依存関係を調べてください。
結果だけ返してもらえれば、実装はこちらで行います。
このようにタスク分割することで、サブエージェントが大量のファイルを読み込んで解析した場合でも、メインセッションに返ってくるのはその要約結果のみなので、大きな調査コストをサブエージェント側に押し込み、メインセッションのコンテキストを節約できます。
対策③ Skillsで「現場特有の知識」を外出しする
レガシーシステムには、そのプロジェクト固有の「暗黙知」が必ず存在します。命名規則や設計書のフォーマット、コーディング規約、業務ドメイン用語の定義などなど…….
これらを毎セッション口頭で説明していると、それ自体がコンテキストを消費する上に、伝え方のブレが品質のブレに直結します。
上記のような知識は Skills に定義しておくことで、ファイルとして管理でき、必要なタイミングだけ自動でコンテキストに注入できます。
Skills とは
.claude/skills/<スキル名>/SKILL.md に置いたマークダウンファイルです(個人の全プロジェクトで共有したい場合は ~/.claude/skills/<スキル名>/SKILL.md)。ここに「いつ使うか」と「処理内容」を定義しておくと、Claude が適切なタイミングで自動的に参照してくれます。
この Skills は CLAUDE.md に全部書くのとは異なり、必要な時だけ読み込まれるためコンテキストの無駄遣いを防ぐことができます。具体的には、起動時にロードされるのはフロントマターの name と description のみ(後の例を参照)で、SKILL.md の本文は呼び出しが必要になったときに初めて読み込まれる2段階の仕組みになっています。
Skills の呼び出し方
Claude Code では /<スキル名> と入力することで、そのスキルを明示的に呼び出すことができます。
加えて、description に「いつ使うか」を書いておくことで、Claude 自身が作業内容に応じて自動で参照してくれるため、毎回コマンドを打たなくてもいいです。
例えば命名規則のスキルであれば、新しいクラスを作成しようとしたタイミングで Claude が自ら参照し、プロジェクト規約に沿った名前を提案してくれる、ということが起きます。
Skills の書き方
例えば以下のように書きます。ファイルの先頭に YAML 形式のフロントマターを書き、description にいつ使うかの発動条件を定義します。
---
name: naming-convention
description: このプロジェクトの命名規則と設計ガイドラインを提供します。
新規クラス・メソッドの作成時や、既存コードの修正時に参照してください。
---
## プロジェクト固有の命名規則
### クラス名
- Service クラス: `〇〇Service`(ビジネスロジック層)
- Repository クラス: `〇〇Repository`(DB アクセス層)
- DTO クラス: `〇〇Dto`(データ転送オブジェクト)
- 例外クラス: `〇〇Exception`
### メソッド名
- 取得系: `find〇〇`, `get〇〇`(DB あり / なしで使い分け)
- 登録系: `register〇〇`(`save`, `create` は使わない)
- 更新系: `update〇〇`
- 削除系: `delete〇〇`(論理削除は `inactivate〇〇`)
### パッケージ構成
com.example.{システム名}.{ドメイン}.{layer}
例: com.example.billing.payment.service
## コーディング規約(重要箇所抜粋)
- トランザクション境界は Service 層に統一
- Repository は JPA のみ(ネイティブクエリは原則禁止)
- ログは SLF4J 経由、ログレベルは INFO / WARN / ERROR の3種上記は /naming-convention と打てば明示的に呼び出せますし、Claude がユーザからの指示を受けたときに、命名に関係する作業と判断すれば自動で参照してくれます。
コーディング規約だけでなく、設計書のフォーマットや Javadoc 規約といったドキュメント系の暗黙知も同じように外出しできます。
---
name: spec-template
description: 設計書やコメントを書く際のフォーマットを提供します。
詳細設計・クラス設計を作成するときに使ってください。
---
## 詳細設計書フォーマット
### 記載項目(必須)
1. 機能概要(2〜3行)
2. 入力/出力の定義
3. 処理フロー(箇条書き or フローチャート)
4. エラーケースと対処方針
5. 関連テーブル・API
### Javadoc コメント規約
/**
* {クラス・メソッドの一言説明}
*
* {詳細説明(必要な場合)}
*
* @param {引数名} {説明}
* @return {戻り値の説明}
* @throws {例外クラス名} {発生条件}
*/CLAUDE.md は常に参照すべきプロジェクト概要・禁止事項を書きます。一方で、Skills は特定の作業時、特に自分が暗黙的に行っていて手順に起こせる処理を書きます。これらすべてを CLAUDE.md に書くとコンテキストを逼迫しやすいため、作業手順レベルの知識はSkills で分割するのが効果的です。
まとめ
今回ご紹介した対策をまとめると、「読み込ませない(settings.json)」「分割する(サブエージェント)」「外出しする(Skills)」の3本柱です。すべて一度に導入する必要はなく、一番コンテキストを食っていると感じる問題から順番に試してみるのがおすすめです。
最後まで読んでいただきありがとうございました!



コメント