OllamaとComfyUIの連携は、Ollamaに日本語の依頼を「決まった形のJSON」へ変換させ、検証を通った値だけを固定workflowに差し込んでComfyUIのAPIに送る形が最小構成です。LLMが解釈と構造化、ComfyUIが生成の実行を担当し、互いの内側には踏み込ませません。
情報確認日:2026年8月22日(日本時間)
結論:LLMに作らせるのはJSONだけ、実行はこちらのコードが握る
責任範囲
- Ollamaの
formatにJSON Schemaを渡し、日本語の依頼をprompt・seed等の少数fieldに変換する - 返ってきたJSONを自分のコードでSchema検証し、失敗したら生成に進まない
- 検証済みの値を、保存済みのAPI形式workflowの許可したfieldにだけ差し込む
POST /promptで送信し、/historyで結果を回収する- Ollamaの導入はOllamaの使い方、ComfyUIの基本操作はComfyUIの基本に任せ、この記事では扱わない
OllamaとComfyUIはどう役割を分けるか
Ollamaは「人の言葉を読み、決められた項目に整理する」役、ComfyUIは「整理された項目を受け取り、画像を作る」役です。この分け方を最初に決めておくと、後から評価や自動化を足すときも境界がぶれません。
Ollama(ローカルLLM)が担うこと
- 「夕方の海辺で本を読む猫、水彩風」のような日本語を読む
- 英語のprompt・negative prompt・サイズの種類など、決められた項目に整理する
- 項目はJSONとして返す。実行や保存はしない
ComfyUI(生成エンジン)が担うこと
- あらかじめ人が作って保存したworkflowを実行する
- checkpoint・sampler・解像度などの構造は人が決めたまま変えない
- 結果画像を出力し、APIで取り出せる状態にする
逆に、LLMにworkflowそのものやnode名を考えさせる構成は最初に選ばないでください。ComfyUIのnodeや接続は環境ごとに違い、LLMが出した名前が存在するとは限りません。この点は後の章で改めて扱います。
最小のデータフローはどうなるか
登場するのは5つの段階だけです。途中の「検証」は省略できる手順ではなく、LLMとComfyUIの間に置く関所です。
- User:日本語で依頼を書く
- Ollama:
/api/chatにSchema付きで送り、JSONを受け取る - Validation:自分のコードでSchema検証。型・必須項目・値の範囲を確認する
- ComfyUI:固定workflowの許可fieldに値を入れ、
POST /promptへ送る - Image:
GET /history/{prompt_id}でファイル名を取り、GET /viewで画像を取得する
接続先はどちらもローカルです。Ollamaは既定でhttp://localhost:11434、ComfyUIは既定でhttp://127.0.0.1:8188で待ち受けます。両方が同じPCで動いていれば、外部ネットワークを一切使わずに完結します。
Ollamaの/api/chatはstreamの既定値がtrueです。JSONを一括で受け取りたいので、この記事の例では明示的に"stream": falseを付けています。
生成パラメータをLLMに作らせるにはどう頼むか
最初のSchemaは小さくします。promptとnegative prompt、seed、縦横の種類くらいに絞ると、検証も失敗の切り分けも簡単です。項目を増やすのは、10件程度の依頼で安定して通ることを確認してからで十分です。
Ollamaの公式ドキュメントでは、JSON Schemaオブジェクトをformatに渡す方法が案内されています。あわせて、temperatureを下げることと、Schemaをprompt本文にも書いてモデルに示すことが推奨されています。
{
"model": "gemma3",
"stream": false,
"options": { "temperature": 0 },
"messages": [
{
"role": "system",
"content": "あなたは画像生成の指示を整理する係です。日本語の依頼を読み、英語のpromptとnegative_prompt、seed、aspectを決めてJSONだけを返してください。aspectは square / portrait / landscape のいずれかです。seedは0以上の整数で、指定がなければ-1にしてください。"
},
{ "role": "user", "content": "夕方の海辺で本を読む猫。水彩画っぽく、文字は入れないで。" }
],
"format": {
"type": "object",
"properties": {
"prompt": { "type": "string" },
"negative_prompt": { "type": "string" },
"seed": { "type": "integer" },
"aspect": { "type": "string", "enum": ["square", "portrait", "landscape"] }
},
"required": ["prompt", "negative_prompt", "seed", "aspect"]
}
}
モデル名は手元でollama pull済みのものに置き換えてください。どのモデルが日本語の読み取りに向くかは環境と用途で変わるため、この記事では特定のモデルを推奨しません。
受け取る側で確認する項目
応答のmessage.contentにJSON文字列が入ります。ここをJSON.parseやjson.loadsで読み、次を自分のコードで確認します。
- JSONとして構文的に読めたか
- Schemaの
requiredが全部そろっているか seedが整数で、許容範囲(例:-1または0〜2^32-1)に収まるかaspectがenumのどれかかpromptが空でなく、文字数上限(例:800字)を超えていないか
Ollama側のformat指定は「その形に寄せる」仕組みであり、受け取る側の検証を省いてよい保証ではありません。検証を二重に置く理由はここにあります。
ComfyUIへ安全に渡すにはどうするか
ComfyUIへ送るのは、UIで作って保存したworkflowをAPI形式で書き出したJSONです。書き出し方法はComfyUI APIの使い方を参照してください。LLMの出力からこのJSONを組み立てるのではなく、完成したJSONを読み込んで、決めておいたnode IDの決めておいたfieldだけを書き換えます。
import json, copy, urllib.request
ALLOWED = {
"prompt": ("6", "text"), # CLIPTextEncode (positive)
"negative_prompt": ("7", "text"), # CLIPTextEncode (negative)
"seed": ("3", "seed"), # KSampler
}
SIZES = {"square": (1024, 1024), "portrait": (832, 1216), "landscape": (1216, 832)}
def build(base_workflow: dict, params: dict) -> dict:
wf = copy.deepcopy(base_workflow)
for key, (node_id, field) in ALLOWED.items():
wf[node_id]["inputs"][field] = params[key]
w, h = SIZES[params["aspect"]]
wf["5"]["inputs"]["width"] = w # EmptyLatentImage
wf["5"]["inputs"]["height"] = h
return wf
def submit(wf: dict) -> str:
body = json.dumps({"prompt": wf, "client_id": "ollama-bridge"}).encode()
req = urllib.request.Request("http://127.0.0.1:8188/prompt", data=body,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req) as res:
return json.load(res)["prompt_id"]
node IDの"3"や"6"は、自分が保存したworkflowのJSONを開いて確認した番号に置き換えます。workflowが変わればIDも変わるため、ALLOWEDは「このworkflow専用の許可表」として一緒に管理してください。
seedが-1のときは、ここでコード側が乱数を引いて整数にしてから入れます。ComfyUI側に-1の解釈を任せない方が、あとで同じ画像を再現しやすくなります。
POST /promptの応答にnode_errorsが含まれている場合、workflowの構造か値が受理されていません。LLMの出力を疑う前に、まず人が作ったworkflowを手で送って通ることを確認してください。
結果をLLM側へ戻すべきか
最小構成では戻しません。生成が終わったらGET /history/{prompt_id}で出力ファイル名を取り、GET /view?filename=...&type=outputで画像を保存して終わりです。そこに「元の日本語の依頼」「Ollamaが返したJSON」「差し込み後のworkflow」「prompt_id」を一緒に記録しておけば、人が後から見直せます。
「画像が依頼どおりか」をローカルのVision Language Modelに判定させ、外れていればpromptを直してもう一度回す、という閉ループは次の段階です。判定に使うモデルの選び方と評価の型は別記事で扱います。この記事の段階では、まず「変換→検証→生成→記録」が10回連続で壊れないことを確かめてください。
自由文をそのまま実行しないために何を禁じるか
LLMに自由に作らせてはいけないものを先に決めておくと、連携は安全なまま広げられます。
| LLMに作らせないもの | 理由 | 代わりにすること |
|---|---|---|
| ファイルパス・保存先 | 出力先や読み込み元を外へ向けられる | 保存先はコード側の定数にする |
| node名・node構成 | 存在しないnodeや壊れた接続を生む | 人が保存したworkflowのfieldだけ許可する |
| checkpoint・LoRAのファイル名 | 未確認のmodel読み込みにつながる | 許可リストからコード側で選ぶ |
| コード・コマンド | 実行環境そのものを操作できてしまう | JSONの値以外は受け取らない |
| 解像度・steps等の数値の自由入力 | 極端な値でVRAM不足や長時間実行を招く | enumや上限付きの整数に制限する |
この記事の例でaspectを自由な幅・高さではなく3択にしたのも同じ理由です。「LLMが決めてよい自由度」を狭くしておくと、検証コードも短く、失敗時の原因も読み取りやすくなります。
日本語依頼10件で変換を検証する手順
連携が使えるかどうかは、手元のモデルと依頼の書き方で変わります。数値を断定する代わりに、同じ条件で再現できる記録の取り方を示します。
- 日本語の依頼を10件用意する。主題だけの短文、画風指定あり、サイズ指定あり、否定指示あり、曖昧な文を混ぜる
- モデルとtemperatureを固定し、1件ずつ
/api/chatへ送る - 応答ごとに「JSONとして読めたか」「Schema検証を通ったか」「人が見て意図に合うか」を記録する
- 通らなかった件は、system promptを直すのか、Schemaの項目を減らすのかを分けて判断する
| No | 日本語の依頼(要約) | JSON構文 | Schema検証 | 意図一致(人の判断) | メモ |
|---|---|---|---|---|---|
| 1 | 主題のみ | ||||
| 2 | 画風指定あり | ||||
| 3 | サイズ指定あり(縦長) | ||||
| 4 | 否定指示あり(文字なし) | ||||
| 5 | seed指定あり | ||||
| 6 | 曖昧な文 | ||||
| 7 | 複数主題 | ||||
| 8 | 長文 | ||||
| 9 | 英語混じり | ||||
| 10 | Schema外の要求(保存先指定など) |
見るべきポイントは3つあります。JSON構文で落ちるならモデルかformat指定の問題、Schema検証で落ちるならenumや範囲の伝え方の問題、意図一致で落ちるならsystem promptの指示の問題です。10番のように「Schemaにない要求」を混ぜるのは、LLMがそれを無視して決められた項目だけ返すかを確かめるためです。
よくある質問
Ollamaが返すJSONは毎回同じ形になりますか?
Schema付きのformatでかなり安定しますが、保証ではありません。受け取る側の検証を省かず、通らなかった件は記録して原因を分けてください。
日本語のpromptをそのままComfyUIに入れてはいけませんか?
使うcheckpointのtext encoderが日本語をどの程度扱えるかに依存します。この記事でLLMに英語promptを作らせているのは、その差を吸収するためです。日本語のまま通るmodelなら、Schemaのpromptを日本語で返させても構いません。
Tool Callingを使えばもっと簡単になりますか?
LLMに「どの関数をどの引数で呼ぶか」を決めさせる形は、この記事の構成の延長線上にあります。ただし引数の検証と実行権限の設計が先に必要なので、まずJSON変換だけで安定させてから別記事の内容に進んでください。
まとめ
OllamaとComfyUIの連携は、LLMにJSONを作らせ、検証を通った値だけを固定workflowに差し込む形が最小です。Ollamaは/api/chatのformatにSchemaを渡し、ComfyUIはPOST /promptで受け取ります。
パス・node・コードをLLMに自由生成させないこと、Schemaは小さく始めること、10件の記録表で壊れる場所を特定することの3点を守れば、後からVLM評価や自動化を足しても土台は変わりません。