# 报告快速分析功能设计 日期: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 计数 ```java // 在 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` 的上下文组装逻辑(抽出私有方法) | 端点签名: ```json 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. 验证计划 ### 后端 ```bash 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 熔断器,若聊天高频失败会连带影响快速分析(可接受的现状)