2026-09-10-report-quick-analyze-design.md 7.1 KB

报告快速分析功能设计

日期:2026-09-10 状态:已批准

1. 背景与目标

报告详情页(report-detail.vue)目前只有被动的数据展示,用户无法针对报告内容主动提问。本功能提供「快速分析」入口,让用户输入问题,AI 基于当前报告内容做初步解读。

免费版价值主张:免费用户也能体验 AI 报告解读(每日 1 次),作为免费版的核心功能之一,同时引导升级付费版。

目标

  • 免费版(FREE):每日 1 次快速分析,按天重置(Redis 计数)
  • 付费版(FAMILY/PROVIDER):多轮对话,不限制次数

非目标

  • 不做完整的多轮会话管理界面(复用现有 pages/ai/chat.vue 的能力范围之外)
  • 不做报告深度解析/结构化解读(仅问答式初步解读)
  • 不修改 LangGraph chat_graph(零 Python 改动)

2. 架构设计

复用现有 AI 链路,最小新增。核心思路:后端加一个端点 + Redis 计数,前端加按钮和浮层,LangGraph 零改动

report-detail.vue(底部按钮 + 浮层)
   │ POST /api/ai/report/analyze { query, reportId, conversationId?, memberId? }
   ▼
AIChatController 新增端点 /report/analyze
   │ 1. 查 User.memberLevel(FREE/FAMILY/PROVIDER)
   │ 2. FREE → Redis INCR dailyKey,>1 拒绝
   │ 3. familyContextService.buildContext(userId, reportId) 组装报告上下文
   │ 4. AiGateway.chat() → LangGraph /api/v1/chat
   ▼
LangGraph chat_graph(现有,零改动)
   classify → load_context → llm_call → answer

数据流

  1. 前端浮层用户输入问题,调用 POST /api/ai/report/analyze
  2. 后端校验会员级别与免费次数
  3. 组装报告上下文(familyContextService.buildContext(userId, reportId) 已支持报告注入)
  4. AiGateway.chat() → LangGraph /api/v1/chat
  5. LangGraph chat_graph 现有流程返回 answer

3. 关键决策

3.1 复用现有链路,不新建 LangGraph graph

  • 现有 chat_graph 已支持 context.report_id 注入(chat_graph.py 129-137 行:report_id → 家庭上下文 SystemMessage)
  • familyContextService.buildContext(userId, reportId) 已组装报告相关上下文(health_reports + indicators)
  • AiGateway.chat(query, userId, conversationId, inputs) 已透传 context

结论:后端一个端点 + 前端浮层即完成,LangGraph 零改动。

3.2 新增端点 /api/ai/report/analyze(而非复用 /chat/send

  • /chat/send 承载家庭助手通用聊天,职责过重
  • 新端点专门做「报告快速分析」:会员限制 + 报告上下文 + 返回 answer
  • 复用 sendMessage 内部已有的上下文组装逻辑:在 AIChatController 内抽出私有方法 buildChatInputs(userId, params)/chat/send/report/analyze 共同调用

3.3 免费次数限制:Redis 计数

// 在 AIChatController.reportAnalyze() 内
String key = "report:analyze:free:" + userId + ":" + LocalDate.now();
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) redisTemplate.expire(key, Duration.ofDays(1));
if (count > 1) return Result.error("免费版每日仅限 1 次快速分析,升级会员解锁更多");
  • Redis 不可用降级:Redis 异常时 fail-open 放行(避免免费用户因 Redis 故障完全不可用),记 log.warn
  • 实现时按环境配置(本地/测试 localhost:6379,生产由运维提供连接信息)

3.4 免费版锁死多轮

  • 付费版:前端回传 conversationId → LangGraph 保持上下文 → 可追问
  • 免费版:前端每次不带 conversationId(不传则 LangGraph 每次新建会话)→ 天然单次

3.5 前端浮层(页面内嵌,不新建页面)

  • report-detail.vue 底部新增「🎯 快速分析」悬浮按钮(仅 view 模式显示)
  • 点击展开浮层:消息区 + 输入框 + 3 个快捷问题 chips
  • 免费版用完 1 次后:按钮隐藏或显示锁定提示文案"今日次数已用完,升级会员解锁更多";浮层关闭后输入框禁用
  • 付费版:可连续追问(每轮带 conversationId 回传),无按钮禁用逻辑

4. 改动清单

后端(cfc-backend)

文件 改动
pom.xml 新增 spring-boot-starter-data-redis 依赖
application.yml Redis 连接配置
RedisConfig.java(新增 config/ RedisTemplate bean,String 序列化
AIChatController.java 新增 POST /report/analyze 端点:会员检查 + Redis 计数 + 上下文组装 + 调 AiGateway。复用 sendMessage 的上下文组装逻辑(抽出私有方法)

端点签名:

POST /api/ai/report/analyze
Request: { "query": "..." , "reportId": 123, "conversationId": "可选", "memberId": "可选" }
Response: Result<{ answer, conversationId }>

前端(cfc-frontend)

文件 改动
report-detail.vue 新增底部「🎯 快速分析」按钮 + 浮层组件(消息区/输入框/快捷问题/加载态/禁用态)
api.js 新增 reportQuickAnalyze(query, reportId, conversationId) 封装

5. 会员判定

  • 后端判定源:User.memberLevel(FREE/FAMILY/PROVIDER)
  • JwtInterceptor 已从 token 提取 userId,端点内 userService.getUserInfo(userId)memberLevel
  • 前端也可用 getMyMembership() 预判(仅用于 UI 展示,最终以后端校验为准)

6. 错误处理

场景 行为
query 为空 Result.error("消息不能为空")
reportId 为空 Result.error("报告ID不能为空")
免费版超限 Result.error("免费版每日仅限 1 次快速分析,升级会员解锁更多")
Redis 异常(免费计数失败) fail-open 放行 + log.warn("Redis 计数失败,放行: {}", e.getMessage())
AiGateway 返回 null(熔断/超时) Result.error("AI 服务暂不可用,请稍后重试")
LangGraph 调用异常 同上,由 AiGateway 捕获后返回 null,端点统一处理

7. 验证计划

后端

cd cfc-backend && mvn clean compile

手动验证

场景 预期
免费版第 1 次提问 正常返回 answer
免费版第 2 次提问 返回错误「免费版每日仅限 1 次…」
免费版次日 计数重置,可再问
付费版多轮 追问时带 conversationId,AI 记得上文
报告上下文注入 回答体现报告内容(如指标/菌群)
Redis 停掉 免费版仍可用(fail-open),记 warn 日志

8. 风险与注意事项

  1. Redis 是新增基础设施:后端首次引入,需确认生产 Redis 可用;本地开发需 Docker/本地 Redis 或后端 redis.host 指向测试环境
  2. 免费版滥用:按 userId 计数,同一家庭多账号可分别获得 1 次额度(可接受的初期策略)
  3. 上下文长度:报告 payload 可能较大,familyContextService.buildContext 已做截断控制(沿 sendMessage 既有逻辑,无需新增)
  4. AiGateway 熔断共享:快速分析与通用聊天共享同一个 AiGateway 熔断器,若聊天高频失败会连带影响快速分析(可接受的现状)