# 用户使用流程图 — 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`匹配 |