docs(ai): erp-ai 模块设计规格 — AI 智能分析流
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

新增 erp-ai 模块完整设计文档,涵盖:
- 模块架构(独立 crate,AiProvider trait 抽象)
- 请求驱动 SSE 流式管道 + 混合管道演进路线
- 数据脱敏与安全防护层
- Prompt 数据库管理 + 版本控制
- 4 种分析场景(化验单/趋势/方案/摘要)
- 3 张数据库表设计
- 4 Phase 扩展路线图
This commit is contained in:
iven
2026-04-25 12:29:00 +08:00
parent 40b5141832
commit 9fabe39897

View File

@@ -0,0 +1,399 @@
# 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
- 确认审计日志完整记录