接入 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 StartedRust0117- DDeepSeek-V4-ProDeepSeek-V4-Pro(总参数 1.6 万亿,激活 49B)面向复杂推理和高级编程任务,在代码竞赛、数学推理、Agent 工作流等场景表现优异,性能接近国际前沿闭源模型。Python00
MiMo-V2.5-ProMiMo-V2.5-Pro作为旗舰模型,擅⻓处理复杂Agent任务,单次任务可完成近千次⼯具调⽤与⼗余轮上 下⽂压缩。Python00
GLM-5.1GLM-5.1是智谱迄今最智能的旗舰模型,也是目前全球最强的开源模型。GLM-5.1大大提高了代码能力,在完成长程任务方面提升尤为显著。和此前分钟级交互的模型不同,它能够在一次任务中独立、持续工作超过8小时,期间自主规划、执行、自我进化,最终交付完整的工程级成果。Jinja00
SenseNova-U1-8B-MoT-SFTenseNova U1 是一系列全新的原生多模态模型,它在单一架构内实现了多模态理解、推理与生成的统一。 这标志着多模态AI领域的根本性范式转变:从模态集成迈向真正的模态统一。SenseNova U1模型不再依赖适配器进行模态间转换,而是以原生方式在语言和视觉之间进行思考与行动。Python00
MiniMax-M2.7MiniMax-M2.7 是我们首个深度参与自身进化过程的模型。M2.7 具备构建复杂智能体应用框架的能力,能够借助智能体团队、复杂技能以及动态工具搜索,完成高度精细的生产力任务。Python00