Blog

Reasoning models, demystified: build a test-time-compute loop

“Reasoning model” sounds like marketing, but it names a concrete trick: spend more compute at inference and you often get a better answer. By the end of this post you’ll have a short self-consistency loop (about forty lines) that you can wrap around any chat model, local or hosted, to make it reason harder on the tasks that actually deserve it.

1. Train-time compute vs. test-time compute

For most of the deep-learning era, a better answer meant a bigger investment before the model ever met your prompt: more parameters, more data, more training. That’s train-time compute, and it’s fixed by the time you call the API.

The shift that defined 2025 was learning to spend on the other side of the clock. Test-time compute is computation spent at inference (generating a longer chain of reasoning, or sampling several attempts and reconciling them) to improve the answer without touching the trained weights. It’s a different axis: instead of paying once, up front, for a smarter model, you pay per query for a more deliberate one. The practical consequence is that you hold the dial. You can spend more on the hard questions and nothing extra on the easy ones.

2. What a reasoning model actually does

A reasoning model generates a long internal chain of thought (it “thinks” in tokens) before committing to a final answer. Those intermediate tokens are the test-time compute: the model works through the problem in writing, and that extra deliberation is what tends to buy the accuracy.

This is now an industry-wide pattern. OpenAI’s o-series and GPT-5 family (GPT-5 released August 2025) are built around it, and every major lab now ships a “thinking” mode of some kind. The mechanics differ, but the shape is the same: more tokens spent deliberating, then an answer. Which is also the sharp edge: those thinking tokens cost money and add latency, so “always reason” is not a free upgrade.

3. The landmark case: DeepSeek-R1

The result that made the mechanism concrete was DeepSeek-R1 (DeepSeek), whose paper, “DeepSeek-R1 incentivizes reasoning in LLMs through reinforcement learning”, was published in Nature in September 2025 as the journal’s cover article. The headline finding: strong reasoning behavior could be incentivized largely through reinforcement learning, rewarding the model for reaching correct answers rather than hand-labeling every step of the reasoning.

Two things are worth holding onto, and one worth resisting. Hold onto: reasoning is a learnable behavior, and it’s an inference-time behavior. The model produces more useful deliberation, and more deliberation is something you can also induce from the outside. Resist: the temptation to claim R1 “beats” some other model on some benchmark. The durable, defensible lesson here is the mechanism, not a leaderboard number.

4. The cheap DIY version: self-consistency

You don’t need a purpose-built reasoning model to get some of the benefit. Self-consistency (Wang et al., 2022) is a model-agnostic technique: instead of trusting a single greedy answer, sample several reasoning paths at nonzero temperature and take the majority answer. Where one attempt might slip on a single arithmetic step, a vote across several diverse attempts is more robust: the wrong answers scatter, the right one tends to pile up.

A close cousin is best-of-N with a verifier: generate N candidates, score each with something that can actually check them (a unit test, a schema validator, a second model), and keep the best. Reach for self-consistency when the answer collapses to a small discrete set you can vote on; reach for a verifier when you can mechanically check correctness.

The caveat: more sampling shifts the odds, it doesn’t repeal them. A model that is confidently and consistently wrong will vote itself a wrong majority. Self-consistency raises reliability; it does not guarantee correctness.

5. Wrap any chat model and vote

Here’s the whole loop. It talks to any OpenAI-compatible chat endpoint: a hosted API, or the local model from our laptop LLM tutorial, which exposes one at http://localhost:11434/v1. It samples N reasoned attempts, extracts each final answer, and returns the majority.

# self_consistency.py (Python 3.11+)
# pip install "requests==2.34.2"
import os, re, requests
from collections import Counter

BASE_URL = os.environ.get("LLM_BASE_URL", "http://localhost:11434/v1")  # local Ollama, or any OpenAI-compatible API
API_KEY  = os.environ.get("LLM_API_KEY", "not-needed-locally")
MODEL    = os.environ.get("LLM_MODEL", "qwen3:8b")                       # whatever you pulled / are serving

SYSTEM = "Reason step by step. End your reply with a line exactly like: Answer: <value>"

def call_model(prompt, temperature):
    r = requests.post(
        f"{BASE_URL}/chat/completions",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "model": MODEL,
            "messages": [
                {"role": "system", "content": SYSTEM},
                {"role": "user", "content": prompt},
            ],
            "temperature": temperature,
        },
        timeout=180,
    )
    r.raise_for_status()
    return r.json()["choices"][0]["message"]["content"]

def final_answer(text):
    hits = re.findall(r"Answer:\s*(.+)", text, flags=re.IGNORECASE)
    return hits[-1].strip() if hits else None

def self_consistency(prompt, n=5, temperature=0.8):
    votes = [a for a in (final_answer(call_model(prompt, temperature))
                         for _ in range(n)) if a]
    if not votes:
        return None, []
    winner, _ = Counter(votes).most_common(1)[0]
    return winner, votes

if __name__ == "__main__":
    q = "A shirt costs $40 after a 20% discount. What was the original price, in dollars?"
    answer, votes = self_consistency(q, n=5)
    print("votes :", votes)
    print("answer:", answer)

The important choices: temperature is above zero so the samples actually differ (self-consistency needs diverse paths, not five copies of the same one); the system prompt forces a parseable Answer: line so the vote is over clean values; and the aggregation is a plain majority with collections.Counter. Swap MODEL for whatever you’re running. To hide the latency, fire the N calls concurrently rather than in a loop; they’re independent.

6. When it’s worth it, and when it isn’t

Reasoning is not free. N samples cost roughly N times the tokens, and (unless you parallelize) N times the latency. So spend the budget where a wrong answer is expensive and the answer is checkable or discrete: math, extraction you can validate, classification, code that either runs or doesn’t. Don’t spend it on simple lookups, high-volume low-stakes calls, or latency-critical paths where a single fast pass is the right call.

And whatever you do, keep a check on the value, not just the vote count. The whole point of test-time compute is to trade compute for reliability — but reliability you can measure, not assume. Working out where reasoning actually pays off in a product (which requests deserve the extra compute and which don’t) is exactly the kind of question a short architecture review with CloudSignal is built to answer.

Sources / further reading

Written by Ashwin Rajendraprasad for CloudSignal AI. The code above is free to reuse.