Files
hms/wiki/erp-ai.md
iven 049d230bae
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(wiki): 更新 erp-ai 模块 — Ollama 对接 + bug 修复记录
- index.md: 迁移 123 个, 提交 577 次, 新增 AI 分析症状导航 4 条
- erp-ai.md: 新增 §4 Ollama 本地模型对接、已知限制、已修复 bug
- erp-ai.md: 更新 SSE 流程图(预校验 + 缓存回放修复)
- erp-ai.md: 3 个管理前端页面已实现
2026-05-05 20:07:24 +08:00

188 lines
7.1 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.
---
title: erp-ai AI 分析模块
updated: 2026-05-05
status: in-development
tags: [ai, llm, sse, health-analysis, ollama]
---
# erp-ai AI 分析模块
> 从 [[index]] 导航。关联: [[erp-health]] [[erp-core]] [[erp-server]]
>
> 设计规格: `docs/superpowers/specs/2026-04-25-erp-ai-module-design.md`
## 1. 设计决策
### 为什么需要 AI 模块?
健康管理平台需要为医护人员提供智能辅助分析能力:化验单解读、健康趋势分析、体检方案推荐、报告摘要生成。这些能力需要一个独立的模块来管理 AI 提供商、Prompt 模板和用量追踪。
### 核心架构选择
- **原生 Rust crate** — 与 erp-health 同级,直接调用数据库和事件总线
- **ErpModule trait 实现** — `AiModule` 在 erp-server 注册,路由挂载到 `/api/v1/ai`
- **SSE 流式响应** — 所有分析端点使用 Server-Sent Events 实时推送
- **多提供商支持** — AiProvider trait 抽象,已实现 Claude (Anthropic)、Ollama (本地)、OpenAI
- **数据脱敏** — 发送前自动移除患者 PII姓名、身份证、手机号
- **分析预校验** — 触发分析前校验数据完整性items/sections 为空时直接返回 400
- **非对话化 Prompt** — 迁移 000123 更新所有 prompt 为结构化输出格式
## 2. 关键文件 + 数据流
### 目录结构
```
crates/erp-ai/
├── src/
│ ├── lib.rs ← 模块导出 (AiModule, AiState, AiError)
│ ├── module.rs ← ErpModule trait 实现, 6 权限码, 路由定义
│ ├── error.rs ← AiError → AppError (59 行)
│ ├── state.rs ← AiState { db, event_bus, provider }
│ ├── dto.rs ← 请求/响应 DTO (102 行)
│ ├── provider/
│ │ ├── mod.rs ← AiProvider trait 定义
│ │ └── claude.rs ← Claude SSE 流式实现 (227 行)
│ ├── service/
│ │ ├── analysis.rs ← AnalysisService 核心编排 (183 行)
│ │ ├── prompt.rs ← PromptService 模板渲染 (67 行)
│ │ └── usage.rs ← UsageService 用量追踪 (45 行)
│ ├── handler/
│ │ └── mod.rs ← 6 个 SSE + REST 端点 (340 行)
│ ├── prompt/
│ │ └── mod.rs ← Prompt 模板引擎 (25 行)
│ └── entity/
│ ├── ai_prompt.rs ← Prompt 模板 Entity
│ ├── ai_analysis.rs ← 分析结果 Entity
│ └── ai_usage.rs ← 用量日志 Entity
```
### 实体模型6 个实体)
| 实体 | 用途 |
|------|------|
| ai_prompt | Prompt 模板(版本管理、激活/回滚) |
| ai_analysis | 分析结果记录输入参数、输出摘要、token 用量) |
| ai_usage | 用量追踪(按租户/用户聚合) |
| ai_suggestion | AI 建议记录(风险分级、建议内容、状态跟踪) |
| ai_risk_threshold | 风险阈值配置(按指标定义临界值) |
| ai_action | AI 行动分发(从建议到行动的闭环跟踪) |
### 权限码6 个)
| 权限码 | 说明 |
|--------|------|
| `ai.analysis.list` / `ai.analysis.manage` | 查看分析历史 / 发起分析 |
| `ai.prompt.list` / `ai.prompt.manage` | 查看 Prompt / 管理 Prompt |
| `ai.usage.list` | 查看用量统计 |
| `ai.provider.manage` | 管理提供商配置 |
### API 端点: `/api/v1/ai/`
| 端点 | 方法 | 说明 |
|------|------|------|
| `/ai/analyze/lab-report` | POST | 化验单智能解读SSE |
| `/ai/analyze/trends` | POST | 健康趋势分析SSE |
| `/ai/analyze/checkup-plan` | POST | 体检方案推荐SSE |
| `/ai/analyze/report-summary` | POST | 报告摘要生成SSE |
| `/ai/analysis/history` | GET | 分析历史列表 |
| `/ai/analysis/{id}` | GET | 分析结果详情 |
### 集成契约
| 方向 | 模块 | 接口 | 触发时机 |
|------|------|------|---------|
| 依赖 → | [[erp-health]] | 健康数据查询 | 分析时读取患者数据 |
| 依赖 → | [[erp-core]] | EventBus, AppError | 模块注册 |
| 注册 → | [[erp-server]] | `AiModule` | 启动时注册 |
## 3. 代码逻辑
### SSE 流式分析流程
```
客户端 POST → handler::stream_*()
→ 预校验: items/sections 为空 → 400 直接拒绝
→ sanitization: 移除 PII (姓名→患者, 身份证→***)
→ PromptService: 加载激活模板 + 渲染变量
→ AnalysisService: 编排分析流程
→ 检查缓存: 相同输入 + prompt 版本 → 复用已有结果(直接回放纯文本)
→ AiProvider::stream(): 调用 LLM APIOllama/Claude/OpenAI
→ 逐 chunk SSE 推送: data: { "content": "..." }
→ AnalysisService: 保存结果到 ai_analysis已完成的跳过
→ 后处理: 解析建议、发布事件
→ SSE done
```
### 数据脱敏
发送给 LLM 的数据经过脱敏处理:
- 患者姓名 → "患者"
- 身份证号 → 全掩码
- 手机号 → `138****1234` 格式
### 模块依赖
`AiModule` 声明依赖 `["health"]`,确保健康模块先于 AI 模块初始化。
**不变量**: 所有发送到外部 LLM 的数据必须经过 PII 脱敏
**不变量**: SSE 连接超时必须设置,避免挂起
**不变量**: 用量追踪必须记录,用于计费和审计
## 4. Ollama 本地模型对接
### 配置方式
`crates/erp-server/config/default.toml`:
```toml
[ai]
default_provider = "ollama"
model = "qwen3:4b"
[ai.providers.ollama]
provider_type = "ollama"
base_url = "http://localhost:11434"
default_model = "qwen3:4b"
max_tokens = 2048
temperature = 0.3
is_enabled = true
```
### 已知限制
| 问题 | 说明 |
|------|------|
| qwen3-vl:4b 无法运行 | Ollama 已知 bug#13101VL 模型内存估算异常3.3GB 模型要求 38.3 GiB |
| qwen3:4b 思考模式 | 模型内置 `<think/>` 标签,首次响应可能延迟 |
| 无图像识别能力 | 当前所有分析使用结构化数据库数据,不需要 VL 模型 |
| Prompt 模板 model_config | DB 中 `ai_prompt.model_config.model` 优先级高于全局配置,需同步更新 |
### 已修复的 bug
| Bug | 修复 |
|-----|------|
| 缓存回放 JSON 嵌套 | `replay_cached` 直接回放纯文本;`complete_analysis` 跳过已完成记录 |
| 分析返回对话式回复 | 迁移 000123 更新 prompt 为非对话、结构化输出 |
| 空数据触发无效分析 | handler 层预校验 items/sections 非空 |
## 5. 活跃问题 + 陷阱
### 当前状态: 🔧 开发中
6 个 API 端点已实现SSE 流式分析可用,已对接本地 Ollama。前端 3 个管理页面已实现Prompt 管理、分析历史、用量统计)。当前为 Phase 1 MVP。
### 待完善
| 问题 | 级别 | 说明 |
|------|------|------|
| 小程序端集成 | P2 | 患者端查看 AI 分析结果 |
| 用量配额限制 | P1 | 按租户设置用量上限 |
| 化验报告必填项 | P1 | 后端校验已加,前端录入表单也应对应设置必填 |
## 6. 变更记录
| 日期 | 变更 |
|------|------|
| 2026-05-05 | 对接本地 Ollama qwen3:4b修复缓存回放 JSON 嵌套 bug预校验 + prompt 非对话化 |
| 2026-04-25 | 创建 erp-ai wiki 页面 |