Agent强化学习训练框架Microsoft Agent-Lightning之实战记录
文章目录
Agent-Lightning 实战全流程:从Agentic RL原理到 4×A800部署与SQL-Agent强化学习训练
环境:Ubuntu 22.04 · 4×NVIDIA A800 80GB · Python 3.12 · verl 0.5.0 + vllm 0.10.2 + agentlightning 0.3.0
项目:基于 LangGraph 的 SQL-Agent,使用 Agentic RL(GRPO)训练 Qwen3-1.7B 提升文本转 SQL 能力
1. 原理
2. 环境部署
3. 项目结构与数据准备
3.1 目录结构
/work/agent_lignting/
├── models/Qwen3-1.7B/ # 模型权重(modelscope 下载,13 个文件)
├── SQL-Agent-RL/
│ ├── data/ # Spider 数据集
│ │ ├── train_spider.parquet # 训练集 7000 样本
│ │ ├── test_dev_500.parquet # 验证集 500 样本
│ │ ├── test_dev.parquet # 快速验证 100 样本
│ │ └── database/ # 200+ 个 SQLite 数据库
│ ├── models -> ../models # 软链接(让 models/Qwen3-1.7B)
│ ├── spider/
│ │ ├── sql_agent.py # LangGraph SQL-Agent + LitSQLAgent
│ │ ├── train_sql_agent.py # 训练脚本 + 配置
│ │ └── spider_eval/ # Spider 官方评估函数
│ ├── swanlog/ # swanlab 本地缓存
│ └── checkpoints/ # verl 断点(save_freq=10)
3.2 数据说明
Spider 数据集是大规模跨域文本到 SQL 数据集(耶鲁大学),包含约 200 个不同业务领域的 SQLite 数据库,每个 parquet 文件包含字段:
question:自然语言问题db_id:数据库标识符query:标准答案 SQL
跨域特性使训练出的模型有更好的泛化能力。数据库为 SQLite 文件,零配置,无需独立数据库服务器。
3.3 模型下载
pip install modelscope
mkdir -p ./models/Qwen3-1.7B
modelscope download --model Qwen/Qwen3-1.7B --local_dir ./models/Qwen3-1.7B
下载后需验证 safetensors 完整性:
python -c "
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
m = AutoModelForCausalLM.from_pretrained('models/Qwen3-1.7B', torch_dtype=torch.bfloat16).to('cuda')
print('模型加载成功', sum(p.numel() for p in m.parameters())/1e9, 'B')
"
⚠️ Qwen3 thinking 模式:Qwen3 默认开启思考模式,会输出
<think>...</think>块。本项目已在models/Qwen3-1.7B/tokenizer_config.json中修补为默认关闭(备份tokenizer_config.json.bak),否则 SQL-Agent 的parse_query会把 thinking 内容当 SQL 执行而报错。
{%- if add_generation_prompt %}
{{- '<|im_start|>assistant\n' }}
{%- if enable_thinking ... %} <!-- 这里被修改 -->
{{- ' thinking\n\n response\n\n' }}
{%- endif %}
{%- endif %}
4. 训练配置详解
训练脚本 spider/train_sql_agent.py 的核心配置(已优化到 4 卡稳定运行):
RL_TRAINING_CONFIG = {
"algorithm": {
"adv_estimator": "grpo", # GRPO 算法
"use_kl_in_reward": False,
},
"data": {
"train_files": "data/train_spider.parquet", # 训练集 7000 样本
"val_files": "data/test_dev_500.parquet", # 验证集 500 样本
"train_batch_size": 32,
"max_prompt_length": 4096,
"max_response_length": 2048,
"truncation": "error",
},
"actor_rollout_ref": {
"rollout": {
"tensor_model_parallel_size": 1, # 4 卡下 vLLM 按 DP=4 并行
"n": 4, # 每个样本生成 4 条轨迹
"log_prob_micro_batch_size_per_gpu": 4,
"multi_turn": {"format": "hermes"},
"name": "vllm", # verl 自建 vLLM 引擎
"gpu_memory_utilization": 0.6, # ★ 防 OOM 关键值
"engine_kwargs": {"vllm": {
"enable_auto_tool_choice": True,
"tool_call_parser": "hermes",
}},
},
"actor": {
"ppo_mini_batch_size": 32,
"ppo_micro_batch_size_per_gpu": 4,
"optim": {"lr": 1e-6},
"use_kl_loss": False,
"clip_ratio_low": 0.2, "clip_ratio_high": 0.3,
"fsdp_config": {
"param_offload": False, # ★ 小模型不需要 CPU offload
"optimizer_offload": False, # ★ 去掉后参数更新快 2.9 倍
},
},
"ref": {
"log_prob_micro_batch_size_per_gpu": 8,
"fsdp_config": {"param_offload": False},
},
"model": {
"path": "models/Qwen3-1.7B", # 本地模型
"use_remove_padding": True, # 依赖 flash-attn
"enable_gradient_checkpointing": True,
},
},
"trainer": {
"n_gpus_per_node": 4, # ★ 4 卡并行
"val_before_train": True,
"logger": ["console", "swanlab"], # ★ swanlab 日志
"project_name": "Qwen3-1.7B-AgenticRL",
"experiment_name": "spider", # 固定名称保证 checkpoint 可续训
"nnodes": 1,
"test_freq": 32, # 每 32 步验证一次
"total_epochs": 2,
"save_freq": 10, # ★ 每 10 步保存 checkpoint
"resume_mode": "auto", # ★ 崩溃自动续训
},
}
4.1 关键配置项解析
| 配置 | 值 | 说明 |
|---|---|---|
gpu_memory_utilization |
0.6 | 防 OOM 的关键。0.8 会导致 KV cache 唤醒时显存不足死锁 |
param_offload/optimizer_offload |
False | 1.7B 模型 4 卡完全装得下,offload 是负优化 |
n_runners(train() 函数内) |
32 | 并行 SQL-Agent worker 数,提升 GPU 利用率 |
save_freq / resume_mode |
10 / auto | 每 10 步保存断点,崩溃自动续训 |
n_gpus_per_node |
4 | 4 卡 FSDP + vLLM DP 并行 |
4.2 三种训练模式
| 参数 | fast(冒烟) | qwen(正式) |
|---|---|---|
| 验证集 | test_dev(100) | test_dev_500(500) |
| epochs / 步数 | 1 步 | 2 epochs(~438 步) |
| gpu_memory_utilization | 0.6 | 0.6 |
| 模型 | models/Qwen3-1.7B | models/Qwen3-1.7B |
| 说明 | CI 快速验证 | 正式实验 |
5. SwanLab 实验日志系统
SwanLab 是国产免费的实验跟踪平台,接口与 wandb 高度兼容,支持云端与本地两种模式,提供实时可视化、超参数记录、多实验对比、团队协作等完整功能,且国内访问快。
5.1 安装与登录
pip install swanlab
# 注册获取 API Key(https://swanlab.cn → 设置 → API Key)
swanlab login --api-key <你的APIKey>
# 示例:swanlab login --api-key xxx
5.2 快速上手
import swanlab
import random
# 初始化实验
swanlab.init(
project="Qwen3-1.7B-AgenticRL", # 项目名
workspace="yuanyou", # 工作区(账号)
config={ # 超参数记录
"learning_rate": 1e-6,
"model": "Qwen3-1.7B",
},
)
# 训练循环中上报指标
for epoch in range(1, 11):
acc = 1 - 2 ** -epoch - random.random() / epoch
loss = 2 ** -epoch + random.random() / epoch
swanlab.log({"acc": acc, "loss": loss}) # 实时上报
swanlab.finish() # 结束实验(notebook 中必须调用)
5.3 verl 原生集成
- verl 0.5.0 原生支持 swanlab 后端,无需修改任何代码。只需在训练配置的
trainer.logger里启用:
"logger": ["console", "swanlab"], # 启用 swanlab 日志
"project_name": "Qwen3-1.7B-AgenticRL",
verl 的 verl/utils/tracking.py 内置了 if "swanlab" in default_backend 分支,会自动:
- 读取环境变量
SWANLAB_API_KEY(可选,已登录可省略) - 调用
swanlab.init(project=, experiment_name=, config=, logdir=, mode=) - 每步结束后批量上报训练指标(loss、reward、timing 等 80+ 个指标)
- 验证集生成结果通过
swanlab.echarts.Table记录
运行时的环境变量:
export SWANLAB_API_KEY=xxx # 设置后 verl 会自动 login
export SWANLAB_MODE=cloud # 云端(默认);本地实验可用 local/offline
6. 完整运行流程:从 fast 冒烟到正式训练
6.1 环境激活
source /opt/conda/etc/profile.d/conda.sh
conda activate agent_lighting
cd /mnt/nodestorlv/users/sales06/work/agent_lignting/SQL-Agent-RL
6.2 预检
# 关键包可导入
python -c "import torch,vllm,verl,flash_attn; import agentlightning as agl; print('stack OK', agl.__version__)"
# 配置可构造
python -c "
import sys; sys.path.insert(0, 'spider')
from train_sql_agent import config_train_qwen
import agentlightning as agl
alg = agl.VERL(config_train_qwen())
tr = agl.Trainer(n_runners=32, algorithm=alg)
print('4卡 qwen 配置 OK')"
# GPU 4-7 空闲确认
nvidia-smi --query-gpu=index,memory.used --format=csv,noheader | awk -F',' '$1>=4 && $2+0>1000 {print "GPU "$1" 被占用"}'
6.3 fast 冒烟实验(~15 分钟)
CUDA_VISIBLE_DEVICES=4,5,6,7 SWANLAB_API_KEY=4nPZGCu0kzMkkcGdObxmn \
python spider/train_sql_agent.py fast
成功标志:日志出现 step:1 且 val/reward 有数值;4 卡利用率 ~30%+。
6.4 正式训练(全参,约27-20小时)
nohup env CUDA_VISIBLE_DEVICES=4,5,6,7 SWANLAB_API_KEY=4nPZGCu0kzMkkcGdObxmn \
python spider/train_sql_agent.py qwen > train.log 2>&1 &
nohup ... &保证关掉终端训练不中断(nohup 忽略 SIGHUP,无控制终端)。
预期节奏:
- 初始化 ~3 分钟(ray 集群 + 4 卡加载模型 + verl 内部 vLLM 引擎)
- 初始验证 500×4=2000 rollout(~25 分钟)
- 每步 ~60s(生成 + GRPO 更新),共 ~438 步
- 每 32 步跑一次验证
- 每 10 步保存 checkpoint
6.5 监控
tail -f /tmp/qwen_train_full.log # 实时日志
watch -n 2 nvidia-smi # GPU 利用率
grep -c "Completed in" train.log # rollout 进度
grep -E "step:[0-9]+ - val/reward" train.log # 验证集指标
# swanlab 云端看板:https://swanlab.cn/@yuanyou/Qwen3-1.7B-AgenticRL
6.6 断点续训
训练中断(崩溃/关机)后,直接重新运行同一条命令即可自动恢复:
# checkpoint 保存于 SQL-Agent-RL/checkpoints/Qwen3-1.7B-AgenticRL/spider/global_step_<N>/
# resume_mode: auto 会从最近断点继续,最多丢 10 步
7. 踩坑记录与性能优化
7.1 训练中途 OOM 死锁(必踩)
现象:训练正常跑了几十步后突然卡死,日志:
RuntimeError: CUDA Error: out of memory at /workspace/csrc/cumem_allocator.cpp:62
发生在 vLLM wake_up(tags=["kv_cache"])(训练步切回 rollout 阶段)。卡死后步数不再增长、GPU 0% 利用率但显存被占。
根因:verl 把 FSDP 训练和 vLLM 引擎共卡部署。gpu_memory_utilization 设为 0.8 时,vLLM 预留 64GB/卡 做 KV cache,训练步结束后切回 rollout 时 KV cache 重新分配显存不足 → OOM → worker 崩 → 死锁。实测 0.8 在 step 55 挂,0.6 稳定无 OOM。
修复:gpu_memory_utilization 降到 0.6。1.7B 模型 KV cache 需求小,48GB 预留足够,代价(生成吞吐略降)可忽略。
7.2 LoRA 不可用(版本兼容性)
现象:启用 LoRA(lora_rank: 16)后:
- reward 迅速崩塌(0.63 → 0.09 → 0.08)
update_actor反而变慢(32-44s vs 全参 24s)- vLLM 报
Error in preprocessing prompt inputs
根因:verl 0.5.0 + vllm 0.10.2 的 LoRA 集成不兼容。verl 0.5.0 官方锁 vllm<=0.8.5,本项目用 0.10.2。LoRA 适配器权重需要在 FSDP worker ↔ vLLM 引擎间同步,该同步在 0.10.2 上失效——rollout 用到错误权重,模型在收敛但生成越来越烂。
- 结论:本项目坚持全参微调,不要用 LoRA。
7.3 性能优化记录(实测)
| 优化项 | 修改前 | 修改后 | 效果 |
|---|---|---|---|
| CPU offload | True | False | 参数更新 2.9× 加速 |
| 并行 runner | 10 | 32 | rollout 吞吐 +30%,GPU 利用率均衡 |
| gpu_memory_utilization | 0.8 | 0.6 | 消除 OOM 死锁 |
| checkpoint | 无 | save_freq=10 | 中断可恢复 |
单步耗时实测:1卡+offload 200s → 4卡+优化后 46-100s(稳态 ~60s)。训练步阶段 4 卡利用率 100%,rollout 阶段 ~35%。
7.4 为什么 GPU 利用率不是 100%
- Agentic RL 的 rollout 是串行多轮 agent 执行:每个 rollout = SQL-Agent 的 write→执行SQL→check→rewrite 循环(平均 3.7 轮),LLM 调用之间夹着 SQLite 执行、评估、HTTP 往返等 CPU 工作。GPU 在 agent 的 CPU 工作期间空闲,这是该负载的固有特性。32 runner 已远超 GPU 需求,进一步加大收益递减。
8. 实验进展与结果
8.1 训练状态
当前正式实验运行中(4×A800 全参微调 Qwen3-1.7B,GRPO,2 epochs):
| 指标 | 数值 |
|---|---|
| 模型 | Qwen3-1.7B(1.7B 参数,全参 FSDP,bf16) |
| 训练数据 | Spider 训练集 7000 样本 |
| 单步耗时 | ~60s |
| checkpoint | 每 10 步保存 |
| 日志 | SwanLab 云端实时上报 |
8.2 验证集指标
| 验证点 | val/reward |
|---|---|
| step 0(基线) | 0.534 |
| step 32 | 0.594 |
| step 64 | 0.612 |
| step 96 | 0.638 |
| step 128 | 0.626 |
| step 160 | 0.676 |
| step 192 | 0.674 |
| step 224 | 0.672 |
| step 256 | 0.690 |
| step 288 | 0.686 |
| step 320 | 0.680 |
| step 352 | 0.682 |
| step 384 | 0.700 |
| step 416 | 0.692 |
| 最终 | 0.712 |
验证集正确率单调上升(0.534 → 0.712,+33.3%),说明 GRPO 训练真实提升了模型的 SQL 生成能力,且具备泛化性(不是在训练集上过拟合)。
8.3 训练奖励:分段稳步提升
| 训练阶段 | 平均训练 reward |
|---|---|
| step 1-100 | 0.573 |
| step 101-200 | 0.624 |
| step 201-300 | 0.649 |
| step 301-436 | 0.669 |
- 训练奖励从 0.573 稳步提升到 0.669(+16.8%),四个阶段单调上升
- 训练后期出现 0.78-0.79 的高位(step 432: 0.789, step 433: 0.781)
- 训练奖励 < 验证集奖励(0.669 vs 0.712)——因为训练集是 7000 样本的更全集合,含更多难题
9. 正式效果评测(后训练评估)
9.1 评测设置
- 模型:合并训练后的 Qwen3-1.7B(
global_step_436checkpoint,经 verl FSDP 分片合并重建) - 测试集:
test_dev_500.parquet(500 条,与训练验证集一致,便于对比) - 评测方式:加载训练后模型 → vLLM 服务 → 运行完整 SQL-Agent(write→execute→check→rewrite,max_turns=3)→
eval_exec_match执行结果匹配 - 推理配置:temperature=0(贪心解码)、4 卡并行、20 个评估 worker
9.2 评测结果
| 指标 | 数值 |
|---|---|
| 总样本 | 500 |
| 正确 | 309 |
| 准确率 | 61.8% |
| 平均耗时 | 14.2s/条 |
| 400 错误 | 0 |
9.3 与训练验证的对比(关键差异)
| 维度 | 训练验证(val/reward) | 正式评测 |
|---|---|---|
| 每问题生成数 | n=4(4 条采样轨迹) | 1 条(贪心解码) |
| 准确率 | 71.2% | 61.8% |
差异解读:
- 训练验证的 71.2% 是"每个问题采样 4 次"的平均奖励——采样多样性给了更多命中正确 SQL 的机会
- 正式评测的 61.8% 是单次贪心生成的冷准确率——更保守、更真实地反映模型单次能力
- 两者差距(~9.4 个百分点)说明采样多样性(n=4)有实际收益,贪心解码会损失一部分正确率
9.4 评测结论
- 训练后模型的单次 SQL 生成准确率 61.8%(相对基线 53.4% 提升 8.4 个百分点),配合 n=4 采样可达 71.2%
- 4 卡并行评估方案验证有效:GPU 利用率 80%+,500 条评测 ~15 分钟完成(对比单卡串行 ~2 小时)
- 评测与训练验证口径不同(n=1 贪心 vs n=4 采样),单次准确率是更保守的评估
10. 总结与展望
10.1 核心收获
- Agentic RL 让"小模型低成本"成为可能:通过 GRPO 从执行反馈中学习,1.7B 模型在文本转 SQL 任务上能达到约 64% 正确率并持续提升,验证了"低成本 + 高能力"的技术路径。
- 工业级架构的价值:LangGraph(Agent 执行)+ verl(RL 训练)+ Agent-Lightning(封装桥接)的"运行与训练分离"架构,让 Agent 上线后还能持续迭代。
- 环境部署的经验:flash-attn 用官方预编译 wheel 零编译、三个版本坑(libstdc++/fastapi/transformers)、Qwen3 thinking 模式处理。
- 4 卡训练的经验:防 OOM(gpu_memory_utilization 0.6)、去 CPU offload、加大 runner 并行、checkpoint 断点续训。
10.2 展望
- 模型升级:Qwen3-Coder 系列(4B/8B)在 SQL/代码任务上更强,80GB 卡可承载。
- 算法探索:尝试不同 adv_estimator、reward shaping(SQL 执行时间、结果集相似度等)。
- 任务迁移:同一套架构可迁移到数据分析、检索问答、多工具 Agent 等场景,只需替换 LangGraph 执行节点和奖励函数。
- LoRA 前瞻:若升级到与 vllm 0.10.2 兼容的 verl 版本,可重新评估 LoRA 以降低训练成本。
更多推荐

所有评论(0)