DeepAI Paper Hermes Agent 教程,Hermes Gateway 与消息平台,Hermes 上下文、流式与输出 一个终端开关,为什么会让 Discord 消息开始流式编辑?

一个终端开关,为什么会让 Discord 消息开始流式编辑?

有些配置 bug 看起来很小:一个布尔值、一个 fallback、一个 resolver 的查找顺序。

但放到 Agent Gateway 里,它会变成很烦人的真实体验:你明明把消息平台的 streaming 关了,Discord / Telegram / Slack / WhatsApp 还是开始不断编辑消息,带着光标一点点刷新。

NousResearch/hermes-agent issue #8338 记录的就是这种回归:

display:
  streaming: true

streaming:
  enabled: false

按文档理解,display.streaming: true 应该只控制 CLI / terminal 里的 token streaming;而 streaming.enabled: false 才是 Gateway 消息平台是否启用渐进式消息编辑的总开关。

结果实际行为反过来了:只要 display.streaming: true,Gateway 消息平台仍会 streaming。

这不是“用户没关对开关”,而是配置作用域越界。


表面现象:Discord 收到的消息被不断编辑

issue 里的复现很直接。

配置如下:

display:
  streaming: true

streaming:
  enabled: false

用户期望:

终端里可以流式显示
Discord 等消息平台不要流式编辑

实际行为:

Discord 仍然收到带光标的 streaming 消息
随后消息被编辑成最终文本

复现输出类似:

sent: ['interim status', 'first streamed chunk ▉']
edits: ['first streamed chunk plus final chunk']

这说明 Gateway 已经走了“先发一段,再编辑成最终内容”的流式消息路径。


为什么这个 bug 会制造一堆 streaming issue?

issue 原文里有一句很有意思:

This is the reason why so many streaming issues are being opened right now.
Because streaming got suddenly enabled for a lot of people.

这句话点破了这类配置回归的杀伤力。

用户不是主动打开 Gateway streaming 的。他们只是保留了终端显示流式输出:

display:
  streaming: true

然后升级后,消息平台也突然开始 streaming。

于是大量用户会以为自己遇到的是:

  • Discord 编辑消息异常;
  • Telegram 消息刷新太频繁;
  • Slack rate limit;
  • WhatsApp 消息重复;
  • Gateway transport 出问题;
  • provider streaming 响应不稳定。

但真正根因不是平台,也不是模型,而是配置解析把“终端显示开关”误当成了“平台消息 streaming override”。


根因:全局 display.streaming 覆盖了 root streaming.enabled

issue 里给出了关键代码逻辑:

_plat_streaming = resolve_display_setting(user_config, platform_key, "streaming")

_streaming_enabled = (
    _scfg.enabled and _scfg.transport != "off"
    if _plat_streaming is None
    else bool(_plat_streaming)
)

这段逻辑本身看起来合理:

  • 如果平台没有单独配置 streaming,就看 root streaming.enabled
  • 如果平台配置了 streaming,就用平台配置覆盖 root。

问题出在 _plat_streaming 的来源。

resolve_display_setting(user_config, platform_key, "streaming") 不只检查:

display:
  platforms:
    discord:
      streaming: true

它还会读到全局:

display:
  streaming: true

于是 _plat_streaming 不是 None,而是 True

接下来这行就触发了反转:

else bool(_plat_streaming)

也就是说,root 里的:

streaming:
  enabled: false

被全局 display.streaming: true 覆盖掉了。


正确的作用域应该是什么?

更合理的配置语义应该分三层。

1. CLI / terminal display

display:
  streaming: true

只影响本地终端输出体验。

例如:

  • token 是否逐步显示;
  • 终端是否显示 streaming cursor;
  • CLI 输出是否实时刷新。

2. Gateway root streaming

streaming:
  enabled: false

控制消息平台是否启用渐进式编辑。

例如:

  • Discord 是否先发半句再编辑;
  • Telegram 是否更新中间状态;
  • Slack 是否持续改消息;
  • WhatsApp 是否模拟 streaming。

3. Platform-specific override

display:
  platforms:
    discord:
      streaming: true

或者更清晰地放到 Gateway 平台配置里。

这个层级才应该覆盖 root gateway streaming。

换句话说:

display.streaming 不应该越权控制 Gateway 消息 streaming

这是一次“配置优先级反转”

这个 bug 的本质不是 streaming 本身,而是配置优先级反转。

用户以为优先级是:

platform-specific override > streaming.enabled > display.streaming

但实际变成了:

display.streaming > streaming.enabled

这就很危险。

因为 display.streaming 在很多配置里可能默认打开,或者用户为了 CLI 体验主动打开。它突然越权后,会让 Gateway 平台行为全部改变。


为什么消息平台不适合默认 streaming?

CLI 里 streaming 通常是好事,用户可以看到模型正在输出。

但消息平台不一样。

Discord

频繁 edit message 可能让用户看到“已编辑”标记,也可能触发 rate limit。

Telegram

消息编辑过快会遇到平台限制,体验上也容易显得刷屏或闪烁。

Slack

编辑消息频繁会影响线程可读性,尤其是长回复。

WhatsApp / 企业 IM

很多平台并不天然适合 token streaming,只能通过“发送临时内容 + 编辑/替换”模拟。

所以 Gateway streaming 必须有独立开关,不应该被终端 display 设置顺手打开。


回归来源:per-platform display 配置引入的副作用

issue 里指出,这个回归可能来自:

723b5bec feat: per-platform display verbosity configuration (#8006)

这个功能本意是好的:让不同平台可以有不同显示详细程度。

但新增 resolver 时,如果没有严格区分:

终端 display 配置
平台 display 配置
Gateway transport streaming 配置

就会出现这种跨作用域污染。

这也是配置系统最常见的坑:为了复用字段名 streaming,最后把两个本来不同层面的概念混在一起。


修复方向:只让平台级 override 覆盖 root streaming

合理修复思路是:

1. root streaming.enabled 继续作为 Gateway 消息 streaming 总开关; 2. 全局 display.streaming 只影响 CLI / terminal; 3. 只有明确的平台级设置,才能覆盖 root Gateway streaming; 4. 加回归测试,覆盖以下配置:

display:
  streaming: true
streaming:
  enabled: false

预期:

CLI streaming 开
Gateway streaming 关

issue 评论里也提到,canonical fix lane 是 PR #8347,并包含:

  • tests/gateway/test_display_config.py
  • tests/gateway/test_run_progress_topics.py

这类测试非常关键,因为配置回归最容易在重构 display / gateway 逻辑时再次出现。


用户怎么快速判断自己是否踩到这个坑?

如果你升级 Hermes 后突然发现消息平台开始流式编辑,可以这样查。

1. 查看配置里是否有 display.streaming

display:
  streaming: true

如果有,同时你又设置了:

streaming:
  enabled: false

就高度符合 issue #8338

2. 看平台现象是不是“先发后改”

典型表现:

  • 消息末尾有 cursor;
  • Discord 显示消息被 edited;
  • Telegram/Slack 里内容逐步变化;
  • 最终消息正常,但中间过程被发出来了。

3. 升级到包含修复的版本

如果你的版本仍受影响,优先升级到包含 PR #8347 修复的 Hermes 版本。

4. 临时规避

如果暂时不能升级,可以考虑:

display:
  streaming: false

streaming:
  enabled: false

代价是 CLI 终端也不再 streaming。


和 DeepAI API 中转站的关系

这个问题和模型 API 本身关系不大。

无论你用的是:

  • Anthropic;
  • OpenAI;
  • GitHub Copilot;
  • Ollama;
  • DeepAI API 中转站;
  • 其他 OpenAI-compatible provider;

只要 Hermes Gateway 的配置解析把 display.streaming 错当成平台 streaming override,都可能出现类似现象。

如果你使用 DeepAI API 中转站:

Base URL: https://api.deepai.wang/v1
API Key: 你的 DeepAI Key
Model: 以 DeepAI 控制台为准

DeepAI 可以帮你统一模型 API 入口,但消息是否流式编辑,是 Hermes Gateway 自己的配置和平台发送逻辑决定的。

所以排查时不要第一时间怀疑 DeepAI API、模型或上游响应格式,先看 Hermes 的 display.streamingstreaming.enabled


FAQ

display.streamingstreaming.enabled 有什么区别?

前者按文档应控制 CLI / terminal 的显示 streaming;后者控制 Gateway 消息平台是否进行渐进式消息编辑。

为什么我已经设置 streaming.enabled: false,Discord 还是 streaming?

受 issue #8338 影响时,全局 display.streaming: true 会被错误当作平台 override,从而覆盖 root streaming 开关。

这是 Discord 的问题吗?

不是。Discord 只是最容易观察到“消息被编辑”。根因在 Hermes Gateway 配置解析。

临时解决办法是什么?

如果不能升级,可以先把 display.streaming 也设为 false,但会牺牲 CLI streaming 体验。

DeepAI API 中转站会导致这个问题吗?

不会。这是 Hermes Gateway 配置作用域问题,不是 DeepAI API 或模型 provider 问题。


总结

#8338 的教训是:

同名配置项不能跨作用域乱复用。

display.streaming 是终端显示开关,streaming.enabled 是 Gateway 消息 streaming 开关。两者名字相近,但职责不同。

当一个终端开关越权控制 Discord / Telegram / Slack 这类消息平台,用户就会以为平台、provider、模型 API 全都有问题。

真正的问题只有一个:配置优先级反了。

Related Post

你以为传进 Docker 的变量,其实从没上车:Hermes docker_env 配置为何失效你以为传进 Docker 的变量,其实从没上车:Hermes docker_env 配置为何失效

Hermes 的 terminal.docker_env 写在 config.yaml 里却没有进入 Docker 容器,根因是 env_mappings 缺少 docker_env 到 TERMINAL_DOCKER_ENV 的映射。本文复盘 #20537:为什么配置看似存在,运行时却只拿到默认空 dict。

GPT-5 模型报 unsupported_api_for_model?Hermes Agent 自动切换 Responses API 的排错指南GPT-5 模型报 unsupported_api_for_model?Hermes Agent 自动切换 Responses API 的排错指南

Hermes Agent 使用 GPT-5.4、Copilot 或 OpenRouter 时,如果请求漂移到 /chat/completions 并报 unsupported_api_for_model,核心往往不是模型不可用,而是 GPT-5.x 必须走 Responses API / codex_responses。本文解释 provider fallback、api_mode、gateway 缓存和 OpenAI-compatible API 的正确排查顺序。

Kimi-k2.6 明明是 256K,Hermes 为什么按 32K 拒绝启动?Kimi-k2.6 明明是 256K,Hermes 为什么按 32K 拒绝启动?

Hermes Agent 接入 Ollama Cloud 的 kimi-k2.6 时,API 已报告 262,144 tokens,但启动校验仍按 32,768 tokens 拒绝模型,提示低于 64K 最低上下文。本文客观复盘 #23949:context length resolution chain、远程 Ollama provider 检测、models.dev 命名格式和 model.context_length override。