From 135909449cac07ded647ab4488a7035510dbaf19 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 3 Oct 2025 19:39:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor(proactive=5Fthinker):=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=94=A4=E9=86=92=E9=80=BB=E8=BE=91=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=98=B2=E6=89=93=E6=89=B0=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构了日常唤醒任务(ProactiveThinkingTask)的逻辑,将其拆分为私聊和群聊的独立处理流程。 - 私聊现在直接遍历白名单,确保能覆盖到所有配置的用户,即使他们当前不在内存中。 - 群聊则继续遍历内存中的活跃流。 这个改动修复了之前版本中,只有当用户发送消息后,bot才有可能对其进行主动唤醒的问题。 同时,在决策模块中引入了防打扰机制: - 在决策提示词中加入了最近的决策历史记录作为上下文。 - 增加了新的决策原则,明确指示模型在近期已主动发起过对话的情况下,应倾向于保持沉默,以避免过度打扰用户。 此外,对冷启动任务(ColdStartTask)进行了微调,将初始的等待时间移至循环的开始,以确保插件加载后能先等待一段时间再开始工作。 --- .../proacive_thinker_event.py | 81 ++++++++++--------- .../proactive_thinker_executor.py | 7 ++ 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/plugins/built_in/proactive_thinker/proacive_thinker_event.py b/src/plugins/built_in/proactive_thinker/proacive_thinker_event.py index 88fa169e8..c310e5c45 100644 --- a/src/plugins/built_in/proactive_thinker/proacive_thinker_event.py +++ b/src/plugins/built_in/proactive_thinker/proacive_thinker_event.py @@ -38,6 +38,8 @@ class ColdStartTask(AsyncTask): while True: try: + #开始就先暂停一小时,等bot聊一会再说() + await asyncio.sleep(3600) logger.info("【冷启动】开始扫描白名单,寻找从未聊过的用户...") # 从全局配置中获取私聊白名单 @@ -83,9 +85,6 @@ class ColdStartTask(AsyncTask): except Exception as e: logger.error(f"【冷启动】处理用户 {chat_id} 时发生未知错误: {e}", exc_info=True) - # 完成一轮检查后,进入长时休眠 - await asyncio.sleep(3600) - except asyncio.CancelledError: logger.info("冷启动任务被正常取消。") break @@ -157,44 +156,50 @@ class ProactiveThinkingTask(AsyncTask): enabled_private = set(global_config.proactive_thinking.enabled_private_chats) enabled_groups = set(global_config.proactive_thinking.enabled_group_chats) - # 获取当前所有聊天流的快照 - all_streams = list(self.chat_manager.streams.values()) - - for stream in all_streams: - # 1. 检查该聊天是否在白名单内(或白名单为空时默认允许) - is_whitelisted = False - if stream.group_info: # 群聊 - if not enabled_groups or f"qq:{stream.group_info.group_id}" in enabled_groups: - is_whitelisted = True - else: # 私聊 - if not enabled_private or f"qq:{stream.user_info.user_id}" in enabled_private: - is_whitelisted = True - - if not is_whitelisted: - continue # 不在白名单内,跳过 - - # 2. 【核心逻辑】检查聊天冷却时间是否足够长 - time_since_last_active = time.time() - stream.last_active_time - if time_since_last_active > next_interval: - logger.info( - f"【日常唤醒】聊天流 {stream.stream_id} 已冷却 {time_since_last_active:.2f} 秒,触发主动对话。" - ) - - # 构建符合 executor 期望的 stream_id 格式 - if stream.group_info and stream.group_info.group_id: - formatted_stream_id = f"{stream.user_info.platform}:{stream.group_info.group_id}:group" - elif stream.user_info and stream.user_info.user_id: - formatted_stream_id = f"{stream.user_info.platform}:{stream.user_info.user_id}:private" - else: - logger.warning(f"【日常唤醒】跳过 stream {stream.stream_id},因为它缺少有效的用户信息或群组信息。") + # 分别处理私聊和群聊 + # 1. 处理私聊:直接遍历白名单,确保能覆盖到所有(包括本次运行尚未活跃的)用户 + for chat_id in enabled_private: + try: + platform, user_id_str = chat_id.split(":") + # 【核心逻辑】检查聊天流是否存在。不存在则跳过,交由ColdStartTask处理。 + stream = chat_api.get_stream_by_user_id(user_id_str, platform) + if not stream: continue - await self.executor.execute(stream_id=formatted_stream_id, start_mode="wake_up") + # 检查冷却时间 + time_since_last_active = time.time() - stream.last_active_time + if time_since_last_active > next_interval: + logger.info( + f"【日常唤醒-私聊】聊天流 {stream.stream_id} 已冷却 {time_since_last_active:.2f} 秒,触发主动对话。" + ) + formatted_stream_id = f"{stream.user_info.platform}:{stream.user_info.user_id}:private" + await self.executor.execute(stream_id=formatted_stream_id, start_mode="wake_up") + stream.update_active_time() + await self.chat_manager._save_stream(stream) - # 【关键步骤】在触发后,立刻更新活跃时间并保存。 - # 这可以防止在同一个检查周期内,对同一个目标因为意外的延迟而发送多条消息。 - stream.update_active_time() - await self.chat_manager._save_stream(stream) + except ValueError: + logger.warning(f"【日常唤醒】私聊白名单条目格式错误,已跳过: {chat_id}") + except Exception as e: + logger.error(f"【日常唤醒】处理私聊用户 {chat_id} 时发生未知错误: {e}", exc_info=True) + + # 2. 处理群聊:遍历内存中的活跃流(群聊不存在冷启动问题) + all_streams = list(self.chat_manager.streams.values()) + for stream in all_streams: + if not stream.group_info: + continue # 只处理群聊 + + # 检查群聊是否在白名单内 + if not enabled_groups or f"qq:{stream.group_info.group_id}" in enabled_groups: + # 检查冷却时间 + time_since_last_active = time.time() - stream.last_active_time + if time_since_last_active > next_interval: + logger.info( + f"【日常唤醒-群聊】聊天流 {stream.stream_id} 已冷却 {time_since_last_active:.2f} 秒,触发主动对话。" + ) + formatted_stream_id = f"{stream.user_info.platform}:{stream.group_info.group_id}:group" + await self.executor.execute(stream_id=formatted_stream_id, start_mode="wake_up") + stream.update_active_time() + await self.chat_manager._save_stream(stream) except asyncio.CancelledError: logger.info("日常唤醒任务被正常取消。") diff --git a/src/plugins/built_in/proactive_thinker/proactive_thinker_executor.py b/src/plugins/built_in/proactive_thinker/proactive_thinker_executor.py index f4f41426b..ea5187f1f 100644 --- a/src/plugins/built_in/proactive_thinker/proactive_thinker_executor.py +++ b/src/plugins/built_in/proactive_thinker/proactive_thinker_executor.py @@ -240,6 +240,9 @@ class ProactiveThinkerExecutor: - 身份: {persona["identity"]} 你的当前情绪状态是: {context["mood_state"]} + +# 你最近的相关决策历史 (供参考) +{context["action_history_context"]} """ # 根据聊天类型构建任务和情境 if chat_type == "private": @@ -283,6 +286,10 @@ class ProactiveThinkerExecutor: - `topic`: str, 如果 `should_reply` 为 true,你打算聊什么话题?(例如:问候一下今天的日程、关心一下昨天的某件事、分享一个你自己的趣事等) - `reason`: str, 做出此决策的简要理由。 +# 决策原则 +- **避免打扰**: 如果你最近(尤其是在最近的几次决策中)已经主动发起过对话,请倾向于选择“不回复”,除非有非常重要和紧急的事情。 + + --- 示例1 (应该回复): {{