NVIDIA Dynamoによるエージェント推論のフルスタック最適化
NVIDIAは、AIエージェントによる本番コード生成が大規模化する中で、エージェント推論のためのフルスタック最適化ソリューション「Dynamo」を発表し、StripeやRampなどの実例を通じてその実用性と生産性向上効果を示した。
キーポイント
AIエージェントによる本番コード生成の大規模化
Stripeのエージェントは週に1,300以上のプルリクエストを生成し、Rampではマージされたプルリクエストの30%がエージェントによるものであるなど、AIエージェントが実際のプロダクションコード生成に大規模に活用され始めている。
NVIDIA Dynamoによるフルスタック最適化
NVIDIAは、エージェント推論のためのフルスタック最適化ソリューション「Dynamo」を発表し、AIエージェントの推論パフォーマンスと効率を向上させる技術を提供している。
実用性と生産性向上の実証
StripeやRampといった企業での実例が示されており、AIエージェントが開発ワークフローに統合され、具体的な生産性向上(PR生成数、マージ率)に貢献していることが分かる。
影響分析・編集コメントを表示
影響分析
この記事は、AIコーディングエージェントが単なる実験的ツールから、実際のソフトウェア開発プロセスに不可欠な生産性向上ツールへと移行しつつある重要な転換点を示している。NVIDIAのような主要プレイヤーが専用の最適化ソリューションを投入することは、この分野の成熟とさらなる普及を加速させる可能性が高い。
編集コメント
AIコーディング支援が「便利な機能」から「開発プロセスのコア」へと変貌する可能性を感じさせる、業界の重要な動向を伝える記事。実績数値の具体性が説得力を持っている。
コーディングエージェントが、本番環境のコードをスケールして書き始める時代になりました。Stripeのエージェントは週に1,300件以上のプルリクエスト(PR)を生成しています。RampはマージされたPRの30%をエージェントに帰因しています。Spotifyでは月間650件以上のエージェント生成PRが報告されています。Claude CodeやCodexのようなツールは、コーディングセッションごとに数百回のAPI呼び出しを行い、各呼び出しには会話履歴全体が伴います。これらのワークフローの背後には、大きなKVキャッシュ(KV cache)の負荷がかかる推論スタックが存在します。
図1. シーケンシャルなリクエスト間でプロンプトとコンテキストが繰り返し再利用されるため、Agentic Inferenceにおける累積のKVキャッシュ読み取りは書き込みを大幅に上回ります。
Claude Codeを例に取ってみましょう。会話プレフィックスをKVキャッシュに書き込む最初のAPI呼び出しの後、同じワーカーへの後続の呼び出しはすべて85〜97%のキャッシュヒット率を記録します。エージェントチーム(またはスウォーム)は、4人のOpusチームメイト全体で97.2%の集計キャッシュヒット率を達成し、これをさらに押し上げます。11.7倍の読み取り/書き込み比は、システムが書き込むトークンごとにキャッシュからほぼ12回読み取ることを意味します。これは1回書き込み複数読み取り(Write-Once-Read-Many / WORM)アクセスパターンです:システムプロンプトと成長する会話プレフィックスは一度計算され、その後のすべての呼び出しでキャッシュから提供されます。Agentic Inferenceにおける中心的な最適化ターゲットは、すべてのワーカーにわたってキャッシュ再利用率を最大化し、KVブロックをウォームかつルーティング可能に保つことです。
これらの数値は、プロバイダーがプレフィックスマッチング(prefix matching)、キャッシュ配置(cache placement)、およびevictionを制御する管理されたAPIインフラストラクチャに由来します。独自のGPUでオープンソースモデルを実行するチームにとって、これらは何も組み込まれていません。私たちはこのギャップを埋めるためにDynamoの構築を進めてきました。本稿では、フロントエンドAPI、ルーター、KVキャッシュ管理という3つのレイヤーでDynamoをエージェントネイティブ化する方法について解説します。
本稿全体を通して、以下の3つの用語を一貫して使用します:
Harness: ワークフローを駆動するエージェントフレームワーク(Claude Code, Codex, OpenClaw, OpenCode, etc.)
Orchestrator: Dynamoのルーティング、スケジューリング、およびキャッシュ管理レイヤー
Runtime: モデルを実行しKVキャッシュマネージャーを所有する推論エンジン(SGLang, vLLM, TRT-LLM)
レイヤー1:フロントエンド
マルチプロトコルサポート(Multi-protocol support)
エージェント・ハーネスは、インターリーブされた思考(interleaved thinking)やツール呼び出し(tool calls)といった新しいパターンを明確に処理するため、v1/chat/completions に代わって v1/responses および v1/messages の採用を急速に広げています。これらの API における主な違いは構造的なものです。v1/chat/completions では、メッセージ内容は平坦な文字列であり、ツール呼び出しは別フィールドとして後付けされています。例えば、GLM や MiniMax API が v1/chat/completions エンドポイントの背後でモデルをホストする際、インターリーブされた思考(interleaved thinking)をどのように異なる形で処理しているかにご注目ください。v1/responses および v1/messages API は型付きコンテンツブロック(typed content blocks)を使用するため、単一のアシスタントの応答ターンに、思考、ツール呼び出し、テキストを区別されたオブジェクトとして含めることができます。これは推論(inference)において重要です。オーケストレーター(orchestrator)はブロックの境界を認識できるため、プロンプト最適化(prompt optimizations)を実行し、ブロックタイプごとに異なるキャッシュ(cache)およびスケジューリング(scheduling)ポリシーを適用できるからです。Dynamo は共通の内部表現を通じてこれら 3 つのエンドポイントをすべて提供するため、単一のデプロイメントで任意のハーネスに対する推論バックエンドとして機能できます。当チームは、Codex および Claude Code ハーネスを駆動するため、GLM-5 と MiniMax2.5 の Dynamo デプロイメントを社内環境で運用しています。これにより、キャッシュ再利用(cache reuse)のパフォーマンスにおいて同等の性能を目標としつつ、クローズドソースの推論(closed-source inference)に対してバックエンド実装をベンチマークできます。今後数週間以内に、両モデルのデプロイに関する完全な技術記事と最適化レシピを公開する予定です。
ビデオ 1. Dynamo を用いた Claude のサービング
ビデオ 2. Dynamo を用いた Codex のサービング
また、各種オープンソースモデルに対して、day-0 のツール呼び出し(tool call)および推論(reasoning)パースングのサポートにも注力しています。対象モデルがサポートされていない場合は、Issue を作成するか、tool-call-parser-generator スキルを使用して、お好みのハーネス向けに生成してください。
エージェントヒント:ハーネス・オーケストレーター(Orchestrator)インターフェース
現在、推論サーバーは匿名化されたトークン化リクエスト(tokenized requests)のみを認識します。しかし、エージェント・ハーネスにはインフラストラクチャが決して見えないグローバルコンテキストが存在します。どのエージェントがツール呼び出し(tool calls)でブロックされているか、どのエージェントが直近で起動したか、セッション内に残っているターン数、そして現在の呼び出しがクイックな検索(quick lookup)か長時間の合成処理(long synthesis)のいずれであるかといった情報です。コーディングエージェントを使用する場合、ユーザーは個々のトークンストリームではなく最終結果を待機するため、オーケストレーター(orchestrator)はエンドユーザーの体験に影響を与えることなく、エージェント間でリクエストの順序入れ替えと優先順位付けを行うことができます。セッションは長時間のツール呼び出し(tool-call)ポーズを挟みながら、数分から場合によっては数日間にわたって実行されます。この特性は、従来のサービングでは不可能な方法で推論スケジューリング(inference scheduling)を最適化するのに十分な条件です。
図 2. Dynamo を採用した場合、エージェントワークフロー全体で GPU ベースのランタイム(GPU-backed runtimes)へのアクセスを標準化するため、nvext 推論インフラストラクチャ層(inference infrastructure layer)が追加されることを示す、アジェンティックシステムスタックの比較図。
Dynamoの新しいエージェントヒント拡張機能は、このギャップを埋めるために設計されました。これにより、任意のハル(harness)が3つのAPIエンドポイントすべてでリクエストに構造化されたヒントを付加でき、ルーターとランタイムがエージェント対応のスケジューリングやキャッシュ判断を行うために必要なコンテキストを提供します。これはコミュニティと積極的に共同設計しているv1 APIであり、エージェントハルを構築するチームから、どのシグナルが最も有用かというフィードバックをいただければ幸いです。アイデアやご意見があれば、ぜひお問い合わせください。
{ "model": "MiniMaxAI/MiniMax-M2.5", "messages": [...], "tools": [...], "nvext": { "agent_hints": { "osl": 256, "speculative_prefill": true, "priority": 10 }, "cache_control": { "type": "ephemeral", "ttl": "1h" } }}
エージェントヒントフィールドの内容は以下の通りです:
priorityは、ルーターとエンジン全体のスケジューリングを制御します。Dynamo APIレベルでは「より重要」を意味し、Dynamoはこれをルーターのキュー順序とバックエンド固有のエンジン優先度に変換します。
osl(output sequence length:出力シーケンス長)は、このリクエストが生成するトークン数をハル(harness)が推定した値です。ルーターはこれを使用してワーカーが占有される時間を把握し、負荷分散を改善します。ハルはツール呼び出しタイプごとの平均出力長を追跡することで、時間とともにこれを学習できます。
speculative_prefillは、完全なリクエストが準備完了する前に、おそらくのワーカー上でこのリクエストのプレフィックスのキャッシュ開始をオーケストレーターに通知するシグナルです。これは、ハルがツール呼び出しの返却が近づいていることを把握し、事前にキャッシュをウォームアップしたい場合に有用です。
cache_controlフィールドは、AnthropicのプロンプトキャッシュAPIを使用したことのある方にはお馴染みの形式に見えるでしょう。これは、計算されたプレフィックスを指定されたTTL(Time To Live)の間ワーカーに固定し、ツール呼び出しのギャップ中に_eviction_(削除/解放)から保護するようオーケストレーターに指示します。現在、ephemeralのみがサポートされているタイプです(AnthropicのAPIに合わせるため)。この動作の詳細については、以下のキャッシュ保持セクションで説明します。エージェントヒントの完全なドキュメントはここからご覧いただけます。
レイヤー2:ルーター
コーディングエージェントは、長期のプレフィックス、ツール呼び出し、拡張されたプレフィックス、繰り返しというシーケンシャルパターンに従います。マルチエージェントハルは、短く独立したコンテキストを持つ並列サブエージェント間で作業を分散します。デフォルトのラウンドロビンルーティングはこれらのパターンに対して盲点があり、キャッシュの局所性、リクエストの優先度、セッション構造を考慮できません。Dynamoのルーターは、KV対応配置(KV-aware placement)、優先度スケジューリング、拡張可能なルーティング戦略の3つのメカニズムでこのギャップを埋めます。
KV対応配置(KV-aware placement)
キャッシュ認識ルーティング (cache-aware routing) を行わない場合、会話のターン2がターン1と同じワーカーに割り当てられる確率は約1/Nとなります。キャッシュミスが発生するたびに完全なプレフィックスの再計算 (prefix recomputation) が必要となり、これは重大なパフォーマンスボトルネックであり、エンドユーザーにとって極めて高コストとなります。Dynamoのルーターは、どのKVキャッシュブロック (KV cache blocks) がどのワーカーに存在するかを示すグローバルインデックスを維持しています。Flash Indexerの投稿では、このインデクサーを170M ops/s(惑星規模のKVルーティング (planetary scale KV routing))に到達させた6回のイテレーションについて解説しています。リクエストごとに、ルーターはインデックスを照会してワーカーごとのオーバーラップスコア (overlap scores) を取得し、キャッシュミスと現在のデコード負荷 (decode load) の合計コストを最小化するワーカーを選択します。このコスト関数は調整可能であり、以下ではチームがこれに基づいてカスタムエージェント認識ルーティング (agent aware routing) 戦略を構築する方法を示します。
優先度スケジューリング (Priority scheduling)
優先度は、ユーザー側から操作できる唯一のスケジューリングノブ (scheduling knob) です。高い値はDynamo APIレベルで「より重要」を意味します。Dynamoはこのヒントを両方のレイヤーで使用します:
ルーター側では、--router-queue-thresholdが有効な場合、優先度の高いリクエストはキュー内でより前方にシフトされます。
エンジン側では、Dynamoはバックエンド固有の極性 (backend-specific polarity) を正規化し、キュー順序付け (queue ordering)、プリエンプション (preemption)、KVキャッシュの解放 (KV cache eviction) のためにリクエストを転送します。
ルーター側では、着信リクエストは有効到着時間 (effective arrival time) 順に並べられたBinaryHeap<QueueEntry>に入ります。優先度が高いほど、そのリクエストはより早く到着したかのように扱われ、優先度の低い作業の前に配置されます。リクエストはすべてのワーカーが設定可能な負荷閾値 (load threshold) を超えた場合にのみキューに入ります。その閾値を下回る場合、リクエストはキューを完全にスキップしてワーカー選択に直接進みます。容量が解放された場合(プレフィル (prefill) 完了またはリクエスト終了)、キューは最も優先度の高いエントリから順に処理されます。
転送後、SGLang、vLLM、TRT-LLMはエンジン優先度を異なる方法で解釈する可能性があるため、Dynamoはバックエンドごとにエンジン向け値を正規化します。SGLangのようなエンジンは、メモリ逼迫時に優先度の低いブロックが最初に解放される優先度ベースのラディックスキャッシュ解放 (priority-based radix cache eviction) も使用できます。
図3。この図は、エージェント推論 (agentic inference) におけるリクエストルーティングと優先度付けを示しており、レイテンシに敏感なタスク (latency-sensitive tasks) はより早く転送され、エンジン側でより高い優先度とキャッシュ保持 (cache retention) が割り当てられます。
エージェントワークロードルーティング戦略 (Agentic workload routing strategies)
200Kのコンテキストウィンドウ (context window) を持つ研究エージェントは、その完全な状態を保持するのに十分な空きKV容量 (KV capacity) を持つワーカーを必要とします。ルーターのデフォルトコスト関数(オーバーラップスコア+デコード負荷)は一般的なケースを処理しますが、ドメイン固有のワークロードを持つチームはルーターのPythonバインディング (Python bindings) を使用してカスタムルーティング戦略を実装できます。中核となるKvRouterクラス (KvRouter class) は、ルーティング判断の照会にbest_worker()を、ワーカーごとの負荷検査にget_potential_loads()を、ルーティング+転送を1つの呼び出しで行うgenerate()を提供します。カスタムルーターはデフォルトコンポーネントと同じサービスメッシュ (service mesh) に登録され、リクエストごとにルーティング設定を上書きできます:
カスタムルーティングロジックのためのワーカーごとの負荷(per-worker load)とオーバーラップ(overlap)をクエリする
loads = await router.get_potential_loads(token_ids)
リクエストのプロパティに基づいてルーティング設定(routing config)を上書きする
長いコンテキストはより重いオーバーラップ重み付けの恩恵を受ける
config = {"overlap_score_weight": 2.0} if len(token_ids) > 8192 else {}
worker_id, dp_rank, overlap = await router.best_worker(
token_ids,
request_id="req-123",
update_indexer=True,
router_config_override=config)
または、ハースが独自のワーカー選択ロジック(例:セッションアフィニティ)を持つ場合、デフォルトのセレクターを完全にバイパスする
stream = await router.generate(
token_ids, model=model, worker_id=chosen_worker)
NeMo Agent Toolkit (NAT) チームはこれらのAPIを使用して、カスタムなオンライン学習型エージェントルーター(online-learning agentic router)を構築しました。このルーターは、nvext注釈(nvext annotations)からセッションメタデータ(session metadata)を抽出し、負荷下でどのプレフィックスパターン(prefix patterns)に対してどのワーカーが最も優れたパフォーマンスを発揮するかを学習する、トンプソンサンプリングバンディット型コスト関数(Thompson Sampling bandit style cost function)に供給します。Dynamoのデフォルトルーティングと比較して、p50 TTFT(Time To First Token)が4倍短縮され、p50 トークン/秒(tokens-per-second)が1.5倍向上しました。レイテンシ敏感なリクエスト(latency-sensitive requests)への優先タグ付け(Priority tagging)により、中程度のメモリ圧力下でp50 TTFTが最大63%短縮されました。実装の詳細については、NAT Dynamo統合例(NAT Dynamo integration example)を参照してください。この機能はまもなくDynamoのルーティング戦略として提供される予定です。
レイヤー3:KVキャッシュ管理(KV cache management)
エージェントワークロード(Agentic workloads)は、再利用価値が大幅に異なるブロックを生成します。システムプロンプト(system prompts)は毎ターン再利用されますが、推論トークン(reasoning tokens)は一度生成されると二度と再利用されません。しかし、デフォルトのLRU Eviction(最近使用順によるブロック削除)はすべてのブロックを同一に扱います。2〜30秒のツール呼び出し一時停止(tool call pause)により、エージェントのプレフィックス全体が期限切れとなり、再開時に完全な再計算を強いられます。キャッシュはブロックの価値を理解し、ワーカー間共有(cross-worker sharing)をサポートし、エージェントライフサイクルの境界(agent lifecycle boundaries)を尊重する必要があります。
均一なEvictionの問題
ブロックタイプ(Block Type)再利用パターン(Reuse Pattern)価値(Value)システムプロンプト+ツール定義(System prompt + tool definitions)毎ターン最高会話履歴(Conversation history)その後のターン、単調に増加高推論/思考トークン(Thinking/reasoning tokens)推論ループ終了後、通常はゼロ再利用(出力の大部分)ほぼゼロサブエージェントKV(Subagent KV)複数ターン後にエージェントが終了。保持の必要なしほぼゼロ
LRUは近接性(recency)のみを認識します。高トラフィック環境では、呼び出されたツールの完了待ち(エージェントが外部APIを待機している間の2〜30秒)により、エージェントのブロックが期限切れになる可能性があります。そしてエージェントが再開した際、プレフィックス全体を再計算しなければなりません。これを解決するには、どのブロックを保持し、どこに配置し、どれだけの期間維持するかを制御するオーケストレーターAPI(orchestrator APIs)を提供する必要があります。
共有リソースとしてのKVキャッシュ(KV cache)
現在、KVキャッシュ(KV cache)は各ワーカーにおいてローカルで一時的なリソースとして扱われています。エージェントの約32Kトークンのシステムプロンプト(system prompt)とツール定義(tool definitions)は、そのリクエストを処理するすべてのワーカーで独立して計算されます。リードエージェント(lead agent)が4つのサブエージェント(subagents)を生成し、それぞれに重複するツール定義がある場合、それらのサブエージェントが異なるワーカーに配置されれば、その共有プレフィックスは4回再計算されます。Claude Codeのチームセッションを分析した際、これを直接測定しました。その結果、チームメイトのキャッシュヒット率(cache hit rate)は平均79.4%だったのに対し、リードエージェントの探索用サブエージェントは91.3%でした(読み書き比はそれぞれ5.0倍対11.7倍)。この差は、ほぼすべてが各チームメイトの初回呼び出し時のコールドスタート書き込み(cold-start writes)によって生じていました。目標は、高価値なKVキャッシュブロックをクラスター内のすべてのワーカーが利用可能にすることです。本質的には、これらはコールドスタート時に1回だけ書き込まれ、その後はいかなるワーカーからも常に読み取られるようになります。
SGLangのHiCacheやDynamoのKV Block Manager (KVBM)などのソリューションは、4層メモリ階層(4-tier memory hierarchy)の実現に向けて構築されています:
図4. ワーカー間でのスケーラブルな共有キャッシュの再利用を可能にするため、GPU、CPU、ローカルNVMe、リモートストレージにまたがる4層のKVキャッシュメモリ階層を示す図。
ブロックはライトスルーパス(write-through path)に従います。ワーカーがプレフィックスのKVを計算すると、ブロックはGPUからCPUへ、そしてディスクへと自動的に流れます。各ブロックは、グローバルレジストリ(global registry)内のシーケンスハッシュ(sequence hash)によって重複排除されます。一度ブロックが登録されると、それは不変となり、ストレージ階層にアクセスできる任意のワーカーからアドレス指定可能になります。
これにより、サブエージェントのコールドスタート問題が直接的に解決されます。リードエージェントがツール定義とシステムプロンプトを計算すると、それらのブロックは共有ストレージへライトスルーされます。サブエージェント1が別のワーカーで生成されると、ルーターはFlash Indexerを照会して共有ストレージ内のブロックを検出し、ワーカーはゼロから再計算するのではなくNIXL(RDMA read)を介してそれらを読み込みます。サブエージェント2も同様のことを行います。4回の冗長なプレフィル計算(prefill computations)が、1回の計算と3回の読み込みに変わります。同じメカニズムは、デカップリングされたプレフィル-デコードサービング(disaggregated prefill-decode serving)におけるキャッシュ一貫性(cache coherence)にも対応します。disaggモード(disagg mode)では、プレフィルワーカーがKVを計算し、それをNIXLを介してデコードワーカーへ転送します。デコードワーカーはトークンを生成し、新しいKV状態(KV state)を出力します。次のターンでは、プレフィルワーカーが元のプレフィックスと1ターン目で生成されたトークンの両方を必要としますが、それらはデコードワーカー上にのみ存在します。共有ストレージにより、デコードワーカーは新しいブロックを共通階層へ書き込み、任意のプレフィルワーカーが次のターンでそれらを取得できるようになります。
マルチティアーストレージは共有と永続化の問題を解決しますが、ブロックがGPUに転送されるのはリクエストがワーカーに到達した後のままです。エージェントシステム(agentic systems)にとって欠けていたピースはプリフェッチ(prefetch)です。ハーネス(harness)は過去のタイミングデータを使用してエージェントのツール呼び出しが返ってくる時期を予測でき、つまりどのブロックがいつ必要になるかを事前に把握できます。私たちはプリフェッチフック(prefetch hooks)を開発中であり、これによりハーネスは「次のリクエストの前にこれらのブロックをストレージからGPUへ持ってきてください」とシグナルを送ることができます。後述の保持API(retention APIs)と組み合わせることで、ハーネスは完全なライフサイクル制御を行使できます:追出し(eviction)を防ぐためのブロック固定(pin blocks)、追出し順序を制御する優先度設定、そして必要になる前に積極的にブロックをプリフェッチすることです。
図5. エージェント推論におけるKVキャッシュ(KV cache)のプリフェッチを示すダイアグラム。初期呼び出し後にブロックがオフロード(offloaded)され、その後のリクエストに先立ってストレージからGPUへ積極的にプリフェッチされる様子を表しています。
セレクティブキャッシュ保持(Selective cache retention)
ブロックをグローバルに利用可能にすることは共有の問題を解決しますが、追出し(eviction)の問題までは解決しません。SGLangとvLLMはどちらも、ハーネスがリクエストごとに数値優先度を割り当て、低優先度のブロックから先に追出しされるプライオリティヒープ(priority heap)を用いた優先度ベースの追出しをサポートしています。TensorRT-LLMは、単一リクエスト内での領域ごとの制御を可能にするTokenRangeRetentionConfig(Dynamoチームメンバー@jthomson04によって設計・実装)により、これをさらに一歩進めています。
リクエストにはゼロ個以上のディレクティブが含まれます。ディレクティブを持たないブロックは、オーバーヘッドゼロでデフォルトのLRU(Least Recently Used)パスに従います。evictor(追出し処理部)は2つの構造を持つシステムになります:優先度付けられていないブロック用のLRUフリーリスト(O(1)、変更なし)と、注釈付きブロック用の優先度キューです。ハーネスは「システムプロンプトブロックは最後に追出し(priority: 100);会話コンテキストは30秒のツール呼び出しを生き残る(duration: 45s);デコードトークンは最初に削除される(priority: 1)」と表現できますが、エンジン側はなぜそうなのかを理解する必要はありません。
Anthropicのプロンプトキャッシング(prompt caching)では、プレフィックスを自社のインフラ上でキャッシュ可能としてマークできます。Dynamoのcache_control APIは、同じセマンティクスをセルフホスト型推論に持ち込みます。リクエストに cache_control: { type: "ephemeral", ttl: "1h" } が含まれている場合、ルーターはワーカーのラジックスツリー(radix tree)内の一致するプレフィックスノードをそのTTL(Time To Live)期間で固定し、ワーカーのL2ストレージ内での追出しから保護します。
次のステップは、保持(retention)を分散キャッシュと接続することです。現在、保持ディレクティブは単一ワーカーのローカルキャッシュに適用されます。ブロックがワーカーAで固定されていても、次のリクエストがワーカーBにルーティングされる場合、その固定は追従しません。HiCache/KVBMの共有ストレージティア全体にわたって保持セマンティクスを拡張することで、ハーネスはブロックを一度固定するだけでワーカー間で生存させることができます:優先度とTTLメタデータはライトスルーパス(write-through path)を伴ってブロックと共に移動し、共有ストレージからブロックを読み込む任意のワーカーは保持ポリシーを継承します。前述のプリフェッチフックと組み合わせることで、これによりハーネスは完全なメモリ階層全体にわたってエンドツーエンドのライフサイクル制御を行使できます。
エージェントライフサイクル認識(Agent lifecycle awareness)
原文を表示
Coding agents are starting to write production code at scale. Stripe’s agents generate 1,300+ PRs per week. Ramp attributes 30% of merged PRs to agents. Spotify reports 650+ agent-generated PRs per month. Tools like Claude Code and Codex make hundreds of API calls per coding session, each carrying the full conversation history. Behind every one of these workflows is an inference stack under significant KV cache pressure.
Figure 1. Cumulative KV cache reads outpace writes in agentic inference due to repeated reuse of prompt and context across sequential requests.
Lets take Claude Code as an example. After the first API call that writes the conversation prefix to KV cache, every subsequent call to the same worker hits 85-97% cache. Agent teams (or swarms) push this further with 97.2% aggregate cache hit rate across 4 Opus teammates. An 11.7x read/write ratio means the system reads from cache nearly 12 times for every token it writes. This is a write-once-read-many (WORM) access pattern: the system prompt and growing conversation prefix are computed once, then served from cache on every subsequent call. Maximizing cache reuse rate across all workers and keeping KV blocks warm and routable is the central optimization target for agentic inference.
These numbers come from managed API infrastructure where the provider controls prefix matching, cache placement, and eviction. For teams running open-source models on their own GPUs, none of this exists out of the box. We have been building Dynamo to close that gap. This post walks through how we are making Dynamo agent-native at three layers: the frontend API, the router, and KV cache management.
Throughout this post, we use three terms consistently:
Harness: Agent framework that drives the workflow (Claude Code, Codex, OpenClaw, OpenCode, etc.)
Orchestrator: Dynamo’s routing, scheduling, and cache management layer
Runtime: Inference engine that executes the model and owns the KV cache manager (SGLang, vLLM, TRT-LLM)
Layer 1: The frontend
Multi-protocol support
Agent harnesses are increasingly adopting v1/responses and v1/messages over v1/chat/completions to cleanly handle new patterns including interleaved thinking and tool calls. The key difference in these APIs is structural. In v1/chat/completions, message content is a flat string and tool calls are bolted on as a separate field. As an example, notice how GLM and MiniMax API handle interleaved thinking differently when hosting their model behind the v1/chat/completions endpoint. The v1/responses and v1/messages APIs use typed content blocks, so a single assistant turn can contain thinking, tool calls, and text as distinct objects. This matters for inference because the orchestrator can see block boundaries, perform prompt optimizations, and apply different cache and scheduling policies per block type. Dynamo serves all three endpoints through a common internal representation, so a single deployment can act as the inference backend for any harness. Our team has been running a Dynamo deployment of GLM-5 and MiniMax2.5 internally to power our Codex and Claude Code harnesses. This lets us benchmark our backend implementations against closed-source inference, targeting parity on cache reuse performance. We will be sharing a full write-up and some optimized recipes for deploying both models in the upcoming weeks.
Video 1. Serving Claude with Dynamo
Video 2. Serving Codex with Dynamo
We have also invested in day-0 tool call and reasoning parsing support for various open-source models. If you find that a model is not supported, please open an issue or use the tool-call-parser-generator skill to generate it with your harness of choice.
Agent hints: The Harness Orchestrator interface
Today, inference servers see anonymous tokenized requests. But agent harnesses have global context that the infrastructure never sees: which agents are blocked on tool calls, which just spawned, how many turns remain in a session, and whether the current call is a quick lookup or a long synthesis. When using coding agents, the user waits for a final result, not individual token streams, so the orchestrator can reorder and prioritize requests across agents without affecting the end-user experience. Sessions run for minutes to even days with long tool-call pauses. This is enough to optimize inference scheduling in ways that traditional serving cannot.
Figure 2. Agentic system stack comparison showing that with Dynamo, an nvext inference infrastructure layer is added to standardize access to GPU-backed runtimes across agent workflows.
Dynamo’s new agent hints extension was designed to bridge this gap. It allows any harness to attach structured hints to a request across all three API endpoints, giving the router and runtime the context they need to make agent aware scheduling and caching decisions. This is a v1 API that we are actively co-designing with the community and would love feedback from teams building agent harnesses on what signals are most useful. Please reach out to us if you have any ideas or feedback.
{ "model": "MiniMaxAI/MiniMax-M2.5", "messages": [...], "tools": [...], "nvext": { "agent_hints": { "osl": 256, "speculative_prefill": true, "priority": 10 }, "cache_control": { "type": "ephemeral", "ttl": "1h" } }}
The agent_hints fields:
priority controls scheduling across both the router and engine. Higher values mean “more important” at the Dynamo API level; Dynamo translates that into router queue ordering and backend-specific engine priority.
osl (output sequence length) is the harness’s estimate of how many tokens this request will generate. The router uses this to gauge how long a worker will be occupied, which improves load balancing. A harness can learn this over time by tracking average output lengths per tool call type.
speculative_prefill signals the orchestrator to begin caching this request’s prefix on a likely worker before the full request is ready. This is useful when the harness knows a tool call is about to return and wants to warm the cache ahead of time.
The cache_control field will look familiar to anyone who has used Anthropic’s prompt caching API. It tells the orchestrator to pin the computed prefix on the worker for the specified TTL, protecting it from eviction during tool call gaps. Currently ephemeral is the only supported type (to match Anthropic’s API). We discuss how this works in the cache retention section below. You can find complete documentation on agent hints here.
Layer 2: The router
A coding agent follows a sequential pattern: long prefill, tool call, extend prefix, repeat. A multi-agent harness fans out work across parallel subagents with short, independent contexts. Default round-robin routing is blind to both patterns — it cannot account for cache locality, request priority, or session structure. Dynamo’s router closes this gap with three mechanisms: KV-aware placement, priority scheduling, and extensible routing strategies.
KV-Aware placement
Without cache-aware routing, turn 2 of a conversation has a ~1/N chance of landing on the same worker as turn 1. Every miss is a full prefix recomputation which is a significant performance bottleneck and extremely costly for an end user. Dynamo’s router maintains a global index of which KV cache blocks exist on which workers. The Flash Indexer post covers the six iterations that got this indexer to 170M ops/s (planetary scale KV routing). On every request, the router queries the index for per-worker overlap scores and selects the worker that minimizes the combined cost of cache miss and current decode load. This cost function is tunable, and we show below how teams can build custom agent aware routing strategies on top of it.
Priority scheduling
priority is the single user-facing scheduling knob. Higher values mean “more important” at the Dynamo API level. Dynamo uses that one hint at both layers:
At the router, higher-priority requests are shifted earlier in the queue when --router-queue-threshold is enabled.
At the engine, Dynamo normalizes backend-specific polarity and forwards the request for queue ordering, preemption, and KV cache eviction.
At the router, incoming requests enter a BinaryHeap<QueueEntry> ordered by effective arrival time. A higher priority makes the request appear as if it arrived earlier, placing it ahead of lower-priority work. Requests only enter the queue when all workers exceed a configurable load threshold. Below that threshold, they bypass the queue entirely and go straight to worker selection. When capacity frees up (prefill completes or a request finishes), the queue drains highest-priority entries first.
Once dispatched, SGLang, vLLM, and TRT-LLM may interpret engine priority differently, so Dynamo normalizes the engine-facing value per backend. Engines like SGLang can also use priority-based radix cache eviction where lower-priority blocks are evicted first under memory pressure.
Figure 3. This diagram illustrates request routing and prioritization in agentic inference, where latency-sensitive tasks are dispatched earlier and assigned higher priority and cache retention at the engine.
Agentic workload routing strategies
A research agent with a 200K context window needs workers with enough free KV capacity to hold its full state. The router’s default cost function (overlap score + decode load) handles the common case, but teams with domain-specific workloads can use the router’s Python bindings to implement custom routing strategies. The core KvRouter class provides best_worker() for querying routing decisions, get_potential_loads() for per-worker load inspection, and generate() for routing + dispatch in one call. Custom routers register on the same service mesh as the default components and can override routing config per-request:
Query per-worker load and overlap for custom routing logicloads = await router.get_potential_loads(token_ids)# Override routing config based on request properties# Long contexts benefit from heavier overlap weightingconfig = {"overlap_score_weight": 2.0} if len(token_ids) > 8192 else {}worker_id, dp_rank, overlap = await router.best_worker( token_ids, request_id="req-123", update_indexer=True, router_config_override=config)# Or bypass the default selector entirely when the harness# has its own worker selection logic (e.g., session affinity)stream = await router.generate( token_ids, model=model, worker_id=chosen_worker)
The NeMo Agent Toolkit (NAT) team used these APIs to build a custom online-learning agentic router. Their router extracts session metadata from nvext annotations and feeds it to a Thompson Sampling bandit style cost function that learns which workers perform best for which prefix patterns under load. Compared to Dynamo’s default routing, they measured 4x reduction in p50 TTFT and 1.5x increase in p50 tokens-per-second. Priority tagging of latency-sensitive requests achieved up to 63% p50 TTFT reduction under moderate memory pressure. See the NAT Dynamo integration example for implementation details. We will be making this available as a routing strategy in Dynamo soon.
Layer 3: KV cache management
Agentic workloads produce blocks with vastly different reuse value — system prompts reused every turn, reasoning tokens never reused again — but default LRU eviction treats all blocks identically. A 2-30 second tool call pause can age out an agent’s entire prefix, forcing full recomputation when it resumes. The cache needs to understand block value, support cross-worker sharing, and respect agent lifecycle boundaries.
The problem with uniform eviction
Block TypeReuse PatternValueSystem prompt + tool definitionsEvery turnHighestConversation historySubsequent turns, growing monotonicallyHighThinking/reasoning tokensTypically zero reuse after reasoning loop closes (a significant portion of output)Near-zeroSubagent KVMultiple turns then agent dies. No need to retainNear-zero
LRU sees only recency. In a high traffic environment, a wait for the completion of a called tool (2-30 seconds while the agent waits for an external API) might cause the agent’s blocks to age out and when the agent resumes, the entire prefix must be recomputed. To solve this, we need to provide the orchestrator APIs to control which blocks should be retained, where they should live, and for how long.
KV cache as a shared resource
Today, KV cache is treated as a local, ephemeral resource on each worker. An agent’s ~32K-token system prompt and tool definitions are computed independently on every worker that serves its requests. When a lead agent spawns 4 subagents, each with overlapping tool definitions, that shared prefix is recomputed 4 times if the subagents land on different workers. In our analysis of Claude Code team sessions, we measured this directly: teammates averaged 79.4% cache hit rate vs. 91.3% for the lead agent’s explore subagents (5.0x vs. 11.7x read/write ratio), with the gap driven almost entirely by cold-start writes on each teammate’s first call. The goal is to make high value KV cache blocks available to all workers in the cluster. Essentially, they are written once during cold start and then read by any worker at all times.
Solutions like SGLang’s HiCache and Dynamo’s KV Block Manager (KVBM) are building toward a 4-tier memory hierarchy:
Figure 4. Diagram showing the four-tier KV cache memory hierarchy, spanning GPU, CPU, local NVMe, and remote storage to enable scalable, shared cache reuse across workers.
Blocks follow a write-through path: when a worker computes KV for a prefix, the blocks flow from GPU to CPU to disk automatically. Each block is deduplicated by sequence hash in a global registry. Once a block is registered, it is immutable and addressable by any worker that can reach the storage tier.
This directly solves the subagent cold-start problem. When the lead agent computes tool definitions and system prompt, those blocks write through to shared storage. When subagent 1 spawns on a different worker, the router queries the Flash Indexer, finds the blocks in shared storage, and the worker loads them via NIXL (RDMA read) instead of recomputing from scratch. Subagent 2 does the same. Four redundant prefill computations become one compute and three loads. The same mechanism addresses cache coherence in disaggregated prefill-decode serving. In disagg mode, the prefill worker computes KV and transfers it to the decode worker via NIXL. The decode worker generates tokens, producing new KV state. On the next turn, a prefill worker needs both the original prefix and the generated tokens from turn 1, but those live only on the decode worker. With shared storage, the decode worker writes its new blocks to the common tier and any prefill worker can fetch them on the next turn.
Multi-tier storage solves sharing and persistence, but blocks still arrive on GPU only after the request hits the worker. The missing piece for agentic systems is prefetch: the harness can use historical timing data to predict when an agent’s tool call might return, which means it knows which blocks will be needed and when. We are building prefetch hooks so the harness can signal “bring these blocks from storage to GPU ahead of the next request.” Combined with the retention APIs (below), this gives the harness full lifecycle control: pin blocks to prevent eviction, set priority to control eviction ordering, and prefetch blocks proactively before they are needed.
Figure 5. Diagram illustrating KV cache prefetch in agentic inference, where blocks are offloaded after an initial call and proactively prefetched from storage to GPU ahead of subsequent requests.
Selective cache retention
Making blocks globally available solves the sharing problem, but does not solve eviction. SGLang and vLLM both support priority-based eviction via a priority heap where the harness assigns a numeric priority per request and lower-priority blocks are evicted first. TensorRT-LLM takes this further with TokenRangeRetentionConfig (designed and implemented by a Dynamo team member@jthomson04) which allows per-region control within a single request.
A request carries zero or more directives. Blocks without directives follow the default LRU path with zero overhead. The evictor becomes a two-structure system: an LRU free list for unprioritized blocks (O(1), unchanged) and a priority queue for annotated blocks. The harness can express “system prompt blocks are evicted last (priority: 100); conversation context survives a 30-second tool call (duration: 45s); decode tokens are first to go (priority: 1)” without the engine needing to understand why.
Anthropic’s prompt caching lets you mark prefixes as cacheable on their infrastructure. Dynamo’s cache_control API brings the same semantics to self-hosted inference. When a request includes cache_control: { type: "ephemeral", ttl: "1h" }, the router pins the matching prefix nodes in the worker’s radix tree for that TTL, protecting them from eviction in the worker’s L2 storage.
The next step is connecting retention with the distributed cache. Today, retention directives apply to a single worker’s local cache. When a block is pinned on worker A but the next request routes to worker B, the pin does not follow. Extending retention semantics across HiCache/KVBM’s shared storage tier means the harness can pin a block once and have it survive across workers: the priority and TTL metadata travel with the block through the write-through path, and any worker that loads the block from shared storage inherits the retention policy. Combined with the prefetch hooks described above, this gives the harness end-to-end lifecycle control across the full memory hierarchy.
Agent lifecycle awareness
Consider a typical Claude Code session. The lead agent runs for 20+ turns, accumulating a growing conversation prefix. Along the way it spawns explore subagents that each run 1-3 turns and terminate. It might spawn a team of 4 specialists that work in parallel on different subtasks and then terminate. Midway through, the agent hits a context limit and summarizes its history, compressing ~175K tokens down to ~40K. Each of these events produces ephemeral KV: blocks that will never be referenced again. Subagent termination, context summarization, and closed reasoning loops all generate ephemeral KV that occupies the same memory as high-value blocks like the system prompt. Reasoning models amplify this: <think>...</think> blocks account for ~40% of generated tokens but become ephemeral the moment the reasoning loop closes. Without lifecycle awareness, the cache treats all of these blocks identically.
Figure 6. Agent workflow showing KV cache usage across lifecycle stages, separating persistent context from ephemeral blocks created and discarded during subagent, tool, and reasoning steps.
The retention primitives from above (priority, TTL, token ranges) give us the building blocks. What is missing is the ability to associate them with sessions. If the harness can tag a subagent’s requests as belonging to a session and mark that session’s KV as ephemeral, the evictor can target those blocks first and skip writing them to shared storage entirely. When the subagent terminates, its session’s blocks are the first to reclaim. The same mechanism applies to thinking tokens: the engine can detect <think> boundaries during generation and tag those blocks as ephemeral at insertion time, so they skip L2 write-back and evict before normal blocks without any external signal. The design space here is wide: harness-driven session tagging, engine-native semantic detection, hybrid approaches that combine both. We are actively exploring multiple directions and expect the right answer will vary by workload and framework.
Closing the gap
The biggest optimization surface in agentic inference is the gap between what the harness knows and what the infrastructure can see. Which agents are blocked, which are about to resume, which KV is worth keeping, which can be thrown away — all of this context exists at the harness layer but never crosses the API boundary. nvext.agent_hints is our first cut at closing that gap: a small set of structured signals that let the orchestrator make informed routing, scheduling, and cache management decisions instead of treating every request as anonymous tokens. This is a v1 API and we are actively evolving it. If you are building agent harnesses, running open-source models for agentic workloads, or thinking about cache-aware inference, we want to hear what signals matter most for your use case. Reach out on GitHub or tag us on X: @0xishand, @KranenKyle, @flowpow123.
関連記事
今日は何も大きな出来事はありませんでした
Smol AI News は、6月3日から4日にかけての期間に、12件のサブレッドや544件のツイートを調査しましたが、AI業界で特筆すべき動きは確認されませんでした。
AI モデル推論パイプラインの摩擦を解消する方法
NVIDIA は、訓練済み AI モデルを実環境へ展開する際のボトルネック解消法を提示し、モデルのエクスポートや最適化プロセスにおける課題解決策を解説している。
バイブコーディングとエージェントエンジニアリングの融合への懸念
著者は、AI コーディングツールのポッドキャスト出演を通じて、自身の業務において「バイブコーディング」と「エージェントエンジニアリング」が思わぬほど接近し始めているという驚きと懸念を表明した。