$ cd ../blog
$ cat ~/blog/AI 应用开发/llm-workflow-05-ai-coach-shell.mdx

LLM 学习工作流(五):AI 教练页面 Shell

2026年4月21日·10 min read
<AI 应用开发 />
AILLMVuePiniaUI 设计工程实践

这一步在做什么

这一步把前面准备好的:

  • 工作流状态
  • AI payload
  • Edge Function scaffold

开始接到一个真正的页面入口上,也就是:

  • 新的 Pinia store
  • 新的 /coach 路由
  • 新的 AI 教练页面骨架

最终涉及的主要文件是:

  • src/stores/aiCoach.js
  • src/views/AICoach.vue
  • src/router/index.js
  • tests/ai-coach-route.test.js

为什么这一步重要

很多 AI 项目到这一步会犯一个很常见的问题:

  • 还没把真实流程接好
  • 就先写一堆"看起来像真的"的假状态

这样短期看起来页面更"完整",但长期会制造大量误导。

Task 5 的真正目标不是做成完整产品,而是:

先搭一个可接线的 UI 壳子。

也就是先回答:

  1. AI 教练页长什么样
  2. 页面入口怎么进
  3. Store 的最小状态是什么
  4. 哪些地方现在只是占位,后面再接真实逻辑

一开始做了什么

第一版提交是:

  • 8139f494 feat: add ai coach page and route

它确实把页面、路由和 store 做出来了,但很快在 review 里暴露出一个典型问题:

过早把"假流程"做得太像真流程

第一版里做了这些事情:

  • 本地持久化 profile / plan / reflection
  • 自己造了一个新的 workflow stage 模型
  • 用户点几下按钮就能"生成计划""生成测验""生成复盘"
  • 甚至能把流程走到"4/4 完成"

问题在于:

  • 这些都不是真 AI 逻辑
  • 也没有接真实服务端
  • 但 UI 已经会给用户一种"系统已经真的做完了"的感觉

这就是典型的 shell 阶段过度实现。

为什么这是个问题

1. 它会制造假的产品语义

如果一个页面显示:

  • 当前阶段 100%
  • 已生成复盘
  • 已完成今日流程

用户自然会理解成:

  • 系统真的算过了
  • AI 真的返回过结果

但如果这其实只是本地硬编码拼出来的,那页面就在撒谎。

2. 它会和后续真实工作流冲突

我们前面已经有 canonical workflow helper:

  • src/utils/learning-workflow.js

如果此时又在 aiCoach store 里单独造一套:

  • stage
  • completedSteps
  • totalSteps

那后面接真实工作流时就会出现:

  • 一套页面自己的阶段定义
  • 一套系统真正的阶段定义

这会让集成变得很痛苦。

3. 它会让调试变复杂

一旦页面显示的"计划/复盘"是假的,后面你再接真实 API 时,排查问题会变难:

  • 是页面自己的假状态
  • 还是 API 回来的真状态
  • 还是本地缓存的旧状态

这类问题会极大降低开发效率。

修正后做了什么

修正后的提交是:

  • 8dfd7c0f fix: reduce ai coach shell state

这次修正的核心目标只有一个:

把它拉回真正的 shell。

1. Store 回到最小状态

最终的 src/stores/aiCoach.js 只保留最小的四个状态:

  • profile
  • activeRun
  • dailyPlan
  • reflection

而且都是:

ref(null)

这意味着:

  • 默认没有假数据
  • 默认没有假完成度
  • 默认没有假 AI 输出

2. 异步方法保留接口,但不再伪造结果

Store 里仍然保留:

  • saveProfile
  • generateDailyPlan
  • generateQuiz
  • summarizeReflection

但它们现在是 shell 级别的 placeholder,不会再伪造完整流程状态。

这样做的好处是:

  • 页面已经有可以调用的接口
  • 后续任务直接接入真实逻辑即可
  • 但当前页面不会"装作已经实现了 AI"

3. 页面只表达"这里未来会接什么"

修正后的 src/views/AICoach.vue 保留了四个必须的区块:

  • 学习画像表单
  • 今日计划卡片
  • 当前阶段进度
  • 复盘结果区

但它们现在都使用:

  • 中性占位文案
  • 非误导性的空状态
  • 清晰的"后续会接真实 AI 逻辑"的提示

这就让页面从"假成品"变成了"真骨架"。

测试为什么也要一起升级

最开始的测试只验证:

path: '/coach'
name: 'AICoach'

这个太弱了,因为它只能证明:

  • 路由存在

但不能证明:

  • 路由是不是 requiresAuth
  • 组件是不是 AICoach.vue
  • 页面是不是有四个必需区块
  • 页面里有没有误导性的旧文案

所以修正后,测试开始检查:

  • /coach
  • AICoach
  • AI 学习教练
  • requiresAuth: true
  • AICoach.vue
  • 四个 section 标题
  • 并排除旧的误导性 workflow 文案

这说明一个很重要的实践点:

当实现比最初预期复杂时,测试也必须同步升级。

这一步真正学到什么

1. Shell 阶段最重要的是"不撒谎"

一个好的占位页应该做到:

  • 看得出未来功能长什么样
  • 但不假装未来功能已经实现

这是 AI 项目里非常重要的工程审美。

2. 页面壳子和业务真逻辑要严格分层

Task 5 里最危险的点就是:

  • 把"壳子"做成了"假的业务逻辑"

修正后学到的核心是:

  • 页面先只要壳子
  • 真状态机和真 AI 逻辑等后续任务接入

3. 过早持久化是假复杂度

第一版里把很多 placeholder 数据写进了 localStorage。

这类持久化没有真实业务价值,却会产生:

  • 状态清理问题
  • 调试混乱
  • 用户误解

所以在没有真实数据闭环之前,最好不要提前持久化假结果。

4. 路由测试不能只测 path

页面入口的真实要求常常包括:

  • 权限
  • 标题
  • 组件
  • 基本结构

只测 path 和 name,很多错误其实根本不会被发现。

这一步最终做成了什么

路由层

现在已经有:

{
  path: '/coach',
  name: 'AICoach',
  component: () => import('@/views/AICoach.vue'),
  meta: { title: 'AI 学习教练', requiresAuth: true }
}

Store 层

现在已经有一个真正可扩展的 AI Coach store shell:

  • 状态接口已经确定
  • 方法接口已经确定
  • 但没有提前捏造业务语义

页面层

现在已经有一个清晰的 AI 教练页骨架:

  • 可以承载画像输入
  • 可以承载计划结果
  • 可以承载当前阶段
  • 可以承载复盘结果

但不会误导用户说"这些已经接上真实 AI 了"。

你可以自己复现什么

跑这一步的测试

node --test tests/ai-coach-route.test.js -v

跑构建

npm run build

看这一步的关键提交

git log --oneline -3

你会看到:

  • 8139f494 初始版本,壳子做得太像真流程
  • 8dfd7c0f 修正成真正的 shell

这一步你应该学会什么

  • 为什么 shell 阶段不能提前伪造业务结果
  • 为什么页面骨架和真实 AI 流程必须分层
  • 为什么假状态持久化会制造复杂度
  • 为什么路由测试要同时看 path、meta、component 和页面结构
  • 一个"看起来更完整"的实现为什么反而可能更差

下一步会做什么

下一步是 Task 6

  • 首页接入 AI 教练入口
  • 全局导航接入 /coach
  • 把这个新页面真正变成用户能发现、能进入的功能入口

也就是说,接下来你会从"页面壳子存在"推进到:

功能入口真正暴露给用户