Agent SDK のホスティング:本番運用の構成と注意点

Claude Agent SDK エンジニアリング 8分で読めます

Claude Agent SDK は、呼び出すたびに claude CLI のサブプロセスを起動し、そのプロセスがシェル・作業ディレクトリ・ディスク上のセッションファイルを持ちます。そのため、状態を持たない API ラッパーと同じ感覚ではホスティングできません。この記事では公式ドキュメント「Hosting the Agent SDK」に沿って、自前のインフラで SDK を動かすときのセッション構成、コンテナに必要なもの、永続化・監視・認証・スケーリング、マルチテナント分離を整理します。SDK の全体像は「Claude Agent SDK でエージェントを作る」を参照してください。

なお、エージェントループ自体を自分のインフラで動かす必要がなければ、Anthropic がループをホストする Managed Agents という選択肢もあります。こちらはアプリがイベントを送り、結果をストリームで受け取る形で、ツール実行は Anthropic 管理のクラウドサンドボックスか、自前のセルフホスト型サンドボックスで行われます。

サブプロセスモデルとローカルに残る状態

コードから query() を呼ぶと、SDK は別プロセスとして claude CLI を起動し、標準入出力(stdio)でやり取りします。シェル、作業ディレクトリ、JSONL 形式のセッション記録(トランスクリプト)はこのサブプロセスが持ちます。サブプロセス自身はネットワークで待ち受けず、外向きに api.anthropic.com へ HTTPS で通信するだけです。

1セッションは1サブプロセスに対応します。N 件のセッションを同時に動かせば N 個のサブプロセスができ、それぞれが自分のプロセスツリーとトランスクリプトを持ちます。既定ではすべてアプリと同じ作業ディレクトリを引き継ぐので、セッションごとにファイルを分けたいときは query() のオプションで cwd を個別に渡します。

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Summarize the files in this directory",
  options: { cwd: "/work/session-a" },
})) {
  console.log(message);
}

Python では ClaudeAgentOptions(cwd="/work/session-a") を渡します。TypeScript の例はトップレベル await を使うので、.mts で保存するか package.json に "type": "module" を設定します。

既定では次の3種類の状態がコンテナのファイルシステムに置かれ、コンテナの再起動・スケールダウン・別ノードへの移動ではどれも残りません。

状態既定の場所
セッションのトランスクリプト~/.claude/projects/(CLAUDE_CONFIG_DIR を設定していればその下の projects/)
CLAUDE.md メモリファイルユーザー階層は ~/.claude/CLAUDE.md、プロジェクト階層はセッションの作業ディレクトリ
作業ディレクトリの成果物セッションの作業ディレクトリ

トランスクリプトをホストをまたいで残すには SessionStore アダプタを設定します。メモリファイルや作業ディレクトリの成果物は対象外なので、ボリュームのマウントやオブジェクトストレージとの同期など、別の保存方法を用意します。再開・フォークの API 上の扱いは「Agent SDK のセッション管理」を参照してください。

4つのセッション構成から選ぶ

公式は、コンテナの寿命とセッションの関係を次の4パターンに分けています。コンテナをどこで動かすか(ローカル Docker・Modal・Kubernetes)は、公式の hosting cookbook(claude-cookbooks リポジトリの claude_agent_sdk/hosting)にデプロイ可能なコードがあり、パターンとデプロイ先を組み合わせて選びます。

パターン動かし方向いている用途の例
エフェメラルタスクごとにコンテナを作り、終わったら破棄するバグの調査と修正、請求書・領収書の抽出、文書の翻訳、メディア変換
長時間稼働常駐コンテナで、多くは1コンテナに複数の SDK プロセスを載せるメールの仕分けと返信、ユーザーごとの編集可能なサイト、Slack などの継続トラフィックを受けるチャットボット
ハイブリッドエフェメラルなコンテナが起動時に SessionStore から復元し、更新を書き戻すときどき確認する個人用プロジェクト管理、数時間かけて中断・再開する調査、履歴を引き継ぐサポート
マルチエージェント1コンテナ内で複数の SDK サブプロセスを動かす共有環境でエージェント同士がやり取りするシミュレーション

エフェメラルでは、環境変数 TASK_PROMPT からタスクを読み、SDK を呼んで終了する一回きりのエントリポイントを置きます。

import asyncio
import os

from claude_agent_sdk import ClaudeAgentOptions, query


async def main():
    async for message in query(
        prompt=os.environ["TASK_PROMPT"],
        options=ClaudeAgentOptions(max_turns=20),
    ):
        print(message)


asyncio.run(main())

上限内で終われば結果メッセージの subtype は success です。20ターンの上限に達すると error_max_turns になり、そのメッセージを返したあと query() が例外を投げるので、コンテナをきれいに終わらせたい場合はループを try で囲みます(結果の種類は「Agent SDK のエージェントループ」参照)。

長時間稼働では、コンテナが HTTP か WebSocket のエンドポイントを公開し、アクティブなセッションごとに長寿命の query とその裏のサブプロセスを対応させます。TypeScript は streamInput() で進行中のセッションにターンを足し、startup() で事前にサブプロセスを温めておけます(最初のリクエストまで作業ディレクトリが決まらない場合は prewarm())。Python は ClaudeSDKClient でセッションを開いたままにします。コンテナは同時セッションの最大数をメモリに載せられる大きさにします。

ハイブリッドは、アイドル中はコンテナを落とし、利用者が戻ってきたら立ち上げ直す構成です。SessionStore 無しでコンテナを落とすとトランスクリプトも消えるので、このパターンではストアが必須です。データベースなどから引いたセッション ID を resume に、共有ストアを sessionStore(Python は session_store)に渡して再開します。プロバイダのアイドルタイムアウトは、利用者が戻ってくる頻度に合わせて調整します。

マルチエージェントでは、エージェントごとに作業ディレクトリを分けてファイルの上書きを防ぎ、エージェントごとの CLAUDE.md が混ざらないよう設定の読み込みも分離します(方法は最後の節を参照)。

コンテナの準備:ランタイム・リソース・ネットワーク

プロセス分離、リソース制限、ネットワーク制御、使い捨てのファイルシステムを得るため、SDK はサンドボックス化したコンテナで動かします。提供元を選ぶときに確認する点として、公式は次を挙げています。

Docker・gVisor・Firecracker などのセルフホスト型の分離技術と細かな設定は、公式の Secure deployment にまとまっています。サンドボックスの考え方は「Claude Code のサンドボックス環境を選ぶ」も参考になります。

ランタイムは、Python SDK なら Python 3.10 以上、TypeScript SDK なら Node.js 18.14 以上です。どちらの SDK も多くのインストール形態でネイティブの Claude Code バイナリを同梱しており、起動される CLI のために Node.js を別途入れる必要はありません。同梱バイナリは SDK パッケージのバージョンに固定されているので、CLI の更新は SDK の更新で行います。SDK はセマンティックバージョニングに従うため、パッチリリースは継続的に取り込み、マイナーリリースは CHANGELOG を確認してから上げるよう公式は勧めています。

リソースは、起動直後のインスタンスで「エージェント1つあたり RAM 1GiB・ディスク 5GiB・CPU 1」が出発点の目安です。メモリはセッションの長さとツールの使用量に応じて増えるので、アイドル時ではなく実際に必要なセッション長と同時実行数で見積もります。

ネットワークは、api.anthropic.com(Amazon Bedrock や Google Cloud で動かす場合は各リージョンのエンドポイント)への外向き HTTPS が必要です。MCP サーバーや外部ツールを使うならその接続先も開けます。本番では、ドメインの許可リスト・認証情報の注入・リクエストのログ記録を行う外向きプロキシ経由にするのが推奨です。内向きは、コンテナで HTTP か WebSocket のポートを公開し、アプリがそのリクエストを受けて内部で SDK を呼びます。

本番運用で決めておくこと

セッションと状態の永続化: 利用者が再開を期待するセッションは、SessionStore アダプタでトランスクリプトを永続ストレージへミラーします。SDK のリポジトリにはオブジェクトストア(S3)・キーバリューストア(Redis)・データベース(Postgres)向けの参照実装と、自作アダプタ用の適合テストがあります。挙動として押さえておく点は次の3つです。

監視(オブザーバビリティ): SDK は環境変数から OpenTelemetry の設定を引き継ぎます。コンテナやオーケストレータの階層で OTEL の変数を設定しておけば、すべての query() がスパン・メトリクス・ログイベントをコレクタへ送ります。CLAUDE_CODE_ENHANCED_TELEMETRY_BETA はトレースにだけ必要です。プロンプト本文やツール入力は既定では送られません。詳しくは「OpenTelemetry で Claude Code を監視する」も参照してください。

CLAUDE_CODE_ENABLE_TELEMETRY=1
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318

認証とシークレット: 気にすべき点は3つです。

スケーリングと同時実行: セッションごとにサブプロセスが1つできるので、1ホストの同時実行数はメモリで決まります。公式の目安式は次のとおりです。

agents per host = (host RAM - overhead) / (per-session RAM ceiling)

1セッションあたりの上限は、代表的なセッションを想定の長さとツール負荷で実際に流し、ピーク時の RSS を測って決めます。前述の 1GiB は下限であって上限ではありません。長時間稼働パターンで水平に増やすときは、ロードバランサの背後にコンテナを並べ、sessionId のコンシステントハッシュで各セッションを同じコンテナに固定します。

コスト: 一般にトークン費用がコンテナ費用を1桁以上上回ります。最小構成のコンテナは1時間あたり約0.05ドルですが、長いセッション1つでトークンに数ドルかかることがあります。セッション単位の集計は「Agent SDK のコスト追跡」を参照してください。

マルチテナント分離と既知の制約

SDK は既定でファイルシステムから設定と CLAUDE.md を読みます。複数のテナント(利用者・顧客)を1つのコンテナで扱うと、あるテナントの文脈が別のテナントのセッションに漏れるおそれがあります。公式が挙げる分離策は次のとおりです。

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt,
  options: {
    cwd: tenantDir,
    settingSources: [],
    env: {
      ...process.env,
      CLAUDE_CONFIG_DIR: configDir,
      CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
    },
  },
})) {
  // ...
}

TypeScript の env はサブプロセスの環境変数を置き換えるので、PATH や ANTHROPIC_API_KEY を残すために ...process.env を展開します。Python の env は引き継いだ環境変数に上書きで足される形です。tenantDir と configDir は、ほかのテナントから読めないパスにします。権限まわりの設定は「Agent SDK の権限設定」もあわせて確認してください。

設計時に織り込んでおくべき既知の制約は次のとおりです。

制約対処
セッション全体のタイムアウトが無いmaxTurns(Python は max_turns)でターン数の上限を決める
長いセッションでメモリが増えるセッションの長さに上限を設けるか、サブプロセスを定期的に作り直す
大量のサブエージェントを並列で出すとレート制限に当たることがある一度に広く出さず、小さなバッチに分ける
サブエージェントごとの実時間の締め切りが無いAgentDefinition の maxTurns で各サブエージェントを制限する。CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS は出力が止まったときの見張りで、総実行時間の締め切りではない

手元では動くのにデプロイ先で失敗するときは、公式のトラブルシューティングが3つの典型を挙げています。サービス起動時に CLI が見つからない(Python ではサービスの PATH がシェルと違う、TypeScript ではイメージのビルドで SDK の optional dependencies が省かれた、または pathToClaudeCodeExecutable の指す先が無い)、CLI はあるが起動しない(コンテナのアーキテクチャや libc と合わないバイナリ、実行権限が落ちたファイル)、実行途中で Claude Code のプロセスが終了する、の3つです。

本ページは Hosting the Agent SDK を中心に、Persist sessions to external storage と claude-cookbooks の hosting サンプル の記述を踏まえた非公式の日本語解説です(確認日 2026-10-29)。コード例は一部を簡略化しています。最新の仕様は公式ドキュメントを確認してください。