1. 多Agent系统到底在解决什么问题
1.1 从一个真实场景说起
假设你手头有一个仓储机器人的调度任务:几十台AGV小车在同一个仓库里跑来跑去,有的负责拣货、有的负责补货、有的负责充电。每台小车都有自己的传感器、自己的决策逻辑,但它们共享同一个物理空间,彼此之间会互相影响——一台车堵在通道口,后面所有车都得绕路。这种场景就是典型的多Agent系统(Multi-Agent System,MAS)。
单Agent的强化学习我们都很熟了:一个智能体在环境里试错,学到一个策略,让累积回报最大化。但现实世界里,绝大多数有意思的问题都不是“一个人唱独角戏”。自动驾驶车队、无人机编队、游戏里的多角色配合、电网里的分布式能源调度、甚至股票市场里的多个交易策略互相博弈——这些都是多个决策者同时存在、同时学习、互相影响的场景。
多智能体强化学习(Multi-Agent Reinforcement Learning,MARL)就是专门处理这类问题的技术分支。它要解决的核心矛盾是:每个智能体都在学习,环境本身因为其他智能体的学习而不断变化,这就导致经典的“马尔可夫假设”不再成立——你面对的环境是非平稳的。
1.2 多Agent系统的三种协作模式
在动手写代码之前,得先搞清楚你的多Agent系统属于哪种协作模式,因为这直接决定了算法选型和训练架构。
完全合作型:所有智能体共享同一个奖励信号,目标一致。比如多机械臂协同装配一个零件,任何一个臂出错,整体任务失败,大家拿到的奖励是一样的。这种场景下,核心问题是怎么做信用分配——任务成功了,到底是谁的功劳?MAPPO、MADDPG这类算法就是为这种场景设计的。
完全竞争型:智能体之间零和博弈,一方所得即另一方所失。比如围棋、德州扑克这类对抗游戏。这种场景下,每个智能体只需要最大化自己的收益,但对手的策略在变,所以需要用到自博弈(Self-Play)的思路。
混合型:既有合作又有竞争,这是最贴近现实的。比如足球机器人比赛,队友之间要配合,但和对手之间是竞争关系。这种场景最复杂,通常需要结合博弈论和强化学习的方法。
我个人的经验是,新手入门MARL,最好从完全合作型开始,因为奖励设计最直观,调试起来也最容易定位问题。等你把合作型跑通了,再去碰混合型,会顺畅很多。
1.3 为什么传统单Agent方法直接套用会翻车
很多人第一反应是:我把其他智能体也当成环境的一部分不就行了?每个智能体独立跑一个DQN或者PPO,各学各的。这个思路叫Independent Learning(独立学习),听起来简单,但实际跑起来问题很大。
最大的问题是非平稳性。你想想,智能体A在训练过程中策略一直在变,对智能体B来说,它所面对的环境(包含了A的行为)就一直在变。B刚学会怎么应对A的旧策略,A已经更新了,B又得重新适应。这就像你在跟一个不断改变打法的人下棋,你永远摸不清对方的套路。
第二个问题是信用分配。在合作场景下,团队拿到了奖励,但每个智能体贡献了多少?如果简单地给每个智能体都发同样的奖励,那就会出现“搭便车”现象——有的智能体什么都不干也能拿奖励,学习动力不足。
第三个问题是维度爆炸。如果要把所有智能体的联合状态和联合动作都纳入一个中心化的Q网络,状态空间和动作空间会随智能体数量指数级增长。5个智能体、每个10个动作,联合动作空间就是10的5次方,根本训不动。
所以,MARL的核心技术挑战就是围绕这三个问题展开的:怎么处理非平稳性、怎么做信用分配、怎么控制计算复杂度。
2. 核心算法拆解与选型逻辑
2.1 从IQL到VDN:值分解家族的演进
值分解(Value Decomposition)是合作型MARL里最经典的一条技术路线。它的核心思想是:每个智能体学一个局部Q值,然后通过某种方式把这些局部Q值组合成全局Q值。
IQL(Independent Q-Learning)是最朴素的版本,每个智能体独立学自己的Q函数,互不干涉。它的问题前面说了,非平稳性严重,但在智能体数量少、耦合弱的情况下,其实也能跑出不错的效果。我试过在3个智能体的简单协作任务上跑IQL,收敛虽然慢,但最终策略质量不差。
VDN(Value Decomposition Networks)做了一个关键假设:全局Q值等于所有局部Q值之和。这个假设很强,但实现简单,训练稳定。它的局限性在于,很多任务的全局Q值并不是简单的加和关系——比如一个任务需要两个智能体同时到达某个位置才能得分,这种“与”逻辑就没法用加法表示。
QMIX改进了VDN,不再用求和,而是用一个单调混合网络来组合局部Q值。所谓单调,就是保证全局Q值对每个局部Q值的偏导数为正——这意味着每个智能体局部Q值增大时,全局Q值也增大。这个约束保证了贪心策略的一致性:每个智能体选自己局部Q值最大的动作,等价于全局Q值最大。QMIX比VDN表达能力强很多,但实现复杂度也上去了。
QTRAN进一步放松了单调性约束,试图用更一般的变换来表示全局Q值。理论上更强大,但实际训练中经常不稳定,调参难度大。我的建议是,除非你有明确的需求证明QMIX的表达能力不够,否则优先用QMIX。
2.2 策略梯度路线:MADDPG与MAPPO
值分解方法只能处理离散动作空间,而且对合作型任务有较强的假设。如果你面对的是连续动作空间(比如机器人控制),或者混合型任务,就得走策略梯度路线。
MADDPG(Multi-Agent DDPG)是DDPG的多智能体扩展。它的核心创新是“集中训练、分散执行”(Centralized Training with Decentralized Execution,CTDE)。具体来说,每个智能体有一个Actor网络(只用自己的局部观测做决策)和一个Critic网络(用所有智能体的联合观测和动作来评估)。训练时Critic能看到全局信息,执行时Actor只用局部信息。这个架构巧妙地解决了非平稳性问题——Critic因为能看到全局信息,所以能准确评估每个智能体的贡献,缓解了信用分配问题。
MAPPO(Multi-Agent PPO)是PPO的多智能体版本,同样采用CTDE架构。相比MADDPG,MAPPO的优势在于训练更稳定、对超参数更鲁棒。我实测下来,在大多数合作型任务上,MAPPO的收敛速度和最终性能都不输MADDPG,而且调参工作量小很多。如果你刚开始做MARL项目,我强烈建议从MAPPO入手。
这里有个关键细节:MAPPO的Critic输入可以是全局状态(所有智能体的观测拼接),也可以是每个智能体独立的局部Critic。前者叫“共享Critic”,后者叫“独立Critic”。共享Critic能更好地处理信用分配,但要求所有智能体的观测空间一致;独立Critic更灵活,但可能学不到全局信息。我的经验是,如果智能体同质(比如都是同型号机器人),用共享Critic;如果异质(比如一个侦察机加一个打击机),用独立Critic。
2.3 算法选型速查表
| 算法 | 动作空间 | 协作模式 | 训练稳定性 | 实现难度 | 适用场景 |
|---|---|---|---|---|---|
| IQL | 离散 | 任意 | 一般 | 低 | 智能体少、耦合弱 |
| VDN | 离散 | 合作 | 高 | 低 | 简单合作任务 |
| QMIX | 离散 | 合作 | 高 | 中 | 复杂合作任务 |
| MADDPG | 连续 | 任意 | 中 | 中 | 连续控制、混合型 |
| MAPPO | 离散/连续 | 任意 | 高 | 中 | 通用首选 |
| QTRAN | 离散 | 合作 | 低 | 高 | 理论研究 |
选型的时候,先看动作空间是离散还是连续,再看协作模式是纯合作还是混合,最后看你对训练稳定性的要求。大多数工程场景,MAPPO都是最稳妥的选择。
3. 环境建模与实操要点
3.1 怎么把现实问题抽象成MARL环境
环境建模是MARL项目里最容易被低估的环节。很多人算法调了半天没效果,最后发现是环境建模就有问题。
状态空间设计:每个智能体的局部观测应该包含什么?原则是“足够决策,但不冗余”。比如仓储机器人,局部观测至少要有自己的位置、速度、目标位置,以及周围一定范围内其他机器人的相对位置。如果你把所有机器人的绝对位置都塞进去,观测空间会很大,学习效率低;但如果只给相对位置,又可能丢失全局信息。我的做法是,先给一个最小观测集,跑一版基线,然后根据学习曲线判断是否需要增加信息。
动作空间设计:离散动作还是连续动作?如果底层控制已经封装好了(比如给你一个“移动到某点”的接口),那动作空间就是离散的目标点选择;如果需要直接控制轮速,那就是连续动作。离散动作空间小,学习快,但控制精度低;连续动作空间大,学习慢,但控制平滑。工程上,能离散就离散,除非精度要求真的很高。
奖励函数设计:这是最考验功力的地方。合作型任务里,奖励通常分两部分:全局奖励(团队完成任务的奖励)和局部奖励(个体行为的塑形奖励)。全局奖励保证方向正确,局部奖励加速学习。但局部奖励不能乱加,否则会引导智能体学出“刷分”行为。比如你给“靠近目标”一个正奖励,智能体可能会在原地来回晃动来刷这个奖励,而不是真正去完成任务。我的经验是,局部奖励只用来做“引导”,权重不要超过全局奖励的30%。
3.2 训练架构:CTDE的工程实现
CTDE(集中训练、分散执行)是当前MARL的主流范式,但工程实现上有几个坑要注意。
参数共享:如果所有智能体是同质的,强烈建议共享Actor网络参数。这样做的好处是:第一,样本效率高,所有智能体的经验都用来更新同一个网络;第二,智能体数量变化时不需要改网络结构。但共享参数要求所有智能体的观测空间和动作空间完全一致,如果不同质,就只能各自独立。
经验回放:值分解方法(VDN、QMIX)通常用经验回放池,因为它们是离策略算法。但MAPPO是on-policy的,不能用经验回放,只能用当前策略采集的数据。这意味着MAPPO的样本效率天然低于QMIX,但训练更稳定。如果你样本采集成本很高(比如真实机器人),优先考虑QMIX;如果是在仿真环境里,样本不要钱,MAPPO更省心。
并行环境:MARL训练通常需要大量样本,单环境采集太慢。我的做法是开多个并行环境,每个环境跑不同的随机种子,然后把数据汇总。Python里可以用multiprocessing或者ray来实现。注意,并行环境里的随机种子要设置好,否则所有环境跑出一模一样的数据,就白并行。
3.3 超参数调优的实战经验
MARL的超参数比单Agent多得多,而且相互耦合。我整理了一份常用超参数的起始值和调整方向。
| 超参数 | 典型起始值 | 调整方向 | 影响 |
|---|---|---|---|
| 学习率 | 3e-4 | 训练不稳定时降低 | 太大导致震荡,太小收敛慢 |
| 折扣因子γ | 0.95 | 任务周期长时增大 | 越大越看重长期回报 |
| GAE λ | 0.95 | 偏差大方差小时增大 | 平衡偏差与方差 |
| 裁剪范围ε | 0.2 | 策略更新幅度大时减小 | PPO专用,控制更新步长 |
| 熵系数 | 0.01 | 探索不足时增大 | 鼓励探索,太大导致策略随机 |
| 批大小 | 4000 | 显存允许时增大 | 越大梯度估计越准 |
| 训练轮数 | 10 | 过拟合时减小 | 每批数据的复用次数 |
我踩过最大的坑是学习率。MAPPO默认3e-4在单Agent任务上没问题,但在多Agent任务上,因为多个智能体同时更新,等效学习率会放大,导致训练震荡。后来我把学习率降到1e-4,训练就稳了。所以,多Agent场景下,学习率要比单Agent保守一些。
4. 完整实操流程:从零搭建MAPPO训练系统
4.1 环境搭建与依赖安装
我以Python生态为例,搭建一个MAPPO的训练框架。核心依赖就几个:gymnasium(环境接口)、torch(神经网络)、numpy(数值计算)。如果你要用现成的MARL环境,可以装pettingzoo,它提供了很多标准的多Agent环境。
pip install gymnasium torch numpy pettingzoo如果你要自己写环境,继承gymnasium.Env就行。注意,多Agent环境的状态和动作都是字典或者列表形式,每个智能体一个条目。
4.2 网络结构定义
MAPPO的Actor和Critic网络结构不复杂,但有几个细节要注意。
import torch import torch.nn as nn class Actor(nn.Module): def __init__(self, obs_dim, act_dim, hidden=64): super().__init__() self.net = nn.Sequential( nn.Linear(obs_dim, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, act_dim) ) def forward(self, obs): logits = self.net(obs) return torch.distributions.Categorical(logits=logits) class Critic(nn.Module): def __init__(self, global_obs_dim, hidden=64): super().__init__() self.net = nn.Sequential( nn.Linear(global_obs_dim, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, 1) ) def forward(self, global_obs): return self.net(global_obs)Actor输入是局部观测,输出是动作分布;Critic输入是全局状态(所有智能体观测的拼接),输出是状态价值。激活函数用Tanh而不是ReLU,是因为Tanh的输出范围有界,策略更新更平滑。这个细节在单Agent里影响不大,但在多Agent里,多个策略同时更新,平滑性很重要。
4.3 数据采集与优势估计
MAPPO是on-policy算法,数据采集和更新是交替进行的。每一轮采集一批轨迹,计算优势函数,然后更新网络。
def compute_gae(rewards, values, dones, gamma=0.99, lam=0.95): advantages = [] gae = 0 next_value = 0 for t in reversed(range(len(rewards))): if dones[t]: delta = rewards[t] - values[t] gae = delta else: delta = rewards[t] + gamma * next_value - values[t] gae = delta + gamma * lam * gae advantages.insert(0, gae) next_value = values[t] returns = [adv + val for adv, val in zip(advantages, values)] return advantages, returnsGAE(Generalized Advantage Estimation)是PPO的核心组件,它通过λ参数在偏差和方差之间做权衡。λ=0时退化为单步TD误差,偏差大方差小;λ=1时是蒙特卡洛估计,偏差小方差大。0.95是个经验值,大多数任务上都work。
这里有个多Agent特有的细节:优势估计是每个智能体独立算的,但Critic用的是全局状态。这意味着每个智能体共享同一个状态价值基线,但各自的优势不同。这个设计能有效缓解信用分配问题——如果团队表现好,但某个智能体贡献小,它的优势就会低,策略更新幅度就小。
4.4 策略更新与裁剪
PPO的裁剪机制是它稳定性的来源。更新时,计算新旧策略的概率比,如果比值超出[1-ε, 1+ε]范围,就裁剪掉,不让梯度继续增大。
def ppo_update(actor, critic, optimizer, batch, clip_eps=0.2, epochs=10): obs, actions, old_log_probs, advantages, returns = batch for _ in range(epochs): dist = actor(obs) new_log_probs = dist.log_prob(actions) ratio = torch.exp(new_log_probs - old_log_probs) surr1 = ratio * advantages surr2 = torch.clamp(ratio, 1-clip_eps, 1+clip_eps) * advantages actor_loss = -torch.min(surr1, surr2).mean() values = critic(obs).squeeze() critic_loss = nn.MSELoss()(values, returns) loss = actor_loss + 0.5 * critic_loss optimizer.zero_grad() loss.backward() nn.utils.clip_grad_norm_(actor.parameters(), 0.5) nn.utils.clip_grad_norm_(critic.parameters(), 0.5) optimizer.step()梯度裁剪(clip_grad_norm_)是必须的,多Agent训练时梯度容易爆炸,不裁剪的话训练很容易崩。裁剪阈值0.5是个保守值,如果你发现训练太慢,可以适当放宽到1.0。
4.5 训练循环与日志监控
把上面的模块串起来,就是一个完整的训练循环。
for episode in range(total_episodes): obs = env.reset() trajectories = [] for step in range(max_steps): actions = {} log_probs = {} for agent_id in env.agents: dist = actor(obs[agent_id]) action = dist.sample() actions[agent_id] = action log_probs[agent_id] = dist.log_prob(action) next_obs, rewards, dones, infos = env.step(actions) global_obs = torch.cat([obs[a] for a in env.agents]) value = critic(global_obs) trajectories.append({ 'obs': obs, 'actions': actions, 'log_probs': log_probs, 'rewards': rewards, 'value': value, 'done': dones }) obs = next_obs if all(dones.values()): break # 计算优势和回报,更新网络 batch = process_trajectories(trajectories) ppo_update(actor, critic, optimizer, batch) # 日志 if episode % 10 == 0: print(f"Episode {episode}, Avg Reward: {np.mean(episode_rewards)}")日志监控要关注几个指标:平均回报(看整体趋势)、策略熵(看探索是否充分)、价值损失(看Critic学得准不准)。如果平均回报震荡不上升,先看策略熵是不是太低(探索不足),再看价值损失是不是很大(Critic没学好)。
5. 常见问题与排查技巧实录
5.1 训练不收敛的五大原因
原因一:奖励尺度问题。多Agent任务里,全局奖励和局部奖励的尺度可能差好几个数量级。如果全局奖励是100,局部奖励是0.1,那局部奖励基本被淹没,起不到引导作用。解决办法是做奖励归一化,把所有奖励缩放到相近范围。
原因二:观测信息不足。如果智能体的局部观测里缺少关键信息(比如看不到队友位置),那它学不到协作策略。排查方法是:先做一个“上帝视角”版本,给所有智能体全局观测,如果全局观测能学会,局部观测学不会,那就是观测信息不足。
原因三:信用分配失败。表现是团队奖励上不去,但每个智能体单独看行为都合理。解决办法是换用带CTDE架构的算法(MAPPO、MADDPG),或者设计更精细的局部奖励。
原因四:非平稳性太强。如果所有智能体同时更新,环境变化太快,谁都学不好。解决办法是轮流更新——固定其他智能体的策略,只更新一个,更新几轮后再换下一个。这个技巧叫“轮流训练”,能显著提升稳定性,代价是训练时间变长。
原因五:超参数不匹配。最常见的是学习率太大、批大小太小。多Agent场景下,梯度估计的方差比单Agent大,需要更大的批大小来降方差。如果显存不够,可以用梯度累积来模拟大批大小。
5.2 智能体“摆烂”与“内卷”的应对
合作型任务里,经常出现两种极端行为。
摆烂:一个智能体发现不管自己怎么做,团队奖励都差不多,于是干脆不动了,反正有队友兜底。这是典型的“搭便车”问题。解决办法是引入“差分奖励”——每个智能体的奖励等于“团队有它时的得分”减去“团队没它时的得分”。这个差分值能准确反映个体贡献,但计算成本高,通常用近似方法。
内卷:智能体为了刷局部奖励,做出对团队无益甚至有害的行为。比如为了“靠近目标”的局部奖励,两个智能体挤在同一个位置互相阻挡。解决办法是重新设计局部奖励,加入惩罚项,或者干脆去掉局部奖励,只用全局奖励,让智能体自己学协作。
我的经验是,奖励设计宁简勿繁。一开始只用全局奖励,跑一版基线。如果学得太慢,再逐步加局部奖励,每加一个都做消融实验,确认它真的有用。
5.3 问题排查速查表
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 回报震荡不上升 | 学习率太大 | 降低学习率10倍重跑 | 用1e-4或更小 |
| 回报上升后突然崩 | 梯度爆炸 | 检查梯度范数 | 加梯度裁剪 |
| 智能体行为同质化 | 参数共享过度 | 检查是否所有智能体共享网络 | 异质智能体用独立网络 |
| 训练慢 | 样本效率低 | 检查是否on-policy | 换QMIX等off-policy算法 |
| 策略熵骤降 | 过早收敛 | 监控熵曲线 | 增大熵系数 |
| 价值损失不降 | Critic欠拟合 | 检查Critic网络容量 | 增大隐藏层或加层 |
5.4 几个反直觉的实操心得
心得一:智能体数量不是越多越好。我试过在10个智能体的任务上跑MAPPO,训练极其困难。后来降到5个,效果立刻好转。原因是智能体越多,联合状态空间越大,Critic越难学准。如果任务允许,先从小规模开始,跑通了再逐步增加。
心得二:随机种子影响巨大。MARL的训练方差比单Agent大得多,同一个算法、同一套超参数,换个随机种子可能结果天差地别。所以,评估算法时至少跑3-5个种子,取平均值,不要只看一次结果。
心得三:课程学习很管用。直接让智能体学复杂协作任务,往往学不会。可以先简化任务(比如减少智能体数量、缩小地图),等学会了再逐步增加难度。这个思路叫课程学习(Curriculum Learning),在MARL里效果特别明显。
心得四:可视化调试不可少。光看曲线很难定位问题,一定要把智能体的行为渲染出来看。很多时候,你看一眼回放就知道问题在哪——比如两个智能体一直在绕圈,那就是奖励设计有问题。
6. 从仿真到落地:工程化考量
6.1 仿真环境与真实环境的差距
仿真里训好的策略,直接搬到真实系统上,大概率会翻车。差距主要来自三个方面:传感器噪声、执行器延迟、环境动态变化。仿真里传感器是理想的,真实传感器有噪声;仿真里动作立即生效,真实执行器有延迟;仿真里环境静态,真实环境里可能有未建模的干扰。
解决办法是域随机化(Domain Randomization):训练时在仿真里随机化各种参数(传感器噪声、延迟、摩擦系数等),让策略学会适应各种条件。这样训出来的策略,对真实环境的鲁棒性会好很多。我试过在机械臂任务上做域随机化,迁移成功率从30%提升到70%以上。
6.2 分布式训练与加速
智能体数量多、环境复杂时,单机训练太慢。分布式训练是必由之路。基本架构是:多个Worker并行采集数据,一个Learner负责更新网络,Worker定期从Learner拉取最新参数。
实现上,可以用ray框架,它提供了ray.rllib,内置了MARL支持。也可以自己用multiprocessing写,但要注意进程间通信的开销。我的经验是,Worker数量不要超过CPU核心数,否则上下文切换开销会抵消并行收益。
6.3 策略部署的注意事项
训练好的策略部署到实际系统时,有几个点要注意。
推理速度:实际系统对推理延迟有要求。如果Actor网络太大,推理慢,会影响控制频率。解决办法是模型压缩——剪枝、量化、知识蒸馏。通常把网络从64x64压到32x32,性能损失很小,但推理速度能翻倍。
异常处理:实际系统里,智能体可能遇到训练时没见过的状态。这时候策略的输出可能不可靠。需要加一个异常检测模块,当观测超出训练分布时,切换到安全策略(比如紧急停止)。
在线微调:部署后,可以继续用真实数据微调策略,让它适应真实环境的特性。但要注意,在线微调有风险,可能把策略调坏。我的做法是,在线微调时用很小的学习率,并且保留一个“安全基线”,如果微调后性能下降,就回滚。
6.4 评估指标与上线标准
MARL系统的评估不能只看平均回报。我通常看这几个指标:
- 任务成功率:最直观的指标,团队完成任务的概率。
- 协作效率:完成任务的平均步数,越少越好。
- 鲁棒性:在扰动环境下的性能下降幅度。
- 个体贡献均衡度:各智能体的贡献是否均衡,避免有的累死有的闲死。
上线标准通常是:任务成功率超过基线(比如规则策略)20%以上,鲁棒性测试通过,推理延迟满足要求。三个条件都满足,才考虑上线。
7. 我踩过的坑与最后分享
7.1 三个让我印象深刻的坑
第一个坑:Critic输入用了局部观测。刚开始做MAPPO时,我图省事,Critic也只用了局部观测。结果训练极不稳定,智能体之间完全学不会协作。后来改成全局状态,问题立刻解决。CTDE的核心就在这个“C”上,Critic必须能看到全局信息,否则和独立学习没区别。
第二个坑:奖励没做归一化。全局奖励是100,局部奖励是1,结果智能体完全忽略局部奖励,学出来的行为很粗糙。后来把所有奖励缩放到[-1, 1]范围,学习效率提升明显。奖励归一化是个小细节,但影响很大。
第三个坑:并行环境种子没设好。开了8个并行环境,结果所有环境跑出一模一样的数据,等于白开。后来给每个环境设了不同的随机种子,样本多样性立刻上来了。这个坑很隐蔽,因为程序不报错,只是效率低,不容易发现。
7.2 给刚入门的朋友几条建议
如果你刚开始接触MARL,我的建议是:先跑通一个最简单的合作任务(比如两个智能体推箱子),用MAPPO,不要一上来就搞复杂场景。跑通之后,逐步增加智能体数量、增加任务复杂度。每改一个地方,都做消融实验,确认改动真的有用。
工具方面,pettingzoo提供了很多标准环境,可以直接拿来练手。ray.rllib封装好了MAPPO、QMIX等算法,适合快速验证想法。但如果你想深入理解算法细节,还是建议自己从零实现一遍,踩过坑才能真正掌握。
最后分享一个小技巧:训练时把智能体的行为录下来,每隔一段时间回放看看。很多时候,曲线看不出的问题,回放一眼就能发现。这个习惯帮我省了大量调试时间。