Files
AI-Health/健康管家-首次建档引导实施文档.md
MingNian c2399b952f refactor: 4层架构重构 + 饮食VLM接入 + 多项修复
- 后端: remaining_endpoints拆分为6个独立文件
- 后端: AI Agent Handler从ai_chat_endpoints抽取为7个独立处理器
- 后端: 食物识别prompt改为输出结构化JSON
- 前端: 饮食识别从Mock替换为真实VLM API调用
- 前端: 首页图片上传URL修复(/api/upload→/api/files/upload)
- 前端: 拍饮食按钮导航到独立DietCapturePage
- 前端: 删除无用agent_bar.dart
- 前端: 修复widget_test.dart过期属性名
- 前端: 恢复ServicePackageCard和详情页
- 新增6份实施文档(情况/问诊/报告/建档/日历/视觉统一)
2026-06-03 23:17:37 +08:00

330 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI 首次建档引导 — 实施文档
## 一、触发条件
新用户登录后同时满足以下条件时触发:
1. `HealthArchive` 所有字段为空Diagnosis、SurgeryType、Allergies 等全空)
2. 当前对话是新会话(无历史消息)
3. 用户尚未主动输入过内容
## 二、交互流程
```
用户登录 → 首页空白对话页
AI 主动发送引导消息(约 2 秒延迟后出现):
┌──────────────────────────────────────────────┐
│ 🤖 您好我是您的AI健康管家
│ │
│ 为了给您更精准的健康建议,我需要了解一些 │
│ 基本信息。不会太久,大约 2-3 分钟即可完成。 │
│ │
│ 您可以随时说"跳过"或"以后再说"。 │
│ │
│ [开始建档] [以后再说] │
└──────────────────────────────────────────────┘
├── 点"以后再说" → 引导卡片消失,正常对话
└── 点"开始建档" → 进入分步引导
├── Q1: "您的主要诊断是什么?"
│ 选项: [冠心病] [高血压] [糖尿病] [其他]
│ → 用户选择/输入 → 调用 check_archive → 存 diagnosis
├── Q2: "您做过什么手术吗?"
│ 选项: [PCI支架植入术] [心脏搭桥] [其他手术] [没有]
│ 追问: "什么时候做的手术?" → 存 surgeryType + surgeryDate
├── Q3: "您对哪些药物或食物过敏?"
│ 选项: [青霉素] [头孢] [海鲜] [鸡蛋] [无过敏]
│ 多选 → 存 allergies
├── Q4: "您有其他慢性病史吗?"
│ 选项: [高血脂] [糖尿病] [痛风] [无]
│ 多选 → 存 chronicDiseases
├── Q5: "您有饮食方面的限制吗?"
│ 选项: [低盐] [低脂] [低糖] [无限制]
│ 多选 → 存 dietRestrictions
└── 完成 → AI 总结卡片
┌──────────────────────────────────────┐
│ ✅ 健康档案已建立 │
│ │
│ 诊断:冠心病 │
│ 手术PCI支架植入术 (2026-03) │
│ 过敏:青霉素 │
│ 慢病:高血脂 │
│ 饮食:低盐、低脂 │
│ │
│ 随时可以跟我说"修改档案"来更新这些 │
│ 信息。接下来,有什么可以帮您的? │
│ │
│ [查看档案] [开始记录健康数据] │
└──────────────────────────────────────┘
```
## 三、后端改动
### 3.1 新增建档专用 Agent
`PromptManager.cs` 新增 System Prompt
```csharp
private const string OnboardingPrompt = """
你是一个健康管家助手,正在帮助新用户建立健康档案。
必须严格遵守以下流程,一次只问一个问题:
步骤1:询问主要诊断(冠心病/高血压/糖尿病/其他)
步骤2:询问手术史(PCI支架植入/心脏搭桥/其他/没有)→ 追问手术日期
步骤3:询问过敏史(青霉素/头孢/海鲜/鸡蛋/无过敏)→ 可多选
步骤4:询问慢性病史(高血脂/糖尿病/痛风/无)
步骤5:询问饮食限制(低盐/低脂/低糖/无限制)
规则:
- 每次只问一个问题,给出 2-4 个快捷选项
- 用户回答后,调用 manage_archive 工具保存
- 用户说"跳过"/"以后再说"/"再说" 礼貌结束建档
- 完成后生成结构化总结卡片
- 语气温暖、像朋友一样
""";
```
同时在 `GetSystemPrompt` 的 switch 中加入:
```csharp
AgentType.Onboarding => OnboardingPrompt,
```
### 3.2 AgentType 枚举
`health_enums.cs``AgentType` 新增:
```csharp
Onboarding, // 建档引导
```
### 3.3 新增 manage_archive Tool
`CommonAgentHandler.cs` 新增:
```csharp
public static readonly ToolDefinition ManageArchiveTool = new()
{
Function = new()
{
Name = "manage_archive",
Description = "管理用户健康档案(更新诊断/手术/过敏/慢性病/饮食限制)",
Parameters = new
{
type = "object",
properties = new
{
action = new { type = "string", description = "update_diagnosis / update_surgery / update_allergies / update_chronic_diseases / update_diet_restrictions / query" },
diagnosis = new { type = "string" },
surgery_type = new { type = "string" },
surgery_date = new { type = "string" },
allergies = new { type = "array", items = new { type = "string" } },
chronic_diseases = new { type = "array", items = new { type = "string" } },
diet_restrictions = new { type = "array", items = new { type = "string" } },
},
required = new[] { "action" }
}
}
};
```
执行函数:根据 action 字段更新 `HealthArchive` 对应字段。
### 3.4 ai_chat_endpoints.cs 改动
```csharp
// GetToolsForAgent 新增:
AgentType.Onboarding => [CommonAgentHandler.ManageArchiveTool, CommonAgentHandler.CheckArchiveTool],
// ExecuteToolCall 新增:
"manage_archive" => CommonAgentHandler.Execute(toolName, root, db, userId),
```
## 四、前端改动
### 4.1 检测是否新用户
HomePage 初始化后,首次插入引导消息:
```dart
// 在 ChatNotifier.build() 或 init 中
void _checkOnboarding() {
// 如果用户档案为空且第一次打开
final archive = ref.read(healthArchiveProvider);
// 插入引导消息
state = state.copyWith(messages: [
...state.messages,
ChatMessage(
id: 'onboarding_greeting',
role: 'assistant',
content: '',
createdAt: DateTime.now(),
type: MessageType.onboarding,
),
]);
}
```
### 4.2 新增 MessageType.onboarding
`chat_provider.dart` 枚举新增:
```dart
enum MessageType { ..., onboarding }
```
### 4.3 新增 OnboardingCard 组件
`chat_messages_view.dart` 新增渲染分支:
```dart
case MessageType.onboarding:
return _buildOnboardingCard(context, ref, msg);
```
引导卡片 UI
```dart
Widget _buildOnboardingCard(BuildContext context, WidgetRef ref, ChatMessage msg) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
margin: EdgeInsets.only(bottom: 12),
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.88),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(
color: Color(0xFF8B9CF7).withAlpha(25),
blurRadius: 14, offset: Offset(0, 4),
)],
),
clipBehavior: Clip.antiAlias,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 渐变色头部
Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(20, 24, 20, 16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF8B9CF7), Color(0xFFA78BFA)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Container(
width: 48, height: 48,
decoration: BoxDecoration(
color: Colors.white.withAlpha(30),
borderRadius: BorderRadius.circular(14),
),
child: Icon(Icons.health_and_safety, size: 28, color: Colors.white),
),
SizedBox(width: 14),
Text('欢迎来到健康管家!', style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w700, color: Colors.white)),
]),
SizedBox(height: 12),
Text(
'我是您的AI健康管家。为了给您更精准的建议\n我先了解一些基本信息好吗?大约 2-3 分钟。',
style: TextStyle(fontSize: 14, color: Colors.white.withAlpha(220), height: 1.5),
),
],
),
),
// 按钮
Padding(
padding: EdgeInsets.fromLTRB(18, 18, 18, 20),
child: Column(children: [
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// 切换到 Onboarding Agent开始 SSE 对话
ref.read(chatProvider.notifier)
.setAgent(ActiveAgent.onboarding);
ref.read(chatProvider.notifier)
.sendToOnboarding();
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF8B9CF7),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
padding: EdgeInsets.symmetric(vertical: 14),
),
child: Text('开始建档', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
),
),
SizedBox(height: 10),
TextButton(
onPressed: () {
ref.read(chatProvider.notifier).dismissOnboarding();
},
child: Text('以后再说', style: TextStyle(fontSize: 14, color: Color(0xFF999999))),
),
]),
),
],
),
),
);
}
```
### 4.4 建档完成后的总结卡片
复用现有的 `MessageType.dataConfirm` 样式,增加 `MessageType.onboardingComplete`,展示结构化档案总结 + "[查看档案] [开始记录]" 按钮。
### 4.5 ActiveAgent 枚举新增
`chat_provider.dart`
```dart
enum ActiveAgent { default_, consultation, health, diet, medication, report, exercise, onboarding }
```
Agent 栏不显示 onboarding它是对话内触发的。
## 五、后端-前端交互方式
建档过程直接用 **SSE 对话** 驱动:
1. 前端插入 OnboardingCard
2. 用户点击"开始建档" → 前端调 `sendMessage("开始建档")`agentType 设为 `onboarding`
3. 后端用 `OnboardingPrompt` + `manage_archive` tool 走 SSE 流程
4. AI 分步提问用户回复AI 调 tool 存入 HealthArchive
5. 每步保存完成后前端刷新侧边栏数据
6. 建档完成后返回总结卡片Agent 切回 Default
## 六、跳过逻辑
- 点"以后再说" → 卡片消失保存标记LocalDatabase 记录 `onboarding_skipped_at`
- 用户说"跳过"/"以后再说" → AI 回复"好的,随时可以跟我说'完善档案'来继续"
- 7 天内不重复弹出
## 七、文件改动清单
```
后端:
修改: Enums/health_enums.cs (+ Onboarding 枚举, 1行)
修改: AI/prompt_manager.cs (+ OnboardingPrompt, ~30行)
修改: AI/AgentHandlers/common_agent_handler.cs (+ ManageArchiveTool + Execute, ~80行)
修改: Endpoints/ai_chat_endpoints.cs (+ Onboarding 路由, ~5行)
前端:
修改: providers/chat_provider.dart (+ ActiveAgent.onboarding, + onboarding 方法, ~40行)
修改: pages/home/widgets/chat_messages_view.dart (+ OnboardingCard 渲染, ~100行)
修改: pages/home/home_page.dart (+ 检测触发逻辑, ~10行)
```