Claude Media
Claude Agent SDKとVercel AI SDKの違い — Web UIに組み込む側の選び方

Claude Agent SDKとVercel AI SDKの違い — Web UIに組み込む側の選び方

ループを回す場所、ツールの実行場所、承認UIと会話状態の持ち方で、Claude Agent SDKとVercel AI SDKのエージェント機能を比べます。HarnessAgentで両者をつなぐ構成も扱います。

Claude Agent SDKとVercel AI SDKは、どちらも「エージェント」を作る道具です。ただ、ループを回す場所が違います。Vercel AI SDK(以下AI SDK)の ToolLoopAgent は、アプリのプロセス内でモデルとツールのループを回します。Claude Agent SDKは、Claude Codeのエージェントを別プロセスとして起動し、その入出力をアプリが受け取る作りです。

Web UIに組み込むときは、この差が「ツールの実行場所」「ストリーミングの整形」「承認ダイアログ」「会話状態の保存先」の4か所に効いてきます。順に比べます。

2つのSDKは何を提供するか

AI SDKのドキュメントは、エージェントを「LLMがツールをループで使ってタスクをこなすもの」と定義しています。ループは、コンテキスト管理と停止条件の2つで制御します。ToolLoopAgent クラスがこの3要素をまとめて引き受けます。

Claude Agent SDKの説明は、出発点が違います。Claude Codeが使っているツール・エージェントループ・コンテキスト管理を、PythonとTypeScriptのライブラリとして使えるようにしたものです。ファイルの読み書き、コマンド実行、Web検索といった組み込みツールが最初から付きます。

比べる軸Claude Agent SDKAI SDK(ToolLoopAgent)
ループの置き場所Claude Agent SDKclaude CLIのサブプロセスAI SDK(ToolLoopAgent)アプリのプロセス内
ツールClaude Agent SDK組み込みツールに加え、自作はインプロセスMCPサーバーで登録AI SDK(ToolLoopAgent)tool() と execute を自分で書く
承認の仕組みClaude Agent SDK権限評価の6段階と canUseTool コールバックAI SDK(ToolLoopAgent)toolApproval の4つのステータス
UIへの出力Claude Agent SDKStreamEvent(生のAPIイベント)を自分で整形AI SDK(ToolLoopAgent)createAgentUIStreamResponse と useChat
会話状態Claude Agent SDKサブプロセスのローカルディスクにトランスクリプトAI SDK(ToolLoopAgent)クライアントが毎回送るメッセージから再構築(標準パターン)
ループの上限Claude Agent SDKmaxTurns を指定。単独のセッションタイムアウトなしAI SDK(ToolLoopAgent)既定で20ステップ

以降は、この表の行をWeb UIの実装上の問いに読み替えて掘ります。

ツール実行は誰のプロセスで走るか

AI SDKでは、ツールは tool() で定義し、execute 関数にDB検索や社内APIの呼び出しを書きます。ドキュメントのサンプルも、天気の取得と華氏から摂氏への変換という2つのツールを ToolLoopAgent に渡す形です。ループも execute も、Route Handlerと同じプロセスで動きます。

import { ToolLoopAgent, tool } from 'ai';
import { z } from 'zod';
 
const agent = new ToolLoopAgent({
  model: 'anthropic/claude-sonnet-5.5',
  tools: {
    lookupOrder: tool({
      description: '注文番号から配送状況を返す',
      inputSchema: z.object({ orderId: z.string() }),
      execute: async ({ orderId }) => fetchOrderStatus(orderId),
    }),
  },
});

Claude Agent SDKでは、query() を呼ぶたびにSDKが claude CLIのサブプロセスを起動し、標準入出力でやり取りします。シェルも作業ディレクトリもセッションの記録ファイルも、このサブプロセスが持ちます。ReadやBashなどの組み込みツールは、そこで動きます。自作ツールは createSdkMcpServer で包んで渡す方式で、このMCPサーバーはアプリ内で動き、別プロセスにはなりません。

つまり、Web UIの裏側で「ユーザーの依頼ごとに、コードベースを読んでファイルを編集する」ような動きをさせたいなら、Claude Agent SDKは最初からその前提で作られています。AI SDKの ToolLoopAgent で同じことをするなら、ファイル操作のツールを自分で書くことになります。逆に、業務APIを数個呼ぶだけのチャットなら、サブプロセスを立てる構造は過剰になりがちです。

ストリーミングをUIに届ける道のり

AI SDKは、UIまでの経路が用意されています。APIルートで createAgentUIStreamResponse() にエージェントとUIメッセージを渡せば、クライアント向けのストリーム応答になります。

// app/api/chat/route.ts
import { createAgentUIStreamResponse } from 'ai';
 
export async function POST(request: Request) {
  const { messages } = await request.json();
  return createAgentUIStreamResponse({
    agent: myAgent,
    uiMessages: messages,
  });
}

クライアントは useChat でメッセージ配列と状態を受け取ります。InferAgentUIMessage でエージェントからUIメッセージの型を導けるので、ツールごとの表示コンポーネントまで型が通ります。

Claude Agent SDKの出力は、既定では AssistantMessage が内容ブロックごとに届きます。文字を逐次出したいなら includePartialMessages: true を指定し、StreamEvent を受け取ります。中身は生のAPIイベントなので、content_block_delta のうち delta.type が text_delta のものを拾ってテキストを取り出すのは、アプリ側の仕事です。

次のコードは、その処理をサーバー送信イベント(SSE)の行に変換する骨格の例です。ドキュメントの型チェックの流れに沿った書き方で、UIメッセージの形式への変換は含みません。

import { query } from '@anthropic-ai/claude-agent-sdk';
 
export async function POST(request: Request) {
  const { prompt } = await request.json();
  const encoder = new TextEncoder();
 
  const body = new ReadableStream({
    async start(controller) {
      for await (const message of query({
        prompt,
        options: { includePartialMessages: true, allowedTools: ['Read'] },
      })) {
        if (
          message.type === 'stream_event' &&
          message.event.type === 'content_block_delta' &&
          message.event.delta.type === 'text_delta'
        ) {
          controller.enqueue(
            encoder.encode(`data: ${JSON.stringify(message.event.delta.text)}\n\n`),
          );
        }
      }
      controller.close();
    },
  });
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/event-stream' },
  });
}

ツール呼び出しの表示まで出すなら、content_block_start の tool_use ブロックや、完成した AssistantMessage も拾う必要があります。サブエージェントのトークン単位の差分は転送されず、出力の帰属は完成したメッセージの parent_tool_use_id で見分ける仕様です。UI用のイベント形式を自前で設計する手間は、Claude Agent SDK側にかかります。

ストリーミングの有効化と各イベントの順序はAgent SDKのストリーミング出力で詳しく扱っています。

承認ダイアログの作り方

エージェントが「ファイルを消す」「送金する」といった操作をするとき、UIで承認を取りたくなります。両SDKとも仕組みはありますが、前提が違います。

AI SDKでは、ToolLoopAgent の toolApproval に、ツールごとのルールか全ツール共通の関数を渡します。返せるステータスは not-applicable(通常実行、既定)、approved、denied、user-approval の4つです。user-approval を返すと、エージェントはツールを実行せずに tool-approval-request を返します。useChat 側では、そのツール部分が state: 'approval-requested' で届くので、addToolApprovalResponse で応答します。入力値で分岐もできます。

toolApproval: {
  processPayment: async ({ amount }, { runtimeContext }) => {
    if (runtimeContext.role !== 'admin') {
      return { type: 'denied', reason: 'Only admins can send payments' };
    }
    return amount > 1000 ? 'user-approval' : undefined;
  },
},

Claude Agent SDKでは、ツール要求が権限評価を通り、フック・denyルール・askルール・権限モード・allowルールのどこでも決まらなかったときに、canUseTool コールバックが呼ばれます。コールバックは「ユーザーに尋ねてからallowかdenyを返す」関数です。

const canUseTool: CanUseTool = async (toolName, input) => {
  const approved = await askBrowserUser(toolName, input); // ブラウザ側の応答を待つ
  return approved
    ? { behavior: 'allow', updatedInput: input }
    : { behavior: 'deny', message: 'User declined' };
};

Web UIに載せるなら、askBrowserUser の部分、つまりブラウザへ確認を送って応答を待つ橋渡しを自分で作ります。AI SDKでは useChat のツール部分と addToolApprovalResponse がその役を担います。

もう1つ、押さえたい点があります。canUseTool は、allowルールや acceptEdits・bypassPermissions モードで自動承認されたツールには呼ばれません。ツールを allowedTools に裸の名前で入れると、そのツールの確認ダイアログは出なくなります。すべての呼び出しを関門にしたいときは、PreToolUse フックが向いています。承認の詳しい設計はAgent SDKのcanUseToolの解説とパーミッション制御の解説にあります。

会話状態をどこに持つか

AI SDKの標準的な useChat の使い方では、サーバーは会話を保存せず、クライアントが毎ターン送るメッセージから会話を組み立てます。このためメッセージ履歴は、クライアントが細工できる入力です。承認の記録も履歴から復元されるので、スキーマに合う入力に対して偽の承認を作り込まれると、人間の確認を飛ばされる恐れがあります。ドキュメントは、機微な操作を持つツールには experimental_toolApprovalSecret を設定し、承認をサーバーが署名(HMAC)したものに限る方法を挙げています。

Claude Agent SDKは逆です。セッションの状態はサブプロセスのローカルディスクにあります。ホスティングの解説は、これを「ステートレスなAPIラッパーとは違い、ローカル状態を持つ長生きのプロセスを運用する」ことと位置づけ、1エージェントあたりの出発点として1 GiBのRAM、5 GiBのディスク、1 CPUを挙げています。コンテナが落ちるとトランスクリプトも消えるため、アイドル時に停止する構成では SessionStore が必須になります。

Web UIで見ると、次のような違いになります。

  • AI SDK: サーバーに会話を保存しない構成にできる。その代わり、履歴の改ざんへの備えは自分で入れる
  • Claude Agent SDK: セッションごとにサブプロセスと作業ディレクトリを持つ。接続の維持、コンテナの寿命、セッションの保存先を設計する

本番での置き方はAgent SDK本番ホスティングの4つのセッションパターンが出発点です。

HarnessAgent — AI SDKのUIでClaude Codeを動かす

2つは二者択一とは限りません。AI SDKには HarnessAgent があり、自分でループを組む代わりに、Claude CodeやCodexのような完成したハーネス(実行基盤)を動かせます。ハーネスはプロバイダーやモデルとは別の抽象で、結果はAI SDK互換の結果型とUIの部品にストリームされます。

Claude Codeのアダプターを使う例は次のとおりです。

import { HarnessAgent } from '@ai-sdk/harness/agent';
import { claudeCode } from '@ai-sdk/harness-claude-code';
 
export const agent = new HarnessAgent({
  harness: claudeCode,
  model: 'claude-sonnet-4-6',
  instructions: 'You are a careful coding assistant.',
});

制約も押さえておきます。

  • Claude CodeやCodexのようにブリッジ経由で動くハーネスは、@ai-sdk/sandbox-vercel のような実ネットワークのサンドボックスが必要
  • Claude Codeのアダプターは、カスタムツール・スキル・構造化出力・組み込みツールの承認と絞り込みに対応する一方、履歴アクセス(readHistory)は非対応
  • ハーネスのセッションは自前の会話履歴を持つ。メッセージ配列を渡しても、最新のユーザーメッセージだけが入力になり、過去の会話は再生されない。チャットのルートでは、メッセージの再送ではなくセッションの保存と再開で状態をつなぐ

AI SDKのドキュメントは、HarnessAgentの中身がClaude Agent SDKであるとは書いていません。「Claude Codeを動かす」という点は同じでも、別の経路として扱うのが安全です。

選び方の早見表

どちらが優れているかではなく、Web UIで何をさせたいかで分かれます。

作りたいもの向く構成理由
社内APIやDBを数個呼ぶチャットUI向く構成AI SDKの ToolLoopAgent + useChat理由ループもツールも同じプロセス。UIまでの経路が揃っている
コードベースの読み書きやコマンド実行をさせるエージェント向く構成Claude Agent SDK理由組み込みツール・権限・セッションが付属
上の機能をAI SDKのチャットUIで見せたい向く構成AI SDKの HarnessAgent + Claude Codeアダプター理由UI部品をそのまま使える。サンドボックスが前提
ステップごとにモデルを切り替えたいアプリ向く構成AI SDKの ToolLoopAgent理由prepareStep でステップ単位にモデルを選べる
自社でループを運用したくない向く構成Managed Agents理由Anthropicがループをホストする

最後の行は、Claude Agent SDKの概要ページにある使い分けの表の内容です。自分のプロセスで動かすならAgent SDK、AnthropicにホストさせるならManaged Agentsという整理になります。

Web UIに載せる前の確認事項

Claude Agent SDKを自社プロダクトのUIに組み込むときは、ドキュメントの条件に当たります。

  • 認証: 事前の承認がない限り、第三者の開発者が自社製品でclaude.aiのログインやレート制限を提供することは認められていません。APIキーによる認証を使います
  • 表示名: 「Claude Agent」「Claude」(「Agents」と名付けたメニュー内)、「 Powered by Claude」は使えます。「Claude Code」や「Claude Code Agent」、Claude Codeを模したASCIIアートや見た目は使えません
  • ループの上限: 単独のセッションタイムアウトはありません。ブラウザから長く走らせるなら maxTurns で上限を決めておきます。AI SDKの ToolLoopAgent は既定で20ステップ、isLoopFinished() を指定すると上限なしになります

AI SDK側は、既定の20ステップで止まったとき、ログに警告が出ます。上限を明示すれば警告は出ません。長い作業を任せるなら、stopWhen の明示が実質必須です。

まとめ

ツールの中身が「自社の関数」ならAI SDK、「ファイルとシェル」ならClaude Agent SDKで、境目はここにあります。UIまでの配線が既製品のAI SDKに対し、Claude Agent SDKは生のイベントを受け取る代わりに、権限・セッション・フックまで含めたClaude Codeの機能を手に入れます。両方ほしい場合は、HarnessAgentで橋をかける選択肢があります。ただしサンドボックスの運用が追加で必要になり、履歴の読み出しは使えません。

この記事を共有:XはてブLinkedIn