From 709e00a404cfda9bc063fc59416571449e3b2824 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 11 Aug 2025 14:50:13 +0800 Subject: [PATCH] =?UTF-8?q?better=EF=BC=9A=E6=98=8E=E7=A1=AEfocus=20value?= =?UTF-8?q?=E5=92=8C=20talk=20frequency=E7=9A=84=E4=BD=9C=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete test_focus_value.py --- src/chat/chat_loop/heartFC_chat.py | 86 +++++----- .../heart_flow/heartflow_message_processor.py | 3 - src/config/config.py | 2 - src/config/official_configs.py | 157 +++++++++++++++--- template/bot_config_template.toml | 36 ++-- 5 files changed, 193 insertions(+), 91 deletions(-) diff --git a/src/chat/chat_loop/heartFC_chat.py b/src/chat/chat_loop/heartFC_chat.py index dd6071109..dacafa500 100644 --- a/src/chat/chat_loop/heartFC_chat.py +++ b/src/chat/chat_loop/heartFC_chat.py @@ -201,16 +201,16 @@ class HeartFChatting: total_recent_interest = sum(self.recent_interest_records) # 计算调整后的阈值 - adjusted_threshold = 3 / global_config.chat.get_current_talk_frequency(self.stream_id) + adjusted_threshold = 1 / global_config.chat.get_current_talk_frequency(self.stream_id) logger.info(f"{self.log_prefix} 最近三次兴趣度总和: {total_recent_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}") # 如果兴趣度总和小于阈值,进入breaking形式 if total_recent_interest < adjusted_threshold: - logger.info(f"{self.log_prefix} 兴趣度不足,进入breaking形式") + logger.info(f"{self.log_prefix} 兴趣度不足,进入休息") self.focus_energy = random.randint(3, 6) else: - logger.info(f"{self.log_prefix} 兴趣度充足") + logger.info(f"{self.log_prefix} 兴趣度充足,等待新消息") self.focus_energy = 1 async def _should_process_messages(self, new_message: List[Dict[str, Any]]) -> tuple[bool,float]: @@ -225,9 +225,10 @@ class HeartFChatting: bool: 是否应该处理消息 """ new_message_count = len(new_message) + talk_frequency = global_config.chat.get_current_talk_frequency(self.stream_id) - modified_exit_count_threshold = self.focus_energy / global_config.chat.focus_value - modified_exit_interest_threshold = 3 / global_config.chat.focus_value + modified_exit_count_threshold = self.focus_energy * 0.5 / talk_frequency + modified_exit_interest_threshold = 1.5 / talk_frequency total_interest = 0.0 for msg_dict in new_message: interest_value = msg_dict.get("interest_value", 0.0) @@ -247,7 +248,7 @@ class HeartFChatting: if new_message_count > 0: # 只在兴趣值变化时输出log if not hasattr(self, "_last_accumulated_interest") or total_interest != self._last_accumulated_interest: - logger.info(f"{self.log_prefix} breaking形式当前累计兴趣值: {total_interest:.2f}, 专注度: {global_config.chat.focus_value:.1f}") + logger.info(f"{self.log_prefix} 休息中,累计兴趣值: {total_interest:.2f}, 活跃度: {talk_frequency:.1f}") self._last_accumulated_interest = total_interest if total_interest >= modified_exit_interest_threshold: @@ -363,7 +364,7 @@ class HeartFChatting: x0 = 1.0 # 控制曲线中心点 return 1.0 / (1.0 + math.exp(-k * (interest_val - x0))) - normal_mode_probability = calculate_normal_mode_probability(interest_value) / global_config.chat.get_current_talk_frequency(self.stream_id) + normal_mode_probability = calculate_normal_mode_probability(interest_value) * 0.5 / global_config.chat.get_current_talk_frequency(self.stream_id) # 根据概率决定使用哪种模式 if random.random() < normal_mode_probability: @@ -385,33 +386,43 @@ class HeartFChatting: await self.relationship_builder.build_relation() await self.expression_learner.trigger_learning_for_chat() - available_actions = {} - # 第一步:动作修改 - with Timer("动作修改", cycle_timers): - try: - await self.action_modifier.modify_actions() - available_actions = self.action_manager.get_using_actions() - except Exception as e: - logger.error(f"{self.log_prefix} 动作修改失败: {e}") + if random.random() > global_config.chat.focus_value and mode == ChatMode.FOCUS: + #如果激活度没有激活,并且聊天活跃度低,有可能不进行plan,相当于不在电脑前 + actions = [ + { + "action_type": "no_reply", + "reasoning": "选择不回复", + "action_data": {}, + } + ] + else: + available_actions = {} + # 第一步:动作修改 + with Timer("动作修改", cycle_timers): + try: + await self.action_modifier.modify_actions() + available_actions = self.action_manager.get_using_actions() + except Exception as e: + logger.error(f"{self.log_prefix} 动作修改失败: {e}") - # 执行planner - planner_info = self.action_planner.get_necessary_info() - prompt_info = await self.action_planner.build_planner_prompt( - is_group_chat=planner_info[0], - chat_target_info=planner_info[1], - current_available_actions=planner_info[2], - ) - if not await events_manager.handle_mai_events( - EventType.ON_PLAN, None, prompt_info[0], None, self.chat_stream.stream_id - ): - return False - with Timer("规划器", cycle_timers): - actions, _= await self.action_planner.plan( - mode=mode, - loop_start_time=self.last_read_time, - available_actions=available_actions, + # 执行planner + planner_info = self.action_planner.get_necessary_info() + prompt_info = await self.action_planner.build_planner_prompt( + is_group_chat=planner_info[0], + chat_target_info=planner_info[1], + current_available_actions=planner_info[2], ) + if not await events_manager.handle_mai_events( + EventType.ON_PLAN, None, prompt_info[0], None, self.chat_stream.stream_id + ): + return False + with Timer("规划器", cycle_timers): + actions, _= await self.action_planner.plan( + mode=mode, + loop_start_time=self.last_read_time, + available_actions=available_actions, + ) @@ -663,19 +674,10 @@ class HeartFChatting: # 处理动作并获取结果 result = await action_handler.handle_action() - success, reply_text = result + success, action_text = result command = "" - if reply_text == "timeout": - self.reply_timeout_count += 1 - if self.reply_timeout_count > 5: - logger.warning( - f"[{self.log_prefix} ] 连续回复超时次数过多,{global_config.chat.thinking_timeout}秒 内大模型没有返回有效内容,请检查你的api是否速度过慢或配置错误。建议不要使用推理模型,推理模型生成速度过慢。或者尝试拉高thinking_timeout参数,这可能导致回复时间过长。" - ) - logger.warning(f"{self.log_prefix} 回复生成超时{global_config.chat.thinking_timeout}s,已跳过") - return False, "", "" - - return success, reply_text, command + return success, action_text, command except Exception as e: logger.error(f"{self.log_prefix} 处理{action}时出错: {e}") diff --git a/src/chat/heart_flow/heartflow_message_processor.py b/src/chat/heart_flow/heartflow_message_processor.py index 3ed3a3e41..e750cfec3 100644 --- a/src/chat/heart_flow/heartflow_message_processor.py +++ b/src/chat/heart_flow/heartflow_message_processor.py @@ -145,8 +145,6 @@ class HeartFCMessageReceiver: # 3. 日志记录 mes_name = chat.group_info.group_name if chat.group_info else "私聊" - # current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time)) - current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id) # 如果消息中包含图片标识,则将 [picid:...] 替换为 [图片] picid_pattern = r"\[picid:([^\]]+)\]" @@ -164,7 +162,6 @@ class HeartFCMessageReceiver: else: logger.info(f"[{mes_name}]{userinfo.user_nickname}:{processed_plain_text}[兴趣度:{interested_rate:.2f}]") # type: ignore - logger.debug(f"[{mes_name}][当前时段回复频率: {current_talk_frequency}]") # 4. 关系处理 if global_config.relationship.enable_relationship: diff --git a/src/config/config.py b/src/config/config.py index 021275514..c25320cca 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -17,7 +17,6 @@ from src.config.official_configs import ( PersonalityConfig, ExpressionConfig, ChatConfig, - NormalChatConfig, EmojiConfig, MemoryConfig, MoodConfig, @@ -331,7 +330,6 @@ class Config(ConfigBase): relationship: RelationshipConfig chat: ChatConfig message_receive: MessageReceiveConfig - normal_chat: NormalChatConfig emoji: EmojiConfig expression: ExpressionConfig memory: MemoryConfig diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 652440e69..a83608fae 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -72,28 +72,26 @@ class ChatConfig(ConfigBase): max_context_size: int = 18 """上下文长度""" - replyer_random_probability: float = 0.5 - """ - 发言时选择推理模型的概率(0-1之间) - 选择普通模型的概率为 1 - reasoning_normal_model_probability - """ - - thinking_timeout: int = 40 - """麦麦最长思考规划时间,超过这个时间的思考会放弃(往往是api反应太慢)""" - - talk_frequency: float = 1 - """回复频率阈值""" - mentioned_bot_inevitable_reply: bool = False """提及 bot 必然回复""" at_bot_inevitable_reply: bool = False """@bot 必然回复""" + + talk_frequency: float = 0.5 + """回复频率阈值""" # 合并后的时段频率配置 talk_frequency_adjust: list[list[str]] = field(default_factory=lambda: []) + + + focus_value: float = 0.5 + """麦麦的专注思考能力,越低越容易专注,消耗token也越多""" + + focus_value_adjust: list[list[str]] = field(default_factory=lambda: []) + """ - 统一的时段频率配置 + 统一的活跃度和专注度配置 格式:[["platform:chat_id:type", "HH:MM,frequency", "HH:MM,frequency", ...], ...] 全局配置示例: @@ -110,11 +108,31 @@ class ChatConfig(ConfigBase): - 当第一个元素为空字符串""时,表示全局默认配置 - 当第一个元素为"platform:id:type"格式时,表示特定聊天流配置 - 后续元素是"时间,频率"格式,表示从该时间开始使用该频率,直到下一个时间点 - - 优先级:特定聊天流配置 > 全局配置 > 默认 talk_frequency + - 优先级:特定聊天流配置 > 全局配置 > 默认值 + + 注意: + - talk_frequency_adjust 控制回复频率,数值越高回复越频繁 + - focus_value_adjust 控制专注思考能力,数值越低越容易专注,消耗token也越多 """ - - focus_value: float = 1.0 - """麦麦的专注思考能力,越低越容易专注,消耗token也越多""" + + + def get_current_focus_value(self, chat_stream_id: Optional[str] = None) -> float: + """ + 根据当前时间和聊天流获取对应的 focus_value + """ + if not self.focus_value_adjust: + return self.focus_value + + if chat_stream_id: + stream_focus_value = self._get_stream_specific_focus_value(chat_stream_id) + if stream_focus_value is not None: + return stream_focus_value + + global_focus_value = self._get_global_focus_value() + if global_focus_value is not None: + return global_focus_value + + return self.focus_value def get_current_talk_frequency(self, chat_stream_id: Optional[str] = None) -> float: """ @@ -138,6 +156,71 @@ class ChatConfig(ConfigBase): # 检查全局时段配置(第一个元素为空字符串的配置) global_frequency = self._get_global_frequency() return self.talk_frequency if global_frequency is None else global_frequency + + def _get_global_focus_value(self) -> Optional[float]: + """ + 获取全局默认专注度配置 + + Returns: + float: 专注度值,如果没有配置则返回 None + """ + for config_item in self.focus_value_adjust: + if not config_item or len(config_item) < 2: + continue + + # 检查是否为全局默认配置(第一个元素为空字符串) + if config_item[0] == "": + return self._get_time_based_focus_value(config_item[1:]) + + return None + + def _get_time_based_focus_value(self, time_focus_list: list[str]) -> Optional[float]: + """ + 根据时间配置列表获取当前时段的专注度 + + Args: + time_focus_list: 时间专注度配置列表,格式为 ["HH:MM,focus_value", ...] + + Returns: + float: 专注度值,如果没有配置则返回 None + """ + from datetime import datetime + + current_time = datetime.now().strftime("%H:%M") + current_hour, current_minute = map(int, current_time.split(":")) + current_minutes = current_hour * 60 + current_minute + + # 解析时间专注度配置 + time_focus_pairs = [] + for time_focus_str in time_focus_list: + try: + time_str, focus_str = time_focus_str.split(",") + hour, minute = map(int, time_str.split(":")) + focus_value = float(focus_str) + minutes = hour * 60 + minute + time_focus_pairs.append((minutes, focus_value)) + except (ValueError, IndexError): + continue + + if not time_focus_pairs: + return None + + # 按时间排序 + time_focus_pairs.sort(key=lambda x: x[0]) + + # 查找当前时间对应的专注度 + current_focus_value = None + for minutes, focus_value in time_focus_pairs: + if current_minutes >= minutes: + current_focus_value = focus_value + else: + break + + # 如果当前时间在所有配置时间之前,使用最后一个时间段的专注度(跨天逻辑) + if current_focus_value is None and time_focus_pairs: + current_focus_value = time_focus_pairs[-1][1] + + return current_focus_value def _get_time_based_frequency(self, time_freq_list: list[str]) -> Optional[float]: """ @@ -187,6 +270,37 @@ class ChatConfig(ConfigBase): return current_frequency + def _get_stream_specific_focus_value(self, chat_stream_id: str) -> Optional[float]: + """ + 获取特定聊天流在当前时间的专注度 + + Args: + chat_stream_id: 聊天流ID(哈希值) + + Returns: + float: 专注度值,如果没有配置则返回 None + """ + # 查找匹配的聊天流配置 + for config_item in self.focus_value_adjust: + if not config_item or len(config_item) < 2: + continue + + stream_config_str = config_item[0] # 例如 "qq:1026294844:group" + + # 解析配置字符串并生成对应的 chat_id + config_chat_id = self._parse_stream_config_to_chat_id(stream_config_str) + if config_chat_id is None: + continue + + # 比较生成的 chat_id + if config_chat_id != chat_stream_id: + continue + + # 使用通用的时间专注度解析方法 + return self._get_time_based_focus_value(config_item[1:]) + + return None + def _get_stream_specific_frequency(self, chat_stream_id: str): """ 获取特定聊天流在当前时间的频率 @@ -281,15 +395,6 @@ class MessageReceiveConfig(ConfigBase): ban_msgs_regex: set[str] = field(default_factory=lambda: set()) """过滤正则表达式列表""" - -@dataclass -class NormalChatConfig(ConfigBase): - """普通聊天配置类""" - - willing_mode: str = "classical" - """意愿模式""" - - @dataclass class ExpressionConfig(ConfigBase): """表达配置类""" diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index abdb18f6e..a9eda6814 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "6.3.0" +version = "6.3.1" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请递增version的值 @@ -53,26 +53,29 @@ expression_groups = [ ] -[chat] #麦麦的聊天通用设置 -talk_frequency = 1 -# 麦麦活跃度,越高,麦麦回复越多 +[chat] #麦麦的聊天设置 +talk_frequency = 0.5 +# 麦麦活跃度,越高,麦麦回复越多,范围0-1 +focus_value = 0.5 +# 麦麦的专注度,越高越容易持续连续对话,范围0-1 -focus_value = 1 -# 麦麦的专注思考能力,越高越容易持续连续对话 - -max_context_size = 25 # 上下文长度 -thinking_timeout = 40 # 麦麦一次回复最长思考规划时间,超过这个时间的思考会放弃(往往是api反应太慢) -replyer_random_probability = 0.5 # 首要replyer模型被选择的概率 +max_context_size = 20 # 上下文长度 mentioned_bot_inevitable_reply = true # 提及 bot 大概率回复 at_bot_inevitable_reply = true # @bot 或 提及bot 大概率回复 -talk_frequency_adjust = [ - ["", "8:00,1", "12:00,1.2", "18:00,1.5", "01:00,0.6"], - ["qq:114514:group", "12:20,1", "16:10,2", "20:10,1", "00:10,0.3"], - ["qq:1919810:private", "8:20,1", "12:10,2", "20:10,1.5", "00:10,0.2"] +focus_value_adjust = [ + ["", "8:00,1", "12:00,0.8", "18:00,1", "01:00,0.3"], + ["qq:114514:group", "12:20,0.6", "16:10,0.5", "20:10,0.8", "00:10,0.3"], + ["qq:1919810:private", "8:20,0.5", "12:10,0.8", "20:10,1", "00:10,0.2"] ] -# 基于聊天流的个性化活跃度配置 + +talk_frequency_adjust = [ + ["", "8:00,0.5", "12:00,0.6", "18:00,0.8", "01:00,0.3"], + ["qq:114514:group", "12:20,0.3", "16:10,0.5", "20:10,0.4", "00:10,0.1"], + ["qq:1919810:private", "8:20,0.3", "12:10,0.4", "20:10,0.5", "00:10,0.1"] +] +# 基于聊天流的个性化活跃度和专注度配置 # 格式:[["platform:chat_id:type", "HH:MM,frequency", "HH:MM,frequency", ...], ...] # 全局配置示例: @@ -109,9 +112,6 @@ ban_msgs_regex = [ #"\\d{4}-\\d{2}-\\d{2}", # 匹配日期 ] -[normal_chat] #普通聊天 -willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical,mxp模式:mxp,自定义模式:custom(需要你自己实现) - [tool] enable_tool = false # 是否在普通聊天中启用工具