From 6759723731c51730927ba9ea9685bbae6a29e3bb Mon Sep 17 00:00:00 2001 From: iven Date: Mon, 18 May 2026 01:51:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(ai):=20=E4=BF=AE=E5=A4=8D=20Spec=20Review?= =?UTF-8?q?=20=E5=8F=91=E7=8E=B0=E7=9A=84=209=20=E4=B8=AA=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL 修复: - 新增跨 crate 数据访问架构(erp-core HealthDataQuery trait) - 新增 4 个权限码声明(session.list/manage/history + chat.send) - 明确 Provider Function Calling 需中等程度重构,补充适配方案 IMPORTANT 修复: - 说明与 copilot_chat_logs 表的关系(并存不迁移) - 新增 ai_user_profiles 表(长期记忆/用户画像) - 定义 DisplayHint 枚举(5 种富消息类型) - Phase 0 验证标准修正为新端点 - 补充 Taro SSE 兼容层 + Web 从零构建,工期上调 - 新增 PII 脱敏规范(6 类字段处理规则) - 新增故障处理与降级章节 - Phase 0/2 工作量估算上调,总工期 16-23→20-27 天 --- ...2026-05-18-ai-agent-breakthrough-design.md | 203 ++++++++++++++++-- 1 file changed, 188 insertions(+), 15 deletions(-) diff --git a/docs/superpowers/specs/2026-05-18-ai-agent-breakthrough-design.md b/docs/superpowers/specs/2026-05-18-ai-agent-breakthrough-design.md index 5a1e9de..2571146 100644 --- a/docs/superpowers/specs/2026-05-18-ai-agent-breakthrough-design.md +++ b/docs/superpowers/specs/2026-05-18-ai-agent-breakthrough-design.md @@ -1,7 +1,7 @@ # AI Agent 突破口设计规格 > **日期:** 2026-05-18 | **状态:** Draft | **范围:** erp-ai Agent 改造 -> **总工期:** 16-23 天 | **方案:** ReAct Agent + Function Calling +> **总工期:** 20-27 天 | **方案:** ReAct Agent + Function Calling ## 1. 背景与动机 @@ -71,7 +71,8 @@ HMS 健康管理平台综合评分 6.8/10,功能完整度 87%,但 AI 能力" |------|------|------| | Agent 状态管理 | Orchestrator 无状态,会话由 Handler 管理 | 简化 Orchestrator 职责,便于测试 | | Tool 执行模型 | 同步阻塞,单轮内多个 Tool Call 并行 | LLM 返回多个 call 时并行执行,减少延迟 | -| Provider 复用 | 不改 `AiProvider` trait,在调用层传入 function definitions | 最小改动,兼容现有 3 个 Provider | +| Provider 扩展 | 扩展 `GenerateRequest` 添加 tools/functions 字段,3 个 Provider 各自适配 | Function Calling 是核心能力,需中等程度重构每个 Provider 的请求/响应结构 | +| 跨 crate 数据访问 | 在 erp-core 定义 `HealthDataQuery` trait,erp-health 实现,erp-ai 通过 trait 调用 | 保持模块边界,erp-ai 不直接依赖 erp-health | | 安全循环上限 | 单次对话最多 5 轮 Tool Call | 防止无限循环,控制成本 | | 分析调用模式 | Agent 内走非流式同步调用 | Agent 需要拿到完整结果再决策 | @@ -103,7 +104,56 @@ pub struct ToolResult { } ``` -### 3.2 Tool 清单 +### 3.2 跨 Crate 数据访问架构 + +erp-ai 不直接依赖 erp-health(保持模块边界)。数据查询类 Tool 通过以下机制访问健康数据: + +**方案:在 erp-core 定义 `HealthDataQuery` trait,erp-health 实现** + +```rust +// erp-core 中定义 +#[async_trait] +pub trait HealthDataQuery: Send + Sync { + async fn query_vitals(&self, tenant_id: Uuid, patient_id: Uuid, days: i32) -> Result>; + async fn query_lab_reports(&self, tenant_id: Uuid, patient_id: Uuid, limit: i32) -> Result>; + async fn query_patient_profile(&self, tenant_id: Uuid, patient_id: Uuid) -> Result; + async fn query_appointments(&self, tenant_id: Uuid, patient_id: Uuid) -> Result>; + async fn query_medication(&self, tenant_id: Uuid, patient_id: Uuid) -> Result>; +} + +// 轻量 DTO 定义在 erp-core(只含 Tool 需要的字段,非完整 Entity) +pub struct VitalSummary { pub indicator_type: String, pub value: f64, pub unit: String, pub recorded_at: DateTime } +pub struct LabReportSummary { pub id: Uuid, pub report_date: DateTime, pub items: Vec } +pub struct LabItemSummary { pub indicator_name: String, pub value: f64, pub unit: String, pub is_abnormal: bool } +pub struct PatientProfile { pub name: String, pub age: i32, pub gender: String, pub conditions: Vec } +pub struct AppointmentSummary { pub id: Uuid, pub department: String, pub doctor_name: String, pub scheduled_at: DateTime, pub status: String } +pub struct MedicationSummary { pub name: String, pub dosage: String, pub frequency: String } +``` + +**注册机制**:`AppState` 中持有 `Arc`,erp-health 模块注册时注入实现。Agent Tool 通过 `ToolContext` 访问。 + +**对 erp-ai 模块中已有的分析能力**(analysis_service、copilot_engine 等),无需跨 crate,直接在 erp-ai 内部调用。 + +### 3.3 DisplayHint 定义 + +`DisplayHint` 用于给前端提供渲染提示,让 Tool 返回的数据不仅作为 LLM 上下文,还能以富消息形式展示给用户: + +```rust +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 清单 #### 第一类:数据查询(只读,从 erp-health 取数据) @@ -131,6 +181,19 @@ pub struct ToolResult { | `recommend_services` | 根据症状/需求推荐科室或服务 | 新增,基于规则 + 知识库 | | `check_alert_rules` | 检查是否触发告警阈值 | `local_rules_engine` + `ai_risk_threshold` | +### 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`(已存在) | + +行动类 Tool(`create_appointment`、`transfer_to_human`)不单独声明权限,由 Agent 内部根据用户角色判断。 + #### 第四类:行动(写入操作,需更高权限) | Tool 名称 | 功能 | 对接现有能力 | @@ -259,6 +322,8 @@ cache_service → 分析类 Tool 内部复用 #### ai_chat_sessions — AI 会话表 +> 与现有 `copilot_chat_logs` 表的关系:`copilot_chat_logs` 记录 Copilot 内部对话(AI 分析引擎之间的通信),服务于风险洞察和自动分析。`ai_chat_sessions` / `ai_chat_messages` 记录用户与 AI 客服的面向用户对话。两者并存,数据不迁移。 + ```sql CREATE TABLE ai_chat_sessions ( id UUID PRIMARY KEY, @@ -315,7 +380,91 @@ CREATE TABLE ai_tool_call_logs ( ); ``` -### 5.3 API 设计 +#### ai_user_profiles — 用户长期画像(长期记忆) + +```sql +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 脱敏规范 + +Tool 返回数据在传给 LLM 前必须脱敏。具体规则: + +| 字段类型 | 脱敏方式 | 示例 | +|----------|----------|------| +| 患者姓名 | 保留姓氏 + 称呼 | "张爷爷"(Agent 用称呼,不用真名) | +| 身份证号 | 不传给 LLM | Tool 层过滤,不出现在 ToolResult | +| 手机号 | 不传给 LLM | 同上 | +| 具体住址 | 不传给 LLM | 同上 | +| 出生日期 | 转为年龄 | "68 岁" | +| 医疗数据 | 正常传递 | 血压值、化验指标等不脱敏 | + +脱敏在 `AgentTool::execute()` 实现中统一处理,每个 Tool 的返回值必须经过 `sanitize_for_llm()` 函数。 + +### 5.3 Provider Function Calling 适配 + +现有 `AiProvider` trait 的 `GenerateRequest` 不支持 tools/functions 参数,需要扩展: + +```rust +// 扩展 GenerateRequest +pub struct GenerateRequest { + pub system_prompt: String, + pub messages: Vec, // 从单条 user_prompt 改为多轮消息 + pub model: Option, + pub temperature: Option, + pub max_tokens: Option, + pub tools: Option>, // 新增 +} + +pub struct ChatMessage { + pub role: MessageRole, // User / Assistant / Tool + pub content: String, + pub tool_calls: Option>, // assistant 消息中的 tool call + pub tool_call_id: Option, // tool 消息的关联 ID +} + +pub struct ToolDefinition { + pub name: String, + pub description: String, + pub parameters: serde_json::Value, // JSON Schema +} + +pub struct ToolCall { + pub id: String, + pub name: String, + pub arguments: serde_json::Value, +} + +// GenerateResponse 扩展 +pub struct GenerateResponse { + pub content: Option, + pub tool_calls: Option>, // LLM 返回的 tool call + pub usage: Option, +} +``` + +**各 Provider 适配工作量**: +- **Claude**:Anthropic API 使用 `tool_use`/`tool_result` 内容块,需重构消息构建和响应解析(1 天) +- **OpenAI**:使用 `function` 或 `tool` 类型消息,相对标准(0.5 天) +- **Ollama**:Function Calling 支持取决于模型,若不支持则降级为纯文本 Prompt 模式(0.5 天) + +### 5.4 API 设计 ``` POST /api/v1/ai/chat/sessions — 创建会话 @@ -353,20 +502,24 @@ GET /api/v1/ai/chat/sessions/{id}/messages — 消息历史 ## 7. 分阶段实施计划 -### Phase 0:基础设施(3-4 天) +### Phase 0:基础设施(5-6 天) > 目标:Agent 核心循环跑通,能用一个 Tool 完成完整对话 | 任务 | 工作量 | |------|--------| -| `AgentTool` trait + `ToolRegistry` + `ToolContext` | 0.5 天 | -| `AgentOrchestrator` ReAct 循环(含 Function Calling 消息格式) | 1 天 | -| 数据库迁移:`ai_chat_sessions` + `ai_chat_messages` + `ai_tool_call_logs` | 0.5 天 | +| `GenerateRequest` + `GenerateResponse` 扩展(支持 tools/functions) | 1 天 | +| Claude Provider Function Calling 适配(消息构建 + 响应解析) | 1 天 | +| OpenAI + Ollama Provider 适配 | 1 天 | +| `AgentTool` trait + `ToolRegistry` + `ToolContext` + `DisplayHint` | 0.5 天 | +| `AgentOrchestrator` ReAct 循环 | 0.5 天 | +| erp-core `HealthDataQuery` trait 定义 + erp-health 实现 | 1 天 | +| 数据库迁移:`ai_chat_sessions` + `ai_chat_messages` + `ai_tool_call_logs` + `ai_user_profiles` | 0.5 天 | | 实现 1 个 Tool:`query_patient_vitals`(验证端到端链路) | 0.5 天 | | 改造 `chat_handler`:接入 Orchestrator,替换原有简单逻辑 | 0.5 天 | | 单元测试 + 集成测试 | 0.5 天 | -**交付标准**:Postman 调用 `/ai/chat`,Agent 能查到患者体征数据并自然回复。 +**交付标准**:Postman 调用 `/api/v1/ai/chat/sessions/{id}/messages`,Agent 能查到患者体征数据并自然回复。 ### Phase 1:Tool 扩展 + 策略 Prompt(5-7 天) @@ -383,7 +536,7 @@ GET /api/v1/ai/chat/sessions/{id}/messages — 消息历史 **交付标准**:模拟 5 种典型场景(安抚/科普/推荐/预警/引导到院),Agent 均能自主选择正确策略和 Tool。 -### Phase 2:前端升级 + 流式输出(5-7 天) +### Phase 2:前端升级 + 流式输出(7-9 天) > 目标:小程序 + Web 都有完整 AI 客服体验 @@ -391,10 +544,12 @@ GET /api/v1/ai/chat/sessions/{id}/messages — 消息历史 |------|--------| | 后端:会话 CRUD API(创建/列表/历史消息) | 1 天 | | 后端:Agent 最终回复走 SSE 流式输出 | 1 天 | +| 小程序:SSE 兼容层(Taro 原生不支持 SSE,需用 `requestTask` 或轮询适配) | 1 天 | | 小程序:会话列表页 + 消息历史页 + 富消息渲染 | 2 天 | -| Web:同上,复用 API 模块 | 1.5 天 | +| Web:AI 客服页面从零构建(会话列表 + 聊天界面 + 富消息) | 2 天 | | 数据卡片渲染(体征趋势小图表) | 1 天 | -| 前端迁移:本地 Storage → DB 持久化 | 0.5 天 | +| 前端迁移:本地 Storage → DB 持久化 + 旧数据迁移脚本 | 0.5 天 | +| 端到端测试 | 0.5 天 | **交付标准**:小程序打开 AI 客服,能自然对话,能看到数据卡片,能看到流式输出。 @@ -415,18 +570,36 @@ GET /api/v1/ai/chat/sessions/{id}/messages — 消息历史 ### 总工期 ``` -Phase 0 ████████ (3-4天) +Phase 0 ████████████████ (5-6天) Phase 1 ████████████████ (5-7天) -Phase 2 ████████████████ (5-7天) +Phase 2 ████████████████████ (7-9天) Phase 3 ██████████ (3-5天) ──────────────────────── -合计 16-23 天 +合计 20-27 天 ``` 每个 Phase 结束后都有可演示的交付物。 --- +## 9. 故障处理与降级 + +| 故障场景 | 用户看到什么 | 处理方式 | +|----------|-------------|----------| +| 所有 Provider 不可用 | "小华暂时无法回复,请稍后再试" | 返回固定降级消息,记录到 usage_service | +| Agent 循环超时(60s) | 已生成的部分回复 + "回复被中断,请重新提问" | SSE 断流 + 超时日志 | +| 单个 Tool 执行超时(10s) | Agent 跳过该 Tool 继续推理 | ToolResult 返回错误摘要,Agent 可选择其他路径 | +| Ollama 不支持 Function Calling | 自动降级为纯文本 Prompt 模式 | Provider 层检测能力,无 Function Calling 时将 Tool 描述注入 System Prompt | +| LLM 返回无效 Tool Call | "抱歉,我刚才思考有误,请再说一次" | Orchestrator 捕获解析错误,返回重试提示 | + +--- + +## 10. 风险与缓解 + +每个 Phase 结束后都有可演示的交付物。 + +--- + ## 8. 风险与缓解 | 风险 | 概率 | 影响 | 缓解措施 |