把”派单”当成一道路径题,是这类系统最常见的设计起点:给定若干订单和若干运力,算一条总里程最短的路线。真正跑起来之后会发现问题不在图上——状态在变、估计会错、被改派的人不接受结果、出了争议拿不出证据。里程最短只是目标函数里的一项,而系统能不能被使用,取决于另外三层的工程质量。

按四层来拆比较经得起推敲:时空状态层、ETA 层、约束求解层、处置层。每层都有自己的输入质量要求和自己的失效模式,混在一起谈”算法好不好”得不到可执行的结论。

调度系统的状态快照与约束求解分层示意

一、时空状态层:快照与它的新鲜度代价

这一层负责回答”此刻世界是什么样”:运力位置与运动状态、订单的承诺时间窗、商家的出餐进度、路网与楼宇的静态属性、天气。它的工程难点全部集中在新鲜度上。

位置上报的频率越高越好用,但代价由终端承担——频率影响电量和流量,也影响弱信号环境下的功耗。更麻烦的是可用性:城市峡谷与楼宇内部的多径会让定位漂移,把漂移值当成真实位置送进上层,ETA 和顺路度就会一起失真。所以位置字段不能只是一个坐标,必须带采集时刻、精度半径和一个质量分,让上层能选择”用”、”降权用”还是”等下一次”。

商家侧状态是这一层里最容易被低估的部分。出餐进度通常是”商家自报”与”从历史出餐时长推断”的混合,两者都有系统性偏差:高峰期自报会滞后,历史推断对新菜式和不熟练的厨师会过于乐观。这个偏差不是靠更复杂的求解器补偿的,它直接进 ETA,再进时间窗判断,最后表现为一批”看着合理但必然超时”的指派。

原则是:状态层的每个字段都要能被追问”这是什么时候的观测、有多可信”。没有质量分的状态层,会让上层把所有噪声都当成事实来处理。

二、ETA 层:到店与送达要分开估

一条履约时间线至少有三段:从当前位置到商家的移动段、在商家处的取餐等待段、从商家到用户的交付段。三段要分开建模再相加,理由不是精度,而是可校准、可归因、可干预。

移动段靠路网与实时速度,误差相对可控。长尾误差集中在另两段。取餐等待取决于商家当时的排队与出餐节奏,本身方差大;交付段里真正吃掉时间的往往不是骑行,而是楼宇内部:门禁核验与登记、等电梯与电梯停靠层数、到达后的步行与找门牌、高层与无电梯建筑的爬楼。这些动作在地图上不存在,所以任何”按距离和速度算总时长”的做法都会在同类楼宇上反复失准,而且是单向失准——只会低估。

分开估之后,每段都能拿到观测真值做校准,超时也能归因到段;合在一起估,只能得到一个不准的总数,改都不知道往哪改。

还有一个常被跳过的点:进目标函数的不应该是点估计,而是分位数。同样顺路的两个方案,一个的到达时间分布紧凑,另一个长尾很重,均值一样但风险完全不同。用中位数派单,长尾那些订单就会在最后一刻集体超时;用高分位数派单,又整体变保守、单量上不去。取哪个分位数是业务判断,但系统必须把不确定性作为一等公民传下去,而不是在中间层把它抹平。

三、约束求解层:目标函数里有四方

约束这一侧相对清晰:顺路度、同时在手订单上限、载具容量(餐箱体积与保温分区,冷热不能混放)、技能约束(药品、生鲜、大件、需要开箱核验或代开票的品类)、时间窗、运力可用的连续工作时长、商家产能。目标函数这一侧没那么清晰,因为它至少同时装着四方利益:平台成本、商家出餐节奏、运力提供方收入、用户体验。

单纯最小化总里程之所以伤人,是它做了一次代价转移而没有消除代价。里程短往往意味着单件收益下降、在商家处的等待增加、时间窗余量被压薄;被压薄的余量最后落在骑手和用户身上,表现成超时投诉和”明明顺路却不愿意接”。这时系统看到的指标很好,一线的体验很差,接指派率下滑又反过来恶化效率——问题出在目标函数没把等待时间和余量薄度算成成本。

下面这张表是按”谁的代价”来对照指标,很多争论源于同一个指标被三方用不同方式优化。

指标 表面目标 代价实际落在谁身上 容易被忽略的反作用
单均行驶里程 平台成本 运力收入与接单意愿 强制顺路导致等待变长、拒单增多
准时率 用户体验 运力(时间窗被压薄) 为保准时预留过头,整体吞吐下降
在手订单数 吞吐 用户体验与交付质量 并单过多导致每单停留变长、错漏上升
商家平均出餐等待 商家节奏 运力(原地等) 为不等而提前到店,占用车位与人力
改派率 局部最优 运力信任 无理由改派让一线不再相信系统提示

时间窗违约的惩罚项写法也值得推敲:线性惩罚会诱导系统把少量订单推到极深的超时上,因为总惩罚看起来更小;要让违约分布可见,就要对”深度超时”设非线性代价,并把申诉成本一并计入。

四、处置层:压单、改派、预警与申诉

现实里多数价值来自处置,不来自首次指派。压单(暂缓派发等更好的匹配)、改派、超时预警、异常上报与申诉,这四种动作各有工程要求。

改派要幂等且可回滚。一次改派同时改动两方的任务,必须考虑中间状态:原运力已经到店、货已出库,这时撤回指派会产生资损,所以改派动作要有前置状态校验和失败后的补偿路径,不能只更新一条数据库字段。

超时预警的判据要用剩余分布而不是剩余分钟。同样的”还剩十分钟”,在平地短交付和高层写字楼交付上的风险差很远,用固定阈值会同时出现大量误报和关键漏报。预警还要给出可执行选项(改派、协调商家、提前联系用户),否则只是把责任推给一线去判断。

申诉链路是最容易被砍、代价却是长期的一项。它的技术本质是要求系统能重放决策时刻的输入:当时看到的位置与质量分、当时的商家出餐状态、当时可用的运力、目标函数里各项的取值与权重。这就要求决策日志以快照形式留存,保留时长要覆盖申诉周期,而不是只留一个最终指派结果。没有可重放的日志,申诉只能靠双方各执一词,最后由人工经验裁断,规则也永远修不进模型。

五、窗口、频率与可解释:算法系统的工程现实

调度窗口长度是一个明确的取舍。窗口越短,算力越省、响应越快,但解的质量越差——批处理窗口内可交换的组合数量随订单与运力规模增长,即时贪心派单看不到”稍后一单更顺路”的可能。窗口拉长会提升匹配质量,代价是订单在系统里等待,履约时间被自己吃掉一截。这个折中不是调一个常数,而要按品类和时段分别设定,并把它当成可被验收的参数写进配置,改了就记录。

重调度频率与稳定性是第二对矛盾。频繁重调度让指派结果不断变化,一线看不到理由的改派会直接摧毁对系统的信任:一旦形成”系统说的不如我自己判断”的共识,接指派率与主动上报都会下滑,状态层的数据质量随之变差,形成下行回路。所以”可解释的改派理由”是产品要求,不是锦上添花。理由还必须来自目标函数里真实存在的项(哪个约束被破坏、哪段时间窗风险变大),套模板文案会被一线很快识破。

评估是第三道墙。这类系统不能拿真实运力去做对照实验——把一半订单交给较差策略,代价由具体的人承担。可行的替代手段有五种,各自有偏差:

  1. 影子模式:新策略并行计算但不生效,比较两者给出的指派与预估目标值。安全,但看不到一线对新结果的实际响应。
  2. 历史回放:用同一时刻的输入快照重放两种策略,比较违约率与代价构成。适合回归验证,缺点是历史状态里已含旧策略的影响。
  3. 区域或时段配对:在规模与结构相近的区域之间做切换对照。能看到真实行为响应,但要防配对偏差与溢出。
  4. 离线仿真:把运力行为建模进去做压测。适合容量与极端场景推演,但接单意愿、挑单、弃单这类行为最难仿真,仿真结论要打折使用。
  5. 新区域与新品类直发:在刚开通的区域或刚接的品类上直接按新策略上线。这里没有存量运力可以被牺牲,不产生对照代价,但也没有基线,只能与相近区域的成熟指标做结构性比较,适合验证明显错误而不是微调收益。

评估指标也要成套看,不能只看效率项:准时率与深度超时分布、改派率与改派接受率、单均等待时间、申诉发起率与申诉翻案率。申诉翻案率是一个被低估的信号,它高说明系统的判据与一线常识不一致,通常是状态层缺数据。

六、洹拓视角:同一套结构迁移到企业派工

设备维保、外勤安装、巡检这类企业自有履约任务,结构与即时配送同构,差别只在参数上:运力换成熟悉设备与资质证书的工程师,出餐状态换成备件是否在场站、客户是否具备停机窗口;ETA 的长尾从楼宇垂直交通换成进厂审批、安全交底、登高与受限空间作业的准备时间;并单上限换成”一人一天能完成的作业点数”与法规工时;时间窗违约惩罚换成服务等级协议条款与连带停机损失。

真正能直接复用的是那四层结构和三条纪律:

  • 状态字段一律带采集时刻与质量分,到场与完工状态不能只靠人工回填,否则调度层拿到的是”事后编制的现实”。
  • 估计分层,路上时间与作业时间分开建模,作业时长用同设备同工种的分布而不是拍一个定额。
  • 每次指派与改派留存决策快照,费用结算与考核争议要能重放当时的输入。

多数团队做派工系统时把问题当成最短路径,上线后失败点几乎都落在两处:状态新鲜度不够,系统算出来的是过去;申诉与结算链路拿不出证据,一线不再接受指派。这两处都不是算法问题,是数据与流程工程问题。企业客户在选型时可以把它们写成验收项——要求演示一次改派的全链路重放,比看一次漂亮的调度大屏有用得多。