<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Test-Time-Compute on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/test-time-compute/</link><description>Recent content in Test-Time-Compute on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Fri, 12 Jun 2026 05:30:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/test-time-compute/index.xml" rel="self" type="application/rss+xml"/><item><title>Serving reasoning models: the invisible scratchpad that decides your latency and your bill</title><link>https://blog.lo0.es/en/posts/serving-reasoning-models-invisible-scratchpad-latency-bill/</link><pubDate>Fri, 12 Jun 2026 05:30:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/serving-reasoning-models-invisible-scratchpad-latency-bill/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>A reasoning model generates, before the answer you see, a &lt;strong>thinking block&lt;/strong>, hundreds or thousands of tokens enclosed between &lt;code>&amp;lt;think&amp;gt;&lt;/code> and &lt;code>&amp;lt;/think&amp;gt;&lt;/code>, that the user does not read but that &lt;strong>consumes the same compute, the same VRAM and the same bill&lt;/strong> as any other token. Serving them in production is not &amp;ldquo;serving a bigger model&amp;rdquo;: it is serving a model whose cost per request is &lt;strong>variable and, by default, uncontrolled&lt;/strong>. Three levers change the equation: choosing well between &lt;strong>think / non-think mode&lt;/strong> (the hybrid models of 2026 allow it within the same weights), setting a &lt;strong>reasoning budget&lt;/strong> (&lt;code>thinking_token_budget&lt;/code> in vLLM, s1-style &lt;em>budget forcing&lt;/em>) and &lt;strong>measuring the impact on the KV cache&lt;/strong> (a 30k-token reasoning chain can eat ~9 GB of KV in FP16). Managed well, you gain accuracy where it matters; managed badly, you pay up to &lt;strong>113× more energy&lt;/strong> for an answer that did not need that much thinking.&lt;/p>
&lt;hr>
&lt;h2 id="the-analogy">The analogy&lt;/h2>
&lt;p>Picture a candidate sitting a competitive exam. Before writing the good answer on the official sheet, they fill three sheets of scratch paper: they try approaches, correct themselves, discard. Those scratch sheets are not handed in, the board only reads the final answer, but the candidate has spent ink, time and half an hour of the exam on them.&lt;/p>
&lt;p>A reasoning model does exactly that. The &lt;code>&amp;lt;think&amp;gt;…&amp;lt;/think&amp;gt;&lt;/code> block is the scratch paper: it reasons out loud, contradicts itself, backtracks, and finally emits the &amp;ldquo;clean&amp;rdquo; answer. The production problem is that &lt;strong>you pay for the scratch paper too&lt;/strong>: every reasoning token takes a slot in the batch, grows the KV cache and adds to the bill just like an output token. And, like any nervous candidate, the model tends to &lt;strong>overthink&lt;/strong>: it writes five sheets when one would have done.&lt;/p>
&lt;p>The operational question in this post is not &amp;ldquo;does it reason well?&amp;rdquo;, but &amp;ldquo;how much scratch paper do I let it write, and when do I take the pen away?&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="what-changes-when-the-model-thinks">What changes when the model &amp;ldquo;thinks&amp;rdquo;&lt;/h2>
&lt;p>In a normal model, a request is: prompt → output tokens. In a reasoning model the sequence has two stretches:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Reasoning block&lt;/strong> (&lt;code>&amp;lt;think&amp;gt; … &amp;lt;/think&amp;gt;&lt;/code>): the chain of thought (CoT). Long, variable, normally hidden from the end user.&lt;/li>
&lt;li>&lt;strong>Final answer&lt;/strong>: what the user sees.&lt;/li>
&lt;/ol>
&lt;p>vLLM models this explicitly. When started with a &lt;em>reasoning parser&lt;/em>, the output carries a &lt;code>reasoning_content&lt;/code> field separate from &lt;code>content&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-32B &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --reasoning-parser deepseek_r1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The parser detects the thinking delimiters and separates both stretches in the API response (&lt;a href="https://docs.vllm.ai/en/stable/features/reasoning_outputs/">vLLM · Reasoning Outputs&lt;/a>). This matters for serving for one practical reason: if your gateway or your UI does not separate &lt;code>reasoning_content&lt;/code> from &lt;code>content&lt;/code>, you will end up showing the scratch paper, or, worse, recording it in logs and traces without meaning to.&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 210" role="img" aria-label="Anatomy of a request to a reasoning model: prompt, thinking block with budget, final answer" xmlns="http://www.w3.org/2000/svg">
&lt;defs>&lt;marker id="rzm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.3}.dsh{fill:none;stroke:currentColor;stroke-width:1.3;stroke-dasharray:5 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.3;marker-end:url(#rzm)}&lt;/style>
&lt;text x="20" y="28" class="tl">Request&lt;/text>
&lt;rect class="bx" x="20" y="38" width="120" height="50" rx="6"/>
&lt;text x="32" y="60" class="ts">prompt + system&lt;/text>
&lt;text x="32" y="76" class="ts">(visible · billable)&lt;/text>
&lt;path class="ar" d="M140,63 L180,63"/>
&lt;text x="190" y="28" class="tl">Reasoning block &amp;lt;think&amp;gt; … &amp;lt;/think&amp;gt;&lt;/text>
&lt;rect class="dsh" x="190" y="38" width="360" height="80" rx="6"/>
&lt;text x="204" y="60" class="ts">hundreds–thousands of tokens HIDDEN from the user&lt;/text>
&lt;text x="204" y="78" class="ts">grow the KV cache · add to the bill as output&lt;/text>
&lt;text x="204" y="96" class="ts">cap: thinking_token_budget → forces &amp;lt;/think&amp;gt;&lt;/text>
&lt;path class="ar" d="M550,78 L590,78"/>
&lt;text x="600" y="28" class="tl">Answer&lt;/text>
&lt;rect class="bx" x="600" y="38" width="150" height="80" rx="6"/>
&lt;text x="612" y="64" class="ts">final content&lt;/text>
&lt;text x="612" y="82" class="ts">(all the user&lt;/text>
&lt;text x="612" y="98" class="ts">ever sees)&lt;/text>
&lt;text x="20" y="150" class="tl">Cost per request = prompt + reasoning + answer&lt;/text>
&lt;text x="20" y="172" class="ts">Reasoning is invisible in the UI but NOT on the GPU or in the bill. It is the variable that unbalances your cost per request.&lt;/text>
&lt;text x="20" y="192" class="ts">Operational rule: separate reasoning_content from content at the gateway, and set a thinking budget per route.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="the-2026-landscape-from-the-model-that-always-reasons-to-the-switchable-hybrid">The 2026 landscape: from the model that &amp;ldquo;always reasons&amp;rdquo; to the switchable hybrid&lt;/h2>
&lt;p>The first generation (o1, DeepSeek-R1, QwQ-32B) were models that always reasoned. In 2026 the dominant pattern is the hybrid: a single set of weights that switches between &lt;em>think&lt;/em> and &lt;em>non-think&lt;/em>.&lt;/p>
&lt;ul>
&lt;li>DeepSeek-V3.1 introduced a hybrid reasoning architecture in a single model: &lt;code>DeepSeek-V3.1-Think&lt;/code> for complex problems and a faster direct mode for the trivial, switchable by the user (&lt;a href="https://www.infoq.com/news/2025/09/deepseek-v31-hybrid/">InfoQ&lt;/a>). Important for serving: reasoning is off by default and is turned on with &lt;code>thinking=True&lt;/code> in &lt;code>chat_template_kwargs&lt;/code>.&lt;/li>
&lt;li>Qwen3 brings &lt;em>Hybrid Thinking Modes&lt;/em> and an explicit Thinking Budget to bound the reasoning compute; in its series thinking is on by default (like QwQ-32B).&lt;/li>
&lt;li>gpt-oss shows a different reasoning structure from the R1/Qwen family, which in practice means that &lt;strong>the parser and the delimiters are not universal&lt;/strong>: each family has its own.&lt;/li>
&lt;/ul>
&lt;p>The architectural consequence is clear: in 2026 you no longer decide &amp;ldquo;a model that reasons&amp;rdquo; vs &amp;ldquo;one that does not&amp;rdquo;, but &lt;strong>when you let the same model reason&lt;/strong>. That turns reasoning into a &lt;em>routing&lt;/em> and budgeting decision, not a model-catalogue one. It connects directly with &lt;a href="https://blog.lo0.es/en/posts/llm-inference-router-l7-switchboard/">the L7 inference router&lt;/a>: the &amp;ldquo;cheap&amp;rdquo; route turns thinking off; the &amp;ldquo;expensive&amp;rdquo; one turns it on with a cap.&lt;/p>
&lt;hr>
&lt;h2 id="the-economics-why-the-scratch-paper-drives-up-the-bill">The economics: why the scratch paper drives up the bill&lt;/h2>
&lt;p>Here is the heart of the problem. Reasoning tokens are invisible to the user but real in compute and in billing. Providers charge them as output tokens; API providers bill those &lt;em>reasoning tokens&lt;/em> at the output price, not for free (&lt;a href="https://medium.com/@Elongated_musk/test-time-compute-quietly-changed-the-economics-of-inference-9d0b8d77641c">Test-Time Compute Quietly Changed the Economics of Inference&lt;/a>). On-premise there is no external invoice, but there is a cost: they occupy batch slots, KV VRAM and watts.&lt;/p>
&lt;p>The billable cost (or the equivalent cost in GPU·hours) of a request is:&lt;/p>
$$\text{compute tokens} = \text{prompt} + \underbrace{\text{reasoning tokens}}_{\text{hidden, variable}} + \text{visible answer}$$
&lt;p>The middle term is the one that runs out of control. On hard tasks the reasoning/visible-answer ratio can be enormous, and empirical analysis has measured up to 113× the energy cost against standard inference on certain coding tasks (&lt;a href="https://towardsdatascience.com/inference-scaling-test-time-compute-why-reasoning-models-raise-your-compute-bill/">Towards Data Science · Inference Scaling&lt;/a>).&lt;/p>
&lt;p>And it does not always buy accuracy. The overthinking phenomenon is documented: more thinking does not guarantee a better answer, and beyond a certain point it makes things worse. There is work showing that &lt;strong>shorter chains are up to 34.5 % more accurate&lt;/strong> than the longest one sampled for the same question (&lt;a href="https://arxiv.org/pdf/2505.17813">Don&amp;rsquo;t Overthink it&lt;/a>), plus studies on the &amp;ldquo;mirage&amp;rdquo; of test-time scaling (&lt;a href="https://arxiv.org/pdf/2506.04210">Mirage of Test-Time Scaling&lt;/a>) and on when &lt;em>more thinking hurts&lt;/em> (&lt;a href="https://arxiv.org/html/2604.10739v1">When More Thinking Hurts&lt;/a>). The first large-scale study of test-time scaling, more than &lt;strong>30 billion tokens&lt;/strong> generated with 8 open-source LLMs from 7B to 235B across 4 reasoning datasets, systematises where it scales and where it does not (&lt;a href="https://arxiv.org/abs/2512.02008">The Art of Scaling Test-Time Compute&lt;/a>).&lt;/p>
&lt;p>The operational reading: &lt;strong>reasoning is a cost you have to budget for, not a &amp;ldquo;more quality&amp;rdquo; switch you leave on full all the time.&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="controlling-the-thinking-budget">Controlling the thinking budget&lt;/h2>
&lt;p>Three mechanisms, from coarsest to finest.&lt;/p>
&lt;h3 id="1-switching-think--non-think">1. Switching think / non-think&lt;/h3>
&lt;p>The cheapest thing is not to reason when it is not needed. On hybrid models, turn thinking off for classification, extraction, formatting, trivial answers:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># DeepSeek-V3.1: reasoning OFF by default; turned on explicitly&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">chat_template_kwargs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;thinking&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># only on the &amp;#34;hard&amp;#34; route&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is 80 % of the saving for 20 % of the effort: route by difficulty and reserve thinking for what actually pays for it.&lt;/p>
&lt;h3 id="2-setting-a-cap-thinking_token_budget">2. Setting a cap: &lt;code>thinking_token_budget&lt;/code>&lt;/h3>
&lt;p>vLLM ships a &lt;em>sampling parameter&lt;/em> &lt;code>thinking_token_budget&lt;/code> that counts reasoning tokens and, on reaching the limit, forces the block to close (&lt;code>reasoning_end_str&lt;/code>, typically &lt;code>&amp;lt;/think&amp;gt;&lt;/code>), making the model answer straight away. If it is not specified, there is no limit other than &lt;code>max_tokens&lt;/code> (&lt;a href="https://github.com/vllm-project/vllm/pull/37112">PR #37112&lt;/a>, &lt;a href="https://shuyo.wordpress.com/2026/03/26/adding-reasoning-budget-to-vllm-reasoning-token-limit/">implementation note&lt;/a>). Underneath, a &lt;code>ReasoningBudgetLogitsProcessor&lt;/code> injects something like &lt;em>&amp;ldquo;Let me stop thinking and answer now.&lt;code>&amp;lt;/think&amp;gt;&lt;/code>&amp;rdquo;&lt;/em> when the cap is reached.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Define the delimiters of the reasoning block&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vllm serve Qwen/Qwen3-32B &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --reasoning-parser qwen3 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --reasoning-config &lt;span class="s1">&amp;#39;{&amp;#34;reasoning_start_str&amp;#34;:&amp;#34;&amp;lt;think&amp;gt;&amp;#34;,&amp;#34;reasoning_end_str&amp;#34;:&amp;#34;&amp;lt;/think&amp;gt;&amp;#34;}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// per request: cut the scratch paper off at 1024 tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;messages&amp;#34;&lt;/span>&lt;span class="p">:[&lt;/span>&lt;span class="err">...&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nt">&amp;#34;thinking_token_budget&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1024&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-budget-forcing-state-of-the-art">3. Budget forcing (state of the art)&lt;/h3>
&lt;p>The technique that popularised fine-grained control is &lt;strong>budget forcing&lt;/strong>, from the s1 paper: to spend &lt;em>less&lt;/em>, thinking is terminated by forcing the end delimiter; to spend &lt;em>more&lt;/em>, the end is suppressed and the word &amp;ldquo;Wait&amp;rdquo; is appended, which pushes the model to review and often correct its own reasoning. With this, &lt;code>s1-32B&lt;/code> (a Qwen2.5-32B-Instruct fine-tuned on just 1,000 examples) &lt;strong>beat o1-preview by as much as 27 %&lt;/strong> on AIME24/MATH (&lt;a href="https://arxiv.org/abs/2501.19393">s1: Simple Test-Time Scaling&lt;/a>). The serving lesson: the budget is not only a cost cap, it is a &lt;strong>bidirectional quality lever&lt;/strong>.&lt;/p>
$$\text{accuracy} \approx f(\text{reasoning tokens}) \quad\text{with a maximum, not monotonic}$$
&lt;p>The curve rises, saturates and on many tasks falls. Your job is to operate it near the knee, not at the extreme.&lt;/p>
&lt;hr>
&lt;h2 id="the-impact-almost-nobody-measures-the-kv-cache">The impact almost nobody measures: the KV cache&lt;/h2>
&lt;p>This is where reasoning really bites serving. Every token of scratch paper &lt;strong>is one more token in the KV cache&lt;/strong>. A long reasoning chain inflates the working memory just like a long input context.&lt;/p>
&lt;p>The KV size grows linearly with the sequence (reasoning included):&lt;/p>
$$\text{KV bytes} = 2 \times L \times h_{kv} \times d_{head} \times s \times b$$
&lt;p>where \(L\) is layers, \(h_{kv}\) KV heads (few, with GQA), \(d_{head}\) the per-head dimension, \(s\) the sequence length and \(b\) the bytes per element. The term reasoning blows up is \(s\): a &amp;ldquo;normal&amp;rdquo; 500-token answer and one with 8,000 tokens of thinking do not take up the same space, not by a long way.&lt;/p>
&lt;p>The real numbers are frightening: for a distilled reasoning model with standard attention such as &lt;code>DeepSeek-R1-Distill-Llama-70B&lt;/code>, &lt;strong>a single 30,000-token reasoning chain consumes ~9 GB of KV in FP16&lt;/strong>, which quantising the KV to FP8 reduces to ~4.5 GB, one of the highest-impact optimisations for chain-of-thought workloads (&lt;a href="https://www.spheron.network/blog/kv-cache-optimization-guide/">Spheron · KV Cache Optimization&lt;/a>). Multiply that by concurrency and you understand why a cluster that served 200 simultaneous requests of a &amp;ldquo;normal&amp;rdquo; model drops to 40 with the same model reasoning.&lt;/p>
&lt;p>Two state-of-the-art nuances worth knowing:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Prefix caching is not free here.&lt;/strong> The empirical study of reasoning-model serving finds that &lt;em>prefix caching&lt;/em> clearly improves speed on models of 14B or more, but hurts on 7B models (cache management costs more than it saves) (&lt;a href="https://arxiv.org/pdf/2510.18672">Reasoning Language Model Inference Serving Unveiled&lt;/a>). And since the bulk of the reasoning cost sits in the decode (generating tokens one by one), prefix caching, which only speeds up the prefill, barely touches the expensive phase. It connects with &lt;a href="https://blog.lo0.es/en/posts/prefix-cache-hit-rate-engineering/">prefix cache: engineering the hit rate&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Reasoning-specific KV compression.&lt;/strong> Techniques such as R-KV have appeared, compressing the KV by exploiting the redundancy typical of chains of thought (the model repeats itself and rambles), recovering memory without touching quality (&lt;a href="https://arxiv.org/pdf/2505.24133">R-KV&lt;/a>).&lt;/li>
&lt;/ul>
&lt;p>The most profitable and available lever today is still &lt;strong>KV in FP8&lt;/strong> (see &lt;a href="https://blog.lo0.es/en/posts/fp8-end-to-end-enable-measure-quality-decide/">FP8 end to end&lt;/a>) combined with a reasoning budget that avoids 30k-token tails in the first place.&lt;/p>
&lt;hr>
&lt;h2 id="reasoning--structured-output-order-matters">Reasoning + structured output: order matters&lt;/h2>
&lt;p>If you serve &lt;em>structured output&lt;/em> (JSON with a schema) and reasoning at the same time, there is a subtle trap: the grammar must not be applied during the thinking block. The model needs free text to reason; forcing the schema inside the &lt;code>&amp;lt;think&amp;gt;&lt;/code> breaks the reasoning. vLLM solves it by having the structured-output engine (xgrammar) use the reasoner&amp;rsquo;s &lt;code>end_token_id&lt;/code> to skip the constraint while the block lasts and apply it only to the final answer (&lt;a href="https://docs.vllm.ai/en/stable/features/reasoning_outputs/">vLLM · Reasoning Outputs&lt;/a>). If you build this by hand on another engine, remember: &lt;strong>first let it think, then impose the form&lt;/strong>. It links with &lt;a href="https://blog.lo0.es/en/posts/structured-output-bitmask-outlines-xgrammar-llguidance/">structured output&lt;/a>.&lt;/p>
&lt;hr>
&lt;h2 id="reference-architecture">Reference architecture&lt;/h2>
&lt;p>On the blog&amp;rsquo;s example cluster, a node of 4×H100 SXM (80 GB, NVLink), a sensible topology for serving reasoning without wrecking the SLO:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>A cheap difficulty classifier&lt;/strong> up front (a small model or rules) that picks the route. Most of the traffic does not need to think.&lt;/li>
&lt;li>&lt;strong>Fast route (non-think):&lt;/strong> the same hybrid model with reasoning off. Low TTFT, predictable cost.&lt;/li>
&lt;li>&lt;strong>Reasoning route (think):&lt;/strong> reasoning on &lt;strong>with &lt;code>thinking_token_budget&lt;/code> by default&lt;/strong> (say 1–2k tokens) and the option to raise it per request for the genuinely hard cases.&lt;/li>
&lt;li>KV in FP8 in the engine on the reasoning route, plus per-request reasoning-length metrics exported to your observability (&lt;a href="https://blog.lo0.es/en/posts/instrumenting-vllm-otel-measuring-optimisations/">instrumenting vLLM with OTel&lt;/a>).&lt;/li>
&lt;/ol>
&lt;p>To prototype this routing outside the cluster, an RTX 5090 (Blackwell, 32 GB) serves a 7–14B reasoning model and lets you validate parsers, budgets and the &lt;code>reasoning_content&lt;/code>/&lt;code>content&lt;/code> separation before touching the H100s. Do not expect to serve a 32B in &lt;em>think&lt;/em> mode at high concurrency on a consumer card: the reasoning KV eats the 32 GB in no time.&lt;/p>
&lt;p>Sizing starts, as always, from an SLO; the difference is that now the &amp;ldquo;answer size&amp;rdquo; in your &lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">capacity planning&lt;/a> has to count the scratch paper, not just the visible answer.&lt;/p>
&lt;hr>
&lt;h2 id="operational-pitfalls-and-honest-scepticism">Operational pitfalls (and honest scepticism)&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Leaking &lt;code>reasoning_content&lt;/code>.&lt;/strong> If the gateway does not separate it, you end up showing or logging the scratch paper, which may contain wrong attempts, sensitive data or language you do not want in your UI. Always separate it at L7.&lt;/li>
&lt;li>&lt;strong>Serving reasoning &amp;ldquo;just in case&amp;rdquo;.&lt;/strong> Overthinking is real and sometimes lowers accuracy. Do not turn &lt;em>think&lt;/em> on by default: turn it on per route, with a budget.&lt;/li>
&lt;li>&lt;strong>Forgetting the KV.&lt;/strong> The most common mistake: sizing concurrency from the length of the visible answer. The KV is dictated by the total sequence, reasoning included. Measure p50/p95 &lt;code>reasoning tokens&lt;/code> per endpoint.&lt;/li>
&lt;li>&lt;strong>Prefix caching as a silver bullet.&lt;/strong> On small models it can make things worse, and in any case it does not touch the decode, which is where the reasoning cost goes.&lt;/li>
&lt;li>&lt;strong>Assuming universal delimiters.&lt;/strong> R1, Qwen3 and gpt-oss do not share a reasoning structure. Use the right &lt;code>--reasoning-parser&lt;/code> per family and test &lt;em>streaming&lt;/em> (the parser has to separate correctly token by token).&lt;/li>
&lt;li>&lt;strong>Believing more compute = more intelligence.&lt;/strong> The state of the art (s1, short-m@k, &amp;ldquo;When More Thinking Hurts&amp;rdquo;) points the other way in many cases: there is a knee, and operating beyond it is burning watts. Test-time compute is a tool with diminishing, and sometimes negative, returns, not a linear lever.&lt;/li>
&lt;/ol>
&lt;p>A note of caution for June 2026: the field of reasoning control (budget forcing, reasoning-specific KV compression, thinking &lt;em>early-exit&lt;/em>) moves fast and almost all of it is very recent. The specific figures, the 113×, the 34.5 %, the 9 GB, depend on model, task and configuration; take them as an &lt;strong>order of magnitude for design&lt;/strong>, not as constants. Measure on your own workload before committing to SLOs.&lt;/p>
&lt;hr>
&lt;h2 id="closing">Closing&lt;/h2>
&lt;p>Serving a reasoning model means serving a model whose cost per request &lt;strong>you decide with the thinking budget&lt;/strong>, not the catalogue. The chain goes: route by difficulty → turn &lt;em>think&lt;/em> off where it adds nothing → set &lt;code>thinking_token_budget&lt;/code> by default on the route that thinks → quantise the KV to FP8 → measure reasoning length as a first-class metric. Do that, and reasoning becomes a capability you pay for only when it buys accuracy. Do not, and your cluster will serve a fifth of the users while the model fills sheets of scratch paper nobody is going to read.&lt;/p>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>vLLM · Reasoning Outputs — &lt;a href="https://docs.vllm.ai/en/stable/features/reasoning_outputs/">https://docs.vllm.ai/en/stable/features/reasoning_outputs/&lt;/a>&lt;/li>
&lt;li>vLLM PR #37112 · reasoning_budget — &lt;a href="https://github.com/vllm-project/vllm/pull/37112">https://github.com/vllm-project/vllm/pull/37112&lt;/a>&lt;/li>
&lt;li>Adding Reasoning Budget to vLLM — &lt;a href="https://shuyo.wordpress.com/2026/03/26/adding-reasoning-budget-to-vllm-reasoning-token-limit/">https://shuyo.wordpress.com/2026/03/26/adding-reasoning-budget-to-vllm-reasoning-token-limit/&lt;/a>&lt;/li>
&lt;li>s1: Simple Test-Time Scaling — &lt;a href="https://arxiv.org/abs/2501.19393">https://arxiv.org/abs/2501.19393&lt;/a>&lt;/li>
&lt;li>The Art of Scaling Test-Time Compute — &lt;a href="https://arxiv.org/abs/2512.02008">https://arxiv.org/abs/2512.02008&lt;/a>&lt;/li>
&lt;li>Don&amp;rsquo;t Overthink it (short-m@k) — &lt;a href="https://arxiv.org/pdf/2505.17813">https://arxiv.org/pdf/2505.17813&lt;/a>&lt;/li>
&lt;li>Mirage of Test-Time Scaling — &lt;a href="https://arxiv.org/pdf/2506.04210">https://arxiv.org/pdf/2506.04210&lt;/a>&lt;/li>
&lt;li>When More Thinking Hurts — &lt;a href="https://arxiv.org/html/2604.10739v1">https://arxiv.org/html/2604.10739v1&lt;/a>&lt;/li>
&lt;li>Reasoning Language Model Inference Serving Unveiled — &lt;a href="https://arxiv.org/pdf/2510.18672">https://arxiv.org/pdf/2510.18672&lt;/a>&lt;/li>
&lt;li>R-KV: Redundancy-aware KV Cache Compression — &lt;a href="https://arxiv.org/pdf/2505.24133">https://arxiv.org/pdf/2505.24133&lt;/a>&lt;/li>
&lt;li>Spheron · KV Cache Optimization Guide (2026) — &lt;a href="https://www.spheron.network/blog/kv-cache-optimization-guide/">https://www.spheron.network/blog/kv-cache-optimization-guide/&lt;/a>&lt;/li>
&lt;li>Test-Time Compute Quietly Changed the Economics of Inference — &lt;a href="https://medium.com/@Elongated_musk/test-time-compute-quietly-changed-the-economics-of-inference-9d0b8d77641c">https://medium.com/@Elongated_musk/test-time-compute-quietly-changed-the-economics-of-inference-9d0b8d77641c&lt;/a>&lt;/li>
&lt;li>Inference Scaling (Test-Time Compute) · Towards Data Science — &lt;a href="https://towardsdatascience.com/inference-scaling-test-time-compute-why-reasoning-models-raise-your-compute-bill/">https://towardsdatascience.com/inference-scaling-test-time-compute-why-reasoning-models-raise-your-compute-bill/&lt;/a>&lt;/li>
&lt;li>DeepSeek-V3.1 Hybrid Reasoning · InfoQ — &lt;a href="https://www.infoq.com/news/2025/09/deepseek-v31-hybrid/">https://www.infoq.com/news/2025/09/deepseek-v31-hybrid/&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>