DeepAI Paper Hermes Agent 教程 Mattermost 里点不了按钮就只能超时?Hermes clarify 多选题文字兜底为什么没接住回复

Mattermost 里点不了按钮就只能超时?Hermes clarify 多选题文字兜底为什么没接住回复

Agent 在聊天平台里问澄清问题时,最理想的交互是按钮。

比如 Telegram 可以直接给 inline buttons:

请选择:
[1] A
[2] B
[3] C

用户点一下,Agent 就知道答案。

但不是所有平台都能稳定支持同样的按钮交互。Mattermost 这类平台上,Hermes 的 clarify multiple-choice 会退化成 numbered text list:把选项按编号发出来,让用户输入 12 或选项文字。

NousResearch/hermes-agent issue #25567 的问题就在这里:列表显示出来了,用户也回复了数字,但 Hermes 没把这条消息拦截为 clarify 的答案。Agent 继续卡在 wait_for_response,直到 10 分钟超时,最后拿到空响应。

也就是说:

问题问出去了,答案也发回来了,但中间那层“把答案接回 pending clarify”的逻辑没开。

现象:Mattermost 显示了编号列表,但回复数字没用

复现路径很清楚:

1. 用 Mattermost adapter 跑 Hermes gateway; 2. Agent 调用 clarify,并提供 multiple choices; 3. Mattermost 里正确显示编号列表; 4. 用户回复:

   2

或者回复选项文字; 5. Agent 没有继续; 6. 10 分钟后超时:

   [user did not respond within 10m]

从用户角度看,这非常迷惑。

因为 UI 已经告诉你“回复一个编号即可”,你也照做了,但系统像没看见一样。


为什么 Telegram 正常,Mattermost 不正常?

issue 里提到:Telegram inline buttons 是可用的。

这说明 clarify 工具本身不是完全坏掉。

差异在交互方式:

Telegram 路径

multiple choices → inline buttons → callback/action 被直接解析为选择

Mattermost fallback 路径

multiple choices → numbered text list → 用户下一条文本消息需要被拦截解析

Mattermost 没有走按钮 callback,而是走“下一条普通消息作为答案”的文本兜底。

问题正好出在这个兜底没有被 pending clarify 查询逻辑识别。


根因:有 choices 时 awaiting_text 被设成 False

issue 指向 tools/clarify_gateway.py

关键逻辑是:

awaiting_text = not bool(choices)

这行的含义是:

  • 如果没有 choices,也就是开放式问题:
  awaiting_text = True
  • 如果有 choices,也就是多选题:
  awaiting_text = False

这对支持按钮的平台可能没问题,因为按钮回调不依赖文本拦截。

但对 Mattermost 这种 numbered-text fallback 来说,多选题虽然有 choices,实际回答方式仍然是文本。

也就是说,它应该等待文本回复。

可旧逻辑把它标成:

awaiting_text = False

于是后续查询 pending clarify 时就查不到它。


第二个关键点:get_pending_for_session 只返回 awaiting_text=True 的条目

issue 里还指出,get_pending_for_session 只返回:

awaiting_text == True

的 pending entries。

于是 Mattermost 用户发来:

2

Gateway 想查“当前 session 有没有 pending clarify 等待文本回复”,但这个 clarify 因为有 choices,被标成了 awaiting_text=False

所以结果是:

查不到 pending clarify
→ 用户回复没有被当作答案
→ Agent 继续 wait_for_response
→ 10 分钟超时

这就是完整断点。


为什么这是 Gateway/tool 协议问题,不是用户回复格式问题?

用户回复 2 并没有错。

如果 Mattermost 只能展示 numbered text list,那么系统就必须把下一条文本消息纳入解析范围。

这不是用户应该“换一种格式”的问题。

真正的 contract 应该是:

只要平台使用文本 fallback 展示 multiple-choice clarify,下一条文本回复就必须被 pending clarify intercept。

否则 UI 和后端状态机不一致。


正确行为应该是什么?

当 base send_clarify 在 Mattermost 上使用 numbered-text fallback 时,Hermes 应该:

1. 记录一个 pending clarify; 2. 标记它正在等待文本回复; 3. 下一条同 session 用户消息进入时,先检查 pending clarify; 4. 如果用户输入 2,解析为第二个 choice; 5. 如果用户输入完整选项文本,也解析成对应 choice; 6. 结束 wait_for_response,把结果返回给 Agent。

也就是让 Mattermost 的体验和 Telegram 按钮体验在语义上一致。


为什么 10 分钟超时很伤体验?

clarify 的目的,是让 Agent 在不确定时暂停一下,让用户补充选择。

但这个 bug 会让 Agent 卡住:

Agent: 请选择 1/2/3
User: 2
Agent: ...沉默 10 分钟...
Agent: [user did not respond within 10m]

用户明明回答了,却被系统当成没回答。

更糟的是,用户下一条消息可能会被当作新请求,而不是原问题的答案。

于是原任务被打断,上下文也变混乱。


排查时怎么确认?

如果你在 Mattermost 上遇到 clarify 多选题超时,可以这样判断。

1. 看是不是 multiple-choice clarify

如果问题带编号列表:

1. xxx
2. yyy
3. zzz

并要求你回复数字或选项文字,就是 multiple-choice text fallback。

2. 看用户回复是否在 10 分钟内

如果用户很快回复了:

2

但 Agent 仍然超时,说明回复没有被 intercept。

3. 看代码里的 awaiting_text 逻辑

受影响版本里可能有:

awaiting_text = not bool(choices)

同时 pending 查询只返回 awaiting_text=True 的条目。

这两个条件叠加,就会让多选题文本 fallback 永远接不到回复。


修复思路:区分“有按钮”和“需要文本兜底”

问题的关键不应该是:

choices 是否存在

而应该是:

当前平台是否会通过文本消息返回选择

如果平台能发真正的按钮,并且回调会走专门通道,那么 multiple-choice 可以不等待普通文本。

但如果平台退化成 numbered text list,就必须:

awaiting_text = True

也可以理解为:

choices 决定“答案怎么解析”,不应该单独决定“是否等待文本”。

对 DeepAI API 中转站用户的边界说明

如果你的 Hermes Agent 后端接的是 DeepAI API 中转站,链路大概是:

Mattermost → Hermes Gateway → clarify tool pending state → Agent → DeepAI / OpenAI-compatible API

#25567 出错的位置在 clarify tool / Gateway pending response 层。

也就是说:

  • 用户的选择没有被接回 Agent;
  • Agent 卡在等待用户回复;
  • 模型 API 还没继续调用;
  • DeepAI Base URL、API Key、模型名都不是根因。

DeepAI 可以提供 OpenAI-compatible 模型入口,例如:

https://api.deepai.wang/v1

但它不能修复 Mattermost adapter 是否正确拦截用户的文字回复。

如果你看到 Agent “明明问了选择题,用户也答了,但还是超时”,要先查 Gateway/tool 状态机,而不是先怀疑模型。


FAQ

为什么 Telegram 可以,Mattermost 不行?

Telegram 使用 inline buttons,选择通过按钮回调进入系统;Mattermost 使用 numbered text fallback,需要拦截下一条文本消息。旧逻辑没有为 multiple-choice fallback 开启文本等待。

用户回复 2 为什么没被识别?

因为有 choices 时 awaiting_text 被设为 False,而 get_pending_for_session 只返回 awaiting_text=True 的 pending clarify。

这是 Mattermost 的问题吗?

不是单纯的平台问题。Mattermost 只是触发了文本 fallback;Hermes 需要在 fallback 路径中正确接住用户文本回复。

临时怎么绕过?

可以尽量改成开放式 clarify,或在支持按钮的平台上操作。但真正修复应在 clarify pending state / text fallback 逻辑里完成。

这是 DeepAI 或模型 API 问题吗?

不是。问题发生在用户选择进入 Agent 之前,模型 API 还没继续调用。


总结

#25567 的核心教训是:

多选题有 choices,不代表一定不需要等待文本。

在 Mattermost 这种 numbered-text fallback 场景下,用户的下一条文本消息就是按钮回调的替代物。

如果 pending clarify 没把它标成 awaiting_text=True,那用户再怎么回复数字,Agent 也只会继续等,直到 10 分钟超时。

Related Post

模型需要 max_completion_tokens,Hermes 却按网址猜参数:自定义 OpenAI 兼容端点的 400 坑模型需要 max_completion_tokens,Hermes 却按网址猜参数:自定义 OpenAI 兼容端点的 400 坑

Hermes 在自定义 OpenAI-compatible endpoint 上只按 URL host 判断 max_tokens / max_completion_tokens,导致 gpt-4o、gpt-4.1、gpt-5、o-series 模型返回 unsupported_parameter 400。本文复盘 #13901,并说明 DeepAI API 中转站场景该如何排查。

Docker 重新 build 突然 invalid file request:Hermes 的 runtime data 为什么混进了构建上下文Docker 重新 build 突然 invalid file request:Hermes 的 runtime data 为什么混进了构建上下文

Hermes Docker compose 第一次 build 成功,容器运行后下一次却报 invalid file request?根因可能是 bind-mounted ./data 作为 /opt/data 写入 runtime symlink,而 .dockerignore 没排除 data/。本文复盘 #13925。

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

Hermes issue #8338 暴露了一个配置优先级反转:display.streaming 本应只控制 CLI 终端显示,却错误覆盖了 Gateway 的 streaming.enabled: false,让 Discord、Telegram 等消息平台开始流式编辑。本文解释根因、影响和修复思路。