Files
hms/docs/superpowers/specs/2026-05-18-ai-agent-breakthrough-design.md
iven 31771168dd docs(ai): Spec Review R2 修复 — 复用 HealthDataProvider + 新增 generate_with_tools
CRITICAL:
- 移除重复的 HealthDataQuery trait,扩展现有 HealthDataProvider(新增 2 方法)
- Provider 适配改为新增 generate_with_tools 方法,不破坏现有 generate 路径

IMPORTANT:
- 修复章节编号(全文重排为连续编号)
- ai_tool_call_logs 补充 created_by + 说明省略原因(append-only)
- ai_user_profiles 说明省略 created_by/updated_by 原因(Agent 自动维护)
- ToolContext 改为持有 Arc<dyn HealthDataProvider> 而非裸 db
- SSE 语义明确:仅流式输出最终回复
- 5 轮上限强制终止逻辑:追加总结指令让 LLM 正常结束
- GenerateRequest 不再破坏性修改,新旧路径并行
2026-05-18 01:57:16 +08:00

28 KiB
Raw Blame History

AI Agent 突破口设计规格

日期: 2026-05-18 | 状态: Draft | 范围: erp-ai Agent 改造 总工期: 20-27 天 | 方案: ReAct Agent + Function Calling

1. 背景与动机

1.1 当前状态

HMS 健康管理平台综合评分 6.8/10功能完整度 87%,但 AI 能力"有弹药没上膛"

  • erp-ai 有 3 个 ProviderClaude/OpenAI/Ollama+ AiProvider trait 抽象
  • SSE 流式分析已实现(化验解读、趋势分析、报告摘要),但 4 个 SSE 端点无 UI 入口
  • Copilot 引擎(风险评分、规则引擎、洞察服务)已实现但未集成到用户触达层
  • 知识库框架structured_source、KDIGO 规则)已搭建
  • 成本/配额管控usage、quota、cache已就绪
  • v2 架构设计已规划 RAG、事件驱动管线、两级缓存
  • erp-core 已有 HealthDataProvider traitget_lab_report/get_vital_signs/get_patient_summary/get_trend_analysis_data),已注入 AiState

AI 客服"小华"现状:一个硬编码 system prompt + 最近 10 条历史拼成上下文的简单问答,无法识别意图、无法查询数据、无法触发分析。

1.2 核心问题

  1. AI 能力断裂 — 后端分析能力和前端用户触达之间没有桥接
  2. AI 客服能力单调 — 简单问答无法胜任真实客户服务场景(情绪安抚、医疗科普、引导到院)
  3. 缺少差异化竞争力 — 当前系统是工具,不是"主动关怀引擎"

1.3 设计目标

  • 打通现有 AI 链路 — 通过 Agent Tool 机制将 SSE 分析、Copilot 引擎、知识库串联到对话入口
  • 升级 AI 客服为多策略 Agent — 意图识别→策略选择(安抚/科普/推荐/预警/引导)→ Tool 调用→自然回复
  • 纯自研实现 — 在 erp-ai 内用 ReAct Agent 模式,不依赖 Dify 等外部平台
  • 复用现有基础设施 — Provider 抽象、配额管控、缓存、知识库全部复用

2. 整体架构

2.1 Agent 核心循环

┌─────────────────────────────────────────────────────┐
│                   Chat Handler                       │
│  接收用户消息 + 会话历史DB 持久化)                │
└──────────────────────┬──────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────┐
│              Agent Orchestrator                      │
│  1. 组装 System Prompt角色 + 可用 Tools 描述)     │
│  2. 发送给 LLM获取 Tool Call 或最终回复            │
│  3. 如果是 Tool Call → 执行 Tool → 结果加入上下文   │
│  4. 重复 2-3直到 LLM 给出最终回复                  │
│  5. 安全循环上限:最多 5 轮 Tool Call                │
└──────────────────────┬──────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────┐
│              Tool Registry                           │
│  注册所有可用 Tool按权限/场景过滤                   │
│  ┌──────────┐ ┌───────────┐ ┌───────────────┐       │
│  │ 健康数据  │ │ AI 分析    │ │ 知识库        │       │
│  │ 查询工具  │ │ 触发工具   │ │ 检索工具      │       │
│  ├──────────┤ ├───────────┤ ├───────────────┤       │
│  │ 预约工具  │ │ 服务推荐   │ │ 风险预警      │       │
│  │          │ │ 工具       │ │ 工具          │       │
│  └──────────┘ └───────────┘ └───────────────┘       │
└─────────────────────────────────────────────────────┘

2.2 关键设计决策

决策 选择 原因
Agent 状态管理 Orchestrator 无状态,会话由 Handler 管理 简化 Orchestrator 职责,便于测试
Tool 执行模型 同步阻塞,单轮内多个 Tool Call 并行(futures::join_all,单 Tool 超时 10s LLM 返回多个 call 时并行执行,减少延迟
Provider 扩展 AiProvider trait 新增 generate_with_tools 方法,保留原 generate 不变 不破坏现有分析端点调用,新旧路径并行
跨 crate 数据访问 扩展现有 HealthDataProvider trait新增 get_appointments/get_medication 方法 erp-core 已有该 trait 且已注入 AiState避免重复
安全循环上限 单次对话最多 5 轮 Tool Call达到上限时强制 LLM 生成最终回复 防止无限循环,控制成本
分析调用模式 Agent 内走非流式同步调用 Agent 需要拿到完整结果再决策
SSE 语义 SSE 仅流式输出 Agent 最终回复Tool Call 过程不在 SSE 中传输 前端实现简单,用户体验清晰

3. Tool 系统

3.1 AgentTool Trait

#[async_trait]
pub trait AgentTool: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> serde_json::Value;  // JSON Schema
    async fn execute(&self, ctx: &ToolContext, params: serde_json::Value) -> ToolResult;
}

pub struct ToolContext {
    pub tenant_id: Uuid,
    pub user_id: Uuid,
    pub patient_id: Option<Uuid>,
    pub db: DatabaseConnection,                    // erp-ai 本地表sessions/messages/logs
    pub health_provider: Arc<dyn HealthDataProvider>,  // erp-health 数据(已有注入)
}

pub struct ToolResult {
    pub output: String,
    pub display_hint: Option<DisplayHint>,
}

3.2 跨 Crate 数据访问架构

erp-ai 不直接依赖 erp-health保持模块边界。数据查询类 Tool 通过已有的 HealthDataProvider trait 访问健康数据。

现有 HealthDataProvider traiterp-core已注入 AiState

// 已有的方法 — 直接复用
get_lab_report(tenant_id, report_id)  LabReportDto
get_vital_signs(tenant_id, patient_id, metrics, range)  Vec<VitalSignDto>
get_patient_summary(tenant_id, patient_id)  PatientSummaryDto
get_trend_analysis_data(tenant_id, patient_id, metrics, range)  TrendAnalysisDto

// 新增方法 — Phase 0 扩展
get_appointments(tenant_id, patient_id)  Vec<AppointmentSummaryDto>
get_medication_list(tenant_id, patient_id)  Vec<MedicationSummaryDto>

优势:现有的 DTO 已做 PII 脱敏PatientSummaryDto 用 age_group/sex 而非姓名/身份证Tool 无需额外脱敏处理。

注册机制AiState 已持有 Arc<dyn HealthDataProvider>state.rs:25Tool 通过 ToolContext.health_provider 访问。

3.3 DisplayHint 定义

DisplayHint 用于给前端提供渲染提示,让 Tool 返回的数据不仅作为 LLM 上下文,还能以富消息形式展示给用户:

pub enum DisplayHint {
    /// 体征数据卡片 — 前端渲染为小图表
    VitalCard { indicator_type: String, values: Vec<(DateTime, f64)>, unit: String },
    /// 化验报告摘要卡片
    LabReportCard { report_date: DateTime, abnormal_count: usize },
    /// 操作确认 — 前端渲染为确认按钮
    ActionConfirm { action_type: String, summary: String, confirm_payload: serde_json::Value },
    /// 风险等级提示
    RiskAlert { level: String, message: String },
    /// 纯文本(默认)
    Text,
}

3.4 Tool 清单

第一类:数据查询(只读,通过 HealthDataProvider 访问)

Tool 名称 功能 对接现有能力
query_patient_vitals 查询患者最近体征数据(血压/血糖/心率等) get_vital_signs
query_lab_reports 查询患者最近化验报告及指标 get_lab_report
query_patient_profile 查询患者基本信息、病史、过敏史 get_patient_summary
query_appointments 查询患者预约记录 get_appointments新增方法
query_medication 查询患者当前用药情况 get_medication_list新增方法

第二类AI 分析触发(调用 erp-ai 现有能力)

Tool 名称 功能 对接现有能力
analyze_lab_report 分析指定化验报告,返回异常指标解读 analysis_service(非流式调用)
analyze_health_trends 分析体征趋势变化,识别异常模式 get_trend_analysis_data + analysis_service
get_health_insights 获取患者当前风险洞察和 AI 建议 copilot_engine + insight_service

第三类:知识与服务(对话策略支撑)

Tool 名称 功能 对接现有能力
search_medical_knowledge 检索医疗知识库(疾病科普、指标解释) knowledge_structured_source
recommend_services 根据症状/需求推荐科室或服务 新增,基于规则 + 知识库
check_alert_rules 检查是否触发告警阈值 local_rules_engine + ai_risk_threshold

第四类:行动(写入操作,需更高权限)

Tool 名称 功能 对接现有能力
create_appointment 帮用户预约挂号 appointment_service
transfer_to_human 转接人工客服/值班医生 新增WebSocket 通知

3.5 权限与安全

  • 数据查询 Tool:自动注入 tenant_id + patient_id 过滤LLM 无法绕过多租户隔离
  • 分析触发 Tool:走现有配额管控(QuotaService
  • 行动 Tool需额外权限标记System Prompt 约束 LLM 只在用户明确请求时调用
  • 数据脱敏HealthDataProvider 返回的 DTO 已做 PII 脱敏(用 age_group/sex 而非真名/身份证Tool 层无需额外处理
  • 审计日志:每次 Tool Call 记录到 ai_tool_call_logs

3.6 权限码声明

现有权限码 ai.chat.send 保留用于发送消息。新增以下权限码:

权限码 说明 适用端点
ai.chat.session.list 查看会话列表 GET /ai/chat/sessions
ai.chat.session.manage 创建/关闭会话 POST/DELETE /ai/chat/sessions
ai.chat.session.history 查看会话消息历史 GET /ai/chat/sessions/{id}/messages
ai.chat.send 发送消息(触发 Agent POST /ai/chat/sessions/{id}/messages(已存在)

行动类 Toolcreate_appointmenttransfer_to_human)不单独声明权限,由 Agent 内部根据用户角色判断。


4. 多策略对话流

4.1 策略引导机制

Agent 通过 System Prompt 定义 5 种策略方向LLM 根据用户表达的内容和情绪自主选择和切换:

  1. 【情绪安抚】 用户焦虑/恐惧/沮丧时 → 先共情,用通俗语言解释,分享积极案例
  2. 【医疗科普】 用户询问指标/疾病知识时 → 调用 search_medical_knowledge 获取准确信息
  3. 【服务推荐】 用户有就医需求时 → 调用 recommend_services 推荐科室,主动提议预约
  4. 【风险预警】 症状或数据异常时 → 调用分析 Tool 评估风险,明确告知风险等级
  5. 【引导到院】 明确就诊意向或高风险时 → 帮助预约,提供科室信息,必要时转接人工

策略之间不互斥,一轮对话中可自然切换。

4.2 System Prompt 结构

你是 HMS 健康管理平台的 AI 健康顾问"小华"。

## 核心策略
根据用户表达的内容和情绪,自然地采用以下策略方向:

1. 【情绪安抚】当用户表达焦虑、恐惧、沮丧时:
   - 先共情认可感受,不急于给建议
   - 用通俗语言解释,避免医学术语
   - 分享积极案例,降低恐惧感

2. 【医疗科普】当用户询问指标含义、疾病知识时:
   - 调用 search_medical_knowledge 获取准确信息
   - 用比喻和类比让老年患者也能理解
   - 强调"具体请以医生诊断为准"

3. 【服务推荐】当用户表达就医需求或身体不适时:
   - 调用 recommend_services 推荐合适科室
   - 调用 query_appointments 查看已有预约
   - 主动提出帮用户预约

4. 【风险预警】当用户描述的症状或数据异常时:
   - 调用 analyze_health_trends 或 get_health_insights 评估风险
   - 明确告知风险等级和需要注意的事项
   - 高风险时建议尽快就医

5. 【引导到院】当用户有明确就诊意向或高风险预警时:
   - 调用 create_appointment 帮助预约
   - 提供科室位置、出诊医生信息
   - 必要时调用 transfer_to_human 转接值班医生

## 策略不是互斥的,你可以在一轮对话中自然切换。
## 永远不要:推荐具体药物、给出明确诊断、替代医生建议。

4.3 对话流示例

场景:老年患者说"最近头有点晕"

[用户] 最近头有点晕,不知道怎么回事

[Agent 思考] 用户描述头晕症状,可能是高血压或其他问题。
             应该1) 查看最近体征数据 2) 安抚情绪

[Agent 调用] query_patient_vitals → 获取最近血压数据
[Tool 返回] 最近7天平均血压 155/95较上月升高 10mmHg

[Agent 思考] 血压偏高且趋势上升,存在风险。
             应该1) 分析趋势 2) 安抚 + 预警

[Agent 调用] analyze_health_trends → 分析血压趋势
[Tool 返回] 血压持续升高趋势,建议关注,风险等级:中等

[Agent 回复] 张爷爷,我看了您最近的血压记录,确实比之前高了一些。
             头晕可能和血压升高有关。不过您先别担心,这个趋势我们
             可以通过调整生活方式来改善。我建议您先来看看医生,
             要不要我帮您预约个心内科的号?

4.4 会话记忆

  • 短期记忆当前会话完整对话历史DB 持久化 ai_chat_messages
  • 长期记忆:用户画像摘要(偏好、常见问题、健康关注点),存储在 ai_user_profiles 表,每次新会话加载
  • 上下文窗口管理:历史消息按重要性截断,保留最近 10 轮 + 关键上下文摘要

5. 系统集成

5.1 后端集成点

现有能力                          Agent 集成方式
─────────                        ──────────────
HealthDataProvider trait    →  Tool 数据查询层(已有注入,新增 2 方法)
analysis_service (SSE)      →  Tool: analyze_lab_report / analyze_health_trends
                                 非 SSE 模式调用,直接拿结果返回给 Agent
copilot_engine (风险评分)    →  Tool: get_health_insights
                                 调用 scoring + rules返回结构化风险信息
knowledge (structured)      →  Tool: search_medical_knowledge
                                 查询 KDIGO 规则、科室指南、科普文章
local_rules_engine          →  Tool: check_alert_rules
                                 评估当前数据是否触发告警
quota_service               →  Agent Orchestrator 内部调用
                                 每轮 Tool Call 前检查配额
usage_service               →  Agent Orchestrator 内部调用
                                 记录每轮 token 消耗
cache_service               →  分析类 Tool 内部复用
                                 相同参数的重复分析走缓存

5.2 数据模型新增

ai_chat_sessions — AI 会话表

与现有 copilot_chat_logs 表的关系:copilot_chat_logs 记录 Copilot 内部对话AI 分析引擎之间的通信),服务于风险洞察和自动分析。ai_chat_sessions / ai_chat_messages 记录用户与 AI 客服的面向用户对话。两者并存,数据不迁移。

CREATE TABLE ai_chat_sessions (
  id UUID PRIMARY KEY,
  tenant_id UUID NOT NULL,
  user_id UUID NOT NULL,
  patient_id UUID,
  title VARCHAR(255),
  status VARCHAR(20) NOT NULL DEFAULT 'active',  -- active / closed
  metadata JSONB,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_by UUID,
  updated_by UUID,
  deleted_at TIMESTAMPTZ,
  version INTEGER NOT NULL DEFAULT 1
);

ai_chat_messages — AI 聊天消息表

CREATE TABLE ai_chat_messages (
  id UUID PRIMARY KEY,
  tenant_id UUID NOT NULL,
  session_id UUID NOT NULL REFERENCES ai_chat_sessions(id),
  role VARCHAR(20) NOT NULL,  -- user / assistant / tool
  content TEXT,
  tool_calls JSONB,           -- assistant 消息中的 tool call 列表
  tool_call_id VARCHAR(100),  -- tool 消息的关联 ID
  token_count INTEGER,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_by UUID,
  updated_by UUID,
  deleted_at TIMESTAMPTZ,
  version INTEGER NOT NULL DEFAULT 1
);

ai_tool_call_logs — AI 工具调用日志

此表为仅追加日志append-only记录后不更新因此省略 updated_at/updated_by/version/deleted_at

CREATE TABLE ai_tool_call_logs (
  id UUID PRIMARY KEY,
  tenant_id UUID NOT NULL,
  session_id UUID NOT NULL,
  message_id UUID NOT NULL,
  tool_name VARCHAR(100) NOT NULL,
  parameters JSONB,
  result_summary TEXT,
  execution_ms INTEGER,
  success BOOLEAN NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_by UUID
);

ai_user_profiles — 用户长期画像(长期记忆)

created_by/updated_by 省略,因为此表由 Agent 自动维护而非用户手动创建。

CREATE TABLE ai_user_profiles (
  id UUID PRIMARY KEY,
  tenant_id UUID NOT NULL,
  user_id UUID NOT NULL,
  preferences JSONB,           -- 用户偏好(如:偏好简洁回复、关心血压问题)
  health_interests TEXT[],      -- 健康关注点(如:高血压、糖尿病)
  frequent_topics TEXT[],       -- 常见咨询主题
  personality_summary TEXT,     -- AI 生成的用户画像摘要
  last_updated_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  deleted_at TIMESTAMPTZ,
  version INTEGER NOT NULL DEFAULT 1,
  UNIQUE(tenant_id, user_id)
);

每次会话结束时Agent 自动更新用户画像摘要。新会话开始时加载注入 System Prompt。

5.3 PII 脱敏规范

HealthDataProvider 返回的 DTO 已做 PII 脱敏(第 8 行注释:"返回的 DTO 已脱去 PII"Tool 层无需额外处理。

对于 Tool 中可能出现的补充数据,统一通过 sanitize_for_llm() 函数处理:

字段类型 脱敏方式 示例
患者姓名 保留姓氏 + 称呼 "张爷爷"Agent 用称呼,不用真名)
身份证号 不传给 LLM Tool 层过滤
手机号 不传给 LLM 同上
出生日期 转为年龄 "68 岁"
医疗数据 正常传递 血压值、化验指标等不脱敏

5.4 Provider Function Calling 适配

现有 AiProvider trait 的 generate() 方法保持不变(现有分析端点继续使用)。新增 generate_with_tools() 方法:

#[async_trait]
pub trait AiProvider: Send + Sync {
    // 保留 — 现有分析端点继续使用
    async fn stream_generate(&self, req: GenerateRequest)
        -> AiResult<Pin<Box<dyn Stream<Item = AiResult<String>> + Send>>>;
    async fn generate(&self, req: GenerateRequest)
        -> AiResult<GenerateResponse>;
    fn name(&self) -> &str;
    async fn health_check(&self) -> AiResult<bool>;

    // 新增 — Agent 专用,支持 Function Calling
    async fn generate_with_tools(
        &self,
        messages: Vec<ChatMessage>,
        tools: Vec<ToolDefinition>,
        options: GenerateOptions,
    ) -> AiResult<AgentGenerateResponse> {
        // 默认实现:不支持 FC 的 Provider 返回错误
        Err(AiError::UnsupportedOperation("Function Calling not supported".into()))
    }
}

pub struct ChatMessage {
    pub role: MessageRole,  // User / Assistant / Tool
    pub content: String,
    pub tool_calls: Option<Vec<ToolCall>>,
    pub tool_call_id: Option<String>,
}

pub struct ToolDefinition {
    pub name: String,
    pub description: String,
    pub parameters: serde_json::Value,
}

pub struct ToolCall {
    pub id: String,
    pub name: String,
    pub arguments: serde_json::Value,
}

pub struct AgentGenerateResponse {
    pub content: Option<String>,
    pub tool_calls: Option<Vec<ToolCall>>,
    pub usage: Option<TokenUsage>,
}

各 Provider 适配工作量

  • ClaudeAnthropic API 使用 tool_use/tool_result 内容块1 天)
  • OpenAI:使用 functiontool 类型消息相对标准0.5 天)
  • Ollama:若模型不支持 FC返回 UnsupportedOperationOrchestrator 降级为纯 Prompt 模式0.5 天)

5.5 API 设计

POST   /api/v1/ai/chat/sessions                  — 创建会话
GET    /api/v1/ai/chat/sessions                  — 会话列表
GET    /api/v1/ai/chat/sessions/{id}             — 会话详情
DELETE /api/v1/ai/chat/sessions/{id}             — 关闭会话(软删除)
POST   /api/v1/ai/chat/sessions/{id}/messages    — 发送消息(触发 Agent
GET    /api/v1/ai/chat/sessions/{id}/messages    — 消息历史

发送消息端点支持 SSE 流式输出(仅 Agent 最终回复)和 JSON 响应两种模式。


6. 前端演进

6.1 消息类型扩展

  • 文本消息 — 正常对话内容
  • 数据卡片 — "这是您最近的血压趋势" + 小图表(通过 DisplayHint::VitalCard 触发)
  • 操作确认 — "帮您预约了周三上午心内科,确认吗?" + 确认/取消按钮(通过 DisplayHint::ActionConfirm 触发)
  • 转接通知 — "正在为您转接值班医生..."(通过 DisplayHint::RiskAlert 触发)

6.2 会话管理

  • 会话列表页(历史对话)
  • 新建会话 / 继续会话
  • 历史从本地 Storage 迁移到 DB 持久化

6.3 小程序 + Web 实现

小程序

  • SSE 兼容Taro 原生不支持 SSE使用 requestTask 长连接或降级为轮询Phase 2 明确分配 1 天处理)
  • 富消息渲染:基于 DisplayHint 类型分发到不同渲染组件
  • 旧数据迁移:ai-chat.tsgetLocalHistory() 的本地 Storage 数据,首次打开新版本时一键上传到 DB

Web

  • AI 客服页面从零构建(无现有 UI包含会话列表 + 聊天界面 + 富消息渲染
  • 复用小程序的 API 模块(services/ai-chat.tsUI 适配 Ant Design

7. 分阶段实施计划

Phase 0基础设施5-6 天)

目标Agent 核心循环跑通,能用一个 Tool 完成完整对话

任务 工作量
AiProvider trait 新增 generate_with_tools + Claude Provider 适配 1 天
OpenAI + Ollama Provider 适配 1 天
AgentTool trait + ToolRegistry + ToolContext + DisplayHint 0.5 天
AgentOrchestrator ReAct 循环(含 5 轮上限强制终止逻辑) 1 天
HealthDataProvider trait 扩展:新增 get_appointments/get_medication_list 1 天
数据库迁移:ai_chat_sessions + ai_chat_messages + ai_tool_call_logs + ai_user_profiles 0.5 天
实现 1 个 Toolquery_patient_vitals(验证端到端链路) 0.5 天
改造 chat_handler:接入 Orchestrator替换原有简单逻辑 0.5 天
单元测试 + 集成测试 0.5 天

交付标准Postman 调用 /api/v1/ai/chat/sessions/{id}/messagesAgent 能查到患者体征数据并自然回复。

Phase 1Tool 扩展 + 策略 Prompt5-7 天)

目标:覆盖全部核心 Tool多策略对话流生效

任务 工作量
数据查询类 Toolquery_lab_reportsquery_patient_profilequery_appointmentsquery_medication 1.5 天
AI 分析类 Toolanalyze_lab_reportanalyze_health_trendsget_health_insights 2 天
知识类 Toolsearch_medical_knowledgerecommend_servicescheck_alert_rules 1.5 天
多策略 System Prompt 设计 + 调优 1 天
每轮 Tool Call 配额检查 + token 计量 0.5 天
测试覆盖 1 天

交付标准:模拟 5 种典型场景(安抚/科普/推荐/预警/引导到院Agent 均能自主选择正确策略和 Tool。

Phase 2前端升级 + 流式输出7-9 天)

目标:小程序 + Web 都有完整 AI 客服体验

任务 工作量
后端:会话 CRUD API创建/列表/历史消息) 1 天
后端Agent 最终回复走 SSE 流式输出 1 天
小程序SSE 兼容层Taro requestTask 或轮询适配) 1 天
小程序:会话列表页 + 消息历史页 + 富消息渲染 2 天
WebAI 客服页面从零构建(会话列表 + 聊天界面 + 富消息) 2 天
数据卡片渲染(体征趋势小图表) 1 天
前端迁移:本地 Storage → DB 持久化 + 旧数据迁移脚本 0.5 天
端到端测试 0.5 天

交付标准:小程序打开 AI 客服,能自然对话,能看到数据卡片,能看到流式输出。

Phase 3行动类 Tool + 人机协作3-5 天)

目标AI 客服能帮用户预约、转接人工

任务 工作量
create_appointment Tool带二次确认机制 1 天
transfer_to_human Tool + WebSocket 通知值班医护 2 天
操作确认 UI预约确认卡片、转接状态提示 1 天
安全边界加固(行动类 Tool 权限标记、审计日志) 0.5 天
端到端测试 0.5 天

交付标准:用户对 AI 说"帮我预约个号"AI 查时段→推荐→确认→创建预约,全流程跑通。

总工期

Phase 0 ████████████████ (5-6天)
Phase 1 ████████████████ (5-7天)
Phase 2 ████████████████████ (7-9天)
Phase 3 ██████████ (3-5天)
────────────────────────
合计    20-27 天

每个 Phase 结束后都有可演示的交付物。


8. 故障处理与降级

故障场景 用户看到什么 处理方式
所有 Provider 不可用 "小华暂时无法回复,请稍后再试" 返回固定降级消息,记录到 usage_service
Agent 循环超时60s 已生成的部分回复 + "回复被中断,请重新提问" SSE 断流 + 超时日志
Agent 达到 5 轮上限 正常回复Orchestrator 追加 "请基于已有信息总结回复" 指令强制 LLM 结束) 用户无感知,回复可能不够完整
单个 Tool 执行超时10s Agent 跳过该 Tool 继续推理 ToolResult 返回错误摘要Agent 可选择其他路径
Ollama 不支持 Function Calling 自动降级为纯文本 Prompt 模式 Provider 层返回 UnsupportedOperationOrchestrator 将 Tool 描述注入 System Prompt
LLM 返回无效 Tool Call "抱歉,我刚才思考有误,请再说一次" Orchestrator 捕获解析错误,返回重试提示

9. 风险与缓解

风险 概率 影响 缓解措施
Function Calling 格式跨 Provider 不统一 Phase 0 就在 3 个 Provider 上验证Ollama 降级方案已设计
LLM 幻觉(编造数据/错误诊断) 严重 System Prompt 强约束 + Tool 返回数据做事实校验 + 免责声明
Token 成本超预期 每轮配额检查 + 缓存复用 + 5 轮上限
Tool 执行超时 单个 Tool 超时 10s总轮次超时 60s
PII 泄露给 LLM 严重 HealthDataProvider DTO 已脱敏Tool 层补充 sanitize_for_llm()