[Bug]: Group-chat "Reply directly" system line suppresses tool calls — agent ends the turn with only a plan (0 tool calls)
中文摘要:群聊转发消息时会注入一句 Group chat system: ... Reply directly ... do not return an empty response.。模型(含 deepseek-v4-pro)把这句理解成"必须马上回一句话",于是只回一句"收到,我先去读 X 文件"就结束回合,整轮零工具调用,任务永久悬空。建议改为显式要求先调工具。
Environment
- Ekko Studio: 0.7.22(desktop, macOS)
- hermes-web-ui: 0.7.22
- Hermes Agent: 2026.5.29.2
- OS: macOS 15.7.5 (Intel x86_64)
- Model:
deepseek-v4-pro与deepseek-flash均复现 - Room: 群聊,8 个 agent,
agentHandoff关闭,约 34k 条消息
Summary
群聊中 agent 被 @ 时,注入的系统提示要求它 "Reply directly … do not return an empty response"。
模型字面执行:只输出一句确认(如 "收到,三处修改一次做齐。先读执行单全文…"),
回合以 finish_reason=stop 结束,一次工具调用都没有。任务从未执行,且没有任何报错提示用户。
强模型(deepseek-v4-pro)同样复现,因此不是模型能力问题。
Steps to reproduce
- 创建一个群聊,至少 2 个有工具权限的 agent(如 PM profile + engineer profile)。
- 把 engineer profile 的模型设为
deepseek-v4-pro。 - 作为用户 @PM,要求它派发一个需要改文件的任务。
- PM @engineer 派发任务。
- 观察:engineer 只发一条"只含计划"的消息("收到,我先去读 X 文件")就停了,没有任何工具调用。
Evidence
Hermes agent 日志(~/.hermes/profiles/<profile>/logs/agent.log),全部发生在 3 秒内:
2026-09-16 15:15:13,265 agent.conversation_loop: conversation turn: session=gc_run_<room>_<profile>_a577a256...
2026-09-16 15:15:13,307 run_agent: OpenAI client created (chat_completion_stream_request)
2026-09-16 15:15:16,728 run_agent: OpenAI client closed (stream_request_complete)
2026-09-16 15:15:16,728 agent.conversation_loop: API call #1: model=deepseek-v4-pro provider=deepseek
2026-09-16 15:15:16,731 agent.conversation_loop: Turn ended: reason=text_response(finish_reason=stop)
2026-09-16 15:17:21,443 tools.terminal_tool: Cleaned up inactive environment for task: default- 该回合只有 1 次 API 调用
- 该回合零
agent.tool_executor: tool ... completed记录 - 结束原因为
Turn ended: reason=text_response(finish_reason=stop)
该回合落库的消息是一条只含计划的确认:
全栈工程师:收到,三处修改一次做齐。先读执行单全文,精确定位点 1(旧 key 获取段)、回滚段(§四)确切行。
同回合日志还有:
agent.conversation_loop: Repaired 1 message-alternation violations before ...Root cause
dist/server/index.js → groupRuntimeInput()(打包压缩)。指令文本构造如下:
groupRuntimeInput(e, n) {
let r = Sm(e.content)
? "Group chat system: this message mentioned every Agent with @all. You are one of the targets, so reply directly."
: `Group chat system: this message mentioned you (${this.name}). Reply directly even if it also mentions other participants; do not return an empty response.`,
a = n.history.map(s => `${s.role === "assistant" ? "Agent" : "Member"} "${s.senderName}": ${s.content}`).join("\n\n"),
o = [
r,
n.summary ? `The following group chat summary ... <group_chat_summary>\n${n.summary}\n</group_chat_summary>` : "",
a ? `The following group chat history ... <group_chat_history>\n${a}\n</group_chat_history>` : ""
].filter(Boolean).join("\n\n"),
...
return `${o}\n\nCurrent message: ${qw(e.content, this.name) || e.content}`
}问题子串正是:
Group chat system: this message mentioned you (NAME). Reply directly even if it also mentions other participants; do not return an empty response.为什么必然发生:"Reply directly" + "do not return an empty response" 被读作对回复的框定指令
——"现在就产出一条消息"。这与 harness 想要的工具行为冲突
(agent.tool_use_enforcement 注入的是 "Never end your turn with a promise of future action — execute it now")。
由于群聊那行在 user message(离生成更近),而 enforcement 引导在 system prompt,
模型选择了更近、更具体的那条指令,于是以计划结束回合。
Impact
- 静默任务死亡。在多 agent 房间里这看起来像一条正常回复,用户以为"agent 已接单",实际永远不动。
- 零错误暴露——不重试、不告警、不排队。
- 任何期望 agent 做工具操作的群聊房间(编码房、运维房、文档房)都受影响。
- 我们的房间里实际后果:engineer 在几天里反复"确认"同一个任务,而实际工作从未开始。
Suggested fix
在群聊提示中显式说明:先调工具、再回复。例如:
Group chat system: this message mentioned you (NAME).
If the request requires work, call your tools FIRST and finish the work in this turn —
never end the turn with only a plan or a promise of future action.
Then reply with the result. Do not return an empty response.@all 分支建议同步修改。
补充建议:当群聊 run 以 finish_reason=stop、零工具调用结束,
且模型文本中含未来动作承诺(如 我先、先读、I'll、let me check)时,
判定为不完整回合——自动续跑一次,或在房间里给出提示。目前是静默失败。
Additional observation (possibly separate issue)
历史消息渲染为 Agent "<senderName>": <content>。由于 agent 自己的输出也被原样存储,
会自我冠名的模型会产生双层前缀并不断传播:
IT项目经理:IT项目经理:Kyle 的意思是…我们在一个房间里见到最深 25 层嵌套。
既然框架已经用 Agent "<name>": 提供归属,建议在渲染历史时
剥掉内容开头的 <senderName>:,避免前缀复合。
我们本地采用的 workaround(非真正修复):在
SOUL.md中禁止 agent 自我冠名, 并一次性清理了已存储消息。
Workarounds tried (for reference)
agent.tool_use_enforcement: true(强制注入工具使用引导)——有改善,但未消除冲突。- 在每个 agent 的
SOUL.md里加反向指令,说明 "Reply directly" ≠ "只回一句话"—— 有改善,但依赖模型自行调和两条矛盾指令。 - 切换模型
deepseek-flash→deepseek-v4-pro——不能修复(证明这是提示词冲突,而非模型弱)。
Source: EKKOLearnAI/hermes-studio