情感陪伴Agent改造(上):数据库篇

🎯 本文将讲解我们项目如何从数据库查询老人信息,为AI提供"记忆"基础。


📖 背景

情感陪伴Agent要"认识"老人,首先得知道老人的信息从哪来。

答案很简单:数据库

🎯 需要查哪些表

表名查什么为什么需要
elderly姓名、性别、出生日期认识老人
disease疾病名称、描述了解病史,聊天时避免刺激
medication_plan药品名称、剂量了解用药情况
medical_record就诊记录陪诊时有参考
elderly_health_data血压、血糖等关心健康状况

🛠️ 设计数据结构

新建 ElderlyContext.java,作为老人信息的"容器":

@Data
public class ElderlyContext {
    
    private Long elderlyId;
    private String name;        // 张奶奶
    private String gender;      // 女
    private Integer age;        // 78岁
    
    private List<String> diseases;                    // 疾病列表
    private List<MedicationInfo> currentMedications;  // 用药列表
    private List<String> recentMedicalRecords;        // 就诊记录
    private HealthData latestHealthData;              // 健康数据
    
    @Data
    public static class MedicationInfo {
        private String drugName;
        private String dosage;
        private String usage;
        private String diseaseName;  // 用于治疗什么病
    }
    
    @Data
    public static class HealthData {
        private String bloodPressure;
        private String heartRate;
        private String bloodSugar;
        private String temperature;
        private String height;
        private String weight;
    }
}

🛠️ 实现查询服务

新建 ElderlyContextServiceImpl.java

1. 查老人基本信息

private void fillBasicInfo(ElderlyContext context, Elderly elderly) {
    context.setName(elderly.getName());
    context.setGender(elderly.getGender());
    
    // 计算年龄
    if (elderly.getBirthDate() != null) {
        context.setAge(Period.between(elderly.getBirthDate(), LocalDate.now()).getYears());
    }
}

2. 查疾病史

private List<String> getDiseases(Long elderlyId) {
    List<Disease> diseases = diseaseService.list(
        new LambdaQueryWrapper<Disease>()
            .eq(Disease::getElderlyId, elderlyId)
            .eq(Disease::getStatus, 1)
            .orderByDesc(Disease::getCreatedAt)
    );

    return diseases.stream()
        .map(d -> d.getDiseaseDesc() != null 
            ? d.getDiseaseName() + "(" + d.getDiseaseDesc() + ")"
            : d.getDiseaseName())
        .collect(Collectors.toList());
}

3. 查当前用药

private List<MedicationInfo> getMedications(Long elderlyId) {
    List<MedicationPlan> plans = medicationPlanService.list(
        new LambdaQueryWrapper<MedicationPlan>()
            .eq(MedicationPlan::getElderlyId, elderlyId)
            .eq(MedicationPlan::getStatus, 1)
    );

    return plans.stream().map(plan -> {
        MedicationInfo info = new MedicationInfo();
        info.setDrugName(plan.getDrugName());
        info.setDosage(plan.getDosage());
        info.setUsage(plan.getUsage());
        
        // 关联疾病名称
        Disease disease = diseaseService.getById(plan.getDiseaseId());
        if (disease != null) {
            info.setDiseaseName(disease.getDiseaseName());
        }
        return info;
    }).collect(Collectors.toList());
}

4. 查就诊记录

private List<String> getRecentMedicalRecords(Long elderlyId) {
    return medicalRecordService.list(
        new LambdaQueryWrapper<MedicalRecord>()
            .eq(MedicalRecord::getElderlyId, elderlyId)
            .orderByDesc(MedicalRecord::getVisitDate)
            .last("LIMIT 5")  // 只取最近5条
    ).stream().map(r -> {
        return String.join(" ", 
            r.getVisitDate() != null ? r.getVisitDate().toString() : "",
            r.getHospital() != null ? r.getHospital() : "",
            r.getDoctor() != null ? r.getDoctor() : "",
            r.getRecordTitle() != null ? r.getRecordTitle() : ""
        ).trim();
    }).collect(Collectors.toList());
}

5. 查健康数据

private HealthData getLatestHealthData(Long elderlyId) {
    ElderlyHealthData data = elderlyHealthDataService.getOne(
        new LambdaQueryWrapper<ElderlyHealthData>()
            .eq(ElderlyHealthData::getElderlyId, elderlyId)
            .orderByDesc(ElderlyHealthData::getCheckDate)
            .last("LIMIT 1")
    );

    if (data == null) return null;

    HealthData hd = new HealthData();
    if (data.getSystolicPressure() != null) {
        hd.setBloodPressure(data.getSystolicPressure() + "/" + data.getDiastolicPressure() + " mmHg");
    }
    if (data.getHeartRate() != null) {
        hd.setHeartRate(data.getHeartRate() + " 次/分");
    }
    return hd;
}

🛠️ 组装完整上下文

@Override
public ElderlyContext getFullContext(Long elderlyId) {
    Elderly elderly = elderlyService.getById(elderlyId);
    if (elderly == null || elderly.getStatus() != 1) {
        return null;
    }

    ElderlyContext context = new ElderlyContext();
    context.setElderlyId(elderlyId);
    
    fillBasicInfo(context, elderly);
    context.setDiseases(getDiseases(elderlyId));
    context.setCurrentMedications(getMedications(elderlyId));
    context.setRecentMedicalRecords(getRecentMedicalRecords(elderlyId));
    context.setLatestHealthData(getLatestHealthData(elderlyId));

    return context;
}

📊 查询流程图

getFullContext(elderlyId)
         │
         ├─→ elderly表 ──→ 姓名、性别、年龄
         │
         ├─→ disease表 ──→ 疾病列表
         │
         ├─→ medication_plan表 ──→ 用药列表
         │         │
         │         └─→ disease表 ──→ 关联疾病名称
         │
         ├─→ medical_record表 ──→ 就诊记录
         │
         └─→ elderly_health_data表 ──→ 健康数据
         
         ▼
   ElderlyContext(组装完成)

💡 注意事项

1. 只查启用状态的数据

.eq(Disease::getStatus, 1)  // 只查status=1的

2. 限制查询数量

.last("LIMIT 5")  // 避免数据过多

3. 处理空值

if (data == null) return null;
if (disease != null) { ... }

🎯 总结

这篇讲的是数据层工作:

  1. 设计 ElderlyContext 数据结构
  2. 从5张表查询信息
  3. 组装成统一的上下文对象

下一篇将是业务层——如何把这个上下文注入到AI的提示词中。


更多推荐