2026-08-31-self-check-ai-integration-design.md 15 KB

五维家庭自检 AI 结合(P0 + P1)设计

日期:2026-08-31 状态:已获用户方案确认(P0+P1 第一批,P2 后续) 关联:FiveDimensionSelfCheckService / AiGateway / cfc-langgraph


1. 背景与目标

现有五维自检使用静态五行寻源表WuxingSourcingService 硬编码 5 条建议)生成结果,所有用户看到相同文案,无个性化、无趋势感知。

本批次实现 P0+P1 共 4 个子系统,按优先级排序:

优先级 子系统 目标
P0-1 静态建议 → AI 个性化建议 每次自检生成有温度、有针对性的解读
P0-2 用户点击生成健康计划 自检低分可一键生成家庭健康计划草稿
P1-1 历史趋势 + AI 解读 3 次自检趋势可视化 + AI 趋势分析
P1-2 自检结果注入 AI Chat 聊天页自动携带自检上下文

P2(家庭成员差异化建议)延后单独实现。

已确认决策:

  • P0-1:纯 AI 替换,不保留静态五行寻源建议(WuxingSourcingService 仅保留 levelOf/levelName/dimensionName
  • P0-2:用户点击才生成,不自动创建 draft plan
  • P0-1 字段设计:直接改造 advices 字段,新结构 [{dimension, interpretation, microActions, aiInsight}]

2. 现状盘点

后端(自检)

  • FiveDimensionSelfCheckController/questions /submit /latest /history
  • FiveDimensionSelfCheckService
    • QUESTION_BANK(15题)、SUB_DIMENSION_QUESTION_BANK(19题)
    • submitSelfCheck:计分 → wuxingSourcingService.getAdvicesForLowScores() → 落库 adviceJson
    • getQuestions() 已改为支持 retake 参数(上个计划完成)
  • WuxingSourcingService:静态 SOURCING_TABLE(5行×5列)+ levelOf/levelName/dimensionName 纯工具方法
  • five_dimension_self_checksadviceJson TEXT

后端(AI 基础设施)

  • AiGateway.java:统一网关(熔断+降级+PII脱敏)
    • chat(query, userId, conversationId, inputs)POST /api/v1/chat
    • generateInnateReading(portrait)POST /api/v1/innate/reading
    • generateHealthPlan(inputs)POST /api/v1/analysis/run
  • LangGraph Python(cfc-langgraph/app/,端口 9000):
    • app/graphs/chat_graph.py(78行,Dify 兼容)
    • app/graphs/health_plan_graph.py(297行,Java 客户端 JavaClient 读取家庭数据)
    • app/graphs/innate_portrait_graph.py(65行,参考实现)
    • app/api/adapter.py(Dify 兼容路由)
    • app/api/innate_portrait.py/api/v1/innate/reading
    • app/main.py 注册各 router
  • 参考链路:InnatePortraitControllerInnatePortraitService.generateAiReading()AiGateway.generateInnateReading() → LangGraph /api/v1/innate/readinginnate_portrait_graph.py → 成功返回 reading,失败 null(调用方降级模板)

前端

  • pages/family/self-check-result.vue:结果页,advices 展示在第 71-123 行(五行相生寻源建议区块)
  • pages/family/self-check-entry.vue:中间页(刚实现)
  • pages/ai/chat.vue:AI 聊天页(需确认路径)
  • utils/api.js:自检相关方法(getSelfCheckStatus/ignoreSelfCheck/getSelfCheckQuestions/submitSelfCheck/getSelfCheckLatest/getSelfCheckHistory

3. 数据层设计

3.1 adviceJson 结构变更

旧结构(静态五行寻源):

[
  {
    "dimension": "mind",
    "dimensionName": "心",
    "element": "火",
    "color": "#FF6B9D",
    "score": 2,
    "level": "tense",
    "levelName": "紧绷",
    "upstreamDimension": "action",
    "upstreamName": "行",
    "upstreamElement": "木",
    "upstreamColor": "#10B981",
    "upstreamReason": "关系顺畅了,内心才安定",
    "restrainerDimension": "wealth",
    "restrainerName": "富",
    "restrainerElement": "水",
    "restrainerColor": "#F59E0B",
    "restrainerReason": "钱多了,情薄了",
    "action": "关系周记;家庭夜谈"
  }
]

新结构(AI 生成):

[
  {
    "dimension": "mind",
    "dimensionName": "心",
    "element": "火",
    "color": "#FF6B9D",
    "score": 2,
    "level": "tense",
    "levelName": "紧绷",
    "interpretation": "你的心能量偏低,可能最近情绪压力较大...",
    "microActions": ["今晚睡前做10分钟深呼吸", "和伴侣约定每周一次夜谈"],
    "aiInsight": "建议从'行'维度入手...",
    "fallbackUsed": false
  }
]

注意dimension/dimensionName/element/color/score/level/levelName 字段保留,与现有 VO 兼容。upstreamDimension/upstreamReason/restrainerDimension 等静态字段移除,新增 interpretation/microActions/aiInsight/fallbackUsed

3.2 新增 LangGraph Graph 输入/输出

self_check_analysis_graph(P0-1):

  • 输入 dictscores(Map)、questionIds(List[int])、userId(int)、recentHistory(List[dict] 最近3次自检快照)
  • 输出 dictadvice_json(新结构 JSON string)、fallback_used(bool)
  • self_check_trend_graph(P1-1):

    • 输入 dicthistory(List[dict] 最近3次含 totalScore/dimensions/createdAt)、userId(int)
    • 输出 dictaiInsight(str)、trendSummary(str)

    4. 后端接口设计

    4.1 修改 POST /api/family/self-check/submit(P0-1)

    AI 建议在 submitSelfCheck同步生成并落库 adviceJson(不单独暴露 analysis 接口,避免 YAGNI 冗余)。

    POST /api/family/self-check/submit
      ↓
    submitSelfCheck():计分 → selfCheckAnalysisService.generateAdvice(...) → 落库
    

    4.2 新增 POST /api/family/self-check/generate-plan(P0-2)

    请求:{ "checkId": 12 }(可空,默认取最近一次)。

    响应 Result<Map>

    { "planId": 45, "status": "draft" }
    

    4.3 新增 POST /api/family/self-check/trend-analysis(P1-1)

    请求:无 body(JWT 取 userId)。

    响应 Result<TrendAnalysisVO>

    {
      "history": [{ "createdAt": "...", "totalScore": 32, "dimensions": [...] }],
      "aiInsight": "近三次身维度持续下降,可能...",
      "trendSummary": "身-2 智+1 富0 行-1 心+2"
    }
    

    4.4 修改 POST /api/family/self-check/submit(P0-1)

    删除 WuxingSourcingService.getAdvicesForLowScores() 调用,改为:

    SelfCheckAdviceResult adviceResult = selfCheckAnalysisService.generateAdvice(userId, scoreMap, questionIds);
    // adviceResult 含 adviceJson + fallbackUsed
    // 直接落库
    

    4.5 SelfCheckResultVO 字段

    SelfCheckResultVO.advices 类型保持 List<WuxingSourcingAdviceVO> 不变,字段结构按 5.4 改造后的 VO 承载 AI 建议内容。


    5. Java 服务层设计

    5.1 新增 SelfCheckAnalysisService

    @Service
    public class SelfCheckAnalysisService {
        @Resource private AiGateway aiGateway;
        @Resource private FiveDimensionSelfCheckMapper selfCheckMapper;
        
        /** 生成自检建议(AI 优先,LangGraph 失败返回 null) */
        public SelfCheckAdviceResult generateAdvice(Long userId, Map<String, Integer> scoreMap, List<Integer> questionIds) {
            // 1. 组装 inputs
            // 2. 调 aiGateway.generateSelfCheckAdvice(inputs)
            // 3. 返回 SelfCheckAdviceResult(含 adviceJson + fallbackUsed)
        }
        
        /** 生成趋势分析 */
        public TrendAnalysisVO getTrendAnalysis(Long userId) { ... }
    }
    

    5.2 AiGateway 新增方法

    public Map<String, Object> generateSelfCheckAdvice(Map<String, Object> inputs) {
        // POST /api/v1/self-check/analysis
        // 失败返回 null(调用方设置 fallbackUsed=true)
    }
    
    public Map<String, Object> generateSelfCheckTrend(Map<String, Object> inputs) {
        // POST /api/v1/self-check/trend
    }
    

    5.3 WuxingSourcingService 变更

    • 保留DIMENSION_METAlevelOf()levelName()dimensionName()(被 buildDimensionScoreVO 使用)
    • 删除SOURCING_TABLEgetAdvice()getAdvicesForLowScores()

    5.4 WuxingSourcingAdviceVO 改造(P0-1)

    不新建 VO,直接改造现有 dto/WuxingSourcingAdviceVO.java(保持 SelfCheckResultVO.advices 类型不变,最小改动):

    • 保留字段dimension / dimensionName / element / color / score / level / levelName(与现有 VO 兼容)
    • 移除字段upstreamDimension / upstreamName / upstreamElement / upstreamColor / upstreamReason / restrainerDimension / restrainerName / restrainerElement / restrainerColor / restrainerReason / action
    • 新增字段
      • interpretation(String,AI 对低分维度的解读)
      • microActions(List<String>,2-3 个本周微行动)
      • aiInsight(String,AI 补充洞察,可空)
      • fallbackUsed(Boolean,AI 不可用降级标记)

    6. LangGraph Python 设计

    6.1 新增 self_check_analysis_graph.py

    # cfc-langgraph/app/graphs/self_check_analysis_graph.py
    SYSTEM_PROMPT = """你是一位家庭健康顾问,基于五维自检结果(身·智·富·行·心,每维0-9分,满分45)给出个性化建议。
    
    要求:
    1. 用第二人称"你"称呼
    2. 对每个低分维度(≤6分)给出1-2句解读和2-3个具体可执行的微行动
    3. 如有历史数据,简要对比趋势
    4. 语气温暖口语化,不超过300字/维度
    5. 最后给出1句家庭整体洞察
    
    返回 JSON:
    {
      "advice": [
        {"dimension": "mind", "dimensionName": "心", "interpretation": "...", "microActions": ["...", "..."]},
        ...
      ],
      "familyInsight": "..."
    }
    """
    
    class SelfCheckAnalysisAgent:
        async def run(self, scores: dict, questionIds: list, recentHistory: list, userId: int) -> dict:
            # 格式化输入 → LLM → JSON 解析 → 返回
    

    6.2 新增 self_check_trend_graph.py

    SYSTEM_PROMPT = """分析用户近3次五维自检趋势,输出:
    - aiInsight: 趋势解读(2-3句,指出最大变化维度和可能原因)
    - trendSummary: 各维度 delta(如"身-2 智+1 富0 行-1 心+2")
    返回 JSON:{"aiInsight": "...", "trendSummary": "..."}
    """
    

    6.3 注册路由

    cfc-langgraph/app/api/self_check.py

    • POST /api/v1/self-check/analysisself_check_analysis_graph
    • POST /api/v1/self-check/trendself_check_trend_graph

    cfc-langgraph/app/main.py:追加 app.include_router(self_check.router)


    7. 前端设计

    7.1 P0-1:self-check-result.vue 建议区块重写

    删除现有 scr-card 寻源建议区块(第 71-123 行),替换为:

    <view class="ai-advice-card" v-if="result.adviceJson">
      <view class="ai-advice-header">
        <text class="ai-advice-title">AI 健康解读</text>
        <text class="ai-advice-sub">基于你的五维自检结果</text>
      </view>
      <view v-for="item in result.adviceJson" :key="item.dimension" class="ai-advice-item">
        <view class="ai-advice-dim-badge" :style="{background: item.color}">
          <text>{{ item.dimensionName }}</text>
          <text>{{ item.score }}分</text>
        </view>
        <text class="ai-advice-interpretation">{{ item.interpretation }}</text>
        <view class="ai-advice-actions">
          <text class="ai-advice-action-label">本周行动:</text>
          <text v-for="(action, i) in item.microActions" :key="'a'+i" class="ai-advice-action">{{ i+1 }}. {{ action }}</text>
        </view>
      </view>
      <view class="ai-advice-family" v-if="result.adviceJson[0] && result.adviceJson[0].familyInsight">
        <text class="ai-advice-family-label">💡 家庭整体洞察</text>
        <text class="ai-advice-family-text">{{ result.adviceJson[0].familyInsight }}</text>
      </view>
    </view>
    <view class="ai-advice-fallback" v-else-if="result.fallbackUsed">
      <text>AI 分析暂时不可用,请稍后再试</text>
    </view>
    

    7.2 P0-2:结果页加「生成健康计划」按钮

    在结果页底部按钮区追加(有低分维度时显示):

    <button v-if="hasLowScore && !planGenerating" class="plan-btn" @click="generatePlan">
      生成健康计划
    </button>
    

    7.3 P1-1:趋势展示

    新增 POST /api/family/self-check/trend-analysis,结果页中间页可展示(或结果页底部加「查看趋势」链接)。

    7.4 P1-2:Chat 注入 context

    self-check-result.vue 加「问问 AI」按钮:

    <button @click="askAI">问问 AI</button>
    

    跳转:uni.navigateTo({ url: '/pages/ai/chat?selfCheckId=' + result.id })

    AIChatController 读取 selfCheckId,调 getSelfCheckLatest,将结果放入 context 传给 AiGateway。


    8. 边界行为与错误处理

    1. LangGraph 不可用AiGateway 熔断/open 时,generateAdvice 返回 fallbackUsed=trueadviceJson=null,前端显示"AI 分析暂时不可用"
    2. LLM 返回非 JSON:Python 侧 validate 节点捕获,返回 error,Java 侧 fallbackUsed=true
    3. P0-2 计划生成失败:toast "计划生成失败,请稍后重试",不阻断结果页
    4. P1-1 历史不足 3 次:用现有次数展示(1-2 次),LLM 做有限对比
    5. P1-2 chat 上下文:selfCheckId 无效时静默跳过,不影响 chat 正常流程

    9. 测试与验证

    • 后端:mvn clean compile BUILD SUCCESS
    • 前端:node --check api.js 语法校验
    • 手动验证路径:
      1. 提交自检 → 查看 adviceJson 含 AI 生成内容(非静态表)
      2. 点「生成健康计划」→ 跳转 plan 详情(draft 状态)
      3. 点「查看趋势」→ 展示趋势 + AI 解读
      4. 点「问问 AI」→ chat 页,LLM 回答知晓自检背景

    10. 文件变更清单

    LangGraph Python(新增 2 graph + 1 api + 改 main)

    • cfc-langgraph/app/graphs/self_check_analysis_graph.py(P0-1)
    • cfc-langgraph/app/graphs/self_check_trend_graph.py(P1-1)
    • cfc-langgraph/app/api/self_check.py(路由注册)
    • cfc-langgraph/app/main.py(追加 router include)

    Java 后端

    • dto/WuxingSourcingAdviceVO.java(改造:移除 upstream/restrainer/action,新增 interpretation/microActions/aiInsight/fallbackUsed)
    • service/SelfCheckAnalysisService.java(新建)
    • service/WuxingSourcingService.java(删除 SOURCING_TABLE/getAdvice/getAdvicesForLowScores)
    • service/FiveDimensionSelfCheckService.java(修改 submitSelfCheck 调新 Service,新增 trend 方法)
    • service/AiGateway.java(新增 2 方法)
    • controller/family/FiveDimensionSelfCheckController.java(新增 3 接口,修改 submit)
    • service/HealthPlanService.java(新增 generateFromSelfCheck)
    • service/impl/HealthPlanServiceImpl.java(实现 generateFromSelfCheck)

    前端

    • utils/api.js(新增 3 方法)
    • pages/family/self-check-result.vue(P0-1/P0-2/P1-2 改造)
    • pages/family/self-check-entry.vue(P1-1 趋势展示)
    • pages/ai/chat.vue(P1-2 context 注入,需确认是否存在)