Skip to content

[Bug] DeepSeek-V4-Flash-0731: reasoning_effort mapped one level off — high is a no-op and vendor max is unreachable #33185

Description

@bitfinop

Checklist

  • I searched related issues but found no solution
  • The bug persists in the latest version (v0.5.16, and in main as of today)
  • Environment info and a reproducible demo are included below

Describe the bug

reasoning_effort for DeepSeek-V4-Flash-0731 is mapped one level off, and the model's
strongest level is unreachable.

DeepSeek implements the effort level as a prompt prefix. The reference encoder shipped with
the weights (encoding/encoding_dsv4.py in deepseek-ai/DeepSeek-V4-Flash-0731) defines
three distinct texts:

level injected text
low "" (empty — this is DEFAULT_REASONING_EFFORT)
high "Reasoning Effort: Absolute maximum with no shortcuts permitted.\n…"
max "Reasoning Effort: Beyond maximum — exhaustive, relentless, and uncompromising.\n…"

SGLang keeps its own copy of the encoder at
python/sglang/srt/entrypoints/openai/encoding_dsv4.py, and it defines only one
constant:

# encoding_dsv4.py:63
REASONING_EFFORT_MAX = (
    "Reasoning Effort: Absolute maximum with no shortcuts permitted.\n"
    ...
)
# encoding_dsv4.py:294-300
assert reasoning_effort in ["max", None, "high"]
if index == 0 and thinking_mode == "thinking" and reasoning_effort == "max":
    prompt += REASONING_EFFORT_MAX

That constant holds DeepSeek's high text. The max text ("Beyond maximum …") does
not appear anywhere in the SGLang tree — grep -c "Beyond maximum" returns 0 in SGLang
and 1 in the reference encoder.

The resulting mapping:

request SGLang injects effectively equals
low nothing vendor low
high nothing vendor low
max "Absolute maximum …" vendor high
vendor max unreachable ❌

Consequences:

  1. reasoning_effort="high" is a no-op — it is indistinguishable from low.
  2. reasoning_effort="max" actually selects the vendor's high behaviour.
  3. The vendor's max level cannot be selected at all, so benchmark numbers published for
    0731 (Terminal Bench 2.1 82.7, DeepSWE 54.4 — the model card states they were measured
    with the max reasoning effort level) are not reproducible on SGLang.

This looks like the pre-0731 two-level scheme (nothing / max) carried over: the 0731 release
introduced a third level and renamed the texts. #23915 ("Fix dsv4 self-closing invoke tags +
accept reasoning_effort=max") made the parameter accepted, but the 0731 semantics were not
carried over.

Observed behaviour

Measured on the puzzle below, 8 repeats per level, temperature 0.6, median reasoning length:

level reasoning chars completion tokens latency
low 4604 1826 31.0 s
high 4980 1919 33.6 s
max 2608 942 16.0 s

low and high are indistinguishable (the spread across repeats is ±31…86%, far larger
than the difference), which is what the code predicts — neither injects anything.

max is reproducibly shorter than both (−43%, reproduced across three independent runs),
even though the text it injects asks for maximum thoroughness. We did not investigate why
the injected high text shortens deliberation on this checkpoint; the mapping defect above
is what we can demonstrate from the code.

Reproduction

Server:

python3 -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V4-Flash-0731 \
  --served-model-name dsv4 \
  --tp-size 2 --moe-runner-backend flashinfer_mxfp4 \
  --reasoning-parser deepseek-v4 --tool-call-parser deepseekv4 \
  --trust-remote-code --context-length 393216 --mem-fraction-static 0.83 \
  --host 0.0.0.0 --port 30000

Client — same prompt at each level, compare reasoning_content length:

import json, statistics, urllib.request

TASK = ("How many '+' signs must be placed between twenty '5' digits written in a row "
        "so that the sum equals 1000? Answer with the number only.")

def ask(effort):
    body = {"model": "dsv4", "messages": [{"role": "user", "content": TASK}],
            "max_tokens": 16000, "temperature": 0.6, "reasoning_effort": effort}
    req = urllib.request.Request("http://127.0.0.1:30000/v1/chat/completions",
                                 data=json.dumps(body).encode(),
                                 headers={"Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=900) as fh:
        msg = json.loads(fh.read())["choices"][0]["message"]
    return len(msg.get("reasoning_content") or "")

for lvl in ("low", "high", "max"):
    xs = [ask(lvl) for _ in range(8)]
    print(f"{lvl:<5} median reasoning chars: {statistics.median(xs):.0f}  (n=8)")

Static check, no server required:

# SGLang has one constant, holding the vendor's "high" text; the "max" text is absent
grep -c '^REASONING_EFFORT' python/sglang/srt/entrypoints/openai/encoding_dsv4.py   # 1
grep -c 'Beyond maximum'    python/sglang/srt/entrypoints/openai/encoding_dsv4.py   # 0

# reference encoder shipped with the weights has three
python3 - <<'PY'
from huggingface_hub import hf_hub_download
p = hf_hub_download("deepseek-ai/DeepSeek-V4-Flash-0731", "encoding/encoding_dsv4.py")
src = open(p).read()
print("REASONING_EFFORT_PROMPTS keys:", src.count('"low"'), src.count('"high"'), src.count('"max"'))
print("has 'Beyond maximum':", "Beyond maximum" in src)
PY

Suggested fix

Mirror the reference encoder: replace the single constant with the three-entry mapping and
inject by level, keeping low as the default.

REASONING_EFFORT_PROMPTS = {"low": "", "high": "...", "max": "..."}   # texts from the reference
DEFAULT_REASONING_EFFORT = "low"

effort = reasoning_effort or DEFAULT_REASONING_EFFORT
if index == 0 and thinking_mode == "thinking":
    prompt += REASONING_EFFORT_PROMPTS[effort]

Happy to open a PR if that is useful — we have the checkpoint and a two-GPU H200 box to
validate on.

Environment

Python: 3.12.3 (main, Jun 19 2026, 12:46:00) [GCC 13.3.0]
CUDA available: True
GPU 0,1: NVIDIA H200 NVL
GPU 0,1 Compute Capability: 9.0
CUDA_HOME: /usr/local/cuda
NVCC: Cuda compilation tools, release 13.0, V13.0.88
CUDA Driver Version: 595.71.05
PyTorch: 2.11.0+cu130
sglang: 0.5.16
sglang-kernel: 0.4.5
flashinfer_python: 0.6.14
flashinfer_cubin: 0.6.14
flashinfer_jit_cache: 0.6.14+cu130
triton: 3.6.0
transformers: 5.12.1
torchao: 0.17.0+cu130
numpy: 2.3.5
aiohttp: 3.14.3
fastapi: 0.140.0
huggingface_hub: 1.24.0
interegular: 0.3.3
modelscope: 1.38.1
orjson: 3.11.9
outlines: 0.1.11
packaging: 26.2
psutil: 7.2.2
pydantic: 2.13.4
python-multipart: 0.0.32
pyzmq: 27.1.0
uvicorn: 0.51.0
uvloop: 0.22.1
vllm: Module Not Found

Image: lmsysorg/sglang@sha256:7b6a35df9839fd593a94a1eaee82d7777f472225d9f3ad1f8a2e0cb2bd1785d0
(v0.5.16-cu130), 2× H200 NVL, TP=2.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions