# 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行) ```