接入 MiniMax/Qwen3 报错?别让 scratchpad 污染你的流式输出
满屏乱码与 delta.content reasoning 报错:当 Hermes 遇见国产大模型
前两天,我在折腾 Hermes-Agent 这个主打全能的开源智能体框架。官方 README 里大字标榜着“无缝支持任意兼容 OpenAI 规范的 API”。看着这句话,我冷笑一声,顺手就把底层的 LLM 引擎切到了目前推理能力爆表的国产大模型——MiniMax-M2.7 和 Qwen3-Max。
跑个简单的 Hello World 没问题,但当我抛出一个需要复杂 Function Calling 和多步推理的任务时,灾难发生了。
终端没有像预期那样优雅地打出工具调用的 JSON,而是像突然发疯一样,直接把大模型底层的思考过程(比如“我需要先调用 search 工具,然后再比对结果...”)全部生硬地砸在了屏幕上。紧接着,整个 Agent 直接崩溃挂起,控制台无情地甩出了一长串带着 delta.content reasoning 报错 的 Traceback。工具执行层完全瘫痪,TUI 界面彻底被几千字的内心戏(scratchpad)撑爆。
去 GitHub 翻了一圈 Issues(特别是那个全是苦水的 reactions.json 记录),发现只要接入了带有深度思考(Reasoning)能力的开源模型,大家无一例外全在这个坑里翻了车。
报错现象总结: 当在 Hermes-Agent 中配置并调用带有深度思考(Reasoning)能力的国产大模型(如 MiniMax、Qwen3)时,流式回调(Streaming API)会将本该隐藏的推理过程(scratchpad)错误地塞入标准文本流中。这不仅触发了
delta.content reasoning 报错,还会导致下游的 JSON-RPC 解析器将思考过程误认为是非法格式的工具调用,从而引起整个智能体工作流的崩溃。
官方文档对此含糊其辞,暗示是你自己的 API 没配好。但实际上,这是由于官方架构严重偏袒 Claude 而留下的底层设计缺陷。今天,我们就直接扒开源码,看看这个协议割裂到底是怎么把你的终端搞崩溃的。
扒开 reasoning_content 回调:Claude 与开源模型的 API 协议割裂
要搞清楚为什么在 Claude 上跑得如丝般顺滑,到了 Qwen3 和 MiniMax 就疯狂抛错,我们必须深入流式输出(SSE, Server-Sent Events)的底层数据包。
在 Hermes-Agent 的设计哲学里,Anthropic 的 API 规范被当成了“亲儿子”。Claude 3.5 Sonnet 在吐出思维链数据时,使用的是极其克制且独立的通道:delta.thinking_delta。Hermes 的流式解析器发现这个字段后,会优雅地把它扔给一个叫 reasoning_callback 的后台进程,绝对不会让它混入最终呈现在 UI 上或交给解析器的文本里。
但国内大模型(以及大部分基于 vLLM 部署的开源模型)在兼容 OpenAI 的 API 格式时,做法极其简单粗暴:它们直接把带有 <scratchpad> 或 <think> 标签的推理过程,硬生生地塞进了标准文本输出的 delta.content 字段!
来看看这种底层协议的割裂有多离谱:
| 接入的模型类型 | 推理数据传输通道 | Hermes-Agent 流式解析层行为 | 终端与工具执行层实际表现 |
|---|---|---|---|
| Claude 3.5 Sonnet | delta.thinking_delta |
路由至 reasoning_callback,与正文完全物理隔离 |
完美运行,UI 纯净,工具解析精准 |
| MiniMax / Qwen3 | delta.content |
盲目追加到主文本缓冲区 | ❌ 触发 delta.content reasoning 报错,JSON 解析器因混入中文思考过程而彻底崩溃 |
让我们看看 Hermes 源码中处理 OpenAI 兼容流的那段“天真”逻辑(伪代码还原):
async for chunk in response_stream:
delta = chunk.choices[0].delta
# 官方的弱智处理逻辑:根本不区分这到底是正文还是 Reasoning!
if hasattr(delta, 'content') and delta.content:
# 直接把带有 <scratchpad> 的思考过程拼接到 UI 缓冲区和工具解析器
self.message_buffer += delta.content
yield delta.content
# 如果是 OpenAI O1 这种支持 reasoning_content 的还没问题
if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
await self.reasoning_callback(delta.reasoning_content)
致命的时序逻辑就在这里: 下游的 Agent Execution Layer 正在眼巴巴地等着一个符合 JSON Schema 的大括号 { 来触发工具调用。结果 delta.content 劈头盖脸传过来一句:“<scratchpad> 用户让我查天气,我得先获取地点... </scratchpad>”。
解析器当场懵逼,直接抛出 JSONDecodeError,紧跟着抛出业务层的 delta.content reasoning 报错,整个 Agent 状态机直接死锁。
手写中间件清洗 delta.content 的血泪史
病因找到了:开源模型把推理流写进了正文流,而 Hermes 的解析器没有做任何拦截。如果你想自己动手解决,你需要在这个脆弱的异步流中强行插入一个状态机中间件。
这绝非易事。你需要经历以下极其痛苦的“填坑实战”:
首先,钻进你那深不见底的 Python 虚拟环境,找到控制流式解析的底层文件。你需要手写一个 Buffer(缓冲区),去逐个字符地检测 <scratchpad> 或 <think> 的开启和闭合。
最要命的是,流式数据是一块一块(Chunk)吐出来的! 你可能会在一个 chunk 里收到 <scr,在下一个 chunk 里收到 atchpad>。你必须维护一个复杂的全局状态,一旦检测到进入推理模式,就必须把所有流经 delta.content 的数据强行重定向到 reasoning_callback,直到遇到闭合标签,再把通道切换回来。
写这个中间件的过程极其繁琐。Python 的 asyncio 在处理这种高频字节流时毫不留情,你稍微阻塞了 event loop,或者在迭代生成器里抛错,整个终端直接无响应。而在国内网络环境下,如果你为了引入一些高级的流式解析库去执行 uv pip install,又要面对无尽的 Timeout 和依赖版本冲突。折腾一个周末,你的头发掉了一大把,可能仅仅换来一个偶尔还会漏标点符号的半成品。
别再死磕底层协议,用特供版适配补丁一键接管流式输出
作为开发者,你的核心价值是去编排高阶的 Agent 业务流,而不是在一个开源项目的底层源码里和残缺的 SSE 数据包斗智斗勇。
与其浪费一个周末搞环境、改源码、写那恶心的异步正则缓冲,不如直接拿现成的轮子。为了彻底根治这个 delta.content reasoning 报错 的顽疾,我已经把底层的流式拦截器彻底重构了,做成了一个专门针对国内大模型(MiniMax、Qwen3、DeepSeek)的流式输出清洗中间件补丁。
这个补丁在底层实现了一个零延迟的 Token 级状态机。不管模型把 scratchpad 藏在哪个字段,不管网络抖动把 chunk 撕裂成什么样,它都能精准拦截,将推理过程完美剥离给后台,还终端一个纯净的交互环境。
👉 [访问 GitCode 下载国内大模型专用的流式输出适配补丁,一键兼容全系模型] (搜索 Hermes-Agent 流式输出净化计划)
操作极其无脑:
- 访问上方 GitCode 仓库,直接下载
stream_sanitizer.py补丁包(https://gitcode.com/GitHub_Trending/he/hermes-agent) - 扔进项目的核心模块目录,覆盖原有的网关处理逻辑。
- 重启 Hermes-Agent。
再试着用 Qwen3 或 MiniMax 跑一次复杂任务,你会看到那赏心悦目的纯净 TUI 重新回归,工具调用的 JSON 严丝合缝地触发,再也没有恶心的乱码和让人抓狂的崩溃栈。
拿去用,少踩坑,享受国产大模型真正该有的丝滑体验。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0197
cann-learning-hubCANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。Jupyter Notebook0126
MiMo-V2.5-Pro-FP4-DFlashMiMo-V2.5-Pro-FP4-DFlash 是驱动 MiMo-V2.5-Pro-UltraSpeed 的底层模型: FP4 量化骨干网络:对 MoE 专家采用 MXFP4 量化,同时保持模型其他部分的更高精度,在几乎无损质量的前提下,显著减小模型体积并降低内存带宽压力。 BF16 DFlash 草稿生成器:用于块扩散推测解码,每次前向传播可生成一整个块的 tokens,并让骨干网络一步完成验证。 两者协同作用,既降低了每参数的位宽,又减少了骨干网络前向传播的次数,而这两者正是万亿参数模型解码过程中的两大主要成本来源。Python00
JoyAI-EchoJoyAI-Echo,这是一个独立的、仅用于推理的版本,旨在实现分钟级多镜头音视频生成。它采用了经过蒸馏的DMD生成器、配对的跨模态记忆以及故事级别的一致性。其性能的核心在于,一个跨模态视听记忆库能够在长达五分钟的视频中保持角色外观和语音音色的一致性。同时,一个训练后处理流程将基于记忆的强化学习与分布匹配蒸馏相结合,实现了7.5倍的速度提升,显著增强了视觉质量和对齐效果。00
AstrBot✨ 易上手的多平台 LLM 聊天机器人及开发框架 ✨ 平台支持 QQ、QQ频道、Telegram、微信、企微、飞书 | OpenAI、DeepSeek、Gemini、硅基流动、月之暗面、Ollama、OneAPI、Dify 等。附带 WebUI。Python05
handy-ollama动手学Ollama,CPU玩转大模型部署,在线阅读地址:https://datawhalechina.github.io/handy-ollama/Jupyter Notebook07