📝

AIエージェントにおける大規模データ処理のためのHandle設計パターン

に公開

はじめに

AIエージェントを実務で活用する際、避けられない課題があります。それは大量データの取り扱いです。

例えば、アプリケーションのログファイルを解析して異常を検出したり、大量のデータベース検索結果を処理したりする場面を考えてみてください。10,000行のログや数千件のクエリ結果を取得すると、簡単に数百KB〜数MBのデータになります。これをそのまま会話コンテキストに含めると、トークン消費が爆発的に増え、応答が遅くなるだけでなく、コストも跳ね上がります。

従来のアプローチでは、ツールの出力をすべてAIに渡すか、事前に人間が手動でフィルタリングするしかありませんでした。しかし、どちらも理想的とは言えません。

この問題に対し、Anthropicが興味深い設計思想を提示しました。本記事では、その中核となるアイデアを解説し、実際にエージェントフレームワークに導入した設計パターンを紹介します。

Anthropicの設計思想

11月、Anthropicは「Code Execution with MCP」という記事で、エージェントのコンテキスト効率を大幅に改善する手法を発表しました。

従来のモデルコンテキストプロトコル(MCP)では、利用可能なツールの定義をすべてプロンプトに含める必要がありました。ツール数が増えるにつれ、この「ツールカタログ」だけで150,000トークンを消費するケースもあったそうです。

基本原則

Anthropicのアプローチは、従来の「ツールを直接呼び出す」パラダイムから「コードを書いてツールにアクセスする」パラダイムへの転換です。この記事を読んで、特に印象的だったのは以下の3点でした。

まず、ファイルシステムに基づくツール探索という考え方です。エージェントは必要に応じてファイルを読み込み、ツールの定義を取得します。最初からすべてをロードする必要はありません。

次に、実行環境でのデータ処理です。例えば10,000行のスプレッドシートがあったとして、実行環境内でフィルタリングを行い、関連する部分だけをAIに返すことができます。エージェント側で全データを受け取る必要がなくなります。

そして、中間結果の分離により、処理の中間結果は実行環境に留まり、エージェントは明示的に記録された内容だけを見ます。この仕組みはプライバシー保護の観点からも重要で、個人識別情報(PII)の漏洩リスクを低減できます。

この設計により、150,000トークンが2,000トークンに削減されました(98.7%の削減)。

Progressive Disclosure

この設計思想の核心は「Progressive Disclosure(段階的な情報開示)」です。エージェントは最初に概要だけを見て、必要に応じて詳細を取得します。まるで、Webサイトの「もっと見る」ボタンをクリックするように。

データがコンテキストに直接含まれるのではなく、参照として保持されます。この考え方がHandle Systemの原点になっています。

Handle System

Anthropicの設計思想を自分のAIエージェントに取り入れようとしたとき、抽象化すべき要素として以下が見えてきました。データの実体は実行環境やストレージに保存し、データの参照は軽量なIDとメタデータで表現する。そしてデータへのアクセスは必要なときだけ行う。

これらを実現するため、「Handle(ハンドル)」という概念を導入しました。

Handleとは

Handle は、大規模データへの軽量な参照です。書籍の目次のようなもので、中身を見なくても概要が分かります。

interface DataHandle {
  id: string;              // 一意の識別子
  type: HandleType;        // データの種類(TEXT/JSON/BINARY等)
  metadata: {
    source: string;        // データの出所
    estimatedSize: number; // 推定サイズ
    summary: string;       // 要約(例: "10,000行、23件のエラー")
    sample?: any;          // サンプルデータ(最初の数行など)
  };
  createdAt: number;
  options: {
    scope: 'turn' | 'session' | 'persistent';
    storage: 'memory' | 'disk' | 'external';
  };
}

エージェントが見るのは、このメタデータだけです。データの実体は HandleStore に保存され、必要なときだけアクセスします。

データ処理の流れ

実装パターン

では実際に、ツール開発者がHandleをどう使うのか見てみましょう。

自動Handle化

ツールの出力が一定サイズを超えたら、自動的にHandleを作成する仕組みです。

async execute(args, context) {
  const output = await runCommand(args);
  const outputSize = Buffer.byteLength(output);

  // 100KBを超えたらHandleに保存
  if (outputSize > 100 * 1024 && context.handles) {
    const handle = context.handles.create(output, {
      source: `shell: ${args.command}`,
      estimatedSize: outputSize,
      summary: `${(outputSize / 1024).toFixed(2)} KB, ${output.split('\n').length} lines`,
      sample: output.split('\n').slice(0, 20).join('\n')
    });

    return {
      success: true,
      output: `[Large output stored in handle: ${handle.id}]`,
      handles: [handle]
    };
  }

  // 小さい出力はそのまま返す
  return { success: true, output };
}

ユーザーは何も設定する必要がありません。自動的に最適化されます。

リッチなメタデータ

単なるサイズ情報だけでなく、ドメイン固有の統計情報を含めることで、エージェントがより賢い判断を下せます。

// API応答データの例
const metadata = {
  source: 'API: GET /users',
  summary: `${users.length} users, ${errors.length} validation errors`,
  statistics: {
    totalRecords: users.length,
    byStatus: {
      active: users.filter(u => u.status === 'active').length,
      inactive: users.filter(u => u.status === 'inactive').length
    },
    errorCount: errors.length
  }
};

エージェントはメタデータを見て「1,000件のレコードがあり、そのうち800件がアクティブ、検証エラーが23件」と即座に理解できます。全データを読む必要はありません。

filter_handleツール

個人的に最も重要だと考えているのが、このツールです。JavaScriptコードを使ってHandle内のデータを処理できます。

// エージェントの操作例
filter_handle({
  handle_id: "handle_abc_123",
  code: "data.split('\\n').filter(line => line.includes('ERROR')).join('\\n')"
})

エージェントは必要な部分だけを抽出でき、データの実体はコンテキストに含まれません。繰り返しフィルタリングしても、トークン消費は最小限で済みます。

Anthropicの記事で言及された「コードによるデータ処理」を、ツールとして実装しています。

実際の効果検証

言葉だけでは分かりにくいので、実際のテストケースを見てみましょう。

大量テキスト生成

10,000行のテキスト(321KB)を生成するシェルコマンドを実行しました。

結果:

  • 出力は自動的に handle_019a861a_1_oflk として保存
  • エージェントには最初の20行のサンプルだけが表示される
  • filter_handle で100〜105行目を抽出
  • トークン消費: 約30トークン(全文なら約80,000トークン)

Handle操作の具体例

複数のHandle操作を組み合わせた実用的なワークフローです。


操作の流れ:

  1. list_handles - 利用可能なHandleを一覧表示
  2. filter_handle - 特定の行範囲を抽出
  3. filter_handle - さらに別のフィルタリング
  4. get_handle - 必要なら完全データを取得
  5. delete_handle - 不要になったら削除してメモリを解放

エージェントは大規模データを自由に探索できますが、コンテキストには必要最小限しか含まれません。

まとめ

Handle Systemは、Anthropicが提唱した「Progressive Disclosure」の考え方を、ツールシステムに適用したものです。

その本質は、データの実体と参照を分離し、エージェントには必要な情報だけを段階的に提供することです。これにより、従来の「ツール呼び出しパラダイム」から「コード主導のエージェント運用」へ移行できます。

実装の要点は3つです。自動Handle化により閾値ベースで透過的に動作すること、リッチなメタデータでドメイン知識を含む要約情報を提供すること、そして filter_handle によりJavaScriptコードでの柔軟なデータ処理を可能にすることです。

所感として、この設計パターンはログ解析、クラウドリソース監査、大規模API応答の処理など、多くの実用場面で威力を発揮すると感じています。エージェント開発において、コンテキスト効率は今後ますます重要になるはずで、Handle Systemのような抽象化が一つの解決策になるのではないかと考えています。


参考文献

Accenture Japan (有志)

Discussion