メインコンテンツへスキップ
#AI活用 約8分で読めます

Claude Batch API と Opus 4.6 でコスト90%削減|大規模ドキュメント処理の実装ガイド【2026年5月】

Claude Batch APIとOpus 4.6を組み合わせた大規模ドキュメント処理の実装方法を解説。レート制限回避・コスト削減・並列処理の最適化を実例で紹介

大規模なドキュメント処理を Claude API で実行する際、リアルタイムAPIではレート制限やコスト問題に直面しがちです。本記事では、Claude Batch API と Opus 4.6 を組み合わせた実装パターンを解説し、数千件規模のドキュメント処理を効率的に実行する方法を紹介します。

Claude Batch API の特徴とユースケース

Claude Batch API は非同期バッチ処理に特化したエンドポイントで、リアルタイムAPIとは異なる料金体系と実行モデルを持ちます。

Batch API とリアルタイムAPIの違い

主な相違点は以下の通りです。

項目リアルタイムAPIBatch API
レスポンス速度数秒〜数十秒数分〜数時間
レート制限厳格(モデルごとに異なる)緩和
料金通常料金50%割引(2026年5月時点)
用途チャット・即時応答大量データ処理・分析

Batch API は24時間以内の処理完了を保証し、リアルタイム性を求めない処理に最適化されています。

適用すべきユースケース

以下のような処理で効果を発揮します。

  • 大量ドキュメントの要約生成(数百〜数千件)
  • コードレビューの自動化(GitHubリポジトリ全体の解析)
  • 多言語翻訳の一括処理
  • データセットのラベリング・分類
  • PDF・画像からのテキスト抽出と構造化

特に、処理件数が100件を超える場合はBatch APIの導入を検討すべきです。

Batch API の実装パターン

実際の実装手順を段階的に解説します。

1. バッチリクエストの作成

Batch API は JSONL(JSON Lines)形式でリクエストを受け付けます。

// batch-request.ts
interface BatchRequest {
  custom_id: string;
  params: {
    model: string;
    max_tokens: number;
    messages: Array<{
      role: "user" | "assistant";
      content: string;
    }>;
  };
}

// ドキュメントリストからバッチリクエストを生成
function createBatchRequests(documents: string[]): BatchRequest[] {
  return documents.map((doc, index) => ({
    custom_id: `doc-${index}`,
    params: {
      model: "claude-opus-4.6",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: `以下のドキュメントを200文字以内で要約してください:\n\n${doc}`
        }
      ]
    }
  }));
}

// JSONL形式で出力
function saveAsJSONL(requests: BatchRequest[], filepath: string) {
  const jsonl = requests.map(r => JSON.stringify(r)).join('\n');
  fs.writeFileSync(filepath, jsonl);
}

2. バッチジョブの投入

Anthropic SDK を使用してバッチジョブを作成します。

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

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

async function submitBatchJob(jsonlPath: string) {
  // JSONL ファイルをアップロード
  const fileContent = fs.readFileSync(jsonlPath);
  
  const batch = await client.messages.batches.create({
    requests: fileContent.toString().split('\n').map(line => JSON.parse(line))
  });

  console.log(`Batch ID: ${batch.id}`);
  console.log(`Status: ${batch.processing_status}`);
  
  return batch.id;
}

3. ジョブステータスの監視

バッチ処理は非同期で実行されるため、定期的にステータスをポーリングします。

async function waitForCompletion(batchId: string): Promise<void> {
  while (true) {
    const batch = await client.messages.batches.retrieve(batchId);
    
    console.log(`Progress: ${batch.request_counts.succeeded}/${batch.request_counts.total}`);
    
    if (batch.processing_status === "ended") {
      console.log("✓ Batch completed");
      break;
    }
    
    if (batch.processing_status === "failed") {
      throw new Error("Batch processing failed");
    }
    
    // 30秒ごとにチェック
    await new Promise(resolve => setTimeout(resolve, 30000));
  }
}

4. 結果の取得と解析

完了したバッチから結果を取得します。

async function retrieveResults(batchId: string) {
  const batch = await client.messages.batches.retrieve(batchId);
  
  const results = await client.messages.batches.results(batchId);
  
  const summaries = new Map<string, string>();
  
  for await (const result of results) {
    if (result.result.type === "succeeded") {
      const customId = result.custom_id;
      const content = result.result.message.content[0];
      
      if (content.type === "text") {
        summaries.set(customId, content.text);
      }
    } else {
      console.error(`Failed: ${result.custom_id}`, result.result.error);
    }
  }
  
  return summaries;
}

Opus 4.6 との組み合わせによるコスト最適化

Claude Opus 4.6 は高い推論能力を持ちながら、Batch API との併用で大幅なコスト削減が可能です。

料金比較(2026年5月時点)

モデルリアルタイムAPIBatch API削減率
Claude Opus 4.6Input: $15/1M tokens
Output: $75/1M tokens
Input: $7.50/1M tokens
Output: $37.50/1M tokens
50%
Claude Sonnet 4.5Input: $3/1M tokens
Output: $15/1M tokens
Input: $1.50/1M tokens
Output: $7.50/1M tokens
50%

実測コスト例

10,000件のドキュメント(各2,000トークン)を要約する場合の試算です。

【リアルタイムAPI(Opus 4.6)】
Input: 20M tokens × $15/1M = $300
Output: 2M tokens × $75/1M = $150
合計: $450

【Batch API(Opus 4.6)】
Input: 20M tokens × $7.50/1M = $150
Output: 2M tokens × $37.50/1M = $75
合計: $225

削減額: $225(50%削減)

モデル選択の判断基準

以下のフローチャートで適切なモデルを選択できます。

graph TD
    A[処理開始] --> B{タスクの複雑度}
    B -->|高精度が必要| C[Opus 4.6]
    B -->|標準的な処理| D[Sonnet 4.5]
    C --> E{処理件数}
    D --> E
    E -->|100件未満| F[リアルタイムAPI]
    E -->|100件以上| G[Batch API]
    F --> H[処理実行]
    G --> H

複雑な推論(法的文書の分析、高度なコード生成)にはOpus 4.6、定型的な要約・分類にはSonnet 4.5が適しています。

大規模処理での実践テクニック

数千件規模の処理を安定運用するためのノウハウを紹介します。

チャンキング戦略

一度に大量のリクエストを送らず、適切なサイズに分割します。

// 1バッチあたり1,000件に制限
const BATCH_SIZE = 1000;

async function processByChunks(documents: string[]) {
  const chunks = [];
  
  for (let i = 0; i < documents.length; i += BATCH_SIZE) {
    chunks.push(documents.slice(i, i + BATCH_SIZE));
  }
  
  const batchIds = [];
  
  for (const chunk of chunks) {
    const requests = createBatchRequests(chunk);
    saveAsJSONL(requests, `batch-${chunks.indexOf(chunk)}.jsonl`);
    
    const batchId = await submitBatchJob(`batch-${chunks.indexOf(chunk)}.jsonl`);
    batchIds.push(batchId);
    
    // API制限を考慮して間隔を空ける
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  
  return batchIds;
}

エラーハンドリングと再試行

失敗したリクエストを自動的に再処理します。

async function processWithRetry(batchId: string, maxRetries = 3) {
  let attempt = 0;
  
  while (attempt < maxRetries) {
    try {
      await waitForCompletion(batchId);
      const results = await retrieveResults(batchId);
      
      // 失敗したリクエストを抽出
      const batch = await client.messages.batches.retrieve(batchId);
      
      if (batch.request_counts.errored > 0) {
        console.warn(`${batch.request_counts.errored} requests failed`);
        
        // 失敗分のみ再試行
        const failedRequests = await extractFailedRequests(batchId);
        
        if (failedRequests.length > 0 && attempt < maxRetries - 1) {
          console.log(`Retrying ${failedRequests.length} failed requests...`);
          const retryBatchId = await submitBatchJob(failedRequests);
          return processWithRetry(retryBatchId, maxRetries - attempt - 1);
        }
      }
      
      return results;
      
    } catch (error) {
      attempt++;
      console.error(`Attempt ${attempt} failed:`, error);
      
      if (attempt >= maxRetries) {
        throw error;
      }
      
      await new Promise(resolve => setTimeout(resolve, 60000)); // 1分待機
    }
  }
}

進捗管理とログ保存

長時間実行されるバッチ処理では、進捗の可視化が重要です。

import { createWriteStream } from 'fs';

class BatchProgressTracker {
  private logStream: WriteStream;
  
  constructor(logPath: string) {
    this.logStream = createWriteStream(logPath, { flags: 'a' });
  }
  
  async trackBatch(batchId: string) {
    const startTime = Date.now();
    
    while (true) {
      const batch = await client.messages.batches.retrieve(batchId);
      
      const progress = {
        timestamp: new Date().toISOString(),
        batchId,
        status: batch.processing_status,
        total: batch.request_counts.total,
        succeeded: batch.request_counts.succeeded,
        errored: batch.request_counts.errored,
        elapsedMinutes: Math.floor((Date.now() - startTime) / 60000)
      };
      
      this.logStream.write(JSON.stringify(progress) + '\n');
      
      console.log(`[${progress.timestamp}] ${progress.succeeded}/${progress.total} completed (${progress.elapsedMinutes}m)`);
      
      if (batch.processing_status === "ended") break;
      
      await new Promise(resolve => setTimeout(resolve, 30000));
    }
  }
  
  close() {
    this.logStream.end();
  }
}

実運用での注意点

Batch API を本番環境で使用する際の重要なポイントです。

レート制限の考慮

Batch API は緩和されていますが、制限は存在します。

  • 同時実行バッチ数: アカウントあたり最大10個(2026年5月時点)
  • 1バッチあたりの最大リクエスト数: 10,000件
  • 1日あたりの総処理量: ティア制限に依存

大規模処理では、バッチを段階的に投入する必要があります。

// 最大5バッチまで並行実行
const MAX_CONCURRENT_BATCHES = 5;

async function processWithConcurrencyLimit(documents: string[][]) {
  const queue = [...documents];
  const activeBatches = new Set<string>();
  const results = [];
  
  while (queue.length > 0 || activeBatches.size > 0) {
    // 空きスロットがあれば新しいバッチを投入
    while (activeBatches.size < MAX_CONCURRENT_BATCHES && queue.length > 0) {
      const chunk = queue.shift()!;
      const batchId = await submitBatchJob(chunk);
      activeBatches.add(batchId);
    }
    
    // いずれかのバッチが完了するまで待機
    const completed = await Promise.race(
      Array.from(activeBatches).map(async id => {
        await waitForCompletion(id);
        return id;
      })
    );
    
    activeBatches.delete(completed);
    const result = await retrieveResults(completed);
    results.push(result);
  }
  
  return results;
}

コスト監視の実装

予期せぬ高額請求を防ぐため、処理前に概算コストを算出します。

interface CostEstimate {
  totalInputTokens: number;
  totalOutputTokens: number;
  estimatedCost: number;
}

function estimateBatchCost(
  documents: string[],
  model: "opus-4.6" | "sonnet-4.5"
): CostEstimate {
  const pricing = {
    "opus-4.6": { input: 7.50, output: 37.50 },
    "sonnet-4.5": { input: 1.50, output: 7.50 }
  };
  
  // トークン数を概算(1文字 ≈ 0.4トークン)
  const avgInputTokens = documents.reduce((sum, doc) => 
    sum + doc.length * 0.4, 0
  );
  
  // 出力は入力の10%と仮定
  const avgOutputTokens = avgInputTokens * 0.1;
  
  const inputCost = (avgInputTokens / 1_000_000) * pricing[model].input;
  const outputCost = (avgOutputTokens / 1_000_000) * pricing[model].output;
  
  return {
    totalInputTokens: Math.ceil(avgInputTokens),
    totalOutputTokens: Math.ceil(avgOutputTokens),
    estimatedCost: inputCost + outputCost
  };
}

// 使用例
const estimate = estimateBatchCost(documents, "opus-4.6");
console.log(`Estimated cost: $${estimate.estimatedCost.toFixed(2)}`);

if (estimate.estimatedCost > 100) {
  console.warn("⚠️ High cost detected. Proceed with caution.");
}

データプライバシーとセキュリティ

機密情報を含むドキュメント処理では以下に注意します。

  • データ保持期間: Batch APIで処理されたデータは30日間保持される
  • 暗号化: 転送時(TLS)と保管時の暗号化が標準
  • アクセス制御: APIキーの厳格な管理(環境変数・シークレット管理ツールを使用)
// 機密情報のマスキング例
function maskSensitiveData(text: string): string {
  return text
    .replace(/\b\d{3}-\d{4}-\d{4}\b/g, "***-****-****") // 電話番号
    .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "***@***.***") // メールアドレス
    .replace(/\b\d{4}-\d{4}-\d{4}-\d{4}\b/g, "****-****-****-****"); // クレジットカード
}

まとめ

Claude Batch API と Opus 4.6 の組み合わせにより、大規模ドキュメント処理を以下のように最適化できます。

  • コスト削減: リアルタイムAPIと比較して50%のコスト削減
  • レート制限回避: 非同期処理により大量リクエストを安定実行
  • 高精度処理: Opus 4.6 の推論能力で複雑なタスクに対応
  • スケーラビリティ: チャンキングと並行処理で数千〜数万件規模に対応

実装のポイント:

  • JSONL形式でのリクエスト作成
  • ステータス監視と自動再試行の実装
  • チャンク分割による段階的処理
  • コスト事前見積もりと進捗ログ保存

数百件を超えるドキュメント処理では、Batch API の導入を積極的に検討すべきです。特に定期的に実行される分析処理や、リアルタイム性が不要なバックグラウンドタスクで効果を発揮します。

参考リンク

#Claude #Batch API #API最適化 #コスト削減 #LLM
シェア