feat(memory): 添加自动关联功能及相关配置支持
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ class EdgeType(Enum):
|
||||
ATTRIBUTE = "属性关系" # 任意节点 → 属性
|
||||
CAUSALITY = "因果关系" # 记忆 → 记忆
|
||||
REFERENCE = "引用关系" # 记忆 → 记忆(转述)
|
||||
RELATION = "关联关系" # 记忆 → 记忆(自动关联发现的关系)
|
||||
|
||||
|
||||
class MemoryStatus(Enum):
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
从图中删除指定记忆
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user