メインコンテンツへスキップ
ブログ一覧

Claude Agent SDK実践ガイド — 移行手順・Subagents・Hooks・Skillsで構築する本番AIエージェント

(更新: 2026年04月26日)
Claude Agent SDKAIエージェント開発Anthropic SDKMCP統合Claude Code移行

2025年9月、Claude Code SDKは「Claude Agent SDK」にリネームされた。単なる名前変更ではない。SubagentsとHooksというプログラマティック制御機構が加わり、AIエージェントの設計パラダイムが変わった。本記事では、移行の実務手順から、SDK固有のSubagents・Hooksを使った本番エージェント構築パターンまでを、動くコードとともに解説する。

Claude Code SDK → Agent SDKで何が変わったのか

リネームの背景と設計思想の転換

もともとClaude Code SDKは「Claude Codeをライブラリとして使う」ための薄いラッパーだった。しかし、エージェントアプリケーション構築のプラットフォームとしての位置づけが明確になるにつれ、「Code」という名前が実態と合わなくなった。Agent SDKは、ツールループ・ファイル操作・Bash実行を内蔵したフルエージェントランタイムであり、素のAPI呼び出しを提供するAnthropic Client SDK(@anthropic-ai/sdk)とは明確に異なるレイヤーだ。

破壊的変更の全体像

主な変更点を整理する。

  • パッケージ名: @anthropic-ai/claude-code@anthropic-ai/claude-agent-sdk(Python: claude-agent-sdk
  • 型名: Python側で ClaudeAgentOptions に統一、AgentDefinition 型の追加
  • 新機能: options.agents によるSubagents定義、options.hooks によるライフサイクル制御、tool() + createSdkMcpServer() によるインプロセスMCPツール
  • PermissionMode: defaultacceptEditsbypassPermissionsplan 等の選択肢

query() の基本シグネチャ — AsyncGeneratorで SDKMessage をストリーム返却する構造 — は変わっていないため、移行のハードルは低い。

5分で完了する移行手順

パッケージ入れ替えとimport修正

bash
# TypeScript
npm uninstall @anthropic-ai/claude-code
npm install @anthropic-ai/claude-agent-sdk

# Python
pip uninstall claude-code-sdk
pip install claude-agent-sdk

import文の一括置換はシンプルだ。

bash
# プロジェクト全体で一括置換
find src -name '*.ts' -exec sed -i '' \
  's/@anthropic-ai\/claude-code/@anthropic-ai\/claude-agent-sdk/g' {} +

型名・デフォルト値の変更対応

TypeScript側の query() 呼び出しは、import先のパッケージ名さえ変えればほぼそのまま動く。

typescript
// Before
import { query } from '@anthropic-ai/claude-code';

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

const q = query({
  prompt: 'プロジェクトのREADMEを生成して',
  options: {
    model: 'sonnet',
    maxTurns: 30,
    cwd: process.cwd(),
    permissionMode: 'bypassPermissions',
    allowedTools: ['Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep'],
  },
});

for await (const msg of q) {
  if (msg.type === 'result' && msg.subtype === 'success') {
    console.log(msg.result);
    console.log(`Cost: $${msg.total_cost_usd}`);
  }
}

正直、import書き換えだけで動いたときは拍子抜けした。

Subagents — プログラマティックなエージェント分離

CLIのYAMLサブエージェント(.claude/agents/)との違い

ここが最も混同されやすいポイントだ。CLI版のサブエージェントは .claude/agents/*.yml にYAML frontmatterで定義し、Claude Code UIから選択して使う。一方、SDK版Subagentsは options.agentsAgentDefinition の辞書として渡す、完全にプログラマティックな仕組みだ。

AgentDefinitionの設計と実装

以下はリサーチャー・実装者・レビュアーの3エージェントを定義し、連携させる例だ(Python SDK)。

python
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AgentDefinition

agents = {
    "researcher": AgentDefinition(
        description="Web検索でトレンドと技術情報を調査する",
        tools=["WebSearch", "WebFetch", "Write"],
        prompt="あなたはリサーチャーです。指定されたトピックについてWeb検索で情報を収集し、findings.mdに調査結果をまとめてください。",
        model="haiku"
    ),
    "implementer": AgentDefinition(
        description="調査結果に基づいてコードを実装する",
        tools=["Read", "Write", "Edit", "Bash", "Glob"],
        prompt="あなたは実装担当です。findings.mdを読み、仕様に沿ってコードを実装してください。",
        model="sonnet"
    ),
    "reviewer": AgentDefinition(
        description="実装コードのレビューと改善提案を行う",
        tools=["Read", "Glob", "Grep", "Bash"],
        prompt="あなたはコードレビュアーです。実装されたコードの品質・セキュリティ・パフォーマンスを評価してください。",
        model="sonnet"
    ),
}

options = ClaudeAgentOptions(
    permission_mode="bypassPermissions",
    system_prompt="あなたはリードエージェントです。researcher→implementer→reviewerの順にタスクを委譲してください。",
    allowed_tools=["Agent"],  # Agentツールでサブエージェントを呼び出す
    agents=agents,
    model="sonnet"
)

各サブエージェントは独自のコンテキストで動作し、使えるツールもモデルも個別に指定できる。コスト最適化のために調査フェーズはHaiku、実装フェーズはSonnetといった使い分けが可能だ。

Hooks — SDKレベルのライフサイクル制御

CLI版Hooks(settings.json)との違い

CLI版Hooksは settings.jsoncommandhttp 型で外部プロセスを呼び出す仕組みだ。SDK版Hooksは options.hooks にネイティブ関数のコールバックとして定義する。外部プロセスの起動オーバーヘッドがなく、TypeScript/Pythonの型安全な世界で完結する。

実装パターン: ツール実行のフィルタリングと監査ログ

typescript
import { query } from '@anthropic-ai/claude-agent-sdk';
import type { HookJSONOutput } from '@anthropic-ai/claude-agent-sdk';

const q = query({
  prompt: 'プロジェクトをリファクタリングして',
  options: {
    model: 'sonnet',
    maxTurns: 50,
    permissionMode: 'bypassPermissions',
    allowedTools: ['Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep'],
    hooks: {
      PreToolUse: [
        {
          matcher: 'Bash',
          hooks: [
            async (input: any): Promise<HookJSONOutput> => {
              const command: string = input.tool_input?.command || '';

              // 危険なコマンドをブロック
              if (command.includes('rm -rf') || command.includes('DROP TABLE')) {
                return {
                  decision: 'block',
                  stopReason: `危険なコマンドを検出: ${command}`,
                  continue: false,
                };
              }
              return { continue: true };
            },
          ],
        },
      ],
      PostToolUse: [
        {
          matcher: null, // 全ツールにマッチ
          hooks: [
            async (input: any): Promise<HookJSONOutput> => {
              // 全ツール実行を監査ログに記録
              console.log(JSON.stringify({
                timestamp: new Date().toISOString(),
                tool: input.tool_name,
                duration_ms: input.duration_ms,
              }));
              return { continue: true };
            },
          ],
        },
      ],
    },
  },
});

matcher にはパイプ区切りのパターン("Write|Edit|MultiEdit")を指定でき、null で全ツールにマッチする。

Skills systemとMCPサーバー統合

tool()createSdkMcpServer() を使えば、独自のツールをインプロセスMCPサーバーとしてエージェントに統合できる。

typescript
import { query, tool, createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
import { z } from 'zod';

const dbServer = createSdkMcpServer({
  name: 'database',
  version: '1.0.0',
  tools: [
    tool(
      'search_products',
      '商品データベースを検索する',
      {
        keyword: z.string().describe('検索キーワード'),
        limit: z.number().optional().describe('取得件数(デフォルト10)'),
      },
      async (args) => {
        const results = await db.query(
          'SELECT * FROM products WHERE name LIKE ?',
          [`%${args.keyword}%`]
        );
        return {
          content: [{ type: 'text', text: JSON.stringify(results) }],
        };
      }
    ),
  ],
});

const q = query({
  prompt: '最新のワイヤレスイヤホンを検索して比較表を作って',
  options: {
    model: 'sonnet',
    maxTurns: 20,
    mcpServers: { database: dbServer },
    allowedTools: [
      'mcp__database__search_products', // mcp__{server名}__{tool名}
      'Write',
    ],
  },
});

Zodスキーマでツール引数を定義し、型安全にハンドラを実装できる。個人的にはこの設計が一番気に入っている。

実践: 自律開発デーモンをAgent SDKで再設計する

現行アーキテクチャ(CLI spawn方式)の課題

現行の自律開発デーモンでは、spawn("claude", ["-p", "--dangerously-skip-permissions"]) でCLIプロセスを起動し、stdinにプロンプトをパイプ、stdoutのテキスト出力を文字列として受け取っている。

typescript
// Before: CLI spawn方式(claude-runner.ts)
const child = spawn('claude', ['-p', '--dangerously-skip-permissions'], {
  cwd: workDir,
  env: getCleanEnv(),
  stdio: ['pipe', 'pipe', 'pipe'],
});
child.stdin.write(prompt);
child.stdin.end();

let output = '';
child.stdout.on('data', (chunk) => { output += chunk.toString(); });
child.stderr.on('data', (chunk) => {
  // レート制限はstderrの文字列パターンマッチで検出...
});

課題は明確だ。プロセス管理のオーバーヘッド、stdoutの非構造化テキスト解析、stderrの文字列マッチに依存するレート制限検出。

Agent SDK方式への設計比較

typescript
// After: Agent SDK方式
import { query } from '@anthropic-ai/claude-agent-sdk';

const q = query({
  prompt,
  options: {
    cwd: workDir,
    model: 'sonnet',
    maxTurns: 30,
    permissionMode: 'bypassPermissions',
    allowedTools: ['Bash', 'Read', 'Write', 'Edit', 'WebSearch', 'WebFetch'],
  },
});

for await (const msg of q) {
  if (msg.type === 'assistant' && msg.message) {
    for (const block of msg.message.content) {
      if (block.type === 'tool_use') {
        log.info(`Tool: ${block.name}`);
      }
    }
  }
  if (msg.type === 'result' && msg.subtype === 'success') {
    return { output: msg.result, cost: msg.total_cost_usd };
  }
}

構造化された SDKMessage で型安全にメッセージを処理でき、total_cost_usd でコスト追跡、session_id でセッション復元も可能になる。Subagentsでパイプラインステージ(アイデア生成・実装・レビュー)を分離し、Hooksでレート制限検出をPostToolUseに統合する — CLIの文字列解析から脱却できる設計だ。

なお、Managed Agents APIはクラウド側でエージェントを実行する仕組みであり、Agent SDKのようにローカルマシン上でCLIプロセスを制御するものとは用途が異なる。常時稼働デーモンのようなユースケースではAgent SDKが適している。

本番運用のハマりポイントと対策

PermissionModeの選択基準: bypassPermissions はバッチ処理や自律デーモン向け。対話型アプリケーションでは plan モードで実行前にユーザー確認を挟むのが安全だ。

環境変数のクリーンアップ: Agent SDKは内部でCLIをspawnするため、CLAUDECODE_* / CLAUDE_CODE_* 系の環境変数が残っているとネスト検出でエラーになる。env オプションでクリーンな環境を渡すこと。

AsyncGeneratorのリソースリーク: for await...of を途中で break した場合、内部プロセスが残る可能性がある。AbortController を使って明示的に中断するのが安全だ。

typescript
const abortController = new AbortController();

const q = query({
  prompt: '...',
  options: { abortController },
});

// タイムアウト時の安全な中断
setTimeout(() => abortController.abort(), 10 * 60 * 1000);

バージョン固定: SDKはアクティブに開発が進んでおり、マイナーバージョンでも挙動が変わることがある。package.json では ^ ではなく固定バージョンの指定を推奨する。


Claude Agent SDKは単なるリネームではなく、CLIベースの設定から脱却してプログラマティックにエージェントの振る舞いを制御するための転換点だ。Subagentsでエージェントを責務ごとに分離し、Hooksでツール実行のライフサイクルを制御し、MCPツール統合で外部システムと接続する。CLI版の設定ベース機能(settings.json Hooks、.claude/agents/ YAML)との違いを理解した上で、プロジェクトの要件に応じてSDKレベルの制御を活用してほしい。

もっと読む他の技術記事も読む
Claude Agent SDKAIエージェント開発Anthropic SDKMCP統合Claude Code移行

公開: 2026年04月25日

最終更新: 2026年04月26日