Files
ljwx-health/docs/02-architecture/phase2-behavioral-profile-architecture.md
T
brunoandClaude Sonnet 4.5 332c032ef9
CI/CD Pipeline / test-admin (push) Waiting to run
CI/CD Pipeline / test-bigscreen (push) Waiting to run
CI/CD Pipeline / build-push (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / update-deploy (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / security-scan (push) Has been cancelled
CI/CD Pipeline / test-build-boot (push) Has been cancelled
feat: 健康监测系统架构升级 - Profile层、风险评估、质量告警
新增核心功能:
- 健康画像生成系统(用户/部门/组织基线)
- 风险评估框架(心血管/运动/呼吸/睡眠)
- 行为画像分析(饮食/运动/睡眠/健康关注度)
- 数据质量评分和告警

数据库迁移:
- V1.3.0~V1.7.0 健康监测表结构

前端增强:
- ljwx-admin: BigScreen集成、健康搜索优化
- ljwx-bigscreen: SSO认证、登录界面

文档体系:
- 强制文档管理规范(kebab-case、分类、Git hooks)
- 架构文档、开发指南、运维手册
- 工程蓝图 v2.1

CI/CD:
- 文档验证工作流
- 生产就绪性检查脚本
- 完整测试覆盖

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-20 21:06:00 +08:00

35 KiB

Phase 2 Sprint 8 - 行为画像系统架构设计

文档信息

项目 内容
文档标题 行为画像系统架构设计
版本 v1.0
创建日期 2026-01-20
作者 Backend Dev 1 (Claude Code Sonnet 4.5)
状态 ✅ 设计评审通过
关联任务 T2.2.1 - 行为画像架构设计

📋 目录

  1. 系统概述
  2. 四类行为维度设计
  3. 核心算法设计
  4. 数据模型设计
  5. 服务架构设计
  6. 数据库设计
  7. API 设计
  8. 数据流架构
  9. 集成方案

系统概述

业务目标

行为画像系统旨在通过分析用户的健康相关行为数据,识别用户的行为模式和习惯特征,为个性化健康干预提供依据。

核心价值

  1. 行为模式识别: 自动识别用户的运动、睡眠、饮食、健康关注等行为模式
  2. 个性化洞察: 基于行为数据生成个性化的健康建议
  3. 趋势预测: 识别行为趋势变化,提前预警不健康行为
  4. 干预基础: 为 AI 健康顾问提供行为画像上下文

设计原则

  1. 可扩展性: 支持新增行为维度,不修改核心架构
  2. 模块化: 每个行为分析器独立实现,便于维护
  3. 数据驱动: 基于实际数据统计,避免主观假设
  4. 隐私保护: 行为画像仅用于个人健康管理,不泄露给第三方

四类行为维度设计

1. 运动习惯分析 (Exercise Habits)

分析指标

指标名称 数据来源 计算周期 用途
步数统计 t_user_health_profile.step_count 7天 识别运动活跃度
运动频率 有效运动天数 / 7天 7天 评估运动习惯稳定性
时段偏好 t_step_data.upload_time 30天 识别最佳运动时间
运动强度 t_user_health_profile.calorie_total 7天 评估运动消耗水平
运动距离 t_user_health_profile.distance 7天 辅助活跃度评估

画像输出

public class ExerciseHabits {
    private String activityLevel;        // 运动积极性: SEDENTARY/LIGHTLY_ACTIVE/MODERATELY_ACTIVE/VERY_ACTIVE
    private Double avgDailySteps;        // 日均步数
    private Integer activeWeekDays;      // 7天内有效运动天数
    private String preferredTimeSlot;    // 最佳运动时段: MORNING/AFTERNOON/EVENING
    private Double consistency;          // 习惯稳定性评分 (0-100)
    private String trend;                // 趋势: IMPROVING/STABLE/DECLINING
}

分类规则

积极性等级 日均步数范围 有效运动天数 描述
VERY_ACTIVE ≥ 10,000 ≥ 5天 非常活跃,运动习惯优秀
MODERATELY_ACTIVE 7,000 - 9,999 ≥ 4天 中等活跃,运动习惯良好
LIGHTLY_ACTIVE 4,000 - 6,999 ≥ 3天 轻度活跃,需提升运动量
SEDENTARY < 4,000 < 3天 久坐为主,急需改善

2. 睡眠习惯分析 (Sleep Habits)

分析指标

指标名称 数据来源 计算周期 用途
入睡时间 t_sleep_data.sleep_start 7天 识别睡眠类型
睡眠时长 t_user_health_profile.sleep_duration 7天 评估睡眠充足度
睡眠质量 t_user_health_profile.deep_sleep_ratio 7天 评估睡眠效率
中断次数 t_user_health_profile.sleep_interruptions 7天 评估睡眠连续性
起床时间 t_sleep_data.sleep_end 7天 辅助睡眠类型识别

画像输出

public class SleepHabits {
    private String sleepType;              // 睡眠类型: EARLY_BIRD/NIGHT_OWL/NORMAL
    private Double avgSleepDuration;       // 平均睡眠时长 (分钟)
    private String qualityRating;          // 质量评级: EXCELLENT/GOOD/FAIR/POOR
    private LocalTime avgBedTime;          // 平均入睡时间
    private LocalTime avgWakeTime;         // 平均起床时间
    private Double consistency;            // 睡眠规律性评分 (0-100)
    private String trend;                  // 趋势: IMPROVING/STABLE/DECLINING
}

分类规则

睡眠类型识别:

类型 入睡时间范围 起床时间范围 描述
EARLY_BIRD (早睡型) 21:00 - 23:00 05:00 - 07:00 早睡早起,生物钟健康
NIGHT_OWL (夜猫子) 00:00 - 02:00 08:00 - 10:00 晚睡晚起,需调整作息
NORMAL (正常型) 23:00 - 00:00 07:00 - 08:00 标准作息,符合生理规律

质量评级标准:

评级 平均时长 深睡比例 中断次数 描述
EXCELLENT ≥ 420分钟 (7h) ≥ 25% ≤ 1次 睡眠优秀,无需调整
GOOD 360-419分钟 20-24% ≤ 2次 睡眠良好,维持现状
FAIR 300-359分钟 15-19% ≤ 3次 睡眠一般,建议改善
POOR < 300分钟 (5h) < 15% > 3次 睡眠不佳,急需干预

3. 饮食规律分析 (Diet Patterns)

分析指标

指标名称 数据来源 计算周期 用途
用餐时间 t_meal_data.meal_time 7天 识别饮食规律性
热量摄入 t_meal_data.calories 7天 评估饮食合理性
三餐完整度 早/中/晚餐记录数 7天 评估饮食习惯
用餐间隔 相邻用餐时间差 7天 识别饮食节奏

画像输出

public class DietPatterns {
    private String regularityLevel;        // 规律性等级: HIGHLY_REGULAR/REGULAR/IRREGULAR/CHAOTIC
    private Double regularityScore;        // 规律性评分 (0-100)
    private Integer avgMealsPerDay;        // 日均用餐次数
    private Boolean breakfastHabit;        // 是否有早餐习惯
    private Map<String, LocalTime> mealTimes;  // 各餐平均时间: {breakfast: 07:30, lunch: 12:00, dinner: 18:30}
    private String trend;                  // 趋势: IMPROVING/STABLE/DECLINING
}

分类规则

规律性等级 三餐完整率 时间波动 (分钟) 描述
HIGHLY_REGULAR ≥ 90% ≤ 30 饮食规律优秀,三餐定时定量
REGULAR 70-89% ≤ 60 饮食规律良好,基本固定时间
IRREGULAR 50-69% ≤ 120 饮食不规律,需改善作息
CHAOTIC < 50% > 120 饮食混乱,严重影响健康

注: 当前版本由于缺少 t_meal_data 表,饮食规律分析将暂时返回 "DATA_UNAVAILABLE" 状态,等待后续数据源接入。


4. 健康关注度分析 (Health Attention)

分析指标

指标名称 数据来源 计算周期 用途
数据上传频率 t_user_health_data.upload_time 30天 评估数据同步习惯
设备佩戴率 有数据天数 / 30天 30天 评估设备使用习惯
画像查看次数 t_user_profile_view_log 30天 评估健康关注程度
健康建议阅读率 阅读数 / 推送数 30天 评估健康意识

画像输出

public class HealthAttention {
    private String attentionLevel;         // 关注度等级: HIGHLY_ENGAGED/ENGAGED/PASSIVE/INACTIVE
    private Double deviceWearRate;         // 设备佩戴率 (%)
    private Integer avgDailyUploads;       // 日均数据上传次数
    private Integer profileViewsPerMonth;  // 月画像查看次数
    private Double engagementScore;        // 健康参与度评分 (0-100)
    private String trend;                  // 趋势: IMPROVING/STABLE/DECLINING
}

分类规则

关注度等级 设备佩戴率 数据上传频率 画像查看次数 描述
HIGHLY_ENGAGED ≥ 90% 每天 ≥ 3次 ≥ 10次/月 高度关注健康,数据完整
ENGAGED 70-89% 每天 1-2次 5-9次/月 关注健康,习惯良好
PASSIVE 50-69% 每2-3天1次 1-4次/月 较少关注,需激励
INACTIVE < 50% 每周 < 2次 0次/月 不关注健康,急需激活

核心算法设计

1. 运动习惯分析算法

算法输入

List<HealthProfile> last7DaysProfiles  // 近7天健康画像

算法流程

public ExerciseHabits analyzeExerciseHabits(List<HealthProfile> profiles) {
    // 1. 计算统计指标
    double avgDailySteps = profiles.stream()
        .mapToInt(HealthProfile::getStepCount)
        .average().orElse(0.0);

    int activeWeekDays = (int) profiles.stream()
        .filter(p -> p.getStepCount() != null && p.getStepCount() >= 3000)
        .count();

    double avgCalories = profiles.stream()
        .mapToDouble(p -> p.getCalorieTotal() != null ? p.getCalorieTotal().doubleValue() : 0.0)
        .average().orElse(0.0);

    // 2. 确定活跃度等级
    String activityLevel = determineActivityLevel(avgDailySteps, activeWeekDays);

    // 3. 计算稳定性评分 (标准差越小,稳定性越高)
    double stdDev = calculateStandardDeviation(
        profiles.stream().mapToInt(HealthProfile::getStepCount).toArray()
    );
    double consistency = Math.max(0, 100 - (stdDev / avgDailySteps * 100));

    // 4. 识别最佳运动时段 (需结合 t_step_data 分时数据)
    String preferredTimeSlot = identifyPreferredTimeSlot(profiles);

    // 5. 计算趋势 (线性回归斜率)
    String trend = calculateTrend(profiles, HealthProfile::getStepCount);

    return ExerciseHabits.builder()
        .activityLevel(activityLevel)
        .avgDailySteps(avgDailySteps)
        .activeWeekDays(activeWeekDays)
        .preferredTimeSlot(preferredTimeSlot)
        .consistency(consistency)
        .trend(trend)
        .build();
}

private String determineActivityLevel(double avgSteps, int activeDays) {
    if (avgSteps >= 10000 && activeDays >= 5) return "VERY_ACTIVE";
    if (avgSteps >= 7000 && activeDays >= 4) return "MODERATELY_ACTIVE";
    if (avgSteps >= 4000 && activeDays >= 3) return "LIGHTLY_ACTIVE";
    return "SEDENTARY";
}

2. 睡眠习惯分析算法

算法流程

public SleepHabits analyzeSleepHabits(List<HealthProfile> profiles, List<SleepData> sleepData) {
    // 1. 计算平均睡眠时长
    double avgDuration = profiles.stream()
        .filter(p -> p.getSleepDuration() != null)
        .mapToInt(HealthProfile::getSleepDuration)
        .average().orElse(0.0);

    // 2. 计算平均入睡时间
    LocalTime avgBedTime = calculateAverageBedTime(sleepData);
    LocalTime avgWakeTime = calculateAverageWakeTime(sleepData);

    // 3. 识别睡眠类型
    String sleepType = determineSleepType(avgBedTime, avgWakeTime);

    // 4. 评估睡眠质量
    double avgDeepSleepRatio = profiles.stream()
        .filter(p -> p.getDeepSleepRatio() != null)
        .mapToDouble(p -> p.getDeepSleepRatio().doubleValue())
        .average().orElse(0.0);

    double avgInterruptions = profiles.stream()
        .filter(p -> p.getSleepInterruptions() != null)
        .mapToInt(HealthProfile::getSleepInterruptions)
        .average().orElse(0.0);

    String qualityRating = determineSleepQuality(avgDuration, avgDeepSleepRatio, avgInterruptions);

    // 5. 计算规律性 (入睡时间标准差)
    double consistency = calculateSleepConsistency(sleepData);

    // 6. 计算趋势
    String trend = calculateTrend(profiles, HealthProfile::getSleepDuration);

    return SleepHabits.builder()
        .sleepType(sleepType)
        .avgSleepDuration(avgDuration)
        .qualityRating(qualityRating)
        .avgBedTime(avgBedTime)
        .avgWakeTime(avgWakeTime)
        .consistency(consistency)
        .trend(trend)
        .build();
}

private String determineSleepType(LocalTime bedTime, LocalTime wakeTime) {
    int bedHour = bedTime.getHour();
    int wakeHour = wakeTime.getHour();

    if (bedHour >= 21 && bedHour < 23 && wakeHour >= 5 && wakeHour < 7) {
        return "EARLY_BIRD";
    } else if ((bedHour >= 0 && bedHour < 2) && wakeHour >= 8 && wakeHour < 10) {
        return "NIGHT_OWL";
    } else {
        return "NORMAL";
    }
}

private String determineSleepQuality(double duration, double deepRatio, double interruptions) {
    if (duration >= 420 && deepRatio >= 0.25 && interruptions <= 1) return "EXCELLENT";
    if (duration >= 360 && deepRatio >= 0.20 && interruptions <= 2) return "GOOD";
    if (duration >= 300 && deepRatio >= 0.15 && interruptions <= 3) return "FAIR";
    return "POOR";
}

3. 饮食规律分析算法

算法流程 (当前版本)

public DietPatterns analyzeDietPatterns(Long userId) {
    // 注: 当前版本缺少 t_meal_data 表,返回占位符结果
    return DietPatterns.builder()
        .regularityLevel("DATA_UNAVAILABLE")
        .regularityScore(0.0)
        .avgMealsPerDay(0)
        .breakfastHabit(false)
        .mealTimes(Collections.emptyMap())
        .trend("UNKNOWN")
        .remark("饮食数据表暂未实现,待后续版本接入")
        .build();
}

算法流程 (未来版本)

public DietPatterns analyzeDietPatterns(List<MealData> mealData) {
    // 1. 统计三餐完整度
    int breakfastCount = countMealsByType(mealData, "BREAKFAST");
    int lunchCount = countMealsByType(mealData, "LUNCH");
    int dinnerCount = countMealsByType(mealData, "DINNER");

    double completeness = (breakfastCount + lunchCount + dinnerCount) / (7.0 * 3) * 100;

    // 2. 计算各餐平均时间
    Map<String, LocalTime> avgMealTimes = calculateAverageMealTimes(mealData);

    // 3. 计算时间波动 (标准差)
    double timeVariation = calculateMealTimeVariation(mealData);

    // 4. 确定规律性等级
    String regularityLevel = determineDietRegularity(completeness, timeVariation);

    // 5. 计算规律性评分
    double score = calculateRegularityScore(completeness, timeVariation);

    return DietPatterns.builder()
        .regularityLevel(regularityLevel)
        .regularityScore(score)
        .avgMealsPerDay((breakfastCount + lunchCount + dinnerCount) / 7)
        .breakfastHabit(breakfastCount >= 5)
        .mealTimes(avgMealTimes)
        .trend("STABLE")
        .build();
}

4. 健康关注度分析算法

算法流程

public HealthAttention analyzeHealthAttention(Long userId) {
    LocalDate endDate = LocalDate.now();
    LocalDate startDate = endDate.minusDays(30);

    // 1. 计算设备佩戴率 (有数据的天数 / 30天)
    int daysWithData = healthProfileMapper.countDaysWithData(userId, startDate, endDate);
    double wearRate = (daysWithData / 30.0) * 100;

    // 2. 计算日均上传次数
    int totalUploads = healthDataMapper.countUploads(userId, startDate, endDate);
    int avgDailyUploads = totalUploads / 30;

    // 3. 统计画像查看次数 (需新建 t_user_profile_view_log 表)
    int profileViews = profileViewLogMapper.countViews(userId, startDate, endDate);

    // 4. 确定关注度等级
    String attentionLevel = determineAttentionLevel(wearRate, avgDailyUploads, profileViews);

    // 5. 计算参与度评分
    double engagementScore = calculateEngagementScore(wearRate, avgDailyUploads, profileViews);

    // 6. 计算趋势 (对比前30天)
    String trend = calculateAttentionTrend(userId, startDate);

    return HealthAttention.builder()
        .attentionLevel(attentionLevel)
        .deviceWearRate(wearRate)
        .avgDailyUploads(avgDailyUploads)
        .profileViewsPerMonth(profileViews)
        .engagementScore(engagementScore)
        .trend(trend)
        .build();
}

private String determineAttentionLevel(double wearRate, int uploads, int views) {
    if (wearRate >= 90 && uploads >= 3 && views >= 10) return "HIGHLY_ENGAGED";
    if (wearRate >= 70 && uploads >= 1 && views >= 5) return "ENGAGED";
    if (wearRate >= 50 && views >= 1) return "PASSIVE";
    return "INACTIVE";
}

数据模型设计

DTO 类设计

BehavioralProfileDTO.java

package com.ljwx.modules.health.domain.dto.behavioral;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Map;

/**
 * 行为画像 DTO
 *
 * @author LJWX Health Team
 * @since Phase 2 - Sprint 8
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BehavioralProfileDTO {

    private Long userId;
    private LocalDate profileDate;

    // 四类行为画像
    private ExerciseHabits exerciseHabits;
    private SleepHabits sleepHabits;
    private DietPatterns dietPatterns;
    private HealthAttention healthAttention;

    // 综合评分
    private Double overallScore;  // 综合行为评分 (0-100)
    private String behavioralType;  // 行为类型: HEALTH_CONSCIOUS/BALANCED/NEEDS_IMPROVEMENT/AT_RISK

    // 元数据
    private LocalDate analysisStartDate;  // 分析开始日期
    private LocalDate analysisEndDate;    // 分析结束日期

    /**
     * 运动习惯
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class ExerciseHabits {
        private String activityLevel;        // SEDENTARY/LIGHTLY_ACTIVE/MODERATELY_ACTIVE/VERY_ACTIVE
        private Double avgDailySteps;
        private Integer activeWeekDays;
        private String preferredTimeSlot;    // MORNING/AFTERNOON/EVENING
        private Double consistency;          // 0-100
        private String trend;                // IMPROVING/STABLE/DECLINING
        private String recommendation;       // 个性化建议
    }

    /**
     * 睡眠习惯
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SleepHabits {
        private String sleepType;              // EARLY_BIRD/NIGHT_OWL/NORMAL
        private Double avgSleepDuration;       // 分钟
        private String qualityRating;          // EXCELLENT/GOOD/FAIR/POOR
        @JsonFormat(pattern = "HH:mm")
        private LocalTime avgBedTime;
        @JsonFormat(pattern = "HH:mm")
        private LocalTime avgWakeTime;
        private Double consistency;            // 0-100
        private String trend;                  // IMPROVING/STABLE/DECLINING
        private String recommendation;
    }

    /**
     * 饮食规律
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class DietPatterns {
        private String regularityLevel;        // HIGHLY_REGULAR/REGULAR/IRREGULAR/CHAOTIC/DATA_UNAVAILABLE
        private Double regularityScore;        // 0-100
        private Integer avgMealsPerDay;
        private Boolean breakfastHabit;
        private Map<String, LocalTime> mealTimes;  // {breakfast: 07:30, lunch: 12:00, dinner: 18:30}
        private String trend;
        private String recommendation;
        private String remark;  // 当前版本说明
    }

    /**
     * 健康关注度
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class HealthAttention {
        private String attentionLevel;         // HIGHLY_ENGAGED/ENGAGED/PASSIVE/INACTIVE
        private Double deviceWearRate;         // 设备佩戴率 %
        private Integer avgDailyUploads;
        private Integer profileViewsPerMonth;
        private Double engagementScore;        // 0-100
        private String trend;
        private String recommendation;
    }
}

服务架构设计

核心服务: BehavioralProfileService

package com.ljwx.modules.health.service;

import com.ljwx.modules.health.domain.dto.behavioral.BehavioralProfileDTO;
import com.ljwx.modules.health.entity.HealthProfile;
import com.ljwx.modules.health.mapper.HealthProfileMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;

/**
 * 行为画像服务
 *
 * @author LJWX Health Team
 * @since Phase 2 - Sprint 8
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BehavioralProfileService {

    private final HealthProfileMapper healthProfileMapper;
    private final ExerciseHabitsAnalyzer exerciseHabitsAnalyzer;
    private final SleepHabitsAnalyzer sleepHabitsAnalyzer;
    private final DietPatternsAnalyzer dietPatternsAnalyzer;
    private final HealthAttentionAnalyzer healthAttentionAnalyzer;

    /**
     * 生成用户行为画像
     *
     * @param userId 用户ID
     * @param profileDate 画像日期 (默认今天)
     * @return 行为画像 DTO
     */
    public BehavioralProfileDTO generateBehavioralProfile(Long userId, LocalDate profileDate) {
        if (profileDate == null) {
            profileDate = LocalDate.now();
        }

        log.info("开始生成用户行为画像: userId={}, date={}", userId, profileDate);

        // 1. 查询近7天健康画像数据 (用于运动、睡眠分析)
        LocalDate startDate = profileDate.minusDays(6);
        List<HealthProfile> last7DaysProfiles = queryHealthProfiles(userId, startDate, profileDate);

        if (last7DaysProfiles.isEmpty()) {
            log.warn("用户近7天无健康数据,无法生成行为画像: userId={}", userId);
            return null;
        }

        // 2. 运动习惯分析
        BehavioralProfileDTO.ExerciseHabits exerciseHabits =
            exerciseHabitsAnalyzer.analyze(userId, last7DaysProfiles);

        // 3. 睡眠习惯分析
        BehavioralProfileDTO.SleepHabits sleepHabits =
            sleepHabitsAnalyzer.analyze(userId, last7DaysProfiles);

        // 4. 饮食规律分析
        BehavioralProfileDTO.DietPatterns dietPatterns =
            dietPatternsAnalyzer.analyze(userId, profileDate);

        // 5. 健康关注度分析 (使用近30天数据)
        BehavioralProfileDTO.HealthAttention healthAttention =
            healthAttentionAnalyzer.analyze(userId, profileDate);

        // 6. 计算综合行为评分
        Double overallScore = calculateOverallScore(
            exerciseHabits, sleepHabits, dietPatterns, healthAttention);

        // 7. 确定行为类型
        String behavioralType = determineBehavioralType(overallScore);

        // 8. 构建 DTO
        BehavioralProfileDTO dto = BehavioralProfileDTO.builder()
            .userId(userId)
            .profileDate(profileDate)
            .exerciseHabits(exerciseHabits)
            .sleepHabits(sleepHabits)
            .dietPatterns(dietPatterns)
            .healthAttention(healthAttention)
            .overallScore(overallScore)
            .behavioralType(behavioralType)
            .analysisStartDate(startDate)
            .analysisEndDate(profileDate)
            .build();

        log.info("行为画像生成完成: userId={}, overallScore={}, type={}",
            userId, overallScore, behavioralType);

        return dto;
    }

    /**
     * 计算综合行为评分
     * 权重分配: 运动30% + 睡眠30% + 饮食20% + 关注度20%
     */
    private Double calculateOverallScore(
            BehavioralProfileDTO.ExerciseHabits exercise,
            BehavioralProfileDTO.SleepHabits sleep,
            BehavioralProfileDTO.DietPatterns diet,
            BehavioralProfileDTO.HealthAttention attention) {

        double exerciseScore = mapActivityToScore(exercise.getActivityLevel());
        double sleepScore = mapQualityToScore(sleep.getQualityRating());
        double dietScore = diet.getRegularityScore() != null ? diet.getRegularityScore() : 0.0;
        double attentionScore = attention.getEngagementScore();

        return exerciseScore * 0.30 + sleepScore * 0.30 + dietScore * 0.20 + attentionScore * 0.20;
    }

    /**
     * 确定行为类型
     */
    private String determineBehavioralType(double score) {
        if (score >= 80) return "HEALTH_CONSCIOUS";  // 健康意识强
        if (score >= 60) return "BALANCED";          // 平衡型
        if (score >= 40) return "NEEDS_IMPROVEMENT"; // 需改善
        return "AT_RISK";                            // 高风险
    }

    // ... 其他辅助方法
}

分析器接口设计

package com.ljwx.modules.health.service.analyzer;

/**
 * 行为分析器接口
 */
public interface BehaviorAnalyzer<T> {

    /**
     * 分析行为模式
     *
     * @param userId 用户ID
     * @param data 分析数据
     * @return 行为画像结果
     */
    T analyze(Long userId, Object data);
}

数据库设计

扩展 t_user_health_profile 表

-- V1.7.0__add_behavioral_profile_fields.sql

ALTER TABLE t_user_health_profile
    ADD COLUMN behavioral_profile_json JSON COMMENT '行为画像JSON (存储四类行为数据)',
    ADD COLUMN behavioral_score DECIMAL(5,2) COMMENT '综合行为评分 (0-100)',
    ADD COLUMN behavioral_type VARCHAR(30) COMMENT '行为类型: HEALTH_CONSCIOUS/BALANCED/NEEDS_IMPROVEMENT/AT_RISK',
    ADD COLUMN behavioral_update_time DATETIME COMMENT '行为画像更新时间';

-- 虚拟列索引 (加速行为类型查询)
ALTER TABLE t_user_health_profile
    ADD COLUMN behavioral_type_virtual VARCHAR(30)
        AS (JSON_UNQUOTE(JSON_EXTRACT(behavioral_profile_json, '$.behavioralType'))) VIRTUAL,
    ADD INDEX idx_behavioral_type_virtual (behavioral_type_virtual);

-- 行为评分索引 (支持排名查询)
CREATE INDEX idx_behavioral_score ON t_user_health_profile(behavioral_score DESC);

新增 t_user_profile_view_log 表 (用于健康关注度统计)

CREATE TABLE t_user_profile_view_log (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL COMMENT '用户ID',
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    view_type VARCHAR(50) COMMENT '查看类型: HEALTH_PROFILE/RISK_PROFILE/BEHAVIORAL_PROFILE',
    view_time DATETIME NOT NULL COMMENT '查看时间',
    source VARCHAR(50) COMMENT '来源: WEB/MOBILE/API',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_time (user_id, view_time),
    INDEX idx_customer_user (customer_id, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户画像查看日志';

API 设计

BehavioralProfileController.java

package com.ljwx.modules.health.controller;

import com.ljwx.common.api.Result;
import com.ljwx.modules.health.domain.dto.behavioral.BehavioralProfileDTO;
import com.ljwx.modules.health.service.BehavioralProfileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;

/**
 * 行为画像 API
 *
 * @author LJWX Health Team
 * @since Phase 2 - Sprint 8
 */
@Tag(name = "行为画像管理", description = "用户行为模式分析与画像生成")
@RestController
@RequestMapping("/api/health/behavioral-profile")
@RequiredArgsConstructor
@Validated
public class BehavioralProfileController {

    private final BehavioralProfileService behavioralProfileService;

    @Operation(summary = "生成行为画像", description = "基于近期健康数据生成用户行为画像")
    @PostMapping("/generate")
    public Result<BehavioralProfileDTO> generateBehavioralProfile(
            @Parameter(description = "用户ID", required = true) @RequestParam Long userId,
            @Parameter(description = "画像日期 (默认今天)")
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate profileDate) {

        BehavioralProfileDTO profile = behavioralProfileService.generateBehavioralProfile(userId, profileDate);

        if (profile == null) {
            return Result.error("用户近期无健康数据,无法生成行为画像");
        }

        return Result.success(profile);
    }

    @Operation(summary = "查询行为画像", description = "获取已生成的行为画像数据")
    @GetMapping("/query")
    public Result<BehavioralProfileDTO> queryBehavioralProfile(
            @Parameter(description = "用户ID", required = true) @RequestParam Long userId,
            @Parameter(description = "画像日期 (默认今天)")
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate profileDate) {

        BehavioralProfileDTO profile = behavioralProfileService.queryBehavioralProfile(userId, profileDate);

        if (profile == null) {
            return Result.error("未找到行为画像数据");
        }

        return Result.success(profile);
    }
}

数据流架构

┌──────────────────────────────────────────────────────────────────┐
│                       数据采集层                                  │
│  t_user_health_profile (近7天) + t_sleep_data + t_step_data      │
└────────────┬─────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────────────┐
│                     行为分析层                                    │
│  ┌──────────────────┐  ┌──────────────────┐                      │
│  │ ExerciseHabits   │  │ SleepHabits      │                      │
│  │ Analyzer         │  │ Analyzer         │                      │
│  └──────────────────┘  └──────────────────┘                      │
│  ┌──────────────────┐  ┌──────────────────┐                      │
│  │ DietPatterns     │  │ HealthAttention  │                      │
│  │ Analyzer         │  │ Analyzer         │                      │
│  └──────────────────┘  └──────────────────┘                      │
└────────────┬─────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────────────┐
│                  综合评分层                                       │
│  calculateOverallScore() - 加权平均                              │
│  运动30% + 睡眠30% + 饮食20% + 关注度20%                          │
└────────────┬─────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────────────┐
│                  画像存储层                                       │
│  t_user_health_profile.behavioral_profile_json (JSON)            │
│  t_user_health_profile.behavioral_score (评分)                   │
│  t_user_health_profile.behavioral_type (类型)                    │
└────────────┬─────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────────────┐
│                  API 响应层                                       │
│  BehavioralProfileController → BehavioralProfileDTO              │
└──────────────────────────────────────────────────────────────────┘

集成方案

与风险画像集成

行为画像可为风险画像提供行为上下文:

// 示例: 在 RiskProfileService 中引用行为画像
public RiskProfileDTO generateRiskProfile(Long userId, LocalDate profileDate) {
    // 1. 生成风险画像
    RiskProfileDTO riskProfile = ...;

    // 2. 获取行为画像
    BehavioralProfileDTO behavioralProfile =
        behavioralProfileService.queryBehavioralProfile(userId, profileDate);

    // 3. 基于行为画像调整风险建议
    if (behavioralProfile != null && "SEDENTARY".equals(behavioralProfile.getExerciseHabits().getActivityLevel())) {
        // 久坐用户的心血管风险建议更严格
        riskProfile.getCardiovascularRisk().setDetails(
            riskProfile.getCardiovascularRisk().getDetails() +
            "\n建议: 您的运动量较低,请增加日常活动量以降低心血管风险。"
        );
    }

    return riskProfile;
}

与 AI 健康顾问集成 (Phase 3)

行为画像将作为 AI Prompt 的重要上下文:

用户行为画像:
- 运动习惯: SEDENTARY (日均步数 3200, 活跃天数 2/7)
- 睡眠习惯: NIGHT_OWL (平均入睡时间 01:30, 睡眠质量 FAIR)
- 饮食规律: IRREGULAR (规律性评分 45/100)
- 健康关注度: PASSIVE (设备佩戴率 60%, 月查看次数 2)

基于以上画像,请生成个性化健康建议...

总结

核心交付物

  1. ✅ 架构设计文档 (本文档, 380+ 行)
  2. ⏳ 四个行为分析器:
    • ExerciseHabitsAnalyzer.java
    • SleepHabitsAnalyzer.java
    • DietPatternsAnalyzer.java
    • HealthAttentionAnalyzer.java
  3. ⏳ BehavioralProfileService.java (核心编排服务)
  4. ⏳ BehavioralProfileController.java (REST API)
  5. ⏳ 数据库迁移 (V1.7.0__add_behavioral_profile_fields.sql)
  6. ⏳ 单元测试 (覆盖率 > 80%)
  7. ⏳ 集成测试 (端到端测试)

下一步工作

按照 Sprint 8 任务顺序:

  • T2.2.2: 实现 ExerciseHabitsAnalyzer (3天)
  • T2.2.3: 实现 SleepHabitsAnalyzer (2天)
  • T2.2.4: 实现 DietPatternsAnalyzer (2天)
  • T2.2.5: 实现 HealthAttentionAnalyzer (1天)
  • T2.2.6: 单元测试 (2天)
  • T2.2.7: 集成测试 (1天)

文档版本: v1.0 最后更新: 2026-01-20 状态: ✅ 设计评审通过 审核人: LJWX Health Team