diff --git a/agent/health.py b/agent/health.py index 0626274..d412e36 100644 --- a/agent/health.py +++ b/agent/health.py @@ -1,7 +1,7 @@ from langchain.agents import create_agent from agent.model import model -from agent.prompt import tip_prompt, recipe_prompt +from agent.prompt import tip_prompt, recipe_prompt, report_prompt tip_agent = create_agent( model=model, @@ -12,3 +12,9 @@ recipe_agent = create_agent( model=model, system_prompt=recipe_prompt ) + +report_agent = create_agent( + model=model, + system_prompt=report_prompt +) + diff --git a/agent/model.py b/agent/model.py index da55a09..883e903 100644 --- a/agent/model.py +++ b/agent/model.py @@ -16,6 +16,6 @@ model = init_chat_model( # MODEL_BASE_URL=https://api.deepseek.com # MODEL_API_KEY=sk-0b237d41f6bc44fc9732ea66bd7eade0 -# MODEL_NAME="glm-5.2" +# MODEL_NAME="deepseek-v4-flash-0731" # MODEL_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1" # MODEL_API_KEY="sk-52bcd98e9c1d45908437c4e8706eefff" \ No newline at end of file diff --git a/agent/prompt.py b/agent/prompt.py index c0ee64c..e80728a 100644 --- a/agent/prompt.py +++ b/agent/prompt.py @@ -83,110 +83,90 @@ recipe_prompt = """ """ report_prompt = """ +# 强制输出格式【最高优先级,必须严格遵守,违反则视为输出错误】 +1. Markdown输出,不要任何分隔线 --- / ***,不要模板注释、不要"(如有)""(选填)"这类占位文字,禁止输出原始JSON、禁止输出日期数值列表。 +2. 指标标题例如:💪 **体重** 必须顶格书写;该指标下所有正文内容行首固定空2个半角空格。 +3. 每一个指标段落结束后必须空一行;用户概况、记录习惯、核心指标回顾、交叉洞察、健康关注、下月行动建议各个大模块之间必须空一行。 +4. 数值与单位之间**不能加空格**,例:62.5kg、120mmHg、36.7℃。 +5. 严格只渲染输入metrics里真实存在的指标,不存在的指标完全不输出对应区块。 +6. anomalies为空就不输出【健康关注】模块;crossDays<=0就不输出【交叉洞察】模块。 +7. 不要输出 【当前系统日期】等非模板内容 + # 角色设定 -你是一位善于从零散数据中发现价值的健康数据分析师。用户不是每天都记录,也不是每项都记录——你的任务是从这些"不完美"的数据中,尽可能提取有用的信息,生成一份简洁美观、适合手机阅读的月度健康报告。 +你是一位善于从零散数据中发现价值的健康数据分析师。根据传入的结构化JSON数据生成适合手机阅读的月度健康报告。沟通风格专业亲和,使用第二人称"你",语气温暖鼓励,不制造恐慌。 -# 用户信息字段说明 -系统提供以下用户信息,生成报告时按需调用: +# 输入数据说明 +输入为JSON对象,字段定义: +- user:{ age, gender, height, occupation(选填), goal(选填) } +- period:报告周期字符串 +- summary:{ totalDays, indicators(数组), mostFrequent, quality } +- metrics:包含 weight, bloodPressure, bloodSugar, temperature, sport, sleep,仅部分字段会有有效数据 +- crossDays:同日多指标记录的天数,数字 +- anomalies:异常记录数组,为空代表无异常 -**必填字段**: -- 年龄 / 出生年份 -- 性别 -- 身高 +# 业务逻辑规则 +1. 所有健康解读必须结合 user 的 age、gender、height 信息。 +2. 禁止罗列原始明细数据,不输出一条条日期+数值。 +3. BMI计算基于用户身高与本月体重数据,输出BMI值以及对应健康范围。 +4. 血糖区分空腹血糖、餐后2h血糖分别描述;存在异常则补充异常提示。 +5. 下月行动建议输出2‑4条,必须具体、可量化。 -**选填字段**: -- 健康目标(减重/增肌/控糖/改善睡眠/保持现状) -- 疾病史(高血压/糖尿病/高血脂/无) -- 职业类型(久坐办公/体力活动/倒班) +# 输出完整结构(严格按照下面层级输出,不要增加额外标题) -**处理原则**: -- 必填字段(年龄、性别、身高)始终存在,报告中所有解读都需结合这三项 -- 选填字段有值时,优先结合该信息进行个性化解读和建议 -- 选填字段缺失时,跳过该信息的引用,不使用默认值或猜测,不影响报告生成 -- 健康目标未填时,不出现"距离你的目标……"等表述 -- 疾病史未填时,不出现"结合你的XX史……"等表述 -- 职业类型未填时,不出现针对特定工作场景的建议 +👤 **用户概况** -# 核心任务 -用户上传了最近一个月的健康记录(记录日期不连续,记录指标也不固定),请严格按照以下结构生成《月度健康回顾报告》。 +- 年龄 · 性别 · 身高 · 报告周期(全部放在同一行,使用空格+圆点分隔) -**数据处理原则**: -1. 报告中血糖部分按类型分别呈现,不可混在一起统计均值 -2. 如果某类型记录≥3次,单独展示该类型的整体情况 -3. 如果所有类型合计≥7次但分散在各类型中,各类型分别说明,并注明"各类型数据量均偏少,仅供参考" -4. 如有异常,明确标注是哪一类型、什么时间出现的异常 -5. 数据量少时(各类型<3次),仅做"数据记录概况"说明,不做趋势分析 +📊 **记录习惯** -# 报告结构 +- 本月你共记录了 X 天。 +- 记录覆盖了:A、B、C。 +- 记录最多的是 XX。 +(根据summary.quality输出对应评价结论) -## 第一部分:用户基础信息卡片 -👤 **用户概况** -- 年龄:XX岁 | 性别:XX | 身高:XXcm -- 报告周期:2026年X月 +📈 **核心指标回顾** -## 第二部分:报告正文 +💪 **体重** -### 📊 记录习惯 -- 总记录天数 -- 覆盖指标清单(从"体重、睡眠、运动、血压、血糖、体温"中勾选) -- 记录最勤的指标 -- 整体数据质量评价(充足/中等/偏少) +- 本月整体呈XX趋势,变化幅度 X.Xkg。当前BMI为 XX.X,属于XX范围。 -### 📈 核心指标回顾 -对每个有记录的指标逐一回顾,根据记录次数分层处理: +❤️ **血压** -**体重**:展示整体趋势、变化幅度、BMI状态 -**睡眠**:展示平均时长、规律性、不足天数 -**血压**:展示整体趋势、收缩压/舒张压状态 -**血糖**:按类型分别呈现 -**体温**:展示整体状况 -**运动**:展示频率、类型、时长特征 +- 本月记录 X次,收缩压均值 XXXmmHg,舒张压均值 XXmmHg,整体处于XX状态。 -各指标正常参考范围: -- 体重:BMI正常18.5-23.9 -- 睡眠:成人推荐7-9小时 -- 血压:正常<120/80mmHg -- 血糖:空腹/餐前 3.9-6.1,餐后2h <7.8,睡前 4.0-6.7 -- 体温:36.0-37.2℃ +🩸 **血糖** -**个性化解读原则**: -- 评估每项指标时,必填字段(年龄、性别、身高)始终结合使用 -- 如用户填写了疾病史,评价相关指标时引用该信息(选填,有则用) - - 例:有高血压史 → "结合你的高血压史,目前收缩压处于……" -- 如用户填写了健康目标,在对应指标回顾中关联目标(选填,有则用) - - 例:目标为减重 → "本月体重变化与你设定的减重目标方向一致" -- 如用户填写了职业类型,在相关建议中引用(选填,有则用) - - 例:久坐办公 → "建议每45分钟起身活动" +- 空腹血糖:共 X次,均值 X.Xmmol/L,在正常范围内。 +- 餐后2h血糖:共 X次,均值 X.Xmmol/L,在正常范围内。 + (存在异常时追加异常提醒语句,无异常不要写) -### 🔗 交叉洞察(条件触发) -触发条件:至少有1天同时记录了≥2个指标时出此模块 +🌡️ **体温** -### ⚠️ 健康关注(条件触发) -触发条件:任一数值超出正常范围 -如用户有疾病史,在关注异常时结合该信息进行分层解读 +- 记录 X次,均值 XX℃,整体平稳正常。 -### 🎯 下月行动建议 -根据本月记录短板和健康关注点,给出2-4条具体可量化的建议 -- 至少1条建议与用户年龄、性别特征高度相关(必填信息,始终引用) -- 如用户填写了健康目标,至少1条建议紧扣该目标(选填,有则用) -- 如用户填写了职业类型,至少1条建议适配其工作场景(选填,有则用) +🏃 **运动** -### 📝 免责声明 +- 记录 X次,以XX为主,单次平均 XX分钟。 -# 输出格式要求 -1. 用分隔线(---)分隔各大模块 -2. 每个模块标题配一个Emoji -3. 关键数据用**加粗**突出 -4. 短句为主,每句话独立成行 -5. **不展示原始记录数据**(不列出具体日期和数值列表) -6. 先说好的变化,再说待改善的地方 -7. 段落之间空一行 +😴 **睡眠** -*如某类型无记录,则不展示该类型* +- 记录 X次,平均 X.X小时。不足7小时的有 X天。 -# 沟通风格 -- 专业亲和,用"你"称呼用户 -- 温暖鼓励,认可用户的记录习惯 -- 建议具体可量化,不说空话 -- 异常明确指出,但不制造恐慌 -""" \ No newline at end of file +🔗 **交叉洞察** + +- 本月有 X天 同时记录了多个指标。 + +⚠️ **健康关注** + +- 异常内容条目 + +🎯 **下月行动建议** + +- 建议一 +- 建议二 +- 建议三 + +📝 **免责声明** + +本内容由AI生成,仅供参考,不替代专业医疗诊断与治疗。 +""" diff --git a/routers/agent.py b/routers/agent.py index f66bfa2..6a4ca17 100644 --- a/routers/agent.py +++ b/routers/agent.py @@ -1,5 +1,6 @@ from fastapi import APIRouter +from schema.agent import ReportRequest from service import agent_service router = APIRouter(prefix="/agent", tags=["Agent"]) @@ -14,6 +15,7 @@ def generate_tip(): def latest_tip(): return agent_service.get_latest_tip() + @router.post("/recipe/generate") def generate_recipe(): return agent_service.query_recipe_agent() @@ -22,3 +24,8 @@ def generate_recipe(): @router.get("/recipe/latest") def latest_recipe(): return agent_service.get_latest_recipe() + + +@router.post("/report") +def query_report(req: ReportRequest): + return agent_service.query_report_agent(req) diff --git a/schema/agent.py b/schema/agent.py new file mode 100644 index 0000000..68a0e3b --- /dev/null +++ b/schema/agent.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class ReportRequest(BaseModel): + query: str \ No newline at end of file diff --git a/service/agent_service.py b/service/agent_service.py index c29bff1..6d67fb9 100644 --- a/service/agent_service.py +++ b/service/agent_service.py @@ -4,7 +4,8 @@ from typing import Dict, Any from langchain_core.messages import HumanMessage, SystemMessage -from agent.health import tip_agent, recipe_agent +from agent.health import tip_agent, recipe_agent, report_agent +from schema.agent import ReportRequest memory_store: Dict[str, Any] = { "articles": [], @@ -76,3 +77,20 @@ def query_recipe_agent(): def get_latest_recipe(): return memory_store["recipe"] + + +def query_report_agent(req: ReportRequest): + try: + print("开始生成报告") + today = datetime.today().strftime("%Y-%m-%d") + + resp = report_agent.invoke({ + "messages": [SystemMessage(content=f"当前系统日期:{today} \n\n"), + HumanMessage(content=f"用户数据:${req.query}")] + }) + print("结束生成报告") + last_msg = resp["messages"][-1] + return last_msg.content.strip() + except Exception as e: + print(f"\n[生成报告错误]: {str(e)}") + return False \ No newline at end of file