GEMINI LABEN
NANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定ですNANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定です
記事一覧/API / SDK
API / SDK/2026-05-03中級

Gemini APIで突然の「RECITATION」エラー — 著作権ブロックの正体と回避法

Gemini APIが応答を途中でカットして finish_reason に RECITATION を返すエラーの原因と、再現性のある回避策を実装パターン付きで解説します。

gemini-api279troubleshooting57finish-reason3recitationerror-handling8

Gemini API を本番投入してしばらくすると、必ずどこかで遭遇するのが「途中で文章が切れている」「応答が空で返ってくる」という症状です。そして candidates の finish_reason を見ると RECITATION という見慣れない値が入っています。エラーメッセージも出ず、リクエストは HTTP 200 で成功しているように見えます。これは私自身、社内向けナレッジベースを Gemini で組んでいたときに最初にハマったポイントでした。

このエラーは「セーフティフィルター」とも違い、量のチェックでも、トークン超過でもありません。Gemini が「自分の応答が著作権で保護されたコンテンツに似すぎている」と自己判定した時に発火する、独立した中断シグナルです。今回はこの RECITATION の正体と、現場で使える回避パターンを整理します。

RECITATION が発火する具体的な条件

公式ドキュメントには「学習データの一部を逐語的に再生しそうになった場合に停止する」と書かれていますが、実装上のトリガーはもう少し具体的です。私が観測した範囲では、以下のパターンで再現性が高いです。

  • 既存の歌詞・詩・有名スピーチ・聖書の節などを「そのまま」または「ごく軽い改変で」生成しようとした場合
  • 公開リポジトリで広く知られた OSS のコード(よくある useEffect サンプル、TensorFlow チュートリアル等)をそのまま再生成しようとした場合
  • レシピ本・教科書・公式ドキュメントの定型表現を、原文に近い構造で要約させた場合
  • ユーザーの入力プロンプト自体が長く、その中に著作物が含まれていてモデルがそれを反復しようとした場合

つまり「Gemini が学習データから直接コピーしているように見える」と内部判定された瞬間に、応答ストリームが切られます。SAFETY のように完全ブロックされて空応答になることもあれば、生成途中で打ち切られて 400〜800 文字くらいで止まることもあります。

まず最初に確認すべきレスポンス構造

エラーハンドリングの第一歩は、finish_reason を見落とさないコードを書くことです。多くのチュートリアルが response.text だけを読んでいますが、これだと RECITATION 発生時に「短い応答」と「正常終了」を区別できません。

# Python (google-genai SDK) - finish_reason を必ず検査するパターン
from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
response = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="ここにプロンプト",
    config=types.GenerateContentConfig(
        temperature=0.7,
        max_output_tokens=2048,
    ),
)
 
# 必ず candidates と finish_reason を検査する
if not response.candidates:
    raise RuntimeError("候補が空です。プロンプトブロックを確認してください。")
 
candidate = response.candidates[0]
finish_reason = candidate.finish_reason  # "STOP" / "RECITATION" / "SAFETY" / "MAX_TOKENS" など
 
if finish_reason == "RECITATION":
    # 著作権類似ブロック発生 — 後述のリトライ戦略へ
    print("⚠️ RECITATION で中断。テキストは:", candidate.content.parts[0].text if candidate.content else "(空)")
elif finish_reason == "SAFETY":
    print("⚠️ セーフティフィルターでブロック")
elif finish_reason == "STOP":
    print("✅ 正常終了:", response.text)
else:
    print(f"その他の中断: {finish_reason}")

ポイントは finish_reason == "STOP" のときだけを「成功」とみなし、それ以外は全て個別に処理することです。response.text は RECITATION のとき例外を投げるか空文字を返すかが SDK バージョンで揺れるため、テキスト取得は candidate.content.parts[0].text 経由が安全です。

回避パターン1: プロンプトを「変換タスク」に書き換える

最も効果が高いのは、生成タスクを「自由記述」から「変換・要約・分析」にシフトすることです。Gemini は入力に対する変換タスクでは RECITATION が起きにくく、ゼロからの生成(特に「〜の歌詞を書いて」「有名な〜を再現して」)で起きやすい傾向があります。

# ❌ RECITATION を誘発しやすいプロンプト
bad_prompt = "クリスマスキャロル風の歌詞を書いてください。"
 
# ✅ 変換タスクとして書き直す
good_prompt = """次の要素を踏まえて、完全にオリジナルの歌詞を作成してください。
既存の楽曲・童謡・讃美歌の歌詞は一切流用せず、独自の語彙と比喩で書いてください。
 
テーマ: 雪の朝の家族の温もり
構造: 4行 × 4ブロック
韻: ABAB
"""

「既存の歌詞を流用しない」「独自の語彙で」と明示的に指示するだけで、再生成の確率が大きく下がります。これは Gemini が「指示への忠実度」を出力選択時に重視するためです。

回避パターン2: temperature を上げて経路をずらす

RECITATION は出力分布の最尤経路(temperature=0 付近)で発生しやすい現象です。温度を上げて少しランダム性を与えると、学習データそのものの再現を避けながら同等の品質を出せることが多いです。

ただし「温度を上げれば直る」という単純な話ではありません。私の検証では、temperature=0.0〜0.3 で発生していたケースを 0.7 に変えるだけで解消したパターンが多数ありました。一方、temperature=1.0 以上は応答品質が落ちるので、0.6〜0.8 を最初に試すのが実用的です。具体的なプロンプトチューニングのコツについては、Gemini API のセーフティフィルターブロック対応ガイド も合わせて参照すると、ブロック系エラー全般の理解が深まります。

回避パターン3: リトライ + プロンプト書き換えの自動化

本番環境では、RECITATION が発生したら自動でプロンプトを書き換えてリトライする層を入れておくと安心です。ナイーブな実装だと無限ループになるので、最大試行回数を切ってフォールバックを用意します。

# Production-ready: RECITATION 検知 → プロンプト変換リトライ
def generate_with_recitation_recovery(client, model, original_prompt, max_retries=3):
    """RECITATION 発生時にプロンプトを段階的に変換してリトライする。"""
    prompts = [
        original_prompt,
        f"{original_prompt}\n\n注: 既存の作品の文言を一切引用せず、完全にオリジナルの表現で書いてください。",
        f"以下の要件を独自の言葉で達成してください。既存の歌詞・コード・文章の引用は禁止します。\n要件: {original_prompt}",
    ]
 
    for attempt, prompt in enumerate(prompts[:max_retries]):
        response = client.models.generate_content(
            model=model,
            contents=prompt,
            config=types.GenerateContentConfig(
                temperature=0.7 + 0.1 * attempt,  # リトライごとに温度を少し上げる
                max_output_tokens=2048,
            ),
        )
        if not response.candidates:
            continue
        finish_reason = response.candidates[0].finish_reason
        if finish_reason == "STOP":
            return response.text
        if finish_reason != "RECITATION":
            # SAFETY などはリトライしても解消しないので即座に上に返す
            raise RuntimeError(f"非リトライ可能な中断: {finish_reason}")
 
    # 3回試して全て RECITATION ならフォールバック
    raise RuntimeError("RECITATION から復帰できませんでした。プロンプト設計を見直してください。")

このパターンは、エラー処理全般のリトライ戦略の応用です。指数バックオフを含めた網羅的な実装は Gemini API のリトライパターン解説 にまとめてあるので、本番運用ではそちらと組み合わせて使ってください。

RECITATION と「空応答」の見分け方

現場でよく混同されるのが「empty response」と「RECITATION」です。両者は対処が全く違うので、ログ層で必ず区別しておきます。

  • finish_reason == "STOP" で text が空 → 正常応答だが内容が無いケース。プロンプトが曖昧、または max_output_tokens が極端に小さい
  • finish_reason == "MAX_TOKENS" → 出力トークン上限切れ。max_output_tokens を上げる
  • finish_reason == "SAFETY" → セーフティフィルター。カテゴリと閾値を調整
  • finish_reason == "RECITATION" → 本記事の対象。プロンプト書き換え + 温度調整

詳しい原因切り分けは Gemini API の空応答・finish_reason 対応ガイド も参考になります。エラーごとの典型的なシグナルを覚えておくと、ログを見た瞬間に対応の当たりが付きます。

設計レベルでの予防策

最後に、RECITATION を「事故」ではなく「想定内」として扱うための設計指針を3つ挙げます。

ひとつ目は、ユーザー入力に著作物が含まれる前提でバリデーションを入れること。たとえばチャットボットに「歌詞を翻訳して」と入力された場合、その翻訳出力自体が RECITATION でブロックされる可能性が高いです。あらかじめ「著作物の翻訳・要約はサポート外」と仕様で切ってしまうのが安全です。

ふたつ目は、コード生成タスクでは「テンプレートを示して埋めさせる」スタイルを採ること。フリーフォームで「Reactのフォームコンポーネントを書いて」と依頼するより、骨格となる関数シグネチャと型を渡してから埋めさせる方が、よくある OSS パターンとの完全一致を避けやすくなります。

みっつ目は、観測可能性の確保です。finish_reason を構造化ログに必ず吐き、Datadog や Cloud Logging で集計できるようにしておくと、本番投入後に RECITATION の発生率が見えます。経験則として、RECITATION 率が全リクエストの 1% を超えてきたらプロンプト設計の見直しサインです。

まずは観測ログを仕込むところから

RECITATION は「珍しいエラー」ではなく「Gemini を本番で使うなら必ず遭遇する中断シグナル」です。今日からできる最小の一歩は、既存コードの response.text の前に finish_reason をログ出力する1行を足すことです。それだけで、これまで「たまに応答が短い」と思っていた事象の正体が見え始めるはずです。

アプリ運用で見えてきた、Gemini API の使いどころ

シェア

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

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

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

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

関連記事

API / SDK2026-06-12
Gemini API の空応答を finish_reason から逆引きする — 診断フロー・再試行分類・監視の実務
response.text が空になる問題は candidates・prompt_feedback・finish_reason の3層で診断できます。思考トークンによる出力枯渇の検出、再試行可否の分類器、空応答率の監視まで、本番で運用している実装をまとめました。
API / SDK2026-06-14
Gemini API の本文が途中で切れる — finish_reason: MAX_TOKENS を検知して続きを継ぎ直す実装メモ
長文生成で末尾が文の途中でぷつりと切れる。原因の多くは finish_reason: MAX_TOKENS です。例外も 200 のまま静かに混入するこの事故を検知し、続きを継ぎ足して全文を取り戻す実装を、思考トークンの落とし穴とあわせてまとめました。
API / SDK2026-05-12
Gemini File APIのファイルが「PROCESSING」のまま止まる:タイムアウト処理とリトライ設計
Gemini File APIでアップロードしたファイルがPROCESSING状態のまま進まない問題を解説。ポーリングの正しい実装・タイムアウト設計・失敗時のクリーンアップまで、実際のコードで解決します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →