LLM Text Generator
A Full LLM Inside Your ComfyUI Graph — Local or API, No Heavy Setup
- images
- videos
- video_audios
- audios
- text
- reasoning
LLM Text Generator is the flagship of the zyd232 pack, and it's a lot more than a chat widget bolted onto a canvas. It's a complete OpenAI-compatible client in one node - point it at Ollama, vLLM, llama.cpp, or any real API, and it'll call {base_url}/v1/chat/completions, stream the answer to a floating panel in real time, and hand you clean text (and optionally the model's reasoning) as outputs your workflow can use. If you've ever wanted an LLM to rewrite your rough idea into a prompt, caption an image, or write dialogue for an image-to-video clip inside the same graph that generates, this is the shape of thing you want.
The name is almost a lie in the best way: for local servers like Ollama the default api_key of sk-no-key-required is all you need. No key, no account. You're only adding an API key if you point it at a hosted service.
What you actually set
The node has a wall of inputs, but a beginner only touches a handful:
- base_url - the server address (default
http://127.0.0.1:8080). Swap it for whatever yours listens on; Ollama's OpenAI endpoint is usuallyhttp://127.0.0.1:11434, vLLM typicallyhttp://localhost:8000. The node appends/v1/chat/completionsfor you. - model / model_NoVision - the vision model (used when you feed it images/video/audio) and the text-only model (used when you don't). You can type names or use the dropdowns; there's a refresh button that asks the server what it actually has.
- system_prompt and user_prompt - the usual suspects.
- temperature - higher is looser, lower is more stable.
Then the extras that earn their keep: config_name + the 💾 save button stores everything (URL, key, models, prompts) as a named preset and hides your API key behind ********; the key also accepts ENV:MY_VAR so you never paste a secret into a workflow you share.
Multimodal, streaming, and the output that matters
This is where it stops being a toy. The images, videos, video_audios, and audios inputs are autogrow - connect one, another appears, up to 32 each. Images go in as base64 PNG; videos get frame-sampled (the video_fps control samples frames from a 24fps source, capped by max_video_frames so you don't blow the context window); audio needs enable_audio flipped on and a model that supports it.
The node streams tokens over ComfyUI's websocket to a floating "Streaming Text" panel that follows the node around. Two outputs come out the right side: text (the answer) and reasoning (the thinking process, if you turn on thinking - it wraps the model's chain-of-thought in <think>/</think> tags and separates it from the final answer).
The one feature worth calling out: Lock result. Run once, hit 🔒, and the output is embedded in the workflow. Re-run (or send the file to a friend) and the node returns the locked text without calling the LLM at all - no API cost, no dependency on the server still being up.
Install
This is the only "heavy" node in the pack, and even it is light. The real dependency is a running LLM server - the node needs no OpenAI SDK, just Python's stdlib plus aiohttp, which ComfyUI already ships. Install as usual:
cd ComfyUI/custom_nodes
git clone https://github.com/zyd232/ComfyUI-zyd232-Nodes.git
Restart, and search "LLM Text Generator" (category zyd232 Nodes/LLM). Note the pack is built on the V3 backend node API, so keep ComfyUI reasonably current.
Where people get burned
- Wrong base_url. The default
8080is nobody's real default; a "connection refused" almost always means the server isn't there or isn't running. - Dropdowns are empty until you refresh. Hit 🔄 Refresh Model List once the server is up.
- Numbering off by one. Input ports are
image_0,image_1… but the prompt labels sent to the model are 1-based - refer toimage_1in your prompt when you mean portimage_0. It's a documented quirk, but it'll trip you up exactly once. - Fallbacks exist. A 404 on
/v1auto-retries without it; a failed no-vision model falls back to the vision model. Usually invisible, occasionally surprising. - It's a small, new pack. LLM nodes are arbitrary Python that reaches the network - the exact category weaponized once already (the LLMVISION incident). Read what a fresh clone does before trusting it with a real API key; this one's source is open - do that.
Bottom line
If you already run Ollama and want a clean, streaming, multimodal LLM node inside your workflow - presets, reasoning separation, lock-result escape hatch - this is a strong pick.
Inputs (37)
| Name | Type | Default | Description |
|---|---|---|---|
| config_select | COMBO | Choose a saved server preset | |
| config_name | STRING | Default | Name for this preset; illegal characters are removed automatically |
| server_type | COMBO | auto | LLM server type. Determines how unload, reasoning_effort and payload are sent to the server. 'auto' probes the server automatically. |
| base_url | STRING | http://127.0.0.1:8080 | AI service URL, e.g. Ollama or vLLM endpoint |
| api_key | STRING | sk-no-key-required | API key, or ENV:var_name to read from environment |
| model_select | COMBO | Dropdown to select a vision model. Selection will fill the 'model' field below. | |
| model | STRING | Vision model name (free input). Can be typed manually or selected from the dropdown above. | |
| model_NoVision_select | COMBO | Dropdown to select a text-only model. Selection will fill the 'model_NoVision' field below. | |
| model_NoVision | STRING | Text-only model name (free input). Used when no image/video/audio is provided. | |
| system_prompt | STRING | You are a helpful AI assistant. | System prompt that defines the AI's role and behavior |
| user_prompt | STRING | Describe this image or answer my question. | Your question or instruction for the AI |
| temperature | FLOAT | 0.700–2 | Randomness: higher is more creative, lower is more stable |
| top_k | INT | 401–100 | Pick next word from top K candidates |
| seed | INT | -1-1–18446744073709550000 | Random seed for reproducibility, -1 for random |
| context_length | INT | 2048-1–128000 | Context window size. Set to -1 or 0 to omit num_ctx/n_ctx and let the server use its default context length |
| timeout | INT | 1801–3600 | Timeout in seconds for the LLM generation request |
| reasoning_effort_select | COMBO | Choose reasoning effort | Dropdown to pick a reasoning effort. Selection will fill the 'reasoning_effort' field below. |
| reasoning_effort | STRING | off | Reasoning effort sent to the server (requires the LLM server to enable its Jinja template). Can be typed manually or selected from the dropdown above. 'off'/'none' disables thinking. |
| separate_thinking | BOOLEAN | false | Separate AI's thinking process from final answer |
| think_start_tag | STRING | <think> | Opening tag to mark the start of thinking content |
| think_end_tag | STRING | </think> | Closing tag to mark the end of thinking content |
| clean_comfy_vram_before_gen | BOOLEAN | false | Clear ComfyUI VRAM before generation to avoid OOM |
| unload_after_gen | BOOLEAN | false | Unload model after generation to free VRAM |
| unload_endpoint | STRING | auto | API endpoint path for unloading the model. 'auto' uses the endpoint preset for the selected Server Type; a custom value is used as-is. |
| unload_timeout | INT | 10–60 | Max seconds to wait for the server to finish unloading before proceeding. Uses a hybrid strategy: sends the unload request synchronously, then polls /v1/models to confirm the model is released. A timeout prevents the node from blocking the workflow indefinitely if the server is slow. 0 means do not wait and continue immediately. |
| cache_prompt | BOOLEAN | false | Cache prompts to speed up repeated requests |
| auto_lock | BOOLEAN | false | When enabled, the Streaming Text panel automatically locks the result once generation completes |
| frame_step | INT | 1 | Frame sampling interval per reference video: keeps 1 frame out of every frame_step source frames (n = ceil(total / frame_step)), then capped by max_video_frames. Default 1 (keep every frame). |
| max_video_frames | INT | -1 | Maximum number of frames sent per video (to avoid exceeding context length). Set to -1 or 0 to disable the cap and send all frames. |
| enable_audio | BOOLEAN | false | Encode and send audio references to the API (only if the model supports audio) |
| use_locked | BOOLEAN | false | When true, skip LLM generation and return the locked result |
| locked_text | STRING | Locked final text returned when use_locked is true | |
| locked_reasoning | STRING | Locked reasoning text returned when use_locked is true | |
| imagesopt | COMFY_AUTOGROW_V3 | — | |
| videosopt | COMFY_AUTOGROW_V3 | — | |
| video_audiosopt | COMFY_AUTOGROW_V3 | — | |
| audiosopt | COMFY_AUTOGROW_V3 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| text | STRING | — |
| reasoning | STRING | — |