8月13日に Gemini 3.7 Flash が一般提供になった日、私は自分のパイプラインの設定ファイルを開いて、そのまま10分ほど何も打てずにいました。
書き換える行そのものは一行です。モデル名の文字列を差し替えるだけで済みます。
止まったのは、その一行を書き換えてよいかどうかを判断する材料を、自分が毎回ゼロから組み直していることに気づいたからでした。
新しいモデルが出るたび、同じところで手が止まります
私は個人開発で4つの技術ブログと、いくつかのアプリを運用しています。Gemini API はその両方で、下訳・分類・要約といった地味な工程に入っています。
この一年、モデルの世代交代は数えるのが面倒なくらい起きました。そのたびに私がやっていたのは、ベンチマークの表を眺めて「たぶん大丈夫だろう」と判断することでした。
判断としては、あまり良くありません。ベンチマークが測っているのは平均的な賢さであって、私の工程で起きる失敗の性質ではないからです。
実際に困ったのは、賢くないモデルが平凡な答えを返したときではありませんでした。それなりに整った、しかし事実として違う答えが返ってきて、それが誰にも気づかれずに次の工程へ流れたときです。
私が最後に見ているのは「間違いを機械で拾えるか」です
そこで判断基準を一つに絞りました。その工程の出力が間違っていたとき、人間が読む前に機械で弾けるかどうかです。
弾ける工程は、速くて安いモデルに任せて構いません。誤りが混ざる確率が多少上がっても、ゲートが落として再試行するだけで済むからです。追加で払うのは呼び出し1回分のコストであり、私の時間ではありません。
弾けない工程は、そうはいきません。誤りが通ってしまえば、気づくのは公開後です。修正には記事の差し替え、キャッシュの無効化、場合によっては謝罪が伴います。ここで節約した数セントは、あとから何時間にも化けます。
言い換えると、モデル選定は精度の問題ではなく、やり直しの費用を誰が負担するかの問題として扱えます。機械が負担できるなら Flash、自分が負担することになるなら Pro、という単純な線引きです。
私の手元の工程を、この基準で並べ直すとこうなりました。
| 工程 | 誤りの検出手段 | 置いたモデル |
|---|---|---|
| 記事のタグ候補を出す | 既存タグ辞書との突き合わせ(自動) | 3.7 Flash |
| Google Play のストア説明文の翻訳下訳 | 文字数上限・禁止語リスト(自動)+最終目視 | 3.7 Flash |
| レビュー本文の感情分類 | スキーマ検証と列挙値チェック(自動) | 3.7 Flash |
| 技術的な主張の妥当性判断 | 自動化できない | 3.1 Pro |
| コード例の設計方針を決める | 自動化できない | 3.1 Pro |
上3つは、出力が壊れていれば必ず機械が気づきます。下2つは、もっともらしい間違いをそのまま受け取ってしまいます。
機械で拾える工程は、ゲートとセットで置きます
Flash 側に置くと決めた工程は、必ず検証を書いてから移します。順番が逆になると、安くなった実感だけが先に来て、精度の劣化に気づくのが遅れます。
分類工程の実装はこうしています。スキーマで形を縛り、列挙値の範囲外を落とし、落ちたものだけを上位モデルへ回す形です。
import json
from google import genai
from google.genai import types
client = genai.Client(api_key="YOUR_API_KEY")
ALLOWED = {"bug", "feature_request", "praise", "pricing", "other"}
SCHEMA = {
"type": "object",
"properties": {
"label": {"type": "string", "enum": sorted(ALLOWED)},
"confidence": {"type": "number"},
},
"required": ["label", "confidence"],
}
def classify(text: str, model: str = "gemini-3.7-flash") -> dict:
response = client.models.generate_content(
model=model,
contents=f"次のレビューを分類してください。\n\n{text}",
config=types.GenerateContentConfig(
response_mime_type="application/json",
response_schema=SCHEMA,
),
)
return json.loads(response.text)
def classify_with_gate(text: str) -> dict:
result = classify(text)
# ゲート: 列挙値の範囲外と、自信の低い判定だけを上位モデルへ回す
if result["label"] not in ALLOWED or result["confidence"] < 0.6:
return classify(text, model="gemini-3.1-pro")
return resultconfidence の閾値は自分の工程で決める値です。私は最初 0.8 で始めて、Pro へ回る割合が全体の3割を超えたので 0.6 まで下げました。ここを高くしすぎると、安いモデルを入れた意味がなくなります。
一つ補足しておきます。以前のコードでは temperature を 0.1 のように固定して出力のばらつきを抑えていましたが、temperature・top_p・top_k は7月21日に非推奨となりました。まだ動くうちに、指定を外した状態で同じ入力を何度か流し、出力がどれだけ揺れるかを見ておくと、実際に効かなくなったときに慌てずに済みます。
人の目にしか映らない工程は、当面 Pro に残します
残りの2工程は、3.7 Flash がどれだけ速くても移していません。速度が足りないからではなく、間違ったときに私が全額を払うからです。
技術的な主張の妥当性判断がその典型です。「この API はこう振る舞う」という一文は、文章としては何の問題もなく通ってしまいます。しかし事実として違えば、それを読んだ人が自分のコードで何時間か溶かします。ここを自動化する検証手段を、私はまだ持てていません。
3.7 Flash はソフトウェア工学やエージェント的なワークフローで大きく改善したと案内されています。それは疑っていません。ただ、私が Pro を残しているのは能力の上下ではなく、失敗の後始末を誰がするかという一点です。
thinking レベルが low / medium / high の3段階で選べるようになったことで、この線引きはもう少し細かく引けるようになりました。Flash に置いたまま thinking を上げて様子を見る、という中間の選択肢が取れます。まず high で移してみて、ゲートの落ち方が変わらなければ段階的に下げる、という順序が安全です。
値段を根拠にするなら、12月31日をまたいで計算します
「Flash のほうが安いから」という理由づけには、期限が付いています。Gemini 3.7 Flash の導入価格は入力100万トークンあたり $0.75、出力 $3.75 で、2026年12月31日までです。翌日からは $1.50 / $7.50 になります。
つまり単価が倍になります。今の請求額を見て「この規模なら余裕がある」と判断していると、年明けに前提が変わります。
自分の呼び出し量を当てはめて、両方の単価で出しておくのが確実です。1日あたりの呼び出し回数と、1回あたりの入出力トークン数から計算した例を置いておきます。
| 規模(1日あたり) | 導入価格での月額 | 2027年以降の月額 | 年間の差額 |
|---|---|---|---|
| 50回(入力4,000 / 出力800) | $9.00 | $18.00 | $108.00 |
| 300回(入力8,000 / 出力1,200) | $94.50 | $189.00 | $1,134.00 |
| 1,500回(入力12,000 / 出力2,000) | $742.50 | $1,485.00 | $8,910.00 |
小規模なら年間 $108 の増加で、これは判断を揺るがす額ではありません。中規模を超えたあたりから、話が変わってきます。
差額の吸収先まで含めた設計は、Gemini 3.7 Flash の値上げ分は、バッチ層へ移すとちょうど相殺されますで、価格表の切り分けから年明けの請求試算まで扱っています。急ぎでない処理をどこまで後ろへ倒せるかは、規模が大きいほど効いてきます。
次にやること
設定ファイルを開いて、モデル名が書かれている箇所を数えてください。そして各箇所に一つだけ問いを立てます。ここの出力が間違っていたとき、それに最初に気づくのは機械か、自分か。
答えが「機械」なら、その行は速いモデルへ動かせます。答えが「自分」なら、今は動かさないほうが安く済みます。私の場合、この問いだけで5箇所のうち3箇所が片付きました。
私自身、まだ手探りで基準を組み替えている最中です。お読みいただきありがとうございました。