Skip to content

【No.3】feat(inference): unify Rollout, GenRM, and Teacher service - #356

Open
Arazyu wants to merge 55 commits into
redai-studio:mainfrom
Arazyu:codex/rfc71-unified-inference-service
Open

Arazyu wants to merge 55 commits into
redai-studio:mainfrom
Arazyu:codex/rfc71-unified-inference-service

Conversation

@Arazyu

@Arazyu Arazyu commented Sep 22, 2026 •

Copy link
Copy Markdown

Summary

Implements the RFC #71 unified inference service scope for Rollout, GenRM, and Teacher, with integration of GenRM elastic scaling from #370.

  • Add the CPU-only InferenceGateway, shared InferenceManager/lifecycle, placement planner, routing schema, and compatibility client.
  • Validate decoupled, split, and defer placement before startup, with shared drain/offload/onload and deferred Teacher writeback.
  • Preserve static-model protection, logical-head discovery, legacy interfaces, PG ownership, and rollback semantics.
  • Add CPU/GPU tests, validation launchers, and bilingual interface and usage documentation.

GenRM integration

Commit 36ee4ba8edca29fcf6d1d563eaabc503842b5512 integrates #370 at da4acbbab530f082f37c1633c811c704be5a044e into the previous #356 head, 9eec00a186b4b92f32dc2aba9c23e673e2375b13. This PR now includes #370's implementation and original commit history, together with the compatibility fixes:

  • Route canonical discovery and legacy clients through the same published engine states; exclude candidates, draining engines and retired slots from admission.
  • Preserve legacy GenRM sampling and response attribution through the shared gateway. Count raw and streaming requests through completion, and bind closed admission to engine identity so recovered engines can reuse retired addresses.
  • Preserve split placement offsets and shared Teacher PG ownership. Retain owned PGs until Ray confirms REMOVED, reconcile unfinished cleanup, and create a fresh PG when recovering a failed elastic engine.
  • Reject deferred sharing, training-offload pools (--offload-rollout) and multi-GPU elastic engines before taking the training lifecycle lock or allocating resources.
  • Preserve global sglang_* tuning inheritance without overriding GenRM role defaults; per-model engine configuration keeps priority. Cover this contract in CPU tests that do not require SGLang.
  • Update the English/Chinese GenRM and Rollout API documentation and regenerate the GenRM OpenAPI schema.

Elastic scaling retains #370's scope: single-GPU elastic engines and drain accounting within one Gateway. Consistent direct-client routing does not establish direct-client or cross-Gateway graceful drain. Pools that participate in training offload do not support live elastic scaling in this integration.

Acceptance evidence

The following are previously reported results from before the integration with #370. They have not been rerun after integration with #370 and do not establish GPU acceptance of the integrated head:

  • Contract suite: 91 passed, 1 skipped; the skip was the Ray-only port allocator check on a workstation without Ray.
  • GPU allocation 6654867: PP/PD routing and complete Megatron data flow passed.
  • GPU allocation 6772050: four-node split training passed, including Teacher writeback before GenRM and completed Megatron steps.
  • GPU allocation 6780723: four-node decoupled training passed, including Teacher results before training and dynamic Rollout updates.

Evidence inherited from #370 and demos/task4_genrm/ likewise belongs to its original producing revisions, not a new integration run.

The public API pages document the unified inference interfaces and usage:

  • docs/en/api/inference.md
  • docs/zh/api/inference.md

Validation

Current head: 0e1b7228bf3f058e9cca8e16bdea43357f9f2e5d.

The current follow-up isolates the test-only SGLang import bridge: module-cache and parent-package bindings are restored on both success and failure, while an available runtime is imported unchanged. The isolation regressions passed 9 tests; the combined manager/precheck run passed 31 tests with 20 missing-SGLang skips and 5 passing subtests. These counts overlap. All pre-commit hooks passed before committing. The current head requires fresh remote CI results.

Remote validation on the preceding functional head bf354e7:

The following functional regression results were also collected on bf354e7. Local environment: macOS arm64, Python 3.12.13, Ray 2.59.0, pytest 9.1.1, CPU only. Python commands ran through uv in a temporary test environment.

Validation Result
Unified inference, engine/Teacher lifecycle, GenRM routing/scaling, watcher, registry and Autoscaler regressions 454 passed, 4 skipped, plus 5 passing subtests
Engine lifecycle and SGLang argument contracts, included in the preceding suite 31 passed, including global tuning inheritance, override precedence and static-model defaults
pre-commit run --all-files All hooks passed

The four skips concern an unavailable Rollout import. The suite uses the existing test-only import bridges for unavailable optional dependencies; the argument regressions execute the production builder with a minimal supported ServerArgs schema and do not require an installed SGLang runtime. Broader local CPU testing remains incomplete because this macOS environment lacks some Linux/runtime dependencies; it is not reported as a full-suite pass. Multi-node GPU acceptance has not been rerun after the integration; remote CI results must be assessed on the current head separately.

The GenRM routing tests now consume canonical discovery snapshots and verify immediate admission changes, round-robin continuity and recovery. The watcher regression injects the exception at the processing boundary without a real deadline wait. Registry tests cross reduced test-only capacity limits repeatedly and verify eviction while protecting live and dirty records; production limits and CI timeouts are unchanged.

The VitePress documentation build passed on integration commit 36ee4ba; the subsequent fixes do not modify documentation.

Test commands

TEST_PYTHON is the Python executable in the temporary test environment.

uv run --no-project --python "$TEST_PYTHON" python - <<'PYTEST'
from tests.utils._dep_stubs import import_genrm_component
import_genrm_component()
import pytest
raise SystemExit(pytest.main([
    '-q', 'tests/inference',
    'tests/distributed/ray/test_multi_engine_manager.py',
    'tests/distributed/ray/test_genrm_scale_placement.py',
    'tests/distributed/ray/test_teacher_manager.py',
    'tests/distributed/ray/test_teacher_manager_factory.py',
    'tests/components/test_genrm_engine_pick.py',
    'tests/components/test_genrm_scale_endpoints.py',
    'tests/components/test_genrm_scale_watcher.py',
    'tests/utils/test_genrm_scale_registry.py',
    'tests/utils/autoscaler',
    'tests/backends/megatron/test_model_provider_vpp.py',
    '--disable-warnings', '--tb=short', '-ra',
]))
PYTEST

uv run --no-project --python "$TEST_PYTHON" python -m pytest \
  tests/inference/test_engine_contract.py -q --tb=short
uv run --no-project --python "$TEST_PYTHON" python -m pytest -q \
  tests/utils/test_dep_stubs.py \
  tests/distributed/ray/test_genrm_scale_placement.py \
  tests/distributed/ray/test_scale_weight_sync_precheck.py --tb=short
uv run --no-project --python "$TEST_PYTHON" pre-commit run --all-files

Refs #71, #351; integrates #370.

# ⭐ Feature

## Share the inference control plane

- Add the CPU-only gateway, common manager, lifecycle coordinator, placement planner, routing schema, and compatibility client for Rollout, GenRM, and Teacher.
- Validate split, defer, decoupled placement and reject same-phase co-residency before startup.
- Coordinate drain, offload, onload, deferred Teacher publication, and dynamic Rollout updates without changing role workloads.

---

# ✅ Tests

## Cover RFC redai-studio#71 contracts and GPU workflows

- Add CPU tests for routing, discovery, placement, lifecycle rollback, PG ownership, static-weight protection, legacy clients, and deferred publication.
- Add opt-in PP/PD topology and three-role GPU integration tests and validation launchers.
- Record passing split and decoupled multi-node training evidence in the bilingual validation guide.

---

# 📝 Documentation

## Document the acceptance evidence

- Add English and Chinese API and validation guides with reproducible commands and acceptance mapping.
- Keep the scope limited to the explicit RFC redai-studio#71 acceptance checks.
@rai-studio-bot

rai-studio-bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Nyanpasu 审查看板

审查状态: ✅ 已通过

审查版本: 0e1b722

目标分支: main

第五轮复查头 0e1b722(较上轮 36ee4ba 新增三笔提交,均针对上轮发现与 CI 反馈):79d98456 将 engine-pick 回归测试改写为按规范发现快照逐次取准入(旧断言对应集成前缓存语义,36ee4ba8 的 CI 已证实失败);bf354e70 恢复 GenRM 对全局 sglang_* 参数的继承(与合并基线逐字节一致,F4 随之解决),并以真实 dataclasses schema 重建契约测试,无需安装 SGLang 即可执行,消除原 importorskip 盲区;0e1b7228 隔离 _dep_stubs 的引擎导入桥(try/finally 恢复 sys.modules 与包属性),修复了对未改动测试的模块缓存污染(bf354e70 CPU 测试失败的机制)。本地逐文件复跑 scale/registry/contract/pick/precheck/stubs/sglang/gateway 套件共 224 例加 5 子测试全部通过;bf354e70 的 GPU Unit Tests 与 Integration Tests(Qwen3-4B 4GPU/2GPU/4NPU)经 GitHub API 核实成功。当前头的 CPU Tests 因 bypass 门未开尚未运行,多节点 GPU 验收沿用功能性前驱 bf354e7 的运行结果(与本头仅差测试文件)。结论 APPROVE;上轮发布时 36ee4ba 的 CI 失败(engine-pick 旧测试)未及时纳入结论,本轮已核对并确认由 79d9845 修复。

审查阶段进度范围与结果
常规审查 ✅ 已完成 受理清单 62ac2308 全部 115 文件(12 组,115 接收/0 移出/0 待确认),相对上轮清单新增 tests/components/test_genrm_engine_pick.py 与 tests/utils/test_dep_stubs.py,其余 113 文件与本轮已审的 de44c972 清单一致。逐项复核 36ee4ba..0e1b722 全部 7 文件增量:仅 relax/backends/sglang/sglang_engine.py 两行生产变更(恢复继承循环,与合并基线 1632–1637 行逐字节一致,rollout 侧同构),其余为测试对齐、契约测试重建与桩隔离;作者 PR 描述新增的验收声明(继承契约、隔离回归 9 例、bf354e70 GPU 运行)已逐条核实。本地 224 例加 5 子测试通过。
深度审查 ✅ 已完成 跨模块结论沿用第三轮(36ee4ba8)对集成语义的核验,本轮对涉及文件复核未变:弹性恢复 _managed_ranks 排除退役/候选/排水槽位、drain 记账双路径同命名空间、发现快照不持转移锁、PG 保留至 REMOVED 确认。本轮新增增量的必要性:继承循环恢复即回到合并基线契约(非新增机制);桩隔离以 bf354e7 的真实 CI 失败为必要性证据,test_dep_stubs 9 例覆盖恢复路径四态;registry 测试限界为测试时限优化,覆盖等价并加强断言。多节点 GPU 行为已由 bf354e7 的 Integration Tests 覆盖(与本头仅差测试文件),完整训练流程多节点复跑边界沿用 PR 描述披露。

审查发现

待处理
编号 严重性 问题状态规则来源
暂无待处理的记录。
已解决或已取代
编号 严重性 问题状态规则来源
F1 Medium severity 首次异步权重同步后未发布网关就绪状态 ✅ 已解决 —
F2 Medium severity 同步更新旧握手测试的 Manager 替身 ✅ 已解决 —
F3 Low severity 更新 PR 描述中的验收资料引用 ✅ 已解决 —
F4 Medium severity GenRM 引擎丢失全局 sglang_* 参数继承 ✅ 已解决 —
提交范围 · 接收 115 · 建议移出 0 · 待确认 0

接收 115 个文件 · 建议移出 0 个文件 · 待确认 0 个文件。移出与待确认部分暂停深审,不代表审查通过。

文件结论仓库维护必要性依据替代去向或方案
relax/inference/__init__.py
relax/inference/lifecycle.py
relax/inference/manager.py
relax/inference/placement.py
relax/inference/routing.py
relax/distributed/ray/inference_ports.py
relax/utils/inference_client.py
接收 统一推理控制面(网关外的共享生命周期、放置规划、路由 schema、端口分配与兼容客户端)。相对上轮已通过的 9eec00a 内容无变化,本轮结论沿用。 RFC #71 统一推理服务验收范围;controller 启动路径与 Rollout/GenRM/Teacher 服务为既有调用方,前几轮已核对生产调用链。 无更小的现有机制可同时满足三角色统一生命周期与网关路由;沿用各角色独立 Manager 会保留本 PR 要消除的重复生命周期代码。
relax/components/genrm.py
relax/components/inference_gateway.py
relax/distributed/ray/genrm.py
relax/distributed/ray/multi_engine_manager.py
relax/distributed/ray/teacher_manager.py
relax/components/rollout.py
接收 集成提交对两侧实现取并后做出实质解析的交集文件:规范化发现与旧客户端共用同一发布引擎状态、排空记账纳入网关请求计数、拆分放置偏移与 Teacher PG 共享归属、拒绝延迟共享/训练 offload/多 GPU 弹性布局的前置校验。这是本轮新增语义的核心。 集成提交 36ee4ba 的 --cc 解析内容与 PR 描述列出的兼容修复;两侧(#356 统一推理、#370 弹性扩缩容)都改动了这些文件。 回到逐侧取舍(任一整侧)会丢失另一侧的已审语义:只取 #370 会丢统一推理的网关路由与生命周期,只取 #356 会丢弹性扩缩容;并集加显式解析是满足两个功能同时运行的必要边界。
relax/utils/autoscaler/autoscaler_service.py
relax/utils/autoscaler/config.py
relax/utils/autoscaler/metrics_collector.py
relax/utils/autoscaler/monitor.py
relax/utils/autoscaler/scaling_decision.py
relax/utils/genrm_scale_registry.py
relax/backends/sglang/sglang_engine.py
接收 #370 弹性扩缩容实现(Autoscaler 服务、配置、指标、伸缩决策、GenRM scale registry、SGLang 引擎弹性接口),经合并原样并入且与解析文件无交叠;其正确性审查的规范讨论在 #370(本账号 69 条行内评论所在)。 PR #370(GenRM 弹性扩缩容与自动伸缩)经集成提交并入本 PR;#370 评审线程为其规范讨论。 不并入则本 PR 无法提供 GenRM 弹性扩缩容且与 #370 分叉;等待 #370 先合并再 rebase 属编排选择,不改变这些文件必须进入仓库的事实。
relax/backends/megatron/actor.py
relax/backends/megatron/model_provider.py
relax/components/actor.py
relax/core/controller.py
relax/core/service.py
relax/distributed/checkpoint_service/backends/device_direct.py
relax/distributed/ray/multi_instance_orchestrator.py
relax/distributed/ray/rollout.py
relax/engine/rollout/on_policy_distillation.py
relax/engine/rollout/sglang_rollout.py
relax/utils/arguments.py
relax/utils/opd/opd_utils.py
relax/utils/utils.py
接收 既有角色服务、后端与编排层的统一推理接入(放置校验、共享 drain/offload/onload、延迟 Teacher 写回、非阻塞初始权重同步、NPU provider 放置排除),相对上轮已通过内容无变化。 RFC #71 与既有调用链;前几轮已逐项核对并批准,本回合这些文件相对 9eec00a 字节一致。 不改这些调用方则网关没有生产入口;保留旧接口并新增并行路径会造成双份生命周期状态机。
scripts/training/hpc/run-unified-inference-2gpu.sh
scripts/training/hpc/run-unified-inference-3role.sh
scripts/training/hpc/unified_inference_reward.py
scripts/training/genrm/run-qwen3-0.6B-4xgpu-genrm-continuity.sh
scripts/training/genrm/run-qwen3-0.6B-4xgpu-genrm-smoke.sh
demos/task4_genrm/contract_demo.py
demos/task4_genrm/e2e_autoscaler_load.py
demos/task4_genrm/e2e_autoscaler_preregistered.py
demos/task4_genrm/e2e_failure_injection.py
demos/task4_genrm/e2e_genrm_scale.py
demos/task4_genrm/e2e_reward_consistency.py
demos/task4_genrm/e2e_sampling_divergence.py
demos/task4_genrm/e2e_train_continuity.py
demos/task4_genrm/probe_sglang_serve.py
demos/task4_genrm/render_demo.py
demos/task4_genrm/README.md
demos/task4_genrm/README_zh.md
demos/task4_genrm/test_contract_demo.py
接收 统一推理验证入口(hpc 脚本,前轮已通过)与 #370 的 GenRM 弹性扩缩容演示驱动(e2e_*、contract demo、探针与双语 README)。demos 驱动在 #370 中已并入其评审范围且 demos/task4_genrm/test_contract_demo.py 持续执行 contract_demo.py。 PR 描述与 demos/task4_genrm/README;#370 评审线程为演示内容的规范讨论。 若仅作一次性验收证据可放 PR 附件,但演示驱动被仓库测试引用并构成可复现的用户示例,与现有 examples/scripts 布局一致。
demos/task4_genrm/EVIDENCE.md
demos/task4_genrm/results/autoscaler_prereg_v2_20260925_r5/verdicts.json
demos/task4_genrm/results/autoscaler_preregistration_20260925.md
demos/task4_genrm/results/autoscaler_preregistration_v2_20260925.md
demos/task4_genrm/results/autoscaler_run_20260924_v3/verdicts.json
demos/task4_genrm/results/b2_train_smoke_20260925/verdicts.json
demos/task4_genrm/results/b2_train_smoke_20260925_r2/verdicts.json
demos/task4_genrm/results/b2_train_smoke_20260925_r3/verdicts.json
demos/task4_genrm/results/e2e_run_20260924/verdicts.json
demos/task4_genrm/results/failure_injection_20260925_r2/verdicts.json
demos/task4_genrm/results/reward_consistency_20260925_r2/verdicts.json
demos/task4_genrm/results/reward_consistency_20260925_r3/verdicts.json
demos/task4_genrm/results/sampling_divergence_20260925_r3/verdicts.json
demos/task4_genrm/results/train_continuity_20260925_r4/verdicts.json
demos/task4_genrm/results/train_continuity_20260925_r5/verdicts.json
接收 #370 的最终验收证据(预注册协议、逐运行 verdict、EVIDENCE.md 结论表);原始运行工件已被 .gitignore 排除,仅提交最终判定。证据归属其产出提交,证据审查的规范讨论在 #370(本账号对 EVIDENCE.md 有 14 条行内评论)。 #370 的验收证据策略与 demos/task4_genrm/EVIDENCE.md;.gitignore 新增排除规则。 放 PR 描述或外部附件会割裂 #370 的证据链与评审引用;逐运行 verdict 由 EVIDENCE.md 结论表逐行引用,留在仓库内可核查。
tests/components/test_genrm_scale_endpoints.py
tests/components/test_genrm_scale_watcher.py
tests/components/test_scale_response_models.py
tests/distributed/ray/test_genrm_scale_placement.py
tests/distributed/ray/test_teacher_manager.py
tests/backends/sglang/test_sglang_engine.py
tests/utils/_dep_stubs.py
tests/utils/autoscaler/test_autoscaler_service.py
tests/utils/autoscaler/test_metrics_validity.py
tests/utils/autoscaler/test_monitor_service_view.py
tests/utils/autoscaler/test_scaling_decision.py
tests/utils/autoscaler/test_service_targets.py
tests/utils/data/test_identity_window_sampler.py
tests/utils/test_genrm_scale_registry.py
tests/utils/test_dep_stubs.py
接收 #370 弹性扩缩容的端点、watcher、放置、registry 与 autoscaler 指标/目标测试族,以及本机无重型依赖时替换 _dep_stubs 的桩模块。其内容审查的规范讨论在 #370;集成提交对其中端点与放置测试有解析性增补。 第五轮 0e1b722 为 _dep_stubs 的引擎导入桥补隔离(try/finally 恢复 sys.modules 与包属性)并新增其回归测试,修复对未改动测试的 sys.modules 污染。 PR #370 的测试族经集成提交并入;#370 评审线程为规范讨论。 删除即失去弹性扩缩容的回归保护;并入既有组件测试会破坏按模块组织并模糊 #370 的评审归属。 不隔离则桩模块泄漏会破坏同进程后续测试的 patch 解析(bf354e70 的 CI 失败即此机制);仅靠调用方自律不可维持。
tests/inference/test_engine_contract.py
tests/distributed/ray/test_multi_engine_manager.py
tests/components/test_genrm_engine_pick.py
接收 集成解析涉及的既有测试:引擎契约测试并入弹性引擎状态断言,multi_engine_manager 测试补充弹性恢复场景(--cc 解析内容),是集成语义的直接回归载体。 第五轮 79d9845 将 engine-pick 回归测试重写为按规范发现快照逐次取准入(旧版断言缓存列表语义,集成后已失效且在 36ee4ba 被 CI 证实失败)。 集成提交 36ee4ba 的 --cc 测试解析;对应 relax/components/inference_gateway.py 与 relax/distributed/ray/multi_engine_manager.py 的兼容修复。 不加断言则网关发现/排空记账与弹性恢复的集成语义无回归保护;单独新建文件会重复既有测试装置。 测试层无更小替代:缓存列表语义已被集成语义取代,保留旧断言会固化失效行为。
tests/inference/test_control_plane.py
tests/inference/test_deferred_pipeline.py
tests/inference/test_genrm_gateway_compatibility.py
tests/inference/test_rollout_contract.py
tests/inference/test_training_startup.py
tests/inference/test_validation_scripts.py
tests/inference/test_weight_update_transport.py
tests/integration/test_unified_inference_gpu.py
tests/integration/test_unified_inference_topology_gpu.py
tests/examples/test_unified_inference_reward.py
tests/backends/megatron/test_model_provider_vpp.py
tests/backends/sglang/test_genrm_offload_drain.py
tests/components/test_rollout_weight_update_handshake.py
tests/core/test_controller_s3_model_cleanup.py
tests/core/test_service_affinity.py
tests/distributed/ray/conftest.py
tests/distributed/ray/test_opd_multi_teacher_orchestration.py
tests/distributed/ray/test_opd_teacher_controller_colocate.py
tests/distributed/ray/test_utils.py
tests/engine/rollout/test_on_policy_distillation_payload.py
接收 统一推理与既有模块的契约、控制面、延迟流水线、启动模式与 GPU 拓扑测试,以及既有测试的接口适配,相对上轮已通过内容一致(个别文件获 #370 侧少量适配并保留原语义)。 PR 描述的 CPU/GPU 测试范围与前几轮已核对结论;本回合这些文件相对 9eec00a 内容一致或仅并侧保留。 删除即失去既有回归覆盖;将断言并入新测试族会破坏按模块组织的现有测试结构。
docs/.vitepress/config.mts
docs/en/api/genrm.md
docs/en/api/inference.md
docs/en/api/rollout.md
docs/zh/api/genrm.md
docs/zh/api/inference.md
docs/zh/api/rollout.md
接收 统一推理与 GenRM 弹性扩缩容的中英 API 文档与导航入口;GenRM/Rollout 文档经集成解析同时记录两侧语义与支持范围(单 Gateway 排空、单 GPU 弹性副本)。 PR 描述列出的文档页;集成提交在两种语言中记录支持范围与限制。 接口与支持范围若无正式文档页,用户只能读源码或误解弹性能力边界。
docs/public/openapi/genrm.json
docs/public/openapi/rollout.json
scripts/tools/generate_openapi.py
接收 GenRM/Rollout OpenAPI schema 再生成与生成脚本的最小适配;schema 内容由生成脚本从代码派生,属构建产物。 集成提交重新生成 GenRM OpenAPI;scripts/tools/generate_openapi.py 为其生成器。 手改 schema 会与生成器漂移;不更新则 API 文档与实现脱节。
.gitignore
接收 排除 demos/task4_genrm 的原始运行工件(日志、临时输出),保留最终 verdict;与提交证据策略配套。 集成提交新增的忽略规则;demos/task4_genrm/results/ 仅保留最终判定文件。 不忽略则每次运行都会污染工作区并诱导提交原始工件;更窄的白名单式排除属于 #370 已定的证据策略。
精简审查与验证依据
审查范围进度结论
生产代码 ✅ 已完成 第五轮生产变更仅 sglang_engine.py 两行恢复(回到合并基线契约,非新增机制,无需替代方案分析);其余生产文件与 36ee4ba 一致,第三轮的合并/保留决策(recover 去重合并、_engine_state 统一准入、/engines legacy 视图保留)经与当前头逐项核对后沿用。
测试 ✅ 已完成 第五轮测试增量逐项核审:engine-pick 测试重写消除对已失效缓存语义的断言(CI 失败证实必要性);watcher 测试改在处理边界注入异常,覆盖同一崩溃契约且消除 60 秒死等;registry 洪水测试以缩限重复溢出,覆盖等价并加强驱逐断言;_dep_stubs 隔离以真实 CI 失败为必要性证据。三项均无重复或可删除机制。

生产代码的必要性与替代方案

范围必须保留的契约更简单的方案结论依据与限制
relax/distributed/ray/genrm.py 恢复路径(#370 副本 vs 基础 recover) MultiEngineManager.recover 消费 _managed_ranks 判定可恢复槽位;调用方为训练循环与 onload 的恢复点(relax/distributed/ray/multi_engine_manager.py) 保留 #370 的 GenRMManager.recover 独立副本(含 "全部可恢复槽位死亡才抛错" 语义) 合并 集成已合并为 _managed_ranks 钩子;基础 recover 更强:重建异常或仍有死槽即置 inference.state=failed 并抛 RuntimeError(本头已核),早于 #370 副本仅在全部死亡时抛错;本地 40 例 manager/engine-contract 测试通过。限制:多节点 GPU 恢复未复跑。
relax/distributed/ray/genrm.py _engine_state 统一准入状态 get_engine_hosts_ports、_live_published_count、get_inference_snapshot 与规范发现共同消费的准入真相(state==ready 且 direct_eligible 才可路由) 回到 #370 在各调用点散布 hidden 布尔集合检查 保留 单一状态函数取代 4 处独立 hidden 检查,与规范发现的 engine_record 状态对齐,减少候选/排水/退役集合的同步点;集成提交的 diff 显示该统一替换了重复判断。行为由 tests/distributed/ray/test_genrm_scale_placement.py(22 通过)覆盖。
relax/components/genrm.py /engines 合并 legacy 容量视图与规范发现 Autoscaler 消费 legacy 的 current/ready/occupied/pending_cleanup 字段(#370 契约),新客户端消费规范发现 routes/models 删除 legacy 容量视图,Autoscaler 改读规范发现 保留 #370 的 Autoscaler 与其测试族(tests/utils/autoscaler/ 7 文件,本地 100+ 例通过)按 legacy 字段建立;改读规范发现属跨 PR 契约迁移,超出本 PR 集成范围,且 /engines 单端点同时服务两类客户端无重复状态。

测试的必要性与替代方案

范围必须保留的契约更简单的方案结论依据与限制
tests/components/test_genrm_scale_{endpoints,watcher}.py、tests/distributed/ray/test_genrm_scale_placement.py、tests/utils/test_genrm_scale_registry.py 四层分别覆盖 HTTP 端点包装、组件编排(watcher/registry 推进)、管理器放置数学、注册表状态机;调用方为本 PR 的 scale API 面 合并为单一套件或以集成测试替代分层单测 保留 本地逐文件复跑共 125 例加 5 子测试通过(46+11+22+36+5 子测试);第五轮 registry/watcher 增量保留分层并加强断言(registry 溢出限界后断言最旧键被驱逐、最新键可重放;watcher 注入点改为处理边界并断言 poll/sleep 次数),mock 边界不同、无重复夹具。
tests/backends/sglang/test_sglang_engine.py 注意力后端两条测试与 tests/inference/test_engine_contract.py 契约测试族 断言 GenRM server args 构建契约:全局 sglang_* 继承、探测优先级、角色默认不被覆盖、decode 不继承层级缓存 删除与实现不一致的测试,或保留依赖真实 SGLang 的旧测试 保留 bf354e7 恢复实现后本机 11/11 通过;contract 测试族以真实 dataclasses schema 执行生产构建器,31 例通过且不要求安装 SGLang(作者 macOS 无 SGLang 环境同过),消除原 importorskip 盲区;两条旧测试保留为真实 SGLang 环境的复核。
tests/utils/_dep_stubs.py 引擎导入桥与 tests/utils/test_dep_stubs.py 无重型依赖环境导入 relax.distributed.ray.genrm 的桥接;桥接仅在该导入期间可见,不得向同进程其他测试泄露可用引擎假象 保留常驻桩(原实现)或要求所有调用方自行清理 保留 原常驻桩使 sys.modules 与包属性长期持有仅含 SGLangEngine 的假模块,bf354e70 的 CI 即因后续 patch 解析到该桩而失败(tests/distributed/ray/test_scale_weight_sync_precheck.py 的 AttributeError);0e1b7228 以 try/finally 恢复两处绑定,test_dep_stubs 9 例覆盖存在/缺失四态与重试失败路径,消费方套件(scale_placement/endpoints/watcher)全部通过。
tests/components/test_genrm_engine_pick.py GenRM 副本引擎选择必须逐次消费规范发现快照的准入状态(state==ready 且 direct_eligible),空列表与不可路由模型返回 503 保留集成前缓存列表语义的旧断言 保留 旧断言在 36ee4ba 的 CI 中失败(SimpleNamespace 无 get_inference_snapshot),对应语义已被集成提交取代;重写后 17 例通过,含每轮取准入(fetches==12)、模型级状态门(sleeping/draining/onloading/failed/dead→503)、非 ingress 剔除与空列表 503。
Powered by Nyanpasu with glm-5.3-flash max, please check the suggestions carefully.

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已完成审查,有一项非阻塞的启动就绪问题,详见行级评论。

本地 CPU 契约测试为 91 通过、1 跳过;未发现需要阻塞合并的问题。GitHub 暂无 CI 检查记录,完整训练及多节点 GPU 验证未在本机复跑。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

complete
and group.lifecycle_status == EngineGroupLifecycle.ACTIVE
and not self._is_weight_updating
and self._policy_weights_ready.get(name, False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 优先级:P2

请在纯 fully-async 的首次权重同步成功后发布就绪状态。包含 Actor 的默认模型初始为 False,但 Controller 启动时调用的 Actor.update_weights_fully_async → MegatronTrainRayActor.update_weights_fully_async 只完成 DCS 传输,没有更新此标志;目前异步路径要等首次训练后的 /end_update_weight 才设为 True。因此首次同步已成功、引擎可用时,/rollout/generate、/rollout/v1/chat/completions 和新客户端仍会返回 503。建议在初始同步确认成功后解除门控,并补充“首次训练前即可通过网关生成”的回归测试;失败同步仍应保持不可用。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已确认在 4335eab 修复。Actor 在等待全部训练 worker 的初始异步同步成功后发布 Rollout 就绪状态;同步异常和 actor_fwd-only 分支不会发布。已核对启动调用链,并复跑 CPU 契约测试:94 通过、1 跳过。F1 已解决。

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查通过:此前的启动就绪问题已修复,本轮增量未发现新的审查问题。CPU 契约测试 94 通过、1 跳过(缺少 Ray);GitHub 暂无 CI 检查记录,本机未复跑多节点 GPU 验证。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

@Arazyu

Arazyu commented Sep 22, 2026

Copy link
Copy Markdown
Author

@SigureMo 任务已完成,请求 review。

@SigureMo SigureMo changed the title feat(inference): unify Rollout, GenRM, and Teacher service 【No.3】feat(inference): unify Rollout, GenRM, and Teacher service Sep 22, 2026

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新到达的 CI 结果确认了一项测试替身兼容性回归,详见行级评论;此前 F1 仍已解决。本次补充意见不要求阻塞合并。

Pre-commit 检查 也因 ruff-format、docformatter 修改文件而失败,需要应用格式化结果。GPU 检查仍在运行。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

await self._weight_update_ready.wait()

self.status = "running"
await self.rollout_manager.set_policy_weights_ready.remote(True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 优先级:P2

新增 RPC 后需要同步更新 tests/components/test_rollout_weight_update_handshake.py 的 _ManagerStub。它目前仅提供 health_monitoring_pause 和 set_weight_updating,因此现有 test_end_update_weight_does_not_block_after_failed_can_do 在此处抛出 AttributeError: '_ManagerStub' object has no attribute 'set_policy_weights_ready'。此提交的 Python 3.11 CI 已复现该失败(458 通过、47 跳过后停止)。请给替身补充可等待的就绪 RPC,并保留故障后恢复握手的原有断言;新增的 inference 契约测试没有覆盖这个旧测试调用链。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已确认 c519b19 修复 F2:测试替身补充了可等待的就绪 RPC,原有故障恢复断言保留。由于本机缺少 Ray,我提取生产方法并隔离 Ray 导入边界,执行该文件的 6 项握手测试,全部通过;CPU inference 契约测试另有 94 通过、1 跳过。完整 CI 仍需以新提交结果为准。

# 🐛 Bug Fix

## Keep weight readiness test doubles compatible

- Add the rollout readiness RPC to the handshake manager stub.
- Preserve failed synchronization behavior while allowing successful resume.

---

# 🎨 Style

## Apply required CI formatting

- Apply the repository's ruff and docformatter output to touched Python files.
@Arazyu

Arazyu commented Sep 22, 2026

Copy link
Copy Markdown
Author

@rai-studio-bot review

@Arazyu

Arazyu commented Sep 22, 2026

Copy link
Copy Markdown
Author

@SigureMo 不好意思,只验证了rai-studio-bot,忘记检查CI了,我先修复下CI错误

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查通过:F1、F2 均已解决,本轮其余变更仅为格式化,未发现新增问题。

CPU 契约测试 94 通过、1 跳过;隔离 Ray 导入边界后的 6 项握手测试通过。新提交暂未显示 CI 结果,本机未复跑多节点 GPU 验证。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

Comment thread docs/.vitepress/config.mts Outdated
{ text: 'Distributed Checkpoint', link: '/zh/guide/distributed-checkpoint' },
{ text: '健康检查管理器', link: '/zh/guide/health-check-manager' }
{ text: '健康检查管理器', link: '/zh/guide/health-check-manager' },
{ text: '统一推理服务验收记录', link: '/zh/guide/unified-inference-validation' }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先自己检查一下代码吧,比如这个应该是要提交上来的吗?

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复核当前提交 c519b19:与上次审查相同,F1、F2 仍已解决,未发现新增代码问题。

Pre-commit 已通过,Python 3.10–3.12 及 GPU 检查仍在运行。此前本地结果为 94 通过、1 跳过,以及隔离 Ray 导入后的 6 项握手测试通过,不能替代完整 CI。

还需回应维护者关于验收记录进入正式文档的意见,确认文档范围;此前代码审查通过不代表该意见已解决或 PR 已满足合并条件。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

# 🐛 Bug Fix

## Preserve legacy engine discovery and startup fixtures

- Keep `get_engines_info()` compatible with managers created without the unified inference manager.
- Update the startup cleanup fixture for the fully async weight-update arguments and metrics state.

---

# 📝 Documentation

## Keep the public inference API focused

- Remove internal acceptance reports and experiment details from the public API docs.
- Move shared inference links into the related lifecycle and placement sections.

---

# 🔩 Chore

## Remove private validation wrappers

- Delete one-off cluster scripts containing site-specific paths and runtime settings.
@Arazyu

Arazyu commented Sep 22, 2026

Copy link
Copy Markdown
Author

@rai-studio-bot

@rai-studio-bot rai-studio-bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮代码兼容性修复及文档清理未发现新增运行时问题;F1、F2 仍已解决。CPU 契约测试 94 通过、1 跳过,另有 4 项隔离的引擎信息兼容检查通过;当前提交 Pre-commit 已通过,Python/GPU CI 仍在运行,本机未复跑多节点 GPU 验证。

P3 优先级:P3 — 非行级:PR 描述。请同步更新 Acceptance evidence:其中仍列出已删除的中英文 guide/unified-inference-validation.md,并称 API 页面包含验收记录和复现信息,但这些段落也已移除。建议把验收结果及复现信息放在 PR 描述或可访问的附件中,删除失效的文件引用,并将剩余 API 页面说明改为接口与用法文档。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查通过:F3 已解决,PR 描述已移除失效引用,并准确说明 API 页面的用途。此前 F1、F2 仍已解决。

代码提交未变化,沿用此前验证结果;Pre-commit 已通过,Python/GPU CI 仍在运行。本审查结论不替代 CI 结果或维护者的合并决定。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

@Arazyu

Arazyu commented Sep 22, 2026

Copy link
Copy Markdown
Author

@rai-studio-bot

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查 375ed00a 通过:合并 main 后,算法注册与奖励处理、critic 放置及设备/权重同步接口未发现新增回归;此前 F1–F3 仍已解决。

推理契约测试 94 通过、1 跳过,另有 6 项隔离握手检查通过。Pre-commit 已通过,Python/GPU CI 仍在运行;本机缺少相应运行环境,未复跑多节点 GPU 验证。

Powered by Nyanpasu with gpt-6-astra medium, please check the suggestions carefully.

@Arazyu

Arazyu commented Sep 24, 2026

Copy link
Copy Markdown
Author

@SigureMo 任务已完成,请求 review。

Re-review P1: the three-state cleanup gate (UNKNOWN/False/True, missing
!= clean) treats every service status response without an explicit
cleanup_required as UNKNOWN, but that flag only existed in GenRM's
status contract. Rollout's ScaleOutStatusResponse and
ScaleInStatusResponse never declared it, so FastAPI's response_model
stripped the key from the wire and the shared autoscaler -- whose
default target is rollout -- read UNKNOWN for every rollout terminal
operation:

- terminal scale-out (ACTIVE/PARTIAL/FAILED/CANCELLED) and scale-in
  (COMPLETED/FAILED) stayed pending_requests forever;
- the next scaling evaluation stayed frozen ("in progress or awaiting
  cleanup") with no path to unblock;
- a removable rollout-contract target kept failing PATCH removal with
  409 (stale unresolved pending);
- history never recorded the finished operation.

Rollout has no deferred-cleanup lifecycle: a FAILED scale-out rolls its
engines back before reporting and a COMPLETED scale-in reports the
engines removed, so terminal status is cleanup-complete by contract.
The fix therefore makes the rollout status models state that explicitly
(cleanup_required: bool = False) instead of leaving the flag absent.
GenRM's semantics are unchanged: a GenRM POST reply still proves
nothing, a missing/malformed flag still reads UNKNOWN, terminal-dirty
still requires status/reconcile, and finalization still requires an
authoritative cleanup_required is False.

Coverage:
- response-model serialization tests pin model_dump()["cleanup_required"]
  is False for both scale-out and scale-in wire shapes (the response-
  model tests now import the component through tests.utils._dep_stubs
  so they actually run where transfer_queue is absent);
- shared-autoscaler regressions drive a real AutoscalerService against
  a fake speaking the rollout HTTP contract through the actual Pydantic
  response models: scale-out and scale-in terminal requests finalize
  into history, the next decision is no longer blocked, and a finalized
  target no longer 409s on removal;
- the fail-closed guard stays pinned: a rollout-contract response with
  the flag dropped (pre-fix wire shape) keeps the request pending and
  the decision frozen -- the fix lives in the contract, never in the
  autoscaler defaulting missing to clean.
…ic probe declines

Re-review P2: _compute_genrm_server_args pinned attention_backend
unconditionally -- including the architecture probe's None -- so the
sglang_* inheritance loop (which backfills only fields absent from
kwargs) could never apply the user's global --sglang-attention-backend
to a GenRM engine again. The docstring's "falls back to SGLang default"
only held for SGLang's internal default; the relax-level global flag
was silently disabled by 5c1e2e7.

The deterministic backend is now pinned only when the user has not
chosen one globally:

- explicit --sglang-attention-backend wins over the probe (restores the
  pre-5c1e2e7 inheritance behaviour);
- a failed probe defers to SGLang's default instead of pinning None
  over it (and over the user's global choice);
- the arch-appropriate deterministic backend (fa3 on pre-Blackwell,
  flashinfer on Blackwell+, radix cache preserved) is still pinned when
  the user set nothing, keeping the final-code autoscaler acceptance
  behaviour on this machine;
- per-instance --genrm-engine-config overrides still take priority over
  both (applied after the loop).

Regressions:
- an explicit global choice beats the probe result;
- a failed probe pins nothing (key absent, SGLang default applies) while
  the user's global choice still flows through the inheritance loop.
The module-level transfer_queue attribute guard (added with the rollout
contract stub support) places two imports after executable code; ruff's
E402 fires on the pushed tree and would fail the Pre-commit workflow.
Annotate both imports as guarded.
…tion PASS, r5 proxy incident, train-continuity reanalysis v2)

Evidence-branch pointer update only; no product change. Raw artifacts live on
the evidence branch @ d88d6c7 (r6/r4 verdict trees, the archived raw job log
with sha256, and the reanalysis v2 script + parser tests).
…ons table

Per review: the top of the file still pointed at evidence 6b501a2 and called
5c1e2e7 the newest acceptance code while the bottom appended 0481701
reconfirmations — an index that contradicted itself. The top is now the only
current-conclusions table: one row per official criterion, each bound to the
exact product SHA, the producing run and its raw inputs on evidence 66f1f78,
with an explicit superseded-by column. Reading rules state the caliber of
each claim (0/50 = these 50 inputs under this config; GenRM-path-only weight
sync; criterion 5 is continuity, no performance claim absent a control run;
content-deterministic semantics pending maintainer acceptance). A scope
commitments table separates delivered / not-implemented / to-be-negotiated
(cross-Gateway wording now 'not implemented this phase; interface and
responsibility to be negotiated'). The per-run history below is marked as
historical detail and keeps its own producing commits.
- docs/en/api/genrm.md + docs/zh/api/genrm.md: endpoints table, request/
  status contract, NOOP/idempotency semantics, scale-out/in state chains
  with terminal sets, cleanup_required and capacity fields (current/ready/
  occupied/pending_cleanup), strict-capacity 503 and fallback semantics
- docs/public/openapi/genrm.json: regenerate via scripts/tools/
  generate_openapi.py; 10 paths, 9 schemas, descriptions from code
  docstrings
- scripts/tools/generate_openapi.py: write trailing newline so reruns are
  byte-stable

Verified against relax/components/genrm.py, relax/utils/genrm_scale_registry.py
and relax/distributed/ray/genrm.py: every documented route, state, terminal
set, capacity formula and error code matches the implementation.
- docs/public/openapi/rollout.json: add cleanup_required (bool) to
  ScaleOutStatusResponse and ScaleInStatusResponse properties — manual
  patch in generator-faithful style (type + title, not in required),
  avoiding the unrelated /predict drift a full regeneration would bring
- docs/en/api/rollout.md + docs/zh/api/rollout.md: new 'Scale status
  cleanup contract' section (bilingual semantic parity) documenting the
  three-state contract shared with the Autoscaler (true = cleanup still
  pending; false = authoritative complete; absent = unknown, missing !=
  clean) and why rollout terminal states report false (scale-out engines
  serve or were rolled back; scale-in COMPLETED removed / FAILED rolled
  back)

Docs-only; no product code touched.
# 📝 Documentation

- Point the two evidence index links to the reviewed fdf288d snapshot.
- Leave product code, historical verdicts and experiment versions unchanged.
- Keep this commit local; the public PR head and its CI remain unchanged.
# 📝 Documentation

- Withdraw whole-run zero-error and stall-bound claims using reanalysis v2.1.
- Distinguish log-reported sample counts from file-level sample verification.
- Keep original verdicts and producing versions; mark superseded interpretations.
- Correct the long-request drain description and completed reconfirmation status.
- Preserve product code, GPU results and public PR history.
@SigureMo

SigureMo commented Oct 8, 2026

Copy link
Copy Markdown
Member

辛苦解决下冲突~

@Arazyu

Arazyu commented Oct 8, 2026

Copy link
Copy Markdown
Author

辛苦解决下冲突~

好的,我尽快修改

Merge main at 7c4e537 while preserving nonblocking rollout manager binding
and initial weight synchronization. Apply the upstream offline-mode guard
so SFT, DPO, and RM continue to skip startup weight updates.

Retain the English and Chinese unified inference navigation entries using
the current main formatting. Extend startup regression coverage across
online/offline loss modes and synchronous, fully asynchronous, and hybrid
execution.

Validation: selected CPU regressions passed (110 passed, 1 skipped,
2 deselected); all pre-commit hooks passed. Full Ray and multi-node GPU
validation was not rerun in the local environment.

Refs redai-studio#71
@Arazyu
Arazyu requested a review from a team October 11, 2026 07:13
@rai-studio-bot

rai-studio-bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for contributing to Relax, @Arazyu! 感谢你为 Relax 做出贡献!

📚 Contribution guide / 贡献指南

Describe the problem, your changes, and how you validated them. Keep each PR focused and run pre-commit run --all-files before submitting.

请说明问题、改动和验证方式,保持 PR 聚焦,并在提交前运行 pre-commit run --all-files。

English contribution guide · 中文贡献指南

🛠️ CI commands / CI 指令
Command / 指令 Usage / 用途
/rerun Retry failed CI / 重跑失败的 CI
/rerun <target> Rerun a workflow or check / 重跑指定 workflow 或检查
/cancel <workflow> Cancel an entire workflow / 取消整个 workflow
/help Show commands and targets / 查看指令和 target
/review Request a code review / 请求代码 review

Put one command on the first line of a new PR comment. Rerun/cancel require PR authorship or repository write access.

在新 PR 评论的首行写一条指令。PR 作者或有仓库写权限的贡献者可以重跑、取消 CI。

CI usage and targets · CI 用法与 target

🔎 Merge requirements / 合入条件

GitHub:⏳ 合入条件未满足

Requirement / 条件 Status / 状态
审批人数 ❌ 0/1 · 至少 1 位有仓库 write 或更高权限的人 Approve · 处理修改意见后请重新审批:SigureMo
团队审批(relax-block-reviewers) ⏳ 0/1 · 可联系:Aurelius84, Yangruipis, yuanlehome, SigureMo, NINGBENZHE
CI ✅ 已通过

@Arazyu

Arazyu commented Oct 11, 2026

Copy link
Copy Markdown
Author

/review

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查结论:通过(904b4b87)

冲突解决提交已逐项核对:57 个变更文件中 48 个与本轮已通过的 375ed00 的 PR diff 字节一致;其余 9 个文件中,docs/.vitepress/config.mts 保留统一推理中英双导航入口,relax/components/actor.py 将 main 的 SFT/DPO/RM offline-mode 守卫(is_offline_mode)并入本 PR 的非阻塞启动同步结构,配套启动测试改用真实守卫并把参数化扩到 12 组,其余仅行号偏移。F1–F3 的修复在新头均保留;本地 104 项 inference 契约测试与 15 项握手/运行时测试通过,该提交 CI 全绿。多节点 GPU 验证未在本机复跑,沿用 PR 描述中的验收记录。

看板:nyanpasu-review

说明:当前合并因维护者此前的 changes-requested 决定而阻塞;其中验收记录页的意见已由该页移除落实,是否放行由维护者复核决定。

Powered by Nyanpasu with glm-5.3-flash max, please check the suggestions carefully.

The NPU provider copies runtime arguments into the Bridge model config.
The inference placement plan contains frozen dataclasses, which the NPU
image's older Bridge sanitizer tries to rebuild with setattr during the
initial weight export, raising FrozenInstanceError on the role field.

Keep the placement plan on the runtime args and exclude it from the model
config. Preserve the other NPU argument copies and existing provider
overrides. Add GPU/NPU provider regressions that retain the original plan.

Validation: the NPU regression fails before the fix; the provider and
inference suites pass afterward (123 passed, 1 skipped because Ray is
unavailable). All pre-commit hooks pass. Real NPU validation remains with
the integration CI.

Refs redai-studio#71
@Arazyu

Arazyu commented Oct 11, 2026

Copy link
Copy Markdown
Author

/review

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查结论:通过(9eec00a1)

新提交相对上轮已通过的 904b4b8 仅新增两个文件(+25 行):relax/backends/megatron/model_provider.py 在 NPU 分支整体拷贝 vars(args) 时排除运行时放置计划 _inference_placement,配套回归测试用真实 PlacementPlanner 构造放置计划并参数化 NPU 可用性。已核对该字段唯一写入方为 relax/inference/placement.py:171,NPU 拷贝循环是唯一会把该 frozen dataclass 计划带上 provider(随后被整体 pickle)的路径;排除后 args 仍持有计划供运行时消费,无其他泄漏面。本地 20 项 provider 测试与 104 项 inference 契约测试通过,该提交 CI 全绿。其余 57 个变更文件与上轮已通过内容一致,结论沿用;F1–F3 修复均保留。多节点 GPU 验证未在本机复跑,沿用 PR 描述中的验收记录。

看板:nyanpasu-review

说明:当前合并因维护者此前的 changes-requested 决定而阻塞;其中验收记录页的意见已由该页移除落实,是否放行由维护者复核决定。

Powered by Nyanpasu with glm-5.3-flash max, please check the suggestions carefully.

Merge the GenRM elasticity implementation with the unified inference
service. Preserve legacy generation, sampling and attribution through the
gateway, count raw and streaming requests during drain, and bind closed
admission to engine identities so recovered engines may reuse endpoints.

Use the same published engine states for discovery and legacy routing.
Preserve split placement offsets, retain owned placement groups until Ray
confirms removal, and recreate elastic placements during engine recovery.
Exclude retired slots from recovery and keep failed cleanup retryable.

Reject deferred, training-offload and multi-GPU elastic layouts before
taking the lifecycle lock or allocating resources. Document the supported
scope in both languages and regenerate the GenRM API schema.

Validation: focused CPU suite 426 passed, 4 optional-dependency skips;
latest lifecycle/gateway regression rerun 34 passed (overlaps that suite);
additional contract tests 12 passed, 17 optional-dependency skips.
All pre-commit hooks and the VitePress documentation build passed.
Real SGLang and multi-node GPU execution were not rerun on this CPU host.

Refs redai-studio#71, redai-studio#351, redai-studio#356, redai-studio#370
@Arazyu

Arazyu commented Oct 11, 2026

Copy link
Copy Markdown
Author

/review

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查结论:有一项非阻塞回归(P2)

本轮增量是提交 36ee4ba 把 #370 的 GenRM 弹性扩缩容并入本 PR。已逐块核对集成提交对网关、放置与 Teacher 共享语义的兼容改造:legacy /generate 与网关原生请求共用同一 in-flight 计数与 drain 证明命名空间;生命周期操作通过非阻塞 _exclusive_lifecycle 与弹性扩缩容互斥,发现快照不持转移锁、扩缩容期间发现服务仍可用;弹性 PG 保留至 Ray 确认 REMOVED,失败清理保持 fail-closed 并可重试。本地 CPU 套件 330 例:328 通过、2 失败,失败项即下方行级评论的 P2——并入的 #370 测试断言 GenRM 继承全局 sglang_* 参数,而该继承循环在本 PR 早期提交中已从 _compute_genrm_server_args 删除;CI 环境缺少真实 sglang 而跳过这两条测试,未能暴露。F1–F3 修复均保留;#370 引入的弹性扩缩容本体沿其在 #370 的审查讨论评估,此处不复述。

看板:nyanpasu-review

说明:多节点 GPU 与真实 SGLang 运行未在本机复跑,沿用 PR 描述披露的验收边界;当前合并因维护者此前的 changes-requested 决定而阻塞,是否放行由维护者复核决定。

Powered by Nyanpasu with glm-5.3-flash max, please check the suggestions carefully.

# (re-review finding). A failed probe defers to SGLang's default instead
# of pinning ``None`` over it; per-instance ``--genrm-engine-config``
# overrides still take priority over both (applied after the loop).
if getattr(args, "sglang_attention_backend", None) is None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium severity P2 · 恢复 GenRM 对全局 sglang_ 参数的继承*

合并基线(7c4e5371)的 _compute_genrm_server_args 内含 sglang_* 继承循环;本 PR 在 a3bbb30 删除了其中两行(if hasattr(args, f"sglang_{attr.name}") and attr.name not in kwargs: 及其赋值,见 hunk @@ -1632,8 +1699,6),而 #370 并入时新增的注释("the sglang_* inheritance loop below backfills only fields absent from kwargs … (applied after the loop)")与两条测试仍按该循环存在来断言。

本地装有真实 sglang 0.5.17 的环境复跑 tests/backends/sglang/test_sglang_engine.py:test_genrm_attention_backend_respects_global_user_choice 与 test_genrm_attention_backend_probe_failure_defers_to_global_and_default 均失败(用户显式 sglang_attention_backend 未出现在 kwargs);CI 环境因缺少真实 sglang 由 importorskip 跳过,故未能暴露。rollout 侧 _compute_server_args 的同名循环保留完好,两侧行为已分叉。

影响:用户显式 --sglang-attention-backend(以及其他未在 kwargs 显式计算的全局 sglang_* 项)对 GenRM 引擎静默失效;此时确定性推理落到 SGLang 通用默认后端,即上方注释所述 radix cache 被禁、48 路并发评分预填楔死场景的入口。

建议:恢复 genrm 函数内被删的两行继承循环(保留当前 guard "仅在用户未显式选择时探测" 的语义),或在文档中明确 GenRM 不继承全局 sglang_* 并同步修正此注释与两条测试;修改 relax/utils/arguments.py 或后端参数语义需按仓库约定先征求维护者确认。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已在 bf354e7 确认修复:`compute_genrm_server_args` 恢复了被删的两行 `sglang*` 继承循环,与合并基线 1632–1637 行逐字节一致(rollout 侧同构,两侧行为不再分叉)。原先两条依赖真实 SGLang 的测试恢复通过,且 tests/inference/test_engine_contract.py 已改用真实 dataclasses schema 直接执行生产构建器(31 例通过,不要求安装 SGLang),原先 CI 因 `importorskip` 跳过而无法暴露此回归的盲区随之消除。另:bf354e70 的 CPU 测试失败源于 `_dep_stubs` 导入桥的桩模块泄漏污染 `sys.modules`,已在 0e1b722 隔离修复,与本条发现无关。

Exercise canonical discovery on every engine pick while preserving round-robin, recovery and lifecycle admission coverage. Inject watcher failures at the processing boundary and test repeated registry eviction with small caps instead of long waits and large scans.

Validation: 444 passed, 4 dependency skips in focused CPU regressions; 36 registry tests passed after strengthening protected-record eviction coverage; all pre-commit hooks passed.
Backfill supported global SGLang fields without replacing GenRM role defaults, then apply per-model overrides. Add CPU-only builder regressions for attention precedence, memory tuning, static-model defaults and the decode cache exclusion so missing SGLang cannot hide this regression.

Validation: 31 engine contract tests passed; 454 focused tests passed with 4 dependency skips; all pre-commit hooks passed.
Restore both the SGLang engine module cache entry and its parent-package attribute after importing the GenRM manager, including failed imports. This prevents later CPU tests from mistaking a dependency bridge for an installed engine runtime.

Validation: 9 import-isolation regressions passed; ordered manager/precheck regression passed 31 tests with 20 missing-SGLang skips; all pre-commit hooks passed before this commit.
@Arazyu

Arazyu commented Oct 11, 2026

Copy link
Copy Markdown
Author

/review

@rai-studio-bot rai-studio-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复查结论:通过(APPROVE)

本轮增量(36ee4ba8..0e1b722,三笔提交)均已逐项核实:79d98456 将 engine-pick 回归测试改写为按规范发现快照逐次取准入——旧断言对应集成前的缓存列表语义,且该头 36ee4ba 的 CI 失败(get_inference_snapshot 缺失)证实其已失效,watcher 测试改为在处理边界注入异常并断言 poll/sleep 次数,registry 洪水测试限界后覆盖等价并加强驱逐断言;bf354e70 恢复 _compute_genrm_server_args 对全局 sglang_* 的继承(与合并基线 1632–1637 行逐字节一致,rollout 侧同构),F4 随之解决,契约测试改用真实 dataclasses schema,不安装 SGLang 即可执行,消除了原先 importorskip 造成的 CI 盲区;0e1b7228 以 try/finally 恢复 _dep_stubs 引擎导入桥的 sys.modules 与包属性绑定,修复了 bf354e7 CPU 测试失败的模块缓存污染机制。本地逐文件复跑共 224 例加 5 子测试全部通过;bf354e70 的 GPU Unit Tests 与 Integration Tests(Qwen3-4B 4GPU/2GPU/4NPU)经 GitHub API 核实成功,该头与本头仅差测试文件。当前头的 CPU Tests 因 bypass 门未开尚未运行,待其完成后如有失败由后续跟进处理。说明:上轮在 36ee4ba 发布时该头 CI 已有 engine-pick 旧测试失败而未及时纳入结论,本轮已核对并确认由 79d9845 修复;多节点 GPU 完整训练流程未在本机复跑,沿用 PR 描述披露的验收边界。

看板:nyanpasu-review

Powered by Nyanpasu with glm-5.3-flash max, please check the suggestions carefully.

@Arazyu

Arazyu commented Oct 11, 2026

Copy link
Copy Markdown
Author

辛苦解决下冲突~

已解决冲突

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants