LLM sampling stunts

Inference-time-scaling considered unreasonably accurate

2026-07-30 — 2026-08-30

quality 8.4

Wherein Is Charted the Design Space of Mathematical Reasoning Systems—solvers, Provers, and Autoformalizers—noting That a Lean Compiler’s Exact Verdict Permits Sampling Budgets Into the Thousands, Unlike Majority-Vote Solvers.

compsci
language
machine learning
meta learning
Monte Carlo
neural nets
NLP
particle
state space models
stochastic processes
time series
Figure 1

I noticed that there are a number of interesting sampling tricks for LLMs which seem related. The category in my mind is something like sampling from LLMs in ways that resemble classic particle methods, i.e. using the kinematics of multiple hypothetical trajectories to inform the next step(s). So! A new notebook!

What do I mean? I mean the Sequential Monte Carlo (SMC) steering trick for LLMs (Lew et al. 2023): instead of decoding one continuation—or keeping a fixed beam—we keep a small population of \(N\) candidate continuations, score them against a desired constraint or reward, then repeatedly resample promising candidates as generation proceeds. This can enforce constraints or steer semantic properties at inference time without retraining the base model, and should look reminiscent of particle filtering except the likelihood is even of a dog’s breakfast.

Relatedly, LLaMPPL (Lew et al. 2023) claims to be a Probabilistic Programming Language for LLMs based on this idea. It uses Sequential Monte Carlo (SMC) methods to perform probabilistic inference over the outputs of LLMs, which seems logical for prefix sampling; I’m a bit confused about how it works for infill sampling.

Basic idea: We treat a completion \(y = (y_1,\ldots,y_T)\) as a trajectory sampled from the stochastic base model \(p_\theta(y\mid x)\), assuming that it is from something similar to, but not the same as, the target distribution that we want to hit,

\[ \pi(y\mid x) \propto p_\theta(y\mid x)\,R(y) \]

where \(R(y)\) is a score—e.g. “is valid JSON,” “satisfies this regex/grammar,” “answers both prompts,” “is non-toxic,” or “meets a programmatic verifier.”

We…

  1. Maintain \(N\) partial completions.
  2. Sample the next token (or tokens) for each from the “base” LLM (which in SD-SMC might a different model entirely)
  3. Give each continuation an incremental weight based on how well it is doing under the constraint.
  4. When weights become concentrated, resample: copy high-weight trajectories and discard weak ones.
  5. Continue until completion; return a high-weight sample or sample from the final weighted population.

The point of distinction from simple rejection sampling is that SMC does not wait until the entire response is finished to discover failure. It can prune bad paths early and concentrate compute on promising ones.

The “trick” is worthwhile because sometimes we can write a prefix-aware potential—a function that scores a partial answer, not merely a final answer.

Examples:

Goal Useful incremental signal
Strict JSON Parser state; zero/near-zero weight for impossible prefixes
A required phrase/list of facts Which requirements remain satisfiable or already met
Code with tests Compile/type-check signals, partial static analysis, or a verifier near completion
Prompt intersection Likelihood or task score under each of several prompts
Style/safety steering A classifier or discriminator score applied to partial text

For hard constraints, a particle that makes the remaining task impossible gets weight zero. For soft preferences, the weight rises smoothly for “better” paths.

The original SMC-steering formulation frames constrained language generation as posterior inference in a discrete sequence model. It reports capabilities including infilling, syntactic constraints, and “prompt intersection,” at a computational cost comparable to beam search.

LLM vibe-coded pseudo-code example:

particles = [("", 0.0, cache_i) for i in range(N)]  # text, log_weight, KV cache

for t in range(max_new_tokens):
    proposed = []

    for text, logw, cache in particles:
        token, logp, cache2 = sample_next_token(model, prompt + text, cache)
        text2 = text + decode(token)

        # potential should assess the prefix / remaining feasibility
        delta = log_potential(text2, t + 1) - log_potential(text, t)
        proposed.append((text2, logw + delta, cache2))

    particles = proposed
    weights = softmax([logw for _, logw, _ in particles])

    if effective_sample_size(weights) < N * 0.5:
        particles = systematic_resample(particles, weights)
        particles = [(text, 0.0, cache) for text, _, cache in particles]

answer = select_or_sample_final(particles)

A common formulation uses a sequence of potentials \(\phi_t(y_{1:t})\), with the incremental correction:

\[ \log w_t = \log w_{t-1} + \log \phi_t(y_{1:t}) - \log \phi_{t-1}(y_{1:t-1}) \]

That incremental difference prevents repeatedly counting the same “goodness” evidence at every token. In practice, this is never going to be the true target potential, because that is almost always super weird in token space.

There are a few adjacent “SMC for LLMs” ideas that have a similar shape.

1 SMC for LLMs

2 References