diff --git a/src/memory_graph/config.py b/src/memory_graph/config.py index a765f3fc1..5a17cdf72 100644 --- a/src/memory_graph/config.py +++ b/src/memory_graph/config.py @@ -86,6 +86,11 @@ class MemoryGraphConfig: consolidation_similarity_threshold: float = 0.85 consolidation_time_window_hours: int = 24 + # 自动关联配置 + auto_link_enabled: bool = True # 是否启用自动关联 + auto_link_max_candidates: int = 5 # 每个记忆最多关联候选数 + auto_link_min_confidence: float = 0.7 # 最低置信度阈值 + # 遗忘配置 forgetting_enabled: bool = True forgetting_activation_threshold: float = 0.1 @@ -145,6 +150,9 @@ class MemoryGraphConfig: consolidation_interval_hours=getattr(mg_config, 'consolidation_interval_hours', 1.0), consolidation_similarity_threshold=getattr(mg_config, 'consolidation_similarity_threshold', 0.85), consolidation_time_window_hours=getattr(mg_config, 'consolidation_time_window_hours', 24), + auto_link_enabled=getattr(mg_config, 'auto_link_enabled', True), + auto_link_max_candidates=getattr(mg_config, 'auto_link_max_candidates', 5), + auto_link_min_confidence=getattr(mg_config, 'auto_link_min_confidence', 0.7), forgetting_enabled=getattr(mg_config, 'forgetting_enabled', True), forgetting_activation_threshold=getattr(mg_config, 'forgetting_activation_threshold', 0.1), forgetting_min_importance=getattr(mg_config, 'forgetting_min_importance', 0.8), @@ -183,6 +191,9 @@ class MemoryGraphConfig: consolidation_interval_hours=config_dict.get("consolidation_interval_hours", 1.0), consolidation_similarity_threshold=config_dict.get("consolidation_similarity_threshold", 0.85), consolidation_time_window_hours=config_dict.get("consolidation_time_window_hours", 24), + auto_link_enabled=config_dict.get("auto_link_enabled", True), + auto_link_max_candidates=config_dict.get("auto_link_max_candidates", 5), + auto_link_min_confidence=config_dict.get("auto_link_min_confidence", 0.7), forgetting_enabled=config_dict.get("forgetting_enabled", True), forgetting_activation_threshold=config_dict.get("forgetting_activation_threshold", 0.1), forgetting_min_importance=config_dict.get("forgetting_min_importance", 0.8), diff --git a/src/memory_graph/manager.py b/src/memory_graph/manager.py index 45cf32c4a..b88a9da19 100644 --- a/src/memory_graph/manager.py +++ b/src/memory_graph/manager.py @@ -17,12 +17,13 @@ from typing import Any, Dict, List, Optional, Set, Tuple from src.memory_graph.config import MemoryGraphConfig from src.memory_graph.core.builder import MemoryBuilder from src.memory_graph.core.extractor import MemoryExtractor -from src.memory_graph.models import Memory, MemoryNode, MemoryType, NodeType +from src.memory_graph.models import Memory, MemoryEdge, MemoryNode, MemoryType, NodeType, EdgeType from src.memory_graph.storage.graph_store import GraphStore from src.memory_graph.storage.persistence import PersistenceManager from src.memory_graph.storage.vector_store import VectorStore from src.memory_graph.tools.memory_tools import MemoryTools from src.memory_graph.utils.embeddings import EmbeddingGenerator +import uuid logger = logging.getLogger(__name__) @@ -851,6 +852,376 @@ class MemoryManager: logger.error(f"记忆整理失败: {e}", exc_info=True) return {"error": str(e), "merged_count": 0, "checked_count": 0} + async def auto_link_memories( + self, + time_window_hours: float = None, + max_candidates: int = None, + min_confidence: float = None, + ) -> Dict[str, Any]: + """ + 自动关联记忆 + + 使用LLM分析记忆之间的关系,自动建立关联边。 + + Args: + time_window_hours: 分析时间窗口(小时) + max_candidates: 每个记忆最多关联的候选数 + min_confidence: 最低置信度阈值 + + Returns: + 关联结果统计 + """ + if not self._initialized: + await self.initialize() + + # 使用配置值或参数覆盖 + time_window_hours = time_window_hours if time_window_hours is not None else 24 + max_candidates = max_candidates if max_candidates is not None else self.config.auto_link_max_candidates + min_confidence = min_confidence if min_confidence is not None else self.config.auto_link_min_confidence + + try: + logger.info(f"开始自动关联记忆 (时间窗口={time_window_hours}h)...") + + result = { + "checked_count": 0, + "linked_count": 0, + "relation_stats": {}, # 关系类型统计 {类型: 数量} + "relations": {}, # 详细关系 {source_id: [关系列表]} + } + + # 1. 获取时间窗口内的记忆 + time_threshold = datetime.now() - timedelta(hours=time_window_hours) + all_memories = self.graph_store.get_all_memories() + + recent_memories = [ + mem for mem in all_memories + if mem.created_at >= time_threshold + and not mem.metadata.get("forgotten", False) + ] + + if len(recent_memories) < 2: + logger.info("记忆数量不足,跳过自动关联") + return result + + logger.info(f"找到 {len(recent_memories)} 条待关联记忆") + + # 2. 为每个记忆寻找关联候选 + for memory in recent_memories: + result["checked_count"] += 1 + + # 跳过已经有很多连接的记忆 + existing_edges = len([ + e for e in memory.edges + if e.edge_type == EdgeType.RELATION + ]) + if existing_edges >= 10: + continue + + # 3. 使用向量搜索找候选记忆 + candidates = await self._find_link_candidates( + memory, + exclude_ids={memory.id}, + max_results=max_candidates + ) + + if not candidates: + continue + + # 4. 使用LLM分析关系 + relations = await self._analyze_memory_relations( + source_memory=memory, + candidate_memories=candidates, + min_confidence=min_confidence + ) + + # 5. 建立关联 + for relation in relations: + try: + # 创建关联边 + edge = MemoryEdge( + id=f"edge_{uuid.uuid4().hex[:12]}", + source_id=memory.subject_id, + target_id=relation["target_memory"].subject_id, + relation=relation["relation_type"], + edge_type=EdgeType.RELATION, + importance=relation["confidence"], + metadata={ + "auto_linked": True, + "confidence": relation["confidence"], + "reasoning": relation["reasoning"], + "created_at": datetime.now().isoformat(), + } + ) + + # 添加到图 + self.graph_store.graph.add_edge( + edge.source_id, + edge.target_id, + edge_id=edge.id, + relation=edge.relation, + edge_type=edge.edge_type.value, + importance=edge.importance, + metadata=edge.metadata, + ) + + # 同时添加到记忆的边列表 + memory.edges.append(edge) + + result["linked_count"] += 1 + + # 更新统计 + result["relation_stats"][relation["relation_type"]] = \ + result["relation_stats"].get(relation["relation_type"], 0) + 1 + + # 记录详细关系 + if memory.id not in result["relations"]: + result["relations"][memory.id] = [] + result["relations"][memory.id].append({ + "target_id": relation["target_memory"].id, + "relation_type": relation["relation_type"], + "confidence": relation["confidence"], + "reasoning": relation["reasoning"], + }) + + logger.info( + f"建立关联: {memory.id[:8]} --[{relation['relation_type']}]--> " + f"{relation['target_memory'].id[:8]} " + f"(置信度={relation['confidence']:.2f})" + ) + + except Exception as e: + logger.warning(f"建立关联失败: {e}") + continue + + # 保存更新后的图数据 + if result["linked_count"] > 0: + await self.persistence.save_graph_store(self.graph_store) + logger.info(f"已保存 {result['linked_count']} 条自动关联边") + + logger.info(f"自动关联完成: {result}") + return result + + except Exception as e: + logger.error(f"自动关联失败: {e}", exc_info=True) + return {"error": str(e), "checked_count": 0, "linked_count": 0} + + async def _find_link_candidates( + self, + memory: Memory, + exclude_ids: Set[str], + max_results: int = 5, + ) -> List[Memory]: + """ + 为记忆寻找关联候选 + + 使用向量相似度 + 时间接近度找到潜在相关记忆 + """ + try: + # 获取记忆的主题 + topic_node = next( + (n for n in memory.nodes if n.node_type == NodeType.TOPIC), + None + ) + + if not topic_node or not topic_node.content: + return [] + + # 使用主题内容搜索相似记忆 + candidates = await self.search_memories( + query=topic_node.content, + top_k=max_results * 2, + include_forgotten=False, + optimize_query=False, + ) + + # 过滤:排除自己和已关联的 + existing_targets = { + e.target_id for e in memory.edges + if e.edge_type == EdgeType.RELATION + } + + filtered = [ + c for c in candidates + if c.id not in exclude_ids + and c.id not in existing_targets + ] + + return filtered[:max_results] + + except Exception as e: + logger.warning(f"查找候选失败: {e}") + return [] + + async def _analyze_memory_relations( + self, + source_memory: Memory, + candidate_memories: List[Memory], + min_confidence: float = 0.7, + ) -> List[Dict[str, Any]]: + """ + 使用LLM分析记忆之间的关系 + + Args: + source_memory: 源记忆 + candidate_memories: 候选记忆列表 + min_confidence: 最低置信度 + + Returns: + 关系列表,每项包含: + - target_memory: 目标记忆 + - relation_type: 关系类型 + - confidence: 置信度 + - reasoning: 推理过程 + """ + try: + from src.llm_models.utils_model import LLMRequest + from src.config.config import model_config + + # 构建LLM请求 + llm = LLMRequest( + model_set=model_config.model_task_config.utils_small, + request_type="memory.relation_analysis" + ) + + # 格式化记忆信息 + source_desc = self._format_memory_for_llm(source_memory) + candidates_desc = "\n\n".join([ + f"记忆{i+1}:\n{self._format_memory_for_llm(mem)}" + for i, mem in enumerate(candidate_memories) + ]) + + # 构建提示词 + prompt = f"""你是一个记忆关系分析专家。请分析源记忆与候选记忆之间是否存在有意义的关系。 + +**关系类型说明:** +- 导致: A的发生导致了B的发生(因果关系) +- 引用: A提到或涉及B(引用关系) +- 相似: A和B描述相似的内容(相似关系) +- 相反: A和B表达相反的观点(对立关系) +- 关联: A和B存在某种关联但不属于以上类型(一般关联) + +**源记忆:** +{source_desc} + +**候选记忆:** +{candidates_desc} + +**任务要求:** +1. 对每个候选记忆,判断是否与源记忆存在关系 +2. 如果存在关系,指定关系类型和置信度(0.0-1.0) +3. 简要说明判断理由 +4. 只返回置信度 >= {min_confidence} 的关系 + +**输出格式(JSON):** +```json +[ + {{ + "candidate_id": 1, + "has_relation": true, + "relation_type": "导致", + "confidence": 0.85, + "reasoning": "记忆1是记忆源的结果" + }}, + {{ + "candidate_id": 2, + "has_relation": false, + "reasoning": "两者无明显关联" + }} +] +``` + +请分析并输出JSON结果:""" + + # 调用LLM + response, _ = await llm.generate_response_async( + prompt, + temperature=0.3, + max_tokens=1000, + ) + + # 解析响应 + import json + import re + + # 提取JSON + json_match = re.search(r'```json\s*(.*?)\s*```', response, re.DOTALL) + if json_match: + json_str = json_match.group(1) + else: + json_str = response.strip() + + try: + analysis_results = json.loads(json_str) + except json.JSONDecodeError: + logger.warning(f"LLM返回格式错误,尝试修复: {response[:200]}") + # 尝试简单修复 + json_str = re.sub(r'[\r\n\t]', '', json_str) + analysis_results = json.loads(json_str) + + # 转换为结果格式 + relations = [] + for result in analysis_results: + if not result.get("has_relation", False): + continue + + confidence = result.get("confidence", 0.0) + if confidence < min_confidence: + continue + + candidate_id = result.get("candidate_id", 0) - 1 + if 0 <= candidate_id < len(candidate_memories): + relations.append({ + "target_memory": candidate_memories[candidate_id], + "relation_type": result.get("relation_type", "关联"), + "confidence": confidence, + "reasoning": result.get("reasoning", ""), + }) + + logger.debug(f"LLM分析完成: 发现 {len(relations)} 个关系") + return relations + + except Exception as e: + logger.error(f"LLM关系分析失败: {e}", exc_info=True) + return [] + + def _format_memory_for_llm(self, memory: Memory) -> str: + """格式化记忆为LLM可读的文本""" + try: + # 获取关键节点 + subject_node = next( + (n for n in memory.nodes if n.node_type == NodeType.SUBJECT), + None + ) + topic_node = next( + (n for n in memory.nodes if n.node_type == NodeType.TOPIC), + None + ) + object_node = next( + (n for n in memory.nodes if n.node_type == NodeType.OBJECT), + None + ) + + parts = [] + parts.append(f"类型: {memory.memory_type.value}") + + if subject_node: + parts.append(f"主体: {subject_node.content}") + + if topic_node: + parts.append(f"主题: {topic_node.content}") + + if object_node: + parts.append(f"对象: {object_node.content}") + + parts.append(f"重要性: {memory.importance:.2f}") + parts.append(f"时间: {memory.created_at.strftime('%Y-%m-%d %H:%M')}") + + return " | ".join(parts) + + except Exception as e: + logger.warning(f"格式化记忆失败: {e}") + return f"记忆ID: {memory.id}" + async def maintenance(self) -> Dict[str, Any]: """ 执行维护任务 @@ -885,17 +1256,22 @@ class MemoryManager: ) result["consolidated"] = consolidate_result.get("merged_count", 0) - # 2. 自动遗忘 + # 2. 自动关联记忆(发现和建立关系) + if self.config.auto_link_enabled: + link_result = await self.auto_link_memories() + result["linked"] = link_result.get("linked_count", 0) + + # 3. 自动遗忘 if self.config.forgetting_enabled: forgotten_count = await self.auto_forget_memories( threshold=self.config.forgetting_activation_threshold ) result["forgotten"] = forgotten_count - # 3. 清理非常旧的已遗忘记忆(可选) + # 4. 清理非常旧的已遗忘记忆(可选) # TODO: 实现清理逻辑 - # 4. 保存数据 + # 5. 保存数据 await self.persistence.save_graph_store(self.graph_store) result["saved"] = True diff --git a/src/memory_graph/models.py b/src/memory_graph/models.py index 4bb834d4e..497ab4892 100644 --- a/src/memory_graph/models.py +++ b/src/memory_graph/models.py @@ -42,6 +42,7 @@ class EdgeType(Enum): ATTRIBUTE = "属性关系" # 任意节点 → 属性 CAUSALITY = "因果关系" # 记忆 → 记忆 REFERENCE = "引用关系" # 记忆 → 记忆(转述) + RELATION = "关联关系" # 记忆 → 记忆(自动关联发现的关系) class MemoryStatus(Enum): diff --git a/src/memory_graph/storage/graph_store.py b/src/memory_graph/storage/graph_store.py index a3699b373..69b49d089 100644 --- a/src/memory_graph/storage/graph_store.py +++ b/src/memory_graph/storage/graph_store.py @@ -387,9 +387,81 @@ class GraphStore: for node_id, mem_ids in data.get("node_to_memories", {}).items(): store.node_to_memories[node_id] = set(mem_ids) + # 5. 同步图中的边到 Memory.edges(保证内存对象和图一致) + try: + store._sync_memory_edges_from_graph() + except Exception: + logger.exception("同步图边到记忆.edges 失败") + logger.info(f"从字典加载图: {store.get_statistics()}") return store + def _sync_memory_edges_from_graph(self) -> None: + """ + 将 NetworkX 图中的边重建为 MemoryEdge 并注入到对应的 Memory.edges 列表中。 + + 目的:当从持久化数据加载时,确保 memory_index 中的 Memory 对象的 + edges 列表反映图中实际存在的边(避免只有图中存在而 memory.edges 为空的不同步情况)。 + + 规则:对于图中每条边(u, v, data),会尝试将该边注入到所有包含 u 或 v 的记忆中(避免遗漏跨记忆边)。 + 已存在的边(通过 edge.id 检查)将不会重复添加。 + """ + from src.memory_graph.models import MemoryEdge + + # 构建快速查重索引:memory_id -> set(edge_id) + existing_edges = {mid: {e.id for e in mem.edges} for mid, mem in self.memory_index.items()} + + for u, v, data in self.graph.edges(data=True): + # 兼容旧数据:edge_id 可能在 data 中,或叫 id + edge_id = data.get("edge_id") or data.get("id") or "" + + edge_dict = { + "id": edge_id or "", + "source_id": u, + "target_id": v, + "relation": data.get("relation", ""), + "edge_type": data.get("edge_type", data.get("edge_type", "")), + "importance": data.get("importance", 0.5), + "metadata": data.get("metadata", {}), + "created_at": data.get("created_at", "1970-01-01T00:00:00"), + } + + # 找到相关记忆(包含源或目标节点) + related_memory_ids = set() + if u in self.node_to_memories: + related_memory_ids.update(self.node_to_memories[u]) + if v in self.node_to_memories: + related_memory_ids.update(self.node_to_memories[v]) + + for mid in related_memory_ids: + mem = self.memory_index.get(mid) + if mem is None: + continue + + # 检查是否已存在 + if edge_dict["id"] and edge_dict["id"] in existing_edges.get(mid, set()): + continue + + try: + # 使用 MemoryEdge.from_dict 构建对象 + mem_edge = MemoryEdge.from_dict(edge_dict) + except Exception: + # 兼容性:直接构造对象 + mem_edge = MemoryEdge( + id=edge_dict["id"] or "", + source_id=edge_dict["source_id"], + target_id=edge_dict["target_id"], + relation=edge_dict["relation"], + edge_type=edge_dict["edge_type"], + importance=edge_dict.get("importance", 0.5), + metadata=edge_dict.get("metadata", {}), + ) + + mem.edges.append(mem_edge) + existing_edges.setdefault(mid, set()).add(mem_edge.id) + + logger.info("已将图中的边同步到 Memory.edges(保证 graph 与 memory 对象一致)") + def remove_memory(self, memory_id: str) -> bool: """ 从图中删除指定记忆 diff --git a/src/memory_graph/tools/memory_tools.py b/src/memory_graph/tools/memory_tools.py index f933eda9f..0152c62bd 100644 --- a/src/memory_graph/tools/memory_tools.py +++ b/src/memory_graph/tools/memory_tools.py @@ -73,38 +73,84 @@ class MemoryTools: """ return { "name": "create_memory", - "description": "创建一个新的记忆。记忆由主体、类型、主题、客体(可选)和属性组成。", + "description": """创建一个新的记忆节点。 + +⚠️ 记忆创建原则(必须遵守): +1. **价值判断**:只创建具有长期价值的关键信息,避免记录日常闲聊、礼貌用语、重复信息 +2. **细粒度原则**:每条记忆只包含一个明确的事实/事件/观点,避免泛化 +3. **原子性**:如果一句话包含多个重要信息点,拆分成多条独立记忆 +4. **具体性**:记录具体的人、事、物、时间、地点,避免模糊描述 + +❌ 不应创建记忆的情况: +- 普通问候、感谢、确认等礼貌性对话 +- 已存在的重复信息 +- 临时性、一次性的琐碎信息 +- 纯粹的功能操作指令(如"帮我查一下") +- 缺乏上下文的碎片化信息 + +✅ 应该创建记忆的情况: +- 用户的个人信息(姓名、职业、兴趣、联系方式等) +- 重要事件(项目进展、重大决定、关键行动等) +- 长期偏好/观点(喜好、价值观、习惯等) +- 人际关系变化(新朋友、合作关系等) +- 具体计划/目标(明确的待办事项、长期目标等) + +📝 拆分示例: +- ❌ "用户喜欢编程,最近在学Python和机器学习" → 过于泛化 +- ✅ 拆分为3条: + 1. "用户喜欢编程"(观点) + 2. "用户正在学习Python"(事件) + 3. "用户正在学习机器学习"(事件) + +记忆结构:主体 + 类型 + 主题 + 客体(可选)+ 属性""", "parameters": { "type": "object", "properties": { "subject": { "type": "string", - "description": "记忆的主体,通常是'我'、'用户'或具体的人名", + "description": "记忆的主体,通常是'用户'或具体的人名(避免使用'我')", }, "memory_type": { "type": "string", "enum": ["事件", "事实", "关系", "观点"], - "description": "记忆类型:事件(时间绑定的动作)、事实(稳定状态)、关系(人际关系)、观点(主观评价)", + "description": "记忆类型:\n- 事件:时间绑定的具体动作(如'完成项目'、'学习课程')\n- 事实:稳定的客观状态(如'职业是工程师'、'住在北京')\n- 关系:人际关系(如'认识了朋友'、'同事关系')\n- 观点:主观评价/偏好(如'喜欢Python'、'认为AI很重要')", }, "topic": { "type": "string", - "description": "记忆的主题,即发生的事情或状态", + "description": "记忆的核心主题,必须具体且明确(如'学习PyTorch框架'而非'学习编程')", }, "object": { "type": "string", - "description": "记忆的客体,即主题作用的对象(可选)", + "description": "记忆的客体/对象,作为主题的补充说明(如主题是'学习',客体可以是'PyTorch框架')", }, "attributes": { "type": "object", - "description": "记忆的属性,如时间、地点、原因、方式等", + "description": "记忆的具体属性(尽量填写以增加记忆的信息密度)", "properties": { "时间": { "type": "string", - "description": "时间表达式,如'今天'、'昨天'、'3天前'、'2025-11-05'", + "description": "具体时间表达式,如'2025-11-05'、'今天下午'、'最近一周'、'3天前'", + }, + "地点": { + "type": "string", + "description": "具体地点(如果相关)" + }, + "原因": { + "type": "string", + "description": "事件发生的原因或动机(如果明确)" + }, + "方式": { + "type": "string", + "description": "完成的方式或途径(如果相关)" + }, + "结果": { + "type": "string", + "description": "事件的结果或影响(如果已知)" + }, + "状态": { + "type": "string", + "description": "当前状态(如'进行中'、'已完成'、'计划中')" }, - "地点": {"type": "string", "description": "地点"}, - "原因": {"type": "string", "description": "原因"}, - "方式": {"type": "string", "description": "方式"}, }, "additionalProperties": True, }, @@ -112,7 +158,7 @@ class MemoryTools: "type": "number", "minimum": 0.0, "maximum": 1.0, - "description": "记忆的重要性,0-1之间的浮点数,默认0.5", + "description": "记忆的重要性评分(0.0-1.0):\n- 0.3-0.4: 次要信息\n- 0.5-0.6: 一般信息\n- 0.7-0.8: 重要信息(用户明确表达的偏好、重要事件)\n- 0.9-1.0: 关键信息(核心个人信息、重大决定、强烈偏好)\n默认0.5", }, }, "required": ["subject", "memory_type", "topic"], @@ -129,27 +175,42 @@ class MemoryTools: """ return { "name": "link_memories", - "description": "关联两个已存在的记忆,建立因果或引用关系。", + "description": """手动关联两个已存在的记忆。 + +⚠️ 使用建议: +- 系统会自动发现记忆间的关联关系,通常不需要手动调用此工具 +- 仅在以下情况使用: + 1. 用户明确指出两个记忆之间的关系 + 2. 发现明显的因果关系但系统未自动关联 + 3. 需要建立特殊的引用关系 + +关系类型说明: +- 导致:A事件/行为导致B事件/结果(因果关系) +- 引用:A记忆引用/基于B记忆(知识关联) +- 相似:A和B描述相似的内容(主题相似) +- 相反:A和B表达相反的观点(对比关系) +- 关联:A和B存在一般性关联(其他关系)""", "parameters": { "type": "object", "properties": { "source_memory_description": { "type": "string", - "description": "源记忆的描述,用于查找对应的记忆", + "description": "源记忆的关键描述(用于搜索定位,需要足够具体)", }, "target_memory_description": { "type": "string", - "description": "目标记忆的描述,用于查找对应的记忆", + "description": "目标记忆的关键描述(用于搜索定位,需要足够具体)", }, "relation_type": { "type": "string", - "description": "关系类型,如'导致'、'引起'、'因为'、'所以'、'引用'、'基于'等", + "enum": ["导致", "引用", "相似", "相反", "关联"], + "description": "关系类型(从上述5种类型中选择最合适的)", }, "importance": { "type": "number", "minimum": 0.0, "maximum": 1.0, - "description": "关系的重要性,0-1之间的浮点数,默认0.6", + "description": "关系的重要性(0.0-1.0):\n- 0.5-0.6: 一般关联\n- 0.7-0.8: 重要关联\n- 0.9-1.0: 关键关联\n默认0.6", }, }, "required": [ @@ -170,13 +231,25 @@ class MemoryTools: """ return { "name": "search_memories", - "description": "搜索相关的记忆。支持语义搜索、图遍历和时间过滤。", + "description": """搜索相关的记忆,用于回忆和查找历史信息。 + +使用场景: +- 用户询问之前的对话内容 +- 需要回忆用户的个人信息、偏好、经历 +- 查找相关的历史事件或观点 +- 基于上下文补充信息 + +搜索特性: +- 语义搜索:基于内容相似度匹配 +- 图遍历:自动扩展相关联的记忆 +- 时间过滤:按时间范围筛选 +- 类型过滤:按记忆类型筛选""", "parameters": { "type": "object", "properties": { "query": { "type": "string", - "description": "搜索查询,描述要查找的记忆内容", + "description": "搜索查询(用自然语言描述要查找的内容,如'用户的职业'、'最近的项目'、'Python相关的记忆')", }, "memory_types": { "type": "array", @@ -184,33 +257,33 @@ class MemoryTools: "type": "string", "enum": ["事件", "事实", "关系", "观点"], }, - "description": "要搜索的记忆类型,可多选", + "description": "记忆类型过滤(可选,留空表示搜索所有类型)", }, "time_range": { "type": "object", "properties": { "start": { "type": "string", - "description": "开始时间,如'3天前'、'2025-11-01'", + "description": "开始时间(如'3天前'、'上周'、'2025-11-01')", }, "end": { "type": "string", - "description": "结束时间,如'今天'、'2025-11-05'", + "description": "结束时间(如'今天'、'现在'、'2025-11-05')", }, }, - "description": "时间范围过滤(可选)", + "description": "时间范围(可选,用于查找特定时间段的记忆)", }, "top_k": { "type": "integer", "minimum": 1, "maximum": 50, - "description": "返回结果数量,默认10", + "description": "返回结果数量(1-50,默认10)。根据需求调整:\n- 快速查找:3-5条\n- 一般搜索:10条\n- 全面了解:20-30条", }, "expand_depth": { "type": "integer", "minimum": 0, "maximum": 3, - "description": "图遍历扩展深度,0表示不扩展,默认1", + "description": "图扩展深度(0-3,默认1):\n- 0: 仅返回直接匹配的记忆\n- 1: 包含一度相关的记忆(推荐)\n- 2-3: 包含更多间接相关的记忆(用于深度探索)", }, }, "required": ["query"],