本章聚焦于语音助手与物理车辆硬件交互的核心机制——车控工具调用(Vehicle Control ToolCall)。在 OpenAI Realtime API 和 Agents SDK 的架构下,大模型不仅仅是对话者,更是车辆的“执行中枢”。
车控系统的设计难度在于其连接了两个截然不同的世界:一个是概率性、模糊语义的 LLM 世界,另一个是确定性、硬实时、人命关天的嵌入式工程世界。
学习目标:
为了解耦模型与硬件,我们采用经典的三层漏斗模型设计 ToolCall。
[ User Voice ] "我有点热"
|
v
[ Layer 1: Intent & Semantic Layer ] (LLM / Agent)
-> 识别意图: AdjustClimate
-> 提取参数: {"direction": "cooler", "magnitude": "small"}
|
v
[ Layer 2: Vehicle Control Gateway (VCG) ] (Middleware)
-> 语义映射: "cooler" + current(24°C) = target(23°C)
-> 安全校验: 检查车辆电源状态、检查儿童锁
-> 权限裁决: 副驾是否有权调整全车温度?
|
v
[ Layer 3: Vehicle Hardware Abstraction Layer (V-HAL) ] (Embedded)
-> 信号转换: target(23°C) -> CAN Message ID 0x123, Data 0x17
-> 硬件执行: 发送至空调控制器 (HVAC ECU)
工具定义的粒度直接决定了 LLM 的理解准确率和令牌消耗。我们推荐“面向意图”而非“面向寄存器”的定义方式。
set_fan_speed(level), set_ac_mode(on/off), set_temp(val) 分散定义。adjust_climate(temperature, fan_speed, ac_mode, zone)。enable_nap_mode(): 同时执行(座椅躺平 + 车窗关闭 + 播放白噪音 + 闹钟设置)。enable_baby_mode(): 同时执行(音量限制 + 后排车窗锁止 + 空调柔风)。| 等级 | 标识 | 定义 | 典型功能 | 交互/鉴权策略 |
|---|---|---|---|---|
| L0 | INFO |
只读,无物理动作 | 查续航、胎压、说明书 | 直接返回数据,无鉴权 |
| L1 | COMFORT |
可逆,低干扰 | 音乐、氛围灯、香氛 | 隐式确认(”好的”),全员可用 |
| L2 | PHYSICAL |
物理动作,低风险 | 座椅加热、空调风向 | 需检查能源状态,建议区分座次权限 |
| L3 | CAUTION |
物理动作,环境敏感 | 车窗、天窗、遮阳帘 | 环境校验(雨天/高速),失败需解释 |
| L4 | CRITICAL |
涉及行驶安全 | 后备、车门锁、大灯 | 强制二次确认 + 零车速门禁 + 仅主驾 |
| L5 | BLOCKED |
法律/安全禁止 | 油门、转向、换挡 | 不暴露给 LLM,物理层隔离 |
VCG 是本系统的核心守门员,它运行在车机的高算力芯片(如 Qualcomm 8155/8295)的 Android/QNX 层。
LLM 说明的指令往往是不完整的(Partial)。VCG 必须维护一份车辆状态的缓存副本(Shadow State)。
control_window(seat="passenger", action="close")。pos = 50%。action="close" 意味着 target_pos = 0%。0%,VCG 直接拦截并返“已关闭”,不发送 CAN 信号(节省总线带宽)。LLM 擅长处理自然语言,但不擅长处理车企特定的物理量化标准。VCG 需负责“翻译”。
adjust_temp(delta="hotter")Target = Current_Temp + Step_Size (e.g., 1.0°C)Target = min(Target, Max_Limit)open_window(extent="a little bit")Target = Current_Pos + 10% (配置项: define_little_bit = 10%)open_window(extent="halfway")Target = 50%安全是车载系统的底线。我们采用拦截器模式 (Interceptor Pattern)。
function authorize_action(user_role, vehicle_state, tool_name, params):
# 1. 全局互斥锁 (e.g. 正在OTA升级中,正在紧急呼叫中)
if GlobalLock.is_locked(): return DENY("系统占用中")
# 2. 身份鉴权
if user_role == "GUEST" and tool_name in ["open_trunk", "user_profile"]:
return DENY("访客模式无权操作")
# 3. 驾驶状态门禁
if vehicle_state.speed > 0:
if tool_name in ["open_trunk", "video_playback", "pairing_bluetooth"]:
return DENY("行驶中禁止操作")
if tool_name == "open_sunroof" and vehicle_state.speed > 100:
return DENY("车速过快,禁止开天窗")
# 4. 环境感知互斥
if tool_name == "open_window" and vehicle_state.rain_sensor == ON:
return CONFIRM_REQUIRED("正在下雨,确定要开窗吗?")
return ALLOW
利用麦克风阵列的声源定位 (DOA),将语音指令绑定到特定座位。
seat_id="rear_left"。seat_id="driver",VCG 应基于 DOA 信号进行二次校验或纠正。车控动作的执行时间差异巨大(毫秒级到秒级)。
get_tire_pressure()。对于如“打开敞篷这种耗时 10秒+ 的操作:
Q1. 什么是“幽灵操作” (Ghost Operation)?在车控场景中如何通过设计避免它?
Q2. 为什么建议使用 adjust_climate(...) 这样一个大工具,而不是拆分成 set_temp, set_fan 等多个小工具?
Q3. 在设计“座椅加热”工具时,如何处理“主驾”和“副驾”的区分?
seat_id 参数 (enum: driver, passenger, rear_left, rear_right)。
1. 显式指定: 用户说“打开副驾座椅加热”,LLM 提取 seat_id="passenger"。
2. 隐式推断: 用户说“我有点冷”,LLM 输出 seat_id="current_speaker" (或留空)。
3. 网关解析: VCG 接收到 "current_speaker" 后,查询音频模块的声源定位 (DOA) 结果,将其替换为实际的物理座位 ID。
Q4. (架构设计) 设计一个“自动泊车”的语音交互流程。考虑到这是一个高风险、长耗时的过程,请详细描述从用户发出指令到泊车结束的每一个步骤,包括屏幕交互和异常处理。
start_auto_parking(slot_id="A")。
5. 安全握手 (Handshake):
- 系统不直接行动,而是弹窗并语音提示:“请松开刹车,双手离开方向盘,随时准备接管。”
- 用户确认(可能是语音“好了”,或点击屏幕“开始”)。
6. 执行与监视 (Execution):
- 车辆开始运动。
- 语音系统进入“实时播报模式”:“正在倒车... 正在避让行人...”。
7. 完成: 动作结束,挂 P 挡。Bot: “泊车已完成。”
Q5. (模糊逻辑) 用户说“把窗户开个缝”。请编写一段伪代码,说明 VCG 如何将其转化为具体的 CAN 信号。假设车窗全关是 0%,全开是 100%。
function handle_open_crack(seat_id):
# 1. 定义 "缝" 的大小
const CRACK_SIZE = 15%
# 2. 获取当前位置 (Shadow State)
current_pos = vehicle.windows[seat_id].position
# 3. 计算目标位置
# 如果已经在开着,就在当前基础上再开一点?还是保持最小通风位置?
# 策略:如果当前几乎全关 (<5%),设为 15%。
# 如果当前已经开很大了 (>20%),"开个缝"可能意味着"关小到只剩个缝"。
if current_pos < 5:
target_pos = 15
elif current_pos > 20:
target_pos = 15 # 意图理解为:关小到缝
else:
# 已经在缝的状态,可能用户没看清,保持不变或微调
target_pos = 15
return Response("窗户已经开了一条缝了")
# 4. 下发指令
vehicle.hardware.set_window(seat_id, target_pos)
return Response("已打开通风模式")
Q6. (回滚策略) LLM 调用了 set_seat_heat(level=3),但底层硬件返回 ERROR_OVERHEAT_PROTECTION (过热保护中)。此时 Realtime Session 应当如何处理?
{"status": "failed", "error_code": "E_OVERHEAT", "user_msg": "座椅温度过高,已触发保护"}
2. Tool Output 注入: 将上述 JSON 推送回 Realtime API 的会话上下文。
3. Agent 推理: 模型看到 status=failed,不再回复“好的,已开启”,而是根据 `user_msg` 生回复。
4. TTS 输出: “抱歉,检测到座椅温度过高,系统已触发过热保护,暂时无法开启加热。”
Speaker_Role 和 Vehicle_Speed。Media_Status == Playing 时,车控类指令应静默执行(不播放 TTS),或者仅以极短的提示音(”Ding”)作为反馈,并在屏幕上显示 Toast。