OpenAI 将语音连接到 Decisions

2026-11-06 12:39 更新

通过 GPT-Live内置的 Decisions API 集成,可以在用户仍在说话时作出低延迟决策。

原生委派省去一次经过应用的往返。自定义委派中,Live 通知应用,由应用调用 Decisions;原生委派中,Live 直接调用 Decisions。

选择决策时机

  • 当 Live 识别到应用可以处理的请求时,让 Live 委派。在 session.delegation 中设置选项,并告诉 Live 何时委派。
  • 随着用户说话或 Live 回复,对对话作出反应。针对输入或输出转录增量配置 session.triggers。

可以在运行中的 Live 会话里更改问题。先发送 session.update,等待对应的 session.updated,再为该步骤添加决策项。委派类型在创建会话时设置,在该会话中保持不变。

让 Live 委派

一次请求中,Live 可以让 Decisions 从你定义的操作中选择,并判断应用是否应调用 Responses API。

以汽车语音助手为例,驾驶者可以要求调高或调低温度、打开或关闭前挡风玻璃除雾器,或者获取路线和寻找餐厅。选中 none 表示不改变对应车内控制项。

调整车内环境

环节 示例
驾驶者 “我觉得有点冷。”
决策结果 车内温度:升高;除雾器:不变;调用 Responses:否。
应用 调高温度,回读实际新设置,把完整车内状态追加到 Decisions。等待确认后,将结果发送给 Live。
Live 回复 “我把温度调高了一点。”

处理超出车内控制范围的请求

环节 示例
驾驶者 “前挡风玻璃起雾了,请除雾,导航到旧金山,再帮我找几家那里的好餐厅。”
决策结果 车内温度:不变;除雾器:开启;调用 Responses:是。
应用步骤 1 打开除雾器,状态为开启。
应用步骤 2 将驾驶者的完整请求和车内控制结果发送给 Responses。使用 Responses 返回的工具调用启动去旧金山的导航并寻找餐厅,把两项结果返回 Responses。
Live 报告 说明除雾器状态、导航是否启动,以及搜索找到的餐厅。

配置委派

从可用的 Live 连接和 api.decisions.write 权限开始。使用正常 Live 连接所需的请求头,不需要 Decisions 专用的 alpha 请求头。

在 WebRTC 会话请求中,将以下对象放在 session 下,与现有 transport 并列。会话指令告诉 Live 何时委派;选择题告诉 Decisions 返回什么。一次原生决策请求会分别回答全部三个问题。

来源示例 1(json):

程序文字译释14:委派驾驶者完整请求,包括车内控制、导航和本地搜索。等应用报告结果,再用自然语言告诉驾驶者。

程序文字译释15:驾驶者觉得冷或要更暖时选temperature_up,觉得热或要降温时选temperature_down,无关时选none。

程序文字译释16:挡风玻璃起雾或要求除雾时选on,玻璃已清晰或要求关闭时选off,无关时选none。

程序文字译释17:请求任一部分超出这些车内控制,例如导航或找餐厅,选yes,否则no。

{
  "model": "gpt-live-1",
  "instructions": "Delegate the driver’s whole request, including cabin controls, navigation, and local search. Wait for the app to report what happened, then tell the driver in natural language.",
  "delegation": {
    "type": "decisions",
    "decisions": {
      "model": "gpt-6-luna",
      "questions": [
        {
          "type": "choice",
          "name": "cabin_temperature",
          "instructions": "Choose temperature_up if the driver feels cold or wants more heat, temperature_down if they feel hot or want to cool down, or none if the request is unrelated.",
          "choices": [
            { "value": "temperature_up" },
            { "value": "temperature_down" },
            { "value": "none" }
          ]
        },
        {
          "type": "choice",
          "name": "windshield_defogger",
          "instructions": "Choose on if the driver reports a foggy windshield or asks to defog it, off if they say the glass is clear now or ask to turn the defogger off, or none if the request is unrelated.",
          "choices": [
            { "value": "on" },
            { "value": "off" },
            { "value": "none" }
          ]
        },
        {
          "type": "choice",
          "name": "needs_response",
          "instructions": "Choose yes if any part of the request goes beyond these cabin controls, such as getting directions or finding restaurants. Otherwise choose no.",
          "choices": [{ "value": "yes" }, { "value": "no" }]
        }
      ]
    }
  }
}

Live 会自动把对话转录文本发送给 Decisions。

执行操作并报告结果

从 session.delegation.created 保存 delegation.id。找到带有该 delegation_id 的 decision.event,当其 event.type 为 decision.completed 时,按问题名称读取 event.decision.answers 中的各项选择。none 表示对应操作无需执行。如果过滤 WebRTC 事件,应放行 session.delegation.created 和 decision.event。

对于“我觉得有点冷”,Decisions 选择 temperature_up、none 和 no。调高温度并读取实际设置。假设仪表盘现在显示自动模式、目标温度 22 °C、除雾器关闭,就通过 decision.item.create 把这个已确认的车内状态发送给 Decisions。

来源示例 2(json):

程序文字译释18:以最新车内状态快照为准:自动模式,目标温度22°C,挡风玻璃除雾器关闭。

{
  "type": "decision.item.create",
  "event_id": "evt_cabin_after_temperature_up_1",
  "item": {
    "type": "message",
    "role": "user",
    "content": [
      {
        "type": "input_text",
        "text": "Use the latest cabin state snapshot as the current state. Cabin temperature is set to 22 °C in automatic mode. Windshield defogger is off."
      }
    ]
  }
}

仅在仪表盘状态发生变化时,追加一份完整车内状态的精简快照,并以最新快照为当前状态。保留较早输入有助于维持提示词缓存所需的前缀。

等待 decision.item.created,然后使用此次请求的委派 ID,通过 session.commentary.append把结果发送给 Live。

来源示例 3(json):

程序文字译释19:我已调高车内温度,并在仪表盘确认新设置。

{
  "type": "session.commentary.append",
  "delegation_id": "del_cabin_1",
  "content": "I raised the cabin temperature and confirmed the new setting on the dashboard."
}

对于旧金山请求,Decisions 选择 none、on 和 yes。先打开除雾器、回读状态,并按上述方式追加新的车内状态快照,再通过具有 api.responses.write 权限的服务器调用 Responses。包含车内控制结果和驾驶者完整请求,使 Responses 能把“那里”关联到旧金山。

来源示例 4(bash):

程序文字译释20:指令:车辆已处理车内控制,使用工具处理其余请求,再依据实际结果简短告知驾驶者。输入:挡风玻璃起雾,要求除雾、导航去旧金山并找那里的好餐厅;车内结果为除雾器确认开启、温度不变。start_navigation说明:启动目的地导航并报告路线是否开始;find_restaurants说明:寻找指定城市或区域评价好的餐厅。

## [中文] 示例 4:执行操作并报告结果;以下保留本语言原始示例。
## [中文] 本段涉及的 HTTP 端点:/v1/responses;认证和请求体保持原示例形式。
curl https://api.openai.com/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6.1-sol",
    "instructions": "The car has handled the cabin controls. Use the tools for the rest of the request, then briefly tell the driver what happened based on the results.",
    "input": "Driver: My windshield is foggy, so please defog it, navigate to San Francisco, and find me some good restaurants there.\nCabin results: Windshield defogger confirmed on. Temperature unchanged.",
    "tools": [
      {
        "type": "function",
        "name": "start_navigation",
        "description": "Start navigation to a destination and report whether the route started.",
        "parameters": {
          "type": "object",
          "properties": { "destination": { "type": "string" } },
          "required": ["destination"],
          "additionalProperties": false
        },
        "strict": true
      },
      {
        "type": "function",
        "name": "find_restaurants",
        "description": "Find well-rated restaurants in the named city or area.",
        "parameters": {
          "type": "object",
          "properties": { "location": { "type": "string" } },
          "required": ["location"],
          "additionalProperties": false
        },
        "strict": true
      }
    ]
  }'

这是 Responses 函数调用流程的初始请求。对每个 function_call,使用提供的参数执行指定函数,再返回 function_call_output,其中包含实际结果或错误及匹配的 call_id。继续这一过程,直到 Responses 返回最终答案。

仅将 Responses 的简短最终答案与已确认的车内状态发送给 Live,使用相同 delegation_id 的 session.commentary.append。

对转录文本作出反应

需要随着对话进展决定时机时,使用转录触发器。数字人听到“我拿到这份工作了!”时,可以在用户仍在说话期间微笑并点头;输出触发器则可在 Live 说“太棒了!”时,让笑容加深并使角色身体前倾。

发生阶段 转录事件 话语示例 表情与动作
聆听时 session.input_transcript.delta 用户:“我拿到这份工作了!” 微笑并点头;开心,中等强度。
说话时 session.output_transcript.delta Live:“太棒了!” 微笑并前倾;开心,高强度。
另一聆听示例 session.input_transcript.delta 用户:“我没有拿到这份工作。” 难过并轻轻点头;悲伤,低强度。

把以下触发器添加到 session.triggers,分别选择表情、强度和手势:

来源示例 5(json):

程序文字译释21:根据对方最新话语,选择聆听时的表情。

程序文字译释22:选择该表情的表现强度。

程序文字译释23:选择与刚听到内容相符的手势。

{
  "type": "decisions",
  "event_type": "session.input_transcript.delta",
  "decisions": {
    "questions": [
      {
        "type": "choice",
        "name": "expression",
        "instructions": "Choose your expression as you listen to the person's latest words.",
        "choices": [
          { "value": "neutral" },
          { "value": "happy" },
          { "value": "sad" },
          { "value": "concerned" }
        ]
      },
      {
        "type": "choice",
        "name": "intensity",
        "instructions": "Choose how strongly to show that expression.",
        "choices": [
          { "value": "low" },
          { "value": "medium" },
          { "value": "high" }
        ]
      },
      {
        "type": "choice",
        "name": "gesture",
        "instructions": "Choose a gesture that fits what you just heard.",
        "choices": [
          { "value": "none" },
          { "value": "nod" },
          { "value": "shake" },
          { "value": "lean" }
        ]
      }
    ]
  }
}

要为回复添加动画,再添加一个触发器,把 event_type 设为 session.output_transcript.delta,要求选项与 Live 正在说的话相符。Live 会提供模型与触发器 ID。转录触发器独立于委派运行。

如果过滤 WebRTC 事件,除 decision.event 外,还必须放行各触发器对应的转录事件:session.input_transcript.delta、session.output_transcript.delta 或两者。只有源转录事件也被允许时,Live 才会传递对应的触发结果。

触发结果会标识促成决策的转录增量。下面展示“我拿到这份工作了!”示例中 decision.event 的相关字段:

来源示例 6(json):字段名、事件类型和示意值保留原样,含义见相邻正文;片段中的省略号不表示完整可运行程序。

{
  "type": "decision.event",
  "delegation_id": null,
  "trigger_id": "trg_listening_1",
  "source_event_type": "session.input_transcript.delta",
  "source_event_id": "evt_input_42",
  "event": {
    "type": "decision.completed",
    "decision": {
      "answers": [
        { "type": "choice", "name": "expression", "choice": "happy" },
        { "type": "choice", "name": "intensity", "choice": "medium" },
        { "type": "choice", "name": "gesture", "choice": "nod" }
      ]
    }
  }
}

用 source_event_id 匹配转录增量。Live 可以合并待处理增量,结果也可能乱序到达。对输入、输出两个方向分别应用最新的相关结果,嘴部动作则根据音频驱动。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号