ツール呼び出しのロール設計:Claude Code vs Codex
背景
今回の論点:なぜ Claude Code / Anthropic のツール結果は role: user に置かれているように見え、Codex / OpenAI Responses API はツール呼び出しとツール結果を独立イベントとして扱っているように見えるのか。
厳密に区別すると:
- Claude は tool call そのものを
userとは定義していない。Claude の tool call は assistant 側のtool_useだ。 role: userに置かれるのは、ツール実行後のtool_resultである。- この
userは生身のユーザーと等しくなく、client / environment 側が外部の観察結果をモデルへ差し戻すものに近い。
中核の判断
Claude の設計は「会話入力ストリーム」として理解できる:
assistant:モデル自身の発話と、自身のtool_useuser:外部世界からモデルへの新しい入力。人間のメッセージ、環境コンテキスト、ツール結果を含むtool_resultは content block type とtool_use_idで先行するツール呼び出しに対応づく
この設計の利点は、schema が単純で、会話ループが素直で、content block が統一されていること。代償は transcript の可読性だ:大量の role: user の中身は実は人の発話ではなく、shell output、file read、MCP response といったツールの観察である。
Codex / OpenAI Responses の設計は「agent イベントストリーム」に近い:
- ユーザーのメッセージは引き続き
role: user - モデルによるツール要求は
function_call - ツールの返りは
function_call_output - 両者は
call_idで対応づく
この設計の利点は、監査・リプレイ・状態機械・権限分析がより明快なこと。ツール出力は user ロールに混ざらず、ロール体系は主に指示の権威を表現し、ツール出力は observation として扱われる。代償はプロトコルの複雑さで、他のモデルやフレームワークに適配するときは typed items の処理が要る。
一言で言えば:
Claude はツール結果を会話入力ストリームに入れ、Codex はツール結果を agent イベントストリームに入れる。
それぞれ何に向くか
Claude のやり方が向くのは:
assistant tool_use -> client execute -> user tool_result -> assistant continueのループを素早く実装する- 二ロールの message schema を使い、role を増やしすぎない
- テキスト・画像・ツール呼び出し・ツール結果を統一 content block に収める
Codex のやり方が向くのは:
- 複雑なローカル agent runtime
- 多ツール・多ラウンド実行、approval、sandbox、sub-agent などのイベント監査
- ツール出力を human/user メッセージに混ぜず、追跡可能な observation として扱う
- その先の Trace Log、リプレイ、圧縮、権限境界の分析
発展させうる記事の切り口
agent runtime の表現層についての記事に育てられる。仮の切り口:
- タイトル方向:
会話ストリームかイベントストリームか:agent のツール結果はどこに置くべきか - 主線の問い:tool result はユーザー入力なのか、環境の観察なのか、それとも agent runtime のイベントなのか?
- 中核の緊張関係:単純な API schema と、長期に監査可能な runtime とのトレードオフ
- 既存記事の
Trace Logへ延長できる:良い Trace Log は最終出力だけを記録せず、人間の指示・システム制約・モデルの決定・ツールの観察・環境の副作用を区別できなければならない
残る問い
- ツール出力に prompt injection が含まれる場合、
role: userの下ではより高権威の指示と誤認されやすくならないか? - 自作の agent harness は
userを流用せず、明示的なobservation/tool_result層を定義すべきではないか? - Trace Log は可読性と、モデルが消費し続けられる構造を、どう同時に保つべきか?