研究周报 · 2026.04.19–04.25 · DAPO/GiGPO/MAPPA/Dr.MAS 精读与 sub2api 实践

字数 4,296 预计阅读 11 分钟

精读 DAPO、GiGPO、MAPPA、Dr.MAS,梳理 agent-level、step-level、token-level 信用分解的组合思路;开发 sub2api 令牌分发工具;学习 LangGraph、AutoGen、AgentScope、CAMEL 等经典 agent 框架实践。

作者 Yoyo_Lee 发表于

本周继续围绕 multi-agent credit assignment 精读 baseline:DAPO、GiGPO、MAPPA、Dr.MAS。
另外做了一个 sub2api 令牌分发工具,并补了一轮经典 agent 框架开发实践。

本周清单

  1. 阅读 DAPO / GiGPO / MAPPA / Dr.MAS
  2. 开发 sub2api,用来将 Coding Plan 分发为 API 令牌
  3. 学习经典 agent 框架开发实践
  4. to-do

一、阅读论文

上周读了Pignatelli的survey、SHARP、LangMARL,这周继续精读baseline和相关工作,挑了四篇——DAPO(token-level loss那一套trick)、GiGPO(step-level的nested group decomposition)、MAPPA(process reward + 外部coach)、Dr.MAS(per-agent normalization的零开销baseline)。基本思路还是先搞清楚每篇的核心idea和关键公式,然后看能不能借鉴。

1.1 DAPO: An Open-Source LLM Reinforcement Learning System at Scale (arXiv:2503.14476)

ByteDance去年的工作,主要解决long-CoT RL训练里的entropy collapse和token-level credit dilution。DAPO本身不是multi-agent的工作,但我感觉里面提的几个trick对GRPO本体的改造有一些启发,就放进来了。

核心idea: 在GRPO的基础上加了四个工程上的改造:

(a) Clip-Higher —— 把PPO/GRPO里的clip ratio从对称的[1ϵ,1+ϵ][1-\epsilon, 1+\epsilon]拆成上下不对称的[1ϵlow,1+ϵhigh][1-\epsilon_{\text{low}}, 1+\epsilon_{\text{high}}],把上界放宽,给低概率token更多被rollout选中的机会。直觉上就是不希望policy在已经偏好的token上继续过拟合,从而压住entropy collapse。

(b) Dynamic Sampling —— 把那些一整组rollout全对(accuracy=1)或者全错(accuracy=0)的batch直接丢掉。原因是这种batch里AGRPO=(riμG)/σGA^{\text{GRPO}} = (r_i - \mu_G)/\sigma_G的分子整体是0,对应的policy gradient也是0,喂进去纯属浪费一次forward。

© Token-Level Policy Gradient Loss —— 这个我觉得最关键。standard GRPO在算loss的时候是先per-sample做token平均、再per-batch做sample平均:

Lsample-mean=1Ni=1N1τit=1τit(i)L^{\text{sample-mean}} = \frac{1}{N} \sum_{i=1}^N \frac{1}{|\tau_i|} \sum_{t=1}^{|\tau_i|} \ell_t^{(i)}

这种聚合方式下,长trajectory里每个token的权重会被1/τi1/|\tau_i|稀释掉。DAPO直接改成token级求和、batch级平均:

Ltoken-mean=1iτii=1Nt=1τit(i)L^{\text{token-mean}} = \frac{1}{\sum_i |\tau_i|} \sum_{i=1}^N \sum_{t=1}^{|\tau_i|} \ell_t^{(i)}

这样每个token的权重就一致了,长sequence不会被吃掉。

(d) Overlong Reward Shaping —— 对超长被截断的sample用一个soft penalty(length-aware的reward降权)而不是直接置零,避免gradient突然变成噪声。

最终在Qwen2.5-32B上做到了AIME 50分,号称SOTA。

启发:

multi-agent场景下,sample-mean聚合的稀释问题不是只发生在长sequence上,更严重的是agent间相互稀释——agent 1输出100 token,agent 2输出500 token,按sample-mean聚合的话agent 2的credit信号会被压得很低。如果把CAD-GRPO的per-agent advantage A^i\hat{A}_i按token-level loss聚合(而不是先per-agent取平均再加起来),可能会让信号更干净一些。但这里有个细节我还没想清楚:CAD-GRPO的A^i\hat{A}_i本来就是per-agent的,token-level的展开应该是直接展到tlogπi(at(i))A^i\sum_t \nabla \log \pi_i(a_t^{(i)}) \cdot \hat{A}_i这一项里就完事了,不太会和DAPO的token-mean冲突。可能DAPO的trick在CAD-GRPO场景下更像是一个orthogonal的改进,能叠就叠上。

(a)的Clip-Higher其实在multi-agent场景下也值得想一下。如果某个agent本身contributionβi\beta_i就比较小,它的policy gradient天然就弱,然后再被对称clip一刀,可能更难探索新行为,懒惰agent现象会更明显。所以clip-higher在multi-agent里大概率是有正面作用的。

1.2 GiGPO: Group-in-Group Policy Optimization for LLM Agent Training (arXiv:2505.10978)

GiGPO解决的是long-horizon agent training(ALFWorld、WebShop这种)的credit assignment——standard GRPO的advantage是trajectory-level的(一条τ\tau一个A(τ)A(\tau)),但agent task里很多关键决策发生在中间step上,trajectory-level的分辨率不够。

核心idea: 在外层的trajectory-level group下嵌套一个内层的step-level group。具体做法是:把一个batch里所有trajectory的step按"重复出现的anchor state"聚合(比如不同trajectory里都进入了"打开冰箱"这个state),然后在同一个anchor state下不同action之间算relative advantage作为step-level信号。最终的step-level advantage是trajectory-level和同state下相对advantage的加权和:

Astep(st,at)=Atraj(τ)+αr(st,at)μsσsA^{\text{step}}(s_t, a_t) = A^{\text{traj}}(\tau) + \alpha \cdot \frac{r(s_t, a_t) - \mu_s}{\sigma_s}

其中μs,σs\mu_s, \sigma_s是所有trajectory里在state ss下采样到的rollout的均值和标准差。

启发:

理论上可以把两者串联起来:agent-level (CAD-GRPO) → step-level (GiGPO) → token-level (DAPO),构成一个完整的credit分解链。这个想法挺naive但其实可能有意思。如果final advantage可以同时考虑per-agent的边际贡献、per-step的局部贡献、per-token的细粒度梯度,那理论上信号会比单一粒度的GRPO干净很多。当然这是后话,目前先把CAD-GRPO本体跑通再说,否则一上来就把三个改造叠在一起debug肯定崩。

GiGPO另一个比较关键的细节是它的"anchor state聚合"假设——假定不同trajectory真的会经过同一个state。这个在ALFWorld这种离散state space里成立,但LLM agent的state本身就是一段history text,state空间几乎是连续的,要做grouping需要先做state representation的clustering。这块如果以后真要做扩展,应该也是一个比较重的工程项目。

1.3 MAPPA: Scaling Multiagent Systems with Process Rewards (arXiv:2601.23228)

申报书引用文献里[17]那篇。MAPPA(Multi-Agent Process-aware Policy Allocation)。

核心idea: 多智能体LLM RL里team reward只在最后才给,per-action的credit没有信号。MAPPA的解决方案是用一个外部AI coach(一般是更强的模型,比如GPT-4)做per-action的process reward打分,再加一个root-cause analysis的步骤——把错误归因到具体哪个agent的哪个action上。在AMC上做到+7.8~17.2pp,AIME上+5.0~17.5pp。

形式化下大概长这样:对一条轨迹τ={a1(1),a2(2),,aT(N)}\tau = \{a_1^{(1)}, a_2^{(2)}, \ldots, a_T^{(N)}\}(其中at(i)a_t^{(i)}表示agent ii在时刻tt的action),coach LLM对每个action单独打一个process reward ρt\rho_t

ρt=Coach(at(i)contextt,Rteam(τ))\rho_t = \text{Coach}(a_t^{(i)} \mid \text{context}_t, R_{\text{team}}(\tau))

然后把这些per-action的ρt\rho_t加权聚合到对应agent的policy gradient里。

启发:

MAPPA的优势在于可以做per-action粒度(process reward)

但是这里我想到一个比较有意思的结合点:MAPPA的per-action process reward可以作为CAD-GRPO的质量指标qiq_i。具体来说,把coach对agent ii所有action的打分聚合成一个标量(比如取平均或加权和),作为qi(b,k)q_i^{(b,k)}喂进CAD-GRPO的回归里:

R(τ)μ+αb+i=1NβiqiMAPPA(τ)+ϵR(\tau) \approx \mu + \alpha_b + \sum_{i=1}^N \beta_i \cdot q_i^{\text{MAPPA}}(\tau) + \epsilon

这样的话,CAD-GRPO把语言空间的per-action signal聚合成了per-agent的边际贡献,两者的优势就能拼起来:MAPPA提供细粒度的quality proxy,CAD-GRPO负责把这个proxy映射成统计意义上的"边际贡献"。

不过MAPPA的coach开销不低,每条trajectory里每个action都要额外的LLM call。如果把它嵌进CAD-GRPO作为qiq_i,CAD-GRPO就会变成"非零开销"了,与申报书里"零开销"的核心claim矛盾。所以可以考虑在复杂场景如数学推理、AMC/AIME这类里给一个质量更高的qiq_i,让CAD-GRPO的回归更有解释力,但standalone版本仍然只用cheap可验证指标保证零开销。

1.4 Dr.MAS: Stable Reinforcement Learning for Multi-Agent LLM Systems via Per-Agent Advantage Normalization (arXiv:2602.08847)

核心idea: standard multi-agent GRPO直接共享team-level的(μG,σG)(\mu_G, \sigma_G)来归一化所有agent的advantage:

Aknaive(τ)=R(τ)μGσGA^{\text{naive}}_k(\tau) = \frac{R(\tau) - \mu_G}{\sigma_G}

问题在于不同agent的reward分布可能差异很大(角色异构、role-specific的reward shape),用一个共享σG\sigma_G归一化会导致某些agent的advantage scale完全不对,部分agent的gradient要么过大要么趋近于0,结果就是出现lazy agent现象。

Dr.MAS的方案是per-agent的(μk,σk)(\mu_k, \sigma_k)归一化,每个agent用自己的reward分布做归一化:

Ak(τ)=Rk(τ)μkσk,μk=1GτGRk(τ), σk=std({Rk(τ)}τG)A_k(\tau) = \frac{R_k(\tau) - \mu_k}{\sigma_k}, \quad \mu_k = \frac{1}{|G|}\sum_{\tau \in G} R_k(\tau), \ \sigma_k = \text{std}(\{R_k(\tau)\}_{\tau \in G})

零额外开销,因为μk,σk\mu_k, \sigma_k都是从已有batch里直接算出来的。

启发(也是我做申报书的时候反复想的关键点):

Dr.MAS只归一化分解。具体来说,Dr.MAS里的Rk(τ)R_k(\tau)依然是team reward本身(或者某种per-agent的proxy),它没有把"agent iiRR的边际贡献"和"其他agent的影响"分开。RkR_k里依然包含其他agent行为带来的混淆,只是用agent-specific的scale做归一化让数值看起来稳定一点而已。信用混淆的根源没有被真正解决。

CAD-GRPO的核心区别在于通过岭回归显式地把RR分解成iβiqi\sum_i \beta_i q_i,估计的β^i\hat{\beta}_i是真正的per-agent边际贡献系数(在线性可加性假设下)。归一化和分解是两码事。

我觉得在合成实验里,应该能看到比较明显的对比——当agent间贡献差异显著时(比如"强弱配对",一个strong agent + 一个weak agent),CAD-GRPO对βi\beta_i的估计精度应该严格优于Dr.MAS。Dr.MAS给的是(Rμk)/σk(R - \mu_k)/\sigma_k,本质上还是把team信号原样传给每个agent;CAD-GRPO能识别出"strong agent的β1\beta_1 >> weak agent的β2\beta_2",从而在policy update里给两个agent传递正确scale的梯度信号。

不过Dr.MAS的优势是没有任何质量指标qiq_i的依赖,用的是team reward本身,不需要额外的可验证proxy。这一点也警示了如果CAD-GRPO中qiq_i的选择本身就很糟糕、对RR的解释力不足(R2<0.3R^2 < 0.3),CAD-GRPO的β^i\hat{\beta}_i就会失真,不如Dr.MAS稳。

二、开发 sub2api 软件

基于new-api项目,搭建了一个一个极致轻量的静态网站,用来把我的的 Coding Plan 抽象成可分发给其他用户使用的 API 令牌账本。

motivation其实就是因为目前用的中转感觉总是被掺过水的,于是我打算和我的朋友直接自己拼Claude的max 20x Coding Plan。但是两个人用肯定怎么用都用不完。身边有一些朋友也有自己的项目要蹬,但是直接把账号给别人显然是不行的(节点不同的话,整个车队就都废了,同时也不方便管理,因为毕竟还是希望大家可以把token额度AA,这样最promising),所以就想着自己搓个中转,把额度抽象成一个一个的令牌(token),每个令牌独立计费、可吊销、有自己的limit,分给谁都不会动到我自己的账号本体。

同时我自己已经和几十个中转商家打过交道了,其中有好几个商家都是自己魔改的new-api这一个框架来分发令牌。所以我也打算做一个类似的,就只需要实现最轻量化的功能即可。new-api本身是一个LLM API中转网关,能把不同上游服务(OpenAI、Anthropic、各种国内厂商)的接口统一成OpenAI格式对外暴露,同时支持多用户、多令牌、独立计费。所以本质上我没干啥重活,把后端起起来、把上游配成我的Anthropic Claude账号,然后前端套一个静态分发页面就可以了。整个东西部署在一个2C2G的小VPS上。

实现上几个比较关键的点:

  1. 分发可控:每个令牌独立limit、独立有效期、可以一键吊销。我作为admin能看每个令牌实时的消耗情况。
  2. 加密:账号本体的cookie/api key只存在我自己的服务器上,分发出去的只是hash过的虚拟令牌(new-api自己的格式),从协议层面上避免了账号本身泄露。
  3. 轻量:前端就是一个纯静态的Vue页面(连构建都不需要,HTML+CDN直接拉Vue 3),后端只有一个new-api容器。整个repo拢共没几个文件。
  4. OpenAI兼容:因为new-api统一成了OpenAI格式,我朋友拿到令牌之后可以直接当OpenAI兼容的API用,套现有的SDK(openai-python、langchain)零修改。

全过程cc代理解放大脑(不过我感觉我现在用的某鱼拼车的套餐又双叒叕被掺水了,一个小需求花了我12刀,搞笑呢吧…),当然在manual update的时候发现Claude Code的官方SDK对于API endpoint的鉴权方式好像比较挑剔,需要在中转层手动处理一下Anthropic-Beta header才能对上,导致我又多进行了几个turn才调好hhh。整体来说工作量不大,关键收获是顺便看了一遍new-api的代码,对一个生产级LLM gateway是怎么做token管理、流式转发、计费的有了大致的概念,对后续如果要做multi-agent训练框架(需要管rollout、agent间通信、reward聚合)多少有点参考价值。

三、学习经典框架开发实践

这周还发现了一个不错的博客,hello-agents教程第六章 框架开发实践。这个教程主要是教如何从零开始构建agent,第六章把当前主流的几个agent框架——AutoGen、AgentScope、CAMEL、LangGraph挨个过了一遍,每个都给出了完整的hands-on case。我之前都听说过这些框架,这次又看了一便中文教程查漏补缺一下。

3.1 LangGraph——把agent看成状态机

第六章里花了最多篇幅讲的是LangGraph。核心思想是把agent的执行过程建模成一个有向图,节点是具体的计算步骤(LLM调用、tool执行),边是节点间的跳转逻辑。

这个设计最关键的一点是它原生支持循环。standard LangChain的Chain是DAG,没法表达"当条件不满足就回到上一步重新生成"这种reflection或者self-correction的pattern。LangGraph通过显式的状态机模型把loop抬到了极高的高度:

State → Node A (LLM call) → Edge (condition) → Node B (tool exec)
                                           ↘ Node A (loop back if needed)

实际写起来就是定义一个全局State(一般是一个dict或者TypedDict),每个node接收State、修改State、返回新State。Edge要么是unconditional(直接接到下一个node),要么是conditional(根据State的某个字段决定下一步)。

和RL里policy的rollout循环非常像,一个policy network不停产生action,环境根据某个condition决定终止,整个过程可以画成一个state-action图。从credit assignment的角度看,LangGraph的图模型其实给了一个很直观的方式去定位"哪一步贡献了reward",因为每个node都是显式标注的。

3.2 AutoGen / AgentScope / CAMEL——multi-agent的不同抽象

AutoGen和AgentScope主要是面向multi-agent协作的框架,但抽象层次不太一样。AutoGen的核心抽象是ConversableAgent——每个agent是一个能"对话"的实体,agent间通信走的是消息队列,整个系统的逻辑由对话历史驱动。AgentScope则更"工程化"一点,明确区分了agent、message、pipeline三个层次,pipeline是显式的执行流。

CAMEL的novelty是它的role-playing抽象——agent不是一个泛化的"消息处理器",而是被绑定到一个具体的角色(user、assistant、critic、tester)上,role本身决定了它的行为模式。我感觉和StrongerMAS、SHARP里的"agent role assignment"是同一回事——都是把agent的"角色"作为一个首要概念,然后在这个role基础上做reward、做group化。

3.3 启发

  1. 貌似我目前读过且有印象的agent框架基本都把per-agent contribution当成黑盒。CAD-GRPO的batch-level岭回归如果要在真实framework里跑起来,需要框架本身能暴露出每个agent的quality proxy(比如code agent的compile success、test pass rate)。这些framework的接口设计能不能容纳qiq_i,是工程上要考虑的。

  2. 下周的Claude Code harness——这次过完几个开源框架其实是给下周读Claude Code源码做铺垫。Claude Code本身可以看成一个非常成熟的"single-LLM agent + tool use loop"系统,它的tool use循环、context management、multi-step reasoning和上面这些open-source framework一定有共同的核心抽象(state machine + tool dispatch)。先把开源框架的设计哲学过一遍,再去看Claude Code的实现,应该能更快定位到关键设计选择。

四、to-do

4.1 复现Claude Code的harness

这个是上周就立的flag,本周因为出于兴趣原因刷了太多GitHub项目因此暂时没动。下周打算正式开工。

(1) 理解架构:tool use loop(Claude怎么决定何时调用tool、tool result怎么feedback回context)、context management(长对话下怎么管理history、有没有summarization机制)、multi-agent管理(subagent怎么调度、agent间状态怎么同步)。

(2) 写一个最简化版本:在理解架构的基础上,自己用Python实现一个最小版(可能就是single-agent的tool use loop + simple context summarization),自己手写过一个简化版之后再看现有框架(比如veRL或AutoGen)会更有针对性。

4.2 继续读Multi-Agent Credit Assignment方向paper

本周读完4篇之后,下周的reading list计划如下:

  • CCPO (arXiv:2603.21563) ——也是对标的baseline之一,本周计划但没读完,下周补。重点关注它的反事实轨迹生成机制(怎么定义"消融某个agent",是直接mask还是replay)以及它的开销分析(claim是~2x,要verify一下)。
  • C3 (arXiv:2603.06859) ——leave-one-out credit assignment,思路是"留一法"——对每个agent单独跑一次去除它的轨迹。和CCPO思路相近但做的是step-level。读完之后让Claude做一个CCPO/C3/SHARP的横向对比表。
  • StrongerMAS / AT-GRPO (arXiv:2510.11062) ——之前已经看过一遍,但当时主要看的是motivation部分。下周再过一遍,重点关注实现细节,特别是它怎么实现"agent-turn grouping"——这个是申报书第三部分(实验)里要复现的baseline,得把代码层面也搞清楚。

时间允许的话再加一篇Stratified GRPO (2510.06214)或者MASPRM (2510.24803),这两篇都涉及"分层处理异构性"的思路,和CAD-GRPO的batch-level回归在某种意义上是互补的。