AI 数据平台

为什么训练任务不应该直接塞进 Spring Boot 请求里

结合 LingBot-VLA 的训练入口,理解任务受理、后台执行、失败恢复和模型产物之间的边界。

1. 点下“开始训练”以后,接口应该什么时候返回

在LeRobot 平台里,创建训练任务看起来也是一个表单:选择数据,填写参数,点击提交。

但它和新增一条普通记录有个明显区别:后面的计算可能持续很久。

一个容易想到的写法,是在 Controller 里启动 Python,等待进程退出,再返回“完成”。如果只为了理解命令怎样被启动,它很直观;放到页面请求里,就会出现几个难题。

浏览器连接断开,进程是否继续?反向代理超时后,用户再次点击会不会启动第二次训练?Java 服务更新重启,页面还能找到之前的进程吗?

这些问题让我更愿意把一次点击拆成两件事:先受理一个持久任务,再由后台执行这个任务。

2. 返回任务编号,比一直等着更清楚

下面是一个简化的接口约定:

http9 行
POST /training-jobs
Content-Type: application/json
Idempotency-Key: orange-training-request-1

{
  "datasetVersionId": 12,
  "recipeVersionId": 3,
  "baseModelVersionId": 5
}

服务确认权限和输入后,把任务持久保存为排队中,再返回:

http7 行
HTTP/1.1 202 Accepted
Location: /training-jobs/231

{
  "id": 231,
  "status": "QUEUED"
}

202 表示受理,不是训练完成,也不保证此时已经分配到 GPU。页面根据编号查询进度;用户关闭页面,任务身份也不会随连接消失。

为了避免响应丢失后重试创建出两个任务,同一次提交应复用请求键。后端在项目和用户范围内,通过唯一约束保存请求键与规范化后的参数摘要,并与任务创建一同提交。同键同参数返回原任务,同键不同参数拒绝;用户明确要再训练一次时,才使用新的键。

请求里的编号属于平台示例,不是 LingBot-VLA 自带的 HTTP API。后端需要检查这些版本属于允许访问的项目、数据已准备好,并且训练配方与所选模型和数据相容。

表单不直接接受一整段任意 Shell 命令。配方可以由服务端维护固定入口、允许的参数和环境,后台再将业务请求转换成执行配置。

3. Java 管任务,执行器管进程

可以先用这样的职责划分:

text10 行
浏览器
  ↓ 创建 / 查询 / 申请取消
Spring Boot
  ├─ MySQL:任务、执行次数、输入和结果
  └─ 后台调度:领取已持久保存的排队任务
                 ↓
            Python Worker
              ├─ 加载数据与模型
              ├─ 运行训练进程
              └─ 上报进度、日志和产物

小型平台可以先轮询数据库里的排队任务,不一定马上引入消息队列。关键是领取需要原子操作,多个后台实例不能同时把同一任务当成自己的新任务。

如果以后改成消息队列,也仍然要处理数据库已经保存、消息却没有成功发送的窗口,以及消息重复投递。多了一个组件,不代表任务生命周期自然可靠了。

我更关心这几个边界能否说清楚:谁确认受理,谁取得执行权,谁真正运行,谁有资格报告最终结果。

Java 当然可以启动 Python 进程。需要分离的是 HTTP 请求与长时间计算的生命周期,而不是禁止两个语言在一台机器上合作。

4. LingBot-VLA 让“训练参数”变得具体

对照 LingBot-VLA 提交 4eb34b7 的训练配置说明,一次后训练会涉及基础模型、数据路径、机器人配置、归一化统计、训练步数和检查点保存等信息。

这些内容不能只藏在 Worker 上一个随时被修改的 YAML 文件里。任务受理时,应把将要使用的配置固定下来:

输入 需要回答的问题
数据集版本 具体读哪些数据,内容是否固定?
模型版本 从哪份预训练权重开始?
训练配方 使用哪个代码版本、入口和环境?
机器人配置 如何解释状态、动作与相机字段?
统计文件 归一化对应哪份数据和处理配置?

这里的配方可以包含 Python、PyTorch、CUDA 和相关依赖的固定环境描述。安装了 LeRobot,不等于任意 LingBot-VLA 版本和权重都能直接运行,仍需按对应仓库的安装与配置要求准备。

权重文件大小也不等于训练显存需求。运行时还涉及激活、梯度、优化器以及所选精度、批量大小等因素。因此,页面不能根据下载大小就承诺某张显卡一定能完成训练。

5. 排队、运行、成功,每一步由什么事实决定

AWS Batch 的任务状态区分了提交、准备、可调度、启动、运行与最终结果。它提醒我,点击按钮和进程开始之间还有一段过程。

对于这里的小平台,可以先对外提供更少的状态:

text2 行
QUEUED → RUNNING → SUCCEEDED
                  └→ FAILED

排队表示请求已经保存;运行表示执行器确认进程已经启动。成功则至少要求进程正常结束、预期产物写完并通过必要的完整性检查。一个日志里出现过 success 单词,不是可靠的完成信号。

还应分别记录提交时间、开始时间和结束时间。提交到结束包含排队,开始到结束才是执行区间。只有这些时间和资源信息都有来源,训练耗时才有可比较的含义。

没有可信上报时,页面可以显示“执行器连接中断”。不要因为几次心跳没有到,就立刻把任务改成已失败并重启;原进程可能还在占用资源运行。

6. 重试一次,不要覆盖上一次

任务 #231 第一次因为数据路径不可读而停止。修正环境以后再次运行,第二次和第一次仍然是两次执行。

因此可以在任务下面保存执行记录:

text3 行
TrainingJob #231:固定输入与请求
  ├─ Attempt #1:启动时间、资源、失败原因、日志
  └─ Attempt #2:启动时间、资源、运行状态、产物

每次执行使用独立的输出目录。Worker 上报时需要携带任务编号和执行编号,通过受信身份认证;平台只允许当前有效执行推进状态,拒绝旧执行迟到的完成消息。

同一执行的重复消息也应去重,并限制状态前进方向。已经成功的执行,不能因为晚到的“运行中”消息又退回运行中。

如果领取者在启动进程后失联,需要先通过执行记录、运行时标识和资源侧查询确认原任务是否仍存在。租约到期只说明联系中断,不足以证明旧进程已经停止。

这也是重试不能无限自动进行的原因。路径写错、配置不相容等问题,重新运行相同输入往往还会失败,应该把原因交给用户处理。

7. 取消和恢复,都需要执行器确认

用户点击取消,只代表平台收到了停止意图。排队任务可以在尚未被领取时原子取消;运行中的任务则需要通知执行器,并等待进程或运行时确认结束。

可以在界面上显示“正在取消”。如果完成和取消同时发生,平台要按实际执行结果以及明确的状态规则落库,不能仅因按钮先返回就声称 GPU 已经释放。

恢复训练也不是重新执行同一条命令。训练检查点可能需要包含模型之外的优化器、调度器等状态,并与代码及配置兼容。LeRobot 的训练说明也把从检查点恢复作为单独操作。

Worker 重启只恢复一个进程环境。它能否接着上一次的步数继续,需要训练程序自身支持,并且保留可用的检查点。

8. 生成了模型文件,还要知道它能做什么

LingBot-VLA 的仓库说明要求推理模型目录包含权重及配置,并提供单独的开环评估入口。因此,平台登记模型时,不应只保存一个模糊的 model_path。

可以保存产物清单、内容摘要、来源任务和执行编号,再由评估记录关联具体检查结果。

此外,它的开环评估脚本在没有指定数据路径时,会使用配置中的训练数据。想判断未见数据上的表现,就要明确传入独立验证数据,并核对实际使用范围。

训练成功、开环结果合理和真机完成任务,是不同的结论。记录里应该分别表达;不能因为 Worker 退出码为零,就让模型页显示“机械臂部署验证通过”。

9. 下一步,我更想补齐中断后的过程

把长任务移出请求线程以后,真正值得继续追的是:进程还在不在,当前由谁负责,日志和检查点保存到哪里,以及失联之后怎样重新确认结果。@Async 可以改变调用在哪个线程执行,但不会单独回答这些问题。

因此,我会先把任务记录管理和实际执行分别列清楚,再逐项补齐启动、取消与恢复的链路。只有它们能对应起来,页面上的状态才足以帮助用户判断下一步该等待、重试,还是先处理输入和环境问题。

相关阅读

← 返回文章