做了一段时间 LLM 驱动的自动驾驶闭环控制,我最深刻的体会是:不要指望大模型像传统控制器那样,每个毫秒都输出方向盘和油门。它确实聪明,能理解场景、会推理规划,但天生不是干“高频响应”的料。所以我们折腾出了一个叫AdaDrive的框架,核心思路用八个字就能讲清楚——按需介入、按量融合。
这个框架解决的是什么问题?简单说,就是在大模型放进闭环控制之后,如何在“性能”和“实时性”之间找到平衡点。很多团队一上来就让 LLM 直接接管控制输出,结果往往是被延迟打垮,或者在复杂场景下输出不稳定。AdaDrive 的做法是让 LLM 作为“慢支路”只在关键时刻出场,同时让传统控制逻辑作为“快支路”保持高频响应,两条支路输出按置信度动态融合。这个方案对正在做自动驾驶、机器人控制、以及各类具身智能项目的朋友,很有参考价值。尤其是那些“想把大模型用起来,但又被实时性卡住”的团队,这篇文章应该能给你一些直接可用的落地思路。
1. 为什么大模型做闭环控制总是“高开低走”
先说一个真实的现象。很多项目最开始 demo 的时候,大模型表现惊人:给它一段传感器状态,它能输出“前方有事故,准备向左变道”这样合理的决策。但一旦接到真实闭环系统里,长时间跑下来就开始翻车。是不大模型不行?不是,是使用方式不对。
1.1 三个硬伤:延迟、幻觉、交互成本
第一是延迟。LLM 推理一次动辄几百毫秒,哪怕做了量化加速,也很难压到毫秒级。但底层控制回路通常需要 20Hz 甚至 50Hz 的更新频率。如果每一步控制量都要等大模型回答,整个闭环就废了。这个感觉就像让一位战略顾问去当急诊科医生,顾问分析得再透彻,病人等不起。
第二是幻觉和稳定性。大模型偶尔会输出“听上去合理但实际危险”的指令。纯文本生成没有硬约束,遇到训练分布之外的输入,输出可能完全离谱。闭环控制最怕这种不可预期,因为系统会拿这个离谱输出去执行。性能指标不是靠一两次完美的表现撑起来的,而是靠长期的稳定分布。
第三是交互成本。如果按高频周期调用大模型,不管是用本地推理还是调云端服务,成本都非常可观。能耗、延迟、费用都会变成瓶颈。有人可能觉得“只在复杂场景用不就行了”,但问题是什么时候算复杂场景?这需要一个可靠的判断机制,这就是后文要说的触发模块。
1.2 慢快协作的思路从哪来
Slow-Fast 这种架构在视频理解领域已经非常成熟:一条慢路径以低帧率提取全局语义,另一条快路径以高帧率捕捉细节运动。控制领域其实也有类似的经典分层思想:决策层不用跑得快,但要看得远;执行层不用想得多,但要跟得紧。
所以 AdaDrive 的核心就是把这两种思想叠在一起,让 LLM 去承担决策层的“慢支路”,传统控制逻辑承担执行层的“快支路”。很多人一听 LLM 控制就觉得必须让大模型输出底层油门转向,其实这是个误区。让大模型输出“高层意图”或者“目标轨迹”,再由底层控制器去跟踪,这样既用上了语义理解能力,又保住了实时响应能力。
2. AdaDrive 框架设计:按需介入、按量融合
整个框架有一个核心原则:LLM 不要一直在线,但需要它的时候必须在线;LLM 的输出不要直接覆盖底层控制,要根据置信度去融合。这两个原则分别对应“按需介入”和“按量融合”。
2.1 慢支路负责意图,快支路负责执行
AdaDrive 一共有三个主要模块:慢支路、快支路、融合层。
慢支路是一个 LLM 规划器,运行频率很低,比如 1~2Hz,或者由事件触发。它输入的是场景语义摘要、自车状态、任务目标、历史决策摘要,输出的是高层目标路径或驾驶意图。比如“前方施工,走左侧车道”或者“目标点在前方 200 米,当前以巡航为主”。
快支路是一个常规的轨迹跟踪控制器,比如 MPC 或者 PID 类的方案,运行频率维持在 20~50Hz。它接收传感器状态和当前参考路径,输出具体的方向盘转角、油门刹车控制量。这一层不需要大模型,要的是稳定、低延迟、抗噪声。
| 维度 | 慢支路(LLM Planner) | 快支路(Low-level Controller) |
|---|---|---|
| 运行频率 | 1-2 Hz,或事件触发 | 20-50 Hz |
| 输入 | 语义摘要、全局目标、历史决策 | 局部感知、车辆状态、参考轨迹 |
| 输出 | 目标路径、驾驶意图 | 方向盘、油门、刹车 |
| 侧重点 | 语义理解、全局推理、场景泛化 | 稳定性、实时性、平滑控制 |
| 失败模式 | 幻觉、过时、响应慢 | 目标不合理、复杂场景泛化差 |
融合层负责把两条支路的输出变成最终的可执行指令。这里有一个关键设计:融合对象是规划轨迹,而不是底层控制量。也就是说,快支路始终在做跟踪,慢支路输出的是新的参考路径,融合层决定当前参考路径在多大程度上向新路径偏移。这样做能最大程度减少控制层面的抖动,也容易做安全约束。
2.2 触发机制:什么时候才值得唤醒大模型
“按需介入”的前提是我们得知道“需”是什么。AdaDrive 的触发机制分三类:周期触发、事件触发、不确定性触发。
周期触发最简单,比如每 500 毫秒强制让大模型看一眼全局状态,刷新一次高层意图。这种兜底方式避免某些异常事件长时间得不到语义层的关注。
事件触发也很好理解,比如感知模块检测到前方新增静态障碍、导航目标发生变更、或者 V2X 传来的路况信息发生变化,这些都会立刻唤醒慢支路。
最核心的是不确定性触发。系统里每一个传感器、预测、决策模块都会输出一个置信度或者预测误差。AdaDrive 把这些信号汇总成一个触发评分:轨迹预测误差突然变大、前方障碍物行为模式偏离预期、或者当前策略的决策熵过高,这些都表明“快支路自己搞不定了”。
这里有个细节,触发阈值不是拍脑袋定的。我的做法是先在离线数据集上把所有触发评分的分布统计一遍,取 P90 分位作为初始阈值,然后在线上用指数移动平均持续更新。还有一个容易踩的坑:不要用单一固定阈值去卡所有场景。高速场景和城区低速场景的“合理阈值”完全不同,所以 AdaDrive 里的阈值会根据当前环境复杂度动态调整,比如车道数、周围目标数量、车速这些因素都会参与计算。
2.3 融合机制:软切换而不是二选一
很多方案做慢快协作时,喜欢用硬切换:慢支路给出答案就全面接管,没给出就全听快支路。这样做的问题在于,大模型给出的是“高层意图”,它不会像底层控制器一样精确知道当前车辆在车道里的精确位置。一旦硬切过去,控制量很容易跳变。
AdaDrive 用的是一种动态置信度加权策略。慢支路输出的目标路径并不会直接覆盖参考路径,而是和当前参考路径按权重做插值。权重怎么定呢?看慢支路输出和当前场景的一致度。
具体来说,融合层会给慢支路输出计算一个置信度分数,这个分数综合考虑语义上下文匹配度、目标路径合理性、以及距离上一次触发的时间。然后把置信度映射到权重 alpha 上。alpha 越大,说明慢支路当前输出越可信,参考路径越偏向它;alpha 越小,说明快支路维持现状更稳妥。
权重还有一个变化率限制,每个控制周期 alpha 的变化量不能超过一个上限。这一步非常关键,直接决定了融合过程是“顺滑转向”还是“猛打方向盘”。
在融合层之外,还有一道强制安全保护:如果快支路检测到碰撞风险或者车辆失稳,会启动硬保护,直接屏蔽慢支路的当前输出,强制走安全轨迹。慢支路可以锦上添花,但不能在安全问题上“抢方向盘”。
3. 核心实现拆解:从离线训练到部署落地
这一节讲讲我在实现 AdaDrive 时踩过的坑和最终采用的方案。整个流程分三块:离线训练、状态构建、部署优化。
3.1 离线训练:先用模仿学习学意图,再用强化学习调闭环
慢支路的大模型不是拿来即用的。我们做过对比实验,直接拿通用的开源大模型去输出驾驶意图,效果很不稳定。它知道“应该怎么开”,但不知道“在这个场景里具体应该怎么开”。所以需要针对闭环控制任务做微调。
训练分两个阶段。
第一阶段是行为克隆。收集一批人工驾驶或者传统规控模块在仿真环境中跑出来的轨迹,把场景状态构造成 prompt,把目标输出构造成轨迹点序列,用监督学习的方式让大模型学会“给出合理的目标路径”。这个阶段相对容易,数据量不需要特别大,我从几万条片段开始,效果就基本能覆盖常见场景了。
第二阶段是闭环强化学习。行为克隆出来的模型在常见场景表现不错,但一遇到分布外情况还是容易犯错。所以我把它再接进闭环仿真环境里,用 PPO 类的算法做微调。奖励函数包含几个部分:任务完成进度给正向奖励、碰撞和偏离车道给大惩罚、舒适性指标(横向加速度变化率)给小幅惩罚。
这里一个非常重要的细节是:训练阶段必须模拟慢支路的延迟。大模型推理需要时间,如果训练时把慢支路当成零延迟来对待,部署后一有延迟整个决策链就乱套了。我在强化学习环境里给慢支路强制加了一个 200~500 毫秒的随机延迟,让模型学会在“旧信息”的基础上做决策,而不是假设每一次输入都是刚感知到的。
3.2 状态表征与上下文构建:让大模型“看得懂”快支路的处境
很多人在这一步容易犯一个错:试图把传感器的原始数据直接塞给大模型。不是不行,而是效率极低,而且 token 开销巨大。AdaDrive 的做法是构建一个结构化场景摘要。
具体来说,感知模块输出的目标列表会被转成一组固定格式的文本条目:目标编号、类型、相对位置、相对速度、行为预测(直行/变道/刹停)。地图信息也会被摘要成车道拓扑描述,比如“当前车道前方 100 米收窄为单车道,左侧车道可用”。自车状态则包括速度、航向角、当前参考路径的曲率趋势。
Prompt 里还要带上“历史决策摘要”。这一点常被忽略。大模型每次被触发唤醒时,如果看不到前面做了什么决策,就会“失忆式决策”:上一轮准备变道,这一轮又读了一遍场景,因为附近车辆位置稍有变化,突然决定不变了。所以我把上一轮的决策内容和理由压缩成一个摘要放在当前 prompt 里,保证语义层的连续性。
上下文长度也需要管理。自动驾驶场景的障碍物数量可能很多,全塞进 prompt 既浪费又可能干扰推理。我设定了一个动态裁剪策略:距离近、行为不确定性高的目标优先保留,远处的次要目标直接过滤。实测下来,这种方法比盲目堆信息效果更好,大模型输出也更稳定。
3.3 部署优化:量化、蒸馏与异步流水线
就算把大模型当慢支路用,延迟也不能太离谱。毕竟一个决策如果晚了 2 秒,早就不适用了。我在部署时做了几项优化。
第一是模型蒸馏。我们把微调后的大模型当作教师模型,用它的输出监督一个小规模的轻量模型的训练。这个小模型参数量大约只有教师模型的十分之一,专门用来拟合“慢支路”的输入输出映射。本地部署之后,单次推理延迟从 600 毫秒以上压到了 50 毫秒以内,运行频率甚至可以稳定跑到 10Hz 以上。
第二是量化。如果硬要保留较大模型,那就做 INT8 或者 INT4 量化。这一步能显著降低内存占用和推理延迟,但要注意对长上下文任务的精度影响。我做了一些评测,对目标路径输出的精度影响在可接受范围内。
第三是异步流水线。感知、场景摘要、慢支路推理、融合决策各环节完全并行。感知模块以 10Hz 产出结构化信息,场景摘要模块维护一个最新缓存,慢支路基于缓存做推理,快支路每 20 毫秒取一次最新的融合结果去执行。这种异步设计可以让整体链路不互相阻塞,比同步串行调用稳定得多。
4. 实验效果与关键调参经验
前面把框架讲清楚了,这节分享一些实验上的观测和调参心得。毕竟没有一套参数是放之四海皆准的,但我踩过的坑、试出来的规律应该能让后来者少走弯路。
4.1 评估指标:别只看文本回答质量
评价这种慢快协作系统,不能只看大模型的“回答质量”。回答再漂亮,闭环跑不起来也是白搭。我习惯用四个指标一起看:
| 指标 | 度量方式 | 说明 |
|---|---|---|
| 闭环任务成功率 | 完整跑完任务的占比 | 反映整体性能 |
| 人工干预率 | 每百公里平均干预次数 | 反映系统可靠性 |
| 平均决策延迟 | 融合层输出的更新时延 | 反映实时性 |
| 控制平滑度 | 控制量变化率的绝对值 | 反映融合是否顺滑 |
做对比实验时,这三组配置特别值得关注:全高频 LLM 直接控制、纯传统规则控制器、AdaDrive 慢快协作。全高频 LLM 方案在复杂场景的语义理解确实最强,但平均决策延迟高得离谱,而且长跑之后偶发不稳定输出,干扰率反而比规则方案还高。纯规则方案延迟低,但一旦遇到没定义过的场景,成功率明显下滑。AdaDrive 走的是中间路线:延迟接近规则方案,而复杂场景的成功率明显高于规则方案,整体干预率比全高频方案低了不少。
我自己的统计里,AdaDrive 相比纯规则方案,在几种典型长尾场景下任务完成率提高了约两成,同时平均干预率降了将近四成。当然这个数据跟具体环境和模型能力强相关,别当成绝对值,但趋势是可以参考的。
4.2 我调过几个关键参数
第一个是触发阈值的更新速度。EMA 系数调得太快,阈值会被感知噪声带偏,导致频繁误触发;调得太慢,又跟不上环境突变。我的经验是半衰期设在 2 秒左右比较合适。也就是说,新观测的影响力大约在 2 秒内衰减一半,既能跟上场景变化,又不会因为单帧噪声大幅波动。
第二个是融合权重的温度系数 T。这个参数控制置信度到权重的映射曲线。T 太大,alpha 大部分时间都趋近中间值,慢支路的决策介入感太弱;T 太小,alpha 接近 0/1 切换,融合层会退化成硬切换,控制量容易跳变。我试了从 0.1 到 1.0 的几组值,最后稳定在 0.3 附近,既保证了语义层的有效介入,又保持了切换的平滑。
第三个是alpha 变化率上限max_delta。我把它设成每个控制周期不超过 0.05,也就是从信任快支路完全切换到信任慢支路,大概需要 200 毫秒左右。这个跨度既不会让车辆反应迟钝,也不会因为指令突变导致横向抖动。安全模块介入的优先级始终高于融合层,这一点在参数设计上不要动摇。
5. 记录几个容易踩的坑
框架设计和调参都聊完了,最后记录几个我在实际运行中遇到的具体问题。这些问题在论文或者开源代码里很少被讲透,但几乎每个团队落地时都会撞上。
5.1 快慢指令打架,轨迹来回抖
有一段时间我们跑仿真,车辆在直线路段上轻微地左右摆。排查了很久才发现,问题出在慢支路输出的目标路径和快支路跟踪的参考路径发生了“对抗”:慢支路每轮给出一个稍带偏移的新路径,融合层把参考路径往那边拉,等到车辆真的偏移过去,下一轮感知状态已经变了,慢支路又出一个新路径,于是车就在来回修正中行驶,轨迹呈现锯齿状。
解决方式有两步。第一,给目标路径做了平滑处理,用二次规划把路径曲率变化约束到合理范围,避免相邻帧输出剧烈跳变。第二,给 alpha 变化率加上更严格的限幅,并把慢支路的触发冷却时间拉长,防止它在临界区域频繁介入。
5.2 大模型响应迟到,时序怎么对齐
异步架构带来的一个直接问题是:慢支路推理结果返回时,感知数据可能已经过了几百毫秒。如果直接拿这个“旧决策”去和当前状态融合,就会形成“用过去预测未来”的错位。
我的处理方式是在所有状态和输出上都打时间戳,融合层计算一个“结果时效性”指标,按时间差给慢支路输出打折:时间差越大,权重越低。超过一定阈值,比如 600 毫秒,直接丢弃本次结果,等待下一次触发。这个机制极大避免了大模型决策“迟到但不失效”造成的那种诡异行为。
另外,慢支路在输出目标路径时,我会要求它同时输出一个“预测有效期”范围。这个范围告诉融合层:“我这次决策在接下来的多少毫秒内有效。”融合层会拿当前时间和这个有效期比较,超期后自动把 alpha 拉回低值,恢复快支路主导。
5.3 感知噪声导致频繁误触发
最开始的不确定性触发模块用的是单一信号:前方目标预测误差。结果在个别场景里,因为感知对远处目标的速度估计抖动剧烈,触发评分时不时越线,大模型被反复唤醒。每一轮唤醒都会重新生成路径,虽然融合有平滑,但长时间跑下来,系统的行为还是显得“神经质”。
后面我改成“多信号投票”机制:轨迹预测误差、障碍物行为突变、语义环境变化三个信号独立打分,只有至少两个信号都越过各自阈值时,才真正触发慢支路。同时加入滞回比较器和冷却时间:触发后至少 500 毫秒内不重复触发,且要等评分显著回落到阈值以下之后,下一次触发才可能发生。这套组合下去,误触发率明显下降。
个人体会:大模型在闭环控制里最合适的定位是“参谋”,不是“驾驶员”。AdaDrive 这种慢快协作的意义不在于让 LLM 变得多聪明,而在于把聪明用在正确的时间和正确的层级上。如果你也在折腾 LLM 控制类的项目,我建议先把“什么时候需要大模型”和“大模型输出如何参与控制”这两个问题想清楚,再动代码。想清楚这两件事,整个系统的稳定性和实时性都能上一个大台阶。