LiteLLMCompletionWithReflectionFilter
Ask the LLM, look at its answer, and ask again until it's right
- model
- messages
- reflection_filter
- Model
- Messages
- Completion
- Usage
This node is LiteLLMCompletion plus a feedback loop. It runs a completion, hands the result to a "reflection filter" - a callable you connect - and if the filter returns new text, uses that as the next prompt and runs again. It keeps going until the filter returns None or you hit max_iterations. In other words: the model answers, a second brain reviews the answer, and the model gets another shot based on that review.
It's the standalone, one-node version of what AgentNode does with its recursion_filter. Where the agent machinery is built for loops over lists of prompts with memory, this one is the lightweight, single-track version: perfect when you just want a completion that gets one or two self-improvement passes and then stops.
How it works
The node literally reuses LiteLLMCompletion's handler and input schema, then wraps a loop around it. On each pass:
- The reflection filter is called with the current completion.
- If it returns
None, the loop stops - the answer is accepted as-is. - If it returns a string, that string becomes the new prompt, the conversation (
messages) carries the history, and the next completion runs.
The loop always runs at least once (the initial call), so max_iterations is effectively the number of extra review rounds you'll allow. Default is 10.
The inputs that matter
Everything from LiteLLMCompletion - model, prompt, max_tokens, temperature, top_p, the two penalties, reasoning_effort, plus optional messages and use_cached_response - and two additions:
max_iterations(default 10) - the cap on review rounds.reflection_filter(optional,CALLABLE) - the reviewer. Build it withCreateReflectionFilter(which wraps any callable, e.g. another LLM call, as a filter) orFirstCodeBlockReflectionFilter(which extracts the first code fence from the answer before passing it on). Leave it empty and the node behaves like a plainLiteLLMCompletion.
Outputs: Model, Messages, Completion, Usage.
Installing
ComfyUI Manager, search "ComfyUI_LiteLLM", or:
cd ComfyUI/custom_nodes
git clone https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM
cd ComfyUI_LiteLLM
pip install -r requirements.txt
Restart, provider key in your environment, done - it's under ETK/LLM/LiteLLM.
Where people get burned
The obvious one: every reflection round is another paid LLM call, and the default max_iterations of 10 is generous. A filter that never returns None will happily chew through all ten rounds on a single prompt. If you want at most one revision, set max_iterations to 1. Second, the filter contract is subtle - the loop checks for None to mean "stop." If your filter returns an empty string instead of None, that's not a stop, that's a new (blank) prompt, and you'll burn rounds on garbage. Third, a weak reflection filter can make answers worse - if your reviewer is a cheap model rubber-stamping everything, you've just doubled your bill for the same answer. The pattern only pays off when the filter genuinely critiques: use a capable model as the reviewer, or a filter that only rewrites when there's something to fix.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| model | LITELLM_MODEL | anthropic/claude-3-haiku-20240307 | — |
| max_tokens | INT | 2501–10000000000 | — |
| temperature | FLOAT | 0.500–1 | — |
| top_p | FLOAT | 0.500–1 | — |
| frequency_penalty | FLOAT | 0.00 | — |
| presence_penalty | FLOAT | 0.00 | — |
| prompt | STRING | Hello World! | — |
| reasoning_effort | COMBO | low | 3 options: low, medium, high |
| max_iterations | INT | 10 | — |
| messagesopt | LLLM_MESSAGES | — | |
| use_cached_responseopt | BOOLEAN | false | — |
| reflection_filteropt | CALLABLE | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| Model | LITELLM_MODEL | — |
| Messages | LLLM_MESSAGES | — |
| Completion | STRING | — |
| Usage | STRING | — |