Skip to content

Halogen vision requests get zero MTP draft tokens, so OCR decodes at 26 tok/s instead of the 44 tok/s the drafter delivers on text #439

Description

@mecattaf

MEASURED 2026-09-19 on the running Halogen 0.7.0 image (modules/halogen.nix, worker:8731). Three vision requests tonight, all temperature: 0, all through /v1/chat/completions with one image_url data URI, all returning finish_reason: stop.

request image thinking predicted_n draft_n draft_n_accepted predicted_per_second
tonight, regression table 1240 x 1755 PNG off 893 0 0 26.4
tonight, figure page 1240 x 1754 PNG off 144 0 0 25.8
tonight, figure page (self test) 1241 x 1754 PNG off 121 0 0 25.9

For comparison, the recorded handwriting run against the same server on 2026-09-14 (notes/references/devlogs/2h26/huion-notepad-pipeline/huion/ocr/runs/halogen-vanilla-2026-09-14/p01-response.json), also vision, also greedy, but with thinking left at the server default:

request predicted_n draft_n draft_n_accepted predicted_per_second
2026-09-14, handwriting page 650 460 279 44.3

So the drafter did engage on that run and does not engage on tonight's. The server advertises it as on:

drafters_available: ["serial", "mtp"]
drafter_default: "mtp"
drafter_weights_loaded: true
prompt_lookup: {ngram: 3, chain: 3, applies_to: "greedy requests with the mtp drafter"}

The difference between the two sets of requests is enable_thinking: false. That is the only field tonight's requests carry that the 2026-09-14 run did not. So the hypothesis worth testing first is that sending enable_thinking: false disables the MTP drafter as a side effect, the way /health already documents for a different field: tool_calls.forced_call_is_a_prefill: true and forced_call_disables_thinking: true show the server does couple these paths.

Why it is worth the look

Decode is the whole cost of an OCR page. The table page above spent 4.5 s in prefill and 33.8 s in decode. At 44 tok/s rather than 26 the same page is about 25 s instead of 42, which is a 1.7x change in the throughput of any page-at-a-time OCR campaign. Against the 156,811 pending pages of the academic corpus that is the difference between weeks and a month of GPU.

Asks

  1. Confirm or refute the coupling: one request with enable_thinking: false and one without, same image, and read draft_n on both. If thinking off is what costs the drafter, say so in /health the way the tool-call coupling is already stated.
  2. If they are independent, find what else about a vision request suppresses the draft. prompt_lookup.applies_to says "greedy requests with the mtp drafter" with no vision exclusion, so today the documentation and the counters disagree.
  3. If the coupling is real and intended, the OCR lane needs a ruling on which it wants: thinking off protects the token budget from a finish_reason=length discard, the drafter buys 1.7x on decode. They should not have to be traded blind.

This is a dotfiles issue because the image digest is pinned here (modules/halogen.nix) and the serving plane is dotfiles' domain. Nothing in it asks for a rebuild tonight.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions