# M10 AI 工作台从基础接口到后台闭环

到了 `M10`，这个项目已经不缺“AI 后端能力存在”的证明了。

前面的里程碑已经逐步把这些基础打好：

- `apps/server` 已经有 Provider 适配器
- 文件提取能力已经存在
- 缓存报告接口已经存在
- `admin / viewer` 的基本角色边界也已经成立

但如果只停在这里，AI 这一条线仍然很难被读者真正理解。因为对外呈现出来的状态还是不完整：

- 后台虽然提到了 AI，但还没有一条完整的工作台主线
- 文件提取能力存在，却还没有成为后续分析的真实输入
- 管理员和 viewer 的边界更多停留在规则层，而不是页面体验层

所以 `M10` 要解决的，不是“再加更多 AI 功能”，而是把现有基础能力收成一条可演示、可解释、可继续扩展的后台闭环。

这篇文章围绕 `M10` 讲清楚四件事：

1. 为什么这一步先做 AI 工作台短链路，而不是一开始就上任务中心和队列
2. 为什么文件提取必须继续由 `NestJS` 统一承载
3. 为什么管理员真实分析和 viewer 缓存体验要收在同一个工作台里
4. 为什么教程型仓库里，AI 成本控制不能只靠“禁用按钮”

## 一、为什么 `M10` 必须单独成立

`M9` 结束后，项目已经具备了更稳定的体验基线：

- `web / admin` 已经不再只是验证态页面
- 统一主题与最小共享 UI 已经成立
- 后台开始有更清楚的工作台感

这时候继续往前做 AI，会自然遇到一个问题：

后端已经有一些 AI 能力，但前端还没有一条真正可体验、可讲解、可验证的闭环。

如果不单独把这件事拉出来做，会出现两种常见结果：

- 要么 AI 继续散落在后台零碎入口里，读者看不出主线
- 要么一上来就想做队列、历史、任务中心，直接把教程节奏拉得过快

所以 `M10` 的真正价值，不是“功能又变多了”，而是先把 AI 从“后端有能力”推进到“后台有闭环”。

这一步要收住的几个关键边界是：

- AI 工作台入口边界
- 文件输入边界
- 管理员真实分析边界
- viewer 缓存体验边界

## 二、`M10` 这轮到底要交付什么

这一轮的交付目标可以概括成一句话：

让读者看到项目如何在不引入队列、不做历史持久化、不做复杂编排系统的前提下，先立 AI 工作台入口，再接上传提取，再接管理员真实分析，最后把 viewer 的只读缓存体验真正落到页面上。

这里面有五个关键边界。

### 1. 先把 AI 能力收成独立工作台

如果 AI 入口继续散在后台首页按钮、角色动作卡或其他说明文案里，后续每增加一项能力，页面结构都会越来越乱。

所以 `M10` 的第一步，不是立刻做上传和分析，而是先把 AI 能力收成一个独立工作台，让读者先看清楚：

- 当前 Provider / model / mode 是什么
- 当前支持哪些分析场景
- 当前页面为什么要单独存在

### 2. 输入链路先站稳，再谈分析闭环

很多人做 AI 页面时，会自然想先做“输入框 + 提交分析”。

但当前项目已经有文件提取基础能力，所以更合理的顺序是：

- 先把统一输入入口接出来
- 再让它为真实分析提供输入

这样不仅更贴近真实工作流，也能让教程更清楚解释“上一轮做的能力，这一轮是怎样被继续复用的”。

### 3. 真实分析先做同步短链路

进入 `M10` 后，队列、异步状态、任务中心和历史列表当然都已经是可以想象的方向。

但这一轮刻意没有先做这些，而是只做：

- 输入
- 同步触发
- 结果阅读
- 错误反馈

这个判断非常关键。因为当前更重要的是先证明“这条 AI 主线真的能工作”，而不是过早把系统铺成一个复杂的半成品。

### 4. viewer 必须拥有一条真实可用的只读体验

如果 viewer 只能看到“你没有权限”，成本控制当然也成立，但教学价值会很弱。

所以 `M10` 的最后一步，不是继续强化拒绝，而是给 viewer 一条真正可走的链路：

- 读取缓存报告列表
- 查看缓存报告详情
- 理解自己为什么能体验、但不能触发真实分析

### 5. 这一轮刻意不做异步任务系统

`M10` 碰到的所有边界，其实都在提醒“后面迟早要做更复杂的 AI 基建”。

但这一轮没有顺势把 Redis、BullMQ、历史表和任务状态中心全部拉进来，而是继续守住当前教学阶段最重要的短链路。

## 三、`M10` 为什么要按这些 issue 来拆

这一轮的拆法，其实是在回答一个很典型的 AI 产品问题：

当后端已经有了一部分 AI 基础能力后，应该先把哪几层接起来，才能让它变成真正可演示、可验证、可继续扩展的后台主线？

`M10` 的答案是：

先立工作台入口，再立输入链路，再立管理员真实分析，最后立 viewer 只读缓存体验。

### issue-47：先立 AI 工作台入口

第一步不是做上传，也不是直接触发分析，而是先把 AI 能力从后台各处的零散入口中抽出来，放到独立页面里。

这一层真正固定下来的，是：

- AI 页面入口在哪里
- 运行时摘要如何展示
- 场景、Provider 和角色边界如何被读者第一眼理解

这一步让后续所有 AI 相关能力，都有了稳定生长点。

### issue-48：再把文件上传与文本提取接出来

有了工作台入口以后，下一步才是统一输入链路。

这一步不是为了“先做一个上传组件”，而是为了把已经存在的后端文件提取能力真正接进后台，并且让它形成明确主线：

- 上传文件
- 统一走 `NestJS`
- 返回提取结果
- 页面内预览输入

这一步让 AI 工作台第一次不再只是入口说明，而是开始消费真实业务能力。

### issue-49：再让管理员走通真实分析

当输入链路已经成立后，才轮到真正的分析触发。

这一步的重点不是“加一个分析按钮”，而是让上一轮的输入结果可以继续接力到这一轮：

- 手动输入可以分析
- 文件提取结果也可以直接分析
- 分析结果和失败反馈都能在页面里阅读

这一步完成后，`admin` 第一次拥有了一条真正闭合的 AI 短链路。

### issue-50：最后把 viewer 体验真正收住

如果到管理员真实分析为止就停下，`M10` 其实还是不完整的。因为 viewer 仍然停留在“不能做”的描述上。

所以最后一步不是扩更多 AI 能力，而是给 viewer 一条真正成立的只读体验：

- 缓存列表可读取
- 缓存详情可查看
- 页面顺序更贴近“先告诉你可以体验什么”

这一步让角色边界不再只是规则，而成为页面体验的一部分。

### issue-51：及时把这一轮收成可继续写的文档骨架

AI 相关里程碑比一般功能更容易失控，因为它天然会诱导人去继续做更复杂的事情。

所以 `M10` 结束后，必须及时把：

- 当前已经成立的短链路
- 当前刻意没有做的复杂系统
- 后续如何继续拆分

明确沉淀下来。这样下一阶段继续做时，才不会把这一轮重新写散。

## 四、这一轮最重要的设计取舍

### 1. 为什么先做同步最小闭环，不先做队列

这是 `M10` 最重要的判断之一。

如果一开始就进入 Redis、BullMQ、任务中心、历史记录，读者很快会陷入这样一种状态：

- 每一层都像是“合理的下一步”
- 但没有一条短链路真正被完整证明

所以 `M10` 刻意先收同步短链路。先让后台真正做到：

- 有输入
- 能分析
- 能看结果
- 能看错误

只要这条线站稳，后面的复杂系统就会更容易解释。

### 2. 为什么文件提取必须继续统一收在 `NestJS`

这一步不是技术洁癖，而是边界控制。

如果页面层顺手自己做提取，或者把输入处理拆到另一套前端后端逻辑里，很快就会破坏项目一直坚持的原则：

- `Next.js` 负责页面、交互和前端会话壳
- `NestJS` 负责业务 API、文件、AI 和权限

所以这一轮再次强化了一件事：

- 上传、提取、缓存读取、真实分析都继续走 `apps/server`

### 3. 为什么 admin 和 viewer 不拆成两套 AI 页面

从表面看，拆成两套页面也能实现功能。

但教程型仓库里，这样做会带来两个问题：

- 页面结构会更碎
- 角色边界会更难解释成“同一工作台的两种能力”

所以 `M10` 坚持保留一个 AI 工作台，只在页面内通过顺序、入口可用性和提示语把边界讲清楚。

### 4. 为什么 viewer 体验不能只停在“不能”

这是 `M10` 最有教学价值的地方之一。

如果 viewer 只会收到：

- 没权限
- 按钮禁用
- 提示说明

那成本控制虽然成立，但读者体验是不完整的。

而把缓存阅读落进页面后，表达就变成了：

- 你现在不能触发真实分析
- 但你可以体验现有分析结果

这不仅更友好，也更有利于开源读者理解系统边界。

### 5. 为什么这一轮刻意不做历史系统

当真实分析已经成立之后，最自然的下一个诱惑就是：

- 保存历史
- 打开旧记录
- 对比不同结果

这些方向都合理，但它们不适合在当前这一轮就一起落地。因为 `M10` 当前最重要的，是证明“AI 工作台从入口到体验闭环已经成立”，而不是开始把它做成一个更大的业务子系统。

## 五、关键文件应该怎么读

如果你想顺着代码和文档复盘 `M10`，建议优先看这几组材料。

### AI 工作台入口与壳

- `apps/admin/app/dashboard/ai/page.tsx`
- `apps/admin/components/admin-ai-workbench-shell.tsx`
- `apps/admin/lib/ai-workbench-api.ts`

这里解决的是“AI 为什么要先有一个独立工作台入口”。

### 文件输入链路

- `apps/admin/components/ai-file-extraction-panel.tsx`
- `apps/admin/lib/ai-file-api.ts`
- `apps/server/test/ai-file-extraction.e2e-spec.ts`

这里解决的是“为什么统一输入链路比直接写分析框更重要”。

### 管理员真实分析闭环

- `apps/admin/components/ai-analysis-panel.tsx`
- `apps/admin/lib/ai-workbench.types.ts`
- `apps/server/test/ai-report-role-access.e2e-spec.ts`

这里解决的是“最小真实分析闭环到底怎么成立”。

### viewer 缓存体验边界

- `apps/admin/components/ai-cached-reports-panel.tsx`
- `apps/admin/components/admin-ai-workbench-shell.spec.tsx`

这里解决的是“成本控制为什么需要一条真实可体验的只读链路”。

## 六、`M10` 的测试重点是什么

`M10` 的测试重点不是覆盖更多 AI 场景，而是确认这条最小后台闭环是否已经真正站稳。

### 1. 先锁工作台入口与运行时摘要

这里至少要证明：

- 后台首页能进入独立 AI 工作台
- 工作台能读取运行时摘要
- `admin / viewer` 都能在页面级看到自己的边界说明

### 2. 再锁输入链路

这一层要证明：

- 文件确实通过 `FormData` 发到 `NestJS`
- 提取成功后能看到预览
- 提取失败时不会静默失败

### 3. 再锁管理员真实分析

这一层要证明：

- 分析输入可以手动填写，也可以接收提取结果
- 管理员触发真实分析后可读取结果
- 服务端错误和权限失败都能被页面正确感知

### 4. 最后锁 viewer 只读缓存体验

这一层要证明：

- viewer 可以读取缓存结果
- viewer 不能上传文件
- viewer 不能触发真实分析
- 页面顺序先给体验入口，再说明权限边界

## 七、这一轮最容易踩的坑

### 1. 一上来就想做队列、历史和任务中心

这些方向都合理，但它们会很快让当前最值得讲清楚的短链路被淹没。

### 2. 把文件提取做成页面本地逻辑

这样虽然短期也能跑，但会破坏“唯一业务后端”的原则，也会让后续其他前端无法继续复用。

### 3. 只做管理员链路，不收 viewer 体验

这样会让角色边界停留在说明文案层，而不是形成真正的页面体验闭环。

### 4. 把 admin 和 viewer 拆成两套完全割裂的 AI 页面

这会让同一条工作台主线被切碎，也会削弱“同一系统下不同能力边界”的教学表达。

## 八、`M10` 完成后，项目到了什么状态

`M10` 结束后，这个项目第一次真正拥有了一条能对外说明的 AI 后台主线：

- 有独立工作台入口
- 有统一输入链路
- 有管理员真实分析闭环
- 有 viewer 只读缓存体验

也就是说，AI 在这个项目里不再只是“后端已经接了某个接口”，而是开始成为一个在后台可演示、可讲解、可继续演进的实际模块。

## 九、这篇文章对应的原始材料

如果你想继续往下看每个 issue 的实现细节，可以配合这些开发日志一起阅读：

- `docs/30-开发日志/M10-issue-47-admin-AI-工作台最小入口.md`
- `docs/30-开发日志/M10-issue-48-文件上传与文本提取预览.md`
- `docs/30-开发日志/M10-issue-49-管理员真实分析闭环.md`
- `docs/30-开发日志/M10-issue-50-viewer-缓存体验与权限收束.md`
- `docs/30-开发日志/M10-issue-51-教程大纲与里程碑收束.md`
- `docs/40-教程与博客/M10-AI-工作台从基础接口到后台闭环-教程大纲.md`

这些记录更适合看“每一步具体做了什么”，而本文更希望回答“为什么 `M10` 要先把 AI 工作台收成最小后台闭环，再继续进入更复杂的 AI 基建”。

## 小结

`M10` 做的不是一轮大规模 AI 平台建设，而是先把最关键的短链路收住：

- AI 工作台入口成立
- 文件输入链路成立
- 管理员真实分析闭环成立
- viewer 缓存体验边界成立

这些边界一旦成立，后面无论是继续做异步任务、分析历史，还是更成熟的 AI 工作流编排，都会更像是在已有主线上继续增强，而不是重新回头补一遍 AI 产品地基。
