mirror of https://github.com/Mai-with-u/MaiBot.git
feqt 转换旧记忆
parent
cec2c1830e
commit
6e7e9be82a
|
|
@ -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. 删除操作会自动同步到数据库,保持数据一致性
|
||||||
|
|
@ -1452,7 +1452,6 @@ class HippocampusManager:
|
||||||
logger.info(f"""
|
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}
|
记忆图统计信息: 节点数量: {node_count}, 连接数量: {edge_count}
|
||||||
--------------------------------""") # noqa: E501
|
--------------------------------""") # noqa: E501
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,13 @@ class MemoryChest:
|
||||||
request_type="memory_chest",
|
request_type="memory_chest",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.memory_build_threshold = 20
|
self.LLMRequest_build = LLMRequest(
|
||||||
self.memory_size_limit = 300
|
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.running_content_list = {} # {chat_id: {"content": running_content, "last_update_time": timestamp}}
|
||||||
self.fetched_memory_list = [] # [(chat_id, (question, answer, timestamp)), ...]
|
self.fetched_memory_list = [] # [(chat_id, (question, answer, timestamp)), ...]
|
||||||
|
|
@ -80,6 +85,8 @@ class MemoryChest:
|
||||||
|
|
||||||
请将下面的新聊天记录内的有用的信息,添加到你的记忆中
|
请将下面的新聊天记录内的有用的信息,添加到你的记忆中
|
||||||
请主要关注概念和知识,而不是聊天的琐事
|
请主要关注概念和知识,而不是聊天的琐事
|
||||||
|
如果有表情包,仅在意表情包对上下文的影响,不要在意表情包本身
|
||||||
|
如果有图片,尽在意内容,不要在意图片的名称和编号
|
||||||
记忆为一段纯文本,逻辑清晰,指出事件,概念的含义,并说明关系
|
记忆为一段纯文本,逻辑清晰,指出事件,概念的含义,并说明关系
|
||||||
请输出添加后的记忆内容,不要输出其他内容:
|
请输出添加后的记忆内容,不要输出其他内容:
|
||||||
{message_str}
|
{message_str}
|
||||||
|
|
@ -90,7 +97,7 @@ class MemoryChest:
|
||||||
else:
|
else:
|
||||||
logger.debug(f"记忆仓库构建运行内容 prompt: {prompt}")
|
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}")
|
print(f"记忆仓库构建运行内容: {running_content}")
|
||||||
|
|
||||||
|
|
@ -297,7 +304,7 @@ class MemoryChest:
|
||||||
else:
|
else:
|
||||||
logger.debug(f"记忆仓库生成标题 prompt: {title_prompt}")
|
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:
|
if title:
|
||||||
# 保存到数据库
|
# 保存到数据库
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
16
src/main.py
16
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.common.server import get_global_server, Server
|
||||||
from src.mood.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
from src.chat.knowledge import lpmm_start_up
|
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 rich.traceback import install
|
||||||
from src.migrate_helper.migrate import check_and_run_migrations
|
from src.migrate_helper.migrate import check_and_run_migrations
|
||||||
# from src.api.main import start_api_server
|
# from src.api.main import start_api_server
|
||||||
|
|
@ -92,13 +94,13 @@ class MainSystem:
|
||||||
|
|
||||||
logger.info("聊天管理器初始化成功")
|
logger.info("聊天管理器初始化成功")
|
||||||
|
|
||||||
# # 根据配置条件性地初始化记忆系统
|
# 初始化记忆系统
|
||||||
# if global_config.memory.enable_memory:
|
hippocampus_manager.initialize()
|
||||||
# if self.hippocampus_manager:
|
logger.info("记忆系统初始化成功")
|
||||||
# self.hippocampus_manager.initialize()
|
|
||||||
# logger.info("记忆系统初始化成功")
|
# 添加海马体到记忆仓库的转换任务
|
||||||
# else:
|
await async_task_manager.add_task(HippocampusToMemoryChestTask())
|
||||||
# logger.info("记忆系统已禁用,跳过初始化")
|
logger.info("海马体到记忆仓库转换任务已启动")
|
||||||
|
|
||||||
# await asyncio.sleep(0.5) #防止logger输出飞了
|
# await asyncio.sleep(0.5) #防止logger输出飞了
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[inner]
|
[inner]
|
||||||
version = "1.7.2"
|
version = "1.7.3"
|
||||||
|
|
||||||
# 配置文件版本号迭代规则同bot_config.toml
|
# 配置文件版本号迭代规则同bot_config.toml
|
||||||
|
|
||||||
|
|
@ -96,12 +96,12 @@ price_out = 0
|
||||||
[model_task_config.utils] # 在麦麦的一些组件中使用的模型,例如表情包模块,取名模块,关系模块,麦麦的情绪变化等,是麦麦必须的模型
|
[model_task_config.utils] # 在麦麦的一些组件中使用的模型,例如表情包模块,取名模块,关系模块,麦麦的情绪变化等,是麦麦必须的模型
|
||||||
model_list = ["siliconflow-deepseek-v3","qwen3-30b"] # 使用的模型列表,每个子项对应上面的模型名称(name)
|
model_list = ["siliconflow-deepseek-v3","qwen3-30b"] # 使用的模型列表,每个子项对应上面的模型名称(name)
|
||||||
temperature = 0.2 # 模型温度,新V3建议0.1-0.3
|
temperature = 0.2 # 模型温度,新V3建议0.1-0.3
|
||||||
max_tokens = 800 # 最大输出token数
|
max_tokens = 2048 # 最大输出token数
|
||||||
|
|
||||||
[model_task_config.utils_small] # 在麦麦的一些组件中使用的小模型,消耗量较大,建议使用速度较快的小模型
|
[model_task_config.utils_small] # 在麦麦的一些组件中使用的小模型,消耗量较大,建议使用速度较快的小模型
|
||||||
model_list = ["qwen3-8b","qwen3-30b"]
|
model_list = ["qwen3-8b","qwen3-30b"]
|
||||||
temperature = 0.7
|
temperature = 0.7
|
||||||
max_tokens = 800
|
max_tokens = 2048
|
||||||
|
|
||||||
[model_task_config.tool_use] #工具调用模型,需要使用支持工具调用的模型
|
[model_task_config.tool_use] #工具调用模型,需要使用支持工具调用的模型
|
||||||
model_list = ["qwen3-30b"]
|
model_list = ["qwen3-30b"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue