Skip to main content

7. PTC / Code Mode: なぜモデルにコードを書かせてツールを呼ばせるのか

7.1 従来の逐次的ツール呼び出しにはどのようなオーバーヘッドがあるか

タスク: 「3 つのモジュールのリスク結果を読み取り、高リスクを絞り込み、重複を統合する。」 基本的なやり方では、モデルが繰り返し関与します。ツール要求 → 大きな JSON 受信 → 次の要求生成 → データ受信 → 項目ごとに要約。フィルタリング、ソート、グルーピング、数値計算に対して、モデルは最も安価でも最も信頼できる実行器でもありません。 PTC は確定的なステップを 1 本のプログラムに任せます。
ここでのコードはツールをオーケストレーションしているのであって、モデルを再学習させているわけではありません。ツール自体は MCP、通常の関数、Shell など多様な由来のままで構いません。

7.2 制御フローとデータフローの変化

n 件の結果がそれぞれ S token だとすれば、直接すべてを見せると結果の負担は n*S に近くなります。コードで R token に集約すれば、モデルが目にするデータは R に近づき、そこにプログラム、ツール定義、プロトコルのオーバーヘッドが加わります。元のツール I/O は依然として存在し、モデルへ渡す量が少ないことをシステム全体でこれらのデータを扱わないことと同一視してはいけません。

7.3 OpenAI API PTC と Codex Code Mode の違い

API PTC のドキュメントが述べているのは、マネージドな JavaScript 実行です。programmatic_tool_calling を有効化し、ツールごとに allowed_callers を設定し、プログラムは隔離された V8 環境で動きます。一般的な Node、ファイルシステム、ネットワークの能力は持ちません。アプリ自身のツールは依然としてアプリが実行します。Programmatic Tool Calling Codex の公開ソースには、ローカル/リモートの Code Mode Host、runtime、session、cell、execute/wait などのモジュールもあります。これらは「コードでツールをオーケストレーションする」という同じ発想を体現しますが、API PTC とそのまま置き換え可能なインターフェースではありません。ソースには session の明示的な stored values と cell のライフサイクルがあり、それらを API PTC もプログラムをまたぐグローバル変数の永続化を約束していると書いてはいけません。Code Mode runtimeSession runtime

7.4 V8 isolate はどのようにツールにつながっているか

以下は公開コードの構造に基づいて整理した原理の例示で、具体的な転送の詳細は省略しています。
固定したソースには、RuntimeCommand の中のツール応答、エラー、タイムアウト、終了と、RuntimeEvent の中の ToolCall、Pending、YieldRequested、Result が確認できます。これは isolate の外側にホストのスケジューリングとメッセージブリッジがあることを示しており、「V8 を使っている」というのはそのうちの一層を述べているに過ぎません。 V8 isolate は完全な OS サンドボックスでもありません。信頼できないプログラムの乱用を防ぐには、取得できるツール、呼び出し回数、出力量、CPU/メモリ、実行時間、ネットワークとファイルの権限も制限する必要があります。特に、無制限の shell を与えてから「安全な API しか使えない」と主張してはいけません。

7.5 実 API 接続で最も抜けやすいフィールド

ネストされた function_call には caller メタ情報が付きます。function_call_output を返送する際は、呼び出しから返ってきた caller を保持し、サーバー側で正しいプログラムを復元できるようにしなければなりません。ステートレスに続行する場合も、program、fingerprint、reasoning など返却項目一式を保持する必要があり、出力テキストだけをつなげてはいけません。
完全な例は live_api.py ptc を参照してください。この例は API から返されたプログラムをマネージドランタイムに返送して継続させます。ローカルで eval() を使ってモデルのコードを実行することはしません。

7.6 なぜローカル Demo は allSettled を使っているのか

Promise.all は 1 つでも rejection があるとすぐ reject しますが、残りの作業は自動でキャンセルされません。上位側で全体例外だけを見ると、部分的な成功結果を失う一方で、すべての動作が起きなかったと誤認するおそれがあります。 ptc_demo.mjsallSettled で各結果を集め、由来を保持し、欠けたモジュールを partial として記録します。これは読み取り専用の集約に適します。すべてのタスクを allSettled にすべきという意味ではありません。1 ステップ目が失敗すれば 2 ステップ目に意味がない場合は、依存順に停止すべきです。書き込み操作なら、明確なコミット境界を保つのが望ましいです。

7.7 PTC と MCP の関係

MCP は Host、Client、Server がどのように能力とデータを交換するかを規定し、PTC はモデルがプログラムでどのように呼び出しを組み立てるかを規定します。片方は接続プロトコル、もう片方は実行/オーケストレーションの方式であり、組み合わせて使えます。MCP アーキテクチャ仕様
Anthropic は公開記事で、ツール記述や中間データによるコンテキスト負担を減らすために code execution と MCP を組み合わせることについて論じています。したがって「コードでツールを呼ばせるやり方を理解しているのは Codex だけ」というのは成り立ちません。Anthropic: Code execution with MCP

7.8 面接での回答

PTC は、確定的な制御フローとデータ処理をモデルとの逐次対話からプログラム側へ移すやり方で、バッチ的な読み取り専用クエリ、フィルタ、集約、予測可能な依存チェーンに向いています。主な利得はモデル往復と中間コンテキストの削減であり、ツール実行コストの消失ではありません。MCP とは直交し、ネストされた各呼び出しでも権限、予算、監査は依然として必要です。