日期:2026-08-31 状态:已获用户方案确认(P0+P1 第一批,P2 后续) 关联:
FiveDimensionSelfCheckService/AiGateway/cfc-langgraph
现有五维自检使用静态五行寻源表(WuxingSourcingService 硬编码 5 条建议)生成结果,所有用户看到相同文案,无个性化、无趋势感知。
本批次实现 P0+P1 共 4 个子系统,按优先级排序:
| 优先级 | 子系统 | 目标 |
|---|---|---|
| P0-1 | 静态建议 → AI 个性化建议 | 每次自检生成有温度、有针对性的解读 |
| P0-2 | 用户点击生成健康计划 | 自检低分可一键生成家庭健康计划草稿 |
| P1-1 | 历史趋势 + AI 解读 | 3 次自检趋势可视化 + AI 趋势分析 |
| P1-2 | 自检结果注入 AI Chat | 聊天页自动携带自检上下文 |
P2(家庭成员差异化建议)延后单独实现。
已确认决策:
WuxingSourcingService 仅保留 levelOf/levelName/dimensionName)advices 字段,新结构 [{dimension, interpretation, microActions, aiInsight}]FiveDimensionSelfCheckController:/questions /submit /latest /historyFiveDimensionSelfCheckService:
QUESTION_BANK(15题)、SUB_DIMENSION_QUESTION_BANK(19题)submitSelfCheck:计分 → wuxingSourcingService.getAdvicesForLowScores() → 落库 adviceJsongetQuestions() 已改为支持 retake 参数(上个计划完成)WuxingSourcingService:静态 SOURCING_TABLE(5行×5列)+ levelOf/levelName/dimensionName 纯工具方法five_dimension_self_checks:adviceJson TEXTAiGateway.java:统一网关(熔断+降级+PII脱敏)
chat(query, userId, conversationId, inputs) → POST /api/v1/chatgenerateInnateReading(portrait) → POST /api/v1/innate/readinggenerateHealthPlan(inputs) → POST /api/v1/analysis/runcfc-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 注册各 routerInnatePortraitController → InnatePortraitService.generateAiReading() → AiGateway.generateInnateReading() → LangGraph /api/v1/innate/reading → innate_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)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。
self_check_analysis_graph(P0-1):
dict:scores(Map)、questionIds(List[int])、userId(int)、recentHistory(List[dict] 最近3次自检快照)
dict:advice_json(新结构 JSON string)、fallback_used(bool)self_check_trend_graph(P1-1):
dict:history(List[dict] 最近3次含 totalScore/dimensions/createdAt)、userId(int)dict:aiInsight(str)、trendSummary(str)POST /api/family/self-check/submit(P0-1)AI 建议在 submitSelfCheck 时同步生成并落库 adviceJson(不单独暴露 analysis 接口,避免 YAGNI 冗余)。
POST /api/family/self-check/submit
↓
submitSelfCheck():计分 → selfCheckAnalysisService.generateAdvice(...) → 落库
POST /api/family/self-check/generate-plan(P0-2)请求:{ "checkId": 12 }(可空,默认取最近一次)。
响应 Result<Map>:
{ "planId": 45, "status": "draft" }
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"
}
POST /api/family/self-check/submit(P0-1)删除 WuxingSourcingService.getAdvicesForLowScores() 调用,改为:
SelfCheckAdviceResult adviceResult = selfCheckAnalysisService.generateAdvice(userId, scoreMap, questionIds);
// adviceResult 含 adviceJson + fallbackUsed
// 直接落库
SelfCheckResultVO 字段SelfCheckResultVO.advices 类型保持 List<WuxingSourcingAdviceVO> 不变,字段结构按 5.4 改造后的 VO 承载 AI 建议内容。
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) { ... }
}
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
}
DIMENSION_META、levelOf()、levelName()、dimensionName()(被 buildDimensionScoreVO 使用)SOURCING_TABLE、getAdvice()、getAdvicesForLowScores()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 / actioninterpretation(String,AI 对低分维度的解读)microActions(List<String>,2-3 个本周微行动)aiInsight(String,AI 补充洞察,可空)fallbackUsed(Boolean,AI 不可用降级标记)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 解析 → 返回
self_check_trend_graph.pySYSTEM_PROMPT = """分析用户近3次五维自检趋势,输出:
- aiInsight: 趋势解读(2-3句,指出最大变化维度和可能原因)
- trendSummary: 各维度 delta(如"身-2 智+1 富0 行-1 心+2")
返回 JSON:{"aiInsight": "...", "trendSummary": "..."}
"""
cfc-langgraph/app/api/self_check.py:
POST /api/v1/self-check/analysis → self_check_analysis_graphPOST /api/v1/self-check/trend → self_check_trend_graphcfc-langgraph/app/main.py:追加 app.include_router(self_check.router)
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>
在结果页底部按钮区追加(有低分维度时显示):
<button v-if="hasLowScore && !planGenerating" class="plan-btn" @click="generatePlan">
生成健康计划
</button>
新增 POST /api/family/self-check/trend-analysis,结果页中间页可展示(或结果页底部加「查看趋势」链接)。
在 self-check-result.vue 加「问问 AI」按钮:
<button @click="askAI">问问 AI</button>
跳转:uni.navigateTo({ url: '/pages/ai/chat?selfCheckId=' + result.id })
AIChatController 读取 selfCheckId,调 getSelfCheckLatest,将结果放入 context 传给 AiGateway。
AiGateway 熔断/open 时,generateAdvice 返回 fallbackUsed=true,adviceJson=null,前端显示"AI 分析暂时不可用"validate 节点捕获,返回 error,Java 侧 fallbackUsed=truemvn clean compile BUILD SUCCESSnode --check api.js 语法校验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 注入,需确认是否存在)