Files
hms/crates/erp-core/src/health_provider.rs
iven b2053d5bcc feat(ai): Phase 2A-4 新增 3 个 Agent Tool — 化验报告/预约/用药查询
新增 3 个 AI Agent Tool 扩展医护沙箱能力:
- query_patient_lab_reports: 查询患者化验报告列表(含异常计数)
- query_patient_appointments: 查询患者即将到来的预约
- query_patient_medications: 查询患者当前用药列表

同时:
- HealthDataProvider trait 新增 get_patient_lab_reports 方法 + LabReportListItemDto
- erp-health 实现新 trait 方法(含 PII 解密)
- sandbox.rs 更新角色权限:Patient 可查体征/化验/用药,MedicalStaff 额外可查预约
- 修复 ai_prompt_tests.rs 中 AnalysisService::new 签名变更的遗留编译错误
- 新增 5 个 agent 测试覆盖新 Tool 和沙箱权限过滤
2026-05-19 00:19:10 +08:00

203 lines
5.1 KiB
Rust
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.
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::error::AppResult;
/// 健康数据提供者 trait由 erp-health 实现
/// 返回的 DTO 已脱去 PII姓名、身份证号等只包含年龄/性别/医疗数据
#[async_trait]
pub trait HealthDataProvider: Send + Sync {
/// 获取化验报告(指标列表)
async fn get_lab_report(&self, tenant_id: Uuid, report_id: Uuid) -> AppResult<LabReportDto>;
/// 获取生命体征趋势数据
async fn get_vital_signs(
&self,
tenant_id: Uuid,
patient_id: Uuid,
metrics: &[String],
range: &TimeRange,
) -> AppResult<Vec<VitalSignDto>>;
/// 获取患者摘要(用于个性化方案)
async fn get_patient_summary(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<PatientSummaryDto>;
/// 获取完整健康报告(用于摘要生成)
async fn get_full_report(&self, tenant_id: Uuid, report_id: Uuid)
-> AppResult<HealthReportDto>;
/// 获取趋势分析预计算数据(统计摘要 + 异常检测)
async fn get_trend_analysis_data(
&self,
tenant_id: Uuid,
patient_id: Uuid,
metrics: &[String],
range: &TimeRange,
) -> AppResult<TrendAnalysisDto>;
/// 获取患者即将到来的预约
async fn get_upcoming_appointments(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<Vec<AppointmentSummaryDto>>;
/// 获取患者当前用药列表
async fn get_medication_list(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<Vec<MedicationSummaryDto>>;
/// 获取患者化验报告列表(简要摘要,不含指标明细)
async fn get_patient_lab_reports(
&self,
tenant_id: Uuid,
patient_id: Uuid,
limit: u64,
) -> AppResult<Vec<LabReportListItemDto>>;
}
// === DTO 定义 ===
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
pub start: chrono::DateTime<chrono::Utc>,
pub end: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabReportDto {
pub age_group: String,
pub sex: String,
pub department: String,
pub report_date: String,
pub items: Vec<LabItemDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabItemDto {
pub name: String,
pub value: f64,
pub unit: String,
pub reference_range: String,
pub is_abnormal: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VitalSignDto {
pub metric: String,
pub values: Vec<(String, f64)>,
pub unit: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PatientSummaryDto {
pub age_group: String,
pub sex: String,
pub chronic_conditions: Vec<String>,
pub medications: Vec<String>,
pub family_history: Vec<String>,
pub last_checkup_date: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReportDto {
pub age_group: String,
pub sex: String,
pub department: String,
pub report_date: String,
pub sections: Vec<ReportSectionDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSectionDto {
pub title: String,
pub findings: Vec<String>,
pub abnormal_items: Vec<String>,
}
// === 趋势分析 DTO ===
/// 趋势方向
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TrendDirection {
Rising,
Falling,
Stable,
}
/// 趋势分析整体 DTO
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrendAnalysisDto {
pub patient_id: Uuid,
pub period_start: String,
pub period_end: String,
pub metrics: Vec<MetricTrendAnalysis>,
}
/// 单个指标的趋势分析结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricTrendAnalysis {
pub metric: String,
pub unit: String,
pub data_point_count: usize,
/// 线性回归统计(数据不足时为 None
pub regression: Option<RegressionStats>,
/// 检测到的异常点
pub anomalies: Vec<AnomalyInfo>,
}
/// 线性回归统计摘要
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionStats {
pub slope: f64,
pub intercept: f64,
pub r_squared: f64,
pub direction: TrendDirection,
pub daily_change: f64,
pub period_change: f64,
}
/// 异常点信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyInfo {
pub date: String,
pub value: f64,
pub mean: f64,
pub std_dev: f64,
pub deviation: f64,
}
// === Agent 新增 DTO ===
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppointmentSummaryDto {
pub id: Uuid,
pub department: String,
pub doctor_name: String,
pub scheduled_at: String,
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MedicationSummaryDto {
pub name: String,
pub dosage: String,
pub frequency: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabReportListItemDto {
pub id: Uuid,
pub report_type: String,
pub report_date: String,
pub abnormal_count: usize,
}