数据截至 (上游 commit 352f1bd7c1a0)
Agent Lightning — 架构与原理
30 秒导读: Agent Lightning 是微软研究院的 agent 强化学习训练框架。v1.0 做了一次彻底重写(旧版 v0.x 的 LightningStore/LitAgent/Tracer 等机制已整体删除,见仓库 README “completely refactored in v1.0”,
README.md:11)——现在的思路极简:你的 agent 不改一行代码,只要把它的 OpenAI base_url 指向框架的 API Gateway,框架就能在旁边把每次模型调用(连同推理引擎真正采样的 token id 和 logprobs)录成事件,等 agent 报 出奖励后,这些记录被自动加工成 RL 训练样本,喂给基于 verl 的训练器更新模型权重。
本页是总入口:先讲清「这是什么」(零基础也能懂),再给一张顶层全景图和一条主线走查,最后是各章阅读地图。想深入某个机制,按地图跳对应章节。
1. 这是什么(零基础也能懂)
一句话定义
Agent Lightning 是一个agent 训练框架:它把你已经写好的 AI agent 当成一个「黑盒」照常运行,在旁边观测它、给它打分,然后用强化学习(RL)反过来优化它背后的语言模型权重。
v1.0 的自我定位是一句口号——“3,500-Line Lightweight Agentic RL Framework”(3500 行的轻量 agent RL 框架,README.md:5),版本 1.0.0(依据:pyproject.toml:3 version)。旧版那套「中央 store + span + 三元组」的复杂机制被整体移除,换来的是三个各司其职的小组件。
它想解决什么问题
先说痛点。你想用 RL 训一个真实 agent(带工具调用、多轮交互、复杂 harness 的那种),通常会遇到两难:
- 传统 RL 框架——要你把 agent 逻辑重写进它的训练循环,多轮工具调用、真实环境几乎塞不进去。
- 现成 sandbox 服务——agent 得跑在别人家的托管环境里,环境依赖搬不动。
Agent Lightning v1.0 的主张(依据:README.md:15-18 Key Features):
- 零代码改动:agent 通过一个 OpenAI 兼容代理访问模型,工具、上下文、控制流、环境全部留在自己的 harness 里。
- 原生 Kubernetes:agent 直接作为 K8s Job 跑在你自己的集群上,不依赖商业 sandbox 服务。
- 真实收益:官方用 6K 训练样本把一个编码 agent 在 SWE-bench Verified 上从 41.8% 提到 56.4%(依据:
README.md:18)。
给谁用
| 读者 | 用它来做什么 |
|---|---|
| 做 agent 的工程师 | 手上有个能跑的 agent,想用 RL 调模型权重,但不想重写 agent |
| RL / LLM 研究者 | 想在真实多轮 agent 轨迹上跑 GRPO/PPO,验证新算法 |
| 平台工程师 | 想在自己的 K8s 集群上规模化地「跑 agent + 采数据 + 训模型」 |
用起来什么样
agent 侧的全部改动,就是读两个环境变量(依据:examples/calc_x/calc_agent.py:29-30):
# 示意,改编自 examples/calc_x/calc_agent.py
openai_base_url = os.environ["AGL_OPENAI_BASE_URL"] # 框架注入的代理地址
event_url = os.environ["AGL_EVENT_URL"] # 框架注入的报分地址
client = OpenAI(base_url=openai_base_url, ...) # 照常调模型,工具照常用
answer = await solve(question) # agent 逻辑一行不改
httpx.post(event_url, json={"event_type": "reward",
"data": {"value": 1.0}}) # 结束时报一个分
训练侧则是一个普通的 verl 风格脚本(依据:examples/calc_x/train_calc_agent.py:192 调 run_ppo),三个组件各自一条命令启动(依据:examples/calc_x/run_local.sh 依次起 agl-server、agl-controller、训练入口)。
一句话直觉
把它想成给 agent 修了个「驾校考场」:
- 考场门卫(API Gateway)——agent 的每次「问模型」都得过这道门,门卫顺手把问答原原本本记下来(连模 型真正说的每个 token 都记)。
- 调度台(Rollout Controller)——按考卷发车:把每道题变成一个真实进程或 K8s Job,跑完收回结果。
- 教练(Trainer)——攒够一批考卷成绩,算出「哪些开法值得强化」,更新模型权重,再发下一批。
2. 顶层全景(它大概怎么转)
怎么读这张图
从中间的 API Gateway 看起——它是唯一的「账本 + 转发台」。左边是学习侧(Trainer),右边是执行侧(Controller + 你的 agent)。三条线:黑实线是控制流(创建/查询/注册),代理那条是 agent 的模型调用流,虚线是数据回流。
学习侧(训) 中央:账本 + 模型代理 执行侧(跑)
┌─────────────────┐ ┌──────────────────────────┐ ┌──────────────────────┐
│ Trainer │ │ API Gateway │ │ Rollout Controller │
│ (verl + vLLM, │──①注册──▶│ rollouts / events / │◀─③领任务─│ (local 子进程 / │
│ GPU 集群) │ │ models 三本内存账 │ │ K8s Job) │
│ │──②排队──▶│ │──④发环境变量─▶ 你的 agent │
│ GRPO 算优势、 │ │ OpenAI 兼容反向代理 ★ │ │ (AutoGen/LangChain/ │
│ 更新权重 │◀─⑥拉事件─│ return_token_ids+ │◀─────│ 裸 OpenAI 都行) │
│ │ │ logprobs 连 token 记账 │ ⑤每次模型调用走代理 + │
└─────────────────┘ └──────────────────────────┘ 结束报 reward 事件 │
└──────────────────────┘
部件一句话职责
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
| API Gateway | FastAPI 服务:存 rollout/事件/模型端点;反向代理模型请求并自动记账 | agentlightning/server/app.py |
| 反向代理路由 | 按 rollout 归账转发模型调用,统一采样参数,捕获 token id | agentlightning/server/proxy.py |
| Rollout Controller | 调谐器:把 QUEUING rollout 变成子进程或 K8s Job 并回收状态 | agentlightning/controller/local_reconciler.py |
| K8s 调谐器 | 同上,但执行单元是 K8s Job(模板渲染 + watch) | agentlightning/controller/k8s_reconciler.py |
| Trainer | 继承 verl 的 RayPPOTrainer,驱动 rollout、转训练样本、更新权重 | agentlightning/verl/trainer.py |
| Rollout 管理器 | Trainer 的 HTTP 客户端层:排队、等待、拉事件、组装 Triplet | agentlightning/verl/agl_rollout_manager.py |
| 样本适配器 | 把完成 rollout 的事件流转成 verl 的 DataProto 训练批 | agentlightning/verl/rollout_adapter.py |
| 轻量 HTTP 客户端 | 带鉴权与重试的 httpx 封装 | agentlightning/client.py |
| 生命周期钩子 | 排队前改写请求、成败后回写自定义事件 | agentlightning/hooks.py |
主线走一遍(一次训练循环,高层不进代码)
跟着上图编号走一圈,就是 v1.0 的心跳:
- ① 注册模型:每个训练步开始,Trainer 把自己 vLLM 推理引擎的地址注册到 Gateway(
register_model,agentlightning/verl/agl_rollout_manager.py:171)——agent 后续所有模型调用都会被转发到这个引擎。 - ② 排队任务:Trainer 把一批训练样本逐个
POST /api/rollouts排进队列(GRPO 下每样本排 n 份),状态QUEUING。 - ③ 领任务:Controller 轮询到 QUEUING 的任务,spawn 一个子进程(local 模式)或创建一个 K8s Job(k8s 模式),并把它 PATCH 成
RUNNING。 - ④ 注入环境:Controller 在子进程/Job 里注入
AGL_OPENAI_BASE_URL(指向 Gateway 的 rollout 专属代理 URL)、AGL_EVENT_URL(报分地址)和AGL_KEY,然后把控制权交给你的 agent。 - ⑤ 跑 + 记账:agent 照常发起 OpenAI 请求——但 URL 里有 rollout_id,Gateway 转发给 vLLM 时强制要求
return_token_ids=True和 logprobs,并把完整问答连 token id 录成一条model_request事件;agent 结束时往AGL_EVENT_URLPOST 一条reward事件。 - ⑥ 拉事件转样本:Trainer 轮询到 rollout 进入终态,用
format=triplet拉回精简后的事件(只剩 token id/logprobs/奖励),拼成 (prompt, response, reward) 三元组,再由样本适配器组装成 verl 训练批——算优势、更新权重,回到第 ① 步。
关键心智模型:三个组件互相只认 HTTP,谁也不 import 谁。 Gateway 是唯一的共享状态(内存里三本账),Controller 和 Trainer 都是它的客户端。agent 更是只知道「一个 OpenAI 端点 + 一个报分 URL」。这就是「零改动」的架构根基。
3. 阅读地图(建议顺序)
按「由浅入深」推荐这样读:
- 01 — Rollout 与事件:中央账本:先搞懂账本记了什么——Rollout 的四态状态机、Event 的插入序模型、两种「知名事件」(
model_request/reward)、以及幂等创建和完成序游标这些工程细节。 - 02 — API Gateway 与模型代理:全框架的心脏。rollout_id 进 URL 的归账设计、稳定哈希选端点、统一采样参数与 token id 捕获(agent RL 正确性的命根子)、上游重试、暂停/排空。
- 03 — Rollout Controller:执行侧。local 子进程模式的 spawn/超时/进程组击杀,K8s 模式的 Jinja2 模板渲染、双循环调谐与限速。
- 04 — Trainer 与 verl:学习侧。GRPO 分组排队、同步/异步两种等待策略、事件→训练样本 的两种聚合粒度(transition/trajectory)、rollout 级优势与逐 rollout 损失这两个默认创新。
- 05 — 深入、边界与代码地图:可借鉴的巧妙设计、它刻意不做什么/会在哪崩、和同书架兄弟项目的对比、以及一张给人和 agent 用的跳转表。
赶时间的话:只读 01 + 02 就能抓住 v1.0 的精髓——账本 + 会记账的代理。