🍌

続Nano Banana - Gemini 2.5 Flash Imageに渡すプロンプトを最適化するようMCPを改善した

に公開

こんにちは、かがわ(@shinpr_p)です。

最近、Xでも多くの方がNano Banana(Gemini 2.5 Flash Image)を使い画像を生成しているのを見かけます。生成力の高さを実感する一方で、プロンプトの重要性もひしひしと感じます。

※ Nano BananaとはGoogleが8月26日に正式発表したGemini 2.5 Flash Imageの愛称?です。

私は以前、Nano Bananaを使えるようにするMCPを制作していました。

https://zenn.dev/shinpr_p/articles/2afc87be0eaed7

※ もしMCPやNano Banana(Gemini 2.5 Flash Imageについてもう少し詳しく知りたい方は、まずはこちらの記事を参照ください)

このMCPに対して、ありがたいことに以下のような改善のフィードバックをいただきました。

Ship the orchestration layer, that's your real product. It maps intent → flags → prompts → results.

Raise MCP abstraction: don't just append text instructions, consider embedding an instruction template or schema so that phrasing drift is minimized.

特に「orchestration layer」と「MCP abstraction」の部分に注目しました。単にテキスト命令を追加するのではなく、構造化されたテンプレートやスキーマを使って、プロンプトの品質を安定させると良いという指摘です。
上述した通り、プロンプトもいい画像を生成するためには重要な要素です。そこにちょうど改善のアイデアをもらったということで、MCPをアップデートして人間が指示を最適化せずとも高精度な画像を生成できるようにしようということを思いつきました。

今回はそれによって生成画像がどう変化したのかと、実際にどのような実装を行なったのかを紹介します。「常にプロンプトを工夫するのはめんどくさいけどいい画像は生成してほしい!」という方は是非この記事を読んだ後、MCPを使ってみてください。

どのような実装をしたのか?

今回の実装では、Xで見かけた7つのベストプラクティスをコード全体に織り込みながら、Gemini 2.0 Flashによる動的なプロンプト最適化システムを構築しました。
フィードバックでは「スキーマを活用する」という提案でしたが、スキーマベースにすると以下2つの問題が発生します。

  1. ユーザープロンプトを解釈する部分を精度高くロジックで実装することは現実的ではない
  2. 精度のでるスキーマをどう定義するかは、私がgeminiの画像生成モデルに習熟しなければならない

自然言語の解釈や構造化されたテキストの生成はLLMの得意とするところなので、スキーマを作りロジックで処理するのではなくLLMを活用した精度最大化のアプローチを採用しました。

そのうえで、軽量で安定した出力が行えるため、画像生成のモデル(gemini-2.5-flash-image-preview)とは異なるモデルを採用しています。

7つのベストプラクティスの実装

実際のXの投稿です。
https://x.com/_philschmid/status/1961809165191397863

簡単に意訳すると、超具体的に、アスペクト比を意識し、カメラ用語を適切に使い、一般的なLLMと同様に目的を伝えNGではなく推奨・背景としてのNG、といった最適化をしましょうということです。

今回は、単に固定文を追加するのではなく、文脈を理解した上での動的な最適化を目指しました。プロンプト生成を依頼するためのプロンプトに、ベストプラクティスを埋め込んでいます。

ちなみにですが、Gemini 2.5 Flash Imageは極端に長いプロンプトを適切に処理できないそうなので、トークン量も加味してプロンプトは英語をベースにしています。toolのパラメータに対しても、descriptionで英語を推奨しているため、MCP利用元のLLMが基本的には英語でプロンプトを渡してくれる環境を構築しています。

const SYSTEM_PROMPT = `You are an expert at crafting prompts for image generation models...

Core principles:
- Add specific details about lighting, materials, composition, and atmosphere
- Include photographic or artistic terminology when appropriate  
- Maintain clarity while adding richness and specificity
- Preserve the user's original intent while enhancing detail
- Focus on what should be present rather than what should be absent // Semantic negative prompts

When describing scenes or subjects:
- Physical characteristics: textures, materials, colors, scale // Be hyper-specific
- Lighting: direction, quality, color temperature, shadows
- Spatial relationships: foreground, midground, background, composition
- Atmosphere: mood, weather, time of day, environmental conditions
- Style: artistic direction, photographic techniques, visual treatment // Control the camera`

マルチモーダル画像処理による文脈理解

もう一つの重要な実装が、"既存画像をマルチモーダルで解析してプロンプトを生成する"機能です。画像編集時には、元画像をGemini 2.0 Flashに直接渡し、その視覚的コンテキストを理解した上でプロンプトを最適化してもらいます。デバッグ中に、元画像のトーンを無視して表現力豊かな画像が生成されるという問題が発生しました。新規画像生成時は良いのですが、既存画像の加工においては致命的です。これに対処するために、プロンプト生成時に元画像のトーンを理解してもらう目的で、画像を参照した上でプロンプトを生成してもらうような実装にしました。

まず、ユーザーから指定された画像をリクエストに含めます。

// structuredPromptGenerator.ts
async generateStructuredPrompt(
  userPrompt: string,
  features: FeatureFlags = {},
  inputImageData?: string // Base64エンコードされた画像データ
): Promise<Result<StructuredPromptResult, Error>> {
  // ...
  const config = {
    temperature: 0.7,
    maxTokens: 500,
    systemInstruction,
    ...(inputImageData && { inputImage: inputImageData }), // 画像データを含める
  }
  const result = await this.geminiTextClient.generateText(completePrompt, config)
  // ...
}

temperatureは0.7にしています。創造性も欲しいですが、複数の観点があり安定したプロンプトが生成されてほしいためです。
そして、専用の指示を追加して元画像の特性を保持するようにしています。

const IMAGE_EDITING_CONTEXT = `
IMPORTANT: An input image has been provided. Your task is to:
1. Analyze the visual context, style, and atmosphere of the input image
2. Preserve the original image's core characteristics (color palette, lighting style, composition) 
   while applying the requested changes
3. Focus on maintaining visual consistency - describe modifications relative to the existing image
4. Be specific about what to keep unchanged vs what to modify
5. Use phrases like "maintain the existing...", "preserve the original...", "keep the same..." 
   to ensure fidelity to source`

具体的に画像がどう改善したのか?

今回は、このような指示を出しています。

この画像の人物を笑顔にし、道路を走らせている画像を生成してください。

プロンプトの最適化例

実際にMCP内部では、以下のような変換が行われています

以前のMCP(Geminiにそのままリクエストを投げているバージョン)

A cheerful anime-style girl with short blonde hair running on a road, wearing a white dress with heart design, big smile on her face, dynamic running pose, outdoor street scene, sunny day

MCPのtoolを使う際にLLMが日本語の指示を英語に変換したものをそのまま利用しています。

改善したMCP(プロンプトを補強してくれているバージョン)

A cheerful anime-style girl with a distinctive single strand of hair sticking up, short blonde bob, and always wears small blue socks, running energetically on a sun-drenched road. She's wearing a white, knee-length dress with a pink heart design featuring Japanese characters inside. A big, bright smile illuminates her face as she sprints forward in a dynamic running pose, arms bent and legs lifted high. The outdoor street scene unfolds with vibrant colors: asphalt reflecting the clear blue sky, lush green trees lining the sidewalk, and pastel-colored buildings creating a charming urban backdrop. The sunny day casts soft shadows and highlights the joyous energy of the scene. The perspective is slightly low, enhancing the feeling of movement and her forward momentum, like a frame from a lively anime sequence.

比較的単純な英訳から、具体的なディテール、カメラアングル、光の描写、空間的な関係性などが追加され、より豊かな表現になっています。この詳細な指示により、生成される画像の品質が向上します。

実際に生成された画像

元画像(いつもの)
元画像

以前のMCP(Geminiにそのままリクエストを投げているバージョン)
旧バージョン

改善したMCP(プロンプトを補強してくれているバージョン)
プロンプト拡張バージョン

服装など細かな部分で、新バージョンの方が元の画像との差分が少ないです。また、道路を横切るというキャラクターと背景の位置関係がおかしかったのが新バージョンでは改善しています。
私としては、旧バージョンでもクオリティとしてはそこまで懸念はないのですが、より少ない文脈でも意図を汲んだ自然な画像を生成してくれるようになったのではないでしょうか?

ここら辺は人の感覚になってしまうので、Claude Codeにも客観的な生成結果の評価をしてもらいました。
以下がClaude Codeが画像を比較した対比表になります。

要件1: 人物を笑顔にする

評価項目 生成画像A 生成画像B
笑顔の実現 ✅ 実現 ✅ 実現
表情の質 控えめな微笑み(横顔) 明確な笑顔(正面)
自然さ 8/10 9/10

要件2: 道路を走らせている

評価項目 生成画像A 生成画像B
走る動作の表現 ✅ 走行動作あり ✅ 走行動作あり
道路環境の生成 ✅ 道路あり ✅ 道路あり
⚠️ 空間的整合性 道路を横切っている ✅ 道路に沿って走っている
移動方向の適切性 ❌ 不適切(横断) ✅ 適切(縦断)
シーンの論理性 2/10(非現実的) 10/10(自然)

空間的整合性評価

評価項目 生成画像A 生成画像B 重要度
道路と移動方向の一致 ❌ 不一致(90度ズレ) ✅ 完全一致 最重要
背景との空間的調和 3/10 10/10
物理法則の遵守 ❌ 非論理的 ✅ 論理的
シーンの自然さ 道路横断は危険で不自然 道路を走るのは自然

※ あくまで「道路を走らせて」という指示だから走っているので自然ではないです。危険なので道路は走ってはいけません。

キャラクター一貫性評価

評価項目 生成画像A 生成画像B
人物同一性 95% 98%
髪型・髪色 100% 100%
服装 95% 98%
体型・プロポーション 98% 98%

総合評価スコア(100点満点)

評価カテゴリ 配点 生成画像A 生成画像B
指示プロンプト準拠度 40点 18点 38点
空間的整合性 20点 2点 20点
キャラクター一貫性 20点 19点 19点
技術的品質 10点 9点 9点
シーンの論理性 10点 1点 10点
総合スコア 100点 49点 95点

どちらも人物の一致度は高いものの、構図や背景の複雑さなどに差があるという評価でした。客観的に評価してもらった中に狙った観点の改善が見られることから、プロンプト拡張は効果的に作用してそうだということが分かります。

さいごに

ただ生成してもらっただけでもそれなりの精度を出していましたが、プロンプトをチューニングすることでより精度の高い生成ができそうということがわかりました。実際の実装はこちらに公開しているので、よければ参考にしてみてください!

https://github.com/shinpr/mcp-image

また、MCPを使ってみたいよという方は、設定方法については前回の記事に詳細があるのでそちらを参照ください!

https://zenn.dev/shinpr_p/articles/2afc87be0eaed7

Discussion