Reality Check (LM Studio)
A small vision model can't judge anatomy, but it can count
- image
- passed
- failed
- score
- report
- json
- image
Ask an 8B vision model "is this pose anatomically impossible?" and it will tell you no. Every time. Including a torso rotated through 180 degrees. This node exists because the author measured that, then built the version that works: don't ask a small model to judge - ask it perception questions with closed answers and do the inferring in Python.
How it works
The model gets asked things like how many heads, arms, hands, legs and feet it can see, whether two bodies look fused, whether front-of-body and back-of-body landmarks appear in the same figure, whether it can see breasts and shoulder blades. Each answer is scored, contradictions between answers become findings, and the worst weighted finding is compared to threshold (default 0.5, and findings land near 1.0, so it's a wide margin rather than a knife edge). One node, one image, passed / failed.
The defaults come from an acceptance run over a 17-image set with eight known-broken pictures: all eight broken ones caught, all eight good ones kept, twice, with different seeds. That's the kind of number that makes a filter usable instead of decorative.
Inputs
image,base_url(http://localhost:1234/v1, LM Studio's OpenAI-compatible endpoint),model- the vision model id. Leave it empty and you get whatever LM Studio has loaded, which is a coin flip; a text-only model answers nonsense.expected_people(default 1) - more heads or limbs than this allows counts as a defect.- The six probe toggles.
check_parts,check_peopleandcheck_landmarksare on;check_handsandcheck_physicsare off on purpose. They measured worse than useless: they never fired on a genuinely broken picture and occasionally fired on a clean one. An 8B model can't resolve fingers at any sane resolution, and it reads a compressed mattress as a body sinking through it.check_textis off unless you're rendering scenes with signage. max_image_size(1024) - below about 900 the giveaways blur away, which is a nice way of saying the check that catches extra limbs depends on actually being able to see them.passes+temperature+aggregation- run the probes several times and reduce withmedian,majority,meanormax. At temperature 0.1 repeated passes give identical answers, so raise both or leave both alone.on_error- the important one. Defaultpass: if the model can't be reached, the picture survives and the report says why. An inspector that can't see should never silently reject a batch.system_promptoverrides the tuned instrument prompt; empty uses the calibrated one.
Outputs are passed, failed, score, report (human-readable), json (the raw verdict) and image, passed straight through so you can chain this between the loader and the router.
Install
No Python dependencies at all - it's an HTTP client. What it needs is LM Studio running with a vision model loaded and its local server started.
cd ComfyUI/custom_nodes
git clone https://github.com/ping1979ping/comfyui-FVMtools
Restart ComfyUI, or install via Manager with comfyui-fvmtools. Then point base_url at LM Studio and name the model. Pair it with Reality Check Probe before you queue 300 runs.
Where people get burned
Censored models. Measured on an abliterated Qwen3-VL build. A stock instruct model refuses on lingerie or nude material, refuses silently, and every picture in the batch comes back as unavailable - which looks exactly like an endpoint problem. Use an uncensored build for that content.
VRAM. You're now running a VLM and a diffusion model on one card. Load a 4B vision model, not the 32B, and expect the reality check to be the slow step in the loop.
Wrong model name. LM Studio lists models it hasn't loaded, and a call to an unloaded model returns nothing useful. Start the server, load the model, check with the probe node, then queue.
Judging the judges. This node is deliberately narrow: it catches anatomical absurdity and fused bodies. It does not know whether your composition is boring, whether the prompt was followed, or whether the LoRA looks like the person. Use it as a gate in the sorting pipeline - it's a bouncer, not an art director.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| base_url | STRING | http://localhost:1234/v1 | LM Studio's OpenAI-compatible endpoint. |
| model | STRING | Vision model id. Empty uses whatever LM Studio has loaded. Needs a VLM — a text-only model answers nonsense. | |
| expected_people | INT | 11–10 | How many people the picture should show. More heads or limbs than this allows is a defect. |
| threshold | FLOAT | 0.500–1 | Fail when the worst weighted finding reaches this. Findings score ~1.0, so 0.5 is a wide margin. |
| passes | INT | 11–9 | Runs per probe. At temperature 0.1 repeats give identical answers — raise both together, or leave at 1. |
| temperature | FLOAT | 0.100–2 | — |
| aggregation | COMBO | median | How repeated passes are reduced. Only matters when passes > 1. |
| check_parts | BOOLEAN | true | Count heads, arms, hands, legs, feet — catches duplicated bodies and extra limbs. |
| check_people | BOOLEAN | true | Count people and spot merged bodies. |
| check_landmarks | BOOLEAN | true | Front-of-body and back-of-body landmarks seen at once — catches impossible torso twists. |
| check_hands | BOOLEAN | false | Finger counts. Off by default: small models cannot resolve fingers and raise false alarms. |
| check_physics | BOOLEAN | false | Floating bodies and limbs through furniture. Off by default: reads a compressed mattress as a body sinking through it. |
| check_text | BOOLEAN | false | Garbled lettering. Worth turning on for scenes with signage. |
| max_image_size | INT | 1024256–2048 | Long edge sent to the model. Below ~900 the giveaways blur away. |
| timeout | INT | 1205–900 | — |
| seed | INT | 00–18446744073709550000 | — |
| on_error | COMBO | pass | What to answer when the model cannot be reached. pass: keep the picture and say so — an inspector that cannot see should not reject a batch. |
| system_promptopt | STRING | Overrides the built-in instrument prompt. Empty uses the calibrated one. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| passed | BOOLEAN | — |
| failed | BOOLEAN | — |
| score | FLOAT | — |
| report | STRING | — |
| json | STRING | — |
| image | IMAGE | — |