ARTICLE DETAIL

资讯详情

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

AReaL 调试指南:从 Agent Workflow 验证到分布式训练死锁诊断

AReaL 调试指南:从 Agent Workflow 验证到分布式训练死锁诊断 AReaL 调试指南从 Agent Workflow 验证到分布式训练死锁诊断【免费下载链接】AReaLThe RL Bridge for LLM-based Agent Applications. Made Simple Flexible.项目地址: https://gitcode.com/GitHub_Trending/are/AReaL本指南是 AReaLThe RL Bridge for LLM-based Agent Applications训练应用调试的实战手册覆盖三条主线如何利用持久化推理服务器在 CPU 上快速迭代调试 Agent Workflowrollout如何对比 Transformers 与推理引擎的 rollout 结果以验证一致性以及如何用py-spy 诊断分布式训练挂起与死锁。读完本指南你将掌握一套从单条样本到并发批量再到接入 AReaL 训练器的渐进式调试流程以及定位训练卡死根因的可复现方法。调试方法论总览在 AReaL 中任何具有方法签名async def run(self, data, **extra_kwargs)的类都被识别为 Agent Workflow。该方法可以在内部使用任意的 Agentic 框架如 OpenAI Agents SDK、CAMEL-AI 等并且必须返回标量或奖励字典为每次 LLM 交互分配信用。关于 Agent 定义与奖励机制的完整说明参见 Agentic RL 指南。调试 Agent Workflow 的核心思路是把生成逻辑与 AReaL 训练系统解耦既可以使用官方 OpenAI/Anthropic API也可以启动一个独立的持久化推理服务器来承载生成逻辑从而无需重启系统即可重复测试。这种方案有三个显著优势轻量级调试程序在 CPU 上运行推理在提供商的 GPU 上进行本地无需显存开销IDE 友好与 VS Code 的 Python 调试器和其他 IDE 无缝协作可以逐行打断点快速迭代调试会话之间无需重启推理服务器改完代码即可重跑。第一步启动独立推理服务器可选如果你打算使用官方模型提供商进行调试可以跳过此步。否则你需要一个暴露 OpenAI/Anthropic HTTP 端点的推理服务。文档示例使用sglang但任何符合该接口约定的框架例如vllm都可以。nohup python3 -m sglang.launch_server --model-path qwen/qwen2.5-0.5b-instruct --host 0.0.0.0 --port 8080 --log-level warning llm_server.log 21 启动成功后日志中会出现服务器地址[2026-02-06 15:38:30] INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRLC to quit)在 AReaL 生产训练中推理服务器通常由 SGLang 远程引擎或 vLLM 远程引擎托管启动并通过 OpenAI 兼容接口与 rollout 进程通信独立服务器调试只是把这一环节替换为手动启动便于本地迭代。第二步使用单次运行调试你的 Agent用一个最简数据集样本驱动一次run调用验证 Agent 逻辑能无错误运行。注意 base URL 和 API key 可以通过extra_kwargs传入也可以从环境变量OPENAI_BASE_URL/OPENAI_API_KEY读取这与 Agentic RL 指南 中代理客户端proxy client的取参方式保持一致import asyncio from openai import AsyncOpenAI class MyAgent: async def run(self, data, **extra_kwargs): base_url extra_kwargs.get(base_url) or os.getenv(OPENAI_BASE_URL) api_key extra_kwargs.get(api_key) or os.getenv(OPENAI_API_KEY) async with AsyncOpenAI(base_urlbase_url, api_keyapi_key) as client: comp await client.chat.completions.create( modelqwen/qwen2.5-0.5b-instruct, messagesdata[messages], temperature0, max_tokens64, ) return 1.0 # random reward data dict(messages[{role: user, content: List 3 countries and their capitals.}]) # If you use a local inference server port 8080 asyncio.run(MyAgent().run(data, base_urlfhttp://127.0.0.1:{port}/v1, api_keyNone)) # If you use the official model provider asyncio.run(MyAgent().run(data, base_urlhttps://api.openai.com/v1, api_keyYOUR_API_KEY))使用数据集中的随机样本测试你的代码。如果它能无错误运行则你的 Agent 逻辑是正确的。第三步使用多个并发运行调试你的 AgentRL 训练通常需要生成大批量因此你必须验证 Agent 代码尤其是内部使用的 Agentic 框架能否处理高并发。部分框架为单线程场景设计可能无法很好地扩展到 RL 训练——这一环就是为了提前暴露这类问题。下面以 GRPO 为例给出并发性验证模板。global_bs为全局 batch 大小group_size为每个输入生成的样本数rollout_dp_size为 rollout 数据并行度local_bs为每个 rollout 进程实际处理的样本数# Example GRPO configuration global_bs 256 group_size 8 # Example allocation rollout_dp_size 4 local_bs global_bs // rollout_dp_size port 8080 async def run_agent(data): return await MyAgent().run(data, base_urlfhttp://127.0.0.1:{port}/v1, api_keyNone) async def grouped_rollout(data): return await asyncio.gather(*[run_agent(data) for _ in range(group_size)]) async def batched_rollout(batch): assert len(batch) local_bs return await asyncio.gather(*[grouped_rollout(data) for data in batch]) # batch should be a list of data dicts with length local_bs batch [data] * local_bs asyncio.run(batched_rollout(batch))这里用asyncio.gather模拟了 AReaL 的并发执行模型组内多个样本并发、批内多组并发。如果在这个层级出现死锁、连接超时或结果互相污染说明 Agent 框架的并发能力不满足 RL 训练要求应尽早替换或改造。第四步与 AReaL 的集成测试完成前序步骤后将 Workflow 集成到 AReaL 中做端到端验证。将你的 Agent 放在可导入的路径中例如my_agent.MyAgent然后在 AReaL 中初始化 rollout 控制器进行批量 rolloutfrom areal.api.alloc_mode import ModelAllocation from areal.api.cli_args import GRPOConfig, SGLangConfig, load_expr_config, vLLMConfig from areal.engine.sglang_remote import RemoteSGLangEngine from areal.engine.vllm_remote import RemotevLLMEngine from areal.infra import LocalScheduler, RayScheduler, SlurmScheduler import sys # Load config and parse rollout backend config, _ load_expr_config(sys.argv[1:], GRPOConfig) rollout_alloc ModelAllocation.from_str(config.rollout.backend) # Initialize scheduler based on config if config.scheduler.type local: scheduler LocalScheduler(exp_configconfig) elif config.scheduler.type ray: scheduler RayScheduler(exp_configconfig) elif config.scheduler.type slurm: scheduler SlurmScheduler(exp_configconfig) # Select inference engine and build server args if rollout_alloc.backend sglang: engine_cls RemoteSGLangEngine server_args SGLangConfig.build_args( sglang_configconfig.sglang, tp_sizerollout_alloc.parallel.tp_size, base_gpu_id0, ) elif rollout_alloc.backend vllm: engine_cls RemotevLLMEngine server_args vLLMConfig.build_args( vllm_configconfig.vllm, tp_sizerollout_alloc.parallel.tp_size, pp_sizerollout_alloc.parallel.pp_size, ) # Create controller and initialize eval_rollout engine_cls.as_controller(config.rollout, scheduler) eval_rollout.initialize( roleeval-rollout, server_argsserver_args, ) # Define workflow and its configuration workflow areal.workflow.rlvr.RLVRWorkflow workflow_kwargs dict( reward_fnareal.reward.gsm8k.gsm8k_reward_fn, gconfigconfig.gconfig, tokenizerconfig.tokenizer_path, enable_thinkingFalse, ) batch eval_rollout.rollout_batch( batch, workflowworkflow, workflow_kwargsworkflow_kwargs, group_sizeconfig.gconfig.n_samples, )使用以下命令运行脚本python3 script.py --config xxx.yaml scheduler.typelocal这基本上遵循与评估相同的过程。关键接口与底层实现rollout_batch是 InferenceEngine 的抽象方法其 docstring 明确指出该方法不支持异步 rollout只应用于离线数据收集或调试而非生产实验。在 SGLang 远程引擎 中它直接透传到底层_engine.rollout_batch并携带group_size、min_usable_group_size、reward_normalization等参数。workflow areal.workflow.rlvr.RLVRWorkflow指向仓库内置的单轮奖励学习工作流 rlvr.py其arun_episode会构造ModelRequest、调用engine.agenerate生成、计算奖励并组装出包含input_ids、loss_mask、logprobs、versions、turn_ids、rewards等张量的轨迹字典——这些正是训练器所需的全部输入。reward_fn传入字符串路径时会在首次arun_episode时通过import_from_string动态加载见 rlvr.py仓库内置的gsm8k_reward_fn定义于 areal/reward/gsm8k.py。重要提示使用与训练相同的配置文件不相关的字段会被忽略。确保max_head_offpolicyness和max_concurrent_rollouts足够大否则 rollout 进程会因过期控制而无限期阻塞。这两个字段定义于 InferenceEngineConfigmax_concurrent_rollouts默认None允许并发提交到推理引擎的 rollout 数量上限缺省时取consumer_batch_size见 rollout_controller.pymax_head_offpolicyness默认0head 允许的最大 off-policy 程度即当前模型版本落后超过该数值时请求会被拒绝。调试时若取默认值 0 且训练中权重更新频繁旧版本请求会被拒绝从而造成阻塞因此文档建议调大此外还可关注queue_sizeI/O 队列大小默认取max_concurrent_rollouts * 16与consumer_batch_size默认 1对吞吐的影响。如果步骤 4 通过你的代码已准备好用于 AReaL可以将其传递给训练器并开始训练。Rollout 一致性对比 Transformers 与推理引擎比较transformers与推理引擎之间的 rollout 结果有助于验证一致性和正确性。虽然大多数模型产生的结果几乎相同但某些模型可能由于推理后端如sglang、vllm为加速前向传播而进行的大量优化而表现出显著差异。如果你怀疑存在差异或者你使用的模型在 Transformers 或 SGLang 中缺乏一流支持请使用简单的验证脚本对照数据集比较输出。仓库提供了完整示例 examples/docs/debug/cmp_rollout.py它对比google/gemma-3-4b-it在BUAADreamer/clevr_count_70k数据集上的 rollout 结果。该脚本的核心思路本地 Transformers 推理用Gemma3ForConditionalGeneration在 GPU 上直接生成do_sampleFalse贪心解码记录准确计数t_count远端推理服务器通过 HTTP POST 向http://127.0.0.1:30000/generate发送同样的input_ids、base64 编码的图片与sampling_paramstemperature0, max_new_tokens16记录准确计数s_count对比输出分别用f[{answer}]与两端解码结果做精确匹配最后打印Transformers accuracy与SGLang accuracy。该脚本同时验证了多模态输入路径图像经image2base64编码后透传对于排查同一提示在不同后端产出不一致的问题非常直接。注意两端必须使用相同的输入同一input_ids、同一采样参数否则对比没有意义。调试训练挂起和死锁分布式训练可能会在 ranks 不同步时挂起或死锁。本节介绍如何诊断这些问题。症状挂起或死锁通常表现为以下情况之一训练停止进展日志停止更新没有新的训练步骤但进程仍保持活跃且 CPU 使用率很高训练无错误退出任务完成有时甚至打印 Training completes!但实际完成了 0 个训练步骤进程在清理过程中可能会无限期挂起某些 ranks 完成其他 ranks 挂起nvidia-smi显示某些 GPU 空闲而其他 GPU 仍处于 100% 利用率。这些症状通常有一个共同的根本原因某些 ranks 上的异常或提前退出导致剩余 ranks 永远等待集合操作例如all_reduce、send/recv或destroy_process_group。常见原因原因发生了什么部分 ranks 上的异常PP/TP 组的一方遇到错误并退出而另一方等待永远不会到达的 P2P 或集合操作。异常可能被清理代码吞掉__exit__→destroy_process_group()挂起。集合调用不匹配代码路径在某些 ranks 上调用all_reduce但在其他 ranks 上不调用例如由于跨 ranks 不同的条件分支。PP 中的形状不匹配流水线并行阶段期望交换特定形状的张量。如果某个阶段产生意外的形状recv将永远阻塞。NCCL 超时网络问题或慢 ranks 导致 NCCL 操作超过超时但默认超时可能很长30 分钟。初始化中的死锁模型加载或编译在不同 ranks 上花费不同时间而在所有 ranks 准备好之前就调用了集合。步骤 1确认挂起首先验证训练确实挂起了不仅仅是慢# Check if training steps are advancing tail -f /path/to/training.log # Check GPU utilization — hung ranks often show 0% GPU, high CPU nvidia-smi # List the training processes ps aux | grep python.*areal | grep -v grep步骤 2使用py-spy转储调用栈py-spy是诊断挂起最有效的工具它附加到正在运行的 Python 进程并转储调用栈而不会中断执行因此不会改变挂起现场的时序。# Install py-spy (if not already installed) pip install py-spy # Dump call stack for a single process py-spy dump --pid PID # Dump all training worker processes at once for pid in $(ps aux | grep python.*areal | grep -v grep | awk {print $2}); do echo PID $pid py-spy dump --pid $pid done步骤 3读取调用栈调用栈会准确告诉你每个 rank 被阻塞的位置。寻找以下三种典型模式模式 A清理死锁——某些 ranks 完成遇到错误或提前完成并卡在destroy_process_group中而其他 ranks 仍在训练循环中等待通信# Ranks that exited (e.g., PP Stage 0 hit an exception) Thread: MainThread destroy_process_group (torch/distributed/distributed_c10d.py) destroy (archon_engine.py) close (sft_trainer.py) ← stuck in cleanup __exit__ (sft_trainer.py) # Ranks still running (e.g., PP Stage 1 waiting for data) Thread: MainThread recv_object_list (torch/distributed/distributed_c10d.py) _shape_inference (torch/distributed/pipelining/stage.py) step (torch/distributed/pipelining/schedules.py) _run_train (archon_runner.py) ← waiting for the other stage模式 B集合不匹配——所有 ranks 都在训练循环内但等待不同的集合操作# Rank 0 all_reduce (torch/distributed/distributed_c10d.py) forward (some_module.py:123) # Rank 1 all_reduce (torch/distributed/distributed_c10d.py) backward (some_module.py:456) ← different code path!模式 CNCCL 超时——所有 ranks 都在相同的集合调用中表明这是网络或性能问题而非代码错误# All ranks show the same stack: all_reduce (torch/distributed/distributed_c10d.py) forward (my_model.py:100) ← same location on all ranks步骤 4用于获取更多详细信息的环境变量在启动训练之前设置这些环境变量以便在发生挂起时获取更多信息# NCCL debug logging — shows collective operations as they happen export NCCL_DEBUGINFO # PyTorch distributed debug — logs every collective call with ranks and shapes export TORCH_DISTRIBUTED_DEBUGDETAIL # Reduce NCCL timeout so hangs fail faster (default is 1800s 30 min) export NCCL_TIMEOUT300 # 5 minutes # CUDA sync mode — makes errors appear at the correct location # WARNING: significant performance impact, use only for debugging export CUDA_LAUNCH_BLOCKING1诊断提示异常被清理吞掉如果 py-spy 显示某些 ranks 在destroy_process_group中而其他 ranks 仍在训练循环中根本原因是退出 ranks 上的异常。此时应重点回溯退出 rank 的异常现场可用CUDA_LAUNCH_BLOCKING1让错误出现在正确位置。使用更少的 GPU 重现如果可能使用最少的 GPU 数量例如 PP22 个 GPU重现。这会使调用栈更容易阅读。检查所有 ranks始终转储所有工作进程的堆栈而不仅仅是一个。挂起从根本上说是关于 rank 发散——你需要比较跨 ranks 的堆栈以了解谁在等待谁。小结AReaL 的调试可以归纳为一条自下而上的验证链路先用独立推理服务器在单样本上验证 Agent 逻辑第二步再模拟并发压力验证框架的可扩展性第三步最后接入rollout_batch做端到端集成测试第四步对于生成结果的可信度用 Transformers vs 推理引擎的一致性对比兜底而对于分布式训练阶段特有的挂起与死锁则依靠py-spy栈转储 环境变量辅助定位。这条链路覆盖了从Agent 代码本身是否正确到多机多卡协同是否正确的各个层次是排查 AReaL 训练问题时的标准动作。【免费下载链接】AReaLThe RL Bridge for LLM-based Agent Applications. Made Simple Flexible.项目地址: https://gitcode.com/GitHub_Trending/are/AReaL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表