Skip to content

Infra:收敛 runtime / registry / backend 架构边界 #109

Description

@TATP-233

背景

UniLab 在进入大规模协作开发前,当前最大的风险不是单点算法实现,而是控制平面已经开始扩散:

  • 环境注册依赖 import side effect
  • 训练和运行时装配逻辑分散在多个入口脚本
  • backend 差异通过所谓的通用层持续向上渗漏
  • task 配置正在吸收本应属于 runtime 或 backend 抽象层的兼容补丁
  • 关键架构边界缺少正式 ADR / architecture docs 沉淀

这些问题在小团队阶段还能靠上下文同步维持,但在多人并行新增 task、backend、训练路径后,会迅速演化为长期技术债。

目标

在继续扩任务和扩 backend 之前,先把 UniLab 的关键架构边界收紧,让后续协作建立在稳定 contract 上,而不是建立在脚本习惯和局部 patch 上。

建议范围

  1. 显式 env registry
  • 用声明式注册 / 发现机制替换 import-side-effect bootstrap
  • 统一主进程、worker、train/play/eval 的 registry 入口
  • 注册失败必须 fail-fast
  1. 共享 runtime 装配层
  • 抽出 checkpoint resolution、run directory、wrapper 装配、device 选择、play/eval/export 装配
  • 让 scripts/train_*.py 只保留 Hydra 入口和算法特有 glue code
  1. capability-based backend interface
  • 显式定义 reset / step / render / snapshot / close / DR application points
  • 停止在通用 env 和脚本里深入 env._backend 或依赖 hasattr(model, ...) 分叉
  1. config truth-source 收口
  • 明确 Hydra + dataclass 与 YAML 的主从关系
  • 停止把 train script config mutation 当作主要兼容机制
  • 分离 task identity、backend override、reward profile
  1. 协作文档与 ADR
  • 为 runtime、backend、task family、config 边界建立正式 ADR / architecture docs
  • 让 README/docs 与真实入口和支持面保持一致

预期产出

  • 一份明确的 registry contract
  • 一套共享 runtime 模块
  • 一份 backend capability interface
  • 一份 config truth-source 约定
  • 一组最小 ADR,覆盖 runtime / backend / config / task family 边界

完成标准

  • 新增 task 不再依赖 side-effect import 才能被发现
  • train / play / eval 不再各自维护一套 runtime 装配逻辑
  • backend-specific 分支不再继续扩散到通用 env 层
  • task YAML 不再继续承担兼容 patch 的主要职责
  • 关键架构边界可以在文档中被稳定引用,而不是只能从实现猜出来

备注

这是一个架构治理 issue,目标是先收敛边界,再拆成后续可执行子 issue。

Activity

  1. self-assigned this
    on Apr 5, 2026
  2. pinned this issue on Apr 5, 2026
  3. changed the title [-]Infra:在大规模协作前收敛 runtime / registry / backend 架构边界[/-] [+]Infra:收敛 runtime / registry / backend 架构边界[/+] on Apr 5, 2026
  4. TATP-233 commented on Apr 5, 2026

    @TATP-233
    CollaboratorAuthor

    补充一个同样重要的维度:user-friendly 不能只从工程师视角定义。

    当前 issue 主要聚焦 runtime / registry / backend / config 的架构边界,这没问题;但如果目标是让 UniLab 在更大范围内被稳定使用,那么还需要把“第一次使用的人会怎么迷路”显式纳入范围。

    需要补充的用户视角约束

    1. 不要默认用户理解内部术语
    • 像 smoke test、preflight、Hydra override、registry bootstrap 这类词,不应作为用户入口的前提知识
    • 文档和 CLI 应优先使用更直接的表述,例如:
      • 第一次运行检查
      • 环境预检查
      • 可用任务列表
      • 当前任务支持哪些后端 / 算法
    1. 必须给出唯一的 first-run 路径
    • 用户第一次进入仓库时,不应该先理解 4 套训练脚本、Hydra 语法、backend 差异,才能跑通一条命令
    • 应该提供一个明确的“第一次运行”入口,并说明:
      • 这条命令会做什么
      • 预计耗时多久
      • 成功后会看到什么
      • 失败时先检查什么
    1. 用户首先需要的是“我现在该跑哪条命令”,不是“系统有多灵活”
    • 当前训练入口、文档和配置能力对熟悉项目的人是灵活的,但对第一次接触的人并不友好
    • 应优先提供:
      • 一个统一入口或统一命令风格
      • 一个可枚举的 task / backend / algo 支持视图
      • 一个明确的推荐路径,而不是把选择负担交给用户
    1. 错误信息必须可行动
    • 如果 task/backend/algo 组合不支持,不应只抛底层异常
    • 应直接告诉用户:
      • 你当前选择了什么
      • 为什么不支持
      • 可替代的支持组合是什么
      • 下一条建议命令是什么
    1. 文档结构要按用户目标组织,而不是按实现模块组织
    • 更适合首批用户的结构通常是:
      • 我想第一次跑通
      • 我想恢复训练
      • 我想只回放结果
      • 我想换后端
      • 我想知道某个任务支不支持某个算法
    • 这些目标不应该要求用户先理解内部目录结构和实现分层

    对本 issue 的直接影响

    建议把“统一 runtime 边界”进一步收紧为同时满足两类目标:

    • 对内:降低架构扩散和协作成本
    • 对外:降低第一次使用和定位问题的认知负担

    换句话说,这个 issue 不应只产出内部更整洁的架构层,还应产出:

    • 一条明确的 first-run 路径
    • 一套用户可读的 task/backend/algo 能力视图
    • 一组可行动的错误提示与预检查机制
    • 一份按用户目标组织的训练/回放入口说明

    否则即使内部边界收紧了,外部使用体验仍然会停留在“只有熟悉仓库的人才知道怎么跑”。

  5. TATP-233 commented on Apr 10, 2026

    @TATP-233
    CollaboratorAuthor

    截至 2026-04-11,我按当前 HEAD 对这个架构治理 issue 做了一轮 repo 内取证和最贴近风险边界的验证。结论是:已明显推进,但还不满足关闭条件,建议继续保持 open,并把剩余工作聚焦到 registry discovery 与 backend capability 边界收口。

    当前已基本完成的部分:

    • runtime / train 装配共享 已有明显收敛。scripts/train_rsl_rl.py、scripts/train_appo.py、scripts/train_offpolicy.py 都已经通过 unilab.training 共享 BackendAdapter、create_env、get_log_root、render_play_mode、ensure_registries 等公共装配能力;共享实现集中在 src/unilab/training/common.py。
    • config truth-source 收口 基本完成。当前 task 已经是 owner 入口,tests/config/test_config_system.py 直接验证了:legacy reward/、backend_task_preset/、algo_preset/、sim_backend/ 组已移除;每个支持的 runtime variant 都通过单一 task owner 文件 compose;最终 reward/env/algo section 来自 compose 结果,而不是 Python glue 重新拼装。
    • 文档边界 已经明显补齐。docs/zh_CN/00-development-architecture.md 和 docs/zh_CN/02-simulation-backends.md 已把 layered architecture、task owner、backend 选择入口写清楚。
    • backend contract 比 issue 提出时更明确了。src/unilab/base/backend/base.py 已经把核心状态/运动学接口,以及 DR capability (get_dr_capabilities / apply_interval_randomization) 收进统一抽象。

    但按这个 issue 原始完成标准看,下面几项还没有真正完成:

    • 显式 env registry / discovery 还没有摆脱 import-side-effect 路径。当前 src/unilab/utils/algo_utils.py::ensure_registries() 仍然通过 pkgutil.walk_packages(...) + importlib.import_module(...) 扫描并导入 env 模块来完成注册;这比散落在脚本里的隐式 import 更集中,也有 fail-fast,但本质上仍然是“靠 import 触发 decorator 注册”。所以“新增 task 不再依赖 side-effect import 才能被发现”这一条,我认为还未满足。
    • capability-based backend interface 只完成了一部分。虽然 base contract 更清晰了,但播放/渲染路径仍然直接触碰 env._backend:src/unilab/training/common.py 里 Motrix 渲染仍然直接调用 env._backend.init_renderer() / env._backend.render();scripts/train_rsl_rl.py、scripts/train_appo.py、scripts/train_offpolicy.py 的 MuJoCo 视频路径仍然通过 env._backend.get_physics_state() 取状态;scripts/play_interactive.py 仍然直接要求 env._backend.model 和 env._backend.get_physics_state()。所以“backend-specific 分支不再继续向通用层和脚本层扩散”这一条,我认为还未满足。
    • ADR 维度 只看 repo 现状仍偏弱。我能看到 architecture docs,但没有看到成体系的 ADR 文件落地;这点我这里标注为推断,依据是 repo 搜索结果里只有 architecture / backend docs,没有 ADR 命名文件。

    这次我还补跑了相关验证:

    • uv run pytest tests/config/test_config_system.py -q -> 52 passed
    • uv run pytest tests/utils/test_algo_utils.py tests/base/test_registry.py tests/training/test_training_helpers.py -q -> 35 passed

    所以我的建议是:

    • 这个 issue 现在可以视为一个仍然有效的 umbrella,但范围已经比最初缩小了很多。
    • 如果要继续推进,剩余高价值收口点主要是 2 个:
      1. 把 ensure_registries() 这种扫描导入式 discovery 收敛成更显式、可引用、可 fail-fast 的 registry contract。
      2. 把播放/渲染/physics snapshot 这些仍在脚本和 common helper 里直接访问 env._backend 的路径,下沉为正式 backend capability 或 env-facing contract。

    基于当前证据,我不建议直接关闭 #109;更合理的是保留 open,或者拆成更小的 follow-up issue 后再关闭这个 umbrella。

  6. TATP-233 commented on Apr 10, 2026

    @TATP-233
    CollaboratorAuthor

    截至 2026-04-11,我按当前 HEAD 重新复核了 #109 对应的 registry / runtime / backend / config 边界。结论与 2026-04-10 的评估基本一致,但我这里补充成更适合后续拆分执行的版本:这个 umbrella issue 已完成大半,但还不满足关闭条件,建议继续保持 open,并把剩余工作拆成更小的 follow-up issue。

    当前已明显收敛的部分:

    • shared runtime 基本落地。src/unilab/training/common.py 与 src/unilab/training/backend_adapter.py 已统一 ensure_registries、create_env、checkpoint resolution、log root、play rendering glue、task/play env override;scripts/train_rsl_rl.py、scripts/train_appo.py、scripts/train_offpolicy.py 的装配已明显收敛,scripts/train_mlx_ppo.py 也在复用同一批 helper。
    • config truth-source 基本完成。tests/config/test_config_system.py 直接验证了 legacy reward/、backend_task_preset/、algo_preset/、sim_backend/ 组已移除,owner YAML 已成为最终 compose 入口,reward/env/algo section 来自 YAML compose,而不是 Python glue 重新拼装。
    • architecture / support docs 已有正式落点。docs/zh_CN/00-development-architecture.md 与 docs/zh_CN/02-simulation-backends.md 已能稳定引用 layered architecture、task owner、support matrix 和 evidence grade。
    • backend base contract 比 issue 创建时清晰得多。src/unilab/base/backend/base.py 已把核心 state / kinematics 接口,以及 DR capability (get_dr_capabilities / apply_interval_randomization) 放进统一抽象。

    但按 issue 原始完成标准,下面几项我认为仍未完成:

    • 显式 registry discovery 还没有真正替代 side-effect import。当前 src/unilab/utils/algo_utils.py::ensure_registries() 仍然是 pkgutil.walk_packages(...) + importlib.import_module(...) 的扫描导入模式。它现在更集中,也更 fail-fast,但本质上仍然是“靠 import 触发 decorator 注册”,所以“新增 task 不再依赖 side-effect import 才能被发现”这一条,我认为还未满足。
    • capability-based backend boundary 还没有完全收口。当前播放/渲染/physics snapshot 路径仍直接访问 env._backend:
      • src/unilab/training/common.py 仍直接调用 env._backend.init_renderer() / env._backend.render()
      • scripts/train_rsl_rl.py、scripts/train_appo.py、scripts/train_offpolicy.py 的 MuJoCo play 路径仍直接取 env._backend.get_physics_state()
      • scripts/play_interactive.py 仍直接要求 env._backend.model 与 env._backend.get_physics_state()
        所以“backend-specific 分支不再继续向通用层和脚本层扩散”这一条,我认为也还未满足。
    • ADR 维度仍偏弱。我能看到 architecture docs,但 repo 搜索里没有看到成体系的 ADR 文件;因此“关键边界可通过 ADR 稳定引用”这一条,我这里也先标为未完成。

    这次复核我补跑了最贴近风险边界的验证:

    • uv run pytest tests/config/test_config_system.py -q -> 52 passed
    • uv run pytest tests/utils/test_algo_utils.py tests/base/test_registry.py tests/training/test_training_helpers.py -q -> 39 passed

    如果要继续推进,我建议把剩余范围拆成 3 个 follow-up:

    1. registry contract / discovery
      目标:新增 task / env 不再依赖扫描导入才能被发现,registry source 可枚举、可 fail-fast、可测试。
    2. render / snapshot capability abstraction
      目标:把 model / render / physics_state 从 env._backend 直连,下沉为正式 backend capability 或 env-facing contract,先收口 training/common.py 和各个 train_* / play_interactive.py。
    3. ADR / architecture references
      目标:把 runtime / backend / config / task family 的边界从“代码里能看出来”变成“文档里能稳定引用”。

    基于当前证据,我不建议现在关闭 #109;更稳妥的做法是继续保持 open,把它作为 umbrella issue 追踪剩余架构收口,等上面几个 follow-up 落地后再关闭。

  7. TATP-233 commented on Apr 10, 2026

    @TATP-233
    CollaboratorAuthor

    基于这轮评估和后续范围确认,我已经把 #109 继续拆成 3 个 follow-up issue:

    这里补充说明一下拆分边界:

    目前看,#109 仍适合作为 umbrella issue 继续保留 open,后续由这些子 issue 分别推进执行。

  8. TATP-233 commented on Apr 10, 2026

    @TATP-233
    CollaboratorAuthor

    截至 2026-04-11,这个 umbrella issue 对应的 3 个 follow-up 已全部完成并合并到 main:

    因此按 #109 的当前拆分边界,这个架构治理 umbrella 已完成,关闭此 issue。

    如果后续还要继续推进更偏 user-facing 的 first-run / preflight / actionable error message 诉求,建议另开新 issue 跟踪。

  9. unpinned this issue on Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions