基于DR-PPO算法的送餐智能体强化学习训练:原理、实战与优化全攻略
前言
用强化学习训练一个送餐智能体,这事儿想想就挺有意思的——从最初完全不知道该干嘛的状态,到最后能自己规划路线、抢单、配送,整个过程带来的成就感确实不少。现在把整个实践中的经历和一些有意思的细节整理出来,希望能给同样在琢磨强化学习的朋友们一些启发。
任务背景
这次送餐任务是在及第平台提供的AI仿真环境里完成的。简单来说,目标就是在一个网格世界里训练出一个智能体,让它能在规定时间内把订单从餐厅送到客户手上,尽量多拿累计回报。训练完成后可以上传至平台,和其他玩家的智能体进行1V1对抗,最终排名按照玩家最后30盘的平均奖励来定。
先看看地图长什么样

整个环境是一个16×16的网格世界,里面有10个餐厅和20个客户。地图上的道路是用来走的,餐厅和客户的格子骑手可以进去,但其他区域不能通行。每次游戏开始时,餐厅和客户的位置会在道路中随机生成,骑手也在随机位置出发,每步可以移动一个网格。
每经过10个时间步,系统会随机产生20个餐厅订单——餐厅的订单容量没有上限,但如果订单超过了截止时间还没被骑手接受,就会被自动取消。有意思的是,每个时间步系统只会从还没被抢的订单里选出最多10个展示给骑手,骑手可以同时抢0到10张订单。骑手到达餐厅后,能根据抢到的订单去取餐。不过要注意,每个骑手最多能抢20个订单(还没取餐的那种),但身上最多只能同时携带5个已经取餐的订单。
取餐的时候也得留意:只有在对应的餐厅才能取到属于自己的订单,想在其他餐厅取餐就是无效操作。
智能体的动作空间分成四类:
1. 移动:只能在可行区域走,方向有上、下、左、右,当然也可以选择原地不动。
2. 抢单:每个时间步都能对展示出来的订单列表里的任意订单发起抢夺。
3. 取餐:只有在骑手位于某个餐厅的位置时,才能对属于该餐厅且已经抢到的订单执行取餐操作。
4. 放餐:当骑手到了客户的位置,就能把已经取到的订单交给客户——如果不在对应客户那边放餐,系统会视作“丢弃订单”。
整个任务的目标是在500个时间步内拿到尽可能高的累计总收益。收益是奖励和惩罚的总和:
奖励:在订单截止时间前把餐送到客户手上,就能拿到奖励,数额等于餐厅到客户点的曼哈顿距离。
惩罚:两种情况会触发扣分,数值是对应订单奖励的一半——要么是抢了单但没在截止时间前送到,要么是中途主动放弃已经抢到或取到的订单(也就是丢弃订单)。
还有个细节:如果有两个骑手同时抢同一个订单,环境会随机选一个来接受。
关于捷径

这里有个挺有意思的点:地图里存在一些“捷径”。按理说骑手只能在道路格子上走,但餐厅和客户所在的格子也允许进入,这就形成了一些能抄近路的路径。实际跑起来会发现,路网的复杂度比单纯的道路网格高得多——比如上面图中标注的两条蓝色移动线路,都是利用了这种捷径。
聊到任务难点,最大的麻烦来自环境里的各种“随机性”:餐厅和客户的位置、因为捷径带来的路网变化、骑手的初始位置、订单的生成规则(餐厅与客户的组合、对应收益、发布时间、截止时间),甚至连待抢订单池里展示的订单,全都是随机的。这些随机性带来的直接后果是:智能体每次收到的状态几乎都是全新的,就算做了同一个动作,下一个环境状态也可能大不一样。状态转移的复杂度比固定环境高出一大截,这也就逼着智能体不能只记住某几条固定的配送路线,必须真正学会通用的配送策略。
为了对抗这些随机性,在训练里试了不少手段:比如在注意力机制里加了噪声因子、调整广义优势估计(GAE)的超参数λ、让价值网络输出分布而不是单一的数值。
除了随机性,另一个难点是奖励和惩罚的延迟性。抢单、移动、取餐这些动作不会立刻带来奖励或惩罚,只有等订单送到客户手上才有奖励,或者订单超时了才会触发惩罚。这意味着智能体必须学会学习长跨度的累积回报,建立起面向长期目标的决策逻辑。
相关技术简介
受篇幅限制,这里只对核心技术做简要说明,算法细节和网络结构就不展开细讲了。
1. 深度强化学习
核心理念是借助神经网络搭建智能体,让它在和环境不断交互、试错的过程中,逐步学到最优决策策略。不需要人为预设固定规则,智能体会在持续交互中吃透任务逻辑,摸索出对应的执行策略——这也是强化学习最让人着迷的地方。这次项目选用了基于AC架构的PPO算法,策略网络依托策略梯度实现优化。说白了,算法的逻辑就是:提高好行为的概率,降低坏行为的概率,不断迭代完善决策。至于怎么判断行为好坏,这就要靠优势函数的定义了:行为比期望收益高就是好的,反之则是坏的。
2. 预训练表征学习
想让智能体做出合理的配送决策,首先得让它理解整张地图的布局。为此设计了一个“最短路径”的辅助任务进行预训练,让模型先学习地图特征,生成高维特征向量(表征),这个向量浓缩了地图的结构信息。有了这份基础表征之后,再开展下游的送餐主任务训练,就能事半功倍。一句话概括就是:让智能体先“理解”再“决策”。实际开发中,下游任务的算法和网络结构迭代了非常多的版本,但全程都直接复用预训练得到的地图表征,大大提升了开发和训练效率。
3. 图神经网络
地图本身的结构和图数据特性很贴合:骑手、餐厅、客户都可以看成图中的节点,道路则是连接节点的边,距离信息作为边的属性,时间等信息作为全局特征参与计算。地图预训练阶段主要用了图注意力网络。
4. Transformer-Encoder
下游送餐主任务里用到了当下主流的Transformer-Encoder架构。智能体每做一次决策,都需要综合考量不同订单之间的关联关系,这个架构刚好能胜任——它的N×N注意力复杂度,正好满足多订单关联分析的需求。
成果展示
很遗憾,截止2026年5月,及第平台只接收智能体提交,不再开放PVP对战,所以没法直接拿到对战模式下的官方评分。下面用本地单机运行的测试成绩作为参考。平台排名前两名的玩家,30局平均回报分别是772.47和764.63。而我的智能体在本地100局单机测试中,平均回报达到了824.19,标准差102.86,最小值554.5,最大值1069.0。
虽然无法直接对比,但做了个粗略估计:每局生成的订单数量比双人对战模式下两位玩家能处理的订单总量还要多得多。这意味着即使切换到对战环境,订单资源依然非常充足,不太可能出现因抢不到单而导致的性能骤降。当然,对战中的策略干扰肯定存在,实际成绩大概率会比单机成绩低一些,但应该不会断崖式下跌。
展示说明
为了让大家更直观地理解智能体的运行逻辑,下面结合Pygame可视化界面,先说明界面里的关键元素,方便大家看懂后续的运行示例。

骑手标识:被操控的智能体;A_0为环境自带的静止骑手,可忽略
餐厅标识:全地图随机生成10间餐厅
客户标识:全地图随机生成20个客户
障碍标识:骑手不能进入的区域
取餐路线标识:标记从骑手当前位置到餐厅的路径,连续取餐会标注顺序
配送线路标识:标记从餐厅到客户的路径,连续配送会标注顺序
订单列表界面说明
智能体行为总结
结合本地测试的运行日志和Pygame可视化界面,可以观察到训练完成的智能体在订单处理和路径规划上展现出了多种实用的策略:
1. 订单聚合决策
同源同宿订单聚合:骑手会在不同时刻进行凑单,将"餐厅相同、客户相同"的多张订单聚合起来,再一并取餐配送——这是效率最高的策略。
区域邻近订单聚合:同理,骑手也会把位置邻近的订单凑在一起,包括"餐厅相同、客户邻近""餐厅邻近、客户相同""餐厅和客户都邻近"这几类情况,实现连续取餐或连续配送,减少来回绕路的时间。
2. 动态路径规划
骑手的目标地不是一成不变的,会根据环境变化随时调整。比如离开餐厅不远,又抢到了该餐厅的新订单,骑手会主动回头取餐,而不是硬着头皮继续往前走;也不会死板地遵守"取餐→清空所有配送库存→再取餐"的模式,而是根据实际情况灵活安排——比如"取餐→先送部分订单→再去取餐→最后清空配送库存",配送顺序不一定和取餐顺序一致,完全以效率为优先。
3. 库存感知与利用
智能体会同时感知两类库存的状态来做最优选择:
对"提单库存"(已抢单但未取餐的订单):在满足取餐需求的情况下,不会把库存抢满,而是保留一部分空间,应对后续可能出现的高收益订单。
对"配送库存"(已取餐待配送的订单):尽量提高库存利用率,规划"取餐→配送"的高效路线,减少空载行驶,最大化单位步数的收益。
4. 时间感知与优先级判断
骑手对订单的剩余时间和本局的总时长都有清晰的感知:会优先配送临近截止时间的订单,避免超时产生惩罚;开局阶段也不会一上来就做复杂的长距离规划,而是就近取餐开始配送,不浪费前期的宝贵时间步。
地图级别的决策偏好

在地图层面,智能体形成了两个很明显的行为倾向:
1. 偏爱长距离配送策略。按任务规则,奖励值等于订单的曼哈顿距离,理论上长短距离的收益效率一样。但因为地图里有障碍(白色单元格),很多短距离订单的实际移动路径比曼哈顿距离长得多——比如图中一个收益只有3的订单(绿色虚线),实际却要走15步(绿色实线)才能送到,收益效率极低。而长距离订单能避开这些弯弯绕绕的路线,整体效率更高。
2. 优先选择左上角片区的订单。观察地图能发现,左上角片区的道路之间只有一格障碍,随机生成的餐厅和客户很容易形成捷径,能大幅缩短配送路程;而其他片区的道路之间障碍至少有两到三格,很难形成这种抄近路的机会。因此智能体也更偏爱以左上角片区为核心的配送路线。
也说明一下:经过训练的智能体确实掌握了不少高效配送策略,但不是完美的,偶尔还会出现判断失误或效率不高的情况,理解万岁。
示例
网络与训练设计
开发环境:Python、PyTorch;训练平台:Kaggle(仅用CPU)。受限于本地硬件资源,全程没有使用GPU加速。考虑到强化学习探索过程的随机性,采用了稳健的迭代训练策略:每天训练5个模型版本分支,筛选出当日最优结果后,第二天基于这个最优版本继续训练5个分支,逐步迭代优化模型性能。
预训练阶段

训练过程是这样的:在地图中随机选两个位置,分别作为出发地和目的地,算法要找出两地之间的最近可行路径。为了解释清楚网络设计,可以拿右上角6×6的地图来说明。


上左图中A点是出发点,代表智能体,目的地是E。智能体可以往上下左右四个方向向可行单元格移动。上右图是我设定的地图节点类型:餐厅及相邻单元格、客户及相邻单元格、出发地、目的地、三叉路口、十字路口、拐弯处。为了展示方便,节点作了很大程度的简化。
图神经网络设计

上游预训练任务收敛后,取出最后一层图神经网络所有节点的输出结果。这些半成品,就是需要的节点高维表征。
训练相关
使用的是常规强化学习PPO算法,每个时间步预测下一步的移动方向。奖励设计:到达终点reward=1,每个时间步reward=-0.001。核心目的很明确——引导智能体用尽可能少的步数从出发地抵达目的地,也就是学会最短路径规划。训练初期尝试过不少奖励塑形技巧,比如虹吸效应(越靠近目的地辅助奖励越大)、走回头路给予惩罚、避免奖励挟持问题等等。后来发现不用辅助奖励也能训练起来,可能地图还算小。
渐进式训练策略:
为了让智能体平稳适应路径规划任务,采用了由易到难的渐进方式:
初期:固定1个出发地,目的地从几个固定点中随机选,先让智能体熟悉任务目标。
中期:扩展到多个固定的出发地和目的地,随机组合训练,让智能体适应更多场景。
后期:出发地和目的地都改为全地图随机生成,让智能体掌握通用的路径规划能力。
预训练成果

上图展示了地图数据中各节点的原始特征,并通过TSNE降维可视化。可以看到,原始特征只能反映节点之间的L2距离,但无法准确体现实际路径关系。观察点:绿框[3,4]与黑框[3,2]、[5,4]在L2距离中相等,但实际可行路径距离不符(白色单元格不可通行)。

经过表征学习后,原始特征已经能反映出真实的路径关系:绿框距离[5,4]最近,[3,9]次之,[3,2]最远。

在另外一次随机地图中,存在[3,3]的可通行路径。经过表征学习后,绿框与[5,4]、[3,2]距离基本相同。可见高质量的表征能根据实际地图情况准确反映路径信息。
下游主任务阶段
基于Transformer-Encoder架构
训练相关
1. 奖励与惩罚设计
主任务的奖励和惩罚完全按照任务原规则执行,没有添加任何额外奖励塑形,直接以任务的收益规则作为优化目标。
2. 动作空间的改造与简化
主任务的原始动作空间维度是:移动(5)×抢单(2^10)×取餐(2^20)×放餐(2^5),直接训练的难度可想而知。为了让智能体能聚焦在核心的订单规划决策上,对动作空间做了关键改造:
不再让智能体直接输出“上下左右不动”这5个移动动作,改为输出目标地(可选目标为地图上的20个餐厅位置+5个客户位置)。为什么是5个客户位置而不是20个?因为骑手最多能带5张订单在身上,也就是最多5个不同客户有即时配送需求,去其他客户点位没有实际业务意义——这也是利用先验知识进一步压缩决策空间。
目标确定后,通过BFS算法分析骑手当前位置到目标地的最短路径,就能得到当前时间步的移动决策。改造的核心目的,是把“寻径”这个已经在预训练阶段学会的能力从主任务中剥离出来,让智能体把全部学习精力放在订单抢取、取餐配送的规划决策上,不用再从头学路径移动。
3. 渐进式训练策略
为了让智能体平稳适应完整配送决策流程,采用了分阶段放开动作空间的渐进方式:
阶段一(基础规则学习):动作空间限定为目标地×抢单。取餐和放餐操作由手写脚本实现:骑手到达餐厅时自动对已抢订单取餐,到达客户时自动放餐。核心目标是先让智能体学会抢单→去餐厅取餐→去客户放餐这个基本流程,理解“完成订单获得收益、超时惩罚”的底层逻辑。
阶段二(取餐决策放开):动作空间扩展为目标地×抢单×取餐。放餐仍由手写脚本实现,但取餐动作的决策权交给了智能体:到达餐厅时不再自动取所有已抢订单,需要自己分辨哪些订单属于该餐厅并决定取餐优先级。这个阶段智能体开始根据订单时间、收益等信息自主判断,配送策略更灵活,收益也更高。
阶段三(全动作放开):动作空间完全放开,智能体可以自主决定在任意位置执行放餐操作。理论上有完整决策权限,但实际测试中收益提升很有限——因为在非客户位置放餐是非法操作会触发惩罚,只有提前清空库存这一个潜在好处,对整体配送效率几乎没帮助。
强化学习算法相关
一、网络结构优化:PPO+Transformer+值分布+记忆单元
核心使用PPO算法进行训练。考虑到送餐环境随机性极强,参考了DSAC算法的价值网络设计思路:让价值网络不再输出单一数值,而是输出一个高斯分布,提升智能体对随机环境的适应能力。在Transformer架构中,额外加入了一个记忆单元,参与多头注意力机制的计算,用于传递智能体的历史决策记忆。
从实际效果看,强化学习天然适配RNN类的记忆结构——因为推理过程本就是按单步时序依次决策的,RNN推理速度慢的特点在这里不会造成负面影响。为此做了消融实验:将记忆单元替换为高斯随机分布噪声,核心能力没有大幅下降,仅策略稳定性略微变差。分析原因可能是:本任务中环境的核心状态(已抢订单库存、已取餐库存、餐厅/客户位置)都相对稳定;抢单列表虽然实时变化,但当提单库存已满或接近满时,智能体并不会持续抢单,时序状态的变化对决策影响有限。不过从设计角度看,记忆单元仍然是更高效优雅的方案。
二、策略更新优化:自定义重要性采样(IS)
标准PPO在策略网络损失计算中,通过重要性采样将样本损失权重限制在采样策略的±20%以内。但训练中考虑了一个假设:训练初期策略不稳定,智能体采样到优质动作时,若分配给该动作的概率极低(如p=0.05),按标准±20%更新后权重上限仅为0.06,容易丢失优质动作样本。针对这个问题,对重要性采样做了改造:将权重系数拆分为固定部分(10%)和浮动部分(10%)。以初始概率0.05为例,更新后权重上限为0.1+0.05×1.1=0.155,能有效避免初期遗漏优质动作。随着训练逐步稳定,固定部分系数衰减至0%,浮动部分逐步提升,最终恢复为标准±20%更新范围。
三、训练策略优化:适配Kaggle训练环境
训练基于Kaggle平台,仅用CPU,内存也有限。在一个训练的BatchSize里,无法直接将完整500步的对局样本全部纳入损失计算,效率也不高。因此做了两点适配:
1. 时间信息归一化:将每局时长归一化映射到0~1区间(对应0~500步),作为全局变量之一,让智能体能感知当前对局的设定游戏时长。
2. 滑动时间窗口采样:训练初期单局运行步数控制在100~300步,后期提升至200~400步。训练时从每局中随机截取连续200步的样本进行学习。通过这种方式,不需要在训练时进行完整的500步训练,也能较好适应500步的完整对局。
四、尝试过的各种技巧
1. 热启动:先写一个简单的规则脚本,让智能体在训练初期能直接获得取餐到完成配送的训练样本,加快前期学习速度。
2. 使用AdaLN处理全局信息:AdaLN是自适应层归一化。把全局变量分别映射成斜率和截距,改写LayerNorm的仿射过程。为了稳定,将斜率和截距初始化均值分别为1和0的高斯分布。
3. 奖励与惩罚调整:试过初期只有奖励、惩罚系数随训练从0到1增长;也试过将“超时扣罚”改成“抢单时先预扣部分惩罚,配送成功后再返还并正常发放奖励”,结果智能体变得特别胆小,不敢轻易抢单。
4. 模仿学习:反复设计网络需要从头训练时,会从旧智能体学习知识,但不能过度模仿,避免失去探索能力。
5. MoE(混合专家模式):参考了DeepSeek大模型里的前馈神经网络设计。采用1+(1/3)专家设计:1个共享专家加上3选1个候选专家,专家维度是原维度的3/4。感觉需要更长的训练时间,因为网络宽度比普通FFN多了3个候选专家。
6. 价值网络双结果输出:价值网络通常输出智能体预测回报的期望,但这个项目回报明显由奖励和惩罚两部分构成。因此尝试价值网络参数共享,分别输出奖励价值和惩罚价值,模型同样能训练起来。
7. 动态记忆型智能体:由于“可抢单的订单列表”是随机展示的,对智能体决策不太友好。如果人类面对这种随机信息,第一反应是“做笔记”。因此为智能体网络添加了“N长笔记区”功能,让它自行将随机展示的订单挑选写入“笔记区”供后续决策参考,还支持自主删除操作。这个设计挺有意思,但当时没重视动作空间过大的问题,导致训练困难。现在回想,同样适合渐进式训练,而且这种设计更具可解释性,可以通过分析智能体的“笔记区”来解读其行为。
有很多尝试,没法具体说明效果如何或性能提升多少。个人时间与算力有限,最主要还是技术水平有限,无法做更多消融测试。但至少这些尝试模型都能训练起来,差别在于性能上限和收敛速度。
每次思考、每次尝试、每次网络设计都能带来兴奋与期待,这个过程很让人享受。同时也犯了很多错,从错误中吸取了宝贵的经验教训。这个曲折的过程,本身就有点像强化学习——在探索试错中成长。
训练心得
这里分享一条本次项目中非常关键的训练心得,也是整套渐进式训练方案的核心底层逻辑。
举个通俗的例子:如果做决策时只有唯一选项,那完全不需要权衡;选项增加到两个,就开始要权衡利弊;当同时存在多项决策维度,每个维度都有大量可选动作,整体就变成了极度复杂的联合决策问题。从强化学习角度看,多维度联合决策是联合概率的过程。动作维度增多、可选动作变多,概率乘积持续变小,不确定性大幅升高(熵变大),直接导致学习难度指数级上升。
所以,在复杂交互任务中,尽可能降低决策不确定性,是提升训练成功率、加快收敛的关键。基于这个思路,下游主任务训练中用到了三套实用技巧:
第一,渐进式放开动作空间。没有直接让模型学习全部动作空间,而是由少到多、逐步增加单步决策的动作概率连乘项,让智能体先掌握简单决策逻辑,再逐步适配复杂的多维度联合决策。
第二,引入先验知识做Action_Mask。在计算损失中的联合概率时(非采样过程),通过掩码机制把当前状态下可执行但无效的动作概率直接置为1。概率为1意味着该项不影响整体联合概率结果,等价于屏蔽了无效动作的干扰。用到的先验规则非常贴合任务逻辑:骑手不在餐厅时屏蔽取餐动作;提单库存为空时屏蔽取餐动作;配送库存为空时屏蔽放餐动作;提单库存已满时屏蔽抢单动作;配送库存已满时屏蔽取餐动作——通过这种方式极大精简了有效决策空间,减少无效噪声。
第三,分阶段冻结网络参数+Action_Mask。逐次放开新动作的训练过程中,不会一次性更新全部网络参数。初期冻结整个主干网络,只单独训练新增动作的输出头;待智能体完全掌握新动作决策逻辑后,再解冻全网参数进行联合微调。同时训练新动作头时,通过Action_Mask将旧有成熟动作的概率置为1,让损失函数在计算联合概率时只专注学习新增动作的优化逻辑,避免新旧动作互相干扰。
总的来说,在结构可控、可以通过先验规则约束的交互环境中,结合渐进训练、概率掩码、参数冻结这套组合方法,能非常高效地降低学习难度、提升训练稳定性,是落地强化学习复杂任务时性价比极高的实操技巧。
总结
看着自己设计的送餐智能体从零基础不断试错、迭代成长,性能一步步稳步提升,确实是整个项目中最有成就感的事情。一直在坚持学习强化学习相关知识,目前也开始接触各类带约束条件的复杂交互环境。相比大语言模型,强化学习的优化目标更加直接、聚焦,优化函数始终围绕任务核心目标展开,所需算力成本更低,让个人和普通企业也能落地实操、进行项目迭代。
回顾本次项目的网络设计与训练落地:整体网络架构由两部分组成——预训练阶段采用4层32维的图神经网络作为骨干网络,现在复盘来看,网络层数还有精简优化的空间;下游送餐主任务采用2层64维的Transformer架构搭建骨干网络。可以看出模型参数量很小。全程依托Kaggle平台使用CPU训练,仅需24小时持续训练,智能体就能基本掌握任务规则。在30天的持续迭代训练中,筛选出效果最优的策略模型作为最终展示成果。
建议尽量利用代码生成工具进行编码。人可以天马行空、充满激情与创意地去构思算法、设计训练过程,而代码生成工具能避免很多人为编码出错。深度学习和强化学习,很多时候编码出错不在于语法,而在于逻辑——可能出现代码能跑通但算法不收敛的情况,耗费的算力成本和时间成本都很昂贵。代码生成工具确实是很好的生产力工具,前提是要完全弄懂算法的方方面面,不含糊,才能驾驭它,而不是被它牵着走。
优化问题是工程实践中最常见、最具经济价值的问题,这与强化学习“最大化回报”的目标高度一致。只要问题的结构满足马尔可夫决策过程(MDP),强化学习就是一个值得优先考虑的方案。
很想写出真情实感,奈何文笔生硬,上述文案经LLM润色修正,特此说明。
2026年6月上旬
阿勇










































