背景

用药安全审核的核心问题是:新药和正在吃的药会不会冲突?

原来的方案是让用户手动输入当前用药,但:

  • 老人可能记不全
  • 药名太专业可能说错
  • 每次都要重复输入

数据库里明明有用药计划表,为什么不让AI自己查?


需要查哪些表

表名查什么为什么需要
elderly姓名、年龄高龄患者用药需特别注意
disease疾病名称了解治疗背景
medication_plan药品名称、剂量、用法核心:当前用药
elderly_health_data血压、血糖辅助判断用药风险

数据结构设计

复用 ElderlyContext,重点关注 MedicationInfo:

@Data
public class ElderlyContext {
    
    private String name;
    private Integer age;
    
    private List<String> diseases;
    private List<MedicationInfo> currentMedications;  // 重点
    private HealthData latestHealthData;
    
    @Data
    public static class MedicationInfo {
        private String drugName;    // 药品名称
        private String dosage;      // 剂量
        private String usage;       // 用法
        private String diseaseName; // 用于治疗什么病
    }
}

实现用药查询

查询当前用药

private List<MedicationInfo> getMedications(Long elderlyId) {
    // 1. 查询用药计划表
    List<MedicationPlan> plans = medicationPlanService.list(
        new LambdaQueryWrapper<MedicationPlan>()
            .eq(MedicationPlan::getElderlyId, elderlyId)
            .eq(MedicationPlan::getStatus, 1)  // 只查启用的
            .orderByDesc(MedicationPlan::getCreatedAt)
    );

    // 2. 转换为MedicationInfo
    List<MedicationInfo> result = new ArrayList<>();
    for (MedicationPlan plan : plans) {
        MedicationInfo info = new MedicationInfo();
        info.setDrugName(plan.getDrugName());
        info.setDosage(plan.getDosage());
        info.setUsage(plan.getUsage());

        // 3. 关联查询疾病名称
        Disease disease = diseaseService.getById(plan.getDiseaseId());
        if (disease != null) {
            info.setDiseaseName(disease.getDiseaseName());
        }

        result.add(info);
    }
    return result;
}

查询结果示例

[
  {
    "drugName": "降压药A",
    "dosage": "10mg/次",
    "usage": "口服",
    "diseaseName": "高血压"
  },
  {
    "drugName": "活血药B",
    "dosage": null,
    "usage": "口服",
    "diseaseName": "冠心病"
  },
  {
    "drugName": "降糖药C",
    "dosage": "500mg/次",
    "usage": "口服",
    "diseaseName": "2型糖尿病"
  }
]

格式化输出

提供方法将用药信息格式化为字符串:

public String toMedicationInfoString() {
    if (currentMedications == null || currentMedications.isEmpty()) {
        return "\n【当前用药】\n- 无\n";
    }
    
    StringBuilder sb = new StringBuilder();
    sb.append("\n【当前用药】\n");
    for (MedicationInfo med : currentMedications) {
        sb.append("- ").append(med.getDrugName());
        if (med.getDosage() != null) {
            sb.append(",剂量:").append(med.getDosage());
        }
        if (med.getUsage() != null) {
            sb.append(",用法:").append(med.getUsage());
        }
        if (med.getDiseaseName() != null) {
            sb.append("(用于治疗:").append(med.getDiseaseName()).append(")");
        }
        sb.append("\n");
    }
    return sb.toString();
}

输出示例:

【当前用药】
- 降压药A,剂量:10mg/次,用法:口服(用于治疗:高血压)
- 活血药B,用法:口服(用于治疗:冠心病)
- 降糖药C,剂量:500mg/次,用法:口服(用于治疗:2型糖尿病)

查询流程

getFullContext(elderlyId)
         │
         ├─→ elderly表 ──→ 姓名、年龄
         │
         ├─→ disease表 ──→ 疾病列表
         │
         ├─→ medication_plan表 ──→ 用药计划列表
         │         │
         │         └─→ disease表 ──→ 关联疾病名称
         │
         └─→ elderly_health_data表 ──→ 健康数据
         
         ▼
   ElderlyContext
         │
         ▼
   toMedicationInfoString()
         │
         ▼
   【当前用药】
   - 降压药A,剂量:10mg/次...

优化点

1. 批量查询避免N+1

// ❌ 循环中逐个查询疾病
for (MedicationPlan plan : plans) {
    Disease disease = diseaseService.getById(plan.getDiseaseId());
}

// ✅ 批量查询
List<Long> diseaseIds = plans.stream()
    .map(MedicationPlan::getDiseaseId)
    .distinct()
    .collect(Collectors.toList());
    
Map<Long, Disease> diseaseMap = diseaseService.listByIds(diseaseIds)
    .stream()
    .collect(Collectors.toMap(Disease::getId, d -> d));

// 使用时直接从Map获取
Disease disease = diseaseMap.get(plan.getDiseaseId());

2. 处理空值

// 用药信息为空时的处理
if (currentMedications == null || currentMedications.isEmpty()) {
    return List.of("无");
}

总结

这篇讲的是用药安全审核Agent的数据层工作:

  1. 从 medication_plan 表查询当前用药
  2. 关联 disease 表获取疾病名称
  3. 格式化为AI可理解的文本

更多推荐