Appearance
Gemini final/think 标签泄漏到消息中:流式 + Control UI 双路径问题
问题
使用 Gemini 系列模型(Gemini Flash、Gemma 等)时,<final> 和 <think> 标签出现在用户可见的消息中,尤其是:
- WhatsApp、Telegram 等频道消息通常不出现标签
- Control UI(网页仪表板)的聊天界面持续出现原始 XML 标签
- 升级到 v2026.4.15 后开始出现(回归 bug)
受影响版本:OpenClaw 2026.4.15 及以下
根本原因分析
社区深度排查发现是两条独立路径的 bug,需要分别修复:
路径一(流式传输):stripBlockTags 使用的正则 /<\s*\/?\s*final\s*>/gi 无法匹配自闭合标签 <final/>,导致 Gemini 偶尔输出的自闭合形式漏网。
路径二(Control UI 持久化):流式传输期间 stripBlockTags 正确处理了标签,但处理后的干净内容没有写回持久化存储。Control UI 重渲染时从原始存储记录读取,因此显示的是带标签的原始内容。
注:WhatsApp/Telegram 等频道直接消费流式结果(stripped),不触发持久化路径,所以这些渠道看起来正常。
解决方案
立即可用的临时绕过:在 agent 系统提示(或 AGENTS.md)中添加约束指令:
Never wrap your responses in <final>, </final>, <final/>, <think>, </think> XML tags.
Respond with plain text only.原理:明确禁止模型输出这些标签,从源头阻断。Google 系模型(Gemini/Gemma)因训练数据中含有大量 XML 结构而特别容易输出这类包装标签,明确约束效果显著。
如果系统提示中有触发 final 标签的指令(如 AGENTS.md 中要求用 <final> 包裹最终回答的规则),需要删除这类指令。
等待官方修复:
- PR #66225:修复流式路径正则(处理
<final/>自闭合标签) - PR #69685:修复持久化路径(确保 stripped 内容写回存储)
两个 PR 合并后,Control UI 和流式渠道都将干净输出。
常见问题
Q: 为什么 WhatsApp 正常但 Control UI 有问题?
A: WhatsApp 消费的是实时流式数据(已 stripped),Control UI 消费的是持久化后的存储记录(未 stripped)。这两条路径在代码上是分开的,所以表现不一致。
Q: 设置了 <final> 提示词但删除后 agent 行为会变吗?
A: 可能会。如果 agent 依赖 <final> 作为"回答完毕"信号,删除后需要测试确认其他终止逻辑是否正常工作。
Q: gemma-4 和 gemini-flash 都会触发吗?
A: 是的,所有 Google 系模型都可能触发,因为它们在训练时都接触过大量 XML 结构化输出示例。flash-lite 尤为明显。