Files
hms/docs/superpowers/specs/2026-04-25-erp-ai-module-design.md
iven 9fabe39897
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
docs(ai): erp-ai 模块设计规格 — AI 智能分析流
新增 erp-ai 模块完整设计文档,涵盖:
- 模块架构(独立 crate,AiProvider trait 抽象)
- 请求驱动 SSE 流式管道 + 混合管道演进路线
- 数据脱敏与安全防护层
- Prompt 数据库管理 + 版本控制
- 4 种分析场景(化验单/趋势/方案/摘要)
- 3 张数据库表设计
- 4 Phase 扩展路线图
2026-04-25 12:29:00 +08:00

400 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.
# erp-ai 模块设计规格
> 日期: 2026-04-25 | 状态: 设计审批通过,待实施
> 技术架构演进方向: 实时能力层 → AI 智能分析流
---
## 1. 背景与目标
HMS 健康管理平台已完成全部基础模块和健康业务模块的开发。为提升患者端体验、降低医患沟通成本,引入 **AI 智能分析能力**,让患者在小程序端即可获得化验单解读、健康趋势分析、个性化体检方案和报告摘要等 AI 驱动的自助服务。
**核心目标:**
- 患者按需获取 AI 流式解读,无需等待医生电话
- 模型无关的 AI Gateway支持多提供商切换和 A/B 测试
- 严格数据脱敏PII 不离开服务器
- Prompt 模板数据库化管理,支持版本控制和回滚
- 架构预留异步分析管道,平滑演进到混合模式
---
## 2. 模块定位
### 2.1 在 HMS 架构中的位置
```
erp-core (ErpModule trait + EventBus + AppState)
erp-health ──publish──→ {patient.lab-report.created, health.vital-signs.updated, ...}
erp-ai (NEW) ──subscribe──→ health 事件 (Phase 3 预留)
──publish──→ {ai.analysis.completed, ai.analysis.failed}
erp-server (组装入口)
```
### 2.2 为什么是独立模块而非内嵌
- AI 是跨横切平台能力,非健康专属(未来消息、工作流、客服都可能用)
- 遵循 CLAUDE.md 铁律:业务 crate 之间禁止直接依赖
- 通过 EventBus + `HealthDataProvider` trait 获取数据,模块边界清晰
- 提供商切换、成本管理、脱敏策略全部内聚在 erp-ai 内部
---
## 3. 架构设计
### 3.1 Crate 结构
```
crates/erp-ai/
├── Cargo.toml
└── src/
├── lib.rs # 模块入口, ErpModule impl
├── error.rs # AiError → AppError
├── provider/ # AI 提供商抽象
│ ├── mod.rs # AiProvider trait 定义
│ ├── claude.rs # Claude API 实现
│ ├── openai.rs # OpenAI API 实现 (Phase 2)
│ └── config.rs # 提供商配置 & 路由策略
├── pipeline/ # 分析管道
│ ├── mod.rs # AnalysisPipeline trait
│ ├── request.rs # 请求驱动管道 (Phase 1, SSE)
│ └── async.rs # 异步管道 (Phase 3, stub)
├── sanitization/ # 数据脱敏层
│ ├── mod.rs # DeIdentificationService
│ └── rules.rs # 脱敏规则
├── prompt/ # Prompt 管理
│ ├── mod.rs # PromptManager trait
│ └── template.rs # 模板渲染引擎
├── entity/ # SeaORM Entity
│ ├── ai_prompt.rs
│ ├── ai_analysis.rs
│ └── ai_usage.rs
├── service/ # 业务逻辑
│ ├── analysis.rs # AnalysisService (核心编排)
│ ├── prompt.rs # PromptService (CRUD + 版本)
│ └── usage.rs # UsageService (用量追踪)
└── handler/ # Axum 路由
├── mod.rs
├── analysis.rs # SSE 流式分析端点
├── prompt.rs # Prompt 管理 CRUD
└── usage.rs # 用量统计端点
```
### 3.2 核心抽象
```rust
/// AI 提供商 trait
#[async_trait]
pub trait AiProvider: Send + Sync {
async fn stream_generate(&self, req: GenerateRequest) -> Result<impl Stream<Item = Chunk>>;
async fn generate(&self, req: GenerateRequest) -> Result<GenerateResponse>;
fn name(&self) -> &str;
async fn health_check(&self) -> Result<bool>;
}
/// 分析管道 trait (Phase 1: RequestPipeline; Phase 3: + AsyncPipeline)
pub trait AnalysisPipeline: Send + Sync {
fn analyze(&self, ctx: AnalysisContext) -> impl Stream<Item = AnalysisChunk>;
}
/// 数据脱敏 trait
pub trait DataSanitizer: Send + Sync {
fn sanitize(&self, data: &serde_json::Value) -> Result<SanitizedData>;
}
```
### 3.3 erp-core 扩展
```rust
/// 新增到 erp-core由 erp-health 实现
pub trait HealthDataProvider: Send + Sync {
async fn get_report_by_id(&self, tenant_id: Uuid, report_id: Uuid) -> AppResult<LabReport>;
async fn get_vital_signs(&self, tenant_id: Uuid, patient_id: Uuid, metrics: &[String], range: TimeRange) -> AppResult<Vec<VitalSign>>;
async fn get_patient_summary(&self, tenant_id: Uuid, patient_id: Uuid) -> AppResult<PatientSummary>;
async fn get_full_report(&self, tenant_id: Uuid, report_id: Uuid) -> AppResult<HealthReport>;
}
/// 新增事件类型
pub enum AiEvent {
AnalysisCompleted { analysis_id: Uuid, patient_id: Uuid, analysis_type: String },
AnalysisFailed { analysis_id: Uuid, error: String },
}
/// 新增权限码
pub const AI_PERMISSIONS: &[&str] = &[
"ai.analysis.request",
"ai.analysis.view",
"ai.analysis.manage",
"ai.prompt.list",
"ai.prompt.manage",
"ai.usage.view",
"ai.admin.provider",
];
```
---
## 4. 数据流设计
### 4.1 请求驱动管道 (Phase 1)
```
患者点击"AI解读" → POST /api/v1/ai/analyze/lab-report
→ 鉴权 (JWT → tenant_id + user_id)
→ 权限检查 (ai.analysis.request)
→ 加载数据 (via HealthDataProvider trait)
→ DeIdentificationService.sanitize()
→ PromptManager.render(template, sanitized_data)
→ AiProvider.stream_generate(prompt)
→ SSE 流式返回给前端
→ 存储完整结果到 ai_analysis_results
→ 记录用量到 ai_usage_logs
→ 发布 ai.analysis.completed 事件
```
### 4.2 SSE 事件格式
```
event: chunk
data: {"content": "您的血常规检查中,", "index": 1}
event: metadata
data: {"model": "claude-sonnet-4-6", "tokens": {"input": 856, "output": 423}, "duration_ms": 3200}
event: done
data: {"analysis_id": "uuid-xxx", "status": "completed"}
```
### 4.3 四种分析场景
| 场景 | 端点 | 输入 | Prompt 模板 |
|------|------|------|------------|
| 化验单解读 | `POST /ai/analyze/lab-report` | report_id | lab_report_interpretation |
| 趋势分析 | `POST /ai/analyze/trends` | patient_id + metrics + 时间范围 | health_trend_analysis |
| 个性化方案 | `POST /ai/analyze/checkup-plan` | patient_id | personalized_checkup_plan |
| 报告摘要 | `POST /ai/analyze/report-summary` | report_id | report_summary_generation |
---
## 5. 数据库设计
### 5.1 ai_prompts
| 列 | 类型 | 说明 |
|----|------|------|
| id | UUID v7 | 主键 |
| tenant_id | UUID | 租户 |
| name | VARCHAR(100) | 模板标识 |
| description | TEXT | 用途描述 |
| system_prompt | TEXT | 系统角色 Prompt |
| user_prompt_template | TEXT | 用户 Prompt 模板 ({{variable}} 占位符) |
| variables_schema | JSONB | 模板变量 JSON Schema |
| model_config | JSONB | {provider, model, temperature, max_tokens} |
| version | INT | 语义版本(自增) |
| is_active | BOOLEAN | 当前激活版本 |
| category | VARCHAR(50) | analysis / summary / suggestion |
| tags | JSONB | 标签数组 |
| + 标准审计字段 | | tenant_id, created_at, updated_at, created_by, updated_by, deleted_at, version |
### 5.2 ai_analysis_results
| 列 | 类型 | 说明 |
|----|------|------|
| id | UUID v7 | 主键 |
| tenant_id | UUID | 租户 |
| patient_id | UUID | 患者 |
| analysis_type | VARCHAR(50) | lab_report / trend / checkup_plan / report_summary |
| source_ref | VARCHAR(200) | 来源引用 |
| prompt_id | UUID | 关联 Prompt |
| prompt_version | INT | Prompt 版本号 |
| model_used | VARCHAR(100) | 实际模型 |
| input_data_hash | VARCHAR(64) | SHA-256缓存键 |
| sanitized_input | JSONB | 脱敏输入快照(审计) |
| result_content | TEXT | AI 完整输出 |
| result_metadata | JSONB | tokens/耗时/模型信息 |
| status | VARCHAR(20) | pending / streaming / completed / failed |
| error_message | TEXT | 失败原因 |
| + 标准审计字段 | | |
### 5.3 ai_usage_logs
| 列 | 类型 | 说明 |
|----|------|------|
| id | UUID v7 | 主键 |
| tenant_id | UUID | 租户 |
| provider | VARCHAR(50) | claude / openai / local |
| model | VARCHAR(100) | 具体模型 |
| analysis_type | VARCHAR(50) | 分析类型 |
| input_tokens | INT | |
| output_tokens | INT | |
| duration_ms | INT | |
| cost_cents | INT | 费用(分) |
| is_cache_hit | BOOLEAN | |
| created_at | TIMESTAMP | |
---
## 6. 数据脱敏与安全
### 6.1 脱敏规则
- **移除**: 姓名、身份证号、手机号、地址、出生日期、医生姓名
- **泛化**: 精确年龄 → 年龄段 (18-30, 30-40, 40-50, ...)
- **保留**: 科室、检验指标、诊断编码、用药记录、家族史
### 6.2 安全防护层
1. **速率限制**: 患者端 10次/天/人,管理端 100次/小时/租户 (Redis Token Bucket)
2. **输入验证**: schema 校验,租户隔离校验
3. **Prompt 注入防护**: JSON 序列化注入,不做字符串拼接
4. **输出过滤**: 正则扫描处方药推荐/诊断结论,强制追加免责声明
5. **审计日志**: sanitized_input 保留脱敏快照
### 6.3 降级策略
```
缓存命中 → 直接返回
缓存未命中 + AI 可用 → 正常 SSE
缓存未命中 + AI 不可用 + 有旧版本 → 返回旧结果 + 标注
缓存未命中 + AI 不可用 + 无历史 → 本地规则引擎50 条常见指标)
```
---
## 7. API 设计
```
/api/v1/ai/
├── analyze/
│ ├── POST /lab-report SSE 化验单解读
│ ├── POST /trends SSE 健康趋势分析
│ ├── POST /checkup-plan SSE 个性化体检方案
│ └── POST /report-summary SSE 报告摘要生成
├── analysis/
│ ├── GET /history JSON 分析历史列表
│ └── GET /:id JSON 分析详情
├── prompts/ (需 ai.prompt.manage)
│ ├── GET / JSON Prompt 列表
│ ├── POST / JSON 新建 Prompt
│ ├── GET /:id JSON Prompt 详情
│ ├── PUT /:id JSON 编辑 (自动+1版本)
│ ├── POST /:id/activate JSON 激活指定版本
│ ├── GET /:id/versions JSON 版本历史
│ └── POST /:id/rollback JSON 回滚
├── usage/ (需 ai.usage.view)
│ ├── GET /stats JSON 用量统计
│ ├── GET /costs JSON 费用明细
│ └── GET /models JSON 模型分布
└── admin/
├── GET /providers JSON 提供商状态
├── PUT /providers/:name/config JSON 更新配置
└── POST /providers/:name/test JSON 连通性测试
```
---
## 8. 前端设计
### 8.1 小程序 (Phase 1)
- 报告详情页新增「AI 智能解读」卡片,引导点击
- 新增 AI 解读展示页SSE 逐字流式渲染
- 历史解读列表(点击查看过往分析)
### 8.2 Web 管理后台 (Phase 2)
- AI Prompt 管理页面:列表/编辑/版本历史/diff 对比/回滚
- AI 用量统计仪表盘:按天/模型/场景维度
- 提供商状态与配置管理
---
## 9. 扩展路线图
### Phase 1 — MVP (约 2-3 周)
- erp-ai crate 骨架 + ErpModule 实现
- AiProvider trait + Claude SSE 实现
- DeIdentificationService
- PromptManager + 3 张表 + migration
- 4 个分析端点
- 缓存 + 降级规则引擎
- 小程序 AI 解读功能
- 速率限制 + 审计日志
### Phase 2 — 运营强化 (约 2 周)
- Web Prompt 管理完整 UI
- 版本 diff 对比 + 回滚
- 用量统计仪表盘
- OpenAI 提供商实现
- 成本告警
- 分享功能
### Phase 3 — 混合管道 (约 2-3 周)
- AsyncAnalysisPipeline 实现
- EventBus 订阅 health 事件
- 后台预分析队列
- 消息中心通知集成
- WebSocket StreamingProvider 实现
- 本地模型对接 (Ollama/vLLM)
### Phase 4 — 智能化 (持续)
- Prompt A/B 测试
- 分析效果评分
- 多轮对话式解读
- 多模态输入 (OCR)
- 知识库 RAG
### Phase 1 架构预留点
| 预留点 | 位置 | 做法 |
|--------|------|------|
| AnalysisPipeline trait | pipeline/mod.rs | RequestPipeline 唯一实现Phase 3 加 AsyncPipeline |
| StreamingProvider trait | provider/mod.rs | SSE 唯一实现Phase 3 加 WebSocket |
| AnalysisContext.trigger | pipeline/mod.rs | 枚举 Request \| EventPhase 3 加 Event |
| HealthDataProvider trait | erp-core | erp-health 实现erp-ai 注入使用 |
| 事件发布 | service/analysis.rs | 完成后发布事件Phase 1 无消费者也发布 |
| model_config 字段 | ai_prompts 表 | 每模板独立配置 provider/model |
---
## 10. 关键文件清单
| 区域 | 文件 | 操作 |
|------|------|------|
| erp-core | `src/trait.rs` | 新增 HealthDataProvider trait |
| erp-core | `src/event.rs` | 新增 ai.* 事件类型 |
| erp-core | `src/permission.rs` | 新增 ai.* 权限码 |
| erp-health | `src/ai_provider.rs` | 新增 HealthDataProvider impl |
| erp-ai | 整个 crate | 新建 |
| erp-server | `src/main.rs` | 注册 AiModule |
| erp-server/migration | 新增 migration | 3 张表 |
| apps/miniprogram | 报告详情页 + 解读页 | 新增/修改 |
| apps/web | Prompt 管理页面 | Phase 2 新增 |
---
## 11. 验证方案
### 后端验证
- `cargo check` — 全 workspace 编译通过
- `cargo test -p erp-ai` — 单元测试覆盖 provider/sanitization/prompt/service
- 启动后端服务,通过 curl 测试 SSE 端点流式输出
- 通过 Swagger UI 测试 Prompt CRUD 和用量统计端点
### 小程序验证
- 打开报告详情页确认「AI 解读」卡片展示
- 点击触发 SSE 流式渲染,确认逐字输出效果
- 测试缓存命中(第二次请求秒返回)
- 测试降级(停止 AI 服务后请求,确认降级提示)
### 安全验证
- 确认发送给 AI 的数据不包含 PII
- 确认速率限制生效(超过 10 次返回 429
- 确认审计日志完整记录