reasoning-budget: opt-in soft wrap-up hint and bounded grace with hard termination cap - #27578
Open
masterjaso wants to merge 1 commit into
Open
reasoning-budget: opt-in soft wrap-up hint and bounded grace with hard termination cap#27578masterjaso wants to merge 1 commit into
masterjaso wants to merge 1 commit into
Conversation
…ination Extends the reasoning-budget sampler with two opt-in stages around the existing hard cutoff: - One-time soft wrap-up hint forced near a configurable fraction of the budget (reasoning-budget-soft-ratio), injected at the next newline boundary, at most once per reasoning block, with multi-block re-arm. - Bounded grace region before the end sequence is forced (reasoning-budget-grace-tokens), so reasoning stays bounded at budget + grace tokens instead of an abrupt hard chop. Important design choice vs the originating draft (ggml-org#25961): this implementation deliberately does NOT inject an intro-budget message (name placeholder / budget announcement) at reasoning start. There is no intro message. The soft hint is the only injected text, and only after the soft threshold is crossed. Natural reasoning-end always takes precedence over forcing in every state. Absent the new options, behavior is byte-for-byte identical to upstream (reasoning-budget, reasoning-budget-message, reasoning-budget-soft-*, reasoning-budget-grace-tokens are all defaults-disabled). New CLI options / env: --reasoning-budget-soft-ratio N (LLAMA_ARG_THINK_BUDGET_SOFT_RATIO) --reasoning-budget-soft-message MESSAGE (LLAMA_ARG_THINK_BUDGET_SOFT_MESSAGE) --reasoning-budget-grace-tokens N (LLAMA_ARG_THINK_BUDGET_GRACE_TOKENS) Validation: 19/19 reasoning-budget unit tests pass (12 upstream + 7 new covering soft-fire-once-at-threshold, not-before-threshold, invalid-ratio disabled, grace-exhaustion forcing, grace-natural-close precedence, grace bounds total reasoning, and multi-block re-arm). Signed-off-by: Jason Neal <masterjaso@gmail.com>
|
Hi @masterjaso, thanks for your contribution! Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:
Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below. |
Author
|
Updated Title and Description to be less 'ai' - but overall content is correct - and hope this contribution is helpful. (Using it locally on my box - and seems to be a really nice fix to 'thought hungry' models like Qwen 3.8 27B and Ornith 1.5 35B) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This is based on the work in draft PR ggml-org/llama.cpp#25961 (
reasoning-budget: Implementing thinking-budget mechanism to control thought process) by @laurencehardman, updated for the current tree and with a slightly different approach to what happens near the end of the reasoning budget.It adds two optional behaviors to the existing
reasoning-budgetsampler:Soft wrap-up hint — when reasoning reaches a configurable fraction of the budget (
--reasoning-budget-soft-ratio N), a hint is injected at the next newline boundary. It fires at most once per reasoning block and re-arms for later blocks. The text can be changed with--reasoning-budget-soft-message MESSAGE.Grace tokens — once the reasoning budget is exhausted, the model gets up to
--reasoning-budget-grace-tokens Nadditional tokens to finish naturally. If it still has not ended reasoning by then, the end sequence is forced.The result is still bounded at
budget + grace_tokens, but avoids cutting the model off immediately when it reaches the configured budget.I did not carry over the intro-budget message from #25961. That PR can inject a message at the start of reasoning telling the model how much budget it has. This version only injects the wrap-up hint near the end.
Differences from #25961
I left out the intro message because it is not necessary to enforce the limit, and injecting text at the beginning of every reasoning block can influence the model before it has started working on the problem. The soft hint and grace window are enough for the intended behavior while keeping the default path close to upstream.
Files changed
common/arg.cpp— CLI options and environment-variable handling.common/common.h— newcommon_params_samplingfields.common/reasoning-budget.h— addsSOFT_PENDING,SOFT_FORCING, andHARD_PENDING; extends the init signature while preserving existing defaults.common/reasoning-budget.cpp— soft threshold handling, grace window, natural-end precedence, and per-block reset.common/sampling.cpp— tokenizes the optional soft message withcommon_tokenize(..., false, true)and passes it into the sampler.tests/test-reasoning-budget.cpp— 7 additional unit tests.CLI / environment variables
These only have an effect when reasoning is enabled and a
reasoning-budgetis active.Invalid values disable the corresponding behavior. For example, a soft ratio outside
(0, 1]disables the soft hint.Tests
Added 7 tests to
tests/test-reasoning-budget.cpp:test_soft_fires_once_at_threshold— fires the soft hint once after the threshold is crossed and a newline is reached.test_soft_does_not_fire_before_threshold— does not fire early.test_soft_disabled_on_invalid_ratio— ratios<= 0or> 1disable the feature.test_grace_exhaustion_forces_end— forces the end sequence once grace tokens are exhausted.test_grace_natural_close_wins— a normal reasoning close during grace is allowed through.test_grace_bounds_total_reasoning— reasoning cannot exceedbudget + grace_tokens.test_soft_and_grace_rearm_per_block— both mechanisms reset correctly for later reasoning blocks.Validation
On base
a298422da(b10548):tests/test-reasoning-budget.cpp: 19/19 passing (12 existing + 7 new)llama-serverbuilt from this branch using.devops/cuda.DockerfileI also ran a live server smoke test with:
The server accepted the new settings and streamed normal
reasoning_content.There was no intro text at the start of reasoning, as intended. The test generation also ended before reaching the 65% soft threshold, and no soft message was injected.
With the new options omitted, the existing reasoning-budget behavior is unchanged.
Motivation
The main use case is reasoning models that sometimes get stuck in repetitive or increasingly unproductive thought loops, particularly at lower temperatures.
A hard token cutoff solves the upper-bound problem, but it can also stop the model in the middle of a useful thought. The soft hint gives it a chance to start wrapping up before the limit, and the small grace window lets it finish naturally without turning the reasoning budget into an unbounded suggestion.
Based on: #25961.
Requirements