CC学校

Deep dive · Agent SDK

Claude を、
あなたの製品の中へ。

Agent SDK で query() を呼ぶ最小例から、カスタムツール、ホスティングパターン、セキュアデプロイまで。本物のプロダクションで使うために必要な要点をひと続きで。

01 / Overview

Claude Code は、SDK でも完全に同じ

Agent SDK は Claude Code と同じエンジン。違うのは「対話 UI」ではなく「あなたのコードから呼ぶ」点だけです。

TypeScript と Python の両方が公式提供。CLAUDE.md・Skills・MCP・Hooks・Subagents・Permissions すべてが SDK からも使えます。CLI で動いたものは、たいてい SDK でも動く。

02 / Quickstart

3 行で動かす

`query()` を回すだけ。ストリーミングで返ってくるイベントを処理するだけです。

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

for await (const msg of query({
  prompt: "src/ の TODO コメントを一覧して",
  options: {
    cwd: process.cwd(),
    permissionMode: "plan",
  },
})) {
  if (msg.type === "result") console.log(msg.result);
}

03 / Two modes

`query()` と `ClaudeSDKClient` の使い分け

単発タスクは query()、長期セッションは ClaudeSDKClient(Python)/ continue: true(TS)。

query() は単発の対話を一発で回す関数。CI / バッチ向き。 ClaudeSDKClient(Python)continue: true オプション(TS)は、内部でセッション ID を管理して文脈を継続できます。長期チャットボット向き。

04 / Streaming

入出力ともストリーミング

トークン単位の streaming output と、対話的に prompt を送り直せる streaming input。

Streaming output で UI に文字を流し込み、tool 呼出のイベントもリアルタイムで観察できます。 Streaming input は、ユーザー入力や外部信号で「途中で方針を変える」ような用途に。

streaming.ts
for await (const msg of query({ prompt: "...", options: { stream: true } })) {
  switch (msg.type) {
    case "assistant":      // 部分テキスト・思考
      process.stdout.write(msg.delta ?? "");
      break;
    case "tool_use":       // ツール呼出が始まった
      console.log("\n[tool]", msg.name, msg.input);
      break;
    case "tool_result":    // ツール結果が返った
      break;
    case "result":         // 終了
      console.log("\n[done]", msg.result);
      break;
  }
}

05 / Structured outputs

型安全な出力を強制する

Zod / Pydantic スキーマで「このフォーマットで返せ」と縛る。

structured.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const schema = z.object({
  todos: z.array(z.object({
    file: z.string(),
    line: z.number(),
    text: z.string(),
  })),
});

for await (const msg of query({
  prompt: "src/ の TODO を抽出して",
  options: { outputSchema: schema },
})) {
  if (msg.type === "result") {
    const parsed = schema.parse(msg.result);
    console.log(parsed.todos.length, "件");
  }
}

06 / Custom tools / MCP

ツールを自分で定義する

`tool()` で型安全に宣言、`createSdkMcpServer()` で束ねて公開。

tools.ts
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const getWeather = tool({
  name: "get_weather",
  description: "都市名から天気を返す",
  inputSchema: z.object({ city: z.string() }),
  handler: async ({ city }) => {
    const res = await fetch(`https://wttr.in/${city}?format=j1`);
    return await res.json();
  },
});

const convertUnit = tool({
  name: "convert_unit",
  description: "1 単位変換ツール",
  inputSchema: z.object({
    value: z.number(),
    from: z.string(),
    to: z.string(),
  }),
  handler: async (i) => convert(i.value, i.from, i.to),
});

export const server = createSdkMcpServer({
  tools: [getWeather, convertUnit],
});

07 / Control

Permissions / Hooks / Subagents を SDK で扱う

セッションのガードレールと拡張は、CLI と同じ仕組みでプログラマティックに設定できます。

control.ts
for await (const msg of query({
  prompt: "...",
  options: {
    permissionMode: "acceptEdits",
    canUseTool: async (tool, input) => {
      if (tool === "Bash" && input.command?.startsWith("rm")) {
        return { allow: false, reason: "rm は禁止" };
      }
      return { allow: true };
    },
    hooks: {
      PostToolUse: [
        { matcher: "Edit|Write",
          handler: async () => ({ command: "biome format --write ${FILE}" }) },
      ],
    },
    agents: [
      { name: "Reviewer",
        description: "Reads diffs and proposes review comments",
        tools: ["Read", "Glob", "Grep"] },
    ],
  },
})) { /* ... */ }

08 / Observability

コストとテレメトリ

毎クエリの token / コストを取り、OTel に流して横断ダッシュボードへ。

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

let total = { input: 0, output: 0, cacheCreate: 0, cacheRead: 0, usd: 0 };

for await (const msg of query({ prompt: "..." })) {
  if (msg.type === "result") {
    total.input += msg.usage.input_tokens;
    total.output += msg.usage.output_tokens;
    total.cacheCreate += msg.usage.cache_creation_input_tokens ?? 0;
    total.cacheRead += msg.usage.cache_read_input_tokens ?? 0;
    total.usd += msg.total_cost_usd;
  }
}

console.log("session cost:", total);

OpenTelemetry エクスポータを有効化すると、これらのメトリクスは自動で OTel Collector に流れます。 Datadog / Grafana / Honeycomb に取り込めば、SDK 利用のコストとパフォーマンスを横断観測できます。

09 / Hosting

本番デプロイの 4 パターン

ユースケースに応じて、コンテナの寿命とメモリ常駐戦略を選びます。

  • pattern 1

    Ephemeral Sessions

    1 リクエスト = 1 コンテナ。終わったら破棄。シンプル・課金が分かりやすい。

    CI / バッチ / 単発のコード生成 API

  • pattern 2

    Long-Running Sessions

    ユーザー単位でコンテナを生かし続け、状態を持たせる。

    チャットボット、IDE プラグイン、長期エージェント

  • pattern 3

    Hybrid Sessions

    アクティブな間だけ常駐、アイドルで眠らせる。コスト効率が高い。

    Slack ボット、社内ヘルプデスク

  • pattern 4

    Single Container

    1 コンテナで複数セッションを多重化。最も低コスト・最も注意が必要。

    PoC / 小規模社内ツール

10 / Secure deployment

脅威モデルと多層防御

ユーザー入力・コードベース・ツール結果はすべて untrusted。サンドボックス、proxy、最小権限の3 つを基本に。

Sandboxing:コンテナ/gVisor/VM/クラウドサンドボックスで OS レベル隔離。The Proxy Pattern:Anthropic API への通信はプロキシ経由。あなたの API キーは Claude プロセスに渡さず、プロキシだけが知っている状態にする。Least privilege:実行する Bash の許可範囲、書込可能パス、egress 先を最初から狭く。