Infra:收敛 runtime / registry / backend 架构边界 #109
Description
Activity
- pinned this issue
on Apr 5, 2026 - changed the title
[-]Infra:在大规模协作前收敛 runtime / registry / backend 架构边界[/-][+]Infra:收敛 runtime / registry / backend 架构边界[/+]on Apr 5, 2026 补充一个同样重要的维度:user-friendly 不能只从工程师视角定义。
当前 issue 主要聚焦 runtime / registry / backend / config 的架构边界,这没问题;但如果目标是让 UniLab 在更大范围内被稳定使用,那么还需要把“第一次使用的人会怎么迷路”显式纳入范围。
需要补充的用户视角约束
- 不要默认用户理解内部术语
- 像
smoke test、preflight、Hydra override、registry bootstrap这类词,不应作为用户入口的前提知识 - 文档和 CLI 应优先使用更直接的表述,例如:
- 第一次运行检查
- 环境预检查
- 可用任务列表
- 当前任务支持哪些后端 / 算法
- 必须给出唯一的 first-run 路径
- 用户第一次进入仓库时,不应该先理解 4 套训练脚本、Hydra 语法、backend 差异,才能跑通一条命令
- 应该提供一个明确的“第一次运行”入口,并说明:
- 这条命令会做什么
- 预计耗时多久
- 成功后会看到什么
- 失败时先检查什么
- 用户首先需要的是“我现在该跑哪条命令”,不是“系统有多灵活”
- 当前训练入口、文档和配置能力对熟悉项目的人是灵活的,但对第一次接触的人并不友好
- 应优先提供:
- 一个统一入口或统一命令风格
- 一个可枚举的 task / backend / algo 支持视图
- 一个明确的推荐路径,而不是把选择负担交给用户
- 错误信息必须可行动
- 如果 task/backend/algo 组合不支持,不应只抛底层异常
- 应直接告诉用户:
- 你当前选择了什么
- 为什么不支持
- 可替代的支持组合是什么
- 下一条建议命令是什么
- 文档结构要按用户目标组织,而不是按实现模块组织
- 更适合首批用户的结构通常是:
- 我想第一次跑通
- 我想恢复训练
- 我想只回放结果
- 我想换后端
- 我想知道某个任务支不支持某个算法
- 这些目标不应该要求用户先理解内部目录结构和实现分层
对本 issue 的直接影响
建议把“统一 runtime 边界”进一步收紧为同时满足两类目标:
- 对内:降低架构扩散和协作成本
- 对外:降低第一次使用和定位问题的认知负担
换句话说,这个 issue 不应只产出内部更整洁的架构层,还应产出:
- 一条明确的 first-run 路径
- 一套用户可读的 task/backend/algo 能力视图
- 一组可行动的错误提示与预检查机制
- 一份按用户目标组织的训练/回放入口说明
否则即使内部边界收紧了,外部使用体验仍然会停留在“只有熟悉仓库的人才知道怎么跑”。
截至 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直接验证了:legacyreward/、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 passeduv 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 个:
- 把
ensure_registries()这种扫描导入式 discovery 收敛成更显式、可引用、可 fail-fast 的 registry contract。 - 把播放/渲染/physics snapshot 这些仍在脚本和 common helper 里直接访问
env._backend的路径,下沉为正式 backend capability 或 env-facing contract。
- 把
基于当前证据,我不建议直接关闭 #109;更合理的是保留 open,或者拆成更小的 follow-up issue 后再关闭这个 umbrella。
截至 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直接验证了 legacyreward/、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 passeduv 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:
registry contract / discovery
目标:新增 task / env 不再依赖扫描导入才能被发现,registry source 可枚举、可 fail-fast、可测试。render / snapshot capability abstraction
目标:把model/render/physics_state从env._backend直连,下沉为正式 backend capability 或 env-facing contract,先收口training/common.py和各个train_*/play_interactive.py。ADR / architecture references
目标:把 runtime / backend / config / task family 的边界从“代码里能看出来”变成“文档里能稳定引用”。
基于当前证据,我不建议现在关闭 #109;更稳妥的做法是继续保持 open,把它作为 umbrella issue 追踪剩余架构收口,等上面几个 follow-up 落地后再关闭。
基于这轮评估和后续范围确认,我已经把 #109 继续拆成 3 个 follow-up issue:
- Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap #220
Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap - Infra:补齐 runtime / backend / config / task family 的正式 ADR 与架构引用 #221
Infra:补齐 runtime / backend / config / task family 的正式 ADR 与架构引用 - Infra:将 play/render/physics snapshot 路径收口为正式 backend capability contract #222
Infra:将 play/render/physics snapshot 路径收口为正式 backend capability contract
这里补充说明一下拆分边界:
registry contract / discovery:问题确认存在,单独拆到 Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap #220,聚焦显式 discovery contract,而不是继续沿用扫描导入式 bootstrap。backend capability:这里不要求 MuJoCo 和 Motrix 渲染形式完全一致。两后端当前渲染路径不同是事实,短期也不以“统一功能表现”为目标;Infra:将 play/render/physics snapshot 路径收口为正式 backend capability contract #222 聚焦的是把脚本 / shared helper 里直接访问env._backend.*的路径,下沉为正式 capability / env-facing contract。ADR / architecture references:单独拆到 Infra:补齐 runtime / backend / config / task family 的正式 ADR 与架构引用 #221,补 runtime / backend / config / task family 的正式决策记录和引用关系。
目前看,#109 仍适合作为 umbrella issue 继续保留 open,后续由这些子 issue 分别推进执行。
- Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap #220
截至 2026-04-11,这个 umbrella issue 对应的 3 个 follow-up 已全部完成并合并到
main:- Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap #220 -> PR fix: formalize registry discovery bootstrap #225
fix: formalize registry discovery bootstrap - Infra:补齐 runtime / backend / config / task family 的正式 ADR 与架构引用 #221 -> PR docs: add architecture adrs for runtime and backend contracts #223
docs: add architecture adrs for runtime and backend contracts - Infra:将 play/render/physics snapshot 路径收口为正式 backend capability contract #222 -> PR fix: formalize backend play and snapshot capabilities #224
fix: formalize backend play and snapshot capabilities
因此按 #109 的当前拆分边界,这个架构治理 umbrella 已完成,关闭此 issue。
如果后续还要继续推进更偏 user-facing 的 first-run / preflight / actionable error message 诉求,建议另开新 issue 跟踪。
- Infra:收敛 env registry discovery contract,消除扫描导入式 side-effect bootstrap #220 -> PR fix: formalize registry discovery bootstrap #225
- unpinned this issue
on Apr 10, 2026
背景
UniLab 在进入大规模协作开发前,当前最大的风险不是单点算法实现,而是控制平面已经开始扩散:
这些问题在小团队阶段还能靠上下文同步维持,但在多人并行新增 task、backend、训练路径后,会迅速演化为长期技术债。
目标
在继续扩任务和扩 backend 之前,先把 UniLab 的关键架构边界收紧,让后续协作建立在稳定 contract 上,而不是建立在脚本习惯和局部 patch 上。
建议范围
scripts/train_*.py只保留 Hydra 入口和算法特有 glue codeenv._backend或依赖hasattr(model, ...)分叉预期产出
完成标准
备注
这是一个架构治理 issue,目标是先收敛边界,再拆成后续可执行子 issue。