实现计划.md 13 KB

数据与 AI 结合 — 实现计划

依赖关系图

Phase 1.1 (DB迁移) ──→ 1.3 (createDynamicTask) ──→ 1.4 (Controller改造)
                                                       │
Phase 1.2 (TaskParseService) ──────────────────────────┘
                                                       │
Phase 1.8 (FamilyContext增强) ─────────────────────────┘
                                                       ↓
                                             1.9 (编译验证)
                                                       │
               ┌───────────────────────────────────────┘
               ↓
Phase 1.5 (AITaskCard组件) ──→ 1.6 (chat.vue改造) ──→ 1.7 (报告详情页入口)
                                                                  │
                                                                  ↓
                                                         Phase 2.x (持续增强)

Phase 1: 基础能力 — 2周

1.1 数据库迁移 — growth_tasks 表扩展

目标: 支持 AI_GENERATED 类型任务,新增维度跟踪字段

文件:

  • cfc-backend/src/main/resources/schema.sql — 同步建表语句
  • cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java — 迁移代码
  • cfc-backend/src/main/java/com/etotem/cfc/entity/GrowthTask.java — 新增字段

迁移内容:

-- migration N: growth_tasks 支持 AI 生成任务
ALTER TABLE growth_tasks MODIFY COLUMN type
  ENUM('DAILY','NEWBIE','AI_GENERATED') NOT NULL DEFAULT 'DAILY';
ALTER TABLE growth_tasks ADD COLUMN dimension VARCHAR(20) NULL COMMENT '五维维度';
ALTER TABLE growth_tasks ADD COLUMN source_conversation_id VARCHAR(100) NULL COMMENT '来源AI会话ID';

实体类新增字段:

@TableField("dimension")
private String dimension;

@TableField("source_conversation_id")
private String sourceConversationId;

验收: mvn clean compile 通过,迁移可重复执行不报错


1.2 TaskParseService — [TASK] 标记解析

目标: 新建服务解析 Dify 返回的 [TASK:{...}] 标记,提取任务参数

文件: 新建 cfc-backend/src/main/java/com/etotem/cfc/service/TaskParseService.java

1. TASK: 解析 Dify answer 中的 [TASK:{"title":"...","description":"...",...}] 标记
2. EXPECTED OUTCOME: 返回解析后的 TaskParseResult 对象列表
3. REQUIRED TOOLS: 正则 Pattern + Jackson ObjectMapper
4. MUST DO:
   - 正则 `\[TASK:\s*(\{.*?\})\](?:\s*\[TASK:...)*` 提取所有 TASK 标记
   - 解析 JSON → TaskParseResult 对象
   - 校验 title 必填
   - 返回解析结果列表
   - 从原 answer 中移除所有 TASK 标记
5. MUST NOT DO: 不写入数据库(由调用方控制)

TaskParseResult DTO:

public class TaskParseResult {
    private String title;          // 必填
    private String description;    // 选填
    private String deadline;       // 选填 yyyy-MM-dd
    private String dimension;      // 选填 body/mind/wisdom/action/wealth
    private Integer rewardPoints;  // 选填
}

验收: "[TASK:{\"title\":\"读书30分钟\",\"dimension\":\"wisdom\"}]" → 解析出 title=读书30分钟, dimension=wisdom


1.3 GrowthTaskService.createDynamicTask()

目标: 新增方法,根据 AI 生成的任务参数创建 growth_tasks + growth_task_log

文件: cfc-backend/src/main/java/com/etotem/cfc/service/GrowthTaskService.java

新增方法:

/**
 * 创建 AI 动态生成任务
 * @param userId 目标用户ID
 * @param task 解析后的任务参数
 * @param conversationId 来源AI会话ID
 * @return 创建的任务ID
 */
@Transactional
public Long createDynamicTask(Long userId, TaskParseResult task, String conversationId) {
    // 1. 插入 growth_tasks (type=AI_GENERATED, enabled=1)
    // 2. 插入 growth_task_log (progress=0, completed=0, claimed=0)
    // 3. 返回 taskId
}

验收: 调用后 growth_tasks 和 growth_task_log 各多一条记录


1.4 AIChatController 通用化改造

目标: 统一处理 [RECOMMEND][TASK] 标记,全模式支持推荐

文件: cfc-backend/src/main/java/com/etotem/cfc/controller/ai/AIChatController.java

改动点:

  1. sendMessage() 方法改造:

    • 将原来只在 sendNutritionMessage() 中的 RECOMMEND 解析提取为通用方法
    • 在 sendMessage() 返回前统一调用 parseAndHandleMarkers(answer)
    • 返回值结构扩展:{ answer, conversationId, recommendations, tasks }
  2. parseAndHandleMarkers() 新增方法:

    private Map<String, Object> parseAndHandleMarkers(String answer, Long userId, String conversationId) {
       // 1. 解析 [RECOMMEND:...] → RecommendationService.search
       // 2. 解析 [TASK:...] → TaskParseService → GrowthTaskService.createDynamicTask
       // 3. 返回 { cleanAnswer, recommendations, tasks }
    }
    
  3. sendNutritionMessage() 简化: 复用 parseAndHandleMarkers() 避免重复

验收:

  • 普通对话输入"帮我推荐一些健康食品" → response 含 recommendations 列表
  • 普通对话输入"给我安排一个每天读书的任务" → response 含 tasks 列表
  • 旧功能不受影响(回归:营养对话仍能正常推荐)

1.5 AITaskCard 组件

目标: 可复用的任务卡片组件,展示任务信息 + 接受按钮

文件: 新建 cfc-frontend/components/AITaskCard.vue

<template>
  <view class="ai-task-card">
    <view class="task-header">
      <text class="task-icon">📋</text>
      <text class="task-title">{{ task.title }}</text>
    </view>
    <text class="task-desc" v-if="task.description">{{ task.description }}</text>
    <view class="task-footer">
      <text class="task-dimension" v-if="task.dimension">维度:{{ dimLabel }}</text>
      <text class="task-deadline" v-if="task.deadline">截止:{{ task.deadline }}</text>
    </view>
    <button class="task-accept-btn" :loading="accepting" @click="handleAccept">接受任务</button>
  </view>
</template>

<script>
export default {
  props: {
    task: Object,
    conversationId: String
  },
  data() { return { accepting: false } },
  methods: {
    async handleAccept() {
      // 调用 POST /api/tasks/accept-dynamic
      // 参数: { taskTitle, taskDescription, deadline, dimension, conversationId }
      this.accepting = true
      try {
        const res = await api.acceptDynamicTask({...})
        if (res.code === 200) {
          uni.showToast({ title: '任务已接受' })
          this.$emit('accepted', res.data)
        }
      } finally {
        this.accepting = false
      }
    }
  }
}
</script>

验收: 组件在 chat.vue 中导入后可正常渲染和点击接受


1.6 chat.vue 改造

目标: 支持任务卡片渲染、全模式推荐展示、报告解读模式

文件: cfc-frontend/pages/ai/chat.vue

改动点:

  1. 消息结构扩展 — 在 data 中支持 tasks 字段
  2. 模板新增任务卡片区域 — messages 循环中插入 AITaskCard
  3. 推荐卡片区域增强 — 从 only nutrition 模式扩展到所有模式
  4. 新模版:mode=report — 接收 reportId 参数,sendMessage 时自动传入
  5. 消息气泡标注来源 — 如果是报告解读,气泡上显示"基于健康报告"标签

    改动区段:
    - <template> 中 #80~90 行,推荐卡片区域改为无条件渲染
    - <template> 消息气泡内新增任务卡片区域
    - <script> data() 中新增支持任务字段
    - <script> sendMessage() 中参数扩展:reportId
    - <script> onLoad() 中新增 mode=report 处理
    

验收:

  • 普通对话返回推荐数据 → 显示推荐卡片
  • AI 返回任务 → 显示任务卡片 + 可点击接受
  • 跳转 chat.vue?mode=report&reportId=123 → 发消息时自动带 reportId

1.7 报告详情页 AI 解读入口

目标: 各报告详情页底部增加"让浠宝/福宝解读"入口

文件:

  • cfc-frontend/pages/body-detail/health-report.vue
  • cfc-frontend/pages/health/gut-index.vue
  • cfc-frontend/pages/health/tongue-index.vue
  • cfc-frontend/pages/health/report-upload.vue
  • cfc-frontend/pages/body-detail/health-report.vue

实现方式: 各页面的模板底部新增:

<view class="ai-interpret-entry" @click="goAIChat">
  <image class="ai-mascot-avatar" :src="mascotAvatar" />
  <view class="ai-entry-text">
    <text class="ai-entry-title">让 {{ mascotName }} 帮你解读</text>
    <text class="ai-entry-desc">基于这份报告,{{ mascotName }} 会给出个建议</text>
  </view>
  <text class="ai-entry-arrow">›</text>
</view>

goAIChat 方法:

goAIChat() {
  const userInfo = uni.getStorageSync('userInfo')
  const mascot = userInfo && userInfo.mascot === 'fubao' ? '福宝' : '浠宝'
  uni.navigateTo({
    url: '/pages/ai/chat?mode=report&reportId=' + this.reportId + '&firstMessage=' 
         + encodeURIComponent('你好' + mascot + ',帮我看看这份报告有什么需要注意的地方?')
  })
}

验收: 每个报告详情页底部可见 AI 入口,点击后跳转 chat.vue 并自动发送解读请求


1.8 FamilyContextService 任务上下文注入

目标: 在 AI 上下文中注入用户当前任务状态,让 Dify 感知任务进度

文件: cfc-backend/src/main/java/com/etotem/cfc/service/FamilyContextService.java

改动点: buildContext() 末尾增加:

// 6. 当前未完成任务列表
List<Map<String, Object>> pendingTasks = getPendingTasks(userId);
if (!pendingTasks.isEmpty()) {
    ctx.put("pendingTasks", pendingTasks);
}
private List<Map<String, Object>> getPendingTasks(Long userId) {
    // 查询当前用户未完成的 growth_task_log 关联的 growth_tasks
    // 返回 title, type, dimension 等信息
}

验收: 用户有未完成任务时,Dify inputs 中包含 pendingTasks 字段


1.9 编译验证

目标: 确保 Phase 1 所有后端改动编译通过,无路由冲突

cd cfc-backend && mvn clean compile
grep -rn '@Mapping' src/main/java/com/etotem/cfc/controller/ | grep -oP '@\w+Mapping\("\K[^"]*' | sort -u | grep -E '(task|ai)'

验收: mvn clean compile exit 0,新增路由无重复


Phase 2: 智能增强 — 2周

2.1 Dify Workflow 合并

平台配置(在 Dify 平台操作,非代码):

  1. 在 Dify 中创建新的 App(含 Workflow)
  2. 配置 Classifier Node,基于 query+inputs 做场景分类
  3. 配置 Report Analysis Agent / Nutrition Advisor Agent / Task Manager Agent / Family Assistant Agent
  4. 配置 Post Processor 格式化输出(合并 RECOMMEND / TASK 标记)
  5. 配置回调 URL 指向 /api/ai/context(保留原有记忆逻辑)
  6. 生成新的 API Key

后端适配:

  • AIService.java:统一使用新 API Key,删除 nutritionApiKey/tongueApiKey
  • 响应兼容处理(workflow 返回格式可能与 chat-messages 有差异)

验收: 现有所有 AI 功能在新 App 上正常运作

2.2 推荐排序优化

文件: cfc-backend/src/main/java/com/etotem/cfc/service/RecommendationService.java

改动点:

  1. search() 方法中增加排序逻辑:
    • 标签匹配度排序(匹配标签数多的优先)
    • 已购商品降权(ProductOrder 中已购买过的商品排后)
    • 维度匹配加分(与用户当前关注维度对齐的优先)
    • createdAt 时效性排序
  2. 前端推荐卡片增加"已购买"标记

2.3 任务展示与接受完整流程

后端: 新建 POST /api/tasks/accept-dynamic

@PostMapping("/api/tasks/accept-dynamic")
public Result<Long> acceptDynamicTask(@RequestAttribute("userId") Long userId,
                                      @RequestBody Map<String, Object> params) {
    // 参数:title, description, deadline, dimension, conversationId
    // 调用 growthTaskService.createDynamicTask()
    // 返回 taskId
}

前端: AITaskCard 组件点击"接受任务" → 调用此接口 → 显示成功提示


Phase 3: 体验优化 — 持续

3.1 Mascot 动效与个性化

  • 浠宝(🌟):暖橙色系动画,温柔语音提示
  • 福宝(💪):金色系动画,活泼语气
  • 表情随对话内容变化(开心/思考/鼓励)

3.2 A/B 测试

  • 对照组:无 AI 解读入口的报告详情页
  • 实验组:有 AI 解读入口
  • 指标:解读点击率、任务接受率、次日回访率

团队任务分配建议

开发 任务
后端 A 1.1 DB迁移 + 1.2 TaskParseService + 1.3 createDynamicTask
后端 B 1.4 Controller改造 + 1.8 FamilyContext增强 + 1.9 编译验证
前端 A 1.5 AITaskCard组件 + 1.6 chat.vue改造
前端 B 1.7 各报告详情页AI入口
并行启动 1.1/1.2 可先启动(无依赖),1.5 可先启动(无依赖)

回滚策略

  • 数据库迁移:ALTER TABLE ... MODIFY COLUMN 改回原 ENUM,DROP COLUMN 新字段
  • 后端:回滚 Git 提交
  • 前端:git revert 对应提交
  • Dify:保留旧 App 配置,新 App 验证通过后再切换