きめ細かいツールストリーミング
レイテンシに敏感なアプリケーション向けに、サーバー側のJSONバッファリングなしでツール入力をストリーミングします。
「fine-grained tool streaming」(きめ細かいツールストリーミング)は、サーバー側のバッファリングやJSON検証を行わずに、Claudeが生成するのと同時にツールの入力をクライアントに配信します。バッファリングのステップを省略することで、ドキュメントやコードブロックのような大きなパラメータの最初のフラグメントが届くまでの時間が短縮されます。フラグメントは、標準のツール使用と同じメッセージのストリーミングイベントを通じて届きます。
きめ細かいツールストリーミングの使用方法
すべてのモデルが、Claude API、Amazon Bedrock、Claude Platform on AWS、Google Cloud、およびMicrosoft Foundryできめ細かいツールストリーミングをサポートしています。使用するには、きめ細かいストリーミングを有効にしたいユーザー定義ツールでeager_input_streamingをtrueに設定し、リクエストでストリーミングを有効にします。
eager_input_streamingフィールドはオプションです。trueに設定するとそのツールのきめ細かいストリーミングがオンになり、省略すると標準のバッファリングされたストリーミングになります。標準のバッファリングされたストリーミングでは、APIが各パラメータ値をバッファリングして検証してからストリーミングで返します。例外は、レガシーのfine-grained-tool-streaming-2025-05-14ベータヘッダーをまだ送信しているリクエストで、この場合はフィールドが未設定のツールに対してきめ細かいストリーミングがオンになります。ツールごとのフィールドはそのヘッダーに代わるものであり、明示的にfalseを指定すると、リクエストがまだヘッダーを送信している場合でも、そのツールではバッファリングされたストリーミングが維持されます。レガシーヘッダーはコンピュータ使用またはブラウザ使用のツールセットエントリと組み合わせることはできません。APIは両方を送信するリクエストを拒否するため、ヘッダーを削除し、必要なユーザー定義ツールにeager_input_streamingを設定してください。フィールドの定義についてはツールリファレンスを参照してください。
次の例では、make_fileツールのきめ細かいストリーミングをオンにし、Claudeに長い詩を依頼します。これにより、ツール入力がストリーミングされる様子を観察できるほど大きくなります。
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=65536,
model="claude-opus-5-5",
tools=[
{
"name": "make_file",
"description": "Write text to a file",
"eager_input_streaming": True,
"input_schema": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The filename to write text to",
},
"lines_of_text": {
"type": "array",
"description": "An array of lines of text to write to the file",
},
},
"required": ["filename", "lines_of_text"],
},
}
],
messages=[
{
"role": "user",
"content": "Can you write a long poem and make a file called poem.txt?",
}
],
) as stream:
for event in stream:
if event.type == "input_json":
print(event.partial_json, end="", flush=True)
final_message = stream.get_final_message()
print()
for block in final_message.content:
if block.type == "tool_use":
print(f"Complete tool input: {block.input}")すべてのタブでmake_fileツールのきめ細かいストリーミングがオンになっています。SDKのタブでは、各入力フラグメントが届いた瞬間に出力し、ストリームが終了すると蓄積された完全な入力を出力します。cURLタブは生のイベントストリームを表示し、CLIタブはjqを使用してフラグメントのみを出力します。出力されたフラグメントは結合されて完全なツール入力になるため、Claudeが書くにつれて詩がターミナルを埋めていきます。
{"filename": "poem.txt", "lines_of_text": ["The Wanderer's Journey", "", "I.", "", "Beneath the vast and star-strewn sky,", "Where silver moonbeams softly lie,", ...
Complete tool input: {"filename": "poem.txt", "lines_of_text": ["The Wanderer's Journey", ...]}eager_input_streamingがない場合、APIは各パラメータ値をバッファリングして検証してからストリーミングで返すため、大きなパラメータについてはClaudeが生成を終えるまで何も出力されません。これを有効にすると、Claudeがパラメータの生成を始めるとすぐにフラグメントが届き始め、フラグメントは通常より長く、単語の途中で区切られることも少なくなります。
ツール入力デルタの蓄積
蓄積の規約は標準のツール使用ストリーミングと同じであるため、このセクションはeager_input_streamingの有無にかかわらず適用されます。イベント形式については、メッセージのストリーミングの入力JSONデルタを参照してください。きめ細かいツールストリーミングでは、結果について想定できることが変わります。サーバーはフラグメントを検証せずにストリーミングするため、蓄積された文字列が有効なJSONではない可能性があります。
tool_useコンテンツブロックがストリーミングされるとき、最初のcontent_block_startイベントにはinput: {}(空のオブジェクト)が含まれます。これはプレースホルダーです。実際の入力は一連のinput_json_deltaイベントとして届き、それぞれがpartial_json文字列フラグメントを持ちます。完全な入力を組み立てるには、これらのフラグメントを連結し、ブロックが閉じたときに結果をパースします。
SDKがアキュムレータヘルパーを提供している場合(前の例のPython、TypeScript、Go、Java、Rubyのタブのように)、ヘルパーがこれを処理します。手動のパターンは、ヘルパーのないSDK向け、または入力の組み立て方法を完全に制御したい場合向けです。
蓄積の規約:
type: "tool_use"のcontent_block_startで、空の文字列を初期化します:input_json = ""type: "input_json_delta"の各content_block_deltaで、追加します:input_json += event.delta.partial_jsoncontent_block_stopで、蓄積された文字列をパースします
以下のSDKの例のように、パースをガードしてください。レスポンスはパラメータの途中でmax_tokensにより停止することもあります。停止理由を確認し、より大きなmax_tokensでリクエストを再試行するか、部分的な入力を修復するかを判断してください。
最初のinput: {}(オブジェクト)とpartial_json(文字列)の型の不一致は設計によるものです。空のオブジェクトはコンテンツ配列内のスロットを示します。デルタ文字列が実際の値を構築します。
client = anthropic.Anthropic()
tool_inputs: dict[int, str] = {} # index -> accumulated JSON string
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get current weather for a city",
"eager_input_streaming": True,
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
],
messages=[{"role": "user", "content": "Weather in Paris?"}],
) as stream:
for event in stream:
match event.type:
case "content_block_start" if event.content_block.type == "tool_use":
tool_inputs[event.index] = ""
case "content_block_delta" if event.delta.type == "input_json_delta":
tool_inputs[event.index] += event.delta.partial_json
case "content_block_stop" if event.index in tool_inputs:
raw_input = tool_inputs[event.index]
try:
parsed = json.loads(raw_input)
except json.JSONDecodeError:
# 蓄積された文字列が有効なJSONであるとは限りません。
# このページの「ツールレスポンスにおける無効なJSONの処理」を参照してください。
print(f"Invalid tool input: {raw_input}")
else:
print(f"Tool input: {parsed}")ツールレスポンスにおける無効なJSONの処理
きめ細かいツールストリーミングでは、ツール呼び出しの蓄積された入力が無効または不完全なJSONである可能性があります。その場合はツールを実行できないため、代わりに失敗をClaudeに報告してください。ツール結果のcontentはJSONである必要はありませんが、生の文字列を単一のキーの下でJSONオブジェクトにラップすると、無効なJSONを受け取ったことがClaudeに明確に伝わり、デバッグ用に元の入力も保持されます。
{
"INVALID_JSON": "<the unparseable input you received>"
}文字列にシリアライズしたラッパーを、is_errorをtrueに設定したツール結果コンテンツブロックのcontentとして返します。
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"is_error": true,
"content": "{\"INVALID_JSON\": \"<the unparseable input you received>\"}"
}次のステップ
コンテキストウィンドウの仕組み、拡張思考とツール使用がどのようにカウントされるか、会話が長くなるにつれてコンテキストをどのように管理するかを理解します。
テキスト、ツール使用、拡張思考のデルタを含むMessages APIレスポンスを、サーバー送信イベントで段階的にストリーミングします。
tool_useブロックをパースし、tool_resultレスポンスをフォーマットし、is_errorでエラーを処理します。
Anthropic提供ツールの一覧と、オプションのツール定義プロパティのリファレンス。
Was this page helpful?