Coalition Delivery 失败机制分析与改进路线

生成时间:2026-06-30 | 训练 run:runs/20260630-1131_delivery_compare_env-comparison-small-scale-rewardfix | 独立 eval:runs/eval/rewardfix-coalition-delivery-64eval_20260630-173918

一、结论摘要

当前主要问题不是“任务发现”本身,也不是简单的学习率或训练时长问题,而是 coalition_delivery 的动作语义、available action mask、奖励时序和特殊动作建模共同制造了错误吸引子。 策略已经学到一部分有效行为,但后半程容易掉进 resupply / explore / idle / empty-delivery 循环。

事实 1:任务大多能发现

64-seed eval 中,HATT v2.0 的 discovered_ratio=1.000,HATT v3.1a 为 0.994,MAPPO latest 为 0.992。失败主要发生在发现之后。

事实 2:后期动作分布异常

hard seeds 上,HATT v2.0 全发现后的 resupply agent 占比约 0.70,delivery 只有 0.10。不少 agent 满载或有载仍反复 resupply。

事实 3:终局惩罚太晚

未完成惩罚主要在 max step 或完成时触发。对 PPO 来说,这个信号离导致失败的错误动作太远,难以稳定反推。

因此,下一步不建议优先继续调学习率、加训练轮数或换探索扇区。更直接的改进路线是: 先修动作可行性约束和无效动作代价,再评估是否需要改 HATT decoder 或增加 agent-specific action features。

二、独立评估与 trace 证据

我对 MAPPO best/latest、HATT v2.0 latest、HATT v3.1a latest 做了 64-episode deterministic eval。 原始结果见 summary.csv。 然后对 hard seeds 8, 9, 41, 43, 49, 52, 60 重新跑 trace,记录逐 step 动作类型、完成数、发现数、剩余需求、死亡数和负载。 trace 输出见 trace_analysis/

64-seed eval 汇总

Checkpoint Success Completed Sent Discovered Reward Length
MAPPO eval_best0.7030.9440.9580.98940.3621.0
MAPPO eval_latest0.7970.9470.9530.99240.8610.0
HATT v2.0 eval_latest0.1090.6370.6681.00021.3716.9
HATT v3.1a eval_latest0.5470.8780.9100.99446.0619.1

Hard seeds 后半程动作占比

统计窗口:从全发现之后开始;若没有全发现,则从 step 300 开始。分母为 living-agent steps。

Checkpoint Hard seed 完成数 Sent Dead Delivery Explore Idle Resupply 终局剩余需求
MAPPO eval_best7.140.7650.710.190.260.110.44767
MAPPO eval_latest7.430.7761.860.450.230.000.32718
HATT v2.0 eval_latest5.140.5251.290.100.200.000.701541
HATT v3.1a eval_latest6.430.6871.290.130.240.160.461011

代表性失败

模型 / seed 现象 解释
HATT v2.0 seed08 发现 10/10,完成 5/10,终局 12 个 agent 全部 resupply,平均 load=60.5,zero_load=0,剩余需求 1535。 不是缺货,也不是任务没发现,而是有载 agent 选择了无意义补给循环。
HATT v3.1a seed52 发现 8/10,完成 7/10;step 400 后基本 12 个 agent 全部 resupply,终局仍有剩余需求 1035。 探索未收尾,同时物流链被 resupply 吸走。特殊动作比实际配送动作更容易成为稳定选择。
HATT v3.1a seed43 完成 4/10,终局 8 个 agent idle,1 explore,0 delivery,3 dead。 后半程进入 idle/explore 吸引子,未形成“有货去送、没货补给”的闭环。
MAPPO latest seed08 完成 2/10,发现 5/10,dead=7。step 100 之后 12 个 agent 全空载但仍全部 delivery,直到陆续死亡。 这是另一类错误吸引子:empty-load delivery forever。说明 MAPPO 虽整体更稳,但仍会在个别场景崩掉。

三、代码机制证据

1. 特殊动作几乎长期合法

动作空间在 env_core.py:301-305 中被编码为: delivery tasks + explore task + idle task + resupply task。nearest 模式下只有一个 explore task。 env_core.py:548-572 中,explore、idle、resupply 都被设为 discovered=True

但 available action mask 只做了一件事:

task_mask = 1.0 if task.discovered and not task.completed else 0.0

env_core.py:616-622。这意味着:

所以策略面对的是一个很宽的动作空间:大量特殊动作始终合法,但它们在不同状态下并不总是物理或任务上合理。

2. mask 确实会被策略使用,但 mask 信息不足

MAPPO 的 Categorical 在 distributions.py:64-68 中将不可用动作 logit 设为 -1e10。 HATT v3.x 在 HATTV30Network.py:448-480 中也会 reshape available actions 并 mask logits。 因此问题不是 mask 没生效,而是 mask 只表达“任务是否发现/完成”,没有表达“当前 agent 是否应该做这个动作”。

3. active mask 会让 agent 延续上次动作

runner 在训练和 eval 中都会执行:

actions = active_masks * actions + (1 - active_masks) * last_actions

训练路径见 macf_runner.py:383-419,eval 路径见 macf_runner.py:481-526。 active mask 在 env_core.py:1005-1031 中只有在 key event、当前任务完成或 all_still 时才重新激活。

这本来是合理的“任务执行中不反复重决策”机制,但和永久可选的 resupply/explore/idle 结合后,会放大错误选择: 一旦 agent 选择了不合理 resupply,它会一直走到补给点;补给完成后如果策略再次选 resupply,就形成循环。

4. 当前奖励对无效特殊动作的即时惩罚过弱

coalition_delivery 奖励见 env_core.py:1298-1382。 当前已经有几项修正:全发现后 explore 小惩罚、empty-load 非 resupply 小惩罚、剩余需求时每步机会成本、终局 shortage penalty。 但 trace 显示仍不够:

5. HATT 的特殊动作候选更容易形成类型偏置

HATT 直接把 task candidates 解码成动作 logits。对 delivery task,它能看到位置、剩余 demand、deadline、priority、type; 对 explore / idle / resupply,它看到的是静态的特殊任务特征。 HATT v3.1a 在 coalition_delivery 中禁用了 capability residual HATTV31Network.py:214-233,这是合理的,因为新版需求不是旧 req-cap 对齐。 但 special actions 仍被当作普通 task candidate 参与解码,且没有 agent-specific feasibility mask。

这可以解释为什么 HATT v2.0/v3.1a 更容易掉进 resupply/idle/explore:结构化 decoder 在“特殊任务”上学到一种稳定类型偏置,而奖励不足以把它纠正到 logistics 闭环。

四、当前失败机制分型

失败类型 典型模型 trace 表现 根因判断
Resupply forever HATT v2.0,HATT v3.1a 发现完成后,agent 有载甚至满载,仍长期全体或大多数选择 resupply。 resupply 永远合法;满载 resupply 无显式强罚;特殊动作候选容易被 decoder 稳定偏好。
Idle / explore late drift HATT v3.1a,MAPPO best 部分 seed 还有剩余需求,但后半程 delivery agent 很少,idle 或 explore 占比高。 全发现后的 explore 只小惩罚;idle 只在剩余需求时多罚 0.03;终局惩罚太晚。
Empty-load delivery forever MAPPO latest seed08 所有 agent 空载后仍持续 delivery,既不补给也不探索,最终死亡。 delivery 动作不按 load mask;空载走 delivery 的即时惩罚不足;active mask 延续错误动作。
Hard geometry / danger seed 所有模型 seed 8/9/41/43/49 多个模型同 seed 失败,但失败模式不完全相同。 场景本身较难,可能涉及危险点、任务空间分布和补给距离;但模型失败仍表现为动作语义错误。

五、改进路线

路线 A:先改上下文 action mask,风险最低,收益最大

这是首选。它不是“喂饭”,而是把物理上或任务语义上无效的动作从策略空间中移除。当前 mask 已经在使用,只是约束过弱。

建议在 EnvCore._get_available_actions() 中加入 agent-specific 条件:

推荐伪代码:

for each agent: if remaining_demand == 0: legal = {idle} else: legal_delivery = discovered_unfinished_tasks if agent.load > 0 else {} legal_explore = {explore} if undiscovered_tasks > 0 else {} legal_resupply = {resupply} if load_ratio < 0.35 or battery_ratio < 0.25 else {} legal_idle = {} # unless no other legal action legal = legal_delivery + legal_explore + legal_resupply if empty(legal): legal = best_fallback(agent)

注意:mask 使用的信息应限制在策略已经可以观测或任务语义允许公开的信息内。已发现/未完成、agent load、battery、全局 discovered count 当前已经在 obs 或 available_actions 逻辑中存在。

路线 B:补上无效动作的即时惩罚

即使加入 mask,也建议保留 reward shaping,避免边界状态变成新漏洞。

路线 C:改善特殊动作建模,而不是把它们当普通 task

HATT 的 task decoder 对 delivery task 是合理的,但 explore/idle/resupply 是 control actions,不是普通空间任务。 可以考虑在 HATT actor 中拆成 typed action heads:

这比继续把特殊动作塞进 task candidate 更符合语义,也能减少 HATT 在特殊任务类型上的静态偏置。

路线 D:增强 eval 与诊断,而不是只看 reward 曲线

以后每组训练建议固定输出以下诊断:

我已经添加了可复用脚本: scripts/analysis/trace_eval_failures.py。 后续可以直接拿它分析新 checkpoint。

六、不建议优先做的事

七、建议实施顺序

  1. 实现 coalition_delivery 专用 contextual action mask。 先只改 _get_available_actions(),保持网络不变,跑 smoke + 64-seed eval。
  2. 加入无效动作即时惩罚。 尤其是高载 resupply、空载 delivery、全发现 explore、有载 idle。
  3. 重训 MAPPO / HATT v2.0 / HATT v3.1a 小规模对照。 先不用 mid-scale,确认 small-scale hard seeds 是否改善。
  4. 如果 HATT 仍明显偏 resupply/idle,再改 HATT typed action decoder。 这一步涉及模型结构,风险高于环境 mask,应放在第二阶段。
  5. 把 trace 指标纳入每次 sweep 的分析报告。 否则 reward 曲线和 success 曲线仍会掩盖“看似 reward 高但物流闭环断掉”的情况。

八、最终判断

当前 coalition_delivery 版本已经比旧 MACF 机制更接近“联盟运送”任务,但还没完全自洽。 主要缺口是:动作空间仍把 logistics control action 和 delivery task action 混在一起,且缺少 agent-specific 可行性约束。 rewardfix 让 MAPPO 和 HATT v3.1a 显著改善,但没有从机制上消除错误吸引子。

因此,下一版重点应是 action feasibility + invalid-action shaping。 只有这两项之后仍不能稳定完成任务,才有必要把主要精力转向 HATT 结构改造。