Claude Codeのfine-grained tool streamingで長い書き込みの固まりを直す
長いファイル書き込みの最中に画面が止まって見えるときは、ツール入力のストリーミングが切れているのかもしれません。CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMINGの既定値と強制オンの条件を示します。
大きなファイルを書かせている最中に、画面が数十秒も動かない。そんなときに疑うのが、環境変数CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMINGです。これがオフだと、長いファイル書き込みのような大きなツール入力は、Claudeが生成し終えるまで届きません。固まったように見えますが、裏では生成が進んでいます。
この変数の既定値は接続先で変わります。Anthropic APIへ直接つなぐ構成ではオン、Microsoft Foundryやゲートウェイ経由ではオフです。プロキシ越しなら1で強制的にオンにできます。
fine-grained tool streamingは何を流す仕組みか
Claudeがツールを呼ぶとき、引数はJSONとして生成されます。Writeツールでファイルを書かせるなら、ファイルの中身そのものが引数の一部です。
fine-grained tool streamingがオンだと、この引数が生成されるそばから断片で届きます。オフでは、引数が完成してから一括で届きます。Claude Codeの環境変数リファレンスは、オフのときの症状を「ハングしているように見えることがある」と書いています。
生成にかかる時間は変わりません。変わるのは、途中経過が画面に出るかどうかです。数百行のファイルを書かせたとき、オンなら中身が流れ、オフなら長い沈黙のあとに一度で現れます。
接続先ごとの既定値
環境変数リファレンスと、ゲートウェイ向けのプロトコル解説を突き合わせると、既定値は次のとおりです。
| 接続先 | 既定 | 備考 |
|---|---|---|
| Anthropic API(直接) | 既定オン | 備考0でオフにできる |
| Amazon Bedrock | 既定モデルごと | 備考デプロイ先のコンテナが対応している場合だけオン |
| Google CloudのAgent Platform | 既定モデルごと | 備考同上 |
| Microsoft Foundry | 既定オフ | 備考Foundryの設定手順はClaude CodeでMicrosoft Foundryを使う手順にある |
| ゲートウェイ接続 | 既定オフ | 備考ANTHROPIC_BASE_URLが独自のホストを指す場合 |
Bedrockの行は「オンになる」ではなく「対応するコンテナなら、そのモデルでオンになる」です。同じBedrockでも、モデルによってオンとオフが混在しえます。
ゲートウェイ側の事情は、ANTHROPIC_BASE_URLの解説にまとまっています。独自のホストを指定すると、ツール検索やRemote Controlなど複数の機能が既定から変わります。逐次ストリーミングもそのひとつです。
設定のしかた
値は1で強制オン、0でオフです。設定場所は2通りあります。
シェルで一時的に試すなら、起動時に付けます。
CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING=1 claude常用するならsettings.jsonのenvキーに書きます。起動の仕方に関わらず効き、保存すると実行中のセッションにも反映されます。
{
"env": {
"CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING": "1"
}
}書き込み先で適用範囲が変わります。~/.claude/settings.jsonは自分の全プロジェクト、.claude/settings.jsonはリポジトリを共有する全員、.claude/settings.local.jsonは自分とこのプロジェクトだけです。組織で一括して入れるなら管理設定を使います。ゲートウェイを通すのが組織の標準なら、変数もそこで配ると個人差が出ません。
シェルとsettings.jsonの両方に同じ変数があるときは、多くのセッションで設定ファイルの値が優先されます。シェルで0、設定ファイルで1と食い違っていれば、効くのは後者です。設定ファイル同士では、管理設定がユーザー設定やプロジェクト設定を上書きします。想定と挙動が合わないときは、まずこの優先順位を疑います。シェルの値は起動時に読まれるため、変えたらclaudeを起動し直す必要があります。
プロキシ経由で強制オンにする条件
強制オンの対象は、公式の説明ではANTHROPIC_BASE_URL、ANTHROPIC_VERTEX_BASE_URL、ANTHROPIC_BEDROCK_BASE_URLのいずれかでプロキシを通している構成です。ゲートウェイ向けの解説は、独自のベースURLでは既定がオフになり、開発者が1を設定したときにゲートウェイへ送られる、という順序で書いています。
強制オンの前に、確かめておく点が3つあります。
- 症状が当てはまるか。ツール入力が大きいときだけ止まり、ほかの応答は普通に流れているなら当てはまりやすい
- ゲートウェイが、ストリーミング応答をバッファリングせずに中継しているか。ゲートウェイ側で応答を溜め込む設定だと、変数をオンにしても沈黙は残る
- Claude Codeのバージョン。v2.1.80のchangelogに「API proxy、Bedrock、Vertex経由でfine-grained tool streamingを使ったときの400エラーを修正」とあり、これ以前のバージョンでは強制オンで400が返りえた
古いバージョンで400が出るなら、まずアップデートです。それでも400が出るときは、変数を外せば元の挙動に戻ります。
強制オンの前後で変わること
オフのまま
ツール入力は生成が完了してから届く。画面は止まって見える。
1で強制オン
ツール入力が断片で届く。中継経路がストリーミングに対応している必要がある。
変数をオンにしても沈黙が残るとき
強制オンはClaude Code側の要求にすぎません。経路の途中で応答が溜め込まれれば、断片は届かないままです。
ゲートウェイ向けのプロトコル解説は、Claude Codeが応答をイベント単位で読んでいると説明し、ゲートウェイが応答を完成まで溜める構成ではClaude Codeが止まる、と明記しています。見直す箇所は次のとおりです。
- 応答のバッファリングを止めているか。SSEをそのまま中継する設定になっていないと、断片は一括になる
content-typeがtext/event-streamのままか。Bedrock形式ではapplication/vnd.amazon.eventstreamを書き換えずに返す- SSEの
pingを落としていないか。長い思考の間はpingだけが流れるため、これを削ると途中で切断の判定に入りうる
Bedrockをゲートウェイ越しに使う構成では、本文の形式にも注意が要ります。Bedrockのストリーミング応答はapplication/vnd.amazon.eventstreamで返ります。ゲートウェイがこれをSSEに変換すると、Claude CodeはBedrock streaming response has content-type "text/event-stream"; expected "application/vnd.amazon.eventstream"というエラーで応答を拒否し、再試行もしません。このエラーが出るのはv2.1.208以降で、それ以前は応答をすべて溜めたあとにTruncated event message receivedと表示されていました。つまりBedrock形式の経路では、応答が溜め込まれていないかどうかを、この表示の違いからも推測できます。
もうひとつの落とし穴は、リクエストの書き換えです。ゲートウェイは、機能ごとに「ベータヘッダー」と「本文のフィールド」が対で届くことを前提にします。片方だけ削ると400エラーになり、本文を検査のために書き換える構成も同じ壊れ方をします。逐次ストリーミングを通すゲートウェイでは、検査はしても改変はしないのが条件です。
オフにしたい場合と、Foundryでの扱い
0を設定すると、直接のAnthropic APIでも逐次ストリーミングを切れます。API側の解説によると、逐次ストリーミングではツール入力がサーバー側で検証されずに届きます。途中で切れたJSONを受け取る前提を避けたい経路では、切る選択もあります。体感の速さを取るか、完成済みの入力だけを受け取る安心を取るかの判断です。
Microsoft Foundryについては、環境変数リファレンスの記載が「既定でオフ」までです。1で強制できるかは書かれていないため、Foundryで試すときは、設定して挙動を確かめる手順が要ります。強制オンの対象として名指しされているのは、3つのベースURL変数経由のプロキシ構成だけです。
効いたかどうかの確かめ方
設定したあとは、実際に大きなツール入力を作って確かめます。たとえば、長めのファイルを新規作成させる指示を出し、生成中に画面が動くかを見ます。
CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING=1 claude起動した対話セッションで「500行ほどのサンプルデータをdata.csvに書き出して」と頼み、書き込みの生成中に画面が動くかを見ます。変数あり・なしで同じ指示を1回ずつ走らせ、最初に文字が出るまでの時間を比べると差が分かります。変化が出ない場合は、前節のゲートウェイ側を確認します。
本当に固まっているときとの切り分け
見た目が同じでも、通信が止まっている場合は別の問題です。Claude Codeには、判別の手がかりがあります。
応答ストリームにデータが20秒届かず、リクエストがまだ保留中のとき、スピナーにWaiting for API response · will retry in … · check your networkと出ます。これが出るなら、逐次ストリーミングではなく通信側を疑います。この表示は、バージョンによって閾値と文言が異なります(v2.1.185より前は10秒で、文言も別でした)。
| 状況 | 見えるもの | 疑うところ |
|---|---|---|
| ツール入力が大きい書き込みの間だけ止まる | 見えるものスピナーが回り続ける | 疑うところ逐次ストリーミングがオフ |
| 20秒以上データが届かない | 見えるものWaiting for API responseの表示 | 疑うところネットワーク、ゲートウェイ |
| 途中で切れる | 見えるものThe response above may be incompleteなど | 疑うところサーバー側の中断、接続断 |
逆に、書き込みの途中でスピナーが動いていて、しばらく待てば結果が出るなら、設定の問題として扱えます。切れたまま戻らない場合は通信の問題で、この変数では直りません。
ツール呼び出しそのものが実行されず、文字列として出力されてしまう別の不具合はClaude Codeでツール呼び出しが実行されない不具合で扱っています。
APIのeager_input_streamingとの関係
Claude APIを自作アプリから呼ぶ場合は、同じ仕組みがAPI側のパラメーターになります。ツール定義にeager_input_streaming: trueを付けると、そのツールの入力が検証なしで断片のまま届きます。API側の解説は、不完全なJSONや、max_tokensで途中で切れたパラメーターが届きうると警告しています。
Claude Codeの環境変数が切り替えるのも、このAPI側の逐次ストリーミングです。自作アプリでの組み込みとJSONの扱いはeager_input_streamingの設定に書きました。
まとめ
画面の沈黙が大きなツール入力のときだけ起きるなら、まず接続先を確かめます。Foundryやゲートウェイなら既定がオフなので、CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING=1で改善する可能性があります。直接のAnthropic APIで同じ症状が出るなら、この変数ではなく通信側の問題です。