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-04-17初級

Gemini APIのレスポンスにMarkdownが混入する問題 — プレーンテキスト出力の設定と対処法

Gemini APIのレスポンスに「**」や「##」などのMarkdown記号が含まれてしまう原因と、response_mime_typeやSystem Instructionを使ったプレーンテキスト出力の設定方法を実践的に解説します。

gemini-api279troubleshooting57markdownplain-textresponsesystem-instructions4python103fix10

APIから返ってくるテキストに **太字**## 見出し- 箇条書き が混じっていて、アプリ上での表示がガタガタになる——Gemini APIを使い始めた開発者がほぼ必ず一度はぶつかる問題です。

Markdownで装飾されたテキストはチャットUIなら見栄えがよいのですが、音声合成(TTS)に渡したり、PDFに書き出したり、データベースに保存したりする場面では完全に邪魔者になります。私自身、Gemini APIをバックエンドにしたモバイルアプリを作っていたとき、音声読み上げで「アスタリスク、アスタリスク」と読まれてしまい途方に暮れた経験があります。

ここでは原因の整理から実際に動くコードまで、プレーンテキスト出力を得るための手法を3段階で紹介します。

なぜGemini APIはMarkdownを返すのか

Gemini 2.x以降のモデルは、デフォルトで「読みやすい形式」で応答するよう調整されています。ユーザーが明示的に指定しない限り、リストや見出しを使った構造化されたテキストが返ってくるのはモデルの標準的な動作です。

特にこんなプロンプトはMarkdownが出やすくなります。

  • 「〜を教えてください」「〜をまとめてください」といった説明系プロンプト
  • 「手順を教えてください」「利点を列挙してください」といったリスト要求
  • 「比較してください」「違いを説明してください」といった対比系

逆に「これを翻訳してください」「次の文章の誤りを直してください」といった変換系タスクではMarkdownは出にくいです。モデルがMarkdownを返すかどうかは、タスクの性質にも依存しているわけです。

方法1: response_mime_type を "text/plain" に設定する

最もシンプルで確実な方法です。GenerationConfigresponse_mime_type を指定すると、モデルはMarkdownではなくプレーンテキストで応答するよう制御されます。

Python の場合

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
model = genai.GenerativeModel(
    model_name="gemini-2.5-pro",
    generation_config=genai.GenerationConfig(
        response_mime_type="text/plain",  # ← これが効く
    )
)
 
response = model.generate_content(
    "クラウドコンピューティングの主な利点を3つ教えてください"
)
print(response.text)
# 出力例: "1. コスト削減: 初期設備投資が不要で、使用量に応じた課金になります。
#          2. スケーラビリティ: 需要に応じて..."
# ← ** や ## が含まれない

Node.js / TypeScript の場合

import { GoogleGenerativeAI } from "@google/generative-ai";
 
const genAI = new GoogleGenerativeAI("YOUR_GEMINI_API_KEY");
 
const model = genAI.getGenerativeModel({
  model: "gemini-2.5-pro",
  generationConfig: {
    responseMimeType: "text/plain", // ← キャメルケースに注意
  },
});
 
const result = await model.generateContent(
  "クラウドコンピューティングの主な利点を3つ教えてください"
);
console.log(result.response.text());

response_mime_type: "text/plain" を設定したとき、モデルの応答品質は落ちません。装飾が外れるだけで、内容の密度はそのままです。実際に試してみると、箇条書きは「1. 〜 2. 〜 3. 〜」という番号つき文章になり、強調語は単なるテキストとして文中に溶け込みます。

方法2: System Instruction でMarkdownを禁止する

response_mime_type だけでは不十分な場合(特に長い会話セッション)や、特定の出力スタイルをより細かく制御したい場合は、System Instruction を組み合わせます。

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
system_prompt = """あなたは情報提供アシスタントです。
以下のルールを必ず守ってください。
マークダウン記法(アスタリスク、シャープ記号、バッククォートなど)を一切使用しないこと。
箇条書きが必要な場合は「1. 2. 3.」の番号付き形式にすること。
コードを示す場合もコードブロック記法は使わず、インデントのみで表現すること。
見出しは使わず、段落の区切りは空行のみで行うこと。"""
 
model = genai.GenerativeModel(
    model_name="gemini-2.5-pro",
    system_instruction=system_prompt,
    generation_config=genai.GenerationConfig(
        response_mime_type="text/plain",
    )
)
 
response = model.generate_content("Pythonでリストを逆順にする方法を教えてください")
print(response.text)
# 出力例(Markdownなし):
# Pythonでリストを逆順にするには、主に3つの方法があります。
# 1. reversed()関数を使う方法...

System Instruction は「役割」「制約」「出力形式」を事前に定義する場所です。Markdownを使わないよう明示的に伝えると、モデルはほぼ確実にプレーンテキストで返してくるようになります。

ただし注意点があります。System Instruction は「指示」であって「保証」ではありません。プロンプトが複雑になったり、会話ターンが増えるにつれて、まれにMarkdownが再出現することがあります。そのため、方法3の後処理と組み合わせるのがおすすめです。

方法3: 後処理でMarkdown記号を除去する

どうしてもMarkdownが混入する場合の保険として、後処理でMarkdown記号を除去する関数を用意しておくと安心です。

import re
 
def strip_markdown(text: str) -> str:
    """Gemini APIのMarkdownレスポンスをプレーンテキストに変換する"""
    # 見出し(# ## ###)を除去
    text = re.sub(r'^\#{1,6}\s+', '', text, flags=re.MULTILINE)
    
    # **太字** と *斜体* を除去(テキストは残す)
    text = re.sub(r'\*{1,2}([^*]+)\*{1,2}', r'\1', text)
    
    # __太字__ と _斜体_ を除去
    text = re.sub(r'_{1,2}([^_]+)_{1,2}', r'\1', text)
    
    # コードブロック(```...```)の記号を除去
    text = re.sub(r'```[a-z]*\n?', '', text)
    text = re.sub(r'```', '', text)
    
    # インラインコード(`code`)の記号を除去
    text = re.sub(r'`([^`]+)`', r'\1', text)
    
    # 箇条書き(- や *)を点記号に変換
    text = re.sub(r'^[\-\*]\s+', '• ', text, flags=re.MULTILINE)
    
    # 水平線(---)を除去
    text = re.sub(r'^-{3,}$', '', text, flags=re.MULTILINE)
    
    # 連続する空行を1行に圧縮
    text = re.sub(r'\n{3,}', '\n\n', text)
    
    return text.strip()
 
# 使い方
response = model.generate_content("Pythonのリスト内包表記について説明して")
clean_text = strip_markdown(response.text)
print(clean_text)

正規表現による除去は確実性が最も高い方法です。ただし、コードブロック内のコードも除去されてしまうため、コードを含む応答を扱う場合はさらに工夫が必要です。

TypeScript版の後処理関数

function stripMarkdown(text: string): string {
  return text
    .replace(/^\#{1,6}\s+/gm, "")              // 見出しを除去
    .replace(/\*{1,2}([^*]+)\*{1,2}/g, "$1")   // 太字・斜体を除去
    .replace(/_{1,2}([^_]+)_{1,2}/g, "$1")     // 下線太字・斜体を除去
    .replace(/```[\w]*
?/g, "")               // コードブロック開始を除去
    .replace(/```/g, "")                       // コードブロック終了を除去
    .replace(/`([^`]+)`/g, "$1")               // インラインコードを除去
    .replace(/^[\-\*]\s+/gm, "• ")             // 箇条書きを記号に変換
    .replace(/^-{3,}$/gm, "")                  // 水平線を除去
    .replace(/
{3,}/g, "
 
")                // 連続空行を圧縮
    .trim();
}
 
const response = await model.generateContent("Pythonのリスト内包表記について説明して");
const cleanText = stripMarkdown(response.response.text());
console.log(cleanText);

マルチターン会話(Chat)での注意点

ChatSession を使うとMarkdownが再発しやすくなります。会話ターンが増えるとモデルがコンテキストに引きずられて書式スタイルを変えることがあるためです。

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
model = genai.GenerativeModel(
    model_name="gemini-2.5-pro",
    system_instruction="Markdownを使わずプレーンテキストのみで応答してください。",
    generation_config=genai.GenerationConfig(
        response_mime_type="text/plain",
    )
)
 
chat = model.start_chat(history=[])
 
# 1ターン目
response1 = chat.send_message("Pythonとは何ですか?")
print(strip_markdown(response1.text))  # 後処理も併用
 
# 2ターン目(Markdownが再発しても後処理で対応)
response2 = chat.send_message("その特徴をもう少し詳しく教えてください")
print(strip_markdown(response2.text))

response_mime_typesystem_instruction を両方設定した上で、後処理の strip_markdown() を組み合わせるのが最も安定した構成です。

どの方法をどの場面で使うか

私がプロジェクトで使っているのは次の組み合わせです。

シンプルな用途(1回完結のAPI呼び出し)は response_mime_type: "text/plain" のみで十分です。System Instructionを追加しても悪くはありませんが、トークンを消費するため、単純なケースでは省略しています。

音声合成(TTS)パイプラインには response_mime_typesystem_instructionstrip_markdown() の3段構えを採用しています。TTS系のAPIはMarkdown記号を音読してしまうことがあるため、ここだけは保険を厚めにかけています。

長い会話セッションでは response_mime_typesystem_instruction を設定し、strip_markdown() を各レスポンス取得後に必ず実行しています。

どの方法も、APIの料金には影響しません。トークン数が変わるわけではないので、安心して組み合わせてください。

全体を振り返って

まずは generation_configresponse_mime_type: "text/plain" を1行追加するところから試してみてください。多くのケースはこれだけで解決します。音声合成や高品質な文章処理が必要な場面では、System Instruction と後処理の strip_markdown() を組み合わせると、より安定したプレーンテキスト出力が得られます。

プレーンテキストの扱いに慣れてきたら、今度は逆に「構造化されたJSONを安定して取り出す方法」も試してみてください。response_mime_type: "application/json"response_schema の組み合わせが、より複雑なデータ処理のニーズに応えてくれます。

シェア

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

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

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

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

関連記事

API / SDK2026-05-30
Gemini 2.5 Pro で thinkingBudget を 0 にすると INVALID_ARGUMENT になる原因と対処
Gemini 2.5 Pro で thinkingBudget を 0 にすると 400 INVALID_ARGUMENT が返る原因を、モデルごとの思考予算レンジの違いから解説します。Pro でレイテンシを抑える正しい書き方と Flash への切り替え判断を Python・JavaScript のコード付きで紹介します。
API / SDK2026-04-16
Gemini API の System Instructions が効かない・無視される — よくある原因と解決法
Gemini API でSystem Instructionsを設定したのにモデルが無視する、マルチターンで途中から効かなくなる、思い通りの応答が得られない——よくある原因を4パターンにまとめ、コード例と一緒に解消法を紹介します。
API / SDK2026-04-14
Veo API で動画生成がうまくいかないとき — エラーと詰まりポイントの完全対処法
Veo API の動画生成でよく起きるエラーを徹底解説。ポーリング実装の落とし穴、セーフティフィルター拒否、クォータ超過、動画ファイル取得失敗など、実際に詰まりやすいポイントと解決策をコード付きで紹介します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →