2026年软件学院创新项目实训|智能居家养老健康守护系统·第七周工作博客
2026年山东大学软件学院创新项目实训 小组周报(第七周)
一、本周工作概述
本周小组围绕"AI 对话系统全面落地 + 安全加固 + 鉴权联调 + 新功能上线"推进开发,主要完成以下工作:
- 后端——AI 多角色对话系统实现与安全加固:完成 5 个 Agent(情感陪伴/健康陪诊/健康干预/用药安全/家属辅诊)的完整对话接口开发,每个 Agent 提供普通对话、流式 SSE、会话列表、会话详情、会话删除共 5 个接口;修复 15 个会话管理接口的用户隔离漏洞;修复家属辅诊
familyId可被伪造的安全问题;新增对话记忆滑动窗口防止 Token 超限。 - 后端——JWT 统一身份识别与数据归属校验:重构登录态体系,将用户主键写入 JWT subject,新增全局过滤器与线程上下文,在健康数据、用药计划、病历等模块按「老人本人 / 家属已绑定老人」过滤读写范围。
- 后端——用药提醒数据层基础设施:设计
medication_reminder_log表结构及索引,完成实体映射、定时任务线程池配置、短信模板扩展。 - 后端——健康报告生成与 OCR 医疗单据识别:新增基于 7 天体征数据的 AI 健康报告生成(含多轮追问);新增 OCR 医疗单据识别功能,调用 qwen3.6-plus 多模态模型自动结构化入库。
- 前端——JWT 鉴权全链路联调:适配后端登录响应字段,增强请求拦截器统一注入 Bearer 令牌,完善双层 401 拦截机制,完成数据归属参数传递与全链路验证。
二、具体工作内容
2.1 AI 多角色对话系统实现
(1)系统架构
采用"统一基座 + 差异化 Prompt"架构,所有 Agent 共享同一套会话管理(ChatSessionService)和大模型调用基础设施,通过不同的 System Prompt 定义角色能力边界。
调用链路:
用户消息 → Controller → resolveSession() → ElderlyContextService.getFullContext()(加载健康档案) → ChatMemoryService.buildMessages()(构建消息数组 + 滑动窗口截断) → DeepSeek API(/v1/chat/completions) → 保存会话 → 返回响应(2)Agent 矩阵
| Agent | 名字 | 接口前缀 | 核心能力 | 温度 |
|---|---|---|---|---|
| 情感陪伴 | 暖心 | /api/companion | 心理慰藉 / 陪诊助手 | 0.8 |
| 健康陪诊 | 康伴 | /api/health-companion | 全科健康问答、导诊 | 0.6 |
| 健康干预 | 养怡 | /api/health-intervention | 饮食/运动/作息个性化方案 | 0.5 |
| 用药安全审核 | — | /api/medication-safety | 药物配伍禁忌筛查 | 0.3 |
| 家属辅诊 | 家护 | /api/family-assist | 跨角色健康分析与照护建议 | 0.4 |
(3)每个 Agent 提供 5 个接口
| 接口 | 方法 | 说明 |
|---|---|---|
/{prefix}/chat | POST | 普通对话(等待完整回复) |
/{prefix}/chat/stream | POST | 流式对话(SSE 逐字输出) |
/{prefix}/sessions | GET | 当前用户的会话列表 |
/{prefix}/sessions/{sessionId} | GET | 会话详情(含完整消息) |
/{prefix}/sessions/{sessionId} | DELETE | 删除会话 |
(4)个性化健康上下文注入
每次对话自动从数据库加载老人健康档案,注入 System Prompt:基本信息(姓名、年龄、性别)、疾病列表、当前用药计划、近期病历记录(最近 5 条)、最新体征数据。家属端采用显式注入(“请基于这些数据回答”),老人端采用隐式注入(“不要主动提及已知信息”)。
(5)对话记忆滑动窗口
- 问题:历史消息全量发送给大模型,对话轮次过多时超出上下文窗口导致 API 报错
- 解决:新建
ChatMemoryService,统一管理消息构建逻辑,超过 30 条消息自动截断保留最近记录;5 个 Agent 的buildMessages()统一改为调用chatMemoryService.buildMessages() - 新增配置项
chat.memory.max-context-messages: 30(约 15 轮对话)
2.2 安全加固
(1)AI 对话用户隔离修复
- 问题:5 个 Agent 共 15 个会话管理接口没有用户隔离,任意用户可查看/删除其他用户的对话
- 修复:
ChatSessionServiceImpl注入ElderlyAccessService,所有会话操作增加归属校验;5 个 Agent Controller 的会话接口统一从JwtUserContext取用户信息
| 操作 | 隔离逻辑 |
|---|---|
| 列出会话 | 老人:elderlyId == 自己;家属:familyId == 自己 |
| 查看/删除 | 校验 session 归属,不匹配抛 403 |
| 创建会话 | assertCanAccessElderly(elderlyId) |
(2)家属辅诊身份修复
- 问题:
FamilyAssistController的familyId从请求体获取,可被伪造 - 修复:Controller 层用
JwtUserContext.requireFamilyId()覆盖请求体中的值,非家属账号调用直接 403;同时校验绑定关系,无绑定返回 403
2.3 JWT 统一身份识别与数据归属校验
(1)登录与令牌重构
JwtServiceImpl.generateAccessToken将 userId 写入 JWT 标准字段subject,userType、phone、openId 写入自定义 claimsJwtService.resolvePrincipal(authorization)统一解析 Bearer 令牌,封装JwtPrincipal(userId, userType, phone, openId)- 短信登录返回
SmsLoginResponse(含 accessToken、userId、elderlyId),前端持久化后携带身份访问业务接口
(2)全局过滤器与线程上下文
- 新增
JwtAuthFilter(OncePerRequestFilter):除登录、发码、Swagger 等白名单路径外,默认要求有效 JWT;解析成功后写入JwtUserContext,请求结束 finally 清理 ThreadLocal 防止线程池复用串用户 JwtUserContext提供requireUserId()、requireFamilyId()、requireElderlyId()等静态方法
(3)数据归属校验体系
- 新增
ElderlyAccessService:assertCanAccessElderly(elderlyId)校验当前用户能否访问指定老人数据——老人仅本人,家属仅bindStatus=1的绑定老人 - 新增
ElderlyScopedCrudSupport:封装带 elderlyId 实体的权限模板,各模块 Controller 改造为listForCurrentUser()/getForCurrentUser(id)等方法 - 解决
ElderlyAccessService与ElderlyFamilyService循环依赖:绑定关系查询改为注入ElderlyFamilyMapper
2.4 用药提醒数据层与定时任务基础设施
(1)数据库设计
新建medication_reminder_log表,记录用药提醒全生命周期(待发送 → 已发送短信 → 已确认服药):
CREATETABLEmedication_reminder_log(id BIGSERIALPRIMARYKEY,schedule_time_idBIGINTNOTNULL,elderly_idBIGINTNOTNULL,plan_dateDATENOTNULL,dose_timeTIMENOTNULL,remind_statusSMALLINTDEFAULT0,-- 0待发送 1已发送 2已确认push_timeTIMESTAMP,confirm_timeTIMESTAMP,created_atTIMESTAMPDEFAULTnow(),CONSTRAINTuk_schedule_dateUNIQUE(schedule_time_id,plan_date));(2)索引与配置
| 索引 | 用途 |
|---|---|
idx_reminder_elderly_date | 查询老人今日用药计划 |
idx_reminder_status | 查询未确认的提醒 |
idx_reminder_dose_time | 定时任务按时间扫描 |
定时任务线程池配置:5 线程,前缀medication-,支持优雅关闭。短信配置扩展reminderTemplateCode用药提醒模板编码。
2.5 健康报告 AI 生成与 OCR 医疗单据识别
(1)健康报告生成
- 基于老人最近 7 天体征数据,AI 自动生成健康趋势分析报告(含数据总览、趋势分析、异常预警、综合评估、健康建议),报告存储在
medical_record表 - 支持普通追问(
/api/health-report/chat)和 SSE 流式追问(/api/health-report/chat/stream) - 提供历史报告列表与详情查询接口
(2)OCR 医疗单据识别
- 调用 qwen3.6-plus 多模态模型识别医疗单据图片,自动提取生化指标并结构化入库
- 识别结果存入
medical_record表,体征数据自动写入elderly_health_data表 - 支持识别:生命体征、身体测量、血常规、炎症指标、影像检查描述等
- 返回结构化指标列表(含指标名、数值、单位、参考范围、是否异常)
2.6 前端——JWT 鉴权全链路联调
(1)登录响应字段适配
后端登录接口返回结构变更,前端同步适配:登录成功后持久化 accessToken、tokenType、userId、elderlyId、userInfo 到本地缓存。
(2)请求拦截器增强
所有业务服务统一通过base.request()发起请求,自动调用auth.buildAuthHeader()注入 `Authorization: Bearer *** 头,杜绝各服务重复手写。
(3)双层 401 拦截机制
| 层级 | 拦截方式 | 说明 |
|---|---|---|
| 第一层 | HTTP 状态码拦截 | statusCode === 401时清除缓存并跳转登录页 |
| 第二层 | 业务消息拦截 | 响应体中匹配 token 过期关键词时触发相同跳转 |
| 第三层 | 错误消息标准化 | 映射为用户友好中文提示 |
(4)数据归属参数传递
- 老人端:
elderlyId登录时已存入本地缓存,查询时自动携带 - 家属端:从绑定关系获取
boundElderlyId,操作老人数据时作为参数传递
三、联调与测试验证
| 模块 | 验证项 | 状态 |
|---|---|---|
| 5 个 Agent 对话 | 角色设定生效,回复符合预期 | ✅ 通过 |
| SSE 流式输出 | 逐字输出正常,120s 超时处理正确 | ✅ 通过 |
| 会话用户隔离 | 老人/家属只能操作自己的会话,越权返回 403 | ✅ 通过 |
| 家属辅诊身份 | familyId 从 JWT 获取,不可伪造 | ✅ 通过 |
| JWT 鉴权 | 所有业务请求携带 Bearer 令牌,无 token 返回 401 | ✅ 通过 |
| 数据归属 | 老人仅查本人数据,家属仅查绑定老人数据 | ✅ 通过 |
| 双层 401 拦截 | HTTP 状态码 + 业务消息双层均生效 | ✅ 通过 |
| 编译验证 | Maven 编译通过 | ✅ 通过 |
四、待解决问题与风险
| 问题 | 当前状态 | 处理计划 |
|---|---|---|
| 会话模块 DB 持久化与 ownerUserId 归属校验未完全对齐 | 4 个会话文件暂对齐 master 版本 | master 合并 JWT 后统一迭代 |
| 用药提醒短信模板编码未配置 | 配置项已预留,值为空 | 阿里云控制台申请模板后填入 |
| Token 刷新机制未实现 | token 过期后直接跳转登录 | 后续增加静默续期 |
| 健康指标数值范围校验尚未补充 | 录入仅校验 ID 非空 | 与产品/医学侧确认阈值后补充 |
| 对话过长 Token 超限 | 滑动窗口已兜底,但无摘要压缩 | 后续引入摘要压缩策略 |
五、下周计划
- 最终联调:完成项目全模块前后端联调,确保鉴权、归属校验、会话管理等全链路无遗漏
- 会话模块对齐:master 合并 JWT 能力后,将会话模块 DB 持久化与 ownerUserId 归属校验统一
- Token 刷新:增加 token 自动刷新机制,在即将过期时静默续期
- 健康指标校验:完善录入数值范围校验,提升数据质量
- 用药提醒业务层:配合完成定时扫描与短信发送的业务层实现
- 健康报告与 OCR 联调:与前端对接健康报告生成、追问及 OCR 识别接口
