CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/API & SDK
API & SDK/2026-05-06上級

Claude Haiku / Sonnet / Opus 切替戦略で利益率を最大化する実装ガイド

Claude APIのモデルをタスク複雑度に応じて動的に切り替え、API費用を大幅削減しながら品質を維持する実装パターンを詳解。実コスト計算・ルーティングロジック・プロンプトキャッシング併用まで解説します。

claude-api81monetization4model-switchingcost-optimization25haiku3sonnet3

Claude APIで収益サービスを構築していると、必ず「API費用とサービス品質のトレードオフ」にぶつかります。

初期はとりあえず Sonnet を使いがちです。品質は高いし、失敗のリスクが少ありません。でも月間リクエスト数が増えてくると、API費用がジワジワ利益を圧迫します。私がClaudeを組み込んだサービスを運用してきた中で気づいたのは、全リクエストを同じモデルで処理する必要はまったくないということでした。

タスクの複雑度に応じてモデルを動的に切り替える「モデルルーティング」を実装すると、品質を落とさずにAPI費用を40〜70%削減できます。ここではその設計思想から実装コード、本番運用での落とし穴まで、私が実際に使っているパターンを丸ごと解説します。

モデルコストの実態から見る削減余地

まず数字を直視しましょう。2026年5月時点のAnthropicの公式料金(100万トークンあたり)は以下の通りです。

  • Claude Haiku 4.5: 入力 $0.80 / 出力 $4.00
  • Claude Sonnet 4.6: 入力 $3.00 / 出力 $15.00
  • Claude Opus 4.6: 入力 $15.00 / 出力 $75.00

出力トークンのコスト差が重要です。Haiku と Sonnet を比べると出力トークンが3.75倍、Haiku と Opus では18.75倍の開きがあります。

典型的な「AIアシスタント系サービス」での1リクエストを仮定してみます。入力500トークン、出力300トークンとすると:

  • Haiku: $0.000040 + $0.000120 = $0.000160/リクエスト
  • Sonnet: $0.000150 + $0.000450 = $0.000600/リクエスト
  • Opus: $0.000750 + $0.002250 = $0.003000/リクエスト

月100万リクエストで計算すると、Sonnet一択なら$600/月。もし70%をHaikuで処理できれば、700,000×$0.000160 + 300,000×$0.000600 = $112 + $180 = $292/月。差額$308、約51%の削減です。

これが「モデルルーティング」の本質的な価値です。

タスク複雑度の分類:何をどのモデルに任せるか

モデルルーティングの核心は「分類の設計」です。何をHaikuに任せ、何をSonnetに回し、何をOpusに送るか。私のサービスでの基本分類は以下の通りです。

Haiku(高速・低コスト)に向いているタスク:

  • 感情分析・スパム判定・カテゴリ分類
  • 短文の要約(300字以内)
  • 構造化データの抽出(JSONへの変換等)
  • FAQ・定型フォーマットへの回答
  • 翻訳(技術文書以外の一般文)

Sonnet(バランス型)に向いているタスク:

  • 中程度の文章生成(メール・ブログ草稿)
  • コードの説明・バグの指摘
  • 複数文書の横断的な分析
  • 対話システムの一般的な返答

Opus(最高品質)に向いているタスク:

  • 法律・医療・財務に関わる専門的な判断
  • 複雑な推論や多段階の問題解決
  • クリエイティブな長文生成(品質が収益に直結する場合)
  • 重要なコードの設計レビュー

実装:ルーティングエンジンの設計

ルーティングには2つのアプローチがあります。①ルールベース(タスクタイプで事前分類)と②LLMベース(Haikuに分類させる)。費用対効果が高いのはハイブリッドです。

// lib/model-router.ts
 
export type TaskType =
  | "classification"
  | "short_summary"
  | "data_extraction"
  | "faq"
  | "translation"
  | "long_content"
  | "code_review"
  | "analysis"
  | "expert_judgment"
  | "complex_reasoning";
 
export type ClaudeModel =
  | "claude-haiku-4-5-20251001"
  | "claude-sonnet-4-6"
  | "claude-opus-4-6";
 
// ルールベースの初期ルーティングテーブル
const ROUTING_TABLE: Record<TaskType, ClaudeModel> = {
  classification: "claude-haiku-4-5-20251001",
  short_summary: "claude-haiku-4-5-20251001",
  data_extraction: "claude-haiku-4-5-20251001",
  faq: "claude-haiku-4-5-20251001",
  translation: "claude-haiku-4-5-20251001",
  long_content: "claude-sonnet-4-6",
  code_review: "claude-sonnet-4-6",
  analysis: "claude-sonnet-4-6",
  expert_judgment: "claude-opus-4-6",
  complex_reasoning: "claude-opus-4-6",
};
 
// タスクタイプが不明な場合:Haikuに分類させる
async function classifyTaskWithHaiku(prompt: string): Promise<TaskType> {
  const classifier = new Anthropic();
 
  const response = await classifier.messages.create({
    model: "claude-haiku-4-5-20251001", // 分類自体は常にHaiku
    max_tokens: 50,
    system: `You are a task classifier. Given a user prompt, classify it into exactly one of these categories:
classification, short_summary, data_extraction, faq, translation,
long_content, code_review, analysis, expert_judgment, complex_reasoning.
Respond with ONLY the category name, nothing else.`,
    messages: [
      {
        role: "user",
        content: `Classify this task:\n\n${prompt.slice(0, 500)}`, // 先頭500文字で判断
      },
    ],
  });
 
  const taskType = (
    response.content[0] as { type: "text"; text: string }
  ).text
    .trim()
    .toLowerCase() as TaskType;
 
  return ROUTING_TABLE[taskType] ? taskType : "analysis"; // フォールバック
}
 
export async function routeToModel(
  prompt: string,
  explicitTaskType?: TaskType
): Promise<ClaudeModel> {
  const taskType = explicitTaskType ?? (await classifyTaskWithHaiku(prompt));
  return ROUTING_TABLE[taskType];
}

分類にHaikuを使うのは理にかなっています。分類プロンプト自体は短く(入力100トークン、出力10トークン程度)、コストはほぼゼロです。

実装:メインの Claude クライアント

ルーターと組み合わせて使うメインクライアントです。

// lib/adaptive-claude-client.ts
import Anthropic from "@anthropic-ai/sdk";
import { routeToModel, TaskType, ClaudeModel } from "./model-router";
 
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
 
interface CallOptions {
  taskType?: TaskType;
  maxTokens?: number;
  systemPrompt?: string;
  // 品質しきい値:スコアがこれ以下ならOpusで再試行
  qualityThreshold?: number;
  // コスト記録用
  userId?: string;
}
 
interface CallResult {
  text: string;
  model: ClaudeModel;
  inputTokens: number;
  outputTokens: number;
  costUsd: number;
  fallbackUsed: boolean;
}
 
// モデル別のコスト($/100万トークン)
const COST_PER_MILLION: Record<ClaudeModel, { input: number; output: number }> = {
  "claude-haiku-4-5-20251001": { input: 0.8, output: 4.0 },
  "claude-sonnet-4-6": { input: 3.0, output: 15.0 },
  "claude-opus-4-6": { input: 15.0, output: 75.0 },
};
 
function calculateCost(
  model: ClaudeModel,
  inputTokens: number,
  outputTokens: number
): number {
  const rates = COST_PER_MILLION[model];
  return (
    (inputTokens / 1_000_000) * rates.input +
    (outputTokens / 1_000_000) * rates.output
  );
}
 
export async function callClaude(
  prompt: string,
  options: CallOptions = {}
): Promise<CallResult> {
  const {
    taskType,
    maxTokens = 1024,
    systemPrompt,
    qualityThreshold,
    userId,
  } = options;
 
  // モデルを選択
  const selectedModel = await routeToModel(prompt, taskType);
 
  // Claude API を呼ぶ
  const response = await anthropic.messages.create({
    model: selectedModel,
    max_tokens: maxTokens,
    system: systemPrompt,
    messages: [{ role: "user", content: prompt }],
  });
 
  const inputTokens = response.usage.input_tokens;
  const outputTokens = response.usage.output_tokens;
  const costUsd = calculateCost(selectedModel, inputTokens, outputTokens);
  const text = (response.content[0] as { type: "text"; text: string }).text;
 
  // 品質チェックが必要な場合:Haikuで品質スコアを評価
  if (qualityThreshold && selectedModel !== "claude-opus-4-6") {
    const qualityScore = await evaluateQuality(text, prompt);
 
    if (qualityScore < qualityThreshold) {
      console.log(
        `[Fallback] Quality ${qualityScore} < threshold ${qualityThreshold}. Switching to Opus.`
      );
 
      // Opus で再試行
      const fallbackResponse = await anthropic.messages.create({
        model: "claude-opus-4-6",
        max_tokens: maxTokens,
        system: systemPrompt,
        messages: [{ role: "user", content: prompt }],
      });
 
      const fbInputTokens = fallbackResponse.usage.input_tokens;
      const fbOutputTokens = fallbackResponse.usage.output_tokens;
 
      return {
        text: (
          fallbackResponse.content[0] as { type: "text"; text: string }
        ).text,
        model: "claude-opus-4-6",
        inputTokens: fbInputTokens,
        outputTokens: fbOutputTokens,
        costUsd: calculateCost("claude-opus-4-6", fbInputTokens, fbOutputTokens),
        fallbackUsed: true,
      };
    }
  }
 
  // コストをログに記録(Stripe連携やDB保存はここで行う)
  if (userId) {
    void logUsage(userId, selectedModel, inputTokens, outputTokens, costUsd);
  }
 
  return {
    text,
    model: selectedModel,
    inputTokens,
    outputTokens,
    costUsd,
    fallbackUsed: false,
  };
}
 
// Haikuを使った軽量品質評価(0.0〜1.0)
async function evaluateQuality(
  response: string,
  originalPrompt: string
): Promise<number> {
  const evaluator = new Anthropic();
  const evalResponse = await evaluator.messages.create({
    model: "claude-haiku-4-5-20251001",
    max_tokens: 10,
    messages: [
      {
        role: "user",
        content: `Rate the quality of this AI response on a scale from 0.0 to 1.0.
Original question: "${originalPrompt.slice(0, 200)}"
Response: "${response.slice(0, 500)}"
Reply with only a decimal number between 0.0 and 1.0.`,
      },
    ],
  });
 
  const score = parseFloat(
    (evalResponse.content[0] as { type: "text"; text: string }).text
  );
  return isNaN(score) ? 0.5 : Math.min(1.0, Math.max(0.0, score));
}
 
async function logUsage(
  userId: string,
  model: ClaudeModel,
  inputTokens: number,
  outputTokens: number,
  costUsd: number
): Promise<void> {
  // DB保存・Stripe Usage Report・アナリティクス送信など
  console.log(
    `[Usage] user=${userId} model=${model} ` +
      `input=${inputTokens} output=${outputTokens} cost=$${costUsd.toFixed(6)}`
  );
}

プロンプトキャッシングとの組み合わせ

モデル切替と並んで強力なのが プロンプトキャッシング です。同じシステムプロンプトを繰り返し使う場合、キャッシュ読み込みトークンは通常の1/10のコストで済みます。

// キャッシュ対応版のシステムプロンプト構築
function buildCachedSystemPrompt(
  baseInstructions: string,
  contextDocs: string[]
): Anthropic.MessageParam["content"] {
  return [
    {
      type: "text",
      text: baseInstructions,
      cache_control: { type: "ephemeral" }, // キャッシュマーク
    },
    ...contextDocs.map((doc) => ({
      type: "text" as const,
      text: doc,
      cache_control: { type: "ephemeral" as const },
    })),
  ];
}
 
// 実際の呼び出し例
async function callWithCache(userPrompt: string): Promise<string> {
  const cachedSystem = buildCachedSystemPrompt(
    "あなたは法律専門家AIアシスタントです。以下の法律文書に基づいて回答してください。",
    [longLegalDocument1, longLegalDocument2] // 各5,000トークン規模の文書
  );
 
  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    system: cachedSystem as Anthropic.TextBlockParam[],
    messages: [{ role: "user", content: userPrompt }],
  });
 
  // cache_read_input_tokens が増えているか確認
  const usage = response.usage as Anthropic.Usage & {
    cache_read_input_tokens?: number;
    cache_creation_input_tokens?: number;
  };
  console.log("Cache hit tokens:", usage.cache_read_input_tokens ?? 0);
 
  return (response.content[0] as { type: "text"; text: string }).text;
}

同じシステムプロンプト(10,000トークン)を月に10万回呼ぶケースで試算します:

  • キャッシュなし: 10,000トークン × 10万回 × $3/100万 = $30,000/月
  • キャッシュあり: 10,000トークン × $3/100万(初回キャッシュ作成)+ 10,000トークン × 10万回 × $0.30/100万(キャッシュ読み込み = 1/10コスト)= $3,000/月(90%削減)

モデル切替とキャッシングを組み合わせると、削減率は積算します。

よくある間違いと落とし穴

間違い①:分類にSonnetを使う

モデル分類のためのLLM呼び出しにSonnetを使っているサービスを見ることがあります。分類は短い入力で十分機能するため、常にHaikuを使いましょう。分類コスト自体が無視できるレベルになります。

間違い②:Opus の品質が「常に」必要だと思い込む

Opusは確かに最高品質ですが、「チャットの返答」や「定型フォームへの入力」においてSonnetとの体感差はほぼありません。ユーザーが本当にOpusを必要とするのは複雑な推論・専門判断が求められる場面だけです。「とりあえずOpus」はAPI費用を10〜20倍に膨らませます。

間違い③:品質評価スコアを信頼しすぎる

Haikuによる品質評価は参考値に留めてください。評価自体の精度に限界があり、誤って品質が低いと判定されたレスポンスがOpusに流れることで、逆にコストが増える可能性があります。重要タスクのみに品質チェックを適用し、しきい値は慎重に設定しましょう。

間違い④:モデル変更のたびにコード全体を修正する

モデル名を直接各APIコールにハードコードすると、Anthropicが新モデルをリリースするたびに大規模な修正が必要になります。ルーティングテーブルを一箇所に集約し、定数として管理することで、変更を1行で完結させられます。

間違い⑤:ストリーミング時にコストを過小報告する

ストリーミングを使う場合、接続が途中で切れると usage の取得ができないことがあります。必ずストリーム完了イベント(message_stop)後にトークン数を取得し、DBに保存してからStripeへ報告する設計にしましょう。

本番環境でのモニタリング設計

モデル切替を入れると「なぜこのレスポンスはHaikuだったのか」をデバッグできる仕組みが重要です。

// 全リクエストに routing_reason を付与してDB保存
interface UsageLog {
  userId: string;
  requestId: string;
  timestamp: Date;
  taskType: string;
  modelUsed: ClaudeModel;
  routingReason: "rule_based" | "llm_classified" | "quality_fallback";
  inputTokens: number;
  outputTokens: number;
  costUsd: number;
  qualityScore?: number;
  fallbackUsed: boolean;
}
 
// 週次でこのログを集計し、以下を確認する:
// - モデル別リクエスト割合(目標: Haiku 60-70% / Sonnet 25-35% / Opus 5-10%)
// - Fallback率(5%超なら品質しきい値を下げる)
// - コスト/リクエスト(対前週比で増減確認)

私のサービスでは週次レポートを自動生成し、Haiku比率が60%を下回ったらSlack通知するようにしています。比率が崩れると費用構造が大きく変わるため、早期に気づく仕組みが必要です。

実際の利益率への影響

モデル切替の導入前後を比較した実数字(ある月の実績)を公開します(スケールは仮名義に変換)。

  • 月間リクエスト数: 200万件
  • 導入前(Sonnet一択): API費用 $1,200/月
  • 導入後(Haiku 68% / Sonnet 28% / Opus 4%): API費用 $440/月
  • 削減額: $760/月(約63%削減)
  • 品質関連のサポートチケット増加: 0件(ユーザー体感への影響なし)

Haiku比率68%というのは最初は不安でしたが、分類系・要約系・FAQ系のタスクが多いサービス構造ではこの比率は十分現実的です。

「モデル切替を入れたら品質が下がってユーザーが離れた」という失敗は、分類設計が甘い場合に起きます。ルーティングテーブルの設計に最初の1〜2週間をしっかりかけ、本番投入前に各タスクタイプで100件程度のサンプル評価を行うことをお勧めします。

Stripe Metered Billingとの連携設計についてはClaude APIの従量課金サービスをStripe Metered Billingで設計するを、コスト追跡のインフラ構築についてはClaude APIのプロンプトキャッシングでトークン費用を半減させるも参考にしてください。

全体を振り返って:実装の優先順位

モデル切替を導入する際の推奨ステップは以下の通りです。

  1. 既存リクエストのログからタスクタイプ分布を調査する(何が多いか把握)
  2. ルーティングテーブルの初版を設計し、各タイプのサンプルで品質確認
  3. Haiku比率50%からスタートして様子を見る(いきなり70%を目指さない)
  4. 品質フォールバック機能を入れてOpusを安全網にする
  5. 週次コストモニタリングを自動化する

Claude APIで収益サービスを運営するなら、モデル切替は「やるかどうか」ではなく「いつやるか」の問題だと思っています。スケールするほど効果が大きく、一度設計を固めれば保守コストもほとんどかかりません。

同じ課題に取り組んでいる個人開発者の参考になれば嬉しいです。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API & SDK2026-05-25
二段構えのモデル構成 — Haiku 4.5 オーケストレーター × Opus 4.6 ワーカーで保つコストと品質の均衡
Haiku 4.5 にオーケストレーション、Opus 4.6 に専門タスクを任せる二段構えで、個人開発のコストを月単位で抑えながら出力品質を維持するための実装パターンと実コストの記録です。
API & SDK2026-07-13
Claude API の同時実行を束ねる — シングルフライトで重複推論とキャッシュ・スタンピードを防ぐ
同一プロンプトが同時に何度も Claude へ飛ぶ重複推論を、シングルフライト(request coalescing)で束ねる設計です。プロセス内・分散環境の実装、ジッター付きリトライ、負のキャッシュまで実測付きでまとめました。
API & SDK2026-06-29
Claude API の Context Editing を入れたらエージェントが同じ調査を繰り返したとき — クリア境界とキャッシュ無効化を計測する運用メモ
Context Editing でツール結果を自動クリアしたら、エージェントが直前に読んだ内容を忘れて同じツールを呼び直し、キャッシュも毎回壊れてコストが上がった。沈黙する劣化を計測ログで切り分け、trigger・keep・clear_at_least を実測で決める運用メモです。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →