[Kimi K3 Bug] Fix kimi k3 reasoning parser (#57098)
Signed-off-by: yewentao256 <zhyanwentao@126.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>
Wentao Ye committed
Sep 17, 2026 at 13:05 UTC
f3aa88d2309523f8438a239a55f59a28179ce5ef
1 file changed
+10
-5
vllm/reasoning/kimi_k3_reasoning_parser.py
+10
-5
@@ -256,11 +256,13 @@ class KimiK3ReasoningParser(ReasoningParser):
256
) -> tuple[str | None, str | None]:
257
"""Split full text into ``(reasoning, rest)`` for the non-streaming path.
258
259
- Handles three shapes:
260
- * no think channel at all -> ``(None, model_output)`` (all content)
259
+ Handles four shapes:
260
+ * response opener without think markers -> no think channel; all content
261
* open marker present -> reasoning starts after ``<|open|>think<|sep|>``
262
* open marker absent but a close marker exists (gen-prefix consumed
263
the open) -> reasoning starts at offset 0
264
+ * neither marker present -> truncated reasoning after a consumed
265
+ generation prefix
266
``rest`` is whatever follows the close marker, fed on to the tool parser.
267
"""
268
if not self._thinking_enabled:
@@ -270,11 +272,14 @@ class KimiK3ReasoningParser(ReasoningParser):
272
# reasoning content begins right after think-open (or at start if the
273
# open marker was already consumed as a generation prefix)
274
content_start = m_open.end() if m_open is not None else 0
273
- # if there is no think channel at all, everything is content
274
- if m_open is None and self._think_close_re.search(model_output) is None:
275
- return None, self._content_after_reasoning(model_output, request)
275
276
m_close = self._think_close_re.search(model_output, content_start)
277
+ if (
278
+ m_open is None
279
+ and m_close is None
280
+ and self._response_open_re.search(model_output) is not None
281
+ ):
282
+ return None, self._content_after_reasoning(model_output, request)
283
if m_close is not None:
284
reasoning = model_output[content_start : m_close.start()]
285
rest = model_output[m_close.end() :]