メインコンテンツへスキップ
← AIで創る
AIに毎回同じキャラクターを描かせる方法
AIで創る

AIに毎回同じキャラクターを描かせる方法

JV
Jay Vergara · 2026年5月7日 · 2分で読める
ai-toolsgemininano-banana-proclaudevibe-codingimage-generationtutorialintermediate

ブログ記事用のイラストを生成していて、Geminiに「同じ人物」を頼むたびに、微妙に違う人物が出てきていました。顎が違う、髪が少し違う、雰囲気が「いとこ」に見える程度に絶妙にずれている。3回やり直した時点で、ストックフォトのサブスクを契約しかけたほどです。

解決までには、Claudeと週末いっぱいいじり続ける時間がかかりました。私はPythonを書けません。問題を普通の言葉で説明して、実際のコードはClaudeに任せるという、いわゆるバイブコーディングで全部作りました。今ではこのサイトのすべてのブログ記事のために本番稼働しています。


AIのキャラクターがぶれる問題は本物です

繰り返し登場するビジュアルにAIを使っているなら(ブログのイラスト、研修資料のマスコット、ニュースレターの画像、SNSのカルーセルなど)、これはあなたにも起きます。1枚目は素晴らしいのに、5枚目は微妙に別人で、10枚目になると完全に別のブランドに見える。読者は何がおかしいのか言葉にできなくても気づきます。見慣れた顔は信頼を築きますが、毎回変わる顔は、その下の文章がどれだけ良くても雑な印象を与えてしまいます。

根本の問題は、画像モデルが決定的ではないことです。同じプロンプトから同じ人物は二度と出てきません。言葉だけではなく、視覚的なアンカーをモデルに渡す必要があります。


最初に試したこと(そして諦めかけた理由)

Claudeに助けを求める前に、Geminiのプロンプトの中だけで解決しようとしました。どれも機能しませんでした。

プロンプトでキャラクターをもっと丁寧に描写する。 どんどん長いキャラクター描写を書きました。えらの張った顎、30代後半、坊主頭、あごひげ、眼鏡。毎回、5つの特徴のうち2つだけ当たっていて残りは外れた人物が出てきます。モデルは長い描写プロンプトを仕様ではなく風味として扱うのです。

全く同じプロンプトを一語一句そのまま再利用する。 うまくいきそうに思えますよね。いきません。画像モデルは生成時にランダムなノイズを加えるので、同一のプロンプト2つから別人が2人出てきます。ときにはかなり違う人が。

セッションをまたいでキャラクターを「覚えて」いてもらうよう頼む。 だめでした。画像モデルには、ClaudeやChatGPTのような持続的なメモリがありません。すべての生成がゼロからのスタートです。

ここでほとんど諦めかけました。転機になったのは、本当の解決にはコードが必要なのに、プロンプトで直そうとしていたと気づいた瞬間です。


どう解決したか。Claudeに作ってもらいました

そこでClaudeを開いて、同僚に話すように問題を説明しました。だいたいこんな内容です。

「ブログのイラストをGeminiで生成していて、毎回同じキャラクターが登場するはずなのに、Geminiが毎回微妙に違う人物を描いてしまいます。プロンプトの改善も、全く同じプロンプトの再利用も試しました。どちらも効きません。私はコードを書けませんが、書いてもらえればPythonスクリプトを実行することはできます。実際に解決できるアプローチはどれですか」

Claudeはまず概念から説明してくれました。画像モデルは決定的ではない。キャラクターを固定するには、テキストの説明だけでなく、参照画像をプロンプトと一緒に入力としてモデルに渡すこと。それから、使っているツール(GeminiのNano Banana Pro)、実行できる言語(Python)、出力の保存先(サイトのリポジトリ内の特定のフォルダ)を確認してきました。

そしてスクリプトの最初のバージョンを書いてくれました。

核となるアイデアは、Pythonを書けない私でも追えるくらいシンプルでした。Gemini APIに2つのものを渡します。参照画像とテキストプロンプトです。参照画像はcontentsリストの中でプロンプトより前に置きます。Claudeが書いた部分がこちらです。

with open(FACE_REFERENCE, "rb") as f:
    image_bytes = f.read()
ref_image = types.Part.from_bytes(data=image_bytes, mime_type="image/png")

response = client.models.generate_content(
    model="gemini-3.1-flash-image-preview",
    contents=[ref_image, full_prompt],
    config=types.GenerateContentConfig(
        response_modalities=["IMAGE", "TEXT"],
    ),
)

これを書いたのは私ではなくClaudeです。私に説明できるのは、これが何をするかです。最初の3行はリポジトリ内のファイルから参照画像を読み込みます。generate_contentの呼び出しが、その画像と私のテキストプロンプトをGeminiに送ります。返ってくるのは、参照のキャラクターと一致するはずの新しい画像です。

テキストプロンプトは、私が反復して調整している部分です。その最初のバージョンもClaudeが書きました。最も重要なブロックは、参照をよく観察して顔を再現するようモデルに指示しています。

FACE REFERENCE: Study the reference illustration carefully. The main
figure is the SAME person as in the reference. Replicate his EXACT
facial structure: broad jaw, wide face shape, specific nose shape,
and eye shape. He has a tightly shaved buzzcut head, a goatee, and
East Asian features. His skin tone must match the reference exactly.
The face must be RECOGNIZABLY the same person as the reference, not
a generic character.

同じプロンプトの後半には、参照画像のポーズを真似しないという明示的な指示があります。

Do NOT reproduce the reference image's composition or pose. The
reference is for face and character likeness only. Create a NEW
scene matching the description above.

この分離こそが、記事ごとに新しいシーンで同じ顔を出すコツです。同じ人物、新しい部屋、新しい行動、新しい服装。毎回そうなります。


実際に機能するまでのバイブコーディングの反復

最初のバージョンは動いたものの、おかしな結果を出していました。だから画像を生成して、出力を眺めて、何がずれているか確認して、Claudeに伝える。実際の構築のほとんどはこのサイクルの中で起きます。

特に効いた3つの反復を紹介します。

反復1:「スマートグラスがいつもサングラスになってしまう」

キャラクターのスマートグラスのレンズが暗い色でレンダリングされ続けるとClaudeに伝えました。目が見えないのです。会議室でアビエイターサングラスをかけているように見えました。ClaudeはCRITICALの上書きブロックを提案して、書いてくれました。

CRITICAL: the lenses are COMPLETELY CLEAR and TRANSPARENT, his eyes
are fully visible behind them. NOT tinted. NOT dark. NOT sunglasses.

これで95%くらいの確率で直りました。強気の大文字も明示的な否定も、どちらもClaudeのアイデアです。モデルに向かって怒鳴るようなプロンプトを書くなんて、私には思いつきもしませんでした。

会議室のシーンで、主人公が明らかに透明なレンズの四角い眼鏡をかけていて、目がはっきり見えている

ClaudeがプロンプトにCRITICALブロックを追加してからは、眼鏡は毎回透明なレンズでレンダリングされます。サングラスバグはもうありません。

反復2:「フォーマルな会議のシーンだと、キャップが浮いてしまう」

私の服装にはときどきベースボールキャップが含まれます。カジュアルなシーンならいいのですが、役員会議室では変です。問題を説明して、フォーマルなシーンを検出して自動的にキャップを外す方法はないかと聞きました。Claudeは、シーンのプロンプトを見て上書きを発動させるキーワードスキャナーを書いてくれました。

FORMAL_SCENE_KEYWORDS = (
    "meeting", "conference room", "boardroom", "workshop",
    "presentation", "auditorium", "training room", "all-hands",
    "huddle", "around a table",
)
is_formal_scene = any(kw in prompt_lower for kw in FORMAL_SCENE_KEYWORDS)

シーンの説明にこれらの単語のどれかが出てきたら、プロンプトが組み立てられる前に服装からキャップが外されます。荒削りですが機能しています。

役員会議室のシーンで、主人公が3人の同僚と長いテーブルについていて、ベースボールキャップをかぶっていない

上のシーンはこの修正の実際のテストです。この生成ではワードローブがランダムにBrooks Brothersのキャップを選んだのですが、フォーマルシーン検出器がプロンプト内の「boardroom」という単語を捉えて、画像がレンダリングされる前にキャップを外しました。

反復3:「同じ人物のまま、服装だけ変えられないか」

顔が固定できたら、今度はイラストが「同じ写真にキャプションだけ変えたもの」に見えないように、記事ごとに服装を変えたくなりました。実際に持っている服のリスト(リネンシャツ、鎌倉シャツのOCBD、Burberryのブレザー、腕時計を2本ほど、ベースボールキャップを数個)があるとClaudeに伝えて、記事ごとにコーディネートされた服装をランダムに選ぶ方法はないかと聞きました。

Claudeはワードローブ全体のPython辞書と、8種類のテイスト(スマートアイビー、ラギッドカジュアル、サマーアイビー、週末カジュアル、ヘリテージプレップ、雨の日、サマーカジュアル、スマートカジュアル)から服装一式をランダムに組み立てる関数を作りました。その一部がこちらです。

"oxford_button_downs": [
    {"name": "OCBD", "brand": "Kamakura", "color": "White"},
    {"name": "OCBD", "brand": "Kamakura", "color": "University Stripe Blue"},
],
"blazers": [
    {"name": "Navy Blazer", "brand": "Burberry", "color": "Navy"},
],
"watches": [
    {"name": "Seamaster 300M Diver", "brand": "Omega"},
    {"name": "Speedmaster '57", "brand": "Omega"},
],

選ばれた服装は説明文(「鎌倉シャツの白いOCBDにネイビーのチノパン、Tricker’sのStowブーツ、手首にはOmegaのSeamaster」)として組み立てられ、CLOTHINGブロックとしてプロンプトに入ります。同じキャラクター、記事ごとに違う服装です。

東京の裏通りを、グレーのポロシャツとジーンズとデッキシューズというカジュアルな服装で歩く主人公のストリートシーン

上の役員会議室や会議室のシーンと同じキャラクターですが、この1枚はワードローブが週末カジュアルを引き当てました。グレーのポロ、インディゴデニム、LL Beanのデッキシューズ、SeikoのアルピニストGMTです。

3つの反復すべてに共通するパターンは同じです。何かおかしいと気づく。症状を普通の言葉で説明する。Claudeが修正を提案する。私がテストする。直らなければ、まだ何がずれているのかをClaudeに伝えて続ける。このループがバイブコーディングです。それ以外の秘密はありません。


同じパターンを自分の仕事に使う

顔の固定と構造化プロンプトとワードローブの変化という組み合わせは、汎用的なパターンです。入力を差し替えれば、こんな用途に使えます。

社内研修資料の一貫したイラストマスコット。 ブランドマスコットの顔参照を一度固定します。モジュールごとにシーンを変えます(テストを受ける受講者、フィードバックをもらう受講者、コースを修了する受講者)。カリキュラム全体を通して、同じ親しみやすいキャラクターが登場します。

LinkedInカルーセルシリーズの定番キャラクター。 同じ固定された顔、スライドごとに違うシーン、全体を通した同じイラストスタイル。カルーセルのたびにイラストレーターへ支払わなくても、シリーズらしさが出せます。

月刊ニュースレターの看板キャラクター。 顔を一度固定すれば、季節のバリエーションをいつまでも生成できます。冬のコートを着た1月版、リネンの7月版、すべて同じ人物です。

ケーススタディや営業資料のためのブランドキャラクターのチーム。 クライアントやペルソナごとに固定参照を用意して、すべてを一貫したハウススタイルでレンダリングします。「このスライドだけ別のブランドが作ったみたい」がなくなります。

持ち運べるのはパターンの部分です。固定する顔も、変化させるワードローブも、描写するシーンも、あなたのものです。


次に作るなら変えたいこと

参照画像は、ベースのモデルが更新されるのに合わせて半年ごとくらいにリフレッシュが必要になりそうです。今きれいにレンダリングされるものも、モデルが変わればずれていくかもしれません。今のところ「定期的に参照を再生成する」以上のいい解決策は持っていません。

服装のバリエーションが顔に漏れることがあります。フォーマルなブレザーを着せると少し老けて見えて、カジュアルなキャップをかぶせると少し若く見えます。顔を安定させる仕事のほとんどはプロンプトがやっていますが、モデルは服装からもいくらか信号を拾っています。

固定した2人のキャラクターを同じシーンに描くことはまだできません。参照画像のシステムは1つの顔用です。すべてのイラストで同じ見た目であるべき2人目(特定の同僚、レギュラーの共同ホスト、クライアントのカメオ出演)が必要になった瞬間、このアーキテクチャは破綻します。次にClaudeと攻略したいのはそこです。

いちばん明らかな問題は、パイプライン全体が、Claudeと私が一緒に作ったPythonスクリプトとGitHub Actionでつぎはぎされていることです。動きますが、きれいではありません。本物のエンジニアなら別の設計にするでしょう。でもちゃんと出荷できていて、1カ月間壊れていません。私が本当に必要だったのはそれです。


出典:


leadhuman.aiのBuild with AIシリーズの一部です。

Jay Vergara

Jay Vergara is an L&D strategist and cross-cultural communication specialist based in Tokyo. He is a partner at Peak Potential Consulting and writes about leadership, learning, and building with AI at leadhuman.ai and on LinkedIn.

こちらもおすすめ