Claude Managed Agents(beta)— サーバー管理型エージェントの実践入門

Anthropic から Managed Agents が beta 公開されました。Claude がエージェントループを自走し、Anthropic 側でコンテナを管理する新しい API 面です。Agent / Session / Environment / Container の 3 レイヤー構造、setup と runtime の分離、イベントストリームの扱いまで、自作ループから移行するときに押さえるべき点を実装込みで整理します。

Anthropic から Managed Agents(beta、managed-agents-2026-04-01)が公開されました。従来の「Claude API + tool use で agent ループを自作」路線に加えて、Claude 側のオーケストレーション層がエージェントループを走らせ、Anthropic 側がセッション毎にコンテナを立てて tool 実行まで面倒を見るという新しい API 面です。本記事では、仕組み・API 構造・自作ループからの移行ポイントを、実装込みで整理します。

到達点

  • Agent(永続・バージョン管理)と Session(毎回)の 2 段構造を理解する
  • Agent は 1 度だけ作って ID を保存、Session はリクエスト毎というパターンを守る
  • SSE イベントストリームから idle / terminated を安全に読む
  • どんなときに Claude API + tool use ではなく Managed Agents を選ぶか

検証環境: 2026-04 時点、SDK は @anthropic-ai/sdk v0.90、beta header managed-agents-2026-04-01(SDK が自動付与)。

3 レイヤーの頭の中

Managed Agents は 4 種類のオブジェクトの重ね合わせです。

  • Agent — 永続・バージョン管理されたエージェント定義。モデル / system prompt / tools / MCP サーバー / skills を保持。POST /v1/agents で作り、ID を永続保存する
  • Session — その Agent を使った1 回の実行。初期メッセージ + resources + vault と共に起動すると、Anthropic 側で container が立ってエージェントループが走る
  • Environment — コンテナの設定テンプレ(ネットワーキング・パッケージ等)。Agent とは別管理で使いまわし
  • Container — Session ごとにプロビジョニングされる sandbox。tool(bash / file / code 実行)はここで動く
                   ┌─ Anthropic orchestration layer ─┐
  Agent (config) ──▶│ エージェントループ (Claude + tools) │
                   └──────────┬───────────────────────┘
                              │ tool calls

  Environment (template) ──▶ Container (tool 実行場所 = /workspace)

                         Session ─┤
                                 ├── Resources (files / github_repository)
                                 ├── Vault IDs (MCP 認証)
                                 └── Event stream (SSE)

エージェントの配線は Anthropic 側に委ね、自分のコードはクライアントとして events を読み書きするだけ」に近い姿になります。

Setup と Runtime の分離(最重要)

Managed Agents で最大のハマりポイントが、agents.create() をリクエストごとに呼んでしまうアンチパターンです。

  • Setup(1 回)environments.create()agents.create() を実行して返ってきた ID を設定ファイル/env に保存する
  • Runtime(毎回) — 保存された Agent ID / Environment ID を読み、sessions.create({ agent, environment_id }) で 1 セッション起動する

新規 Agent をリクエスト経路で毎回作ると、孤児 Agent が累積し、create 分のレイテンシを毎回支払うことになります。**「Agent は 1 度、ID を保存、Session は毎回」**が絶対のルール。

Setup(TypeScript、1 度だけ)

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function setup() {
  // 1) Environment: コンテナ設定テンプレ(ネットワーキング等)
  const env = await client.beta.environments.create({
    name: "r43lab-coder-env",
    config: { type: "cloud", networking: { type: "unrestricted" } },
  });

  // 2) Agent: モデル / system / tools / skills はこっちに乗せる
  const agent = await client.beta.agents.create({
    name: "r43lab-coder",
    model: "claude-opus-4-7",
    system: "You are a senior TypeScript reviewer working in the mounted repo.",
    tools: [
      // 組込 agent toolset(bash / read / write / edit / glob / grep / web_fetch / web_search)
      { type: "agent_toolset_20260401", default_config: { enabled: true } },
    ],
    // 必要に応じて skills や mcp_servers を追加
    // skills: [{ type: "anthropic", skill_id: "xlsx" }],
  });

  console.log("ENV_ID=", env.id);
  console.log("AGENT_ID=", agent.id);
  console.log("AGENT_VERSION=", agent.version);
  // → この 3 つを .env か secrets に保存して runtime で読む
}

setup().catch(console.error);

Runtime(毎回)

Setup で保存した ID だけ読み、sessions.create() を呼びます。

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const AGENT_ID = process.env.AGENT_ID!;
const ENV_ID = process.env.ENV_ID!;

async function run(userText: string) {
  // Session を 1 つ起動(agent と environment を参照するだけ)
  const session = await client.beta.sessions.create({
    agent: AGENT_ID, // 文字列なら常に最新 version
    environment_id: ENV_ID,
    title: `run ${new Date().toISOString()}`,
  });

  // ストリームを先に開いてから user.message を送る
  const stream = await client.beta.sessions.events.stream(session.id);
  await client.beta.sessions.events.send(session.id, {
    events: [{ type: "user.message", content: [{ type: "text", text: userText }] }],
  });

  // 5: status_idle は "一時停止" と "終わり" の両方で出るので stop_reason を見る
  for await (const event of stream) {
    if (event.type === "agent.message") {
      for (const b of event.content) {
        if (b.type === "text") process.stdout.write(b.text);
      }
    }
    if (event.type === "session.status_terminated") break;
    if (event.type === "session.status_idle") {
      // requires_action は tool 確認待ち等。break しない。
      if (event.stop_reason.type === "requires_action") continue;
      break;
    }
  }
}

重要: 「session.status_idle だけで break する」と、tool 確認待ちの中断まで終了扱いになる事故が起きます。stop_reason.type !== "requires_action" のときだけ break するのが正しい gate です。

tool confirmation のラウンドトリップ

Agent に permission_policy: { type: "always_ask" } を指定したツールは、agent.tool_use が来ると session が idle になって user.tool_confirmation を待ちます。

for await (const event of stream) {
  if (event.type === "agent.tool_use" && event.evaluated_permission === "ask") {
    // UI で承認を取った想定
    await client.beta.sessions.events.send(session.id, {
      events: [{
        type: "user.tool_confirmation",
        tool_use_id: event.id,      // ← event.id(toolu_ ではない)
        result: "allow",            // "allow" | "deny"
        // deny_message: "Please read .env.example instead", // deny 時の理由を伝える
      }],
    });
  }
}

tool_use_idevent.id(sevt_...)を渡すのがキモ。Claude API 素の toolu_... と混同しやすい点です。

Claude API + tool use と Managed Agents の使い分け

こういう時選ぶ surface
分類 / 要約 / 抽出 / 単発 Q&AClaude API(単発リクエスト)
自作 tools を叩くワークフロー、ループの細部を自分で制御したいClaude API + tool use
bash / file / code 実行を Anthropic 側のサンドボックスで走らせたいManaged Agents
セッションごとにファイルマウント / GitHub リポマウントが要るManaged Agents
永続・バージョン管理されたエージェント設定が要るManaged Agents
長時間走る multi-turn 作業を SSE で UI に流したいManaged Agents

ポイントは「Anthropic 側にコンテナを持たせたい / 長期セッションが要る」かどうか。自社側で tool 実行環境を持っていて制御したいなら従来の Claude API + tool use が合理的です。

知っておくべき制約

  • 1P 限定: Bedrock / Vertex AI / Microsoft Foundry では Managed Agents は未提供。マルチクラウド前提のシステムでは Claude API + tool use を使う
  • Archive は永続: Agent / Environment / Session / Vault / Credential いずれも archive は read-only 化の終点で、unarchive は無い。本番の agent を routine cleanup で archive しないこと
  • SSE に replay なし: ストリームが切れた瞬間に配信されたイベントは失われる。再接続時は events.list() で履歴を取ってevent.id で dedupeしてから再開する
  • file mount の file_id はコピー: sessions.create() 時に元ファイルの session-scoped コピーが作られ、session.resources[0].file_id !== uploaded.id。セッション終了後は GC されるので、元ファイルは自分で消す

落とし穴

  • agents.create() をリクエスト毎に呼ぶ — 最頻の間違い。setup スクリプトに隔離して ID を保存する運用へ
  • Session に model / system / tools を書く — これらはすべて Agent 側に乗る。session に入れても受け付けられない
  • session.status_idle だけで break するrequires_action を終了扱いにしてしまう。stop_reason.type で分岐する
  • stream-after-sendevents.send() を先に呼んで events.stream() を後で開くと、最初のイベントを取り逃す。stream 先 → send 後
  • archive を routine にする — Agent / Environment は永続リソース、archive は終点。本番に対しては人間承認つきでのみ
  • MCP 認証をインラインに書く — Agent の mcp_servers{type, name, url} のみ。credential は vault に入れ、session に vault_ids で紐付ける

まとめ

Managed Agents は「エージェントループの配線と tool 実行サンドボックスを Anthropic に委ねる代わり、クライアントはイベントストリームの応対に集中できる」サーフェスです。既存の Claude API + tool use が消えるわけではないので、セッション永続とコンテナ実行が要る用途で Managed Agents を選ぶという切り分けで十分です。

次回以降、release notes タグで続報(Skills / Memory / Context Editing 等)を追いかけていきます。

参考

記事で登場したコードをひとつの最小リポジトリとしてまとめました。ファイルツリーから切り替えて、全体の構造をそのまま確認できます。

$cat./package.jsonjson
{
  "name": "managed-agents-starter",
  "private": true,
  "type": "module",
  "scripts": {
    "setup": "bun src/setup.ts",
    "run": "bun src/run.ts",
    "tool": "bun src/tool-confirmation.ts"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.90.0"
  },
  "devDependencies": {
    "@types/bun": "^1.3.0",
    "typescript": "^6.0.3"
  }
}
slugclaude-managed-agents-introfiles8click a file in the tree to switch