ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

恶劣天气下即时配送系统如何实现:ETA修正与骑手安全兜底

恶劣天气下即时配送系统如何实现:ETA修正与骑手安全兜底 暴雨天打开外卖 App你看到的不是骑手变少而是配送时长比平时多了一点。很多人会忽略这个细节多出来的几分钟背后是一整套即时配送系统在跟天气对抗。而对抗失败时压力并不会自动消失它会落到骑手身上变成一路的提心吊胆、边看导航边注意积水、在订单压力和身体安全之间做权衡。“恶劣天气坚持配送”确实是这份职业最辛苦的部分之一但如果我们只看情绪很容易错过真正值得解决的问题配送系统在极端天气下为什么容易失灵ETA 为什么突然不准调度为什么会失衡骑手安全的兜底机制为什么不够这些问题不是靠“多给骑手发几块钱补贴”就能解决的它们藏在了天气数据、预估模型、调度策略和异常检测这些工程环节中。这篇文章不打算写成一篇泛泛的行业观察我想从工程实现的角度拆解一件事一套面向恶劣天气的即时配送系统需要具备哪些能力。你会看到天气特征如何建模、配送时长如何修正、调度权重如何调整、骑手端安全兜底如何设计以及每次恶劣天气结束后技术团队应该怎么复盘和迭代。1. 恶劣天气下配送系统面临的核心挑战1.1 订单量与运力倒挂恶劣天气对即时配送的第一次冲击来自需求端。下雨、降温、台风天用户外出就餐的意愿明显下降外卖订单反而上升。尤其是在暴雨或者寒潮来临时很多人选择点外卖解决三餐订单中心流量甚至会接近峰值。但供给端不会同步增长。骑手同样要面对积水、大风和低能见度一部分骑手会暂停接单出勤人数下降即使出勤骑行速度也会显著变慢。需求上升、供给下降系统如果还在按正常天气下的规则调度就会产生两个直接后果一是单个骑手被分配更多订单压力成倍增加二是配送路线和预估时长全面失真。短期看是“运力不足”本质上却是系统没有为恶劣天气建立独立的供需模型。1.2 ETA 预估失真配送时长预估ETA是所有后续体验的基础。正常情况下模型综合商家出餐时间、骑手到店时间、路径距离、红绿灯数量、取送难度等因素给出一个相对准确的预计送达时间。天气一旦突变这个模型的前提就被打破了。问题出在数据分布上。历史订单样本中正常天气样本占绝大多数模型在学习时会把恶劣天气场景当作小概率情况平滑掉。结果就是雨天、风天、雪天的 ETA 仍然偏向“正常水平”系统低估了真实配送时长。更要命的是天气对配送时长的影响不是线性叠加的小雨可能只增加短短几分钟暴雨加积水加拥堵时长可能变成平时的 1.5 倍以上。ETA 一旦失真用户催单、客服承压、骑手为了赶时效加速骑行整个链路都开始向不安全的方向滑动。1.3 骑手安全缺少系统兜底从技术体系的角度看恶劣天气不仅是效率问题更是安全问题。导航推荐的路线可能默认走快速路或者桥隧但这些路线在雨天对两轮车并不友好调度系统可能因为运力紧张给骑手连续派发距离更远、单价更高的订单异常检测模型基于正常天气下的行为模式在暴雨中骑手长时间停留在一个位置可能不是异常而是被困、摔车或者需要休息。如果系统完全没有感知天气这些安全隐患就会变成一句“骑手自己小心”。但骑手并不是唯一需要小心的一方。通过路线规避、派单限制、异常识别平台侧完全可以承担一部分安全责任。技术在这里要做的事情不是监控骑手有没有偷懒而是在极端天气下为骑手提供一层主动性保护。1.4 用户预期管理失效用户端的体验问题同样被天气放大。用户在 App 里看到的 ETA 如果完全没有反映天气情况他会默认这笔订单应该按正常速度送达。一旦超时第一反应是投诉平台或者骑手。实际上天气导致的延迟不应该由骑手单方面承担也不应该只靠“免单红包”来事后补救。更合理的做法是在展示层面提前把天气影响透明化用户在点单前就知道这次配送可能会慢一些知道自己所在区域正在经历恶劣天气知道平台已经调整了送达时间。这一过程涉及 ETA 计算、前端展示、售后判责等多个系统而它们必须使用同一套数据口径。2. 天气数据接入与特征建模2.1 数据来源与接入层级要让系统“感知天气”第一步是接入天气数据。常见的来源有三类商业气象服务商提供分钟级或小时级的天气数据包括温度、降水、风力、能见度、湿度、体感温度等字段政府气象部门发布的公开数据覆盖面广但更新频率有限自建气象站点或与本地气象机构合作则更适合城市级精细化场景。配送平台通常采用商业气象服务商为主、公开数据兜底的组合方式。数据接入层级同样需要设计。城市级天气数据粒度太粗同一座城市的不同城区可能一边暴雨一边多云。至少应该做到区县级甚至网格级。更进一步可以结合雷达回波图预测未来半小时内某个区域的降水趋势为调度系统争取提前量。这种短临预报能力对配送系统来说比单纯的“当前天气实况”更有价值。2.2 地区与时间粒度问题天气数据的时间粒度很关键。一次冷锋过境可能上午晴天、下午暴雨。如果系统只按 3 小时的粒度更新天气数据很可能在暴雨开始后的第一个小时仍然按晴天做预估和调度。更稳妥的设计是支持 15 分钟或 30 分钟粒度的刷新并在天气发生显著变化时主动触发一次系统状态更新。还要注意天气影响不是全局统一的。即使同一个区域不同商圈的积水情况、道路条件也差异巨大。可以考虑引入“天气可达性”的概念用历史恶劣天气下的配送时长数据反推每个网格的实际通行系数再与实时天气数据做融合。这样得到的不是一个单一的天气标签而是一张反映“哪条路在什么天气下更难走”的动态地图。2.3 天气特征工程示例下面用一个最小示例演示天气原始数据如何转换成模型可用的特征。实际项目中数据字段会更多但这个流程代表了基本思路。# 输入城市天气接口返回的原始数据 raw_weather { city_id: 101020100, district_id: 330106, temp: 26.0, # 气温单位摄氏度 humidity: 82, # 相对湿度单位% precip_type: rain, # 无降水 / 雨 / 雪 / 冰雹 precip_intensity: 6.2, # 降水强度单位mm/h wind_speed: 11.8, # 风速单位m/s visibility: 3.1, # 能见度单位km } def build_weather_features(raw): features {} # 1. 降水等级划分 if raw[precip_type] rain: intensity raw[precip_intensity] if intensity 2.5: level light elif intensity 8.0: level moderate elif intensity 16.0: level heavy else: level storm features[precipitation_level] level features[is_precip] 1 elif raw[precip_type] snow: features[precipitation_level] snow features[is_precip] 1 else: features[precipitation_level] none features[is_precip] 0 # 2. 风力等级风速大于等于 10.8 m/s 约为 6 级风 features[strong_wind] 1 if raw[wind_speed] 10.8 else 0 # 3. 低能见度小于 5km 对两轮车骑行有明显影响 features[low_visibility] 1 if raw[visibility] 5.0 else 0 # 4. 综合风险分供调度和前端展示复用 risk_score 0.0 level_score { none: 0.0, light: 0.2, moderate: 0.4, heavy: 0.7, storm: 1.0, snow: 0.9, } risk_score level_score[features[precipitation_level]] risk_score 0.15 if features[strong_wind] else 0.0 risk_score 0.1 if features[low_visibility] else 0.0 features[risk_score] min(risk_score, 1.0) return features features build_weather_features(raw_weather) print(features)这段代码的关键在于等级划分和风险分计算。降水强度、风力、能见度的阈值都应该结合当地气候和骑行场景做验证不同城市对“大雨”的感知差异很大。正式项目中这些阈值应该配置化由数据团队根据历史配送记录校准而不是硬编码在代码里。3. 配送时长预估天气修正因子如何设计3.1 基础 ETA 模型的局限大多数配送 ETA 模型可以抽象成下面这个结构base_time 商家出餐时间 骑手到店时间 配送时间 交付时间其中配送时间又由路径距离、路网速度、红绿灯等待、取送难度等因素决定。这种结构在稳定天气下表现很好但天气突变时会全面失效。核心原因还是数据分布正常天气的样本量远大于恶劣天气模型在学习过程中会以多数样本的规律为主把少数极端样本当作噪声平滑掉。如果只是在特征列里加一个“天气”字段而不做样本层面的处理模型依然难以学到恶劣天气的真实影响。因为网络结构复杂天气信息很容易被其他强特征淹没。所以工程上通常先采用规则修正再逐步演进到完整的特征化模型。3.2 天气修正因子的整体设计设计修正因子时有四个原则值得注意。第一因子要有明确语义。“中雨”对应多少额外时间“六级风”对应多少额外时间这些数值要能解释清楚。第二因子与基础时长相乘而不是相加因为恶劣天气对配送时长的影响比例上更明显距离越长影响越大。第三要设置上限避免极端天气下预估时间过长给用户造成二次压力。第四不同的出行方式要分开计算电动车的雨天降速比例比汽车明显步行在雪天的影响又与骑行不同。3.3 规则型修正代码示例下面的函数演示了如何把天气特征作用到基础 ETA 上。def compute_eta_with_weather(base_eta, weather_features, rider_type): 根据天气特征修正基础 ETA。 :param base_eta: 正常天气下模型预估的配送时长单位分钟 :param weather_features: build_weather_features 的输出 :param rider_type: 出行方式可选 bike / car / walk :return: 修正后的 ETA factor 1.0 # 1. 降水修正 precipitation_factor { none: 1.0, light: 1.05, moderate: 1.15, heavy: 1.30, storm: 1.45, snow: 1.40, } factor * precipitation_factor[weather_features[precipitation_level]] # 2. 大风修正六级以上对两轮车影响明显 if weather_features[strong_wind]: factor * 1.15 # 3. 低能见度修正 if weather_features[low_visibility]: factor * 1.10 # 4. 出行方式修正 rider_type_factor { bike: 1.12, car: 1.0, walk: 1.05, } factor * rider_type_factor.get(rider_type, 1.0) return max(base_eta * factor, base_eta 5)这个函数的输入是基础 ETA 和天气特征输出是修正后的 ETA。因子采用乘法但同时用base_eta 5作为下限避免极端天气下预估时间反而变短。各因子的具体取值应从历史恶劣天气配送记录中回归得到而不是直接照搬网上其他项目的配置。3.4 从规则到学习模型的演进规则修正虽然实现成本低但表达力有限。随着恶劣天气样本的积累可以考虑把天气特征直接放入 ETA 模型让模型自己学习天气与配送时长的关系。此时需要格外小心特征穿越训练样本里的天气值应该使用预测时刻能获取到的天气数据而不是事后才记录的实测值。如果训练时用了“未来天气”模型上线后用不上效果就会大打折扣。另一个痛点是恶劣天气样本天然稀少且标签噪声大。一种做法是对恶劣天气样本做加权采样让模型更关注这部分数据另一种做法是单独训练一个“天气补偿模型”输入主模型的预测结果和天气特征输出一个修正量再与主模型集成。两种方案没有绝对优劣取决于工程团队的数据积累和迭代节奏。4. 调度系统恶劣天气下的运力保护4.1 调度系统为什么要感知天气调度系统解决的核心问题是什么订单、用什么方式、在什么时间、交给哪个骑手。正常天气下调度策略的目标是全局效率最优包括最短总行驶距离、最低超时率、最高骑手收入。恶劣天气下这个目标需要重新排序安全权重提升用户体验和骑手负担也要被纳入考量。如果调度系统感知不到天气它就会把雨天当作普通的一天继续给骑手派很多订单继续按正常路线规划结果就是超时率和安全事故同时上升。所以调度系统里必须有一个“天气风险评分”的概念。它作为订单分配、并行单量限制、配送费调整的公共输入让每一次派单决策都意识到天气的存在。4.2 订单分配与配送费调整恶劣天气下调度系统通常做以下三件事降低单个骑手的并行单量。雨天路况复杂同时接太多订单会让骑手在多个商家和用户之间来回穿梭风险成倍增加。调整订单分配权重。远距离订单或取送难度高的订单更倾向于分配给汽车运力或顺路运力。动态调整配送费和跑单奖励。用经济杠杆弥补运力供需缺口吸引更多骑手出勤。配送费动态调整的本质是“实时定价”。订单的配送难度可以拆成基础难度加天气额外难度天气额外难度映射成合理的费用增量。这里最值得关注的是口径一致性配送费计算使用的天气评分应该和 ETA 修正、调度风险评分来自同一套数据源否则会出现“预计送达时间增加了但配送费没有变化”这种让骑手难以理解的情况。4.3 调度策略调整代码示例下面用一段简化代码演示天气风险如何参与调度排序。真实调度系统会复杂得多但核心思想相同。def compute_order_rider_score(order, rider, weather_risk): 计算订单与骑手的匹配评分天气风险作为显式约束。 :param order: 订单对象包含距离、预计取餐时间等字段 :param rider: 骑手对象包含当前位置、并行单量等字段 :param weather_risk: 天气风险分取值范围 0.0 到 1.0 :return: 匹配分-1 表示不建议分配 if weather_risk 0.8 and rider.vehicle_type bike: # 高风险天气下两轮车不派送远距离订单 if order.distance_km 5.0: return -1 # 高风险天气下控制骑手并行单量 if rider.concurrent_orders 2: return -1 base_score get_base_match_score(order, rider) # 天气风险越高匹配分折损越大 weather_penalty weather_risk * 10.0 return base_score - weather_penalty def get_base_match_score(order, rider): # 基础评分距离越近、方向越顺、商家出餐越快分数越高 distance_score 10.0 / (order.pickup_distance order.delivery_distance 0.1) direction_score 5.0 if is_same_direction(order, rider) else 0.0 return distance_score direction_score这里的关键不是代码实现而是策略思想天气风险不是一个可选项而是一个硬约束。风险超过阈值时哪怕订单收益很高也会优先保障骑手安全。同时天气风险的阈值也应该是可配置的不同城市、不同季节、不同运力结构下系统的容忍度是不同的。5. 骑手端安全保护技术能做的兜底5.1 智能安全提醒骑手端 App 是平台触达骑手最直接的渠道也是安全能力落地的主要载体。恶劣天气来临时App 可以基于实时天气数据和骑手轨迹在启动配送前给出安全提示例如极端天气风险等级、建议减速路段、历史积水点信息。这些信息由天气服务和地图数据共同生成比单纯的气象预警更贴近骑手的实际骑行路线。更进一步系统可以结合骑手速度做动态干预。检测到骑手在暴雨中仍然高速骑行时推送提醒检测到骑手要进入已知的危险积水路段时建议绕行并同步更新预计送达时间。这一层能力需要安全规则引擎与地理围栏配合不是写几行判断代码就能完成的事但框架是清晰的。5.2 异常驻留与主动关怀传统异常检测会将“骑手在某个位置停留时间过长”判定为潜在异常。但在恶劣天气下停留可能是避雨、可能是积水过深无法通行也可能是摔倒受伤。如果系统只用正常天气下的规则就会出现两种情况要么误报率高运营被无效报警淹没要么漏报骑手被困很久都没人知道。更好的做法是结合天气数据做上下文判断。天气风险越高驻留检测的触发阈值就越低异常发生后不是直接触发处罚流程而是进入关怀链路先发一条确认消息没有回复就电话联系仍然联系不上再触发救援联动。这种设计把技术从“监控工具”变成了“安全工具”。5.3 一键求助与救援联动恶劣天气下骑手的一键求助功能价值会被放大同时也会面临更多挑战。暴雨天定位漂移更严重、信号可能不稳求助消息的发送和位置回传都要做容错处理。此外求助不只是通知客服还要能联动线下救援资源这需要提前完成地图、客服、运力调度、外部救援机构等多个系统的接口联调。这里给出一个工程建议在恶劣天气季节来临前安排一次“灾害天气应急演练”。模拟暴雨导致大面积积水、通信不稳、骑手被困等场景检查求助链路是否可用、消息是否能在弱网下送达、运营人员是否知道处置流程。技术系统真正可靠的时刻是在已经经过演练之后。6. 用户端预期管理把天气影响讲清楚6.1 前端 ETA 展示透明化用户看到的 ETA 其实是预估配送时长经过多次转换后的界面展示。恶劣天气下如果前端展示仍然基于正常天气 ETA用户必然产生过高期待。透明化的做法有两个一是展示天气延迟提示例如“所在区域正在下雨配送可能延迟”二是拉宽 ETA 区间例如“预计 35 到 50 分钟送达”而不是一个精确到分钟的单一时间点。这里有一个容易忽略的技术问题用户端展示的 ETA 和骑手端看到的订单时效必须保持同一套数据。否则用户看到的是延迟后的时间骑手端却仍然是旧时效超时判责时就会产生争议。接口层面最稳妥的方式是让两端读取同一个 ETA 字段而不是各自计算。6.2 无接触配送与免责机制恶劣天气下越来越多的用户会选择无接触配送。无接触配送在技术上并不复杂关键是订单备注的语义解析和取货通知的触达。平台可以在恶劣天气时默认开启无接触配送引导减少骑手与用户在物理空间的接触也减少等待时长。免责机制则直接关系到骑手收入和心理安全感。超时订单是否免除骑手责任不能靠人工逐单判断应该建立客观的“天气免责”开关当系统判定某区域在某时段的天气风险达到阈值自动将相关订单标记为天气免责。判责系统读取这个标记后不再将超时责任计入骑手考核。这个设计能让骑手在恶劣天气下不需要背负“不跑就扣钱”的心理压力。6.3 平台规则与用户体验的平衡平台规则需要避免自相矛盾。如果一边在恶劣天气下为骑手开通免责一边又用强时效指标排名和考核骑手那免责就形同虚设。系统设计上时效考核、超时判责、用户补偿应该统一到一套规则引擎中天气是其中的显式参数。用户侧同样需要公平。恶劣天气下配送延迟不应该由骑手承担全部责任但用户的损失也需要被妥善处理。常见的方案是平台主动发放无门槛优惠券或会员时效延长。这个决策可以由规则引擎自动触发基于订单延迟原因和天气免责标记。技术在这里的作用是让规则变得透明、一致、可解释。7. 恶劣天气后的数据复盘与系统迭代7.1 复盘指标体系恶劣天气过去后技术团队需要做一次完整复盘。复盘不能只看“今天超时了多少单”这种单一指标应该拆分出以下几类ETA 预测误差实际配送时长与预估时长的偏差在什么范围调度命中率订单是否被分配给了合适的运力安全事件数恶劣天气期间发生的事故、异常驻留情况骑手收入结构恶劣天气下的配送费调整是否有效用户投诉变化天气延迟引发的投诉是否下降。这些指标要按天气等级和片区维度做交叉分析。同样是中雨A 片区的 ETA 误差远高于 B 片区原因可能是 A 片区路面积水严重也可能是 A 片区的模型训练样本不足。归因决定了接下来的优化方向。7.2 样本沉淀与模型再训练每一次恶劣天气都是值的样本采集机会。天气数据、订单数据、骑手轨迹数据需要按统一格式落入数据仓库内容包括天气等级、片区编号、订单时长、骑手出行动态、实际送达时间、用户是否催单等。这些数据积累到一定规模后就可以用来重新训练天气修正因子或者开发专门的极端天气 ETA 模型。样本时效性需要持续关注。城市道路改造、地铁修建、骑手出行工具变化都会让历史天气样本的可用性下降。一般建议按季度对恶劣天气样本做一次数据质量审计剔除过时记录保证模型没有在旧数据上越学越偏。7.3 灰度与预案机制调度策略调整、ETA 修正、配送费动态调整都属于高风险系统改动。恶劣天气本身是小概率事件一旦改错短时间内很难完成回滚。因此天气策略一定要支持按城市、按片区、按天气等级灰度上线配合实时监控面板观察指标变化。更稳妥的做法是准备一套“恶劣天气预案包”。提前定义不同天气等级下要启用的策略组合、参数阈值和回滚条件。真正遇到恶劣天气时运营和研发团队只需要一键触发不需要现场调试代码。预案要经过演练否则真到紧急时刻还是会手忙脚乱。8. 常见问题与排查思路下面汇总了恶劣天气配送场景中常见的几类问题和排查方向适用于从 0 到 1 搭建天气配送能力的团队参考。问题现象可能原因排查方式解决方案雨天订单 ETA 偏短用户频繁催单天气特征没有传入 ETA 模型检查特征链路中是否有天气字段在预估模型接入天气修正因子恶劣天气下骑手超时率明显上升调度系统没有感知天气查看调度日志中是否有天气风险评分增加天气风险评分限制并行单量骑手在暴雨中长时间停留未被发现异常检测没有结合天气上下文查看驻留检测触发日志降低高风险天气下的驻留告警阈值用户端展示 ETA 与骑手端不一致两端使用了不同的 ETA 服务对比两端接口的输入输出统一 ETA 数据源天气免责订单没有被判责系统识别判责规则未读取天气免责标记查看判责规则配置将天气免责标记接入判责流程配送费调整后运力仍不足调价幅度不够或者用户接受度差分析订单取消率和响应率结合天气风险分自动调整费用策略暴雨时段并发请求导致天气服务超时天气服务没有做缓存和降级查看天气服务调用链路增加本地缓存配置降级策略极端天气样本过少模型效果不稳定历史数据积累不足统计各天气等级的样本量先采用规则修正再逐步演进到模型每个问题的排查路径都很直接但如果体系搭建得不够完善这些问题往往会同时爆发。所以从工程规划的角度看天气能力不应该是一个个补丁而应该是一个独立的基础服务。9. 工程实践建议与落地路径9.1 把天气当作“第一公民”从数据模型的角度看天气不应该被当作一个额外的注释字段而应该与地理位置、时间一样成为配送全链路的基础维度。订单、骑手、调度、ETA、结算所有环节都应该能按天气条件做检索、分析和策略配置。只有把天气当成“第一公民”恶劣天气下的系统设计才不会显得像四处打补丁。具体操作上可以考虑建设一个统一的天气风险服务对外输出天气等级、风险分、修正因子、免责标记等标准化字段。ETA、调度、判责、前端展示、配送费都以这个服务作为数据源。这样做的好处是口径一致也方便后续扩展新场景。9.2 安全兜底优先于履约诉求在恶劣天气场景下系统的目标排序应该是骑手安全大于履约体验履约体验大于效率成本。这不是一句口号而是需要落到具体的资源分配和策略选择中。运力不足时延长配送时间、缩小服务范围比让少数骑手承担全部订单压力更合理。骑手端的每一个安全提醒、调度端的每一个并行单量限制、判责端的每一个天气免责标记都是在为“安全优先”提供工程支撑。这些能力不一定能直接带来GMV增长但能够在关键时刻降低事故率从长期看反而会增强用户和骑手对平台的信任。9.3 用户预期管理要从下单前开始用户预期管理不是客服话术而是系统能力。它应该从用户搜索和下单阶段就开始介入展示天气延迟提示、提供更宽的 ETA 区间、在异常延迟时主动推送补偿方案。这其中的关键在于让前端的展示、后端的预估、售后的判责使用同一套数据口径。如果能做到这一点用户在恶劣天气下点外卖看到的不再是一个冷冰冰的“延迟配送”而是一个可以被理解的“天气导致的时间调整”。这既是对用户负责也是对骑手负责。9.4 后续值得深入研究的方向如果继续深入可以关注这几个方向基于雷达回波的短临降水预测让系统在暴雨形成之前就调整调度策略恶劣天气下的多运力联合调度把电动车、汽车、步行运力统一编排骑手安全画像与主动干预从个体维度发现风险并提前预警天气免责规则的量化边界明确什么程度的天气应该免责、什么程度的天气应该停止服务。回到文章最开始的问题。恶劣天气配送的辛苦是真实存在的但这份辛苦有一部分可以通过系统设计被分摊掉。骑手的坚持仍然是整个链条中最重要的变量但系统也不应该把所有不确定性都留给最末端的那个人。技术能做的事情是让天气变得可见、让预估变得可信、让调度变得克制、让安全得到兜底。等到这些能力逐步落地我们再在暴雨天打开外卖 App看到的不只是骑手冒雨前行的辛苦还有一个真正在替骑手分担压力的系统。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进