"""Persona Generator - Generate user persona from scenarios and memories.""" import json import logging from typing import Optional from lifecycle.llm_parse import parse_llm_json_object logger = logging.getLogger(__name__) PERSONA_SYSTEM_PROMPT = """你是JSON生成器。直接输出JSON对象,禁止分析、思考、解释、markdown。 根据记忆和场景生成用户画像。 输出格式(第一个字符必须是{,最后一个字符必须是}): {"preferences":["偏好1"],"habits":["习惯1"],"expertise":["擅长1"],"communication_style":"风格","summary":"100字以内摘要"} 只输出JSON,不要有任何其他文字。""" class PersonaGenerator: """Generate user persona from memories and scenarios.""" def __init__(self, mysql_store, llm_client): self.mysql = mysql_store self.llm = llm_client def generate(self, agent_id: str, team_id: str, max_items: int = 30) -> dict: 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_items) scenarios = self.mysql.get_scenarios_by_agent(agent_id) if not memories and not scenarios: return {"error": "No memories or scenarios found for this agent"} context_parts = [] if memories: mem_lines = [f"- {m.get('content', '')[:100]}" for m in memories] context_parts.append("历史记忆:\n" + "\n".join(mem_lines)) if scenarios: scene_lines = [f"- [{s.get('name', '')}] {s.get('summary', '')}" for s in scenarios] context_parts.append("已识别场景:\n" + "\n".join(scene_lines)) user_prompt = "请根据以下内容生成用户画像JSON:\n\n" + "\n\n".join(context_parts) try: persona = parse_llm_json_object( self.llm, PERSONA_SYSTEM_PROMPT, user_prompt, temperature=0.3, context="generate-persona", max_tokens=2000, ) except ValueError as e: return {"error": str(e)} if not isinstance(persona, dict): logger.warning("LLM returned non-dict persona: %r", persona) return {"error": "LLM returned invalid persona format"} pid = self.mysql.add_persona( team_id=team_id, agent_id=agent_id, preferences=persona.get("preferences", []), habits=persona.get("habits", []), expertise=persona.get("expertise", []), communication_style=persona.get("communication_style", ""), summary=persona.get("summary", ""), ) persona["id"] = pid return {"persona": persona} def get_persona(self, agent_id: str): return self.mysql.get_persona_by_agent(agent_id) def delete_persona(self, persona_id: str, team_id: str) -> bool: persona = self.mysql.get_persona(persona_id) if not persona or persona["team_id"] != team_id: return False return self.mysql.delete_persona(persona_id)