feat:优化了了auto模式切换逻辑

This commit is contained in:
SengokuCola
2025-06-14 13:09:13 +08:00
parent 8158f2cda4
commit bf0e813142
11 changed files with 190 additions and 131 deletions

View File

@@ -154,54 +154,61 @@ class NormalChat:
通常由start_monitoring_interest()启动
"""
while True:
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
await asyncio.sleep(0.5) # 每秒检查一次
# 检查任务是否已被取消
if self._chat_task is None or self._chat_task.cancelled():
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消或置空,退出")
break
try:
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
await asyncio.sleep(0.5) # 每秒检查一次
# 检查任务是否已被取消
if self._chat_task is None or self._chat_task.cancelled():
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消或置空,退出")
break
items_to_process = list(self.interest_dict.items())
if not items_to_process:
continue
items_to_process = list(self.interest_dict.items())
if not items_to_process:
continue
# 并行处理兴趣消息
async def process_single_message(msg_id, message, interest_value, is_mentioned):
"""处理单个兴趣消息"""
try:
# 处理消息
if time.time() - self.start_time > 300:
self.adjust_reply_frequency(duration=300 / 60)
else:
self.adjust_reply_frequency(duration=(time.time() - self.start_time) / 60)
# 并行处理兴趣消息
async def process_single_message(msg_id, message, interest_value, is_mentioned):
"""处理单个兴趣消息"""
try:
# 处理消息
if time.time() - self.start_time > 300:
self.adjust_reply_frequency(duration=300 / 60)
else:
self.adjust_reply_frequency(duration=(time.time() - self.start_time) / 60)
await self.normal_response(
message=message,
is_mentioned=is_mentioned,
interested_rate=interest_value * self.willing_amplifier,
)
except Exception as e:
logger.error(f"[{self.stream_name}] 处理兴趣消息{msg_id}时出错: {e}\n{traceback.format_exc()}")
finally:
self.interest_dict.pop(msg_id, None)
await self.normal_response(
message=message,
is_mentioned=is_mentioned,
interested_rate=interest_value * self.willing_amplifier,
)
except Exception as e:
logger.error(f"[{self.stream_name}] 处理兴趣消息{msg_id}时出错: {e}\n{traceback.format_exc()}")
finally:
self.interest_dict.pop(msg_id, None)
# 创建并行任务列表
tasks = []
for msg_id, (message, interest_value, is_mentioned) in items_to_process:
task = process_single_message(msg_id, message, interest_value, is_mentioned)
tasks.append(task)
# 创建并行任务列表
tasks = []
for msg_id, (message, interest_value, is_mentioned) in items_to_process:
task = process_single_message(msg_id, message, interest_value, is_mentioned)
tasks.append(task)
# 并行执行所有任务,限制并发数量避免资源过度消耗
if tasks:
# 使用信号量控制并发数最多同时处理5个消息
semaphore = asyncio.Semaphore(5)
# 并行执行所有任务,限制并发数量避免资源过度消耗
if tasks:
# 使用信号量控制并发数最多同时处理5个消息
semaphore = asyncio.Semaphore(5)
async def limited_process(task):
async with semaphore:
await task
async def limited_process(task):
async with semaphore:
await task
limited_tasks = [limited_process(task) for task in tasks]
await asyncio.gather(*limited_tasks, return_exceptions=True)
limited_tasks = [limited_process(task) for task in tasks]
await asyncio.gather(*limited_tasks, return_exceptions=True)
except asyncio.CancelledError:
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消")
break
except Exception as e:
logger.error(f"[{self.stream_name}] 兴趣监控任务出错: {e}\n{traceback.format_exc()}")
await asyncio.sleep(1) # 出错后等待一秒再继续
# 改为实例方法, 移除 chat 参数
async def normal_response(self, message: MessageRecv, is_mentioned: bool, interested_rate: float) -> None:
@@ -259,7 +266,7 @@ class NormalChat:
await self.action_modifier.modify_actions_for_normal_chat(
self.chat_stream, self.recent_replies, message.processed_plain_text
)
available_actions = self.action_manager.get_using_actions()
available_actions = self.action_manager.get_using_actions_for_mode("normal")
except Exception as e:
logger.warning(f"[{self.stream_name}] 获取available_actions失败: {e}")
available_actions = None
@@ -428,12 +435,6 @@ class NormalChat:
else:
logger.warning(f"[{self.stream_name}] 没有设置切换到focus聊天模式的回调函数无法执行切换")
return
else:
await self._check_switch_to_focus()
pass
# with Timer("关系更新", timing_results):
# await self._update_relationship(message, response_set)
# 回复后处理
await willing_manager.after_generate_reply_handle(message.message_info.message_id)
@@ -494,7 +495,10 @@ class NormalChat:
logger.debug(f"[{self.stream_name}] 尝试取消normal聊天任务。")
task.cancel()
try:
await task # 等待任务响应取消
# 添加超时机制最多等待2秒
await asyncio.wait_for(task, timeout=2.0)
except asyncio.TimeoutError:
logger.warning(f"[{self.stream_name}] 等待任务取消超时,强制结束")
except asyncio.CancelledError:
logger.info(f"[{self.stream_name}] 结束一般聊天模式。")
except Exception as e:
@@ -539,29 +543,6 @@ class NormalChat:
# 返回最近的limit条记录按时间倒序排列
return sorted(self.recent_replies[-limit:], key=lambda x: x["time"], reverse=True)
async def _check_switch_to_focus(self) -> None:
"""检查是否满足切换到focus模式的条件"""
if not self.on_switch_to_focus_callback:
return # 如果没有设置回调函数,直接返回
current_time = time.time()
time_threshold = 120 / global_config.chat.auto_focus_threshold
reply_threshold = 6 * global_config.chat.auto_focus_threshold
one_minute_ago = current_time - time_threshold
# 统计1分钟内的回复数量
recent_reply_count = sum(1 for reply in self.recent_replies if reply["time"] > one_minute_ago)
if recent_reply_count > reply_threshold:
logger.info(
f"[{self.stream_name}] 检测到1分钟内回复数量({recent_reply_count})大于{reply_threshold}触发切换到focus模式"
)
try:
# 调用回调函数通知上层切换到focus模式
await self.on_switch_to_focus_callback()
except Exception as e:
logger.error(f"[{self.stream_name}] 触发切换到focus模式时出错: {e}\n{traceback.format_exc()}")
def adjust_reply_frequency(self, duration: int = 10):
"""
调整回复频率

View File

@@ -5,6 +5,8 @@ from src.chat.utils.chat_message_builder import build_readable_messages, get_raw
from src.config.config import global_config
import random
import time
from src.chat.message_receive.message_sender import message_manager
from src.chat.message_receive.message import MessageThinking
logger = get_logger("normal_chat_action_modifier")
@@ -42,6 +44,7 @@ class NormalChatActionModifier:
Args:
chat_stream: 聊天流对象
recent_replies: 最近的回复记录
message_content: 当前消息内容
**kwargs: 其他参数
"""
@@ -104,7 +107,7 @@ class NormalChatActionModifier:
# print(f"current_actions: {current_actions}")
# print(f"chat_content: {chat_content}")
final_activated_actions = await self._apply_normal_activation_filtering(
current_actions, chat_content, message_content
current_actions, chat_content, message_content, recent_replies
)
# print(f"final_activated_actions: {final_activated_actions}")
@@ -157,6 +160,7 @@ class NormalChatActionModifier:
actions_with_info: Dict[str, Any],
chat_content: str = "",
message_content: str = "",
recent_replies: List[dict] = None,
) -> Dict[str, Any]:
"""
应用Normal模式的激活类型过滤逻辑
@@ -166,22 +170,37 @@ class NormalChatActionModifier:
2. RANDOM类型保持概率激活
3. KEYWORD类型保持关键词匹配
4. ALWAYS类型直接激活
5. change_to_focus_chat 特殊处理:根据回复频率判断
Args:
actions_with_info: 带完整信息的动作字典
chat_content: 聊天内容
message_content: 当前消息内容
recent_replies: 最近的回复记录列表
Returns:
Dict[str, Any]: 过滤后激活的actions字典
"""
activated_actions = {}
# 特殊处理 change_to_focus_chat 动作
if "change_to_focus_chat" in actions_with_info:
# 检查是否满足切换到focus模式的条件
if await self._check_should_switch_to_focus(recent_replies):
activated_actions["change_to_focus_chat"] = actions_with_info["change_to_focus_chat"]
logger.debug(f"{self.log_prefix} 特殊激活 change_to_focus_chat 动作,原因: 满足切换到focus模式条件")
return activated_actions
# 分类处理不同激活类型的actions
always_actions = {}
random_actions = {}
keyword_actions = {}
for action_name, action_info in actions_with_info.items():
# 跳过已特殊处理的 change_to_focus_chat
if action_name == "change_to_focus_chat":
continue
# 使用normal_activation_type
activation_type = action_info.get("normal_activation_type", "always")
@@ -220,8 +239,6 @@ class NormalChatActionModifier:
else:
keywords = action_info.get("activation_keywords", [])
logger.debug(f"{self.log_prefix}未激活动作: {action_name},原因: KEYWORD类型未匹配关键词{keywords}")
# print(f"keywords: {keywords}")
# print(f"chat_content: {chat_content}")
logger.debug(f"{self.log_prefix}Normal模式激活类型过滤完成: {list(activated_actions.keys())}")
return activated_actions
@@ -276,6 +293,46 @@ class NormalChatActionModifier:
logger.debug(f"{self.log_prefix}动作 {action_name} 未匹配到任何关键词: {activation_keywords}")
return False
async def _check_should_switch_to_focus(self, recent_replies: List[dict]) -> bool:
"""
检查是否满足切换到focus模式的条件
Args:
recent_replies: 最近的回复记录列表
Returns:
bool: 是否应该切换到focus模式
"""
# 检查思考消息堆积情况
container = await message_manager.get_container(self.stream_id)
if container:
thinking_count = sum(1 for msg in container.messages if isinstance(msg, MessageThinking))
print(f"thinking_count: {thinking_count}")
if thinking_count >= 4 / global_config.chat.auto_focus_threshold: # 如果堆积超过3条思考消息
logger.debug(f"{self.log_prefix} 检测到思考消息堆积({thinking_count}条)切换到focus模式")
return True
if not recent_replies:
return False
current_time = time.time()
time_threshold = 120 / global_config.chat.auto_focus_threshold
reply_threshold = 6 * global_config.chat.auto_focus_threshold
one_minute_ago = current_time - time_threshold
# 统计1分钟内的回复数量
recent_reply_count = sum(1 for reply in recent_replies if reply["time"] > one_minute_ago)
print(f"recent_reply_count: {recent_reply_count}")
print(f"reply_threshold: {reply_threshold}")
should_switch = recent_reply_count > reply_threshold
if should_switch:
logger.debug(f"{self.log_prefix} 检测到1分钟内回复数量({recent_reply_count})大于{reply_threshold}满足切换到focus模式条件")
return should_switch
def get_available_actions_count(self) -> int:
"""获取当前可用动作数量排除默认的no_action"""
current_actions = self.action_manager.get_using_actions_for_mode("normal")

View File

@@ -36,7 +36,6 @@ def init_prompt():
重要说明:
- "no_action" 表示只进行普通聊天回复,不执行任何额外动作
- "change_to_focus_chat" 表示当聊天变得热烈、自己回复条数很多或需要深入交流时正常回复消息并切换到focus_chat模式进行更深入的对话
- 其他action表示在普通回复的基础上执行相应的额外动作
你必须从上面列出的可用action中选择一个并说明原因。
@@ -159,7 +158,7 @@ class NormalChatPlanner:
try:
content, (reasoning_content, model_name) = await self.planner_llm.generate_response_async(prompt)
# logger.info(f"{self.log_prefix}规划器原始提示词: {prompt}")
logger.info(f"{self.log_prefix}规划器原始提示词: {prompt}")
logger.info(f"{self.log_prefix}规划器原始响应: {content}")
logger.info(f"{self.log_prefix}规划器推理: {reasoning_content}")
logger.info(f"{self.log_prefix}规划器模型: {model_name}")
@@ -177,7 +176,7 @@ class NormalChatPlanner:
action_data = {k: v for k, v in action_result.items() if k not in ["action", "reasoning"]}
# 验证动作是否在可用动作列表中,或者是特殊动作
if action not in current_available_actions and action != "change_to_focus_chat":
if action not in current_available_actions:
logger.warning(f"{self.log_prefix}规划器选择了不可用的动作: {action}, 回退到no_action")
action = "no_action"
reasoning = f"选择的动作{action}不在可用列表中回退到no_action"
@@ -257,21 +256,6 @@ class NormalChatPlanner:
# 构建动作选项文本
action_options_text = ""
# 添加特殊的change_to_focus_chat动作
action_options_text += "动作change_to_focus_chat\n"
action_options_text += "该动作的描述当聊天变得热烈、自己回复条数很多或需要深入交流时使用正常回复消息并切换到focus_chat模式\n"
action_options_text += "使用该动作的场景:\n"
action_options_text += "- 聊天上下文中自己的回复条数较多超过3-4条\n"
action_options_text += "- 对话进行得非常热烈活跃\n"
action_options_text += "- 用户表现出深入交流的意图\n"
action_options_text += "- 话题需要更专注和深入的讨论\n\n"
action_options_text += "输出要求:\n"
action_options_text += "{{"
action_options_text += ' "action": "change_to_focus_chat"'
action_options_text += "}}\n\n"
for action_name, action_info in current_available_actions.items():
action_description = action_info.get("description", "")
action_parameters = action_info.get("parameters", {})

View File

@@ -219,7 +219,7 @@ class PromptBuilder:
# 构建action描述 (如果启用planner)
action_descriptions = ""
logger.debug(f"Enable planner {enable_planner}, available actions: {available_actions}")
# logger.debug(f"Enable planner {enable_planner}, available actions: {available_actions}")
if enable_planner and available_actions:
action_descriptions = "你有以下的动作能力,但执行这些动作不由你决定,由另外一个模型同步决定,因此你只需要知道有如下能力即可:\n"
for action_name, action_info in available_actions.items():