Model-Optimizer 评估运行指南:基于 nemo-evaluator-launcher 的 INPUT → EXPLORE → ACT 三阶段实践
Model-Optimizer 评估运行指南:基于 nemo-evaluator-launcher 的 INPUT → EXPLORE → ACT 三阶段实践
导读
本文围绕 nemo-evaluator-launcher(简称 NEL)展开,讲解如何在 Model-Optimizer 仓库中通过一条 uv run nemo-evaluator-launcher run --config <path.yaml> 命令,将 LLM 评估任务提交到 Slurm 集群上运行。文章以仓库内 launching-evals 技能 中定义的 INPUT → EXPLORE → ACT 三阶段工作流为主线,完整覆盖从收集配置、预检解析到提交运行的每一步操作,并结合同技能下的进度监控、失败调试与结果分析文档,给出可立即照做的命令与排查清单。读完本文,你将能独立完成一次评估任务的配置确认、干跑预检、正式提交、状态轮询与结果拉取。
1. 评估运行的整体工作流
在 Model-Optimizer 仓库的 launching-evals 技能中,评估运行被组织为一个必须按顺序执行的全流程:
- 使用
nel-assistant技能创建或修改评估配置;若用户提供了历史运行,则以该次运行的config.yml产物作为起点; - 运行评估(执行本文所述的 INPUT → EXPLORE → ACT 三阶段,见 run-evaluation.md);
- 监控进度(每次
nel run之后强制执行):反复轮询状态直至SUCCESS或FAILED,见 check-progress.md; - 到达终态后的处理:
SUCCESS时分析结果(见 analyze-results.md),FAILED时调试失败运行(见 debug-failed-runs.md)。
本仓库中,launching-evals 的定位是“运行、监控、分析、调试评估”,它不负责创建或修改评估配置——配置的增删改由 nel-assistant 类技能负责,这一点在技能描述中明确标注。
2. INPUT:收集运行需求
运行评估前,先以清单方式从用户处收集四项输入(对应 run-evaluation.md 的 Phase 1):
- Config path(必填):要运行的 YAML 配置文件路径。注意,如果上一步骤已经处理过该配置,路径可能已存在于上下文中,无需重复询问。
- Credentials(按需):部分任务需要环境变量(如
AWS_ACCESS_KEY_ID、HF_TOKEN)。先检查工作区根目录是否存在.env文件;若不存在,请用户创建并写入凭据。NEL 会自动从工作区根目录读取.env,因此不需要手动 source。 - Task filter(可选):通过
-t <task_name>只运行指定任务。 - Overrides(可选):通过
-o key=value覆盖配置项。 - Dry-run first?(可选):是否先用
--dry-run预览解析后的配置与 sbatch 脚本,再正式提交。
一个完整的收集结果示例:config=examples/eval_config.yaml、无凭据需求、-t swebench-verified、无覆盖项、先干跑。
3. EXPLORE:干跑预检解析结果
进入第二阶段后,核心动作是把 --dry-run 标志加到最终命令上,预览两样东西:
- 解析后的完整配置(resolved config):即 YAML 合并所有继承、默认值与
-o覆盖之后的最终形态; - sbatch 脚本:NEL 将据此向 Slurm 提交的作业脚本内容。
uv run nemo-evaluator-launcher run --config <path.yaml> --dry-run
干跑的价值在于把错误前置:未填写的必填字段(MissingMandatoryValue,即未填充的 ???)、类型不匹配(ValidationError)、YAML 语法错误(ScannerError)都可以在这一步被捕获,而不必等到提交到集群后才失败(见 debug-failed-runs.md 的 Config validation 一节)。
4. ACT:提交评估任务
4.1 基本提交命令
确认干跑结果无误后,正式提交:
uv run nemo-evaluator-launcher run --config <path.yaml>
4.2 常用变体
| 场景 | 命令 |
|---|---|
| 只跑单个任务 | uv run nemo-evaluator-launcher run --config <path.yaml> -t <a_single_task_to_be_run_by_name> |
| 跑多个指定任务 | uv run nemo-evaluator-launcher run --config <path.yaml> -t <task_name_1> -t <task_name_2> ... |
| 覆盖采样数等参数 | uv run nemo-evaluator-launcher run --config <path.yaml> -o evaluation.nemo_evaluator_config.config.params.limit_samples=10 ... |
| 干跑预览 | uv run nemo-evaluator-launcher run --config <path.yaml> --dry-run |
注意 -o 覆盖使用的是 Hydra 风格的 ++ 语法:例如验证修复后的小样本冒烟测试写作 -o ++evaluation.nemo_evaluator_config.config.params.limit_samples=10。
4.3 提交后的必做动作
提交命令会打印 Invocation ID: <id>,这是后续所有监控与排查的锚点。每次 nel run 之后必须轮询状态,直到出现 SUCCESS 或 FAILED(技能将监控设为强制步骤)。轮询命令:
uv run nemo-evaluator-launcher status <invocation_id> --json
--json 用于机器可读输出。需要更详细信息(输出路径、Slurm 作业 ID、集群主机名等)时使用:
uv run nemo-evaluator-launcher info <invocation_id>
4.4 提交前必须知道的三个关键事实
- Slurm 作业对(job pairs):NEL 会提交一对 Slurm 作业——一个 RUNNING 作业加一个 PENDING 的重启作业(用于 4 小时 walltime 到期后自动续跑)。不要取消 PENDING 重启作业,它们是预期且必需的。
data_parallel_size是按节点计的:dp_size=1配合num_nodes=8意味着总共 8 个模型实例(每节点一个),由 haproxy 负载均衡,不要把dp_size理解为全局副本数。- HF 离线缓存要求:配置了
HF_HUB_OFFLINE=1的 config 需要模型已预下载到各集群的 HF 缓存中。在新集群上运行模型前,务必先询问用户该模型是否已缓存。若未缓存,在集群登录节点执行:
python3 -m venv hf_cli && source hf_cli/bin/activate && pip install huggingface_hub
HF_HOME=<your_hf_cache_path> hf download <model>
在 lustre 风格的 HPC 集群上,缓存路径通常在 /lustre/.../<group>/users/<username>/cache/huggingface 下。缺少该步骤时 vLLM 会以 LocalEntryNotFoundError 失败。
5. 运行中的状态机:RUNNING / SUCCESS / FAILED 分支
提交完成后进入监控阶段(check-progress.md),按状态分流:
- 获取状态与任务名:
status <invocation_id> --json; - 查基准专属文档:在
references/benchmarks/下寻找与任务名匹配的文档(如terminal-bench-*任务对应terminal-bench-general-info.md),这些文档包含监控命令与基准特有上下文; - 从配置取输出路径:
info <invocation_id>得到output_dir与集群主机名。
然后:
- RUNNING:SSH 到集群查看
client-*.log中的实时进度(优先使用基准文档中的监控命令); - SUCCESS:转入结果分析(analyze-results.md);
- FAILED:转入失败调试(debug-failed-runs.md)。
仓库内的测试用例(tests.json)对状态语义做了额外约束:RUNNING 只表示 Slurm 作业在运行,不代表 vLLM 服务器已成功启动;且诊断根因时必须同时查看 client 日志与 server 日志——client 日志常只呈现症状(如 unknown_agent_error、failed_samples_policy),而 server 日志才揭示真正原因(如 CUDA OOM、上下文长度溢出、vLLM 校验错误)。
6. 失败运行的五步调试清单
当状态为 FAILED 时,按 debug-failed-runs.md 执行:
Step 1 收集信息:失败运行的 Invocation ID,以及用户观察到的症状(超时、OOM 等)。
Step 2 获取作业信息:
uv run nemo-evaluator-launcher status <invocation_id> --json
uv run nemo-evaluator-launcher info <invocation_id>
从中提取状态、日志远程路径、Slurm 作业 ID、集群登录主机名。
Step 3 本地复制并检查日志:优先把需要的日志复制到本地再分析(每次 SSH 命令都需要用户批准,远程逐条读取会打断流程,而复制过多又太慢):
uv run nemo-evaluator-launcher info <invocation_id> --copy-logs /tmp/debug-logs
LOGS=/tmp/debug-logs/<job_id>/logs
cat $LOGS/slurm-*.log # 作业级错误:调度、walltime、抢占
tail -200 $LOGS/server-*-0.log # 部署错误:OOM、缺模型、坏参数、驱动不匹配
grep -i -E '(error|exception|failed|OOM|killed)' $LOGS/server-*-0.log | tail -50
cat $LOGS/proxy-*.log 2>/dev/null # 负载均衡错误(仅多实例时存在)
tail -200 $LOGS/client-*.log # 评估错误:数据集、评分器、超时、限流
四类日志的职责边界:slurm-*.log 覆盖作业级错误(健康检查超时、账号/分区错误、walltime 超限、抢占);server-*-N.log 覆盖部署错误(CUDA OOM、缺失模型/检查点、坏的 extra_args、GPU 驱动不匹配、镜像拉取失败);proxy-*.log 是 HAProxy 负载均衡器错误;client-*.log 覆盖评估错误(数据集访问、评分器错误、超时、限流)。
Step 4 应用修复(常见修复对照):
| 症状 | 修复 |
|---|---|
| CUDA OOM | 增大 deployment.tensor_parallel_size 跨更多 GPU 分片;多节点时增大 execution.num_nodes 并设置 deployment.pipeline_parallel_size;最后手段是在 deployment.extra_args 加 --max-model-len <lower_value>。不要把量化当作首选修复,应优先扩展算力 |
| 缺失模型/检查点 | FileNotFoundError/RepositoryNotFoundError/GatedRepoError: 403 —— 核对 deployment.checkpoint_path 或 deployment.hf_model_handle;门控模型在 deployment.env_vars 设置 HF_TOKEN |
坏的 extra_args |
unrecognized arguments/unexpected keyword argument —— 对照部署引擎版本检查参数(例如 --rope-scaling 在 vLLM > 0.11.0 中已移除) |
| 镜像拉取失败 | manifest not found/pyxis: child 1 failed —— 核实镜像 tag 存在;本地 GitLab 仓库需去掉 URL 中的端口后缀(如 :5005) |
| GPU 驱动不匹配 | CUDA driver version is insufficient —— 换用与宿主机 CUDA 驱动匹配的旧版容器镜像 |
| 健康检查超时/连接拒绝 | 服务未启动——先查 server 日志;增大 execution.endpoint_readiness_timeout(秒),Slurm 默认 null(回退到 walltime) |
| 评估中途服务器崩溃 | Connection reset by peer —— 查 server 日志是否 OOM;降低 parallelism(并发请求数);查 Slurm 日志是否抢占或 walltime 超限 |
| 缺失数据集 | DatasetNotFoundError/GatedRepoError: 403 —— 在 HuggingFace 接受许可,在 evaluation[].env_vars 设置 HF_TOKEN |
| 评分器错误 | ScorerError/KeyError —— 检查模型输出格式、adapter_config、max_new_tokens |
| 超时 | TimeoutError/Request timed out —— 增大 evaluation[].nemo_evaluator_config.config.params.request_timeout;过载时降低 max_new_tokens 或 parallelism |
| 配置校验失败 | MissingMandatoryValue/ValidationError/ScannerError —— 先跑 --dry-run 前置捕获 |
| Walltime 超限 | CANCELLED DUE TO TIME LIMIT —— NEL 的重启作业对会自动续跑,这通常是预期行为而非失败;仅当跨重启仍无进展时才增大 execution.walltime |
| 抢占 | CANCELLED DUE TO PREEMPTION —— 重启作业对应自动续跑;若无,改用不可抢占分区或重跑 |
| 容器找不到 | 同时适用于 deployment.image 与任务级 eval 容器;本地 GitLab 仓库去掉 URL 端口后缀 |
Step 5 验证修复,按序执行四条命令:
# 1. 干跑(只校验配置不运行)
uv run nemo-evaluator-launcher run --config <config> --dry-run
# 2. 冒烟测试(10 个样本)
uv run nemo-evaluator-launcher run --config <config> -o ++evaluation.nemo_evaluator_config.config.params.limit_samples=10
# 3. 只跑失败的那一个任务
uv run nemo-evaluator-launcher run --config <config> -t <failed_task> -o ++evaluation.nemo_evaluator_config.config.params.limit_samples=10
# 4. 监控
uv run nemo-evaluator-launcher status <new_invocation_id> --json
正确性警告:部分修复手段会改变评估结果——--max-model-len 限制上下文窗口可能截断提示词,temperature 影响采样随机性,top_p 是核采样阈值,max_new_tokens 过低会截断输出。因此在量化对比等场景中,必须用相同基准版本、任务配置、服务参数、token 限制与基础设施,差异才可归因于量化本身(见 analyze-results.md 的 Model baseline comparison 一节)。
7. 结果拉取与产物管理
运行成功后,产物按 Invocation ID 组织。核心原则:先用 nel info 发现路径——产物若在本地直接读取,若在远端则 SSH 探索后仅 rsync 所需内容。
# 快速复制日志(调试用,速度快)
uv run nemo-evaluator-launcher info <invocation_id> --copy-logs ./evaluation-results/
# 远端产物按需同步
rsync -avzP <user>@<hostname>:<artifacts_path>/{results.yml,eval_factory_metrics.json,config.yml} ./evaluation-results/<invocation_id>.<job_index>/artifacts/
技能文档特别警告:不要使用 nemo-evaluator-launcher export --dest local——它只写出汇总 JSON(processed_results.json),即使接受 --copy_logs/--copy-artifacts 标志也不会真正复制日志或产物。nel info --copy-artifacts 虽然可用,但对大型基准会复制所有内容(非常慢)。标准产物之外,基准还会在子目录产生额外产物,需主动探索。其他常用命令还包括:resume <invocation_id> 重新调度失败/中断运行(在原运行目录重新提交已有的 run.sub)、ls runs --since 1d 列出近期运行、ls tasks(以及 --from_container nvcr.io/nvidia/eval-factory/simple-evals:26.03 按容器列出任务)。
8. 基准专项:SWE-bench 与 Terminal Bench 的进度与产物要点
8.1 SWE-bench(OpenHands harness)
- 快速取分:
artifacts/results.yml、artifacts/.../swebench_summary.json;官方逐实例结果看artifacts/.../output.report.json(顶层键含dataset、evaluation_method、resolved、resolved_count、results、total_instances,每行results含instance_id、resolved、error、exit_code);逐实例 token 与调试数据看output.jsonl/output_errors.jsonl/logs/instance_<id>.log。 - 实时进度:运行期间官方结果文件尚未生成,应使用增量写入的
tasks.jsonl。该文件是 append-only 的,重启后同一task_id可多次出现,行数会超过基准规模——必须按task_id去重(最后一条生效)。技能提供了内置去重脚本(见 swebench-general-info.md),输出形如success: 120, TOTAL unique: 123/500, REMAINING: 377。 - 状态语义:
tasks.jsonl顶层的success表示最终官方评测判定已解决;failure表示有可评估补丁但未解决;error表示硬性运行时失败(超时、上下文超限等)。termination.reason=status=stuck只是对话结束态(OpenHands 检测到无进展模式),SWE-bench 仍可能收集补丁并最终判定为success或failure。
8.2 Terminal Bench(agentic 终端任务)
- 产物结构:
artifacts/terminal-bench/下的tb.lock(完整解析后配置,最佳复现依据)、run_metadata.json、task_status.json(每任务一条,success具有粘性——任务成功后后续失败不会覆盖)、tb_results.json(最丰富的单个产物,逐 trial 含is_resolved、failure_mode、token 用量、trajectory_length、时间戳、asciinemarecording_path,聚合含pass_at_k、accuracy、failure_mode_counts等)。逐 trial 子目录artifacts/terminal-bench/<task>/<trial>/下还有 agent 日志agent-logs/episode-N/(prompt.txt、response.txt、含思维链的debug.json)和终端快照panes/(pre-agent.txt、post-agent.txt、post-test.txt)。 - 失败模式枚举(见
failure_mode.py):UNSOLVED、TOKEN_LIMIT_EXCEEDED、PARSE_ERROR、FATAL_LLM_PARSE_ERROR、CONTEXT_LENGTH_EXCEEDED、OUTPUT_LENGTH_EXCEEDED、TEST_TIMEOUT、AGENT_TIMEOUT、UNKNOWN_AGENT_ERROR、AGENT_INSTALLATION_FAILED、UNKNOWN。failed_samples_policy默认default,只对“不公平失败”(UNKNOWN、UNKNOWN_AGENT_ERROR、AGENT_INSTALLATION_FAILED)停跑。 - 缓解 agent 超时:高
AGENT_TIMEOUT率(85%+)源于推理争抢。推荐组合拳——把一次n_samples: 8, parallelism: 100的大运行拆成 8 个n_samples: 1, parallelism: 24的独立单样本运行,水平扩展多个小作业(8x1 模式)。监控client-*.log时因其含 ANSI 格式化内容,需用grep -a。
9. 与仓库整体评估体系的衔接
launching-evals 并非孤立存在。在同一仓库的 evaluation 技能 及其 references/launcher-workflow.md、references/slurm.md 中,可以看到 NEL 在更大评估管线中的位置——包括按 Slurm 账号/项目组合码(PPP,即 cluster_config.yaml 的 account 字段)组织任务、payload_modifier 拦截器(通过 params_to_remove 列表如 <a href="https://link.gitcode.com/i/343351bcae65114b0efe4e7340d5a02b" target="_blank">max_tokens, max_completion_tokens] 剥离输出长度限制,让推理模型按需长思考)等机制。对评估结果感兴趣时,还可结合本仓库的 [llm_eval 示例(mmlu.py、lm_eval_hf.py、lm_eval_trtllm.py、simple_evals.py)了解非 NEL 路径下的轻量评估方式。
结语
运行一次可靠的 LLM 评估并不复杂,关键在于流程纪律:INPUT 阶段把配置、凭据、任务过滤与覆盖项收集齐;EXPLORE 阶段用 --dry-run 把配置与 sbatch 脚本前置校验;ACT 阶段提交后立即进入强制轮询,并依据 SUCCESS / FAILED 分别走结果分析或五步调试清单。文中所有命令与清单均可在 plugins/modelopt/skills/launching-evals 目录下找到对应文档原文,建议在实际提交前通读一遍 SKILL.md 的 Key Facts,尤其是 Slurm 作业对、data_parallel_size 按节点计、HF 离线缓存这三个容易踩坑的事实。