本周继续围绕 multi-agent credit assignment 精读 baseline:DAPO、GiGPO、MAPPA、Dr.MAS。
另外做了一个 sub2api 令牌分发工具,并补了一轮经典 agent 框架开发实践。
本周清单
- 阅读 DAPO / GiGPO / MAPPA / Dr.MAS
- 开发 sub2api,用来将 Coding Plan 分发为 API 令牌
- 学习经典 agent 框架开发实践
- 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从对称的拆成上下不对称的,把上界放宽,给低概率token更多被rollout选中的机会。直觉上就是不希望policy在已经偏好的token上继续过拟合,从而压住entropy collapse。
(b) Dynamic Sampling —— 把那些一整组rollout全对(accuracy=1)或者全错(accuracy=0)的batch直接丢掉。原因是这种batch里的分子整体是0,对应的policy gradient也是0,喂进去纯属浪费一次forward。
© Token-Level Policy Gradient Loss —— 这个我觉得最关键。standard GRPO在算loss的时候是先per-sample做token平均、再per-batch做sample平均:
这种聚合方式下,长trajectory里每个token的权重会被稀释掉。DAPO直接改成token级求和、batch级平均:
这样每个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 按token-level loss聚合(而不是先per-agent取平均再加起来),可能会让信号更干净一些。但这里有个细节我还没想清楚:CAD-GRPO的本来就是per-agent的,token-level的展开应该是直接展到这一项里就完事了,不太会和DAPO的token-mean冲突。可能DAPO的trick在CAD-GRPO场景下更像是一个orthogonal的改进,能叠就叠上。
(a)的Clip-Higher其实在multi-agent场景下也值得想一下。如果某个agent本身contribution就比较小,它的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的(一条一个),但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的加权和:
其中是所有trajectory里在state 下采样到的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。
形式化下大概长这样:对一条轨迹(其中表示agent 在时刻的action),coach LLM对每个action单独打一个process reward :
然后把这些per-action的加权聚合到对应agent的policy gradient里。
启发:
MAPPA的优势在于可以做per-action粒度(process reward)
但是这里我想到一个比较有意思的结合点:MAPPA的per-action process reward可以作为CAD-GRPO的质量指标。具体来说,把coach对agent 所有action的打分聚合成一个标量(比如取平均或加权和),作为喂进CAD-GRPO的回归里:
这样的话,CAD-GRPO把语言空间的per-action signal聚合成了per-agent的边际贡献,两者的优势就能拼起来:MAPPA提供细粒度的quality proxy,CAD-GRPO负责把这个proxy映射成统计意义上的"边际贡献"。
不过MAPPA的coach开销不低,每条trajectory里每个action都要额外的LLM call。如果把它嵌进CAD-GRPO作为,CAD-GRPO就会变成"非零开销"了,与申报书里"零开销"的核心claim矛盾。所以可以考虑在复杂场景如数学推理、AMC/AIME这类里给一个质量更高的,让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的来归一化所有agent的advantage:
问题在于不同agent的reward分布可能差异很大(角色异构、role-specific的reward shape),用一个共享归一化会导致某些agent的advantage scale完全不对,部分agent的gradient要么过大要么趋近于0,结果就是出现lazy agent现象。
Dr.MAS的方案是per-agent的归一化,每个agent用自己的reward分布做归一化:
零额外开销,因为都是从已有batch里直接算出来的。
启发(也是我做申报书的时候反复想的关键点):
Dr.MAS只归一化不分解。具体来说,Dr.MAS里的依然是team reward本身(或者某种per-agent的proxy),它没有把"agent 对的边际贡献"和"其他agent的影响"分开。里依然包含其他agent行为带来的混淆,只是用agent-specific的scale做归一化让数值看起来稳定一点而已。信用混淆的根源没有被真正解决。
CAD-GRPO的核心区别在于通过岭回归显式地把分解成,估计的是真正的per-agent边际贡献系数(在线性可加性假设下)。归一化和分解是两码事。
我觉得在合成实验里,应该能看到比较明显的对比——当agent间贡献差异显著时(比如"强弱配对",一个strong agent + 一个weak agent),CAD-GRPO对的估计精度应该严格优于Dr.MAS。Dr.MAS给的是,本质上还是把team信号原样传给每个agent;CAD-GRPO能识别出"strong agent的 >> weak agent的",从而在policy update里给两个agent传递正确scale的梯度信号。
不过Dr.MAS的优势是没有任何质量指标的依赖,用的是team reward本身,不需要额外的可验证proxy。这一点也警示了如果CAD-GRPO中的选择本身就很糟糕、对的解释力不足(),CAD-GRPO的就会失真,不如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上。
实现上几个比较关键的点:
- 分发可控:每个令牌独立limit、独立有效期、可以一键吊销。我作为admin能看每个令牌实时的消耗情况。
- 加密:账号本体的cookie/api key只存在我自己的服务器上,分发出去的只是hash过的虚拟令牌(new-api自己的格式),从协议层面上避免了账号本身泄露。
- 轻量:前端就是一个纯静态的Vue页面(连构建都不需要,HTML+CDN直接拉Vue 3),后端只有一个new-api容器。整个repo拢共没几个文件。
- 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 启发
-
貌似我目前读过且有印象的agent框架基本都把per-agent contribution当成黑盒。CAD-GRPO的batch-level岭回归如果要在真实framework里跑起来,需要框架本身能暴露出每个agent的quality proxy(比如code agent的compile success、test pass rate)。这些framework的接口设计能不能容纳,是工程上要考虑的。
-
下周的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回归在某种意义上是互补的。