问题 / #2731

#2731 serve: a reply that ends inside its thinking still returns an empty answer on 0.1.44.1 (the #1814 shape)

open · @47Hunter47 · 0 评论 · 去 GitHub 看

BenchmarksSetup & installServer & APINVIDIA / CUDAModels & quants

说明

This is the shape #1814 reported. That issue was closed in the three-day sweep, and its close comment asked for the engine log (or a new issue that links it) — so, linking it: the same end is still there on the newest release. Reproduced on a **stock checkout of the tag `v0.1.44.1`** — the tag's own `serve/`, no local patches — with the released 0.1.44.1 engine, and `reasoning_close_retry` off (its default), so this is what a default install does.

**Setup:** RTX 3090, Qwen3.8-Flash-Next IQ3_XXS, 250K context, `--kv int8`, sampling 1.0/0.95/20, `reasoning_budget_tokens` 16384. `/props.build_info` is `Strata 0.1.44.1`.

**Reproduction.** The minimal input from #1178 — it asks for the assistant turn-end marker verbatim, which is what makes the model reach for that token:

```
POST /v1/chat/completions
{"model": "qwen3.8-flash-next", "max_tokens": 8000, "temperature": 1.0,
 "messages": [{"role": "user", "content": "Qwen 聊天模板里,助手回合的结束标记是什么?请原样写出,例如 \"标记\"。"}]}
```

**4 of 4 runs:** `finish_reason` is `stop`, `content` is empty, and `reasoning_content` holds 164–476 characters. On #1814's prompt (show the closing thinking tag in a code fence) the same end took 2 of 4 runs, and of the two that answered one wrote `</thinking>`, which is not the token this tokenizer ends thinking with.

**The engine log for one of those empty replies** (`STRATA_DEBUG=1`; elisions are marked `[...]`):

```
[strata] req openai: msgs=1 tools=0 max_tokens_raw=8000/None max_new=8000 thinking=True stream=False prompt_tokens=76 last='user':'Qwen 聊天模板里,助手回合的结束标记是什么?请原样写出,例如 "标记"。'
[strata] thinking capped at 6000 of max_tokens 8000 to leave room for the answer (budget 16384)
[strata] thinking: 75 of budget 6000 (max 8000) tokens, 84.9 tok/s, 1 s
[strata] done: 106 tokens in 2 s (76.2 tok/s) (stop, cancel=False), expert cache 97.4% hit
[strata] raw: '我们需要回答用户问题:[...]常见 Qwen 模板:ChatML? [...] Often includes:\n\n<|im_start|>system\n{system_content}<|im_end|>'
```

and on #1814's prompt:

```
[strata] done: 129 tokens in 2 s (76.4 tok/s) (stop, cancel=False), expert cache 91.7% hit
[strata] raw: 'We need to respond to user: "In a markdown code fence, show exactly how the closing thinking tag looks.[...]"\n\nNeed comply.[...]Final can contain code fence with closing tag maybe <|im_end|>'
```

Not the thinking budget (75 of 6000) and not `max_tokens` (106 of 8000), with `cancel=False`: the raw turn simply ends on the marker and the reply comes back with nothing in it.

**Why the server cannot tell.** In this pack's tokenizer the token that ends the turn, `<|im_end|>`, is a **type-3 control token** (id 248046, matched only with `parse_special`), and the closing thinking tag `</think>` is a **type-4 token** (id 248069). The turn ends on that control token itself, so no character of any marker reaches the stream, and a turn that ended there on purpose looks exactly the same — the client gets an empty reply with no sign of why. (Ids measured with the pack's own `tokenizer/` files, no GPU.)

**A fix is in review:** #1840 (opt-in `literal_think_guard`) gives that token's text back where the model was writing it and then closes the thinking, and behind the same flag reports the end — a log line, `totals.ended_inside_thinking`, and `ended_inside_thinking` beside `choices` in the response. On `main` (`296b59d2`) neither the continuation nor any reporting of this end exists, so an empty reply is still silent. #2674 adds a log line that names this end; #1886 is the parser side of the same shape.

本站相关内容

相关页面的快捷入口。