From dd4a327b182ca0fdc53f7c5fb1c42149a22597fb Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 2 Jun 2025 21:47:21 +0800 Subject: [PATCH 1/4] =?UTF-8?q?better=EF=BC=9A=E4=BC=98=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E8=AE=B0=E5=BF=86=EF=BC=8C=E7=BB=99reply=20action?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E9=A2=9D=E5=A4=96=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../focus_chat/planners/planner_simple.py | 18 ++++- .../focus_chat/replyer/default_replyer.py | 17 ++-- .../working_memory/memory_manager.py | 79 +++++++++---------- 3 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/chat/focus_chat/planners/planner_simple.py b/src/chat/focus_chat/planners/planner_simple.py index d8518ea23..a5ccde07c 100644 --- a/src/chat/focus_chat/planners/planner_simple.py +++ b/src/chat/focus_chat/planners/planner_simple.py @@ -137,7 +137,8 @@ class ActionPlanner(BasePlanner): self_info = info.get_processed_info() elif isinstance(info, StructuredInfo): structured_info = info.get_processed_info() - # print(f"structured_info: {structured_info}") + else: + extra_info.append(info.get_processed_info()) # elif not isinstance(info, ActionInfo): # 跳过已处理的ActionInfo # extra_info.append(info.get_processed_info()) @@ -218,6 +219,15 @@ class ActionPlanner(BasePlanner): action_data[key] = value action_data["identity"] = self_info + + extra_info_block = "\n".join(extra_info) + extra_info_block += f"\n{structured_info}" + if extra_info or structured_info: + extra_info_block = f"以下是一些额外的信息,现在请你阅读以下内容,进行决策\n{extra_info_block}\n以上是一些额外的信息,现在请你阅读以下内容,进行决策" + else: + extra_info_block = "" + + action_data["extra_info_block"] = extra_info_block # 对于reply动作不需要额外处理,因为相关字段已经在上面的循环中添加到action_data @@ -257,9 +267,13 @@ class ActionPlanner(BasePlanner): ) action_result = {"action_type": action, "action_data": action_data, "reasoning": reasoning} + + + plan_result = { "action_result": action_result, + # "extra_info_block": extra_info_block, "current_mind": current_mind, "observed_messages": observed_messages, "action_prompt": prompt, @@ -288,7 +302,7 @@ class ActionPlanner(BasePlanner): if running_memorys: memory_str = "以下是当前在聊天中,你回忆起的记忆:\n" for running_memory in running_memorys: - memory_str += f"{running_memory['topic']}: {running_memory['content']}\n" + memory_str += f"{running_memory['content']}\n" chat_context_description = "你现在正在一个群聊中" chat_target_name = None # Only relevant for private diff --git a/src/chat/focus_chat/replyer/default_replyer.py b/src/chat/focus_chat/replyer/default_replyer.py index 650eb2788..88f78d1fd 100644 --- a/src/chat/focus_chat/replyer/default_replyer.py +++ b/src/chat/focus_chat/replyer/default_replyer.py @@ -30,8 +30,7 @@ logger = get_logger("expressor") def init_prompt(): Prompt( """ -你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: -{style_habbits} +{extra_info_block} {time_block} 你现在正在群里聊天,以下是群里正在进行的聊天内容: @@ -42,6 +41,8 @@ def init_prompt(): {chat_target} {identity},在这聊天中,"{target_message}"引起了你的注意,你想要在群里发言或者回复这条消息。 你需要使用合适的语法和句法,参考聊天内容,组织一条日常且口语化的回复。注意不要复读你说过的话。 +你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: +{style_habbits} 请你根据情景使用以下句法: {grammar_habbits} {config_expression_style},请注意不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。只输出回复内容。 @@ -55,8 +56,7 @@ def init_prompt(): Prompt( """ -你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: -{style_habbits} +{extra_info_block} {time_block} 你现在正在聊天,以下是你和对方正在进行的聊天内容: @@ -67,8 +67,10 @@ def init_prompt(): {chat_target} {identity},在这聊天中,"{target_message}"引起了你的注意,你想要发言或者回复这条消息。 你需要使用合适的语法和句法,参考聊天内容,组织一条日常且口语化的回复。注意不要复读你说过的话。 -请你根据情景使用以下句法: +你可以参考以下的语言习惯和句法,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: +{style_habbits} {grammar_habbits} + {config_expression_style},请注意不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。只输出回复内容。 {keywords_reaction_prompt} 请不要输出违法违规内容,不要输出色情,暴力,政治相关内容,如有敏感内容,请规避。 @@ -267,6 +269,7 @@ class DefaultReplyer: target_message = action_data.get("target", "") identity = action_data.get("identity", "") + extra_info_block = action_data.get("extra_info_block", "") # 3. 构建 Prompt with Timer("构建Prompt", {}): # 内部计时器,可选保留 @@ -274,6 +277,7 @@ class DefaultReplyer: chat_stream=self.chat_stream, # Pass the stream object # in_mind_reply=in_mind_reply, identity=identity, + extra_info_block=extra_info_block, reason=reason, sender_name=sender_name_for_prompt, # Pass determined name target_message=target_message, @@ -334,6 +338,7 @@ class DefaultReplyer: chat_stream, sender_name, # in_mind_reply, + extra_info_block, identity, target_message, config_expression_style, @@ -429,6 +434,7 @@ class DefaultReplyer: grammar_habbits=grammar_habbits_str, chat_target=chat_target_1, chat_info=chat_talking_prompt, + extra_info_block=extra_info_block, time_block=time_block, # bot_name=global_config.bot.nickname, # prompt_personality="", @@ -448,6 +454,7 @@ class DefaultReplyer: grammar_habbits=grammar_habbits_str, chat_target=chat_target_1, chat_info=chat_talking_prompt, + extra_info_block=extra_info_block, time_block=time_block, # bot_name=global_config.bot.nickname, # prompt_personality="", diff --git a/src/chat/focus_chat/working_memory/memory_manager.py b/src/chat/focus_chat/working_memory/memory_manager.py index 1015207aa..19fef5e7a 100644 --- a/src/chat/focus_chat/working_memory/memory_manager.py +++ b/src/chat/focus_chat/working_memory/memory_manager.py @@ -226,25 +226,24 @@ class MemoryManager: """ prompt = f"""请对以下内容进行总结,总结成记忆,输出两部分: 1. 记忆内容主题(精简,20字以内):让用户可以一眼看出记忆内容是什么 -2. key_points:多条,包含关键的概念、事件,每条都要包含解释或描述,谁在什么时候干了什么 +2. content:一到三条,包含关键的概念、事件,每条都要包含解释或描述,谁在什么时候干了什么 内容: {content} 请按以下JSON格式输出: {{ - "brief": "记忆内容主题(20字以内)", - "key_points": [ - "要点1:解释或描述", - "要点2:解释或描述", - ... + "brief": "记忆内容主题", + "content": [ + "内容", + "内容" ] }} 请确保输出是有效的JSON格式,不要添加任何额外的说明或解释。 """ default_summary = { "brief": "主题未知的记忆", - "key_points": ["未知的要点"], + "content": ["未知的要点"], } try: @@ -277,13 +276,13 @@ class MemoryManager: json_result["brief"] = "主题未知的记忆" # 处理关键要点 - if "key_points" not in json_result or not isinstance(json_result["key_points"], list): - json_result["key_points"] = ["未知的要点"] + if "content" not in json_result or not isinstance(json_result["content"], list): + json_result["content"] = ["未知的要点"] else: - # 确保key_points中的每个项目都是字符串 - json_result["key_points"] = [str(point) for point in json_result["key_points"] if point is not None] - if not json_result["key_points"]: - json_result["key_points"] = ["未知的要点"] + # 确保content中的每个项目都是字符串 + json_result["content"] = [str(point) for point in json_result["content"] if point is not None] + if not json_result["content"]: + json_result["content"] = ["未知的要点"] return json_result @@ -328,13 +327,13 @@ class MemoryManager: 目前主题:{summary["brief"]} 目前关键要点: -{chr(10).join([f"- {point}" for point in summary.get("key_points", [])])} +{chr(10).join([f"- {point}" for point in summary.get("content", [])])} 请生成修改后的主题和关键要点,遵循以下格式: ```json {{ "brief": "修改后的主题(20字以内)", - "key_points": [ + "content": [ "修改后的要点1:解释或描述", "修改后的要点2:解释或描述" ] @@ -345,7 +344,7 @@ class MemoryManager: # 定义默认的精简结果 default_refined = { "brief": summary["brief"], - "key_points": summary.get("key_points", ["未知的要点"])[:1], # 默认只保留第一个要点 + "content": summary.get("content", ["未知的要点"])[:1], # 默认只保留第一个要点 } try: @@ -377,13 +376,13 @@ class MemoryManager: summary["brief"] = refined_data.get("brief", "主题未知的记忆") # 更新关键要点 - key_points = refined_data.get("key_points", []) - if isinstance(key_points, list) and key_points: + content = refined_data.get("content", []) + if isinstance(content, list) and content: # 确保所有要点都是字符串 - summary["key_points"] = [str(point) for point in key_points if point is not None] + summary["content"] = [str(point) for point in content if point is not None] else: - # 如果key_points不是列表或为空,使用默认值 - summary["key_points"] = ["主要要点已遗忘"] + # 如果content不是列表或为空,使用默认值 + summary["content"] = ["主要要点已遗忘"] except Exception as e: logger.error(f"精简记忆出错: {str(e)}") @@ -391,7 +390,7 @@ class MemoryManager: # 出错时使用简化的默认精简 summary["brief"] = summary["brief"] + " (已简化)" - summary["key_points"] = summary.get("key_points", ["未知的要点"])[:1] + summary["content"] = summary.get("content", ["未知的要点"])[:1] except Exception as e: logger.error(f"精简记忆调用LLM出错: {str(e)}") @@ -510,11 +509,11 @@ class MemoryManager: # 如果有摘要信息,添加到提示中 if summary1: prompt += f"记忆1主题:{summary1['brief']}\n" - prompt += "记忆1关键要点:\n" + "\n".join([f"- {point}" for point in summary1.get("key_points", [])]) + "\n\n" + prompt += "记忆1关键要点:\n" + "\n".join([f"- {point}" for point in summary1.get("content", [])]) + "\n\n" if summary2: prompt += f"记忆2主题:{summary2['brief']}\n" - prompt += "记忆2关键要点:\n" + "\n".join([f"- {point}" for point in summary2.get("key_points", [])]) + "\n\n" + prompt += "记忆2关键要点:\n" + "\n".join([f"- {point}" for point in summary2.get("content", [])]) + "\n\n" # 添加记忆原始内容 prompt += f""" @@ -529,7 +528,7 @@ class MemoryManager: {{ "content": "合并后的记忆内容文本(尽可能保留原信息,但去除重复)", "brief": "合并后的主题(20字以内)", - "key_points": [ + "content": [ "合并后的要点1:解释或描述", "合并后的要点2:解释或描述", "合并后的要点3:解释或描述" @@ -543,18 +542,18 @@ class MemoryManager: default_merged = { "content": f"{content1}\n\n{content2}", "brief": f"合并:{summary1['brief']} + {summary2['brief']}", - "key_points": [], + "content": [], } - # 合并key_points - if "key_points" in summary1: - default_merged["key_points"].extend(summary1["key_points"]) - if "key_points" in summary2: - default_merged["key_points"].extend(summary2["key_points"]) + # 合并content + if "content" in summary1: + default_merged["content"].extend(summary1["content"]) + if "content" in summary2: + default_merged["content"].extend(summary2["content"]) # 确保列表不为空 - if not default_merged["key_points"]: - default_merged["key_points"] = ["合并的要点"] + if not default_merged["content"]: + default_merged["content"] = ["合并的要点"] try: # 调用LLM合并记忆 @@ -589,13 +588,13 @@ class MemoryManager: merged_data["brief"] = default_merged["brief"] # 处理关键要点 - if "key_points" not in merged_data or not isinstance(merged_data["key_points"], list): - merged_data["key_points"] = default_merged["key_points"] + if "content" not in merged_data or not isinstance(merged_data["content"], list): + merged_data["content"] = default_merged["content"] else: - # 确保key_points中的每个项目都是字符串 - merged_data["key_points"] = [str(point) for point in merged_data["key_points"] if point is not None] - if not merged_data["key_points"]: - merged_data["key_points"] = ["合并的要点"] + # 确保content中的每个项目都是字符串 + merged_data["content"] = [str(point) for point in merged_data["content"] if point is not None] + if not merged_data["content"]: + merged_data["content"] = ["合并的要点"] except Exception as e: logger.error(f"合并记忆时处理JSON出错: {str(e)}") @@ -623,7 +622,7 @@ class MemoryManager: # 设置合并后的摘要 summary = { "brief": merged_data["brief"], - "key_points": merged_data["key_points"], + "content": merged_data["content"], } merged_memory.set_summary(summary) From 78f6476ebd826c339a0a2359ff4ca1359ebeb6ec Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 2 Jun 2025 22:23:11 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix=EF=BC=9A=E5=81=B7=E8=A1=A8=E6=83=85?= =?UTF-8?q?=E5=8C=85=E9=85=8D=E7=BD=AE=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/emoji_system/emoji_manager.py | 4 +- src/chat/utils/utils_image.py | 58 +++++++++++++------------- src/config/official_configs.py | 9 ---- template/bot_config_template.toml | 6 +-- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/chat/emoji_system/emoji_manager.py b/src/chat/emoji_system/emoji_manager.py index df697155f..48a0cea61 100644 --- a/src/chat/emoji_system/emoji_manager.py +++ b/src/chat/emoji_system/emoji_manager.py @@ -602,9 +602,9 @@ class EmojiManager: continue # 检查是否需要处理表情包(数量超过最大值或不足) - if (self.emoji_num > self.emoji_num_max and global_config.emoji.do_replace) or ( + if global_config.emoji.steal_emoji and ((self.emoji_num > self.emoji_num_max and global_config.emoji.do_replace) or ( self.emoji_num < self.emoji_num_max - ): + )): try: # 获取目录下所有图片文件 files_to_process = [ diff --git a/src/chat/utils/utils_image.py b/src/chat/utils/utils_image.py index 9dcd644a9..6d5fdd4f4 100644 --- a/src/chat/utils/utils_image.py +++ b/src/chat/utils/utils_image.py @@ -202,37 +202,37 @@ class ImageManager: logger.debug(f"描述是{description}") # 根据配置决定是否保存图片 - if global_config.emoji.save_pic: - # 生成文件名和路径 - current_timestamp = time.time() - filename = f"{int(current_timestamp)}_{image_hash[:8]}.{image_format}" - image_dir = os.path.join(self.IMAGE_DIR, "image") - os.makedirs(image_dir, exist_ok=True) - file_path = os.path.join(image_dir, filename) + # 生成文件名和路径 + current_timestamp = time.time() + filename = f"{int(current_timestamp)}_{image_hash[:8]}.{image_format}" + image_dir = os.path.join(self.IMAGE_DIR, "image") + os.makedirs(image_dir, exist_ok=True) + file_path = os.path.join(image_dir, filename) + + try: + # 保存文件 + with open(file_path, "wb") as f: + f.write(image_bytes) + + # 保存到数据库 (Images表) try: - # 保存文件 - with open(file_path, "wb") as f: - f.write(image_bytes) - - # 保存到数据库 (Images表) - try: - img_obj = Images.get((Images.emoji_hash == image_hash) & (Images.type == "image")) - img_obj.path = file_path - img_obj.description = description - img_obj.timestamp = current_timestamp - img_obj.save() - except Images.DoesNotExist: - Images.create( - emoji_hash=image_hash, - path=file_path, - type="image", - description=description, - timestamp=current_timestamp, - ) - logger.trace(f"保存图片元数据: {file_path}") - except Exception as e: - logger.error(f"保存图片文件或元数据失败: {str(e)}") + img_obj = Images.get((Images.emoji_hash == image_hash) & (Images.type == "image")) + img_obj.path = file_path + img_obj.description = description + img_obj.timestamp = current_timestamp + img_obj.save() + except Images.DoesNotExist: + Images.create( + emoji_hash=image_hash, + path=file_path, + type="image", + description=description, + timestamp=current_timestamp, + ) + logger.trace(f"保存图片元数据: {file_path}") + except Exception as e: + logger.error(f"保存图片文件或元数据失败: {str(e)}") # 保存描述到数据库 (ImageDescriptions表) self._save_description_to_db(image_hash, description, "image") diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 8ae3fe985..fe59ef7b9 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -205,15 +205,6 @@ class EmojiConfig(ConfigBase): check_interval: int = 120 """表情包检查间隔(分钟)""" - save_pic: bool = True - """是否保存图片""" - - save_emoji: bool = True - """是否保存表情包""" - - cache_emoji: bool = True - """是否缓存表情包""" - steal_emoji: bool = True """是否偷取表情包,让麦麦可以发送她保存的这些表情包""" diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 9d69827c4..14db89843 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "2.9.1" +version = "2.10.0" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请在修改后将version的值进行变更 @@ -114,9 +114,7 @@ working_memory_processor = false # 是否启用工作记忆处理器,不稳定 max_reg_num = 40 # 表情包最大注册数量 do_replace = true # 开启则在达到最大数量时删除(替换)表情包,关闭则达到最大数量时不会继续收集表情包 check_interval = 120 # 检查表情包(注册,破损,删除)的时间间隔(分钟) -save_pic = true # 是否保存图片 -cache_emoji = true # 是否缓存表情包 -steal_emoji = true # 是否偷取表情包,让麦麦可以发送她保存的这些表情包 +steal_emoji = true # 是否偷取表情包,让麦麦可以将一些表情包据为己有 content_filtration = false # 是否启用表情包过滤,只有符合该要求的表情包才会被保存 filtration_prompt = "符合公序良俗" # 表情包过滤要求,只有符合该要求的表情包才会被保存 From 5e47efe987288733abcbb1055a761f04b3cdfd73 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 2 Jun 2025 22:25:24 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9Bprompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelogs/changelog.md | 3 + src/api/config_api.py | 1 - .../focus_chat/replyer/default_replyer.py | 11 +-- .../working_memory/memory_manager.py | 79 +++++++++---------- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/changelogs/changelog.md b/changelogs/changelog.md index 5eb93dc82..160d21a81 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -3,6 +3,9 @@ ## [0.7.1] -2025-6-2 - 修复关键词功能,并且在focus中可用 - 更新planner架构,大大加快速度和表现效果,建议使用simple规划器 +- 为normal加入使用action的能力 +- 修复emoji配置项无效问题 + - 修复log出错问题 - 修复focus吞第一条消息问题 diff --git a/src/api/config_api.py b/src/api/config_api.py index d28b1e809..9af2a30ea 100644 --- a/src/api/config_api.py +++ b/src/api/config_api.py @@ -71,7 +71,6 @@ class APIBotConfig: max_emoji_num: int # 最大表情符号数量 max_reach_deletion: bool # 达到最大数量时是否删除 check_interval: int # 检查表情包的时间间隔(分钟) - save_pic: bool # 是否保存图片 save_emoji: bool # 是否保存表情包 steal_emoji: bool # 是否偷取表情包 enable_check: bool # 是否启用表情包过滤 diff --git a/src/chat/focus_chat/replyer/default_replyer.py b/src/chat/focus_chat/replyer/default_replyer.py index 88f78d1fd..759236511 100644 --- a/src/chat/focus_chat/replyer/default_replyer.py +++ b/src/chat/focus_chat/replyer/default_replyer.py @@ -30,6 +30,11 @@ logger = get_logger("expressor") def init_prompt(): Prompt( """ +你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: +{style_habbits} +请你根据情景使用以下句法: +{grammar_habbits} + {extra_info_block} {time_block} @@ -40,11 +45,7 @@ def init_prompt(): {chat_target} {identity},在这聊天中,"{target_message}"引起了你的注意,你想要在群里发言或者回复这条消息。 -你需要使用合适的语法和句法,参考聊天内容,组织一条日常且口语化的回复。注意不要复读你说过的话。 -你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: -{style_habbits} -请你根据情景使用以下句法: -{grammar_habbits} +你需要使用合适的语言习惯和句法,参考聊天内容,组织一条日常且口语化的回复。注意不要复读你说过的话。 {config_expression_style},请注意不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。只输出回复内容。 {keywords_reaction_prompt} 请不要输出违法违规内容,不要输出色情,暴力,政治相关内容,如有敏感内容,请规避。 diff --git a/src/chat/focus_chat/working_memory/memory_manager.py b/src/chat/focus_chat/working_memory/memory_manager.py index 19fef5e7a..cccb213b2 100644 --- a/src/chat/focus_chat/working_memory/memory_manager.py +++ b/src/chat/focus_chat/working_memory/memory_manager.py @@ -234,7 +234,7 @@ class MemoryManager: 请按以下JSON格式输出: {{ "brief": "记忆内容主题", - "content": [ + "points": [ "内容", "内容" ] @@ -243,7 +243,7 @@ class MemoryManager: """ default_summary = { "brief": "主题未知的记忆", - "content": ["未知的要点"], + "points": ["未知的要点"], } try: @@ -276,13 +276,13 @@ class MemoryManager: json_result["brief"] = "主题未知的记忆" # 处理关键要点 - if "content" not in json_result or not isinstance(json_result["content"], list): - json_result["content"] = ["未知的要点"] + if "points" not in json_result or not isinstance(json_result["points"], list): + json_result["points"] = ["未知的要点"] else: - # 确保content中的每个项目都是字符串 - json_result["content"] = [str(point) for point in json_result["content"] if point is not None] - if not json_result["content"]: - json_result["content"] = ["未知的要点"] + # 确保points中的每个项目都是字符串 + json_result["points"] = [str(point) for point in json_result["points"] if point is not None] + if not json_result["points"]: + json_result["points"] = ["未知的要点"] return json_result @@ -327,15 +327,15 @@ class MemoryManager: 目前主题:{summary["brief"]} 目前关键要点: -{chr(10).join([f"- {point}" for point in summary.get("content", [])])} +{chr(10).join([f"- {point}" for point in summary.get("points", [])])} 请生成修改后的主题和关键要点,遵循以下格式: ```json {{ "brief": "修改后的主题(20字以内)", - "content": [ - "修改后的要点1:解释或描述", - "修改后的要点2:解释或描述" + "points": [ + "修改后的要点", + "修改后的要点" ] }} ``` @@ -344,7 +344,7 @@ class MemoryManager: # 定义默认的精简结果 default_refined = { "brief": summary["brief"], - "content": summary.get("content", ["未知的要点"])[:1], # 默认只保留第一个要点 + "points": summary.get("points", ["未知的要点"])[:1], # 默认只保留第一个要点 } try: @@ -376,13 +376,13 @@ class MemoryManager: summary["brief"] = refined_data.get("brief", "主题未知的记忆") # 更新关键要点 - content = refined_data.get("content", []) - if isinstance(content, list) and content: + points = refined_data.get("points", []) + if isinstance(points, list) and points: # 确保所有要点都是字符串 - summary["content"] = [str(point) for point in content if point is not None] + summary["points"] = [str(point) for point in points if point is not None] else: - # 如果content不是列表或为空,使用默认值 - summary["content"] = ["主要要点已遗忘"] + # 如果points不是列表或为空,使用默认值 + summary["points"] = ["主要要点已遗忘"] except Exception as e: logger.error(f"精简记忆出错: {str(e)}") @@ -390,7 +390,7 @@ class MemoryManager: # 出错时使用简化的默认精简 summary["brief"] = summary["brief"] + " (已简化)" - summary["content"] = summary.get("content", ["未知的要点"])[:1] + summary["points"] = summary.get("points", ["未知的要点"])[:1] except Exception as e: logger.error(f"精简记忆调用LLM出错: {str(e)}") @@ -509,11 +509,11 @@ class MemoryManager: # 如果有摘要信息,添加到提示中 if summary1: prompt += f"记忆1主题:{summary1['brief']}\n" - prompt += "记忆1关键要点:\n" + "\n".join([f"- {point}" for point in summary1.get("content", [])]) + "\n\n" + prompt += "记忆1关键要点:\n" + "\n".join([f"- {point}" for point in summary1.get("points", [])]) + "\n\n" if summary2: prompt += f"记忆2主题:{summary2['brief']}\n" - prompt += "记忆2关键要点:\n" + "\n".join([f"- {point}" for point in summary2.get("content", [])]) + "\n\n" + prompt += "记忆2关键要点:\n" + "\n".join([f"- {point}" for point in summary2.get("points", [])]) + "\n\n" # 添加记忆原始内容 prompt += f""" @@ -528,10 +528,9 @@ class MemoryManager: {{ "content": "合并后的记忆内容文本(尽可能保留原信息,但去除重复)", "brief": "合并后的主题(20字以内)", - "content": [ - "合并后的要点1:解释或描述", - "合并后的要点2:解释或描述", - "合并后的要点3:解释或描述" + "points": [ + "合并后的要点", + "合并后的要点" ] }} ``` @@ -542,18 +541,18 @@ class MemoryManager: default_merged = { "content": f"{content1}\n\n{content2}", "brief": f"合并:{summary1['brief']} + {summary2['brief']}", - "content": [], + "points": [], } - # 合并content - if "content" in summary1: - default_merged["content"].extend(summary1["content"]) - if "content" in summary2: - default_merged["content"].extend(summary2["content"]) + # 合并points + if "points" in summary1: + default_merged["points"].extend(summary1["points"]) + if "points" in summary2: + default_merged["points"].extend(summary2["points"]) # 确保列表不为空 - if not default_merged["content"]: - default_merged["content"] = ["合并的要点"] + if not default_merged["points"]: + default_merged["points"] = ["合并的要点"] try: # 调用LLM合并记忆 @@ -588,13 +587,13 @@ class MemoryManager: merged_data["brief"] = default_merged["brief"] # 处理关键要点 - if "content" not in merged_data or not isinstance(merged_data["content"], list): - merged_data["content"] = default_merged["content"] + if "points" not in merged_data or not isinstance(merged_data["points"], list): + merged_data["points"] = default_merged["points"] else: - # 确保content中的每个项目都是字符串 - merged_data["content"] = [str(point) for point in merged_data["content"] if point is not None] - if not merged_data["content"]: - merged_data["content"] = ["合并的要点"] + # 确保points中的每个项目都是字符串 + merged_data["points"] = [str(point) for point in merged_data["points"] if point is not None] + if not merged_data["points"]: + merged_data["points"] = ["合并的要点"] except Exception as e: logger.error(f"合并记忆时处理JSON出错: {str(e)}") @@ -622,7 +621,7 @@ class MemoryManager: # 设置合并后的摘要 summary = { "brief": merged_data["brief"], - "content": merged_data["content"], + "points": merged_data["points"], } merged_memory.set_summary(summary) From 258512e11ffe2d302b6a4d872e5bf3fcada058bf Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 2 Jun 2025 23:05:15 +0800 Subject: [PATCH 4/4] =?UTF-8?q?better=EF=BC=9A=E4=BC=98=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E8=AE=B0=E5=BF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../focus_chat/info/workingmemory_info.py | 27 +++++------ .../working_memory_processor.py | 19 +++----- .../focus_chat/working_memory/memory_item.py | 28 +++--------- .../working_memory/memory_manager.py | 45 ++++--------------- .../working_memory/working_memory.py | 5 +-- 5 files changed, 34 insertions(+), 90 deletions(-) diff --git a/src/chat/focus_chat/info/workingmemory_info.py b/src/chat/focus_chat/info/workingmemory_info.py index 0edce8944..0a3282edf 100644 --- a/src/chat/focus_chat/info/workingmemory_info.py +++ b/src/chat/focus_chat/info/workingmemory_info.py @@ -18,30 +18,28 @@ class WorkingMemoryInfo(InfoBase): self.data["talking_message"] = message def set_working_memory(self, working_memory: List[str]) -> None: - """设置工作记忆 + """设置工作记忆列表 Args: - working_memory (str): 工作记忆内容 + working_memory (List[str]): 工作记忆内容列表 """ self.data["working_memory"] = working_memory def add_working_memory(self, working_memory: str) -> None: - """添加工作记忆 + """添加一条工作记忆 Args: - working_memory (str): 工作记忆内容 + working_memory (str): 工作记忆内容,格式为"记忆要点:xxx" """ working_memory_list = self.data.get("working_memory", []) - # print(f"working_memory_list: {working_memory_list}") working_memory_list.append(working_memory) - # print(f"working_memory_list: {working_memory_list}") self.data["working_memory"] = working_memory_list def get_working_memory(self) -> List[str]: - """获取工作记忆 + """获取所有工作记忆 Returns: - List[str]: 工作记忆内容 + List[str]: 工作记忆内容列表,每条记忆格式为"记忆要点:xxx" """ return self.data.get("working_memory", []) @@ -53,33 +51,32 @@ class WorkingMemoryInfo(InfoBase): """ return self.type - def get_data(self) -> Dict[str, str]: + def get_data(self) -> Dict[str, List[str]]: """获取所有信息数据 Returns: - Dict[str, str]: 包含所有信息数据的字典 + Dict[str, List[str]]: 包含所有信息数据的字典 """ return self.data - def get_info(self, key: str) -> Optional[str]: + def get_info(self, key: str) -> Optional[List[str]]: """获取特定属性的信息 Args: key: 要获取的属性键名 Returns: - Optional[str]: 属性值,如果键不存在则返回 None + Optional[List[str]]: 属性值,如果键不存在则返回 None """ return self.data.get(key) - def get_processed_info(self) -> Dict[str, str]: + def get_processed_info(self) -> str: """获取处理后的信息 Returns: - Dict[str, str]: 处理后的信息数据 + str: 处理后的信息数据,所有记忆要点按行拼接 """ all_memory = self.get_working_memory() - # print(f"all_memory: {all_memory}") memory_str = "" for memory in all_memory: memory_str += f"{memory}\n" diff --git a/src/chat/focus_chat/info_processors/working_memory_processor.py b/src/chat/focus_chat/info_processors/working_memory_processor.py index faef24288..e13cddbe4 100644 --- a/src/chat/focus_chat/info_processors/working_memory_processor.py +++ b/src/chat/focus_chat/info_processors/working_memory_processor.py @@ -45,7 +45,6 @@ def init_prompt(): "selected_memory_ids": ["id1", "id2", ...], "new_memory": "true" or "false", "merge_memory": [["id1", "id2"], ["id3", "id4"],...] - }} ``` """ @@ -104,11 +103,10 @@ class WorkingMemoryProcessor(BaseProcessor): all_memory = working_memory.get_all_memories() memory_prompts = [] for memory in all_memory: - # memory_content = memory.data memory_summary = memory.summary memory_id = memory.id memory_brief = memory_summary.get("brief") - memory_keypoints = memory_summary.get("key_points", []) + memory_points = memory_summary.get("points", []) memory_single_prompt = f"记忆id:{memory_id},记忆摘要:{memory_brief}\n" memory_prompts.append(memory_single_prompt) @@ -122,11 +120,11 @@ class WorkingMemoryProcessor(BaseProcessor): memory_str=memory_choose_str, ) + print(f"prompt: {prompt}") + # 调用LLM处理记忆 content = "" try: - # logger.debug(f"{self.log_prefix} 处理工作记忆的prompt: {prompt}") - content, _ = await self.llm_model.generate_response_async(prompt=prompt) if not content: logger.warning(f"{self.log_prefix} LLM返回空结果,处理工作记忆失败。") @@ -159,13 +157,12 @@ class WorkingMemoryProcessor(BaseProcessor): for memory_id in selected_memory_ids: memory = await working_memory.retrieve_memory(memory_id) if memory: - # memory_content = memory.data memory_summary = memory.summary memory_id = memory.id memory_brief = memory_summary.get("brief") - memory_keypoints = memory_summary.get("key_points", []) - for keypoint in memory_keypoints: - memory_str += f"记忆要点:{keypoint}\n" + memory_points = memory_summary.get("points", []) + for point in memory_points: + memory_str += f"记忆要点:{point}\n" working_memory_info = WorkingMemoryInfo() if memory_str: @@ -216,9 +213,7 @@ class WorkingMemoryProcessor(BaseProcessor): merged_memory = await working_memory.merge_memory(memory_id1, memory_id2) logger.debug(f"{self.log_prefix} 异步合并记忆成功: {memory_id1} 和 {memory_id2}...") logger.debug(f"{self.log_prefix} 合并后的记忆梗概: {merged_memory.summary.get('brief')}") - logger.debug(f"{self.log_prefix} 合并后的记忆详情: {merged_memory.summary.get('detailed')}") - logger.debug(f"{self.log_prefix} 合并后的记忆要点: {merged_memory.summary.get('key_points')}") - logger.debug(f"{self.log_prefix} 合并后的记忆事件: {merged_memory.summary.get('events')}") + logger.debug(f"{self.log_prefix} 合并后的记忆要点: {merged_memory.summary.get('points')}") except Exception as e: logger.error(f"{self.log_prefix} 异步合并记忆失败: {e}") diff --git a/src/chat/focus_chat/working_memory/memory_item.py b/src/chat/focus_chat/working_memory/memory_item.py index 15724a387..14161f92d 100644 --- a/src/chat/focus_chat/working_memory/memory_item.py +++ b/src/chat/focus_chat/working_memory/memory_item.py @@ -7,14 +7,14 @@ import string class MemoryItem: """记忆项类,用于存储单个记忆的所有相关信息""" - def __init__(self, data: Any, from_source: str = "", tags: Optional[List[str]] = None): + def __init__(self, data: Any, from_source: str = "", brief: str = ""): """ 初始化记忆项 Args: data: 记忆数据 from_source: 数据来源 - tags: 数据标签列表 + brief: 记忆内容主题 """ # 生成可读ID:时间戳_随机字符串 timestamp = int(time.time()) @@ -23,11 +23,10 @@ class MemoryItem: self.data = data self.data_type = type(data) self.from_source = from_source - self.tags = set(tags) if tags else set() + self.brief = brief self.timestamp = time.time() # 修改summary的结构说明,用于存储可能的总结信息 # summary结构:{ - # "brief": "记忆内容主题", # "detailed": "记忆内容概括", # "keypoints": ["关键概念1", "关键概念2"], # "events": ["事件1", "事件2"] @@ -47,23 +46,6 @@ class MemoryItem: # 格式: [(操作类型, 时间戳, 当时精简次数, 当时强度), ...] self.history = [("create", self.timestamp, self.compress_count, self.memory_strength)] - def add_tag(self, tag: str) -> None: - """添加标签""" - self.tags.add(tag) - - def remove_tag(self, tag: str) -> None: - """移除标签""" - if tag in self.tags: - self.tags.remove(tag) - - def has_tag(self, tag: str) -> bool: - """检查是否有特定标签""" - return tag in self.tags - - def has_all_tags(self, tags: List[str]) -> bool: - """检查是否有所有指定的标签""" - return all(tag in self.tags for tag in tags) - def matches_source(self, source: str) -> bool: """检查来源是否匹配""" return self.from_source == source @@ -103,9 +85,9 @@ class MemoryItem: current_time = time.time() self.history.append((operation_type, current_time, self.compress_count, self.memory_strength)) - def to_tuple(self) -> Tuple[Any, str, Set[str], float, str]: + def to_tuple(self) -> Tuple[Any, str, float, str]: """转换为元组格式(为了兼容性)""" - return (self.data, self.from_source, self.tags, self.timestamp, self.id) + return (self.data, self.from_source, self.timestamp, self.id) def is_memory_valid(self) -> bool: """检查记忆是否有效(强度是否大于等于1)""" diff --git a/src/chat/focus_chat/working_memory/memory_manager.py b/src/chat/focus_chat/working_memory/memory_manager.py index cccb213b2..14ffdba00 100644 --- a/src/chat/focus_chat/working_memory/memory_manager.py +++ b/src/chat/focus_chat/working_memory/memory_manager.py @@ -71,14 +71,13 @@ class MemoryManager: return memory_item.id - async def push_with_summary(self, data: T, from_source: str = "", tags: Optional[List[str]] = None) -> MemoryItem: + async def push_with_summary(self, data: T, from_source: str = "") -> MemoryItem: """ 推送一段有类型的信息到工作记忆中,并自动生成总结 Args: data: 要存储的数据 from_source: 数据来源 - tags: 数据标签列表 Returns: 包含原始数据和总结信息的字典 @@ -88,11 +87,8 @@ class MemoryManager: # 先生成总结 summary = await self.summarize_memory_item(data) - # 准备标签 - memory_tags = list(tags) if tags else [] - # 创建记忆项 - memory_item = MemoryItem(data, from_source, memory_tags) + memory_item = MemoryItem(data, from_source, brief=summary.get("brief", "")) # 将总结信息保存到记忆项中 memory_item.set_summary(summary) @@ -103,7 +99,7 @@ class MemoryManager: return memory_item else: # 非字符串类型,直接创建并推送记忆项 - memory_item = MemoryItem(data, from_source, tags) + memory_item = MemoryItem(data, from_source) self.push_item(memory_item) return memory_item @@ -136,7 +132,6 @@ class MemoryManager: self, data_type: Optional[Type] = None, source: Optional[str] = None, - tags: Optional[List[str]] = None, start_time: Optional[float] = None, end_time: Optional[float] = None, memory_id: Optional[str] = None, @@ -150,7 +145,6 @@ class MemoryManager: Args: data_type: 要查找的数据类型 source: 数据来源 - tags: 必须包含的标签列表 start_time: 开始时间戳 end_time: 结束时间戳 memory_id: 特定记忆项ID @@ -191,10 +185,6 @@ class MemoryManager: if source is not None and not item.matches_source(source): continue - # 检查标签是否匹配 - if tags is not None and not item.has_all_tags(tags): - continue - # 检查时间范围 if start_time is not None and item.timestamp < start_time: continue @@ -491,9 +481,6 @@ class MemoryManager: if not memory_item1 or not memory_item2: raise ValueError("无法找到指定的记忆项") - content1 = memory_item1.data - content2 = memory_item2.data - # 获取记忆的摘要信息(如果有) summary1 = memory_item1.summary summary2 = memory_item2.summary @@ -515,31 +502,22 @@ class MemoryManager: prompt += f"记忆2主题:{summary2['brief']}\n" prompt += "记忆2关键要点:\n" + "\n".join([f"- {point}" for point in summary2.get("points", [])]) + "\n\n" - # 添加记忆原始内容 - prompt += f""" -记忆1原始内容: -{content1} - -记忆2原始内容: -{content2} - + prompt += """ 请按以下JSON格式输出合并结果: ```json -{{ - "content": "合并后的记忆内容文本(尽可能保留原信息,但去除重复)", +{ "brief": "合并后的主题(20字以内)", "points": [ "合并后的要点", "合并后的要点" ] -}} +} ``` 请确保输出是有效的JSON格式,不要添加任何额外的说明或解释。 """ # 默认合并结果 default_merged = { - "content": f"{content1}\n\n{content2}", "brief": f"合并:{summary1['brief']} + {summary2['brief']}", "points": [], } @@ -579,10 +557,6 @@ class MemoryManager: logger.error(f"修复后的JSON不是字典类型: {type(merged_data)}") merged_data = default_merged - # 确保所有必要字段都存在且类型正确 - if "content" not in merged_data or not isinstance(merged_data["content"], str): - merged_data["content"] = default_merged["content"] - if "brief" not in merged_data or not isinstance(merged_data["brief"], str): merged_data["brief"] = default_merged["brief"] @@ -605,9 +579,6 @@ class MemoryManager: merged_data = default_merged # 创建新的记忆项 - # 合并记忆项的标签 - merged_tags = memory_item1.tags.union(memory_item2.tags) - # 取两个记忆项中更强的来源 merged_source = ( memory_item1.from_source @@ -615,8 +586,8 @@ class MemoryManager: else memory_item2.from_source ) - # 创建新的记忆项 - merged_memory = MemoryItem(data=merged_data["content"], from_source=merged_source, tags=list(merged_tags)) + # 创建新的记忆项,使用空字符串作为data + merged_memory = MemoryItem(data="", from_source=merged_source, brief=merged_data["brief"]) # 设置合并后的摘要 summary = { diff --git a/src/chat/focus_chat/working_memory/working_memory.py b/src/chat/focus_chat/working_memory/working_memory.py index db9824150..b06456a50 100644 --- a/src/chat/focus_chat/working_memory/working_memory.py +++ b/src/chat/focus_chat/working_memory/working_memory.py @@ -51,19 +51,18 @@ class WorkingMemory: except Exception as e: print(f"自动衰减记忆时出错: {str(e)}") - async def add_memory(self, content: Any, from_source: str = "", tags: Optional[List[str]] = None): + async def add_memory(self, content: Any, from_source: str = ""): """ 添加一段记忆到指定聊天 Args: content: 记忆内容 from_source: 数据来源 - tags: 数据标签列表 Returns: 包含记忆信息的字典 """ - memory = await self.memory_manager.push_with_summary(content, from_source, tags) + memory = await self.memory_manager.push_with_summary(content, from_source) if len(self.memory_manager.get_all_items()) > self.max_memories_per_chat: self.remove_earliest_memory()