一行要約
Claude にツールを呼ぶ Python コードを書かせて、中間結果を context に載せずに処理させる仕組み。効くのは fan-out 型のワークロードだけ — 逐次的な流れでは効かず、τ²-bench ではむしろ 8% 高くついた。
要点
動作
- Claude がツールを関数として呼ぶ Python コードを書く(複数呼び出しと前後処理を含みうる)
- サンドボックスコンテナで実行する
- ツール関数が呼ばれるとコード実行が一時停止し、API が
tool_useブロックを返す - こちらがツール結果を返すとコード実行が続く。中間結果は Claude の context window にロードされない
- 実行完了後、Claude が最終出力を受け取る
Tools that allow a code execution caller are exposed to Claude’s code as async Python functions, so Claude can run them in parallel with
asyncio.gather. Each function takes a single dict of arguments and returns a string: the text of thetool_resultyou send back. code execution からの呼び出しを許可したツールは、Claude のコードに対して async な Python 関数として公開される。そのため Claude はasyncio.gatherで並列に実行できる。各関数は引数の dict をひとつ受け取り、文字列を返す。返すのは、あなたが送り返すtool_resultのテキストである。
→ Claude 側のコードは rows = json.loads(await query_database({"sql": "<sql>"})) のように自分で JSON をパースする。
allowed_callers
| 値 | 意味 |
|---|---|
["direct"] | 直接呼ぶよう誘導(省略時の既定) |
["code_execution_20260120"] | コード実行内からのみ呼ぶよう誘導 |
["direct", "code_execution_20260120"] | どちらも可 |
Choose either
["direct"]or["code_execution_20260120"]for each tool rather than enabling both, as this provides clearer guidance to Claude. **各ツールについて["direct"]か["code_execution_20260120"]のどちらかを選べ。両方を有効にするな。**そのほうが Claude への指示が明確になる。
重要な注意:
allowed_callerscontrols how the tool is presented to Claude and is validated againsttool_choice, but it is not a hard API-level block on direct invocation. Your client should still be prepared to handle a directtool_usefor any tool it defines. Do not rely onallowed_callersas a security boundary.allowed_callersはツールが Claude にどう提示されるかを制御するもので、tool_choiceに対して検証もされるが、直接呼び出しを API レベルで硬く禁じるものではない。クライアントは、自分が定義したどのツールについても直接のtool_useを処理できるよう備えておくべきである。allowed_callersをセキュリティ境界として当てにするな。
レスポンスの caller フィールド
すべての tool_use ブロックが caller を持つ。
{"caller": {"type": "direct"}}
{"caller": {"type": "code_execution_20260120", "tool_id": "srvtoolu_abc123"}}tool_id は呼び出した code execution の server_tool_use の id なので、どの実行が生んだ呼び出しかを対応付けられる。
コンテナのライフサイクル(タイムアウトが厳しい)
- リクエストごとに新しいコンテナ(再利用しない限り)
- プログラム的ツール呼び出しが結果を待っている間、コンテナ ID は必須(任意ではない)。ないとリクエストが拒否される
- アイドルのコンテナは約5分で回収される。 作成から30日を超えて再利用はできない
- 待機中のツール呼び出しは約4分でタイムアウトし、コード内で
TimeoutErrorを投げる
メッセージ書式の制約(実装で必ず踏む)
Tool result only responses: If there are pending programmatic tool calls waiting for results, your response message must contain only
tool_resultblocks. You cannot include any text content, even after the tool results. tool result のみの応答: 結果待ちの programmatic なツール呼び出しが残っている場合、応答メッセージにはtool_resultブロックのみを含めなければならない。テキストの内容を含めることはできない。tool result の後であっても不可である。
Text-only tool result content: The
contentof eachtool_resultthat answers a programmatic call must be a string ortextblocks. Image, document, and other content block types are rejected. tool result の内容はテキストのみ: programmatic な呼び出しに応える各tool_resultのcontentは、文字列またはtextブロックでなければならない。画像・文書その他のコンテンツブロック型は拒否される。
この制約はプログラム的な呼び出しへの応答時のみ。 通常のツール呼び出しではテキストを含めてよい。
使えない組み合わせ
strict: trueの structured outputstool_choiceで特定ツールのプログラム的呼び出しを強制することはできないdisable_parallel_tool_use: true- MCP connector 提供のツールはプログラム的に呼べない
input_schemaに再帰的な$refを含むツール —allowed_callersに code execution を入れると400 invalid_request_errorのCircular $ref detectedになる(同じスキーマでも直接呼び出しなら受理される)
トークン効率の実測(ここが最も重要)
削減の仕組みは3つ — プログラム的呼び出しのツール結果は context に入らない、中間処理がコード内で完結する、1回のコード実行で複数のツール呼び出し。
| 条件 | 結果 |
|---|---|
| 75ツールのプロジェクト管理エージェントのベンチマーク | 課金入力トークンが約 38% 減り、タスク精度は変わらず |
| τ²-bench(1ターンに1〜2回の逐次的なツール呼び出し) | スコアは変わらず、コストは約 8% 増。逐次的な単発呼び出しのワークフローは恩恵を受けない |
本番トラフィック全体(tools が 10〜49 個) | 典型的に 20〜40% の削減 |
課金: プログラム的呼び出しのツール結果は入出力トークンに算入されない。最終的なコード実行結果と Claude の応答だけが算入される。
向き / 不向き
向く:
- 多数の項目への fan-out / 並列操作(50 エンドポイントの確認、20 レコードの照会)
- context に届く前にフィルタ・集約・要約できる大きなツール結果
- agentic な検索と取得 — 反復的なクエリと結果フィルタが主体のワークフロー
向かない:
- 厳密に逐次的なワークフロー — 各呼び出しが前の結果に対する Claude の推論に依存する場合、スクリプトはモデルのラウンドトリップを飛ばせない
- 少数のツール呼び出しで応答も小さい場合(特に会話の最初のターン)— コンテナとスクリプトのオーバーヘッドが節約を上回りうる
- 呼び出しの間にユーザーのフィードバックが要るツール
If you are unsure, measure billed input tokens with and without
allowed_callerson a representative sample of your traffic before enabling it broadly. 判断がつかないなら、広く有効にする前に、代表的なトラフィックのサンプルでallowed_callersの有無それぞれの課金対象入力トークンを測れ。
ツール設計のコツ
- 出力形式を詳細に文書化する — Claude はコード内で結果をデシリアライズするので、JSON の構造とフィールドの型を書く
- 構造化データを返す
- 応答は簡潔に
そのまま使える具体例
ツールをプログラム的呼び出しの対象にする:
{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query to execute"}
},
"required": ["sql"]
},
"allowed_callers": ["code_execution_20260120"]
}バッチ処理(N ラウンドトリップが1回になる):
regions = ["West", "East", "Central", "North", "South"]
results = {}
for region in regions:
rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))
results[region] = sum(row["revenue"] for row in rows)
# Process results programmatically
top_region = max(results.items(), key=lambda x: x[1])
print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")早期終了:
endpoints = ["us-east", "eu-west", "apac"]
for endpoint in endpoints:
status = await check_health({"endpoint": endpoint})
if status == "healthy":
print(f"Found healthy endpoint: {endpoint}")
break # Stop early, don't check remaining条件によるツール選択:
path = "/tmp/example.txt"
file_info = json.loads(await get_file_info({"path": path}))
if file_info["size"] < 10000:
content = await read_full_file({"path": path})
else:
content = await read_file_summary({"path": path})
print(content)データのフィルタ(大量のログから必要な分だけ返す):
server_id = "srv-01"
log_text = await fetch_logs({"server_id": server_id})
errors = [line for line in log_text.splitlines() if "ERROR" in line]
print(f"Found {len(errors)} errors")
for error in errors[-10:]: # Only return last 10 errors
print(error)応答メッセージの書式(テキストを混ぜると拒否される):
// ❌ 無効
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "toolu_01", "content": "[...]"},
{"type": "text", "text": "What should I do next?"}
]}
// ✅ 有効
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "toolu_01", "content": "[...]"}
]}原典で言及されている関連文書
- advanced-tool-use — この機能の発表と実測値(37%削減)
- code-execution-with-mcp — MCP に同じ発想を適用したもの
- manage-tool-context — 4手法の使い分け
- tool-search-tool — 併用できるもう一方の手段
- demystifying-evals-for-ai-agents — τ²-bench
未取得の派生リンク
- https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool — code execution ツール本体と課金
- https://claude.com/blog/improved-web-search-with-dynamic-filtering — 検索での 11% 改善 / 24% トークン削減