-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Labels
area:coreThe bug / feature is about astrbot's core, backendThe bug / feature is about astrbot's core, backendbugSomething isn't workingSomething isn't workingfeature:pluginThe bug / feature is about AstrBot plugin system.The bug / feature is about AstrBot plugin system.
Description
What happened / 发生了什么
问题描述
当 AI 在普通对话中调用 send_message_to_user 工具发送消息后,又返回相同内容的文本回复,导致用户收到两次相同的消息:
- 第一次:通过
send_message_to_user工具发送的完整消息 - 第二次:通过正常的消息流程发送的相同内容(可能经过 splitter插件或原生正则 分段,经过分析判断并非插件的问题。这个非常难复现,因为据我所知只有这一个用户遇到了这个问题,并且他本人没有什么技术基础)
Reproduce / 如何复现?
复现条件
- 平台支持主动消息(
platform_meta.support_proactive_message = True) - AI 模型在普通对话中选择使用
send_message_to_user工具(非预期行为) - 工具执行后,AI 又返回了相同内容的文本回复
日志示例
[12:12:03.089] completion: ... finish_reason='tool_calls', tool_calls=[...name='send_message_to_user'...]
[12:12:03.167] Agent 使用工具: ['send_message_to_user']
[12:12:03.904] Tool `send_message_to_user` Result: Message sent to session...
# 工具发送完消息后,AI 又返回了相同内容的文本回复
[12:12:18.455] completion: ... finish_reason='stop', message=ChatCompletionMessage(content=' (轻笑一声...')
问题根源
在 astrbot/core/astr_main_agent.py 第 1166-1169 行:
if event.platform_meta.support_proactive_message:
if req.func_tool is None:
req.func_tool = ToolSet()
req.func_tool.add_tool(SEND_MESSAGE_TO_USER_TOOL)只要平台支持主动消息,send_message_to_user 工具就会被注册到普通对话的工具集中。
但根据工具描述,这个工具应该 "Only use this tool when you need to proactively message the user",即主动消息场景(如定时任务触发、后台任务完成通知等),而不是普通对话。
建议解决方案
方案 1:添加配置项控制
# 只在主动型 Agent 场景下注册此工具,普通对话不注册
proactive_agent_enabled = config.get("proactive_agent_settings", {}).get("enable", False)
if event.platform_meta.support_proactive_message and proactive_agent_enabled:
if req.func_tool is None:
req.func_tool = ToolSet()
req.func_tool.add_tool(SEND_MESSAGE_TO_USER_TOOL)方案 2:在 Agent Runner 层面处理
在 tool_loop_agent_runner.py 中,当 send_message_to_user 工具执行后,标记该会话已发送消息,后续的文本回复如果内容相同则跳过发送。
方案 3:修改工具描述
强化工具描述,明确告知 AI 在普通对话中不应使用此工具:
description: str = (
"Directly send message to the user. "
"IMPORTANT: Only use this tool in proactive agent scenarios (cron jobs, background tasks). "
"In normal conversations, do NOT use this tool - just output your reply directly."
)AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
环境信息
- AstrBot 版本: v4.19.5
- 平台: aiocqhttp
- AI 模型: gemini-3.1-pro-preview
OS
Linux
Logs / 报错日志
日志示例
# 第一次 LLM 响应:AI 决定调用 send_message_to_user 工具
[2026-03-15 12:12:03.089] [Core] [DBUG] [sources.openai_source:262]: completion: ChatCompletion(
id='chatcmpl-xxx',
choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None,
message=ChatCompletionMessage(content='', refusal=None, role='assistant',
tool_calls=[ChatCompletionMessageFunctionToolCall(
id='call_xxx',
function=Function(
arguments='{"messages":[{"text": " (某段回复内容) \\n\\n...","type":"plain"}]}',
name='send_message_to_user'
),
type='function'
)]
)
)],
model='gemini-3.1-pro-preview-high'
)
# 多个插件在 on_decorating_result 阶段清空消息结果(因为这是工具调用,没有直接内容)
[2026-03-15 12:12:03.151] [Core] [DBUG]: hook(on_decorating_result) -> memes - on_decorating_result 将消息结果清空。
[2026-03-15 12:12:03.155] [Core] [DBUG]: hook(on_decorating_result) -> astrbot_plugin_soulmap - on_decorating_result 将消息结果清空。
[2026-03-15 12:12:03.160] [Core] [DBUG]: hook(on_decorating_result) -> astrbot_plugin_splitter - on_decorating_result 将消息结果清空。
# 框架发送空消息(因为 result 被清空了)
[2026-03-15 12:12:03.161] [Core] [INFO] [respond.stage:184]: Prepare to send - xxx:
# 工具被执行
[2026-03-15 12:12:03.167] [Core] [INFO] [runners.tool_loop_agent_runner:657]: Agent 使用工具: ['send_message_to_user']
[2026-03-15 12:12:03.168] [Core] [INFO] [runners.tool_loop_agent_runner:703]: 使用工具:send_message_to_user,参数:{'messages': [{'text': ' (某段回复内容) ...', 'type': 'plain'}]}
[2026-03-15 12:12:03.904] [Core] [INFO] [runners.tool_loop_agent_runner:881]: Tool `send_message_to_user` Result: Message sent to session xxx
# ========= 问题关键:工具执行后,LLM 又返回了相同内容的普通文本回复 =========
# 第二次 LLM 响应:AI 返回普通文本(finish_reason='stop'),内容与工具发送的相同
[2026-03-15 12:12:18.455] [Core] [DBUG] [sources.openai_source:262]: completion: ChatCompletion(
id='chatcmpl-yyy',
choices=[Choice(finish_reason='stop', index=0, logprobs=None,
message=ChatCompletionMessage(
content=' (某段回复内容) \\n\\n...', # <-- 与工具发送的内容相同!
refusal=None, role='assistant',
tool_calls=None # 这次没有工具调用
)
)],
model='gemini-3.1-pro-preview-high'
)
# Splitter 插件对这个文本回复进行分段发送
[2026-03-15 12:12:18.522] [Plug] [INFO] [astrbot_plugin_splitter.main:129]: [Splitter] 消息被分为 12 段。
[2026-03-15 12:12:18.523] [Plug] [INFO] [astrbot_plugin_splitter.main:229]: [Splitter] 第 1/12 段 (主动发送): (某段回复内容)
...
[2026-03-15 12:12:46.875] [Plug] [INFO] [astrbot_plugin_splitter.main:229]: [Splitter] 第 12/12 段 (交给框架): ...
# 结果:用户收到了两次相同内容的消息
# 1. 通过 send_message_to_user 工具发送的完整消息
# 2. 通过 Splitter 分段发送的同样内容
Are you willing to submit a PR? / 你愿意提交 PR 吗?
- Yes!
Code of Conduct
- I have read and agree to abide by the project's Code of Conduct。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:coreThe bug / feature is about astrbot's core, backendThe bug / feature is about astrbot's core, backendbugSomething isn't workingSomething isn't workingfeature:pluginThe bug / feature is about AstrBot plugin system.The bug / feature is about AstrBot plugin system.