现象
实例 default(恋恋),core dev 8d3d1d9 / v4.0.0-beta.6,主模型 opencode:deepseek-v4-flash。群聊里 bot 决定保持沉默时,群友会看到一条正文:
模型原始输出通常是:
<inner_thought>…保持沉默…</inner_thought>
[调用 finish]
parseReply 会剥掉 <inner_thought>,但 [调用 finish] 被当作正常消息投递到群里。
另有同源问题:部分回合正文尾部出现工具调用残留标签,例如:
</||DSML||parameter>
</||DSML||invoke>
</||DSML||tool_calls>
根因
core/src/runtimes/prompt.ts 的内心独白示例用中括号示意工具调用([调用 finish 工具]、[调用搜索工具]),模型会模仿把“调用 finish”写成正文文本。
core/src/messages/index.ts 的 parseReply 只剥离 <inner_thought> 和 noreply,不处理伪工具调用文本 / DSML 残留,于是这些文本作为 segment 直接投递。
建议修复(已在本地验证)
parseReply 在 stripInnerThoughtRegions 之后增加一层 stripPseudoToolCalls:
- 去掉
[调用 xxx] / [call xxx] 伪工具调用文本;
- 去掉
DSML / tool_call(s) / function_call(s) 形式的标签残留(兼容全角竖线 ||)。
- 重写 prompt 示例:不再展示中括号伪工具调用,并增加规则“工具调用本身不是文本,不要输出「[调用 xxx]」;需要沉默时直接调用 finish 工具且正文留空”。
本地 core 相关测试通过(messages 44 + output 4 + prompt 2,共 50)。补丁很小(2 个文件,+16/-4),需要的话我可以开 PR。
现象
实例 default(恋恋),core dev 8d3d1d9 / v4.0.0-beta.6,主模型
opencode:deepseek-v4-flash。群聊里 bot 决定保持沉默时,群友会看到一条正文:模型原始输出通常是:
parseReply会剥掉<inner_thought>,但[调用 finish]被当作正常消息投递到群里。另有同源问题:部分回合正文尾部出现工具调用残留标签,例如:
根因
core/src/runtimes/prompt.ts的内心独白示例用中括号示意工具调用([调用 finish 工具]、[调用搜索工具]),模型会模仿把“调用 finish”写成正文文本。core/src/messages/index.ts的parseReply只剥离<inner_thought>和noreply,不处理伪工具调用文本 / DSML 残留,于是这些文本作为 segment 直接投递。建议修复(已在本地验证)
parseReply在stripInnerThoughtRegions之后增加一层stripPseudoToolCalls:[调用 xxx]/[call xxx]伪工具调用文本;DSML/tool_call(s)/function_call(s)形式的标签残留(兼容全角竖线||)。本地 core 相关测试通过(messages 44 + output 4 + prompt 2,共 50)。补丁很小(2 个文件,+16/-4),需要的话我可以开 PR。