Files
memory-system/lifecycle/aggregator.py
T
zqf b1f93588f1 初始化:记忆系统源代码上传(已脱敏)
- 排除 .env / *.bak / 内部运维文档(README_INTERNAL.html)
- config.py 默认密码已替换为占位符 CHANGE_ME_*
- init_db.sql 移除生产数据库用户 GRANT 段
- README.html 数据库用户名已脱敏
- 保留:源码 + 公网 API 文档 + 建表 SQL(无授权语句)
2026-08-03 04:53:48 +08:00

93 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Scenario Aggregator - Group related memories into scenario blocks."""
import json
import logging
from typing import Optional, List
from lifecycle.llm_parse import parse_llm_json_array
logger = logging.getLogger(__name__)
SCENE_SYSTEM_PROMPT = """你是JSON生成器。直接输出JSON数组,禁止分析、思考、解释、讨论、markdown。
任务:将记忆按主题聚合成场景块。
规则:
1. 将相关记忆归入同一场景
2. 每个场景:name(名称)、summary100字以内摘要)、memory_idsID列表)
3. 最多10个场景
4. 第一个字符必须是[,最后一个字符必须是]
输出格式:
[{"name":"场景名","summary":"摘要","memory_ids":["id1","id2"]}]
只输出JSON,不要有任何其他文字。"""
class ScenarioAggregator:
"""Aggregate personal memories into scenario blocks."""
def __init__(self, mysql_store, llm_client):
self.mysql = mysql_store
self.llm = llm_client
def aggregate(self, agent_id: str, team_id: str,
max_memories: int = 50) -> dict:
"""Aggregate memories into scenarios using LLM."""
if not self.llm.available:
return {"error": "LLM not configured. Set LLM_API_URL, LLM_API_KEY, LLM_MODEL environment variables."}
memories = self.mysql.get_personal_memories_by_agent(agent_id, limit=max_memories)
if not memories:
return {"scenarios": [], "count": 0}
memory_lines = []
for m in memories:
mid = m["id"]
content = m.get("content", "")[:100]
memory_lines.append(f"[{mid}] {content}")
user_prompt = "请将以下记忆聚合为JSON场景数组:\n\n" + "\n".join(memory_lines)
try:
scenarios = parse_llm_json_array(
self.llm, SCENE_SYSTEM_PROMPT, user_prompt,
temperature=0.3, context="aggregate-scenes",
max_tokens=2000,
)
except ValueError as e:
return {"error": str(e)}
stored = []
for scene in scenarios:
if not isinstance(scene, dict):
logger.warning("Skipping non-dict item in scenarios: %r", scene)
continue
name = scene.get("name", "unnamed")
summary = scene.get("summary", "")
memory_ids = scene.get("memory_ids", [])
valid_ids = [mid for mid in memory_ids if isinstance(mid, str) and len(mid) > 0]
scene_id = self.mysql.add_scenario(
team_id=team_id,
agent_id=agent_id,
name=name,
summary=summary,
memory_ids=valid_ids,
)
stored.append({
"id": scene_id,
"name": name,
"summary": summary,
"memory_ids": valid_ids,
})
return {"scenarios": stored, "count": len(stored)}
def get_scenarios(self, agent_id: str) -> List[dict]:
return self.mysql.get_scenarios_by_agent(agent_id)
def delete_scenario(self, scenario_id: str, team_id: str) -> bool:
scenario = self.mysql.get_scenario(scenario_id)
if not scenario or scenario["team_id"] != team_id:
return False
return self.mysql.delete_scenario(scenario_id)