From 6e7e9be82aa59bcc1cd59383a61d6c191fa8a774 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sun, 28 Sep 2025 11:48:32 +0800 Subject: [PATCH] =?UTF-8?q?feqt=20=E8=BD=AC=E6=8D=A2=E6=97=A7=E8=AE=B0?= =?UTF-8?q?=E5=BF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/hippocampus_to_memory_chest_task.md | 86 ++++++++++ src/chat/memory_system/Hippocampus.py | 1 - src/chat/memory_system/Memory_chest.py | 15 +- .../hippocampus_to_memory_chest_task.py | 153 ++++++++++++++++++ src/main.py | 16 +- template/model_config_template.toml | 6 +- 6 files changed, 262 insertions(+), 15 deletions(-) create mode 100644 docs/hippocampus_to_memory_chest_task.md create mode 100644 src/chat/memory_system/hippocampus_to_memory_chest_task.py diff --git a/docs/hippocampus_to_memory_chest_task.md b/docs/hippocampus_to_memory_chest_task.md new file mode 100644 index 00000000..75bac532 --- /dev/null +++ b/docs/hippocampus_to_memory_chest_task.md @@ -0,0 +1,86 @@ +# 海马体到记忆仓库转换任务 + +## 功能描述 + +这个功能实现了每60秒自动将海马体的节点转换为记忆仓库格式的功能。系统会随机选择5个海马体节点,将它们的记忆内容拼接成一个完整的文本,然后使用LLM生成标题并存储到记忆仓库中。 + +## 实现细节 + +### 核心组件 + +1. **HippocampusToMemoryChestTask** (`src/chat/memory_system/hippocampus_to_memory_chest_task.py`) + - 继承自 `AsyncTask` 基类 + - 每60秒执行一次转换任务 + - 启动后等待60秒再开始第一次执行 + +### 工作流程 + +1. **节点选择**:从海马体的所有节点中随机选择5个节点 +2. **内容拼接**:将选中节点的记忆内容按格式拼接: + ``` + 【节点名称1】记忆内容1 + + 【节点名称2】记忆内容2 + + ... + ``` +3. **标题生成**:使用Memory_chest的LLM模型为拼接的内容生成描述性标题 +4. **数据存储**:将标题和内容保存到MemoryChest数据库表中 +5. **节点删除**:如果保存成功,删除已转换的海马体节点,防止重复构建 + +### 集成方式 + +任务已集成到主系统 (`src/main.py`) 中: + +```python +# 初始化记忆系统 +hippocampus_manager.initialize() +logger.info("记忆系统初始化成功") + +# 添加海马体到记忆仓库的转换任务 +await async_task_manager.add_task(HippocampusToMemoryChestTask()) +logger.info("海马体到记忆仓库转换任务已启动") +``` + +## 配置参数 + +- **等待时间**:60秒(启动后等待时间) +- **执行间隔**:60秒(每次执行间隔) +- **节点数量**:5个(每次随机选择的节点数) + +## 日志输出 + +任务执行过程中会输出详细的日志信息: + +- `[海马体转换] 开始执行海马体到记忆仓库的转换任务` +- `[海马体转换] 随机选择了 X 个节点: [节点列表]` +- `[海马体转换] 拼接完成,内容长度: X 字符` +- `[海马体转换] 已保存到记忆仓库,标题: [生成的标题]` +- `[海马体转换] 已删除节点: [节点名称]` +- `[海马体转换] 已删除 X 个节点并同步到数据库` +- `[海马体转换] 转换任务完成` + +## 错误处理 + +- 如果海马体管理器未初始化,会跳过本次转换 +- 如果节点数量少于5个,会跳过本次转换 +- 如果没有有效的记忆内容,会跳过本次转换 +- 如果标题生成失败,会跳过保存操作 +- 所有错误都会记录到日志中 + +## 测试 + +可以使用提供的测试脚本进行功能验证: + +```bash +python test_hippocampus_task.py +``` + +## 注意事项 + +1. 确保海马体管理器已正确初始化 +2. 确保Memory_chest的LLM模型可用 +3. 确保数据库连接正常 +4. 任务会在系统启动后60秒开始第一次执行 +5. **重要**:转换后的海马体节点会被永久删除,确保不会重复构建 +6. 删除操作会自动同步到数据库,保持数据一致性 diff --git a/src/chat/memory_system/Hippocampus.py b/src/chat/memory_system/Hippocampus.py index 8c499843..afbc45a1 100644 --- a/src/chat/memory_system/Hippocampus.py +++ b/src/chat/memory_system/Hippocampus.py @@ -1452,7 +1452,6 @@ class HippocampusManager: logger.info(f""" -------------------------------- 记忆系统参数配置: - 遗忘间隔: {global_config.memory.forget_memory_interval}秒|遗忘比例: {global_config.memory.memory_forget_percentage}|遗忘: {global_config.memory.memory_forget_time}小时之后 记忆图统计信息: 节点数量: {node_count}, 连接数量: {edge_count} --------------------------------""") # noqa: E501 diff --git a/src/chat/memory_system/Memory_chest.py b/src/chat/memory_system/Memory_chest.py index 6c595f9b..cc7b8bef 100644 --- a/src/chat/memory_system/Memory_chest.py +++ b/src/chat/memory_system/Memory_chest.py @@ -18,8 +18,13 @@ class MemoryChest: request_type="memory_chest", ) - self.memory_build_threshold = 20 - self.memory_size_limit = 300 + self.LLMRequest_build = LLMRequest( + model_set=model_config.model_task_config.utils, + request_type="memory_chest_build", + ) + + self.memory_build_threshold = 30 + self.memory_size_limit = 800 self.running_content_list = {} # {chat_id: {"content": running_content, "last_update_time": timestamp}} self.fetched_memory_list = [] # [(chat_id, (question, answer, timestamp)), ...] @@ -80,6 +85,8 @@ class MemoryChest: 请将下面的新聊天记录内的有用的信息,添加到你的记忆中 请主要关注概念和知识,而不是聊天的琐事 +如果有表情包,仅在意表情包对上下文的影响,不要在意表情包本身 +如果有图片,尽在意内容,不要在意图片的名称和编号 记忆为一段纯文本,逻辑清晰,指出事件,概念的含义,并说明关系 请输出添加后的记忆内容,不要输出其他内容: {message_str} @@ -90,7 +97,7 @@ class MemoryChest: else: logger.debug(f"记忆仓库构建运行内容 prompt: {prompt}") - running_content, (reasoning_content, model_name, tool_calls) = await self.LLMRequest.generate_response_async(prompt) + running_content, (reasoning_content, model_name, tool_calls) = await self.LLMRequest_build.generate_response_async(prompt) print(f"记忆仓库构建运行内容: {running_content}") @@ -297,7 +304,7 @@ class MemoryChest: else: logger.debug(f"记忆仓库生成标题 prompt: {title_prompt}") - title, (reasoning_content, model_name, tool_calls) = await self.LLMRequest.generate_response_async(title_prompt) + title, (reasoning_content, model_name, tool_calls) = await self.LLMRequest_build.generate_response_async(title_prompt) if title: # 保存到数据库 diff --git a/src/chat/memory_system/hippocampus_to_memory_chest_task.py b/src/chat/memory_system/hippocampus_to_memory_chest_task.py new file mode 100644 index 00000000..184ec7d7 --- /dev/null +++ b/src/chat/memory_system/hippocampus_to_memory_chest_task.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +import random +from typing import List + +from src.manager.async_task_manager import AsyncTask +from src.chat.memory_system.Hippocampus import hippocampus_manager +from src.chat.memory_system.Memory_chest import global_memory_chest +from src.common.logger import get_logger + +logger = get_logger("hippocampus_to_memory_chest") + + +class HippocampusToMemoryChestTask(AsyncTask): + """海马体到记忆仓库的转换任务 + + 每60秒随机选择5个海马体节点,将内容拼接为content, + 然后根据memory_chest的格式生成标题并存储 + """ + + def __init__(self): + super().__init__( + task_name="Hippocampus to Memory Chest Task", + wait_before_start=60, # 启动后等待60秒再开始 + run_interval=60 # 每60秒运行一次 + ) + + async def run(self): + """执行转换任务""" + try: + logger.info("[海马体转换] 开始执行海马体到记忆仓库的转换任务") + + # 检查海马体管理器是否已初始化 + if not hippocampus_manager._initialized: + logger.warning("[海马体转换] 海马体管理器尚未初始化,跳过本次转换") + return + + # 获取海马体实例 + hippocampus = hippocampus_manager.get_hippocampus() + memory_graph = hippocampus.memory_graph.G + + # 获取所有节点 + all_nodes = list(memory_graph.nodes()) + + if len(all_nodes) < 5: + logger.info(f"[海马体转换] 当前只有 {len(all_nodes)} 个节点,少于5个,跳过本次转换") + return + + # 随机选择5个节点 + selected_nodes = random.sample(all_nodes, 5) + logger.info(f"[海马体转换] 随机选择了 {len(selected_nodes)} 个节点: {selected_nodes}") + + # 拼接节点内容 + content_parts = [] + for node in selected_nodes: + node_data = memory_graph.nodes[node] + memory_items = node_data.get("memory_items", "") + + if memory_items and memory_items.strip(): + # 添加节点名称和内容 + content_parts.append(f"【{node}】{memory_items}") + else: + logger.debug(f"[海马体转换] 节点 {node} 没有记忆内容,跳过") + + if not content_parts: + logger.info("[海马体转换] 没有找到有效的记忆内容,跳过本次转换") + return + + # 拼接所有内容 + combined_content = "\n\n".join(content_parts) + logger.info(f"[海马体转换] 拼接完成,内容长度: {len(combined_content)} 字符") + + # 生成标题并存储到记忆仓库 + success = await self._save_to_memory_chest(combined_content) + + # 如果保存成功,删除已转换的节点 + if success: + await self._remove_converted_nodes(selected_nodes) + + logger.info("[海马体转换] 转换任务完成") + + except Exception as e: + logger.error(f"[海马体转换] 执行转换任务时发生错误: {e}", exc_info=True) + + async def _save_to_memory_chest(self, content: str) -> bool: + """将内容保存到记忆仓库 + + Args: + content: 要保存的内容 + + Returns: + bool: 保存是否成功 + """ + try: + # 使用Memory_chest的LLMRequest生成标题 + title_prompt = f""" +请为以下内容生成一个描述全面的标题,要求描述内容的主要概念和事件: +{content} + +请只输出标题,不要输出其他内容: +""" + + # 使用Memory_chest的LLM模型生成标题 + title, (reasoning_content, model_name, tool_calls) = await global_memory_chest.LLMRequest_build.generate_response_async(title_prompt) + + if title and title.strip(): + # 保存到数据库 + from src.common.database.database_model import MemoryChest as MemoryChestModel + + MemoryChestModel.create( + title=title.strip(), + content=content + ) + + logger.info(f"[海马体转换] 已保存到记忆仓库,标题: {title.strip()}") + return True + else: + logger.warning("[海马体转换] 生成标题失败,跳过保存") + return False + + except Exception as e: + logger.error(f"[海马体转换] 保存到记忆仓库时发生错误: {e}", exc_info=True) + return False + + async def _remove_converted_nodes(self, nodes_to_remove: List[str]): + """删除已转换的海马体节点 + + Args: + nodes_to_remove: 要删除的节点列表 + """ + try: + # 获取海马体实例 + hippocampus = hippocampus_manager.get_hippocampus() + memory_graph = hippocampus.memory_graph.G + + removed_count = 0 + for node in nodes_to_remove: + if node in memory_graph: + # 删除节点(这会自动删除相关的边) + memory_graph.remove_node(node) + removed_count += 1 + logger.info(f"[海马体转换] 已删除节点: {node}") + else: + logger.debug(f"[海马体转换] 节点 {node} 不存在,跳过删除") + + # 同步到数据库 + if removed_count > 0: + await hippocampus.entorhinal_cortex.sync_memory_to_db() + logger.info(f"[海马体转换] 已删除 {removed_count} 个节点并同步到数据库") + else: + logger.info("[海马体转换] 没有节点需要删除") + + except Exception as e: + logger.error(f"[海马体转换] 删除节点时发生错误: {e}", exc_info=True) diff --git a/src/main.py b/src/main.py index e4935559..496242bf 100644 --- a/src/main.py +++ b/src/main.py @@ -13,6 +13,8 @@ from src.common.logger import get_logger from src.common.server import get_global_server, Server from src.mood.mood_manager import mood_manager from src.chat.knowledge import lpmm_start_up +from src.chat.memory_system.Hippocampus import hippocampus_manager +from src.chat.memory_system.hippocampus_to_memory_chest_task import HippocampusToMemoryChestTask from rich.traceback import install from src.migrate_helper.migrate import check_and_run_migrations # from src.api.main import start_api_server @@ -92,13 +94,13 @@ class MainSystem: logger.info("聊天管理器初始化成功") - # # 根据配置条件性地初始化记忆系统 - # if global_config.memory.enable_memory: - # if self.hippocampus_manager: - # self.hippocampus_manager.initialize() - # logger.info("记忆系统初始化成功") - # else: - # logger.info("记忆系统已禁用,跳过初始化") + # 初始化记忆系统 + hippocampus_manager.initialize() + logger.info("记忆系统初始化成功") + + # 添加海马体到记忆仓库的转换任务 + await async_task_manager.add_task(HippocampusToMemoryChestTask()) + logger.info("海马体到记忆仓库转换任务已启动") # await asyncio.sleep(0.5) #防止logger输出飞了 diff --git a/template/model_config_template.toml b/template/model_config_template.toml index 01786f98..d48d7f2d 100644 --- a/template/model_config_template.toml +++ b/template/model_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "1.7.2" +version = "1.7.3" # 配置文件版本号迭代规则同bot_config.toml @@ -96,12 +96,12 @@ price_out = 0 [model_task_config.utils] # 在麦麦的一些组件中使用的模型,例如表情包模块,取名模块,关系模块,麦麦的情绪变化等,是麦麦必须的模型 model_list = ["siliconflow-deepseek-v3","qwen3-30b"] # 使用的模型列表,每个子项对应上面的模型名称(name) temperature = 0.2 # 模型温度,新V3建议0.1-0.3 -max_tokens = 800 # 最大输出token数 +max_tokens = 2048 # 最大输出token数 [model_task_config.utils_small] # 在麦麦的一些组件中使用的小模型,消耗量较大,建议使用速度较快的小模型 model_list = ["qwen3-8b","qwen3-30b"] temperature = 0.7 -max_tokens = 800 +max_tokens = 2048 [model_task_config.tool_use] #工具调用模型,需要使用支持工具调用的模型 model_list = ["qwen3-30b"]