陈亚南推进算法与闭环雏形
从 root 到 v0.1 的历史看,viewer、保存标注、训练、异步推理、motion / label、ContinualLearning、HPC、3D arch、teacher forcing 等核心能力都在这一阶段形成。
这不是一次单纯的 TurboTune 项目回顾,而是借一个真实软硬结合大型工程,提炼 AI 时代的工程方法论:如何从“超级个体靠经验救火”,沉淀为团队和 AI 都能复用的架构、流程、测试和决策体系。
从 root 提交、v0.1、Tutorial 产品闭环、tag、提交者分布和 docs 演进,还原事实,但目的不是讲流水账。
重点复盘哪些判断是对的,哪些判断需要修正:为什么先看 UI 是合理的,为什么最终必须转向架构清创。
把项目经验抽象为 AI 长期工程方法:设计文档、Skill、分层治理、Pipeline 测试、Review、MR 和最终决策权。
TurboTune 的演进不是一次普通功能迭代,而是从算法原型到 API V2、WebUI、TaskManager、训练推理、发版链路、测试体系和 AI 约束体系的连续重构。
v0.1 不是最原始起点,而是接手时已经经历过一部分 V1 UI 与功能收敛后的 baseline;后续 tag 是围绕真实交付持续推进的架构和功能演进。
从 root 到 v0.1 的历史看,viewer、保存标注、训练、异步推理、motion / label、ContinualLearning、HPC、3D arch、teacher forcing 等核心能力都在这一阶段形成。
在 v0.1 前后,project、dataset、viewer 图层、magic、deploy、训练进度、SSE 进度和 UI 调整逐步落地,把原型推向可操作的 V1 产品形态。
后续重点不只是继续补功能,而是围绕 API V2、TaskManager、状态分层、runtime、SSE、训练推理闭环、项目导入导出和测试体系做系统性收口。
v0.1 看到的不是“从零开始的原型”,而是已经经过原型验证、部分功能开发和一轮 V1 UI 收敛后的结果。后续重构面对的是一个已有业务闭环雏形、但架构和协作治理尚未收口的系统。
baseline v0.1:已包含原型验证、部分功能开发和一轮 V1 UI 收敛。
alpha1 version:进入可运行产品形态,但架构约束仍不足。
add extension system:API V2、TaskManager、Pydantic、SSE、UI 重构开始密集演进。
完全切换 API V2 并删除 API V1,减少 AI 参考旧实现的风险。
优化架构、UI 状态响应、训练曲线、发版和 Model Zoo,进入 Beta 级治理。
Labeled、对比、停止能力、GPU slot、HPC、视频导出和批量发版补齐。
docs/api_v2_design.md 成为 API V2、状态模型、恢复语义、owner 边界和偏差收口的唯一正式设计文档。
本地 Git 记录中,我相关 author 记录合计 100 次、committer 记录合计 148 次,覆盖大量系统性重构。
在进入 AI 开发复盘之前,需要先明确 TurboTune 到底是什么。它不是一个普通 WebUI,也不是一个单点训练脚本。 从 Tutorial 的产品定义看,TurboTune 是一个专业的 AI 交互标注训练平台:它把原始帧、交互式标注、快速反馈训练、Validation、部署和发版记录串成一个连续闭环。
| 步骤 | 用户看到的功能 | 背后的工程含义 |
|---|---|---|
| 1. 开场动画 | 展示 AI 交互式标注训练的产品概念 | 先让用户理解 TurboTune 不是离线训练工具,而是交互式反馈平台。 |
| 2. Welcome 与创建项目 | 使用真实 CreateProjectDialog 创建项目 |
Project 是所有数据、模型、训练、发版和追溯信息的业务容器。 |
| 3. Hammer 概览 | 查看模型、数据集和右侧 ISP 参数面板 | 把模型参数、数据集选择、预览和推理准备放在同一工作流里。 |
| 4. 添加数据集 | 打开真实 AddDatasetDialog,解析 meta 并添加数据集 |
Dataset 不只是路径,而是训练、推理、标注和 runtime summary 的业务主键。 |
| 5. 预览与推理 | 自动预览、触发推理、等待 runtime 完成、开放结果层 | Baseline 结果进入可消费状态,后续标注和训练才有依据。 |
| 6. Viewer / Task / 标注 | 切帧、查看 Motion / Weight、画笔标注、删除、清空、保存 | 标注是 durable project information,不是临时 cache,是后续 labeled 和训练反馈的事实源。 |
| 7. Magic 训练与训练曲线 | 触发训练、展示 SSE 进度、打开非空训练曲线 | 训练从离线脚本变成工作区内可观察、可验证、可继续迭代的任务。 |
| 8. Validation 与结果对比 | 展示 trained 结果与 baseline 对比 | 验证训练是否真的改善结果,而不是只看训练是否跑完。 |
| 9. Deploy 与发版记录 | 打开发版弹窗、提交发版、查看发版记录 drawer | 把训练成果变成可追溯、可发布、可回看来源的模型产物。 |
负责项目中的模型、数据集、预览、推理和基础结果查看,是从数据进入模型反馈链路的入口。
负责帧级查看、图层切换、Motion / Weight 对比、画笔标注、保存标注和任务文件列表,是人机交互闭环的核心。
负责训练、训练曲线、Validation 和 Baseline / Trained 对比,是把标注反馈转化为模型改进的入口。
负责发版、记录、模型追溯和后续复用,把训练结果变成可交付、可回溯的模型资产。
Tutorial 的意义不是“再做一个演示页面”,而是用可视化方式向别人解释 TurboTune 是什么、怎么用,以及完整产品链路为什么成立。 它要展示的是一条真实流程:创建项目、添加数据集、预览、推理、标注、训练、Validation、Deploy 和发版记录。
但 Tutorial 同时施加了几个非常强的工程约束:不能为了演示侵入正式 UI,不能把 tutorial 专属语义塞进正式后端,也不能维护一套与真实产品不一致的假界面。 正确做法是用独立 demo server 提供 mock backend,在独立运行态里模拟完整流程;前端继续驱动真实业务组件、真实 store、真实 client 和真实 `/api/v2` 契约。
| Tutorial 约束 | 具体要求 | 对架构的反向证明 |
|---|---|---|
| 不侵入 UI | Welcome、CreateProjectDialog、AddDatasetDialog、Hammer、Viewer、Magic、Deploy 等都使用真实组件。 | 如果真实组件只能依赖页面私有状态,Tutorial 就无法非侵入地驱动完整流程。 |
| 不侵入正式后端 | 正式后端只负责 launcher;Tutorial 状态、节拍、仿真数据和重放逻辑收敛在 tutorial/*。 |
如果后端业务 owner 不清晰,Tutorial 很容易把演示逻辑污染到正式业务链路。 |
| mock backend 同形契约 | 独立 demo server 提供同形 /api/v2 能力,并满足真实前端的 SSE、runtime 和 artifact 读取预期。 |
只有 API 稳定,mock backend 才能替换真实 backend;否则每个演示步骤都要特判。 |
| 完整真实流程 | 演示链路必须覆盖项目、数据集、推理、标注、训练、Validation、部署和发版记录。 | Tutorial 不是 UI 动画,而是对产品闭环、API 契约和状态模型的一次端到端验收。 |
这也解释了为什么 Tutorial 反过来证明了 API V2 的价值。只要 API、状态分层、数据模型和任务系统足够稳定, Tutorial 就可以用 mock backend 完整展现真实产品流程,而不需要改正式 UI 和正式后端;反过来,如果 API 不稳定,Tutorial 会被迫复刻第二套状态,最终变成另一个屎山入口。
从代码可以看到,TurboTune 的 UI 变化不是单纯换皮,而是在不断回答一个产品问题:
我们到底是在做一个临时研发工具,还是一个能承载完整 AI 交互式训练闭环的产品工作台?
从最终 UI 回看 v0.1,再看当前 UI,变化最明显的不是组件数量,而是产品链路、API 边界、后端职责和状态模型一起被重新组织了。
v0.1 的前端结构集中在 MainApp.vue、project.vue、hammer.vue、magic.vue、model-zoo.vue、viewer.vue。
它已经具备 Project、Hammer、Magic、Model Zoo、Viewer 等产品入口,也有侧边栏、可拖拽宽度、SSE 连接、项目状态显示等能力。
这说明当时不是没有产品意识,而是产品形态还主要围绕“把功能放进页面”组织。
folder_name 这类实现细节,前端通过 globalState.js、dataset.js、project.js 等 JS store 串联功能,页面与状态边界不够清晰。
当前 UI 已经演进为 MainLayout.vue 统一承载工作区,并拆分出 HeaderBar、ActivityBar、DynamicSidebar、ViewerContent、RightPanel、StatusBar 等稳定布局模块。
这不是简单组件拆分,而是产品逻辑被明确分区:
| 区域 | 当前 UI 承载的产品语义 | 对应的工程收口 |
|---|---|---|
| HeaderBar | 项目上下文、数据集上下文、导入导出、视频导出、连接状态 | 把 project 和 dataset 从页面局部选择提升为全局工作区上下文。 |
| ActivityBar | Hammer、Magic、Model Zoo、Extensions、Task、Label、ISP、Layer 等工作模式入口 | 把功能入口从固定页面切换,升级为可组合、可停靠、可扩展的产品导航。 |
| DynamicSidebar | 根据当前 mode 动态加载工作流侧栏 | 把 Hammer / Magic / Model Zoo 等功能从大组件拆成受控 panel,不再互相持有状态。 |
| ViewerContent | 主画布、结果查看、图层展示、结果对比 | 让 Viewer 成为统一结果消费区,而不是每个页面各自解释推理结果。 |
| RightPanel | ISP 参数、Label 工具、Layer 控制 | 把局部工具能力提升为围绕当前 dataset / frame 的上下文工具栏。 |
| StatusBar | 运行状态、系统状态、任务反馈 | 把“任务有没有在跑”从页面文案变成统一状态出口。 |
早期 UI 是 Project / Hammer / Magic / Viewer 等页面能力的组合;当前 UI 是围绕项目和数据集上下文组织的工作台。 用户不再是在多个页面之间找功能,而是在同一个产品工作区里完成添加数据、推理、标注、训练、验证和发版。
早期接口更接近页面需要什么就补什么;当前公开契约统一到 /api/v2,并围绕 projects、datasets、inference、labels、train、deploy、runtime 组织。
UI 能产品化,是因为 API 不再暴露页面临时语义,而是提供稳定资源边界。
后端不再只是“接请求后跑脚本”,而是拆成 router、schema、task preparation、TaskManager、runner、completion、runtime snapshot、SSE 等边界。 这让长任务、GPU、artifact、训练状态和结果回写能被统一治理。
早期状态容易混在 global store、页面组件、SSE 和后端文件里;当前状态被拆成 durable facts、runtime read model、task runtime、SSE overlay、probe 和 UI local state。 UI 之所以能稳定恢复,是因为每一类状态都有 owner。
最终 UI 展示出的产品链路,是 TurboTune 研发过程的结果:早期验证算法闭环,V1 把功能放到用户能点的地方,后续重构再把 UI、API、后端和状态统一到一个长期可交付的产品结构里。 这也是为什么这次复盘不能只讲“AI 写代码快不快”,而要讲 AI 在产品化工程里如何被约束。
这次分享的重点不是给个人贴标签,而是把代码历史背后的工程演进讲清楚:谁在什么阶段解决了什么问题,为什么后面会从功能迭代转向架构治理。 从提交历史看,TurboTune 不是一开始就进入 V2 重构,而是先经历了算法闭环验证、V1 UI 与功能收敛、AI 快速堆功能、再到系统性重构。
v0.1 前 115 次 author 提交
形成 viewer、保存标注、训练、异步推理、motion / label、ContinualLearning、HPC、3D arch、teacher forcing 和算法链路优化等能力,证明项目的核心算法闭环可行。
v0.1 前 63 次相关提交
补齐 project、dataset、viewer 图层、magic、deploy、训练进度、SSE 进度和 UI 调整,让算法原型开始具备用户可操作的产品雏形。
v0.1 前少量工程化提交
主要涉及 CI、pytest 环境、依赖整理和 data_loader 入口。此时还没有主导重构,角色更接近后续工程治理的准备者。
v0.1 不是“混乱原始代码”的起点,而是一个已经证明业务方向、也已经完成一部分 V1 UI 和功能收敛的接手基线。
后面的问题不是“没有做出东西”,而是“做出来的东西开始进入长期迭代,需要新的工程秩序”。
v0.1..HEAD 的差异达到 807 个文件、187319 行新增、30453 行删除。
这种规模说明后续不是修修补补,而是围绕 API、schema、task、runtime、SSE、前端 store、测试、文档和发版链路的系统性重构。
我 30 次,陈栓 24 次,陈亚南 4 次;API V2、TaskManager、Pydantic、SSE、UI 重构和 Extension 系统起步。
我 25 次,陈栓 14 次;projects / datasets 迁移到 V2,删除 API v1,runtime state、task architecture 和 UI 配置收口。
我 14 次,陈栓 11 次;prepared runners、main-process state ownership、ProjectBundle、path resolution、system settings 和训练曲线落地。
我 15 次,陈栓 15 次,刘迎召 3 次;GPU slot、停止能力、HPC、video export、thumbnail task UI、client_v2 收口为 client。
陈栓 47 次,陈亚南 18 次,刘迎召 7 次,我 6 次;模型溯源、simpleai 主线统一、项目重命名、S3 导出、训练状态和测试补齐继续推进。
在架构完全稳定之前,我一开始预期承担的是工程化项目角色:把项目从原型和功能堆叠状态,推进到可维护、可测试、可协作的工程系统。 但随着 API V2、TaskManager、runtime、SSE、schema、docs 和测试体系逐步收口,角色也开始发生变化。
中后期,我逐渐从“主要亲自改核心架构的人”,转向“架构 reviewer 和产品经理”:一方面审核后续功能是否符合 API V2 设计、状态分层和 owner 边界;另一方面从产品经理视角判断哪些能力应该进入产品闭环,哪些只是局部研发便利。
这个变化从代码量和提交角色上也能看出来。v0.5-beta.2 -> HEAD 期间,我作为 author 的直接提交只有 6 次,但作为 committer 的提交有 28 次;
多条由陈栓、陈亚南、刘迎召完成的功能或修复,最终由我合入。Git 记录不能完整代表所有 review 讨论,但 author / committer 的差异已经能说明角色正在从“主要实现者”转向“reviewer、合入者和架构把关者”。
这个阶段开始验证“架构是否真的稳定到可以让非核心开发者介入”。刘迎召并不是作为“工程组代表”出现,而是我负责的工程组中第一批开始介入 TurboTune 开发的同学; 他参与 Model Zoo、画框模式、发版登录校验、数据集 meta 自动解析、缓存读取窗口滑动、前端卡死修复等功能,意义不只是补功能,而是验证 API V2、状态分层、docs 和 Skill 是否已经稳定到不依赖核心开发者本人也能交付。
这个判断成立后,后续才适合继续引入其他工程组同学,以及 AI 训练组的开发同学。此时项目治理的目标,不再只是“我能把架构改好”,而是“架构、文档、测试和 Skill 能让更多人和 AI 都在同一套边界里安全开发”。
v0.5-beta.2 -> HEAD 期间,我 6 次,陈栓 47 次,陈亚南 18 次,刘迎召 7 次。功能实现开始由更多开发者在既有架构和 Skill 约束下完成。
同一区间内,我作为 committer 有 28 次,陈栓 49 次,陈亚南 3 次。直接写代码减少,但合入、review 和架构边界判断的角色增强。
大量 Resolve ...、功能修复、性能优化、测试补齐和文档约束提交出现,重点变成“功能是否落在正确架构边界内”。
回答“业务和算法方向是否成立”。没有这个阶段,就没有后续工程化价值。
回答“用户是否能操作完整流程”。它把算法能力包装成可用产品,但也放大了架构约束不足的问题。
回答“这个系统能否长期迭代”。它不只是写更多代码,而是定义边界、契约、测试和 AI 行为规则。
回答“更多人如何持续交付正确产品”。它要求架构 reviewer、工程组协作和产品经理视角同时存在。
TurboTune 的文档演进,是这次 AI 开发实践里最重要的工程信号之一。 早期文档更多是给人看的说明,后期文档逐渐变成给 AI 和团队共同执行的架构约束。
在 v0.1,仓库里主要是 README.md、api/schemas/Readme.md、tests/README.md 和旧 doc/ 下的 project 说明。
API 入口仍是 api/server/endpoints/*,前端主要是 JS store,例如 src/stores/dataset.js、src/stores/project.js、src/lib/globalState.js。
这说明当时还没有一个统一的架构设计源来告诉 AI:哪些状态属于事实,哪些只是 UI 页面态,哪些路径不能继续扩张。
| 文档 | 作用 | 对 AI 开发的意义 |
|---|---|---|
docs/api_v2_design.md |
唯一正式主设计文档,定义 API 契约、状态模型、owner 边界、恢复语义和偏差清单。 | AI 修改 V2 链路前必须先读它。它告诉 AI 什么能做、什么不能做、冲突时以谁为准。 |
docs/system_architecture_overview.md |
给新人和 AI 建立系统分层地图:UI、store、client、router、schema、task、runner、runtime、SSE。 | 避免 AI 一上来逐行看代码,而是先判断问题属于哪一层。 |
docs/testing.md |
定义 unit、integration、e2e、stress 四层测试,以及运行方式和覆盖清单。 | 把 AI 生成测试的入口从“随便补几个断言”拉回“按测试层级验证契约”。 |
docs/newcomer-guide.md |
把人和 AI 的协作方式写成流程:先判断层级、再确认边界、再实现、最后验证。 | 它是团队如何指挥 AI 的使用手册。 |
.codex/skills/turbotune-v2-design-guardrails/SKILL.md |
把 API V2 设计约束压缩成可复用 Skill。 | 让 AI 每次进入 V2 状态链路时自动遵守相同规则,而不是靠临时 prompt。 |
从提交历史看,docs/api_v2_design.md 不是一次写完的文档,而是随着架构问题被发现、修复、收口而持续演进:
4 月初围绕 API V2、Pydantic、TaskManager、SSE 起步;4 月 13 日删除 API v1;4 月中下旬围绕 runtime、task architecture、main-process ownership、ProjectBundle、path resolution 等问题持续更新;
5 月到 6 月,功能开发中的 project_id/name、deploy meta、train status、simpleai、模型溯源等问题继续反哺设计文档。
AI 最怕的不是复杂,而是多个互相冲突的事实源。一个需求如果同时参考旧 doc/、旧 API endpoints、旧前端 store、临时 task 文档和口头共识,
AI 会倾向于把所有东西都兼容下来,最终制造更多第二事实源。
因此最终必须明确:docs/api_v2_design.md 是核心唯一主设计文档。WebUI 设计文档可以指导布局和交互,TaskManager 文档可以指导通用调度,
testing 文档可以指导验证,但涉及 API V2 契约、状态语义、恢复、前后端边界和当前偏差时,以 api_v2_design.md 为准。
这一阶段主要由陈亚南推进算法和闭环原型,陈栓开始补 project、dataset、viewer、magic、deploy 等产品功能。
到 v0.1 时,项目已经不是空白原型,而是有一部分 V1 UI 和功能收敛结果的接手基线。
这个阶段主要目标不是工程优雅,而是验证模型能不能跑、训练有没有价值、标注和推理能不能形成正向反馈。
在原型开发和功能开发已经形成 V1 雏形后,两位优秀开发者开始大量使用 AI 快速迭代,短期功能增长非常快。但 AI 被当成掌控者,而不是写作者。 没有统一架构、没有事实源、没有协作纪律、没有强测试,AI 产出开始互相冲突,系统从快速增长变成快速失控。
核心任务从继续写功能变成重建工程秩序。通过唯一设计文档、API V2 契约、状态分层、Pydantic schema、TaskManager 边界、分层测试和 Skill 约束, 项目重新回到人掌控架构、AI 执行实现的模式。
| 阶段 | 当时的主要目标 | 暴露的问题 | 方法论沉淀 |
|---|---|---|---|
| 原型阶段 | 验证算法方向和业务闭环是否成立。 | 代码粗糙、边界不清、工程规范不足,但这是探索期的合理代价。 | 早期不要过度工程化。先证明核心闭环,再决定是否值得投入长期架构。 |
| AI 快速迭代阶段 | 用 AI 快速补功能,把原型推向可用产品。 | AI 产出互相冲突,页面接口、状态、分支、测试和文档都开始失控。 | AI 只能放大已有结构。没有架构约束时,它放大的是混乱,不是生产力。 |
| 系统性重构阶段 | 重建工程秩序,让项目能长期迭代。 | 需要付出清创成本,短期功能速度会下降,决策压力集中到架构 owner 身上。 | 长期工程必须把人的判断固化为设计文档、Skill、测试和 review 机制,才能从个人能力变成组织能力。 |
这次复盘不能只靠主观感受,必须回到 git log。提交历史显示,TurboTune 的后续演进不是“继续堆功能”,而是先经历了一段高密度架构清创,再在稳定架构上重新恢复产品功能迭代。 前文已经建立 tag 节奏,这里只看提交主题、改动范围和 author / committer 变化如何证明架构治理发生过。
Project、Dataset、Inference、Annotation、Train、Validation、Deploy 被串成连续工作流。
从页面接口转向资源契约,API V2、OpenAPI、Pydantic、TS 类型成为共同事实源。
TaskManager、prepared runner、GPU slot、停止能力和 runtime read model 形成清晰边界。
durable facts、runtime、task runtime、SSE overlay、probe、UI local state 被分层。
从页面堆叠演进为 MainLayout、ActivityBar、DynamicSidebar、ViewerContent、RightPanel。
docs、Skill、MR、review、pipeline test 共同约束 AI,把个人能力转为系统能力。
代表提交包括 refactor server api v2、feat(schema): add client_v2.ts、docs(api/v2): add fastapi docs。这一阶段把后端接口、schema、OpenAPI 和前端 client 放到同一契约体系中,先给 AI 建立可执行的事实入口。
代表提交包括 Refactor migrate projects dataset api to v2、Refactor task architecture and runtime UI configuration、remove api server v1、Unify runtime state handling。项目、数据集、task、runtime 和旧 API 被集中清理,这是删除旧路的清创阶段。
代表提交包括 Refactor project path resolution、Refactor/unify system settings、unify async task state ownership、unify task execution around prepared runners、Introduce ProjectBundle。路径、配置、异步任务状态、prepared runner、导入导出开始形成明确 owner。
代表提交包括 run_hpc、export video、TaskManager GPU slot allocation、rename client_v2.ts to client.ts。HPC、视频导出、GPU slot 和 client 命名收口后,架构开始反过来提高 AI 做复杂功能的成功率。
代表提交包括 project->name和id区分开、后台系统status统一RuntimeStatus、simpleai->和主线统一版本、模型支持溯源、add-intertest+e2etest。主键、runtime、训练状态、模型溯源和测试体系继续收口,AI 开发进入“在设计约束中扩展”的阶段。
Git log 里能看到多次 80+、100+ 文件级提交。这些不是普通功能迭代,而是对应跨层旧事实源的一次性手术式收口—— 每一次都同时触及 schema、API router、store、SSE、runtime、task system 和测试,把散落在各处的临时实现统一回正式契约。
把 runtime 状态和 deploy 语义从多个临时路径收回统一 V2 契约。
发现 runtime 事实源问题后,跨前后端重建状态 owner 和恢复路径。
把长任务从“各处临时执行”收口为 prepared runner。
统一训练依赖、模型权重和发版路径,减少跨仓库事实源分裂。
第二阶段的问题不能简单归因于开发者能力。真正的问题是 AI 使用方式和工程治理缺位。 AI 可以安全地翻译清晰想法,但当它被用来填补人的架构盲区时,会快速制造全局混乱。
AI 一次性修改多个层级,人逐渐不再掌握系统真实边界,只能追着 AI 的产物补 bug。
野分支、长分支和重复实现让每个人的 AI 都生成一套局部合理但全局冲突的系统假设。
静态事实、runtime、SSE、cache、UI local state 混在一起,每修一个问题都可能新增一个影子状态。
接口按页面需求临时组织,而不是从资源、数据边界和领域模型出发,导致 UI 越写越依赖偶然实现。
没有完整 pipeline 测试时,AI 倾向于让当前问题看起来修好,而不是保证业务闭环长期正确。
文档如果只是事后说明,AI 无法从中获得稳定约束,最终仍会自由发挥。
每个开发者都会有自己的分支,这本身不是问题。真正的问题是:当团队不使用 git 小步快跑的理念时,分支会变成个人思路的无限延伸。 一个人本来在做 A 功能,过程中发现 B 有问题,于是顺手修 B;修 B 时又发现 C 不对,于是继续改 C。最后一个分支里混着 A、B、C 三类问题,提交历史无法解释,代码边界无法判断,也没有人能有效 review。
AI 会放大这个问题。因为 AI 很擅长在当前上下文里继续写下去,它会把“顺手修一下”变成跨 UI、store、API、后端、测试的连锁修改。 每一步看起来都有道理,但整体已经偏离原始目标。人最后面对的不是一个可审查的功能分支,而是一团夹杂需求、修复、重构、兼容和临时判断的混合差异。
| 失控模式 | 表现 | 后果 | 治理原则 |
|---|---|---|---|
| A 功能串到 B/C 问题 | 一个分支里同时修改多个无明确依赖的目标。 | reviewer 无法判断这次 MR 到底想解决什么。 | 一分支一目标;发现新问题先记录,必要时另开分支或另开 MR。 |
| 长分支长期游离 | 分支不及时合入主线,持续积累差异。 | 主线、个人分支和 AI 上下文形成多个事实源。 | 小步提交、小步合入、持续 rebase 或同步主线。 |
| AI 连续扩张上下文 | 从一个 bug 扩展到页面、store、API、后端和测试的全链路改动。 | 局部修复变成不可控重构,风险无法定位。 | 先定义边界,再让 AI 写代码;超出边界必须停下来重新设计。 |
| 没有 review 入口 | 提交历史没有清晰意图,测试也不能覆盖完整业务意义。 | review 只能变成逐行猜测,最终没人真正掌控质量。 | MR 必须带设计意图、影响范围、测试证据和 OpenAPI / schema 变化说明。 |
这一段是整个分享中最重要的决策复盘。它不是“我一开始判断错了”的故事,而是一个长期工程里很典型的过程: 基于业务逻辑做出合理的局部优化判断,随后被现实揭示出更深层的架构问题,最终必须从渐进优化转向清创式重构。
我进入项目时,首先看到的是前端 UI 的混乱。最初的想法很简单:把 UI 重构好就够了,不打算主导一个完整的系统性重构。 这个判断并非轻率,而是基于对项目核心业务逻辑的理解。
TurboTune 的核心价值,是将传统离线训练转变为可持续正向反馈的训练体系。其中最关键的一环,就是通过画布和标注体系,实现“训练 -> 标注 -> 再训练 -> 再标注”的反馈闭环。 因此 UI 不是表层皮肤,而是这个闭环的人机交互核心。
其他功能已经迭代了一段时间,看起来相对稳定、可行。
UI 是当时最明显的短板,也是用户完成反馈闭环的关键入口。
只要补齐 UI,训练反馈闭环就有机会跑通,工程就具备交付条件。
实际推进很快超出了我的预料。问题不在于 UI 写得不好,而在于底层架构混乱,让 AI 根本无法写出能支撑核心闭环的 UI。 API 从页面出发组织,而不是从数据边界和资源契约出发;数据结构不分离,状态 owner 不清晰,前端 store、后端 runtime、SSE 和 cache 互相制造第二事实源。
大模型看不懂这种混乱。基于混乱 API 生成的 UI,只会把页面问题、状态问题和接口问题继续叠加。UI 的混乱只是冰山露出水面的部分,水下是已经歪到无法支撑长期迭代的地基。
这就是我从“有限介入”转向“全面重构”的临界点。继续做 UI 优化,看起来是最省力的路,但它无法解决结构性问题,只会让 AI 在错误地基上继续生成更多局部合理、全局冲突的代码。
因此,我被迫从一个本打算“有限介入”的修复者,变成必须主导系统性重构的人。这不是轻率地推倒重来,而是在渐进路径被证明不可行之后,被迫做出的理性选择。
当底层架构无法支撑上层业务闭环时,即使上层承载着最核心的用户交互,继续从表现层渐进优化也是徒劳的。 真正负责任的做法,是先把数据模型、API 契约、状态 owner 和任务系统边界重新立住,然后再让 AI 回到高效实现的位置。
先修 UI → 发现 API 不对 → 改 API → 发现数据模型混乱 → 改模型 → 发现测试全挂 → 修补测试 → 发现状态不一致...
每层修复都会破坏上层已做的工作,AI 在错误地基上越改越乱。
先定数据模型 → 定 API 契约 → 定状态 owner → 定 TaskManager 边界 → 再让 AI 实现 UI 和业务逻辑。
地基立住后,AI 在上层能高效、安全地交付,不再互相冲突。
AI 可以给方案,团队可以讨论,但必须有人拥有最终决策权。长期工程不能靠谁的 AI 生成得快来决定方向。 人必须决定哪个文档是唯一设计源、哪个 API 是正式契约、哪个状态是 canonical source、哪些兼容逻辑要删除。
docs/api_v2_design.md 最终成为 TurboTune API V2 的唯一正式设计文档。
它统一定义资源边界、公开契约、主键生命周期、状态分层、ServiceContext、TaskManager、Reporter、缓存、恢复与 reconcile 的 owner。
AI 不怕文档长,怕文档不明确。文档必须明确回答:什么是事实源,谁是 owner,哪些路径禁止走,当前偏差在哪里,后续怎么收口。 这样的文档不是“给人看的说明”,而是“给 AI 执行的约束”。
项目进一步把规则固化为 turbotune-v2-design-guardrails。它让 AI 每次进入 V2 链路时都先遵守同一套边界:
不把 trace_id 当业务主键,不让 SSE 成为 canonical state,不把 runtime 写回 projectStore,不手改生成的 TS schema,不把业务语义塞进 TaskManager。
| 层 | Owner | 作用 | 是否 durable |
|---|---|---|---|
| Static durable facts | Project / Dataset / Annotation / Deploy records | 业务静态事实 | 是 |
| Runtime read model | ServiceContext + canonical builders | inference / train / deploy 查询事实 | 否 |
| Task runtime | TaskManager / executor / runtime registry | 运行中 task 的内部状态 | 否 |
| SSE live overlay | main-process broker | 页面实时覆盖层 | 否 |
| Controlled probe | check_only / frame-level probe | 补 frame 级局部信息 | 否 |
| UI local state | stores / components | displayMode、panel、草稿、缩放等 | 否 |
后端 Pydantic schema 是源定义,前端 TypeScript 类型从这里生成,不手写维护。
define.py 管领域类型,api.py 管 request / response,runtime.py 管 runtime read model。
这让人、AI、前端、后端和 OpenAPI 都围绕同一份契约协作。
TaskManager 的正式目标是 generic scheduler / executor / store。它负责排队、调度、执行、取消和 GPU slot 分配,不承载项目、数据集、训练、推理这些业务语义。 业务语义放在 API V2 的 preparation、runner 和 completion 边界中。
这次分享的目标不只是复盘 TurboTune,而是回答一个更通用的问题:在 AI 时代,如何用 AI 构建一个长期可持续迭代的大型复杂工程。 TurboTune 的结论是,AI 开发不是“把需求丢给 AI”,而是建立一套让 AI 只能在正确边界内高效工作的工程系统。
| AI 使用方式 | 典型输入 | 结果 | 适用条件 |
|---|---|---|---|
| 翻译想法 | 清晰的数据模型、API 契约、状态 owner、验收测试和影响范围。 | AI 能快速生成实现、补测试、改 UI、整理边界 case。 | 人已经想清楚系统结构,AI 负责把结构落实成代码。 |
| 填补盲区 | 只有一句需求,没有事实源、没有 owner、没有测试、没有边界。 | AI 会根据局部上下文补出看似合理但全局冲突的实现。 | 只适合探索方案,不适合直接进入长期主线。 |
| 层级 | 治理方式 | AI 可以做什么 | 人必须守住什么 |
|---|---|---|---|
| 底层:数据模型、API、runtime、TaskManager | 严控 | 在设计文档和测试约束下做局部实现。 | 事实源、owner、主键语义、恢复语义和兼容策略。 |
| 中层:store、client、composable、业务 orchestration | 强约束 | 补齐流程、错误处理、状态同步和接口适配。 | 不能新增第二事实源,不能绕过正式 client,不能把 runtime 写回 durable facts。 |
| 上层:UI 展示、交互细节、教程引导 | 相对自由 | 快速生成布局、交互、提示、空状态、视觉优化。 | 必须复用真实契约和真实组件,不能为了演示污染正式业务语义。 |
明确产品到底要跑通什么。TurboTune 的闭环是数据集、推理、标注、训练、Validation、Deploy。
确定哪些是 durable facts,哪些是 runtime read model,哪些只是 SSE overlay 或 UI local state。
文档必须能直接指导 AI:走哪条路、不要走哪条路、冲突时以谁为准。
每个分支只验证一个工程假设。发现新问题先拆分,不把 A/B/C 混在一个长分支里。
AI 可以扩展覆盖量,但核心 pipeline 必须由人定义,确保测试代表真实业务价值。
每次踩坑都要沉淀到 docs 或 Skill,让下一次 AI 调用自动继承约束。
前期可以依赖核心开发者强行把系统拉回正轨,但长期不能靠某个人永远盯住所有代码。 真正的工程化,是让新加入的人和 AI 都能通过同一套文档、契约、测试、MR 和 review 机制做出正确修改。 刘迎召开始介入功能开发的意义就在这里:当非核心开发者也能在既有架构和 Skill 约束下交付,说明架构治理开始具备可复制性。
AI 时代,传统逐行 review 会失效。一个 MR 可能修改几十个文件、几千行代码,如果人仍然试图逐行校对,就会变成“AI 的校对员”,而不是系统质量的负责人。 因此 review 的第一目标必须从“看代码写得怎么样”,转为“判断 AI 实现的是不是我们想要的系统意图”。
AI 让代码量爆炸,局部实现看起来都能自圆其说,但系统层面的意图可能已经偏移。
如果没有设计文档、契约和测试作为基准,reviewer 只能在大量 diff 里猜作者和 AI 的真实意图。
先审查设计文档、设计方案、OpenAPI、schema、runtime read model、SSE 语义、测试结果和完整 pipeline。
只有确认意图正确后,才进入局部代码质量、性能、异常处理和重复逻辑审查。
先确认这次修改有没有清晰意图,是否符合 docs/api_v2_design.md 的 owner、状态和契约边界。
看公开契约是否变化、是否破坏前后端一致性、是否引入隐式字段或第二套类型。
看完整业务闭环是否仍然成立,而不是只看某个接口或按钮返回成功。
看这次分支是否一目标一变更,是否说明影响范围、验证结果和无法覆盖的风险。
在前四项成立后,再看局部实现是否简单、可维护、可回滚、可定位。
如果发现设计文档与代码偏差,要么修代码,要么更新设计文档,不能留下隐性口头共识。
| Review 问题 | 判断标准 |
|---|---|
| 是否新增第二事实源? | 任何 runtime、SSE、UI local state 都不能替代 canonical query 和 durable facts。 |
| 是否绕过正式 client? | 前端正式入口统一为 api/client.ts,不能在组件里临时拼 transport。 |
| 是否混淆主键? | project_id、dataset_id、frame_id、deploy_id、trace_id 各司其职。 |
| 是否违反 TaskManager 边界? | generic task system 不承载业务语义。 |
| 是否有业务意义测试? | 不只看单元测试,还要看完整 pipeline 是否代表真实业务闭环。 |
AI 时代,测试不是收尾动作,而是战略核心。AI 可以写大量代码,也可以写大量测试,但人必须定义哪些测试代表业务意义。
AI 能快速生成大量实现,人工很难逐行确认所有行为。
AI 容易写出证明当前实现正确的测试,而不是证明业务闭环正确的测试。
架构清创会触碰 API、状态、任务和 UI 多层边界,缺少 pipeline 测试就无法安全推进。
如果测试只围绕局部实现,很快会变成维护负担,而不是质量资产。
文档、后端 schema、前端类型和真实行为一旦分离,AI 会从错误事实源继续生成代码。
没有测试作为证据时,reviewer 只能靠经验猜测系统是否仍然可用。
| 层级 | 测试策略 | 人和 AI 的分工 |
|---|---|---|
| 底层 | 完整 Pipeline 测试,覆盖项目、数据集、推理、标注、训练、Validation、Deploy、恢复。 | 人手写核心场景,定义“功能要跑的意义”。 |
| 中层 | 契约测试和接口测试,基于 OpenAPI、Pydantic schema、runtime read model。 | 人定义契约边界,AI 辅助扩展 fixture、异常 case 和断言。 |
| 上层 | 冒烟测试、UI 交互测试、Tutorial 演示链路。 | AI 辅助补覆盖,人判断是否代表真实用户流程。 |
| 稳定性 | stress、crash、race condition、重复导入、重启恢复和长任务中断。 | 人定义风险模型,AI 扩展组合场景。 |
TurboTune 的核心测试不是某个按钮返回 200,而是完整业务闭环: 创建项目,添加 dataset,baseline 推理,保存 annotation,labeled 结果失效并重新生成,启动训练,发布 epoch,trained validation 可查询,部署产物可追溯,服务重启后 runtime 能恢复。
后端使用 FastAPI 和 Pydantic V2 后,OpenAPI 3.0 不只是文档,而是正式契约。它必须和代码保持强一致: 后端 schema 是源定义,前端 TS 类型从 schema 生成,接口测试基于同一份契约展开,review 也以 OpenAPI 变化作为锚点。
| 维度 | 第二阶段 | 第三阶段治理 | 评估 |
|---|---|---|---|
| 🎯 决策机制 | 群龙无首 | 明确最终决策权 | 有效 |
| 🤝 协作理念 | 野分支、分叉开发 | 一分支一目标 + 小步合入 | 有效 |
| 📅 阶段节奏 | 无尽叠加 | Alpha / Beta + 小版本 tag | 持续控制中 |
| 🏗️ 架构约束 | 无统一设计源 | 核心设计文档 + Skill | 有效 |
| 📐 治理哲学 | 无分层 | 底层严控、中层约束、上层自由 | 有效 |
| 🗄️ 数据模型 | 隐式依赖 | Pydantic V2 驱动统一 | 有效 |
| 🔗 API 契约 | 文档代码脱节 | FastAPI + OpenAPI 强一致 | 有效 |
| 📦 依赖管理 | 跨仓库易错配 | 训练包单仓化 + 发布契约 | 有收益有复杂度 |
| 🚀 上线策略 | 一次性堆叠 | 双版本迁移后删除旧版 | 有效 |
| 🔀 重构决策 | 聚焦业务短板 | 发现地基问题后全面重构 | 从误判到修正 |
| ⬆️ 重构顺序 | 前端先行 | 数据模型和 API 契约先行 | 关键教训 |
| ✅ 质量保障 | 零散测试 | 分层测试 + 手写 Pipeline | 有效 |
| 🔍 代码 Review | 逐行看代码 | 审查设计意图和契约变化 | 必要转型 |
| 🤖 AI 角色 | AI 是掌控者 | AI 是协作者,人是掌控者 | 核心转变 |
业务短板有时只是冰山一角。 UI 混乱可能不是 UI 问题,而是 API、数据模型和状态 owner 混乱的外在表现。
渐进优化有边界。 当底层架构无法支撑上层闭环时,继续渐进就是在屎山上雕花。
重构必须自底向上。 数据模型、API 契约和状态 owner 是一切上层建筑的地基。
设计文档要写给 AI 看。 文档必须明确事实源、owner、禁止路径、当前偏差和收口计划。
Review 不先看代码。 先看 AI 是否实现了设计意图,再看局部代码质量。
分支是可审查的工程假设。 一分支一目标,小步快跑;发现新问题要拆出来,而不是让 AI 在同一个长分支里不断扩张上下文。
测试是战略核心。 人手写 pipeline 验证“功能要跑的意义”,AI 扩展覆盖范围。
人没问题,是 AI 使用方式有问题。 优秀开发者也会被 AI 放大错误,关键是建立治理体系。
共同建设代码,也共同建设文档。 代码是系统现状,文档是系统意图。AI 需要两者同时存在。
AI 工程不能只依赖当次对话。真正的长期价值,是把一次次开发中的事实、决策、坑、盲点和改进建议沉淀下来。
这里的 Record.md 和 Insight.md 不是拘泥于某个具体工具名,而是一套思路:前者建立项目长期记忆,后者帮助我发现自己都没有意识到的协作模式和问题。
记录哪个版本引入了什么能力,哪次重构解决了什么问题,哪个 bug 暴露了哪个边界缺失,哪次测试失败说明了什么。
从历史事实和 AI 协作记录中抽象规律,发现我自己没有意识到的重复解释、反复踩坑、prompt 缺口和治理盲区。
| 维度 | Insight 思路 | Record 思路 |
|---|---|---|
| 目的 | 分析过去一段时间的人机协作模式,识别优点、摩擦点和待改进点。 | 把散落的会话、修复和决策提炼成持久化项目知识。 |
| 产出 | 更像个人 AI 协作体检报告:工作模式、提示习惯、工具使用、改进建议。 | 更像项目长期记忆库:决策记录、踩坑指南、架构约定、常见修复模式。 |
| 应用范围 | 偏个人级,帮助我优化如何提问、如何约束 AI、如何暴露盲点。 | 偏项目级,可以提交到仓库,供团队成员和未来 AI 会话共享。 |
| 回答的问题 | “我和 AI 协作得怎么样?哪里反复出问题?哪些规则应该写进 Skill?” | “我们上次为什么这么做?哪个坑已经踩过?当前项目有哪些不能破坏的约定?” |
长期记忆不是越多越好。AI 最怕多个互相冲突的事实源,因此 Record 和 Insight 机制必须包含清理动作: 已经废弃的 API、旧状态模型、临时 workaround、过期 prompt、被验证无效的测试策略,都要明确标记为失效或从主路径移除。
保留版本演进、架构决策、业务闭环、owner 边界、测试证据和真实踩坑过程。
清理旧 API、旧 store 假设、过期运行方式、错误经验和已经被新架构替代的规则。
把反复出现的问题转成 CLAUDE.md / AGENTS.md 规则、项目 docs、测试模板或 Codex Skill。
周期性回看 AI 协作记录,识别重复解释、反复犯错、边界不清和 review 低效的模式。
把洞察转成具体动作:更新设计文档、补 pipeline 测试、拆分分支规则、修正 prompt 和 MR 模板。
把有效动作写入 Record、docs 和 Skill;把失效内容清掉,避免 AI 在下一轮继续引用旧事实源。
Record.md 是项目事实库,Insight.md 是协作洞察库,Skill 是可执行约束库。
三者连起来,才能让 AI 开发从“每次重新解释”变成“持续进化的方法论”。
TurboTune 的经验可以压缩成一句话:AI 可以极大提升代码产出速度,但长期工程的核心竞争力不是写得快,而是人能不能持续定义正确的边界、契约、测试和决策机制。
在 AI 时代,用 AI 构建长期工程,识别核心业务闭环当然重要。但更关键的是判断底层架构地基能否支撑这个闭环。 如果短板只是 UI,就聚焦 UI;如果短板是架构,就必须做清创式重构。
定义方向、事实源、API 契约、状态 owner、测试意义和最终决策权。AI 在这些边界内高效执行。
写给 AI 看的设计文档、Skill 约束和测试规范,让每一次 AI 调用都自动遵守同一套工程规则。
Record 记事实,Insight 找盲点,Skill 固规则。三者联动,把个人能力持续转化为组织可复用的系统能力。
本文件为单 HTML 分享稿,可直接在浏览器打开。建议配合仓库中的 docs/api_v2_design.md、docs/testing.md、docs/system_architecture_overview.md 一起讲解。