refactor(proactive_thinker): 优化唤醒逻辑并增加防打扰机制
重构了日常唤醒任务(ProactiveThinkingTask)的逻辑,将其拆分为私聊和群聊的独立处理流程。 - 私聊现在直接遍历白名单,确保能覆盖到所有配置的用户,即使他们当前不在内存中。 - 群聊则继续遍历内存中的活跃流。 这个改动修复了之前版本中,只有当用户发送消息后,bot才有可能对其进行主动唤醒的问题。 同时,在决策模块中引入了防打扰机制: - 在决策提示词中加入了最近的决策历史记录作为上下文。 - 增加了新的决策原则,明确指示模型在近期已主动发起过对话的情况下,应倾向于保持沉默,以避免过度打扰用户。 此外,对冷启动任务(ColdStartTask)进行了微调,将初始的等待时间移至循环的开始,以确保插件加载后能先等待一段时间再开始工作。
This commit is contained in:
@@ -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,42 +156,48 @@ 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())
|
||||
# 分别处理私聊和群聊
|
||||
# 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
|
||||
|
||||
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} 秒,触发主动对话。"
|
||||
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},因为它缺少有效的用户信息或群组信息。")
|
||||
continue
|
||||
|
||||
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 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)
|
||||
|
||||
|
||||
@@ -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 (应该回复):
|
||||
{{
|
||||
|
||||
Reference in New Issue
Block a user