ComfyUI で挿絵を作る:NanoBanana Pro からの移行
画像生成サービスからローカル ComfyUI へ移行し、Claude Code がワークフロー JSON を生成する仕組みを作った話
← 前の記事: GPTs をつくる:ペルソナとフォーマットの試行錯誤NanoBanana Pro で十分だった
テキストだけのページは、印象が弱い。
それに気づいたのは、たんぱくパスタの story 記事を書き始めたときだった。科学者のキャラクターが食材と対話しながら調理の謎を解く——という構成で記事を書いていたのだが、文章だけ読んでいると頭の中に絵が浮かびにくい。挿絵があれば、読者がキャラクターを掴みやすくなる。
最初に使ったのが NanoBanana Pro という画像生成サービスだ。ブラウザで開いてプロンプトを入力すると、数秒で画像が出てくる。気に入ったら右クリックで保存。あとは cwebp コマンドで WebP に変換して public/images/ に置いて、コードに参照を追加する。
記事が2〜3本のうちは、この手順で十分だった。
ComfyUI への興味
NanoBanana Pro で記事数本ぶんの挿絵を作るうちに、画像生成の「裏側」が気になり始めた。
ちょうどその頃、ComfyUI というツールの存在を知った。ノードベースでワークフローを自由に組めて、モデルの入れ替えも自在、API 経由での自動化もできる。キャラクターの一貫性を保つ Redux のような手法も試せる。画像生成の仕組みが全部見える構造だ。
この可能性の広さに惹かれて、ローカル環境を立てることにした。
ComfyUI をコンテナで立ち上げた
ComfyUI は、ノードベースの画像生成ツールだ。「ノードベース」というのは、処理の部品をブロックで表して、ブロック同士を線で繋いでワークフローを組む方式のことだ。Scratch に近いイメージで、コードを書かなくても画像生成の手順を組み立てられる。
これを Docker コンテナとして立ち上げた。dev コンテナと同じ Docker ネットワークに入れることで、API 経由(http://comfyui:8188)で画像生成を呼び出せる。
モデルは FLUX.2 Klein 4B という。4ステップで生成が終わる高速モデルで、Apache 2.0 ライセンスなので商用利用も OK だ。VRAM は 8.4GB 使う。
スキルを3層で作った
Claude Code には「スキル」という仕組みがある。SKILL.md というファイルに環境情報と手順を書いておくと、「〇〇して」と頼んだとき Claude がそのファイルを読んで動いてくれる。
ComfyUI 周りのスキルを3層で作った。
インフラ層(comfyui): コンテナの起動・停止を担当する。「ComfyUI を起動して」と言うと、SSH ラッパー経由でコンテナを立ち上げる。ComfyUI が動いているかどうかの確認もここで行う。
画像生成層(comfyui-flux2): 6本のシェルスクリプトを束ねたスキルだ。テキストから直接生成するスクリプト、参照画像を使ったキャラ一貫性生成(Redux)、複数参照を扱う Redux、インペインティング(画像の一部だけを修正)、部分的な高解像度化——用途ごとにスクリプトが用意されている。
統合層(yatmita-illustration): 「挿絵を作って」と言われたときの全手順を定義している。記事を読んでシーンを選ぶ → キャラ参照画像を探す → Redux で生成 → WebP に変換して public/images/ に配置 → storyImages 辞書に追加 → pnpm run build で確認。この一連の流れを、Claude が一人でやり切る。
「挿絵を作って」の一言で、3層を辿って最後にビルドが通るまでやってくれる。
ワークフロー JSON を Claude Code が組み立てる
これが一番面白かった部分だ。
ComfyUI は普通、GUI でノードをドラッグして線で繋いでワークフローを組む。でも ComfyUI には API がある。ワークフローを JSON で表現して POST すれば、GUI を開かなくても画像を生成できる。
generate-flux2-klein.sh というスクリプトの中を見ると、こういうコードが書いてある:
w = {
'1': {'class_type': 'UNETLoader', 'inputs': {'unet_name': 'flux-2-klein-4b-fp8.safetensors'}},
'2': {'class_type': 'CLIPLoader', 'inputs': {'clip_name': 'qwen_3_4b.safetensors', 'type': 'flux2'}},
'3': {'class_type': 'VAELoader', 'inputs': {'vae_name': 'flux2-vae.safetensors'}},
'4': {'class_type': 'CLIPTextEncode', 'inputs': {'text': prompt, 'clip': ['2', 0]}},
'7': {'class_type': 'KSampler', 'inputs': {
'model': ['1', 0], 'seed': seed, 'steps': 4,
'positive': ['5', 0], 'latent_image': ['6', 0]
}},
'8': {'class_type': 'VAEDecode', 'inputs': {'samples': ['7', 0], 'vae': ['3', 0]}},
'9': {'class_type': 'SaveImage', 'inputs': {'images': ['8', 0], 'filename_prefix': prefix}}
}これは ComfyUI のノードグラフを Python の辞書として表現したものだ。各ノードに番号を振って、['2', 0] というのが「ノード2の出力0番をここに繋げ」を意味する。GUI で線を引く操作を、辞書のデータ構造で表している。
これを JSON に変換して ComfyUI の /prompt エンドポイントに POST すると、ComfyUI がそのワークフローを実行して画像を生成する。
このスクリプト自体を Claude Code が書いた。「FLUX.2 で画像生成するスクリプトを作って」と頼んだら、ComfyUI の API 仕様を理解した上でワークフロー JSON を動的に組み立てるコードを書いてくれた。
さらに「参照画像を使ったキャラ一貫性(Redux)が欲しい」と言えば、Redux ノードを追加したワークフローの新スクリプトが生まれる。「インペインティングも欲しい」と言えば、マスク処理のノードを組み込んだスクリプトが増える。ComfyUI を使っているのに、GUI をほとんど開かない状態になった。
実質ガチャである
正直に書くと、画像生成はそんなにスマートではない。
Redux で参照画像を渡しても、キャラクターの一貫性が保たれるときとそうでないときがある。手が3本生えていたり、指の数がおかしかったり、破綻した画像が平気で出てくる。1回の指示で完璧な挿絵が出るわけではない。
やっていることは実質ガチャだ。1回の生成で5〜6枚出して、まともなものを選ぶ。設定を追い込めばもっと安定するのかもしれないが、今のところ「数を出して当たりを引く」が現実的な運用になっている。
面白いのは、人と AI の役割分担が自然に生まれたことだ。たとえばインペインティング——画像の一部だけを塗り直す処理——では、Claude がワークフローを組んで ComfyUI にアップロードするところまでやってくれる。そこから先、Web UI を開いて「ここを直したい」とマスクを描くのは私の仕事だ。Claude はワークフローの構築が得意で、私は目で見て判断するのが得意。それぞれ得意なところを持ち寄る形になっている。
NanoBanana Pro を使っていた頃の「生成 → ダウンロード → 変換 → 配置 → コード追加」という手順の大部分が「挿絵を作って」の一言になったのは大きい。ガチャを回すのも選ぶのも Claude がやってくれる。当たりが出るまで回して、ビルドが通るところまで持っていく。全部任せきりではないが、ComfyUI という共通の作業台があることで、AI とのコラボレーションが成り立っている。
そして ComfyUI の可能性は画像生成だけに留まらない。カスタムノードを追加すれば、同じノードベースの仕組みで TTS(テキスト読み上げ)、動画生成、音楽生成までできる。実際、TTS のノードはもう動いている。
コンテナ間を API で繋ぐという発想で広げれば、VOICEVOX のような専用エンジンも同じ構造に乗る。さらに n8n のようなワークフロー自動化ツールと組み合わせれば、生成の連鎖——画像を作って、音声を乗せて、動画にまとめる——といった流れも組める。Claude が JSON でワークフローを組み、API で各コンテナに投げる。画像も音声も動画も、同じパターンで扱える土台がここにある。
画像生成サービスを使っていた頃、こうなるとは想像していなかった。ComfyUI を触ってみたいという好奇心から始まって、気づいたら GUI の外に出てしまった。API の向こう側に、画像だけでは収まらない世界が広がっていた。