refactor(chat): 优化自消息处理逻辑和回复目标选择机制
- 添加自消息阻断机制,避免机器人回复自己的消息 - 重构回复目标选择逻辑,优先选择非机器人用户的消息作为回复目标
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
[inner]
|
||||
version = "0.2.0" # 版本号
|
||||
# 请勿修改版本号,除非你知道自己在做什么
|
||||
|
||||
[nickname] # 现在没用
|
||||
nickname = ""
|
||||
|
||||
[napcat_server] # Napcat连接的ws服务设置
|
||||
mode = "reverse" # 连接模式:reverse=反向连接(作为服务器), forward=正向连接(作为客户端)
|
||||
host = "localhost" # 主机地址
|
||||
port = 8095 # 端口号
|
||||
url = "" # 正向连接时的完整WebSocket URL,如 ws://localhost:8080/ws (仅在forward模式下使用)
|
||||
access_token = "" # WebSocket 连接的访问令牌,用于身份验证(可选)
|
||||
heartbeat_interval = 30 # 心跳间隔时间(按秒计)
|
||||
|
||||
[maibot_server] # 连接麦麦的ws服务设置
|
||||
host = "localhost" # 麦麦在.env文件中设置的主机地址,即HOST字段
|
||||
port = 8000 # 麦麦在.env文件中设置的端口,即PORT字段
|
||||
|
||||
[voice] # 发送语音设置
|
||||
use_tts = false # 是否使用tts语音(请确保你配置了tts并有对应的adapter)
|
||||
|
||||
[debug]
|
||||
level = "INFO" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
|
||||
@@ -233,6 +233,19 @@ class DefaultReplyer:
|
||||
|
||||
self.tool_executor = ToolExecutor(chat_id=self.chat_stream.stream_id)
|
||||
|
||||
def _should_block_self_message(self, reply_message: Optional[Dict[str, Any]]) -> bool:
|
||||
"""判定是否应阻断当前待处理消息(自消息且无外部触发)"""
|
||||
try:
|
||||
bot_id = str(global_config.bot.qq_account)
|
||||
uid = str(reply_message.get("user_id"))
|
||||
if uid != bot_id:
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"[SelfGuard] 判定异常,回退为不阻断: {e}")
|
||||
return False
|
||||
|
||||
async def generate_reply_with_context(
|
||||
self,
|
||||
reply_to: str = "",
|
||||
@@ -260,6 +273,10 @@ class DefaultReplyer:
|
||||
prompt = None
|
||||
if available_actions is None:
|
||||
available_actions = {}
|
||||
# 自消息阻断
|
||||
if self._should_block_self_message(reply_message):
|
||||
logger.debug("[SelfGuard] 阻断:自消息且无外部触发。")
|
||||
return False, None, None
|
||||
llm_response = None
|
||||
try:
|
||||
# 构建 Prompt
|
||||
@@ -822,36 +839,35 @@ class DefaultReplyer:
|
||||
# 兼容旧的reply_to
|
||||
sender, target = self._parse_reply_target(reply_to)
|
||||
else:
|
||||
# 获取 platform,如果不存在则从 chat_stream 获取,如果还是 None 则使用默认值
|
||||
if reply_message is None:
|
||||
logger.warning("reply_message 为 None,无法构建prompt")
|
||||
return ""
|
||||
platform = reply_message.get("chat_info_platform")
|
||||
person_id = person_info_manager.get_person_id(
|
||||
platform, # type: ignore
|
||||
reply_message.get("user_id"), # type: ignore
|
||||
)
|
||||
person_info = await person_info_manager.get_values(person_id, ["person_name", "user_id"])
|
||||
person_name = person_info.get("person_name")
|
||||
|
||||
# 如果person_name为None,使用fallback值
|
||||
if person_name is None:
|
||||
# 尝试从reply_message获取用户名
|
||||
fallback_name = reply_message.get("user_nickname") or reply_message.get("user_id", "未知用户")
|
||||
logger.warning(f"无法获取person_name,使用fallback: {fallback_name}")
|
||||
person_name = str(fallback_name)
|
||||
|
||||
# 检查是否是bot自己的名字,如果是则替换为"(你)"
|
||||
# 需求:遍历最近消息,找到第一条 user_id != bot_id 的消息作为目标;找不到则静默退出
|
||||
bot_user_id = str(global_config.bot.qq_account)
|
||||
current_user_id = person_info.get("user_id")
|
||||
current_platform = reply_message.get("chat_info_platform")
|
||||
|
||||
if current_user_id == bot_user_id and current_platform == global_config.bot.platform:
|
||||
sender = f"{person_name}(你)"
|
||||
# 优先使用传入的 reply_message 如果它不是 bot
|
||||
candidate_msg = None
|
||||
if reply_message and str(reply_message.get("user_id")) != bot_user_id:
|
||||
candidate_msg = reply_message
|
||||
else:
|
||||
# 如果不是bot自己,直接使用person_name
|
||||
try:
|
||||
recent_msgs = await get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=chat_id,
|
||||
timestamp=time.time(),
|
||||
limit= max(10, int(global_config.chat.max_context_size * 0.5)),
|
||||
)
|
||||
# 从最近到更早遍历,找第一条不是bot的
|
||||
for m in reversed(recent_msgs):
|
||||
if str(m.get("user_id")) != bot_user_id:
|
||||
candidate_msg = m
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"获取最近消息失败: {e}")
|
||||
if not candidate_msg:
|
||||
logger.debug("未找到可作为目标的非bot消息,静默不回复。")
|
||||
return ""
|
||||
platform = candidate_msg.get("chat_info_platform") or self.chat_stream.platform
|
||||
person_id = person_info_manager.get_person_id(platform, candidate_msg.get("user_id"))
|
||||
person_info = await person_info_manager.get_values(person_id, ["person_name", "user_id"]) if person_id else {}
|
||||
person_name = person_info.get("person_name") or candidate_msg.get("user_nickname") or candidate_msg.get("user_id") or "未知用户"
|
||||
sender = person_name
|
||||
target = reply_message.get("processed_plain_text")
|
||||
target = candidate_msg.get("processed_plain_text") or candidate_msg.get("raw_message") or ""
|
||||
|
||||
# 最终的空值检查,确保sender和target不为None
|
||||
if sender is None:
|
||||
@@ -867,6 +883,8 @@ class DefaultReplyer:
|
||||
|
||||
target = replace_user_references_sync(target, chat_stream.platform, replace_bot_name=True)
|
||||
|
||||
# (简化)不再对自消息做额外任务段落清理,只通过前置选择逻辑避免自目标
|
||||
|
||||
# 构建action描述 (如果启用planner)
|
||||
action_descriptions = ""
|
||||
if available_actions:
|
||||
@@ -895,7 +913,6 @@ class DefaultReplyer:
|
||||
read_mark=0.0,
|
||||
show_actions=True,
|
||||
)
|
||||
|
||||
# 获取目标用户信息,用于s4u模式
|
||||
target_user_info = None
|
||||
if sender:
|
||||
@@ -1068,6 +1085,8 @@ class DefaultReplyer:
|
||||
prompt = Prompt(template=template_prompt.template, parameters=prompt_parameters)
|
||||
prompt_text = await prompt.build()
|
||||
|
||||
# 自目标情况已在上游通过筛选避免,这里不再额外修改 prompt
|
||||
|
||||
# --- 动态添加分割指令 ---
|
||||
if global_config.response_splitter.enable and global_config.response_splitter.split_mode == "llm":
|
||||
split_instruction = """
|
||||
|
||||
Reference in New Issue
Block a user