2026山东大学软件学院创新实训——IntelliHealth(五)

概要

本周主要完成了用户画像与智能分析模块的代码实现。和上周的调研相比,这周的重点从“方案设计”转到了“后端功能落地”,主要包括用户画像建模与更新、画像偏移计算、个性化健康建议生成,以及连续健康指标的趋势分析与短期预测。

目前画像更新接口已经可以在新增健康记录后重新计算特征向量,并返回本次画像变化情况;趋势预测部分也完成了以体重为代表的短期预测接口,同时提供了过去至少 90 天连续健康趋势图的数据接口。

一、用户画像建模与更新逻辑

核心要点

用户画像并不是简单地给用户贴几个标签,而是要把用户的静态信息和动态健康记录结合起来。系统中主要用到了两类数据:

  • HealthProfile:用户的基础档案,例如年龄、性别、身高、目标体重、慢病、过敏史、健康目标等。
  • HealthRecord:用户每天或每次录入的动态记录,例如体重、BMI、心率、睡眠、血压、血糖、疲劳等级、压力水平等。

这次实现时,我把画像设计成了统一的特征向量。这样做的好处是后续无论是健康建议、趋势预测,还是提醒系统,都可以直接复用这组特征。

画像特征向量设计

画像向量主要包含以下几类特征:

特征类型 具体字段 作用
基础特征 年龄、身高、目标体重 表示用户长期稳定信息
生理特征 BMI、体重、心率、血压、血糖 判断当前健康状态
行为特征 睡眠时长、疲劳等级、压力水平 反映近期生活状态
风险特征 体重偏移、睡眠不足、疲劳风险等 用于后续建议生成

实际保存时,画像中包含特征名、特征向量、上一版基准向量、偏移向量和偏移幅度。

@Document(collection = "user_health_portraits")
public class UserHealthPortrait {
    @Id
    private String id;

    private String userId;
    private List<String> featureNames;
    private List<Double> featureVector;
    private List<Double> baselineVector;
    private List<Double> deltaVector;

    private Double shiftMagnitude;
    private Long updateDurationMs;
    private Boolean updateWithinTarget;

    private Integer sampleCount;
    private List<String> tags;
    private Instant updatedAt;
}

画像更新流程如下:

新增健康记录

读取用户档案

读取最近健康记录

归一化各项指标

生成当前画像向量

与上一版画像做差

计算偏移幅度

保存画像并返回结果

更新逻辑

画像更新的核心目标是:新数据输入后,画像特征向量的偏移计算在 3 秒内完成。

因此这里没有采用复杂模型,而是使用了比较轻量的统计方式:

  1. 读取用户最近的健康记录。
  2. 对 BMI、体重、睡眠、心率、血压、血糖等指标做标准化。
  3. 得到当前版本的 featureVector
  4. 和上一版 baselineVector 做差,得到 deltaVector
  5. 使用欧氏距离计算整体偏移幅度。

偏移计算公式如下:

deltaVector = featureVector - baselineVector

shiftMagnitude = sqrt(Σ(delta_i ^ 2))

接口返回中会带上本次计算耗时:

{
  "userId": "u1001",
  "shiftMagnitude": 0.28,
  "updateDurationMs": 15,
  "updateWithinTarget": true,
  "sampleCount": 90,
  "tags": ["sleep_attention", "fatigue_risk"]
}

这里的 updateWithinTarget 就是用来判断是否满足 3 秒要求的。

二、个性化健康建议生成

核心要点

健康建议部分没有直接使用黑盒模型,而是先采用“规则判断 + 优先级排序”的方式实现。这样比较适合当前阶段,因为每条建议都能说清楚是因为什么触发的。

当前已经支持的建议类型包括:

  • 疲劳干预建议
  • 用药提醒建议
  • 心率、血压等生命体征复测建议
  • 血糖和饮食建议
  • 体重目标跟踪建议

大致逻辑如下:

if (fatigueRiskHigh) {
    advices.add(advice(
        "FATIGUE",
        "HIGH",
        "疲劳风险偏高",
        "建议暂停连续用眼,并安排短时间休息"
    ));
}

if (hasMedicationRelatedTag) {
    advices.add(advice(
        "MEDICATION",
        "MEDIUM",
        "注意按时用药",
        "建议结合用药计划设置提醒"
    ));
}

这部分实现之后,前端就可以直接通过接口获取建议列表,不需要自己再判断各种健康规则。

主要接口为:

GET /api/health/analysis/advice?userId=u1001

三、健康趋势分析与预测

核心要点

趋势分析部分主要围绕连续生理指标展开,目前先以体重为重点实现。考虑到当前数据规模还不算大,所以我没有一开始就使用很重的预测模型,而是采用了比较稳定的加权移动平均和线性趋势结合的方法。

整体思路是:

  1. 先按日期聚合健康记录。
  2. 对缺失日期进行补齐,保证图表能连续展示。
  3. 使用最近数据计算加权移动平均。
  4. 再根据近期变化斜率预测未来几天的趋势。
  5. 使用历史回测计算 MAPE,判断误差是否控制在 5% 以内。

预测部分的核心形式如下:

predicted = smoothedValue + slope * i

其中:

  • smoothedValue 表示加权平滑后的当前指标值。
  • slope 表示最近一段时间的变化趋势。
  • i 表示预测未来第几天。

误差评价使用 MAPE:

MAPE = (1 / n) * Σ |actual - predicted| / actual * 100%

接口返回中会带上预测是否达标:

{
  "metric": "weight",
  "meanAbsolutePercentageError": 3.42,
  "targetAchieved": true,
  "history": [],
  "prediction": []
}

主要接口为:

GET /api/health/analysis/trends/predict?userId=u1001&metric=weight&days=90&horizonDays=7

四、90 天趋势图后台数据接口

核心要点

除了预测接口,还实现了一个专门给前端画图使用的数据接口。这个接口会返回至少 90 天的连续数据点,避免前端在画折线图时因为某些日期没有记录而断开。

GET /api/health/analysis/trends/chart?userId=u1001&days=90

返回的数据包括:

  • 体重
  • BMI
  • 心率
  • 睡眠时长
  • 血糖
  • 疲劳等级
  • 压力水平

整体流程如下:

查询最近健康记录

按日期聚合

补齐缺失日期

生成连续趋势点

返回图表数据

前端绘制折线图

总结与收获

这周最大的收获是把上周的画像和趋势预测方案真正写进了项目里。画像模块一开始看起来比较抽象,但落到代码里之后,本质上就是把用户长期信息和最近健康记录统一成一组可以计算的向量。

趋势预测也是类似,当前阶段不一定要追求很复杂的模型,先保证数据连续、结果稳定、误差可解释会更重要。

下周计划

下周计划开始实现智能提醒系统的后端部分,主要包括:

  • 设计提醒任务的数据模型。
  • 实现疲劳提醒、服药提醒、药物过期提醒三类提醒。
  • 完成提醒任务的创建、查询、启用、停用和删除接口。
  • 实现提醒触发日志记录。
  • 为后续前端提醒页面和 Android 定时任务预留接口。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐