innate_portrait_graph.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. from langchain_openai import ChatOpenAI
  2. from langchain_core.messages import SystemMessage, HumanMessage
  3. from app.config import settings
  4. from app.monitoring import monitor_agent
  5. import logging
  6. logger = logging.getLogger(__name__)
  7. SYSTEM_PROMPT = """你是一位融合中国传统文化与现代心理学的家庭成长解读师。
  8. 请根据用户的先天画像数据,生成一段温情、专业、可执行的成长解读文案。
  9. 要求:
  10. 1. 用第二人称"你"称呼
  11. 2. 先认可先天特质优势,再给出1-2条心维度成长建议
  12. 3. 语气温暖克制,避免玄学恐吓或过度承诺
  13. 4. 800字以内,用中文,分2-3段
  14. 5. 以"心能量小贴士"收尾,给一个当天就能做的行动
  15. """
  16. class InnatePortraitAgent:
  17. def __init__(self):
  18. self.llm = ChatOpenAI(
  19. model=settings.llm_model,
  20. api_key=settings.llm_api_key,
  21. base_url=settings.llm_base_url,
  22. temperature=settings.llm_temperature,
  23. )
  24. @monitor_agent("innate_portrait")
  25. async def run(self, portrait: dict) -> dict:
  26. """生成先天画像解读,失败返回空 reading(调用方降级模板)"""
  27. try:
  28. source_summary = self._summarize(portrait)
  29. messages = [
  30. SystemMessage(content=SYSTEM_PROMPT),
  31. HumanMessage(content=f"先天画像数据:\n{source_summary}"),
  32. ]
  33. response = await self.llm.ainvoke(messages)
  34. return {"reading": response.content.strip()}
  35. except Exception as e:
  36. logger.warning("先天画像解读生成失败: %s", e)
  37. return {"reading": ""}
  38. @staticmethod
  39. def _summarize(portrait: dict) -> str:
  40. parts = []
  41. if portrait.get("zodiac"):
  42. parts.append(f"生肖: {portrait['zodiac']}")
  43. if portrait.get("bloodType"):
  44. parts.append(f"血型: {portrait['bloodType']}")
  45. if portrait.get("wuxingElements"):
  46. parts.append(f"五行: {portrait['wuxingElements']}")
  47. if portrait.get("mindBaseScore") is not None:
  48. parts.append(f"心先天基础分: {portrait['mindBaseScore']}")
  49. if portrait.get("wisdomBaseScore") is not None:
  50. parts.append(f"智先天基础分: {portrait['wisdomBaseScore']}")
  51. if portrait.get("eightCharacters"):
  52. parts.append(f"八字四柱: {portrait['eightCharacters']}")
  53. ns = portrait.get("numSoul") or {}
  54. if ns.get("lifePath") is not None:
  55. parts.append(
  56. f"生命灵数: {ns['lifePath']}"
  57. + (f"({ns['lifePathTitle']})" if ns.get("lifePathTitle") else "")
  58. )
  59. return "\n".join(parts) if parts else "暂无画像数据"