| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- from typing import TypedDict, Optional
- from langgraph.graph import StateGraph, START, END
- from langgraph.checkpoint.memory import MemorySaver
- from langchain_openai import ChatOpenAI
- from langchain_core.messages import SystemMessage, HumanMessage
- from app.tools.report_tools import get_report_detail, get_survey_data, get_dimension_scores
- from app.config import settings
- from app.prompt_service import get_prompt
- import logging
- logger = logging.getLogger(__name__)
- class AnalysisState(TypedDict):
- report_id: int
- user_id: int
- focus: Optional[str] # nutrition / gut / chronic / overall
- report_data: Optional[dict]
- survey_data: Optional[dict]
- dimension_scores: Optional[dict]
- analysis: Optional[str]
- recommendations: list[str]
- ANALYSIS_SYSTEM_PROMPT = """你是一个儿童健康报告解读专家。根据健康报告数据和调研问卷, 提供专业、易懂的分析。
- 分析原则:
- 1. 用通俗语言解释各项指标含义
- 2. 关注异常指标, 给出改善建议
- 3. 结合问卷数据提供个性化分析
- 4. 五维能量(身/心/智/行/富)角度解读整体状况
- 5. 输出格式: 总体评估 → 分项分析 → 改善建议
- """
- def create_analysis_graph():
- """创建报告解读 StateGraph"""
- llm = ChatOpenAI(
- model=settings.llm_model,
- api_key=settings.llm_api_key,
- base_url=settings.llm_base_url,
- temperature=settings.llm_temperature,
- )
- llm_with_tools = llm.bind_tools([
- get_report_detail,
- get_survey_data,
- get_dimension_scores,
- ])
- builder = StateGraph(AnalysisState)
- async def gather_data(state: AnalysisState) -> dict:
- """收集报告 + 问卷 + 维度数据"""
- result = {}
- if state.get("report_id"):
- try:
- detail = await get_report_detail.ainvoke({"report_id": state["report_id"]})
- result["report_data"] = detail
- except Exception as e:
- logger.warning("获取报告详情失败: %s", e)
- try:
- survey = await get_survey_data.ainvoke({"report_id": state["report_id"]})
- result["survey_data"] = survey
- except Exception as e:
- logger.warning("获取问卷数据失败: %s", e)
- return result
- async def analyze(state: AnalysisState) -> dict:
- """LLM 分析"""
- context_parts = []
- if state.get("report_data"):
- context_parts.append(f"报告数据: {state['report_data']}")
- if state.get("survey_data"):
- context_parts.append(f"问卷数据: {state['survey_data']}")
- if state.get("focus"):
- context_parts.append(f"重点关注: {state['focus']}")
- context_text = "\n".join(context_parts) if context_parts else "暂无数据"
- messages = [
- SystemMessage(content=await get_prompt("analysis") or ANALYSIS_SYSTEM_PROMPT),
- SystemMessage(content=f"待分析数据:\n{context_text}"),
- HumanMessage(content="请分析以上健康数据, 给出评估和建议。"),
- ]
- response = await llm_with_tools.ainvoke(messages)
- return {"analysis": response.content}
- builder.add_node("gather_data", gather_data)
- builder.add_node("analyze", analyze)
- builder.add_edge(START, "gather_data")
- builder.add_edge("gather_data", "analyze")
- builder.add_edge("analyze", END)
- checkpointer = MemorySaver()
- return builder.compile(checkpointer=checkpointer)
|