ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PyCaret Platform Phase 0 数据模型重构:Trial/Run 语义反转规范与落地指南

PyCaret Platform Phase 0 数据模型重构:Trial/Run 语义反转规范与落地指南 PyCaret Platform Phase 0 数据模型重构Trial/Run 语义反转规范与落地指南【免费下载链接】pycaretOpen-source, low-code AutoML platform for Python. PyCaret 4.0: sklearn-native engine React control plane.项目地址: https://gitcode.com/gh_mirrors/py/pycaret本篇技术指南围绕 PyCaret 开源平台gh_mirrors/py/pycaret的 Phase 0 数据模型重构规范docs/revamp/phase-0-spec.md展开完整讲解平台将Trial逻辑管道候选与 Run执行实例层级关系反转的设计动因、目标实体模型、表结构、API 契约变更、迁移计划、代码改动面与测试方案。读完本文你将理解为什么Trial 拥有 Runs的模型比旧模型更贴合用户心智与可复现性要求并掌握该重构在仓库中的迁移文件、编排器与调度层源码落地点以及后续 Session 32 反转该层级方向的真实演进。为什么 Phase 0 必须成为第一个重构Phase 0 在整个 0–14 阶段路线图中排在最前被定位为基础性重构foundational refactor。其理由非常直接后续每一个阶段队列与 Worker 分离、对象存储抽象、模型注册表、调度与漂移触发重训、统计分析等都默认依赖本文描述的实体模型。在开发数据库还很小、且不存在生产数据的窗口期先做掉是现在便宜、以后昂贵的典型取舍。该决策的源头是 docs/revamp/PHASES.md 中锁定的架构决策A3Trial 一个逻辑管道候选logical pipeline candidate拥有稳定身份。Logistic Regression、Tuned XGBoost、Bagged Decision Tree、Stacked Ensemble各自都是一个 TrialRun 一个 Trial 的一次执行实例execution instance。Run 1是首次训练Run 2是用更新数据重训Run 3是漂移触发的重训。而旧代码恰好是反过来的Run 拥有 compare/search 执行以及 leaderboard JSONTrial 是 Run 的 compare 循环产生的行——二者是 Run 为父的 1:N 关系对 Trial 做调参tune时会在同一个 Run 里插入一条新的 Trial 行这是几个 session 前同意的模型长期看是错误的。新模型将二者反转Experiment 直接拥有 TrialsTrial 拥有 Runs1:NRun 拥有 metrics 与 artifactCompare 一次点击产出 N 个 Trial每个都带 Run 1Tune 产出一个新 Trial 及其 Run 1重训同一个 Trial 产出 Run 2。这套语义直接服务于精确可复现Deployment 同时引用(trial_id, run_id)就能精确回溯到一次具体的训练事件而不是一个模糊的候选模型。目标实体模型Phase 0 之后的实体层级如下出自规范原文Workspace └── Project └── Experiment (problem definition: data target preprocessing config) └── Trial (logical pipeline candidate) └── Run (execution instance — metrics, artifact, status, started_at) ↑ Deployment ───┘ (references trial_id run_id together)四个关键职责划分实体职责Workspace顶层容器Project工作区内的项目Experiment问题定义数据 目标列 预处理配置Phase 0 表结构不变Trial逻辑管道候选稳定身份归 Experiment 所有Run执行实例metrics、artifact、status、started_at归 Trial 所有Deployment同时引用trial_idrun_id锁定到精确训练事件从当前源码看这套层级在 services/api/pycaret_server/db/models.py 中已部分落地Experiment.trials、Experiment.runs关系在 L228-L233 定义同时该文件的 Phase 0 注释块L236-L244仍明确记载着Compare 产出 N 个 Trial、每个带 Run 1、共享created_by_action_id的设计意图。表结构设计详解trials修订后规范给出了完整的目标列columntypenotesiduuid PKexperiment_iduuid FK →experimentsON DELETE CASCADE新增—— Trial 属于 Experiment而非 Runworkspace_iduuid FK →workspaces反规范化加速作用域查询kindvarchar(16) NOT NULL DEFAULTcomparecompare \| tuned \| ensembled \| blended \| stacked \| manualnamevarchar(128)引擎模型 id如xgboost或生成名如tuned_xgboostmodel_idvarchar(64)适用时指向引擎注册表 idparent_trial_idsjsonbuuid 列表血缘——tune/blend/stack 的来源created_by_action_iduuid将一次用户动作如一次compare_models点击产出的 Trials 分组独立 Trial 为 NULLcreated_at/updated_attimestampscreated_byuuid FK →users被移除的列run_idFKTrial 不再局限于单个 Run、rank、metrics、is_best、stored_path、sha256、size_bytes、params、notes。这些要么移动到 Runartifact/metrics要么留在 Trial 上以派生方式计算best-run metrics 在读取时计算。runs修订后columntypenotesiduuid PKtrial_iduuid FK →trialsON DELETE CASCADE新增—— Run 属于 Trialexperiment_iduuid FK →experiments反规范化按 Experiment 查询时免 joinworkspace_iduuid FK →workspaces反规范化sequenceint NOT NULL每个 Trial 内的运行序号1、2、3…(trial_id, sequence)唯一statusvarchar(16)queued \| running \| succeeded \| failed \| cancelledstarted_at/finished_attimestampsduration_msfloatmetricsjsonbper-fold 聚合指标stored_pathvarchar(1024)已拟合管道 pickle 的对象存储 URIsha256varchar(64)size_bytesintparamsjsonb估计器超参 tuned 时_best_params、_cv_historyerrortext失败原因snapshotjsonb请求载荷——用于可复现性triggered_byvarchar(32)user \| schedule \| drift \| apitriggered_by_iduuid指向触发源的可空 FKcreated_at/updated_attimestampssnapshot与triggered_by的设计意义值得展开snapshot把派发时刻的请求载荷原样冻结在 Run 上保证任何一次执行都可以按原输入重放这正是后面 Phase 1 Job 表、Phase 9 调度/漂移重训的输入契约triggered_by则让用户点击、定时调度、漂移报警、API 调用四种触发来源在数据上可区分是后续运维审计的基础。deployments修订后columnchangepipeline_id重命名为registered_model_id占位——Phase 7 接线Phase 0 保留pipeline_id并新增 NOT NULL 的trial_idrun_id对trial_id新增—— FK →trialsNOT NULLrun_id新增—— FK →runsNOT NULL。trial_idrun_id合起来 精确可复现规范特别强调Phase 0不会干掉pipelines表——那是 Phase 7 的事。本阶段只增加(trial_id, run_id)让每个 deployment 都能追溯到精确的训练事件。回滚一个部署本质上就是改 deployment 的(trial, run)引用。experimentsPhase 0 内不变无表结构变更但行为发生变化Experiment 的leaderboard视图变成所有 Trials各自按其最佳 Run 的主指标评分。也就是说 leaderboard 不再是一个 Run 内部的产物而是 Experiment 维度对所有逻辑候选的聚合排名。API 契约变更每个 trial/run 端点都会随之变化规范给出的完整对照如下currentbecomesPOST /experiments/:id/runs创建一个 Run内嵌 N 个 trialsPOST /experiments/:id/runs创建一个compare-batchN 个 Trial每个带 Run 1共享created_by_action_id。返回 Trial 列表GET /runs/:run_idGET /runs/:run_id返回一个 Run 其父 Trial ExperimentGET /runs/:run_id/trialsGET /experiments/:id/trialsTrials 现在挂在 Experiments 下GET /runs/:run_id/trials/:trial_idGET /trials/:trial_id或/trials/:trial_id/runs/:run_id取 run 级详情POST /runs/:run_id/trials/:trial_id/tunePOST /trials/:trial_id/tune—— 创建新 Trial Run 1返回新 trial idPOST /runs/:run_id/blendPOST /experiments/:id/blend—— body 列出源trial_ids创建新 Trial Run 1POST /runs/:run_id/trials/:trial_id/promotePOST /trials/:trial_id/runs/:run_id/promoteRun 级保证可复现性GET /runs/:run_id/events/ws不变 —— WebSocket 仍按 Run 作用域—POST /experiments/:id/retrain新增—— 同一 Experiment、同一批 Trial、产出新 Runs。Trial 本身不变。Bodytrial_ids?: [...] // default: all trials in the experiment前端 Trial 详情 URL 从/runs/:run_id/trials/:trial_id变为/trials/:trial_idrun 级子路由为/trials/:trial_id/runs/:run_id。几个值得注意的语义变化Tune 的结果不再是同 Run 内的新行而是独立的POST /trials/:trial_id/tune产出新的 Trial 新的 Run 1血缘通过parent_trial_ids回指源 TrialPromote 变为 Run 级——用户明确选择哪个 Trial 的哪次执行上线杜绝提升的是最新一次重训还是当初那次的歧义Retrain 是全新的第一等端点——它不产生新 Trial只给既有 Trials 追加新 Runs把重训同一候选从隐式操作变成显式 API。引擎与编排层影响规范的结论是引擎本身不需要改动。Compare / Tune / Ensemble / Blend / Stack 本来就把结果作为对象返回平台侧只需把结果持久化到新的 Trial/Run 形状里即可。编排器orchestrator的submit(spec)演化为submit_action(action_spec)按动作类型决定产出action产出compareN 个 Trial N 个 Run-1tune \| ensemble1 个 Trial 1 个 Run-1blend \| stack1 个 Trial 1 个 Run-1retrain0 个新 Trial N 个新 Runs每个源 Trial 一个每个 Trial 都会得到稳定的name由 action 来源计算而来例如tuned_xgboost、stacked(rfxgblr)。源码佐证当前 services/api/pycaret_server/runs/orchestrator.py 中RunOrchestrator.submitL166仍负责主 Run 的排队执行submit_trial_actionL185专门处理 tune / ensemble / blend / stack 这类后续动作其 docstring 明确写道Resolution is by run_id —— action 的事件流进入父 run结果的 Trial 落在该 run 的 trials 表不再创建新的 Run 行_execute_actionL371则把引擎动词exp.tune_model/exp.ensemble_model/exp.blend_models/exp.stack_models逐个映射到kindtuned / ensembled / blended / stacked并通过_insert_followon_trialL536落库。这恰好印证了规范中引擎动词不变、平台侧负责持久化形状的论断——Phase 0 要做的正是把这段 follow-on 逻辑从同 Run 插行重构为新 Trial Run 1。调度侧 services/api/pycaret_server/runs/dispatch.py 的_spawn_trialsL202注释也与规范一致为每个 model id 持久化一个 Trial 一个kindtrial的 Job即 compare 一次点击被拆解成 N 个可并行执行的 Trial-Job——这为后续 Phase 1 的 Redis/RQ Worker 并行化铺平了道路。迁移计划该迁移对开发库是破坏性的——团队明确接受这一点因为那里没有真实数据。新的 Alembic revisionf0a1b2c3d4e5_session28_phase0_trial_run_pivot.pydroptrials.{run_id, rank, metrics, is_best, stored_path, sha256, size_bytes, params, notes}addtrials.{experiment_id, name, created_by_action_id}kindparent_trial_ids已存在addruns.{trial_id, sequence, snapshot, triggered_by, triggered_by_id}大多数字段已存在只需修 FK 和补 sequenceadddeployments.{trial_id, run_id}数据迁移对每个既有 Trial创建一个 experiment 作用域的行并用曾经拥有它的遗留 Run 填充一个 Run 行sequence赋 1。Bootstrap 检测器更新trials表含experiment_id列 ⇒ Phase 0 指纹。pycaret-server migrate --reset-dev标志开发期干净重建。仓库证据该迁移文件确实存在即 services/api/pycaret_server/migrations/versions/20260512_2000_f0a1b2c3d4e5_session28_phase0_trial_run_pivot.py。其 docstring 完整复述了上述设计upgrade()中依次处理三张表trials 增加experiment_id/name/created_by_action_id并显式 droprank、metrics、is_best、stored_path、sha256、size_bytes、params、run_id连索引一起删保证 Postgres 上干净runs 增加trial_id、sequence、metrics、stored_path、sha256、size_bytes、params、triggered_by、triggered_by_iddeployments 增加trial_id、run_id两个 FKON DELETE SET NULL。Bootstrap 指纹在 services/api/pycaret_server/db/bootstrap.py L124-L136 中可查到对应实现has_phase0_trials判定为trials含experiment_id与created_by_action_id且不再含run_id、rank、is_besthas_phase0_runs判定runs含trial_id、sequence、metrics。这说明指纹驱动迁移机制是真实存在且可验证的。回滚迁移按步骤可逆Alembicdowngrade但遗留Run.leaderboardJSON 与新形状之间的数据血缘是有损的。因此实践中回滚 清空开发库 回退到之前的 Alembic revision。团队承诺绝不在没有升级脚本的情况下把 Phase 0 推上生产库目前还不存在升级脚本也还不需要。代码改动面清单规范给出的完整表格如下layerfilesscopeDBservices/api/pycaret_server/db/models.pyTrial Run Deployment ORM 更新Migrationservices/api/pycaret_server/migrations/versions/一个新 revision见上Bootstrapservices/api/pycaret_server/db/bootstrap.pyPhase 0 指纹Schemasservices/api/pycaret_server/api/schemas.pyTrialResponse、RunResponse、请求体——全部更新Routesservices/api/pycaret_server/api/runs.py多数端点移动或改变形状Orchestratorservices/api/pycaret_server/runs/orchestrator.pysubmit_action取代submit按新形状产出 TrialRun 行Dispatchservices/api/pycaret_server/runs/dispatch.pydispatch_action(experiment, payload)返回新 Trial id 列表SDKpackages/sdk-python/pycaret_client/client.py镜像 API 表面Frontend typesapps/web/src/api/types.tsTrial Run Experiment 形状Frontend APIapps/web/src/api/endpoints.ts每个 trial/run helperFrontend pagesRunDetail、TrialDetail、TrialsCard、ExperimentDetail、TrialCompare、ModelCardURL 路由 数据获取 chip 渲染全部涉及Frontend routesapps/web/src/App.tsx/trials/:trial_id、/trials/:trial_id/runs/:run_id注意这张表的路径与当前仓库完全对应例如 services/api/pycaret_server/api/runs.py 的submit_run路由、packages/sdk-python/pycaret_client/client.py、apps/web/src/api/types.ts、apps/web/src/App.tsx 均存在说明该改动面清单是可直接用于工作量估算与验收核对的操作性文档。测试计划后端新增测试文件tests/test_phase0_model.py对 iris 做 Compare → 1 个 experiment、N 个 trials每算法一个、N×1 个 runscompare 产出的 Trial 带有created_by_action_id同一次调用产出的 trials 共享该 idTune trial X → 1 个新 trialkindtuned、parent_trial_ids[X]、1 个新 runsequence1Retrain Experiment → 既有 trials 各自新增一个sequence2的 runBlend[X, Y, Z]→ 1 个新 trialkindblended、parents[X, Y, Z]、1 个新 runStack 同理创建 Deployment 必须同时提供trial_id和run_id缺任一 → 400Deployment 查询返回精确的 Run snapshot。既有使用遗留 run/trial 形状的测试会被重写或标记为 obsolete。前端新TrialDetail/RunDetail组件的 Vitest 测试冒烟测试渲染 Experiment 页、Trial 页、Run 页无 console 错误。端到端手动验证全新数据库pycaret-server migrate --reset-dev上传boston.csv创建 Experiment点击 Compare models → 观察 Trials 逐个出现点击任意 Trial → 查看其 Run 1 详情点击 Tune → 观察新 Trial 创建 → Run 1 流式输出点击 Retrain experiment → 所有既有 Trials 获得 Run 2Promote → 选择 (trial, run) 对 → 部署 → 预测。这套 E2E 流程实际上就是新模型的用户验收路径一次 Compare 批量出 N 个候选、每个候选有独立 Run 历史、Tune 开新枝、Retrain 在旧枝上叠加新 Run、部署锁定到精确 (trial, run)。破坏性变更清单开发库必须清空重来今天没有生产数据需要担心Trial 详情 URL 变更/runs/:run_id/trials/:trial_id→/trials/:trial_id旧书签 404SDK 客户端调用runsApi.trials(run_id)的代码需迁移到experimentsApi.trials(experiment_id)WebSocket 订阅仍按run_id为键——此处无变化但run_id现在标识的是某个 Trial 的一次执行而非一次 compare 批次。最后一条值得强调同一个run_id的语义变化是隐性破坏点所有依赖 WebSocket 事件流做 UI 聚合的代码都需要重新审视。成功标准验收回顾用户应当能够上传 CSV → 创建 Experiment → 点击 Compare → 看到 N 个 Trials 出现每个带 Run 1点击任意 Trial → 看到它的 Run 历史初始只有 Run 1点击 Tune → 看到新 Trial 创建kindtuned其 Run 1 在事件日志中实时流式输出点击 Retrain experiment → 看到每个既有 Trial 获得新 Run打开含多个 Runs 的 Trial → 在子列表中看到它们 → 选中一个 → Promote部署一个具体的(trial, run)对通过改 deployment 的(trial, run)引用实现回滚Phase 7 完全接线Phase 0 只打地基。工程验收条件四个后端 session 测试文件对新形状全绿tsc 零错误59 个 UI 测试仍然通过部分新增、部分更新。未决问题与设计取舍规范在动工前列出四个待确认问题它们直接决定迁移代码的写法Trial.name归属平台自动命名tuned_xgboost、stacked_3还是允许用户在创建时覆盖建议自动生成 事后可编辑。仓库现状可佐证该建议已被采纳——services/api/pycaret_server/db/models.py 中Trial.name的注释写明默认取model_id事后用户可编辑L1466-L1468Deployment FK 对Phase 0 保留pipeline_id并新增(trial_id, run_id)兼容旧数据Phase 7 收拢为(registered_model_id, version)并去掉 Trial/Run FK。仓库中 Deployment 模型L429-L482同时保留了pipeline_id、registered_model_id/registered_model_version_id与trial_id/run_id说明这种过渡期并存策略是当前事实Retrain 端点形状body 为{trial_ids?: [...]}默认取 experiment 的全部 trials仅 succeeded 的。确认Created-by-action 分组一个created_by_action_idUUID 足以per action如 compare/retrain暂不需要独立的actions表。确认四个问题一旦答复迁移编码即可开始。仓库落地现状迁移已实现随后 Session 32 发生反转需要如实说明的是Phase 0 规范在仓库中的演进并未止步于起草状态。从迁移目录可观察到完整脉络20260512_2000_f0a1b2c3d4e5_session28_phase0_trial_run_pivot.py 实现了本文描述的Trial owns Runs迁移但随后 20260516_1200_d4e5f6a8b9c0_session32_revert_trial_run.py 又将层级反转回 PyCaret 3.x 约定Run 包含 1..N 个 Trials理由是每个 Trial 需要独立的状态生命周期queued → running → succeeded|failed|cancelled这才能让 orchestrator 把一个 compare Run 拆成 N 个create_modelJob 并行派发、UI 逐行点亮。值得注意的是 Session 32 的 docstring 明确列出从 Phase 0 保留下来的好东西Trial.kind、parent_trial_ids、created_by_action_id、experiment_idExperiment 作用域反规范化、name、notes、fitted_pipeline_id。也就是说Phase 0 规范中关于 Trial 语义、血缘、动作分组的核心设计被完整保留只是Trial 与 Run 谁拥有谁的挂载方向最终回归了 Run-owns-Trials当前 models.py L1426-L1514 的Trial模型即为该状态含run_id、experiment_id、kind、status、metrics、stored_path、parent_trial_ids、created_by_action_id等。bootstrap.py中同时存在has_phase0_trialsTrial-owns-Run 指纹与has_phase0_v2_trialsRun-owns-Trial 指纹两套判定L124-L147正是这段往返历史的直接代码证据。对读者的实用结论无论你基于这份 spec 做二次开发还是学习借鉴都应把它视为一份设计决策档案——其价值在于把 Trial 稳定身份、Run 执行实例、动作分组、血缘追踪、精确部署可复现这些长期正确的语义论证清楚。这些语义在当前代码库中依然是活跃的骨架而 Trial/Run 的父子方向则建议以 services/api/pycaret_server/db/models.py 的现行 ORM 为准切勿照搬 spec 中已反转的挂载方向去建表。小结Phase 0 数据模型重构是 PyCaret 平台从demo 工具走向可治理、可复现的 MLOps 平台的第一块基石。本文完整覆盖了规范的背景动因、目标实体模型、trials/runs/deployments三张表的列级设计、9 项 API 契约变更、编排器submit_action的四种产出形态、破坏性迁移与回滚策略、跨 12 个文件的代码改动面、三层测试计划、破坏性变更清单、六条成功标准与四个待决问题并结合仓库中的迁移文件、ORM 模型、编排器与调度源码进行了逐项印证。后续 Phase 1队列与 Worker 分离、Phase 7模型注册表 v2、Phase 9调度与漂移重训都建立在本阶段确定的实体边界之上——理解 Phase 0就理解了整个平台的数据骨架。【免费下载链接】pycaretOpen-source, low-code AutoML platform for Python. PyCaret 4.0: sklearn-native engine React control plane.项目地址: https://gitcode.com/gh_mirrors/py/pycaret创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表