# 用户使用流程图 — AI助手 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动 > > **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体 ```mermaid flowchart TD %% ============ 颜色定义 ============ classDef page fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef api fill:#fff3e0,stroke:#f57c00,stroke-width:1px classDef service fill:#e8f5e9,stroke:#388e3c,stroke-width:1px classDef data fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px classDef external fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:3 2 classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3 %% ============ 角色 ============ ROLE_USER(("👤 用户(家长/孩子)")):::actor ROLE_DIFY(("🤖 Dify AI引擎")):::external ROLE_LG(("🐍 LangGraph Python")):::external %% ================================================================ %% 阶段一:AI对话 %% ================================================================ subgraph 阶段一[阶段一:AI对话] direction TB P1["🏠 小程序:AI聊天页"]:::page P1 -->|"输入消息"| P1a["🏠 消息输入框"]:::page P1a -->|"query, conversationId, reportId, surveyId"| A1["🔗 POST /api/ai/chat/send"]:::api A1 -->|"userId, query, conversationId, inputs"| S1{"⚙️ AIService.sendMessage()
优先LangGraph → 回退Dify"}:::service S1 -->|"query, userId, conversationId"| LG1["⚙️ AiGateway.chat()
Python推荐服务"]:::service LG1 -->|"超时/熔断回退"| DIFY1["⚙️ Dify Chatbot API
/chat-messages"]:::service DIFY1 -->|"answer, conversation_id"| LG1 S1 -->|"解析[TASK]标记"| S1a["⚙️ TaskParseService.parseTasks()"]:::service S1a -->|"任务标题, 维度, 奖励"| S1b["⚙️ GrowthTaskService.createDynamicTask()"]:::service S1b -->|"写入动态成长任务"| D_TASKS["📦 growth_tasks 表"]:::data S1 -->|"镜像会话到本地"| S1c["⚙️ ChatMirrorService.upsertConversation()"]:::service S1c -->|"userId, difyConversationId, 消息"| D_CHAT["📦 chat_conversations + chat_messages"]:::data S1 -->|"构建家庭上下文输入"| S2["⚙️ FamilyContextService.buildContext()"]:::service S2 -->|"用户信息, 孩子列表, 健康报告, 任务统计"| D_CTX["📦 User, ChildInfoDTO, HealthReport
(内存组装)"]:::data S1 -->|"注入AI记忆层"| S2a["⚙️ AIService.enrichInputsWithMemory()"]:::service S2a -->|"最近3条会话摘要"| D_SUM["📦 ai_conversation_summaries 表"]:::data S2a -->|"关键事实列表"| D_FACT["📦 ai_user_facts 表"]:::data A1 -->|"answer, conversationId, tasks[]"| P1b["🏠 显示AI回答 + 推荐任务卡片"]:::page end %% ================================================================ %% 阶段二:会话管理 %% ================================================================ subgraph 阶段二[阶段二:会话管理] P1b -->|"查看历史"| P2["🏠 会话列表页"]:::page P2 -->|"userId"| A2["🔗 POST /api/ai/chat/conversations"]:::api A2 -->|"调用Dify GET /conversations"| S3["⚙️ AIService.getConversations()"]:::service S3 -->|"Dify失败回退本地"| S3a["⚙️ ChatMirrorService.getConversations()"]:::service S3a -->|"本地镜像会话"| D_CHAT P2 -->|"选择会话"| P2a["🏠 消息历史页"]:::page P2a -->|"conversationId"| A3["🔗 POST /api/ai/chat/messages"]:::api A3 -->|"调用Dify GET /messages"| S4["⚙️ AIService.getMessages()"]:::service S4 -->|"Dify失败回退本地"| S4a["⚙️ ChatMirrorService.getMessages()"]:::service S4a -->|"本地消息记录"| D_CHAT P2a -->|"删除会话"| A4["🔗 POST /api/ai/chat/conversations/{id}/delete"]:::api A4 -->|"调用Dify DELETE /conversations/{id}"| S5["⚙️ AIService.deleteConversation()"]:::service end %% ================================================================ %% 阶段三:精准营养分析 %% ================================================================ subgraph 阶段三[阶段三:精准营养分析] P1b -->|"报告ID参数"| P3["🏠 营养分析对话页"]:::page P3 -->|"query, conversationId, reportId"| A5["🔗 POST /api/ai/nutrition/send"]:::api A5 -->|"reportId"| S6["⚙️ HealthAnalysisService.analyze()"]:::service S6 -->|"菌群分析结果"| D_HR["📦 HealthReport 肠道报告数据"]:::data S6 -->|"分析结果 + 家庭上下文"| S7["⚙️ AIService.sendNutritionMessage()"]:::service S7 -->|"专用dify.nutrition-api-key"| DIFY2["⚙️ Dify精准营养助手
/chat-messages"]:::external A5 -->|"解析[RECOMMEND]标记"| S7a["⚙️ 解析推荐标签 tags/types/limit"]:::service S7a -->|"营养标签, 类型筛选"| S7b["⚙️ RecommendationService.search()"]:::service S7b -->|"Product/Activity/Article多表搜索"| D_PROD["📦 products, activities, articles 表"]:::data A5 -->|"解析[TASK]标记"| S7c["⚙️ TaskParseService + GrowthTaskService"]:::service S7c -->|"动态成长任务"| D_TASKS A5 -->|"answer, recommendations[], tasks[]"| P3a["🏠 显示营养建议 + 推荐内容"]:::page end %% ================================================================ %% 阶段四:智能推荐 %% ================================================================ subgraph 阶段四[阶段四:智能推荐] P3a -->|"搜索推荐"| P4["🏠 营养推荐搜索页"]:::page P4 -->|"nutritionTags, types, limit"| A6["🔗 POST /api/recommend/search"]:::api A6 -->|"5%灰度→LangGraph"| S8["⚙️ AiGateway.recommend()"]:::service S8 -->|"Python推荐服务"| LG2["🐍 LangGraph推荐API"]:::external A6 -->|"本地搜索"| S9["⚙️ RecommendationService.search()"]:::service S9 -->|"按标签模糊搜索上架商品"| D_PROD S9 -->|"按标签搜索进行中活动"| D_ACT["📦 activities 表"]:::data S9 -->|"按标签搜索已发布文章"| D_ART["📦 articles 表"]:::data P4 -->|"复购提醒"| P4a["🏠 复购提醒列表"]:::page P4a -->|"userId"| A7["🔗 POST /api/recommend/repurchase-reminders"]:::api A7 -->|"userId"| S10["⚙️ RecommendationService.getRepurchaseReminders()"]:::service S10 -->|"未购买提醒记录"| D_REP["📦 repurchase_reminder_record 表"]:::data P4a -->|"点击提醒"| A8["🔗 POST /api/recommend/repurchase-reminder/{id}/click"]:::api A8 -->|"reminderId"| S11["⚙️ RecommendationService.markRepurchaseClicked()"]:::service S11 -->|"更新clicked=1"| D_REP end %% ================================================================ %% 阶段五:饮食推荐 %% ================================================================ subgraph 阶段五[阶段五:饮食推荐] P1b -->|"饮食推荐"| P5["🏠 食谱推荐页"]:::page P5 -->|"mealType, conversationId"| A9["🔗 POST /api/meal/recommend"]:::api A9 -->|"userId"| S12["⚙️ MealRecommendService.aggregateContext()"]:::service S12 -->|"候选食材 + 营养摘要"| D_FOOD["📦 foods, recipes 表"]:::data S12 -->|"inputs"| S13["⚙️ AIService.sendNutritionMessage()"]:::service S13 -->|"Dify营养助手"| DIFY2 A9 -->|"answer, replaceOptions, nutritionSummary"| P5a["🏠 展示AI生成食谱"]:::page P5a -->|"替换食材"| A10["🔗 POST /api/meal/replace"]:::api A10 -->|"foodId, userId"| S14["⚙️ MealRecommendService.findReplaceCandidate()"]:::service S14 -->|"同类替代食材"| D_FOOD P5a -->|"记录饮食"| A11["🔗 POST /api/meal/log"]:::api A11 -->|"userId, childId, mealType, foods, note"| S15["⚙️ MealLogService.create()"]:::service S15 -->|"写入饮食记录"| D_LOG["📦 meal_logs 表"]:::data P5a -->|"查看近期饮食"| A12["🔗 POST /api/meal/logs"]:::api A12 -->|"userId, days"| S16["⚙️ MealLogService.getRecentMeals()"]:::service S16 -->|"近N天饮食记录"| D_LOG P5a -->|"营养摄入统计"| A13["🔗 POST /api/meal/nutrition-summary"]:::api end %% ================================================================ %% 阶段六:AI上下文 %% ================================================================ subgraph 阶段六[阶段六:AI上下文与知识库] A13 -->|"intentType, params"| A14["🔗 POST /api/ai/context"]:::api A14 -->|"意图: health_report / task_progress / child_info / emotion_status / user_facts"| S17["⚙️ AiContextService.getContext()"]:::service S17 -->|"健康报告"| D_HR S17 -->|"任务进度"| D_TASKS S17 -->|"孩子信息"| D_CHILD["📦 User(孩子角色)"]:::data S17 -->|"情绪打卡"| D_EMO["📦 emotion_checkins 表"]:::data S17 -->|"会话摘要Layer1"| D_SUM S17 -->|"用户事实Layer2"| D_FACT end %% ================================================================ %% 角色关联 %% ================================================================ ROLE_USER -.- P1 ROLE_USER -.- P3 ROLE_USER -.- P4 ROLE_USER -.- P5 ROLE_DIFY -.- DIFY1 ROLE_DIFY -.- DIFY2 ROLE_LG -.- LG1 ROLE_LG -.- LG2 ``` ## 端点明细 ### AI对话 | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/ai/chat/send` | 发送聊天消息 | 📱小程序 | `{query, conversationId, reportId, surveyId}` | `{answer, conversationId, tasks[]}` | | `POST /api/ai/chat/conversations` | 获取会话列表 | 📱小程序 | Header: `Authorization` | `[{id, name, last_message_at, ...}]` | | `POST /api/ai/chat/messages` | 获取消息历史 | 📱小程序 | `{conversationId}` | `[{role, content, created_at, ...}]` | | `POST /api/ai/chat/conversations/{id}/delete` | 删除会话 | 📱小程序 | path: `id` | `null` | | `POST /api/ai/nutrition/send` | 发送营养分析消息 | 📱小程序 | `{query, conversationId, reportId}` | `{answer, conversationId, recommendations[], tasks[]}` | | `POST /api/ai/context` | 获取AI上下文(供Dify回调) | ⚙️系统自动 | `{intentType, userId, params}` | `{has_data, ...根据意图的结构化数据}` | ### 智能推荐 | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/recommend/search` | 按营养标签推荐搜索 | 📱小程序 | `{userId, nutritionTags[], types[], limit}` | `[{type, id, name, description, price, url, source}]` | | `POST /api/recommend/repurchase-reminders` | 获取复购提醒列表 | 📱小程序 | Header: `Authorization` | `[{id, productId, name, price, coverImage, reason}]` | | `POST /api/recommend/repurchase-reminder/{id}/click` | 标记复购提醒已点击 | 📱小程序 | path: `id` | `null` | | `POST /api/recommend/repurchase-reminders/list` | 获取待处理复购提醒 | 📱小程序 | Header: `Authorization` | `[{id, productId, productName, ...}]` | | `POST /api/recommend/repurchase-reminders/click` | 标记已点击 | 📱小程序 | `{id}` | `null` | | `POST /api/recommend/repurchase-reminders/purchased` | 标记已购买 | 📱小程序 | `{id, orderId}` | `null` | ### 饮食推荐 | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/meal/recommend` | 获取AI食谱推荐 | 📱小程序 | `{mealType, conversationId}` | `{answer, replaceOptions[], nutritionSummary}` | | `POST /api/meal/replace` | 替换指定食材 | 📱小程序 | `{foodId}` | `Food(替代食材)` | | `POST /api/meal/log` | 记录饮食日志 | 📱小程序 | `{childId, mealType, foods[], mealDate, note}` | `{id, message}` | | `POST /api/meal/logs` | 获取近期饮食日志 | 📱小程序 | `{days}` | `[MealLog]` | | `POST /api/meal/nutrition-summary` | 获取营养摄入统计 | 📱小程序 | `{days}` | `{...营养统计数据}` | ### 营养知识库(北京报告) | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/nutrition/beijing/bacteria/save` | 保存/更新菌群状态 | 📱小程序 | `{userId, bacteriaList[{latinName, chineseName, status}]}` | `"保存成功"` | | `POST /api/nutrition/beijing/recommend` | 基于菌群数据获取食材推荐 | 📱小程序 | `{userId, limit}` | `{foods[], categories[], ...}` | | `POST /api/nutrition/beijing/recommend/custom` | 直接传入菌群状态获取推荐 | 📱小程序 | `{userId, bacteriaList[...], limit}` | `{foods[], categories[], ...}` | | `POST /api/nutrition/beijing/kb/query` | 查询菌属知识库 | 📱小程序 | `{name}` | `BacteriaEntry(菌属详细)` | | `POST /api/nutrition/beijing/kb/list` | 获取菌属知识库列表 | 📱小程序 | — | `[BacteriaEntry]` | | `POST /api/nutrition/beijing/kb/info` | 获取知识库概况 | 📱小程序 | — | `{metadata, 总菌属数, 菌属列表}` | ## 数据实体关系 ```mermaid erDiagram User ||--o{ ChatConversation : "userId" ChatConversation ||--o{ ChatMessage : "会话消息" User ||--o{ AiConversationSummary : "对话摘要" User ||--o{ AiUserFact : "关键事实" User ||--o{ HealthReport : "健康报告" User ||--o{ MealLog : "饮食记录" Product ||--o{ RepurchaseReminderRecord : "复购提醒" Article ||--o{ RecommendationResult : "推荐结果" Activity ||--o{ RecommendationResult : "推荐结果" GrowthTask ||--o{ AIChatController : "动态任务" ChatConversation { Long id PK Long userId FK string difyConversationId "Dify会话ID" string assistantType "family/nutrition" string title "会话标题" date lastMessageAt } ChatMessage { Long id PK Long conversationId FK string role "user/assistant" text content text inputs "上下文快照" } AiConversationSummary { Long id PK Long userId FK string conversationId text summaryText int messageCount } AiUserFact { Long id PK Long userId FK string factKey string factValue string sourceConversation } HealthReport { Long id PK Long userId FK date reportDate int overallScore int gutHealthScore int nutritionScore string gutType } ``` ## 完整性分析 | # | 维度 | 评估 | 说明 | |---|------|------|------| | 1 | **流程完整性** | ✅ 完整 | 覆盖AI对话(含LangGraph/Dify双引擎)、会话管理、精准营养分析、智能推荐、饮食推荐、AI上下文6个阶段,路径完整 | | 2 | **异常路径** | ✅ 完整 | LangGraph超时/熔断自动回退Dify(AiGateway熔断器);Dify失败回退本地镜像数据(ChatMirrorService);5%灰度流量走LangGraph;所有外部调用有try-catch包裹 | | 3 | **端点覆盖** | ✅ 完整 | 24个端点全部映射到流程图中,与代码实际暴露的`/api/ai/*`、`/api/recommend/*`、`/api/meal/*`、`/api/nutrition/beijing/*`一致 | | 4 | **角色覆盖** | ✅ 完整 | 所有端点为📱小程序端口,家长/孩子/规划师均可使用AI助手;Dify AI引擎和LangGraph Python服务标注为⚙️外部系统 | | 5 | **数据实体** | ✅ 完整 | chat_conversations、chat_messages(本地镜像)、ai_conversation_summaries(记忆Layer1)、ai_user_facts(记忆Layer2)、health_reports、foods/meal_logs、repurchase_reminder_record等均在图中映射 | | 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(AIChatController、RecommendationController、MealRecommendController、BeijingNutritionController)中的`@PostMapping`匹配 |