ある朝、Anthropic の利用明細を眺めながら、ふと「これ、全部 Opus に投げる必要は本当にあるのか」と立ち止まったことがあります。アーティスト・クリエイターの廣川政樹です。2014年から個人でアプリ開発を続けて累計5,000万ダウンロードを超え、現在は Claude API を組み込んだ自動化パイプラインを4サイト並行で動かしています。その月の請求書を見て、出力1トークンあたりのコスト差をようやく実感の伴う数字として受け止めることができました。
ここで扱う「二段構え」は、Haiku 4.5 をオーケストレーター(指揮役)に置き、Opus 4.6 をワーカー(専門役)として呼ぶ構成です。安いモデルが上に立ち、必要なときだけ高価なモデルを呼ぶ。一見すると逆では、と思われるかもしれませんが、私の運用ではこの並びが結果として最も読み筋が安定しました。ここから先は、実コストの数字、判定基準、コード、そして実装中に詰まったいくつかの場面を順に整理していきます。
なぜオーケストレーターを Haiku に置くのか
ナチュラルな発想は「賢いモデルにルーティングさせて、安いモデルに作業させる」だと思います。私も最初はそうしていました。ところが Opus 4.6 にルーティング判定をさせると、判断の遅さと API 単価の二重の重さが効いてきて、入力 1M トークン換算で見ると指揮役のコストが本体作業を上回る場面が増えていきました。
オーケストレーション側の仕事は、実は「短い文脈で、JSON を返す」という制約の強い作業です。文章を生成する力よりも、構造化された出力が安定して返ってくることのほうが重要になります。Haiku 4.5 は短文の構造化出力で十分な精度を出してくれるため、ここでは Haiku のほうが用途に合っています。むしろ Opus は、長い文脈を抱えて創造的に書き下ろす、あるいは複雑な推論を逐次的に重ねる場面で本領を発揮します。
私はこれを、宮大工だった両家の祖父の仕事の流儀になぞらえて考えています。墨付けをする職人と、削り出す職人は別の人がやるほうが速い。判断の道具と、作業の道具は別物として持っておいたほうが、最終的な仕上がりは安定する。そういう感覚に近いです。
実コストの内訳 — 1Mトークンあたりで比較する
API 料金は変動するため、ここでは2026年5月時点の参考値で計算します。あくまで内部の運用ログから抽出した数字であり、各位の運用環境では別途検証してください。
入力1Mトークンあたりの参考コストを、私の運用パイプラインで実測した内訳と合わせて並べると次のようになります。
Opus 4.6 単独構成: 入出力合算で約 $15.00 / 1M(出力比率が大きいタスクほど上振れ)
Sonnet 4.6 単独構成: 約 $3.00 / 1M
Haiku 4.5 単独構成: 約 $0.80 / 1M
二段構成(Haiku オーケストレーター + 30% Opus 呼び出し): 約 $4.50 / 1M
二段構成で 30% という数字は、私のブログ自動生成パイプラインで、実際に Opus にエスカレーションされるタスクの比率を 100記事分のログから測ったものです。残り 70% は Haiku がそのまま処理する、あるいはツール呼び出しを通じて軽量な後段に流すだけで完結します。
結果として、Opus 単独に比べて月額換算で 70% 程度のコスト圧縮になりました。前年の同月、つまり Opus を中心に組んでいた頃と並べると、原稿1本あたりの API コストが約3分の1に落ち、メンバーシップ事業(Stripe で Pro ¥580 / Premium ¥2,480)の粗利が初めて安定して黒字に振れたタイミングがちょうどこの再構成と重なっています。
数値だけ見ると「Haiku 単独でいいのでは」と思われるかもしれません。実際に試したのですが、私の用途では出力品質の差が無視できませんでした。本文の論理展開、コード例のニュアンス、見出しの選び方など、読者の課題に寄り添う細部で Opus の出力がやはり一段抜けていて、メンバーシップ価値を維持するためには、ここを Haiku に統一しないほうが妥当だと判断しています。
何をワーカーに任せるか — 5つの判定基準
Haiku から Opus を呼び出す判断は、何となく「難しそうだから Opus」では再現性がありません。私の運用では、ルーティング層のプロンプトに次の5つの基準を明示的に書き込み、JSON で出力させています。
出力長が 2,000 トークンを超える見込みか
5ホップ以上の論理連鎖を要するか
政樹さん個人の文体・体験を強く反映する必要があるか
既存記事と類似度が高く、差別化が必要か
長く参照される技術的判断(アーキテクチャ選択など)を含むか
このうち2つ以上が true の場合のみ Opus に回し、それ以外は Haiku の継続出力で完結させます。実装の中核を抜粋すると次のようになります。
import os
import json
from anthropic import Anthropic
client = Anthropic( api_key = os.environ[ "ANTHROPIC_API_KEY" ])
ROUTER_SYSTEM = """あなたはオーケストレーターです。タスク仕様を受け取り、
Opus 4.6 に処理を委譲すべきかを判定して JSON のみで返してください。
判定基準は次の通りです。
- output_long: 出力 2000 token を超える見込み
- multi_hop: 5 ホップ以上の論理連鎖が必要
- author_voice: 強い個人体験/文体の再現が必須
- differentiation: 類似既存記事との差別化が必要
- architecture: 長く参照されるアーキテクチャ判断を含む
2 つ以上が true なら escalate=true。
出力スキーマ:
{
"output_long": bool,
"multi_hop": bool,
"author_voice": bool,
"differentiation": bool,
"architecture": bool,
"escalate": bool,
"reason": "短い日本語の根拠"
}
"""
def route (task_spec: dict ) -> dict :
response = client.messages.create(
model = "claude-haiku-4-5-20251001" ,
max_tokens = 400 ,
system = ROUTER_SYSTEM ,
messages = [{
"role" : "user" ,
"content" : json.dumps(task_spec, ensure_ascii = False )
}]
)
raw = response.content[ 0 ].text
return json.loads(raw)
ポイントは、ルーター側で max_tokens=400 と短く絞り、出力フォーマットを JSON に固定していることです。Haiku 4.5 は短い構造化出力が安定して速いため、ここで余計な前置きを書かれないようにシステムプロンプトで制約しておきます。私の運用では、ルーティング判定の平均レイテンシが 1.2秒、コストが1判定あたり約 $0.0006 に収まっています。
ワーカー側の起動と結果の取り回し
ルーターが escalate=true を返した場合のみ Opus 4.6 を起動します。ここで重要なのは、Opus に渡す入力を「ルーターの判断ログ + 元のタスク仕様」の2層構造にしておくことです。これにより、Opus 側が「なぜ自分が呼ばれたか」を文脈として理解し、より深く踏み込んだ出力を返してくれるようになります。
def delegate (task_spec: dict , routing: dict ) -> str :
if not routing[ "escalate" ]:
return run_haiku_inline(task_spec)
response = client.messages.create(
model = "claude-opus-4-6" ,
max_tokens = 8000 ,
system = (
"あなたは熟練ライターです。前段のルーターが以下の理由であなたに"
"処理を委譲しました: "
f " { routing[ 'reason' ] }\n "
"この理由に応じて、長文・論理連鎖・個人体験の反映を意識して"
"原稿を作成してください。"
),
messages = [{
"role" : "user" ,
"content" : build_prompt(task_spec)
}]
)
return response.content[ 0 ].text
実装当初、私はこの「ルーターの理由を Opus に渡す」工夫を入れていませんでした。当時の Opus は呼び出されると確かに高品質な出力を返してきましたが、ルーターの基準と微妙にずれた書き方をすることがあり、後段の品質ゲート(CLAUDE.md で運用している article_gate.py)で違反検出されて差し戻しになる頻度が無視できませんでした。
ルーター理由を渡すように変えてから、Opus 出力の品質ゲート一発通過率が 62% から 84% まで改善しました。これは月単位では「再生成のための追加課金」が大きく減るということで、コスト最適化の観点でも見過ごせない差です。
ストリーミングとブロッキングの使い分け
ルーター層は短い JSON 応答を返すだけなので、ストリーミングを使う旨味は薄いです。1.2秒のレイテンシをさらに削るより、レスポンス全体を受け取ってから JSON パースに進むほうが、エラーハンドリングがシンプルになります。
一方で Opus 側はストリーミングを積極的に使います。本文生成では5,000〜8,000 トークンの出力が普通で、最初の数十トークンを受け取った時点で品質ゲート相当のキーワード検査を回し、明らかな違反パターン(テンプレート導入文、禁止語句、自慢調のタイトル)が混入していたら早期に abort する設計にしました。
def stream_with_early_abort (prompt: str , banned: list[ str ]) -> str :
buffer = []
with client.messages.stream(
model = "claude-opus-4-6" ,
max_tokens = 8000 ,
messages = [{ "role" : "user" , "content" : prompt}],
) as stream:
for text in stream.text_stream:
buffer.append(text)
joined = "" .join(buffer)
for word in banned:
if word in joined:
raise EarlyAbort(word)
if len (joined) > 600 and looks_like_template_intro(joined):
raise EarlyAbort( "template_intro" )
return "" .join(buffer)
この早期 abort は、Opus 出力の品質ゲート一発通過率を上げると同時に、無駄なトークン課金を防ぐ効果がありました。実測で、abort が発火した記事1本あたり 3,500 トークン程度の節約になり、月単位では 5〜8% のコスト削減につながっています。
ハイブリッド構成で詰まった3つの落とし穴
理屈はきれいに整理できるのですが、実運用に乗せると思わぬ場所で詰まりました。同じ構成を採用する方のために、私が経験した3つを書き残しておきます。
1. ルーターが「全部 escalate=true」に寄ってしまう問題
最初の2週間、Haiku ルーターはほぼ全リクエストを Opus にエスカレーションしました。原因は、システムプロンプトに「迷ったら escalate=true」と書いていたことです。Haiku は迷うのが上手な性格のモデルなので、この一文があると全部 true に寄せます。
修正後は「迷ったら escalate=false。Haiku 自身で処理して構わない」と明示し、5基準の判定を「2つ以上 true」と数値化しました。これでエスカレーション率が 92% から 30% 前後に落ち、本来の二段構成として機能し始めました。
2. キャッシュキーの衝突によるレイテンシ悪化
Opus 側で prompt caching を効かせていたのですが、システムプロンプトに「ルーター判断ログ」を入れたことでキャッシュキーが毎回変わり、キャッシュ命中率がほぼゼロまで落ちました。実測でレイテンシが平均 4.8秒から 11.3秒まで悪化しました。
対処として、ルーター判断ログは messages 側に入れ、システムプロンプトは固定文字列を保ちました。ephemeral cache breakpoint をシステムプロンプト末尾に置き、cache_control を明示することで命中率は 78% まで戻り、レイテンシも 5.2秒前後に収まりました。
3. 二段ロギングがログ容量を圧迫する
ルーターと Opus の両方のレスポンスをそのまま保存していたら、月次のログ容量が前年比 2.4倍に膨らみました。Cloudflare R2 のストレージコストが意外に効いてくる規模です。
対処として、ルーターのフルレスポンスは保存せず、escalate / reason の2フィールドだけを残し、本体は Opus の出力に絞りました。デバッグ用にルーター生レスポンスが必要なときは、当日分のみ別のテンポラリ KV に置く構成にしています。これで月次ログ容量を前年並みに戻せました。
採用に至るまでに捨てた3つのアプローチ
二段構成にたどり着く前、私はいくつかの別構成を試して、最終的に捨てました。失敗の記憶は再現性のある教訓になるので、書き残しておきたいと思います。
ひとつめは「Opus 単独 + temperature を下げてコスト圧縮」というアプローチでした。出力を短くしてトークン消費を抑える発想です。実際に temperature を 0.2 まで下げると出力長は確かに 20% 程度減りましたが、表現の幅も同時に痩せ、メンバーシップ価値として読者に提供したい「文体の手触り」が薄くなりました。コストはわずかに下がっても、解約率が前月比で 4 ポイント上がり、結果的に粗利は悪化しました。
ふたつめは「Sonnet 4.6 単独で全タスクを処理」する構成でした。Opus より一桁安く、Haiku より一段賢いという中庸路線です。これは半年ほど採用しましたが、本文の論理連鎖が複雑になる長文タスクで Opus 同等の深さが出ない場面が増え、品質ゲートで差し戻される頻度が上がりました。月次の再生成課金が積み上がり、結果として Opus を一切使わない月のほうがコスト総額が高くなる、という逆転が起きてしまったのです。
みっつめは「ルーター層を別アプリケーションに分離して Cloudflare Workers 上で動かす」構成でした。ルーティング判定はステートレスなので、Workers の Edge ロケーションで動かせばレイテンシをさらに削れるはず、という設計です。実装してみると確かにルーター単独のレイテンシは 0.4秒まで下がりましたが、Workers の制約(CPU 時間、メモリ)と Anthropic SDK の依存解決が想像以上に厄介で、運用負荷の増加に対してメリットが釣り合いませんでした。今は素直に Python ランタイム上で同居させています。
これらを捨てた経験から学んだのは、コスト最適化を「単価を下げる方向」だけで考えると視野が狭くなる、ということです。再生成課金、運用負荷、解約率といった周辺コストを含めた総コストを最小化する観点で構成を選ぶと、二段構成のような少し回りくどい設計に落ち着きました。
観測すべき指標 — オーケストレーターを健康に保つために
二段構成は「動いている」ことの確認だけでは不十分です。私は次の指標を Grafana で毎日眺めるようにしました。
エスカレーション率(理想は 20〜40%)
ルーター判定の平均レイテンシ
Opus 出力の品質ゲート一発通過率
Opus 入力に占める prompt cache 命中率
1記事あたりの実コスト(Haiku + Opus 合算)
特に「エスカレーション率」は健康指標として大事で、20% を下回ると Haiku 単独で十分なケースが増えている可能性があり、40% を超えると Opus に頼りすぎている可能性があります。私の運用では、月次レビューでこの数値を確認し、ルーターのシステムプロンプトを微調整するというリズムが回っています。
月単位で見る実コスト試算 — 1日10記事を回す場合
抽象的な単価より、自分の運用に当てはめた具体数字のほうが判断しやすいので、私の運用を例に置いて月次のコストを試算してみます。1サイトあたり1日4本、4サイト並行で月当たり概ね 480 本の記事を自動生成する規模を前提にします。
1記事あたりの平均トークン消費は、ルーター入力 1,500、ルーター出力 300、Opus 入力 3,000、Opus 出力 5,000 程度になります。エスカレーション率を 30% と仮定すると、月当たりの消費は次のように積み上がります。
Haiku ルーター入力: 480本 × 1,500 = 720,000 トークン
Haiku ルーター出力: 480本 × 300 = 144,000 トークン
Opus 入力(30%エスカレ): 144本 × 3,000 = 432,000 トークン
Opus 出力(30%エスカレ): 144本 × 5,000 = 720,000 トークン
Haiku 本体処理(70%): 336本 × 4,500 = 1,512,000 トークン
これを単価に当てて加算すると、月次合計で約 $25 前後に収まりました。前年同月、Opus 単独で同規模を回していたときは月 $90 前後でしたから、絶対額にしてざっと月 $65、年間で約 $780 の差です。Stripe 経由のメンバーシップ収益(Pro ¥580 / Premium ¥2,480)と並べて見ると、API コストが粗利を圧迫する度合いがかなり穏やかになりました。
数字を作るときに注意すべきは、エスカレーション率は固定ではなく、シーズンや扱うトピックで揺れるという点です。私の場合、年末年始のセール記事を量産する期間はエスカレーション率が 45% まで上がり、月コストが $35 を超えます。逆にトラブルシューティング型記事を多めに回す月は 18% 程度まで下がり、月 $20 を切ります。月次でこの数字を観察して、ルーター基準を微調整するリズムが運用の核になります。
ロギング設計 — ルーター出力の二次活用
ルーターが返す JSON は、エスカレーション判断のためだけに使うともったいないと感じています。私の運用では、ルーター出力を構造化ログとして Cloudflare D1 に蓄積し、後段の分析に使っています。
import sqlite3
import datetime
def log_routing (task_id: str , task_spec: dict , routing: dict , escalated: bool ):
conn = sqlite3.connect( "routing.db" )
conn.execute(
"""
INSERT INTO routing_log
(task_id, ts, topic, output_long, multi_hop, author_voice,
differentiation, architecture, escalate, reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""" ,
(
task_id,
datetime.datetime.utcnow().isoformat(),
task_spec.get( "topic" , "" ),
int (routing[ "output_long" ]),
int (routing[ "multi_hop" ]),
int (routing[ "author_voice" ]),
int (routing[ "differentiation" ]),
int (routing[ "architecture" ]),
int (escalated),
routing[ "reason" ][: 200 ],
),
)
conn.commit()
このログがあると、月末のレビューで「どの判定軸が最もエスカレーション判断に効いているか」を集計できます。私の運用では、author_voice フラグが立った場合のエスカレーション率は実質 100% に近く、逆に output_long 単独では 32% 程度しか escalate されません。基準ごとの寄与度を測れると、ルーター基準そのものの調整が定量的にできるようになります。
論理連鎖(multi_hop)の判定はとくに難しく、Haiku が誤判定しやすいポイントでもあります。私はここを補強するために、過去30日分の multi_hop=true でエスカレーションされた記事タイトルを、ルーターのシステムプロンプトに数例だけ追記する Few-shot 化を試しました。これにより判定一致率が体感で2割ほど上がっています。
3段構成にする選択肢 — Sonnet 4.6 を挟む場合
ここまでは Haiku と Opus の2段で書いてきましたが、運用が成熟してくると Sonnet 4.6 を中段に挟む「3段構成」も選択肢になります。私の場合、メンバーシップの中核となるプレミアム記事のうち、Opus に丸投げするほど深掘りは不要だが Haiku では物足りない、という中間帯のタスクが見えてきました。
3段構成のルーティング基準は、2段構成の5基準に「output_long」のしきい値を3段化した形で実装しています。たとえば 1,200 トークン以下は Haiku、1,200〜3,500 は Sonnet、3,500 以上は Opus、というふうに段階を切る形です。実コストでは Sonnet 中段が約 $3.00 / 1M、Opus 単独より一桁安いので、ここを上手に使うとさらに月単位で 10〜15% の追加圧縮が見込めます。
ただ、3段にすると保守の負担も上がります。プロンプトのバージョン管理、各段の品質ゲート、エスカレーション率のモニタリングが、それぞれ独立して必要になります。私は最初の半年は2段に絞り、運用が安定して数字に余裕が出てから3段に拡張するほうが、現場の感覚としては無理がないと感じました。
審査基準を持つことの効用 — 17年分のアート活動から
少し技術から離れた話をします。私は2019年に視覚表現を本格化させてから国際芸術賞への応募を重ね、これまでに17の賞をいただいてきました。応募を重ねるなかで痛感したのは、「自分の作品を出すべき公募と、出すべきでない公募の見極め」が、受賞そのものより大切だということでした。
公募によって審査基準はまったく違います。技術的完成度を重視するもの、コンセプトの独自性を見るもの、市場性で測るもの。基準を読まずに闇雲に応募していた頃は、落選を重ねるだけで何も学べませんでした。基準を言語化して持ってから、応募する公募を選び、応募作品を作り分けるようになり、ようやく受賞が積み重なり始めました。
二段構成のルーターを設計しているとき、私はこの感覚を思い出していました。タスクの仕様を見て、どのモデルを呼ぶか判定する作業は、公募の審査基準を読み解く作業ととてもよく似ています。判定軸を言葉として書き出し、判断のたびにそれに照らす。これを続けるかどうかで、6ヶ月後のコスト構造と品質構造が大きく分かれていきます。
オーケストレーターを Haiku に置く選択は、コスト最適化として語られがちですが、私はそれより、自分自身の「判断基準を明文化する習慣」を運用に組み込めることのほうが本質的な価値だと考えています。
どこから始めるか
これから二段構成を試す方には、いきなり全タスクに導入するのではなく、次の順序で段階的に切り替えることをお勧めします。
既存パイプラインのうち、定型的な分類タスク(タグ付け、カテゴリ判定、メタデータ抽出)を1つ選び、まず Haiku 単独に置き換える
出力品質が落ちないことを2週間モニターする
出力品質に揺らぎが出るタスク(本文生成、コード生成)に対して、ルーター層を挟む
エスカレーション率が想定範囲(20〜40%)に収まるまでシステムプロンプトを微調整する
prompt caching の命中率を高めるため、キャッシュ可能な前段を切り出す
私自身、4サイト並行運用の中でこの順序を守れたわけではなく、いきなりルーターを差し込んで上記の落とし穴に全部踏みました。だからこそ、これから取り組まれる方には、もう少し穏やかな入り方をお勧めしたいのです。
二段構成の本当の価値は、コストが下がることそのものより、判断の道具と作業の道具が分かれることで、ふだん見えにくかった「判断の質」を別軸で測れるようになることだと感じています。請求書の数字に追われる前に、まず Haiku を判断に置く一歩から始めてみてください。同じ課題に取り組んでいる方の参考になれば幸いです。