refactor(memory): 完全移除旧记忆系统,全面切换到新记忆图系统

重大变更:
- 移除 default_generator.py 中对旧增强记忆系统的所有调用
- 移除 prompt.py 中的记忆构建函数
- 记忆检索全面使用新记忆图系统
- 禁用旧记忆系统的自动存储逻辑

记忆构建流程:
- 记忆创建: LLM 通过 create_memory 工具主动创建
- 记忆检索: default_generator.py 自动检索
- 记忆传递: 通过 pre_built_params 传入 prompt

工具可用性:
- CreateMemoryTool: available_for_llm = True
- LinkMemoriesTool: available_for_llm = False
- SearchMemoriesTool: available_for_llm = False

技术细节:
- 提高记忆检索数量 top_k=10
- 降低重要性阈值 min_importance=0.3
- 修复类型错误和警告
This commit is contained in:
Windpicker-owo
2025-11-05 19:22:34 +08:00
parent edd74bed9f
commit cd15c51e6b
3 changed files with 32 additions and 196 deletions

View File

@@ -555,164 +555,8 @@ class DefaultReplyer:
instant_memory = None instant_memory = None
# 使用新的增强记忆系统检索记忆 # 使用新的记忆系统检索记忆
running_memories = [] all_memories = []
instant_memory = None
if global_config.memory.enable_memory:
try:
# 使用新的统一记忆系统
from src.chat.memory_system import get_memory_system
stream = self.chat_stream
user_info_obj = getattr(stream, "user_info", None)
group_info_obj = getattr(stream, "group_info", None)
memory_user_id = str(stream.stream_id)
memory_user_display = None
memory_aliases = []
user_info_dict = {}
if user_info_obj is not None:
raw_user_id = getattr(user_info_obj, "user_id", None)
if raw_user_id:
memory_user_id = str(raw_user_id)
if hasattr(user_info_obj, "to_dict"):
try:
user_info_dict = user_info_obj.to_dict() # type: ignore[attr-defined]
except Exception:
user_info_dict = {}
candidate_keys = [
"user_cardname",
"user_nickname",
"nickname",
"remark",
"display_name",
"user_name",
]
for key in candidate_keys:
value = user_info_dict.get(key)
if isinstance(value, str) and value.strip():
stripped = value.strip()
if memory_user_display is None:
memory_user_display = stripped
elif stripped not in memory_aliases:
memory_aliases.append(stripped)
attr_keys = [
"user_cardname",
"user_nickname",
"nickname",
"remark",
"display_name",
"name",
]
for attr in attr_keys:
value = getattr(user_info_obj, attr, None)
if isinstance(value, str) and value.strip():
stripped = value.strip()
if memory_user_display is None:
memory_user_display = stripped
elif stripped not in memory_aliases:
memory_aliases.append(stripped)
alias_values = (
user_info_dict.get("aliases")
or user_info_dict.get("alias_names")
or user_info_dict.get("alias")
)
if isinstance(alias_values, list | tuple | set):
for alias in alias_values:
if isinstance(alias, str) and alias.strip():
stripped = alias.strip()
if stripped not in memory_aliases and stripped != memory_user_display:
memory_aliases.append(stripped)
memory_context = {
"user_id": memory_user_id,
"user_display_name": memory_user_display or "",
"user_name": memory_user_display or "",
"nickname": memory_user_display or "",
"sender_name": memory_user_display or "",
"platform": getattr(stream, "platform", None),
"chat_id": stream.stream_id,
"stream_id": stream.stream_id,
}
if memory_aliases:
memory_context["user_aliases"] = memory_aliases
if group_info_obj is not None:
group_name = getattr(group_info_obj, "group_name", None) or getattr(
group_info_obj, "group_nickname", None
)
if group_name:
memory_context["group_name"] = str(group_name)
group_id = getattr(group_info_obj, "group_id", None)
if group_id:
memory_context["group_id"] = str(group_id)
memory_context = {key: value for key, value in memory_context.items() if value}
# 获取记忆系统实例
memory_system = get_memory_system()
# 使用统一记忆系统检索相关记忆
enhanced_memories = await memory_system.retrieve_relevant_memories(
query=target, user_id=memory_user_id, scope_id=stream.stream_id, context=memory_context, limit=10
)
# 注意:记忆存储已迁移到回复生成完成后进行,不在查询阶段执行
# 转换格式以兼容现有代码
running_memories = []
if enhanced_memories:
logger.debug(f"[记忆转换] 收到 {len(enhanced_memories)} 条原始记忆")
for idx, memory_chunk in enumerate(enhanced_memories, 1):
# 获取结构化内容的字符串表示
structure_display = str(memory_chunk.content) if hasattr(memory_chunk, "content") else "unknown"
# 获取记忆内容优先使用display
content = memory_chunk.display or memory_chunk.text_content or ""
# 调试:记录每条记忆的内容获取情况
logger.debug(
f"[记忆转换] 第{idx}条: display={repr(memory_chunk.display)[:80]}, text_content={repr(memory_chunk.text_content)[:80]}, final_content={repr(content)[:80]}"
)
running_memories.append(
{
"content": content,
"memory_type": memory_chunk.memory_type.value,
"confidence": memory_chunk.metadata.confidence.value,
"importance": memory_chunk.metadata.importance.value,
"relevance": getattr(memory_chunk.metadata, "relevance_score", 0.5),
"source": memory_chunk.metadata.source,
"structure": structure_display,
}
)
# 构建瞬时记忆字符串
if running_memories:
top_memory = running_memories[:1]
if top_memory:
instant_memory = top_memory[0].get("content", "")
logger.info(
f"增强记忆系统检索到 {len(enhanced_memories)} 条原始记忆,转换为 {len(running_memories)} 条可用记忆"
)
except Exception as e:
logger.warning(f"增强记忆系统检索失败: {e}")
running_memories = []
instant_memory = ""
# 尝试从记忆图系统检索记忆
graph_memories = []
try: try:
from src.memory_graph.manager_singleton import get_memory_manager, is_initialized from src.memory_graph.manager_singleton import get_memory_manager, is_initialized
@@ -722,8 +566,8 @@ class DefaultReplyer:
# 搜索相关记忆 # 搜索相关记忆
memories = await manager.search_memories( memories = await manager.search_memories(
query=target, query=target,
top_k=5, top_k=10, # 增加检索数量
min_importance=0.5, min_importance=0.3, # 降低最低重要性阈值,获取更多记忆
include_forgotten=False include_forgotten=False
) )
@@ -733,27 +577,29 @@ class DefaultReplyer:
topic = memory.metadata.get("topic", "") topic = memory.metadata.get("topic", "")
mem_type = memory.metadata.get("memory_type", "未知") mem_type = memory.metadata.get("memory_type", "未知")
if topic: if topic:
graph_memories.append({ all_memories.append({
"content": topic, "content": topic,
"memory_type": mem_type, "memory_type": mem_type,
"importance": memory.importance, "importance": memory.importance,
"relevance": 0.7, # 默认相关度 "relevance": 0.7, # 默认相关度
"source": "memory_graph", "source": "memory_graph",
}) })
# 提取最重要的记忆作为瞬时记忆
if all_memories:
top_memory = max(all_memories, key=lambda m: m.get("importance", 0))
instant_memory = top_memory.get("content", "")
else: else:
logger.debug("[记忆图] 未找到相关记忆") logger.debug("[记忆图] 未找到相关记忆")
except Exception as e: except Exception as e:
logger.debug(f"[记忆图] 检索失败: {e}") logger.debug(f"[记忆图] 检索失败: {e}")
graph_memories = [] all_memories = []
# 合并记忆(增强记忆系统 + 记忆图系统)
all_memories = running_memories + graph_memories
# 构建记忆字符串,使用方括号格式 # 构建记忆字符串,使用方括号格式
memory_str = "" memory_str = ""
has_any_memory = False has_any_memory = False
# 添加长期记忆(来自增强记忆系统 + 记忆图系统) # 添加长期记忆(来自记忆图系统)
if all_memories: if all_memories:
# 使用方括号格式 # 使用方括号格式
memory_parts = ["### 🧠 相关记忆 (Relevant Memories)", ""] memory_parts = ["### 🧠 相关记忆 (Relevant Memories)", ""]
@@ -2159,23 +2005,9 @@ class DefaultReplyer:
show_actions=True, show_actions=True,
) )
# 异步存储聊天历史(完全非阻塞) # 旧记忆系统的自动存储已禁用
memory_system = get_memory_system() # 新记忆系统通过 LLM 工具调用create_memory来创建记忆
task = asyncio.create_task( logger.debug(f"记忆创建通过 LLM 工具调用进行,用户: {memory_user_display or memory_user_id}")
memory_system.process_conversation_memory(
context={
"conversation_text": chat_history,
"user_id": memory_user_id,
"scope_id": stream.stream_id,
**memory_context,
}
)
)
# 将任务添加到全局集合以防止被垃圾回收
_background_tasks.add(task)
task.add_done_callback(_background_tasks.discard)
logger.debug(f"已启动记忆存储任务,用户: {memory_user_display or memory_user_id}")
except asyncio.CancelledError: except asyncio.CancelledError:
logger.debug("记忆存储任务被取消") logger.debug("记忆存储任务被取消")

View File

@@ -398,6 +398,9 @@ class Prompt:
""" """
start_time = time.time() start_time = time.time()
# 初始化预构建参数字典
pre_built_params = {}
try: try:
# --- 步骤 1: 准备构建任务 --- # --- 步骤 1: 准备构建任务 ---
tasks = [] tasks = []
@@ -406,7 +409,6 @@ class Prompt:
# --- 步骤 1.1: 优先使用预构建的参数 --- # --- 步骤 1.1: 优先使用预构建的参数 ---
# 如果参数对象中已经包含了某些block说明它们是外部预构建的 # 如果参数对象中已经包含了某些block说明它们是外部预构建的
# 我们将它们存起来,并跳过对应的实时构建任务。 # 我们将它们存起来,并跳过对应的实时构建任务。
pre_built_params = {}
if self.parameters.expression_habits_block: if self.parameters.expression_habits_block:
pre_built_params["expression_habits_block"] = self.parameters.expression_habits_block pre_built_params["expression_habits_block"] = self.parameters.expression_habits_block
if self.parameters.relation_info_block: if self.parameters.relation_info_block:
@@ -428,11 +430,9 @@ class Prompt:
tasks.append(self._build_expression_habits()) tasks.append(self._build_expression_habits())
task_names.append("expression_habits") task_names.append("expression_habits")
# 记忆块构建非常耗时,强烈建议预构建。如果没有预构建,这里会运行一个快速的后备版本。 # 记忆块构建已移至 default_generator.py 的 build_memory_block 方法
if self.parameters.enable_memory and not pre_built_params.get("memory_block"): # 使用新的记忆图系统,不再在 prompt.py 中构建记忆
logger.debug("memory_block未预构建执行快速构建作为后备方案") # 如果需要记忆,必须通过 pre_built_params 传入
tasks.append(self._build_memory_block_fast())
task_names.append("memory_block")
if self.parameters.enable_relation and not pre_built_params.get("relation_info_block"): if self.parameters.enable_relation and not pre_built_params.get("relation_info_block"):
tasks.append(self._build_relation_info()) tasks.append(self._build_relation_info())
@@ -637,8 +637,12 @@ class Prompt:
logger.error(f"构建表达习惯失败: {e}") logger.error(f"构建表达习惯失败: {e}")
return {"expression_habits_block": ""} return {"expression_habits_block": ""}
async def _build_memory_block(self) -> dict[str, Any]: # _build_memory_block 和 _build_memory_block_fast 已移除
"""构建与当前对话相关的记忆上下文块(完整版).""" # 记忆构建现在完全由 default_generator.py 的 build_memory_block 方法处理
# 使用新的记忆图系统,通过 pre_built_params 传入
async def _REMOVED_build_memory_block(self) -> dict[str, Any]:
"""已废弃:构建与当前对话相关的记忆上下文块(完整版)."""
if not global_config.memory.enable_memory: if not global_config.memory.enable_memory:
return {"memory_block": ""} return {"memory_block": ""}
@@ -753,8 +757,8 @@ class Prompt:
logger.error(f"构建记忆块失败: {e}") logger.error(f"构建记忆块失败: {e}")
return {"memory_block": ""} return {"memory_block": ""}
async def _build_memory_block_fast(self) -> dict[str, Any]: async def _REMOVED_build_memory_block_fast(self) -> dict[str, Any]:
"""快速构建记忆块(简化版),作为未预构建时的后备方案.""" """已废弃:快速构建记忆块(简化版),作为未预构建时的后备方案."""
if not global_config.memory.enable_memory: if not global_config.memory.enable_memory:
return {"memory_block": ""} return {"memory_block": ""}

View File

@@ -107,7 +107,7 @@ class LinkMemoriesTool(BaseTool):
("strength", ToolParamType.FLOAT, "关系强度0.0-1.0默认0.7", False, None), ("strength", ToolParamType.FLOAT, "关系强度0.0-1.0默认0.7", False, None),
] ]
available_for_llm = True available_for_llm = False # 暂不对 LLM 开放
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]: async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
"""执行关联记忆""" """执行关联记忆"""
@@ -166,7 +166,7 @@ class SearchMemoriesTool(BaseTool):
("min_importance", ToolParamType.FLOAT, "最低重要性阈值0.0-1.0),只返回重要性不低于此值的记忆", False, None), ("min_importance", ToolParamType.FLOAT, "最低重要性阈值0.0-1.0),只返回重要性不低于此值的记忆", False, None),
] ]
available_for_llm = True available_for_llm = False # 暂不对 LLM 开放,记忆检索在提示词构建时自动执行
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]: async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
"""执行搜索记忆""" """执行搜索记忆"""
@@ -183,7 +183,7 @@ class SearchMemoriesTool(BaseTool):
query = function_args.get("query", "") query = function_args.get("query", "")
top_k = function_args.get("top_k", 5) top_k = function_args.get("top_k", 5)
min_importance_raw = function_args.get("min_importance") min_importance_raw = function_args.get("min_importance")
min_importance = float(min_importance_raw) if min_importance_raw is not None else None min_importance = float(min_importance_raw) if min_importance_raw is not None else 0.0
# 搜索记忆 # 搜索记忆
memories = await manager.search_memories( memories = await manager.search_memories(