初始化:记忆系统源代码上传(已脱敏)
- 排除 .env / *.bak / 内部运维文档(README_INTERNAL.html) - config.py 默认密码已替换为占位符 CHANGE_ME_* - init_db.sql 移除生产数据库用户 GRANT 段 - README.html 数据库用户名已脱敏 - 保留:源码 + 公网 API 文档 + 建表 SQL(无授权语句)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""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(名称)、summary(100字以内摘要)、memory_ids(ID列表)
|
||||
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)
|
||||
Reference in New Issue
Block a user