アルアカ - Arcadia Academia

Arcadia Academiaは「エンジニアリングを楽しむ」を合言葉に日本のデジタル競争力を高めることをミッションとするテックコミュニティです。

Gemini TTSが指示文まで読み上げる時はsystemInstructionを疑う

Featured image of the post

「Gemini TTSに『落ち着いたトーンで、ゆっくり読んでください』と指示を渡したのに、生成された音声の冒頭でその指示文そのものが読み上げられていた」「エラーは何も出ていないのに、なぜか指示が声になって流れてくる」——Gemini TTSのAPIを触り始めた人が最初につまずくのがこの現象です。コードは正しく動いているのに出力だけがおかしいため、原因をコードのバグだと思い込んで時間を溶かしがちです。この記事では、症状の見分け方・原因・回避策をコード付きで解説します。

💡
30秒で要点
- 症状: Gemini TTSに読み方の指示を渡すと、対応していないモデルでは指示文までそのまま音声化される
- 原因: system_instruction パラメータに非対応のTTSモデルでは、指示文がただの読み上げ対象テキストとして扱われる
- 対策: system_instruction を使わず、「指示」と「読み上げる台本」をプロンプト本文内で明確に区切って渡す
- 副次的な注意: Gemini TTSのレスポンスは24kHz monoのRIFFヘッダ付きWAVなので、自前でWAVヘッダを付け直す必要はない

目次を開く

症状: 音声の冒頭が指示文の読み上げになる

読み方を制御したくて、次のように system_instruction へトーン指定を渡すコードを書いたとします。

from google import genai
from google.genai import types

client = genai.Client()

script = "今日は在庫システムのリリース作業について説明します。"
instruction = "落ち着いたトーンで、ゆっくり読んでください。"

response = client.models.generate_content(
    model="gemini-3.8-flash-tts",
    contents=script,
    config=types.GenerateContentConfig(
        system_instruction=instruction,
        response_modalities=["AUDIO"],
    ),
)

エラーは出ず、音声ファイルも生成されます。ところが再生してみると、冒頭数秒で「落ち着いたトーンで、ゆっくり読んでください」という指示文そのものが読み上げられ、そのあとに本題の台本が続く、という出力になっていることがあります。

原因: system_instruction に非対応のモデルがある

Gemini TTS系のモデルは、system_instruction パラメータそのものには対応していても、モデルによっては読み上げの「口調」を制御する指示として解釈せず、単なる追加の入力テキストとして扱ってしまうことがあります。この場合、指示文と台本の両方が読み上げ対象の文字列として連結され、そのまま音声化されてしまいます。

エラーが出ないのが厄介な点です。API呼び出しは成功しているので、コードのバグを疑って response_modalities や認証周りを見直しても原因にはたどり着けません。

切り分け方: 自分の環境で再現しているか確認する

まず、生成した音声の冒頭5〜10秒を再生し、instruction に使った文言(上の例なら「落ち着いたトーン」「ゆっくり」)がそのまま聞こえるかを確認します。聞こえていれば、この記事の症状に該当します。

コード側で機械的に切り分けたい場合は、instruction を明らかに読み上げ台本とは混同しない特殊な文字列(例: 半角英数のID)に一時的に差し替えて生成し、そのIDが音声化されているかを人手または音声認識で確認する方法もあります。

対策: プロンプト本文内で「指示」と「台本」を区切る

system_instruction に頼らず、プロンプトの本文側で指示と台本の境界を明示します。

from google import genai
from google.genai import types

client = genai.Client()

script = "今日は在庫システムのリリース作業について説明します。"
instruction = "落ち着いたトーンで、ゆっくり読んでください。"

prompt = f"""以下の【指示】に従って、【台本】だけを音声にしてください。指示文そのものは読み上げないでください。

【指示】
{instruction}

【台本】
{script}"""

response = client.models.generate_content(
    model="gemini-3.8-flash-tts",
    contents=prompt,
    config=types.GenerateContentConfig(
        response_modalities=["AUDIO"],
    ),
)

この形にすると、指示文が読み上げ対象から除外されるようになります。進め方としては、まず system_instruction に渡して結果を確認し、指示文が音声に混ざっていたら本文内区切りにフォールバックする、という順序が安全です。モデルやSDKのバージョンによって挙動が変わる可能性があるため、新しいモデルに切り替えたときは同じ確認を1回挟んでください。

副次情報: レスポンスはWAVとしてそのまま保存できる

Gemini TTSが返す音声データは24kHz monoのRIFFヘッダ付きWAVです。生のPCMだと思い込んでWAVヘッダを自前で組み立て直す必要はなく、そのままファイルに書き出せば再生できます。

audio_data = response.candidates[0].content.parts[0].inline_data.data

with open("output.wav", "wb") as f:
    f.write(audio_data)

まとめ

Gemini TTSで読み方の指示を渡したのに指示文まで読み上げられる場合、原因は system_instruction パラメータにモデルが対応していないことにあります。エラーは出ないため気づきにくいですが、生成音声の冒頭を聞けばすぐに切り分けられます。対策は難しいことをせず、指示と台本をプロンプト本文内で【指示】【台本】のように区切って渡すだけです。あわせて、返ってくる音声データがそのままWAVとして保存できることも覚えておくと、余計な変換コードを書かずに済みます。

よくある質問(FAQ)

Q1. 自分が使っているモデルが system_instruction に対応しているかはどこで確認できますか?

公式ドキュメントのモデル一覧で確認するのが確実ですが、最も速いのは実際に短い指示を渡して生成し、冒頭の音声を聞いて指示文が混ざっていないか耳で確かめる方法です。モデルの世代やバージョンによって対応状況が変わることがあるため、新しいモデルに切り替えるたびに1回確認してください。

Q2. 本文内で指示と台本を区切る以外に対処法はありますか?

台本の前後に読み上げさせたくない文言を置かないシンプルな構成にする、あるいは指示自体をやめてモデルの既定の読み上げ方に任せる、という選択肢もあります。どうしてもトーンを細かく制御したい場合は、区切り方式が最も確実です。

Q3. 日本語以外の指示文でも同じ現象は起きますか?

指示文の言語に関係なく、モデルが system_instruction を口調制御として解釈しない場合は同じ現象が起きます。英語の指示でも冒頭に指示文が読み上げられることがあるため、言語を変えても切り分け方は同じです。

プログラミング学習でお悩みですか?

現役エンジニアがあなたの学習をマンツーマンでサポートします。

  • 学習の進め方がわからない
  • ポートフォリオの作り方を知りたい
  • 現場で使える技術を学びたい
まずは30分の無料相談

相談は完全無料・オンラインで気軽に

あなたを爆速で成長させるメンタリングプログラムはこちら

メンタープログラムバナー

学習・開発のお悩みは現役エンジニアに相談

メンタープログラムの詳細を見る

エンジニアの基礎学習ゲーム

プログラミング学習支援

無料相談はこちら