feat(replyer): 添加最近消息支持以构建记忆块和查询文本

This commit is contained in:
Windpicker-owo
2025-11-20 18:06:23 +08:00
parent e46a900f10
commit bd4e36b1cf
2 changed files with 94 additions and 14 deletions

View File

@@ -566,12 +566,18 @@ class DefaultReplyer:
return f"{expression_habits_title}\n{expression_habits_block}" return f"{expression_habits_title}\n{expression_habits_block}"
async def build_memory_block(self, chat_history: str, target: str) -> str: async def build_memory_block(
self,
chat_history: str,
target: str,
recent_messages: list[dict[str, Any]] | None = None,
) -> str:
"""构建记忆块(使用三层记忆系统) """构建记忆块(使用三层记忆系统)
Args: Args:
chat_history: 聊天历史记录 chat_history: 聊天历史记录
target: 目标消息内容 target: 目标消息内容
recent_messages: 原始聊天消息列表(用于构建查询块)
Returns: Returns:
str: 记忆信息字符串 str: 记忆信息字符串
@@ -589,9 +595,12 @@ class DefaultReplyer:
logger.debug("[三层记忆] 管理器未初始化") logger.debug("[三层记忆] 管理器未初始化")
return "" return ""
# 目标查询改为使用最近多条消息的组合块
query_text = self._build_memory_query_text(target, recent_messages)
# 使用统一管理器的智能检索Judge模型决策 # 使用统一管理器的智能检索Judge模型决策
search_result = await unified_manager.search_memories( search_result = await unified_manager.search_memories(
query_text=target, query_text=query_text,
use_judge=True, use_judge=True,
recent_chat_history=chat_history, # 传递最近聊天历史 recent_chat_history=chat_history, # 传递最近聊天历史
) )
@@ -629,6 +638,62 @@ class DefaultReplyer:
logger.error(f"[三层记忆] 检索失败: {e}", exc_info=True) logger.error(f"[三层记忆] 检索失败: {e}", exc_info=True)
return "" return ""
def _build_memory_query_text(
self,
fallback_text: str,
recent_messages: list[dict[str, Any]] | None,
block_size: int = 5,
) -> str:
"""
将最近若干条消息拼接为一个查询块,用于生成语义向量。
Args:
fallback_text: 如果无法拼接消息块时使用的后备文本
recent_messages: 最近的消息列表
block_size: 组合的消息数量
Returns:
str: 用于检索的查询文本
"""
if not recent_messages:
return fallback_text
lines: list[str] = []
for message in recent_messages[-block_size:]:
sender = (
message.get("sender_name")
or message.get("person_name")
or message.get("user_nickname")
or message.get("user_cardname")
or message.get("nickname")
or message.get("sender")
)
if not sender and isinstance(message.get("user_info"), dict):
user_info = message["user_info"]
sender = user_info.get("user_nickname") or user_info.get("user_cardname")
sender = sender or message.get("user_id") or "未知"
content = (
message.get("processed_plain_text")
or message.get("display_message")
or message.get("content")
or message.get("message")
or message.get("text")
or ""
)
content = str(content).strip()
if content:
lines.append(f"{sender}: {content}")
fallback_clean = fallback_text.strip()
if not lines:
return fallback_clean or fallback_text
return "\n".join(lines[-block_size:])
async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str: async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str:
@@ -1251,7 +1316,10 @@ class DefaultReplyer:
self._time_and_run_task(self.build_relation_info(sender, target), "relation_info") self._time_and_run_task(self.build_relation_info(sender, target), "relation_info")
), ),
"memory_block": asyncio.create_task( "memory_block": asyncio.create_task(
self._time_and_run_task(self.build_memory_block(chat_talking_prompt_short, target), "memory_block") self._time_and_run_task(
self.build_memory_block(chat_talking_prompt_short, target, message_list_before_short),
"memory_block",
)
), ),
"tool_info": asyncio.create_task( "tool_info": asyncio.create_task(
self._time_and_run_task( self._time_and_run_task(

View File

@@ -312,7 +312,8 @@ class ThreeTierMemoryFormatter:
# 查找客体和属性 # 查找客体和属性
objects = [] objects = []
attributes = {} attributes: dict[str, str] = {}
attribute_names: dict[str, str] = {}
for edge in memory.edges: for edge in memory.edges:
edge_type = edge.edge_type.value if hasattr(edge.edge_type, 'value') else str(edge.edge_type) edge_type = edge.edge_type.value if hasattr(edge.edge_type, 'value') else str(edge.edge_type)
@@ -320,17 +321,28 @@ class ThreeTierMemoryFormatter:
if edge_type == "核心关系" and edge.source_id == topic_node.id: if edge_type == "核心关系" and edge.source_id == topic_node.id:
obj_node = memory.get_node_by_id(edge.target_id) obj_node = memory.get_node_by_id(edge.target_id)
if obj_node: if obj_node:
if edge.relation and edge.relation != "未知": relation_label = (edge.relation or "").strip()
objects.append(f"{edge.relation}{obj_node.content}") obj_text = obj_node.content
if relation_label and relation_label not in {"未知", "核心关系"}:
objects.append(f"{relation_label}{obj_text}")
else: else:
objects.append(obj_node.content) objects.append(obj_text)
elif edge_type == "属性关系": elif edge_type == "属性关系":
attr_node = memory.get_node_by_id(edge.target_id) attr_node = memory.get_node_by_id(edge.target_id)
if attr_node: if not attr_node:
attr_name = edge.relation if edge.relation else "属性" continue
# 使用字典避免重复属性,后面的会覆盖前面的
attributes[attr_name] = attr_node.content if edge.source_id == topic_node.id:
# 记录属性节点的名称,稍后匹配对应的值节点
attribute_names[attr_node.id] = attr_node.content
continue
attr_name = attribute_names.get(edge.source_id)
if not attr_name:
attr_name = edge.relation.strip() if edge.relation else "属性"
attributes[attr_name] = attr_node.content
# 检查节点中的属性(处理 "key=value" 格式) # 检查节点中的属性(处理 "key=value" 格式)
for node in memory.nodes: for node in memory.nodes:
@@ -338,9 +350,9 @@ class ThreeTierMemoryFormatter:
# 处理 "key=value" 格式的属性 # 处理 "key=value" 格式的属性
if "=" in node.content: if "=" in node.content:
key, value = node.content.split("=", 1) key, value = node.content.split("=", 1)
attributes[key.strip()] = value.strip() attributes.setdefault(key.strip(), value.strip())
else: else:
attributes["属性"] = node.content attributes.setdefault("属性", node.content)
# 构建最终格式 # 构建最终格式
result = f"[{type_label}] {subject}-{topic}" result = f"[{type_label}] {subject}-{topic}"
@@ -437,4 +449,4 @@ class ThreeTierMemoryFormatter:
# 创建全局格式化器实例 # 创建全局格式化器实例
memory_formatter = ThreeTierMemoryFormatter() memory_formatter = ThreeTierMemoryFormatter()