From 342a1e22c4986febe0b17bc1f8da3c037f3187b0 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 8 Dec 2025 20:13:39 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E4=BB=85=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E4=B8=A4=E7=A7=8D=E6=80=9D=E8=80=83=E5=8A=9B=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bw_learner/expression_selector.py | 24 ++---- src/chat/heart_flow/heartFC_chat.py | 45 +---------- src/chat/planner_actions/planner.py | 98 ++++------------------- src/chat/replyer/group_generator.py | 7 +- src/chat/replyer/prompt/replyer_prompt.py | 26 +----- src/memory_system/memory_retrieval.py | 1 - template/bot_config_template.toml | 6 +- 7 files changed, 32 insertions(+), 175 deletions(-) diff --git a/src/bw_learner/expression_selector.py b/src/bw_learner/expression_selector.py index 996ed04a..931c5eb5 100644 --- a/src/bw_learner/expression_selector.py +++ b/src/bw_learner/expression_selector.py @@ -234,7 +234,7 @@ class ExpressionSelector: max_num: 最大选择数量 target_message: 目标消息内容 reply_reason: planner给出的回复理由 - think_level: 思考级别,0/1/2 + think_level: 思考级别,0/1 Returns: Tuple[List[Dict[str, Any]], List[int]]: 选中的表达方式列表和ID列表 @@ -266,7 +266,7 @@ class ExpressionSelector: max_num: 最大选择数量 target_message: 目标消息内容 reply_reason: planner给出的回复理由 - think_level: 思考级别,0/1/2 + think_level: 思考级别,0/1 Returns: Tuple[List[Dict[str, Any]], List[int]]: 选中的表达方式列表和ID列表 @@ -276,7 +276,7 @@ class ExpressionSelector: if think_level == 0: return self._select_expressions_simple(chat_id, max_num) - # think_level == 1 或 2: 先选高count,再从所有表达方式中随机抽样 + # think_level == 1: 先选高count,再从所有表达方式中随机抽样 # 1. 获取所有表达方式并分离 count > 1 和 count <= 1 的 related_chat_ids = self.get_related_chat_ids(chat_id) style_query = Expression.select().where( @@ -300,19 +300,11 @@ class ExpressionSelector: # 分离 count > 1 和 count <= 1 的表达方式 high_count_exprs = [expr for expr in all_style_exprs if (expr.get("count", 1) or 1) > 1] - # 根据 think_level 设置要求 - if think_level == 1: - # level 1: 需要至少10个高count和10个总数 - min_high_count = 10 - min_total_count = 10 - select_high_count = 5 - select_random_count = 5 - else: # think_level == 2 - # level 2: 需要至少20个高count和20个总数 - min_high_count = 20 - min_total_count = 20 - select_high_count = 10 - select_random_count = 10 + # 根据 think_level 设置要求(仅支持 0/1,0 已在上方返回) + min_high_count = 10 + min_total_count = 10 + select_high_count = 5 + select_random_count = 5 # 检查数量要求 if len(high_count_exprs) < min_high_count: diff --git a/src/chat/heart_flow/heartFC_chat.py b/src/chat/heart_flow/heartFC_chat.py index 06c84db3..725960bd 100644 --- a/src/chat/heart_flow/heartFC_chat.py +++ b/src/chat/heart_flow/heartFC_chat.py @@ -29,7 +29,7 @@ from src.chat.utils.chat_message_builder import ( build_readable_messages_with_id, get_raw_msg_before_timestamp_with_chat, ) -from src.chat.utils.utils import get_chat_type_and_target_info, record_replyer_action_temp +from src.chat.utils.utils import record_replyer_action_temp from src.hippo_memorizer.chat_history_summarizer import ChatHistorySummarizer if TYPE_CHECKING: @@ -100,7 +100,6 @@ class HeartFChatting: self._current_cycle_detail: CycleDetail = None # type: ignore self.last_read_time = time.time() - 2 - self.no_reply_until_call = False self.is_mute = False @@ -208,23 +207,6 @@ class HeartFChatting: if len(recent_messages_list) >= threshold: # for message in recent_messages_list: # print(message.processed_plain_text) - # !处理no_reply_until_call逻辑 - if self.no_reply_until_call: - for message in recent_messages_list: - if ( - message.is_mentioned - or message.is_at - or len(recent_messages_list) >= 8 - or time.time() - self.last_read_time > 600 - ): - self.no_reply_until_call = False - self.last_read_time = time.time() - break - # 没有提到,继续保持沉默 - if self.no_reply_until_call: - # logger.info(f"{self.log_prefix} 没有提到,继续保持沉默") - await asyncio.sleep(1) - return True self.last_read_time = time.time() @@ -615,31 +597,6 @@ class HeartFChatting: return {"action_type": "no_reply", "success": True, "result": "选择不回复", "command": ""} - elif action_planner_info.action_type == "no_reply_until_call": - # 直接当场执行no_reply_until_call逻辑 - logger.info(f"{self.log_prefix} 保持沉默,直到有人直接叫的名字") - reason = action_planner_info.reasoning or "选择不回复" - - # 增加连续 no_reply 计数 - self.consecutive_no_reply_count += 1 - self.no_reply_until_call = True - await database_api.store_action_info( - chat_stream=self.chat_stream, - action_build_into_prompt=False, - action_prompt_display=reason, - action_done=True, - thinking_id=thinking_id, - action_data={}, - action_name="no_reply_until_call", - action_reasoning=reason, - ) - return { - "action_type": "no_reply_until_call", - "success": True, - "result": "保持沉默,直到有人直接叫的名字", - "command": "", - } - elif action_planner_info.action_type == "reply": # 直接当场执行reply逻辑 self.questioned = False diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index 703a8a39..298791f6 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -45,10 +45,10 @@ reply 动作描述: 1.你可以选择呼叫了你的名字,但是你没有做出回应的消息进行回复 2.你可以自然的顺着正在进行的聊天内容进行回复或自然的提出一个问题 -3.不要回复你自己发送的消息 +3.不要选择回复你自己发送的消息 4.不要单独对表情包进行回复 -5.think_level表示思考深度,0表示该回复不需要思考和回忆,2表示该回复需要深度思考,进行深入的回忆和思考 -{{"action":"reply", "think_level":数值等级(0-2), "target_messamge_id":"消息id(m+数字)"}} +5.think_level表示思考深度,0表示该回复不需要思考和回忆,1表示该回复需要进行回忆和思考 +{{"action":"reply", "think_level":数值等级(0或1), "target_messamge_id":"消息id(m+数字)"}} no_reply 动作描述: @@ -56,15 +56,12 @@ no_reply 控制聊天频率,不要太过频繁的发言 {{"action":"no_reply"}} -{no_reply_until_call_block} - {action_options_text} **你之前的action执行和思考记录** {actions_before_now_block} 请选择**可选的**且符合使用条件的action,并说明触发action的消息id(消息id格式:m+数字) -不要回复你自己发送的消息 先输出你的简短的选择思考理由,再输出你选择的action,理由不要分点,精简。 **动作选择要求** 请你根据聊天内容,用户的最新消息和以下标准选择合适的动作: @@ -251,7 +248,7 @@ class ActionPlanner: # 验证action是否可用 available_action_names = [action_name for action_name, _ in current_available_actions] - internal_action_names = ["no_reply", "reply", "wait_time", "no_reply_until_call"] + internal_action_names = ["no_reply", "reply", "wait_time"] if action not in internal_action_names and action not in available_action_names: logger.warning( @@ -307,7 +304,6 @@ class ActionPlanner: self, available_actions: Dict[str, ActionInfo], loop_start_time: float = 0.0, - is_mentioned: bool = False, ) -> List[ActionPlannerInfo]: # sourcery skip: use-named-expression """ @@ -348,11 +344,6 @@ class ActionPlanner: logger.debug(f"{self.log_prefix}过滤后有{len(filtered_actions)}个可用动作") - # 如果是提及时且没有可用动作,直接返回空列表,不调用LLM以节省token - if is_mentioned and not filtered_actions: - logger.info(f"{self.log_prefix}提及时没有可用动作,跳过plan调用") - return [] - # 构建包含所有动作的提示词 prompt, message_id_list = await self.build_planner_prompt( is_group_chat=is_group_chat, @@ -360,7 +351,6 @@ class ActionPlanner: current_available_actions=filtered_actions, chat_content_block=chat_content_block, message_id_list=message_id_list, - is_mentioned=is_mentioned, ) # 调用LLM获取决策 @@ -432,32 +422,6 @@ class ActionPlanner: return plan_log_str - def _has_consecutive_no_reply(self, min_count: int = 3) -> bool: - """ - 检查是否有连续min_count次以上的no_reply - - Args: - min_count: 需要连续的最少次数,默认3 - - Returns: - 如果有连续min_count次以上no_reply返回True,否则返回False - """ - consecutive_count = 0 - - # 从后往前遍历plan_log,检查最新的连续记录 - for _reasoning, _timestamp, content in reversed(self.plan_log): - if isinstance(content, list) and all(isinstance(action, ActionPlannerInfo) for action in content): - # 检查所有action是否都是no_reply - if all(action.action_type == "no_reply" for action in content): - consecutive_count += 1 - if consecutive_count >= min_count: - return True - else: - # 如果遇到非no_reply的action,重置计数 - break - - return False - async def build_planner_prompt( self, is_group_chat: bool, @@ -466,7 +430,6 @@ class ActionPlanner: message_id_list: List[Tuple[str, "DatabaseMessages"]], chat_content_block: str = "", interest: str = "", - is_mentioned: bool = False, ) -> tuple[str, List[Tuple[str, "DatabaseMessages"]]]: """构建 Planner LLM 的提示词 (获取模板并填充数据)""" try: @@ -487,47 +450,18 @@ class ActionPlanner: ) name_block = f"你的名字是{bot_name}{bot_nickname},请注意哪些是你自己的发言。" - # 根据是否是提及时选择不同的模板 - if is_mentioned: - # 提及时使用简化版提示词,不需要reply、no_reply、no_reply_until_call - planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt_mentioned") - prompt = planner_prompt_template.format( - time_block=time_block, - chat_context_description=chat_context_description, - chat_content_block=chat_content_block, - actions_before_now_block=actions_before_now_block, - action_options_text=action_options_block, - moderation_prompt=moderation_prompt_block, - name_block=name_block, - interest=interest, - plan_style=global_config.personality.plan_style, - ) - else: - # 正常流程使用完整版提示词 - # 检查是否有连续3次以上no_reply,如果有则添加no_reply_until_call选项 - no_reply_until_call_block = "" - if self._has_consecutive_no_reply(min_count=3): - no_reply_until_call_block = """no_reply_until_call -动作描述: -保持沉默,直到有人直接叫你的名字 -当前话题不感兴趣时使用,或有人不喜欢你的发言时使用 -当你频繁选择no_reply时使用,表示话题暂时与你无关 -{{"action":"no_reply_until_call"}} -""" - - planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt") - prompt = planner_prompt_template.format( - time_block=time_block, - chat_context_description=chat_context_description, - chat_content_block=chat_content_block, - actions_before_now_block=actions_before_now_block, - action_options_text=action_options_block, - no_reply_until_call_block=no_reply_until_call_block, - moderation_prompt=moderation_prompt_block, - name_block=name_block, - interest=interest, - plan_style=global_config.personality.plan_style, - ) + planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt") + prompt = planner_prompt_template.format( + time_block=time_block, + chat_context_description=chat_context_description, + chat_content_block=chat_content_block, + actions_before_now_block=actions_before_now_block, + action_options_text=action_options_block, + moderation_prompt=moderation_prompt_block, + name_block=name_block, + interest=interest, + plan_style=global_config.personality.plan_style, + ) return prompt, message_id_list except Exception as e: diff --git a/src/chat/replyer/group_generator.py b/src/chat/replyer/group_generator.py index ec9ee4dc..57f64dba 100644 --- a/src/chat/replyer/group_generator.py +++ b/src/chat/replyer/group_generator.py @@ -798,7 +798,7 @@ class DefaultReplyer: self._time_and_run_task(self.build_personality_prompt(), "personality_prompt"), self._time_and_run_task( build_memory_retrieval_prompt( - chat_talking_prompt_short, sender, target, self.chat_stream, self.tool_executor, think_level=think_level + chat_talking_prompt_short, sender, target, self.chat_stream, think_level=think_level ), "memory_retrieval", ), @@ -884,11 +884,8 @@ class DefaultReplyer: # 根据think_level选择不同的回复模板 # think_level=0: 轻量回复(简短平淡) # think_level=1: 中等回复(日常口语化) - # think_level=2: 深度回复(仔细思考,把握话题) if think_level == 0: prompt_name = "replyer_prompt_0" - elif think_level == 2: - prompt_name = "replyer_prompt_2" else: # think_level == 1 或默认 prompt_name = "replyer_prompt" @@ -923,8 +920,6 @@ class DefaultReplyer: ) -> str: # sourcery skip: merge-else-if-into-elif, remove-redundant-if chat_stream = self.chat_stream chat_id = chat_stream.stream_id - is_group_chat = bool(chat_stream.group_info) - sender, target = self._parse_reply_target(reply_to) target = replace_user_references(target, chat_stream.platform, replace_bot_name=True) diff --git a/src/chat/replyer/prompt/replyer_prompt.py b/src/chat/replyer/prompt/replyer_prompt.py index ddd0e2bb..b9a6addf 100644 --- a/src/chat/replyer/prompt/replyer_prompt.py +++ b/src/chat/replyer/prompt/replyer_prompt.py @@ -15,7 +15,7 @@ def init_replyer_prompt(): {reply_target_block}。 {planner_reasoning} {identity} -{chat_prompt}你正在群里聊天,现在请你读读之前的聊天记录,然后给出日常且口语化的回复,平淡一些, +{chat_prompt}你正在群里聊天,现在请你读读之前的聊天记录,然后给出日常且口语化的回复, 尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理。 {reply_style} 请注意不要输出多余内容(包括不必要的前后缀,冒号,括号,表情包,at或 @等 ),只输出发言内容就好。 @@ -35,31 +35,11 @@ def init_replyer_prompt(): {reply_target_block}。 {planner_reasoning} {identity} -{chat_prompt}你正在群里聊天,现在请你读读之前的聊天记录,然后给出日常且口语化的回复, -{keywords_reaction_prompt}请注意把握聊天内容。 -{reply_style} -请注意不要输出多余内容(包括不必要的前后缀,冒号,括号,表情包,at或 @等 ),只输出发言内容就好。 -现在,你说:""", - "replyer_prompt", - ) - - Prompt( - """{knowledge_prompt}{tool_info_block}{extra_info_block} -{expression_habits_block}{memory_retrieval}{jargon_explanation} - -你正在qq群里聊天,下面是群里正在聊的内容,其中包含聊天记录和聊天中的图片 -其中标注 {bot_name}(你) 的发言是你自己的发言,请注意区分: -{time_block} -{dialogue_prompt} - -{reply_target_block}。 -{planner_reasoning} -{identity} -{chat_prompt}你正在群里聊天,现在请你仔细阅读之前的聊天记录,把握当前的话题,然后给出回复, +{chat_prompt}你正在群里聊天,现在请你读读之前的聊天记录,把握当前的话题,然后给出回复, {keywords_reaction_prompt}请注意把握聊天内容。 {reply_style} 请注意不要输出多余内容(包括不必要的前后缀,冒号,括号,at或 @等 ),只输出发言内容就好。 现在,你说:""", - "replyer_prompt_2", + "replyer_prompt", ) diff --git a/src/memory_system/memory_retrieval.py b/src/memory_system/memory_retrieval.py index 2cd4dfde..248e3062 100644 --- a/src/memory_system/memory_retrieval.py +++ b/src/memory_system/memory_retrieval.py @@ -1034,7 +1034,6 @@ async def build_memory_retrieval_prompt( sender: str, target: str, chat_stream, - tool_executor, think_level: int = 1, ) -> str: """构建记忆检索提示 diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index ad6f87c2..a381104b 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "7.1.3" +version = "7.1.5" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- # 如果你想要修改配置文件,请递增version的值 @@ -85,10 +85,10 @@ all_global_jargon = true # 是否开启全局黑话模式,注意,此功能 [chat] # 麦麦的聊天设置 -talk_value = 1 # 聊天频率,越小越沉默,范围0-1,如果设置为0会自动转换为0.0001以避免除以零错误 +talk_value = 1 # 聊天频率,越小越沉默,范围0-1 mentioned_bot_reply = true # 是否启用提及必回复 max_context_size = 30 # 上下文长度 -planner_smooth = 2 # 规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐1-5,0为关闭,必须大于等于0 +planner_smooth = 3 # 规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐1-5,0为关闭,必须大于等于0 enable_talk_value_rules = true # 是否启用动态发言频率规则