OpenAI 迁移到 GPT-Live

2026-11-06 12:39 更新

GPT-Live 负责聆听与说话,后端决定如何完成任务、调用哪些工具。保留现有工具实现、权限检查与任务记录;迁移时,将后端连接到 GPT-Live,并决定各类指令分别属于哪个模型。

本指南以预约助手为例:先查询可预约时间,请用户确认时段,再完成预约。从入门指南中的已连接会话开始,并保留原应用中有代表性的对话用于比较。

迁移之前

记录迁移后必须保留的要求:

  • 工具与业务规则:列出既有提示词、工具、工作流及各操作的触发条件。
  • 输入类型:确认音频、键入文字、图像分别从哪里进入应用,以及哪个后端需要这些输入。见添加图像与视觉上下文。
  • 依赖音频的决策:识别哪些决定除转录文字外还需要原始声音。见保留依赖音频的决策。
  • 语音与播放:规定何时可以开始讲话、何时必须停止,以及音频播放前必须完成哪些检查。
  • 权限与防护规则:列出授权、确认及输入输出检查,并明确应用在哪里执行。见适配防护规则。
  • 持久状态:识别断开连接及新建会话后必须保留的记录、任务进度与待执行操作。
  • 基线对话:保存现有应用的代表性对话,包括初始状态、预期工具操作、最终应用状态和口头回复。

会话设置见入门指南,比较方案可参考语音智能体评估 Cookbook。

选择委派模式

选择由谁运行后端:

  • Responses 委派:配置托管的 Responses 模型负责推理和工具选择,应用执行自定义函数并返回结果。如果目前由 Realtime 模型选择这些函数,这是合适的起点。
  • 客户端委派:保留现有智能体或编排器,由应用提供对话上下文、启动工作并决定发给 GPT-Live 的结果。

两种模式都可用于任一种迁移路径。例如,已有独立后端智能体的 Realtime 应用,可通过客户端委派保留该智能体。完整比较见选择委派模式。

选择迁移路径

当前语音模型负责选择工具时,从由 Realtime API 迁移开始。保留现有智能体、仅添加 GPT-Live 语音界面时,从由文本智能体或串联流水线迁移开始。

由 Realtime API 迁移

先阅读 GPT-Live 提示词指南。将既有提示词拆分给语音模型与后端,而不是整体复制到 session.instructions。对话风格和委派指导留在语音提示词,详细工作流及工具使用指令移到后端。

迁移前:Realtime 模型处理语音,并选择 check_availability、book_appointment 等函数;应用执行函数并返回结果。

迁移后:GPT-Live 处理语音并委派任务,后端选择同样的函数,应用仍负责验证和执行。这里使用 Responses 委派;保留外部智能体时,使用客户端适配器。

Responses 委派如何工作

在 delegation.responses 中配置后端模型、指令和工具。GPT-Live 判断请求需要后端工作时,Live 服务调用该 Responses 模型并提供相关对话上下文。后端推理并选择工具,应用仍执行自定义函数、强制权限规则并返回结果。

预约助手的流程为:

  1. 用户询问周五可预约时段,GPT-Live 委派请求。
  2. Responses 后端请求 check_availability。
  3. 应用执行函数、返回结果,并继续后端响应。
  4. GPT-Live 根据后端答案与用户讨论可选时段。

后端工作期间,GPT-Live 可以继续讲话。后端任务与音频播放分开追踪:工具结果更新任务状态,播放器状态更新讲话指示。配置与完整事件流见委派与工具。

适配连接与音频生命周期

用 GPT-Live 连接流程替换 Realtime 会话设置,并重新检查传输的启动过程和音频格式。WebRTC 在媒体轨道上传音频、数据通道上传 JSON 事件;主 WebSocket 则在 JSON 事件中承载音频。

如果 Realtime 应用用服务端连接监控通话或执行防护规则,应改为 GPT-Live 旁路连接。对话检查与播放的变化见适配防护规则。

既有 Realtime 行为 GPT-Live 中的调整
用 input_audio_buffer.append 发送 WebSocket 音频。 改用 session.input_audio.append,audio 字段放 Base64 原始音频。
播放 response.output_audio.delta 的 delta。 按顺序播放 session.output_audio.delta 的 delta。
手动轮次控制时提交音频或创建响应来开启轮次。 连续传输音频,由 GPT-Live 决定何时讲话;移除手动音频提交与语音轮次触发。
用 response.output_audio.done、response.done 追踪生成和响应完成。 GPT-Live 没有标记每段语音回复结束的对应事件,播放由客户端追踪。
从输入转录事件显示用户字幕。 追加 session.input_transcript.delta 到用户字幕。
从 response.output_audio_transcript.delta 显示助手字幕。 追加 session.output_transcript.delta 到助手字幕。

生成与播放:讲话指示应由播放器驱动。服务器可能已生成完,播放器却还排着一秒音频。Realtime 的 response.output_audio.done 表示生成结束,response.done 表示响应流结束,还需检查 response.status 了解打断或失败。GPT-Live 没有与每段语音回复结束等价的事件。

字幕:开启输入转录后,Realtime 用 conversation.item.input_audio_transcription.delta 发文本片段,用 conversation.item.input_audio_transcription.completed 发最终转录。GPT-Live 中,将每个片段追加到来电者或助手字幕,两边可同时变化。应用决定文字分组,并通过播放器追踪播放。见显示字幕。

response.create 用于启动或继续被委派的 Responses 工作。GPT-Live 一边聆听,一边决定何时讲话。启动、问候、打断和会话关闭见管理会话。

拆分对话与后端指令

从原 Realtime 助手提示词开始,把说话风格、轮次交替指令移到 Live 提示词,添加委派时机规则。任务指令和工具使用流程保留在后端。

为文本智能体增加语音时,复用其既有后端提示词,另写负责语音交互的 Live 提示词。

保持体验一致

保留助手角色、受众与目的,以及影响对话的细节:

  • 问候、介绍和口头告知声明,包括必要措辞与顺序。
  • 语言与发音要求,例如“说英语”。
  • 个性、亲和力、同理心、正式程度与节奏。
  • 口头回答的详细程度及展示预期风格的示例。
  • 如何回应用户、停下来聆听以及处理打断。

简短 Live 提示词也可以要求详细的口头回答。

编写 Live 提示词

采用推荐提示词结构描述身份、说话风格和对话行为。保留 Backchannel policy 与 Interruption policy,说明简短聆听反馈及被插话时如何回应。

Live 需要知道后端能力才能准确委派。用日常语言描述能力;函数名与工具结构留在处理工具调用的后端。

在 Delegation policy 下,按应用调整以下部分:

  • Backend tools:沿用原提示词术语列出支持能力,例如“检查预约可用性并安排回电”。
  • Delegate to the backend when:说明何时使用能力,例如“用户要求安排回电时委派”。也应涵盖对进行中工作的纠正、确认与新增细节。
  • Do not delegate to the backend when:说明 Live 能直接处理什么,例如问候、简短澄清,或复述对话及仍有效的后端结果。

说明 Live 应如何传达进度、询问后端的下一个问题或转达已验证结果。

如果助手会结束通话,给 Live 告别与委派结束通话请求的指令;实际结束工具和顺序放在后端。例如,流程可能要求应用播放完告别、断开连接、取消待处理计算并阻止继续保存。Live 负责告别与委派,其余步骤由后端和应用执行。

适配后端提示词

以原提示词为起点,在仍适用的地方保留措辞、顺序、示例和结构。如果原文主要描述任务,大部分可以原样保留。

后端保留以下指令:

  • 理解请求、应用纠正、收集缺失信息并追踪进度。
  • 使用领域事实、检查资格,并查阅能确立答案的记录或服务。
  • 遵循搜索、更新、确认、路由、转接、回电等支持操作的流程。
  • 执行安全、隐私、授权规则,处理失败,并限制转接或通话结束后的操作。
  • 准备准确事实、任务状态及下一问题,交给 Live 表达。

声音、问候、轮次交替和委派时机移到 Live 提示词。假定后端直接向用户讲话的指令,改为向 Live 返回信息。凡会影响模型能说、问或做什么的安全与隐私限制,应在两套提示词各自需要的地方保留。

函数名、参数要求和工具使用流程留在后端指令中;工具定义放在后端工具配置。应用执行工具,并依据当前任务状态强制检查权限、参数与必要确认。

由后端模型理解对话中的请求、纠正和确认。正则表达式、关键词列表和精确短语规则无法覆盖依赖前文或纠正的信息。例如,“是”可能是在确认时段、回应问题或指代更早的建议。

保留来电者打断、通话转接或结束时对已运行工作的规则。停止语音不会停止后端工作。用户要求取消时,后端与应用应处理取消并向 Live 报告结果。

解决指令冲突

审查原提示词与两套新提示词,找出相互矛盾的指令。合并重复项,特定条件和例外应紧邻对应规则。检查权限、提问次数限制、确认要求及通话结束后允许的操作。

区分用户想要什么与已经发生什么。来电者把周五改为周四时,最新请求要求后端处理周四;预订记录则说明周五是否已订好。下一步可作何修改,取决于既有确认与授权规则。

使用提示词前,与负责产品选择的人明确冲突。例如,一条指令要求继续预约,另一条要求用户插话后停止全部工作,就应先决定产品实际行为,再写入提示词和应用执行逻辑。

核对每项必需操作都有实现。结束通话需要实际结束能力,仅说再见不会关闭连接。缺少能力时,决定实现它,或与工作流负责人约定受支持的替代方式。

审查两套提示词

与原提示词比较,确认所有必要行为均有归属:

  • Live 提示词保留身份、词汇、说话风格、告知声明及打断行为。
  • 后端提示词保留任务流程、事实、条件、示例、权限和失败处理。
  • 委派涵盖新请求、纠正、确认以及混合对话与任务信息的请求。
  • 两套提示词对提问次数、操作确认时机、工作继续、取消、转接和结束通话的规则一致。

Live 提示词放在 session.instructions。Responses 委派的后端提示词放在 session.delegation.responses.instructions;客户端委派则保留在现有智能体配置。工具定义始终留在后端。配置与结果处理见委派与工具。

示例:拆分预约提示词

预约助手已有 check_availability 和 book_appointment 工具。原提示词将说话风格与预约流程混合,拆分后仍保留相同问候、确认要求和纠正处理。

原始提示词:

来源示例 1(text):

本例中文译文与说明:

你是 Northstar Repairs 的预约助手 Rowan。用英语平静、简短地讲话,只问候一次:“你好,我是 Northstar Repairs 的 Rowan,有什么可以帮助你?”用简短声音回应表示在聆听,被打断时停止讲话。

帮助来电者寻找并预订预约。缺少日期或时区时先询问,再调用 check_availability。只提供工具返回的时段。调用 book_appointment 前,请来电者确认准确时段。日期、时区或时段变化时,丢弃此前确认并重新查询。只有工具确认成功后才报告预约完成;结果不明时说明尚未确认,不自动重试。

You are Rowan, the appointment assistant for Northstar Repairs.
Speak English, calmly and briefly. Greet the caller once with:
"Hello, this is Rowan from Northstar Repairs. How can I help?"
Use brief listening acknowledgments. Stop speaking when interrupted.

Help callers find and book appointments. Ask for the preferred date
and time zone if missing, then use check_availability.
Offer only returned slots. Ask the caller to confirm the exact slot
before calling book_appointment.
If the caller changes the date, time zone, or slot, discard the earlier
confirmation and check availability again.
Report a booking only after the tool confirms success. If the outcome
is unclear, say it is unconfirmed and do not retry automatically.

Live 提示词:

来源示例 2(text):

本例中文译文与说明:

你是 Northstar Repairs 的预约助手 Rowan,用英语平静、简短地讲话,只问候一次:“你好,我是 Northstar Repairs 的 Rowan,有什么可以帮助你?”

Backchannel policy:使用简短聆听回应。
Interruption policy:被打断时停止讲话并聆听。

Delegation policy:
Backend tools:预约能力包括查询可用时段和预订。
Delegate to the backend when:来电者要查询或预订;提供或纠正日期、时区、时段,或回答预约问题,包括确认时段。
Do not delegate to the backend when:来电者问候或要求重复仍有效结果;需要简短澄清以理解需求。

转达后端问题与结果,只提供返回时段。后端确认成功前不得声称已订好;后端表示结果不明确时,说明尚未确认。

You are Rowan, the appointment assistant for Northstar Repairs.
Speak English, calmly and briefly. Greet the caller once with:
"Hello, this is Rowan from Northstar Repairs. How can I help?"

Backchannel policy: Use brief listening acknowledgments.

Interruption policy: Stop speaking when interrupted and listen.

Delegation policy:
Backend tools:
- Appointments: check available times and book appointments.

Delegate to the backend when:
- The caller wants to find or book an appointment.
- The caller supplies or corrects a date, time zone, or slot, or
  answers a booking question, including confirming a slot.

Do not delegate to the backend when:
- The caller greets you or asks you to repeat a still-current result.
- You need a brief clarification to understand what they are asking.

Relay the backend's questions and results. Offer only slots it returns.
Do not claim a booking is complete until the backend confirms success.
If the backend reports an unclear outcome, say it is unconfirmed.

后端提示词:

来源示例 3(text):

本例中文译文与说明:

帮助来电者为 Northstar Repairs 查询并预订。缺少日期和时区时先问,再用 check_availability。只提供返回时段。调用 book_appointment 前确认具体时段。来电者更改日期、时区或时段时,丢弃此前确认并重新查可用性。
只有工具确认成功后报告完成;结果不明时标为尚未确认,不自动重试。

返回可用时段、预订结果或下一个问题,交给语音助手传达。结合对话和当前任务状态理解来电者最新回答与纠正。

Help callers find and book appointments for Northstar Repairs.
Ask for the preferred date and time zone if missing, then use
check_availability. Offer only returned slots.
Ask the caller to confirm the exact slot before calling book_appointment.
If the caller changes the date, time zone, or slot, discard the earlier
confirmation and check availability again.
Report a booking only after the tool confirms success. If the outcome
is unclear, report it as unconfirmed and do not retry automatically.

Return the available slots, booking outcome, or next question for the
voice assistant to communicate. Interpret the caller's latest answers
and corrections using the conversation and current task state.

适配函数处理器

保留 check_availability 与 book_appointment 的实现。把工具定义从 Realtime 的 session.tools 或 response.tools 移至 delegation.responses.tools,并采用 Responses 函数结构。工具选择设置移至 delegation.responses.tool_choice 和 delegation.responses.parallel_tool_calls。见配置 Responses 委派。

函数仍为原 call_id 返回结果,变化的是接收调用和发送结果的位置:

步骤 Realtime API GPT-Live 配合 Responses 委派
接收完成的函数调用 读取 response.output_item.done。 解开 response.event,读取内部 response.output_item.done。
识别并执行操作 读取 name、arguments、call_id,运行获授权处理器。 保留处理器与检查,另存外层 delegation_id 和后端响应 ID。
返回每个函数结果 发送 conversation.item.create。 发送 response.item.create。
全部必要结果返回后继续 发送 response.create。 发送 response.create 以继续后端工作。

例如,check_availability 返回已验证时段后,在连接的会话发送以下事件,把 call_availability 替换为收到的调用 ID。

迁移前:Realtime 结果:

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

{
  "type": "conversation.item.create",
  "item": {
    "type": "function_call_output",
    "call_id": "call_availability",
    "output": "{\"available\":true,\"slot_id\":\"slot_friday_14\",\"booked\":false}"
  }
}

迁移后:GPT-Live 结果:

来源示例 5(javascript):

// [中文] 示例 5:适配函数处理器;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:response.item.create;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:connection.send;异步调用及事件接收顺序保留。
// [中文] 返回函数结果时保留对应 call_id;响应继续事件与结果项目是两个独立步骤。
export function sendUpdate(connection) {
  connection.send({
    type: "response.item.create",
    event_id: "availability_result_1",
    item: {
      type: "function_call_output",
      call_id: "call_availability",
      output: '{"available":true,"slot_id":"slot_friday_14","booked":false}',
    },
  });
}

来源示例 6(python):

## [中文] 示例 6:适配函数处理器;以下保留本语言原始示例。
## [中文] 沿原示例执行这些方法:connection.response.item.create;异步调用及事件接收顺序保留。
## [中文] 返回函数结果时保留对应 call_id;响应继续事件与结果项目是两个独立步骤。
from openai.resources.live.live import AsyncLiveConnection
from openai.resources.live.sideband import AsyncSidebandConnection
from openai.types.responses.response_input_item_param import ResponseInputItemParam


async def send_update(
    connection: AsyncLiveConnection | AsyncSidebandConnection,
) -> None:
    item: ResponseInputItemParam = {
        "type": "function_call_output",
        "call_id": "call_availability",
        "output": '{"available":true,"slot_id":"slot_friday_14","booked":false}',
    }
    await connection.response.item.create(
        event_id="availability_result_1",
        item=item,
    )

// [中文] 保留原例中客户端、输入和返回值的处理顺序;本段需结合所在小节的连接前提使用,未通过真实API调用验证。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import (
    "context"
    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/live"
    "github.com/openai/openai-go/v3/responses"
)

// SendUpdate requires a started Live session.
func SendUpdate(ctx context.Context, connection *live.LiveConnection) error {
    return connection.Send(ctx, live.ClientEventUnionParam{OfResponseItemCreate: &live.ResponseItemCreateEventParam{
        EventID: openai.String("availability_result_1"),
        Item:    responses.ResponseInputItemUnionParam{OfFunctionCallOutput: &responses.ResponseInputItemFunctionCallOutputParam{CallID: openai.String("call_availability"), Output: responses.ResponseInputItemFunctionCallOutputOutputUnionParam{OfString: openai.String("{\"available\":true,\"slot_id\":\"slot_friday_14\",\"booked\":false}")}}},
    }})
}

// [中文] 保留原例中客户端、输入和返回值的处理顺序;本段需结合所在小节的连接前提使用,未通过真实API调用验证。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import com.openai.helpers.LiveConnection;
import com.openai.models.live.*;
import com.openai.models.responses.*;

public static void sendUpdate(LiveConnection connection) {
  connection.send(
      ClientEvent.ofResponseItemCreate(
          ResponseItemCreateEvent.builder()
              .eventId("availability_result_1")
              .item(
                  ResponseInputItem.FunctionCallOutput.builder()
                      .callId("call_availability")
                      .output(
                          "{\"available\":true,\"slot_id\":\"slot_friday_14\",\"booked\":false}")
                      .build())
              .build()));
}

## [中文] 返回函数结果时保留对应call_id;结果项目与继续响应是独立步骤,必须按代码显式续接并持续处理错误事件。
def send_update(connection)
  connection.send_event(
    type: "response.item.create", event_id: "availability_result_1", item: {
      type: "function_call_output",
      call_id: "call_availability",
      output: "{\"available\":true,\"slot_id\":\"slot_friday_14\",\"booked\":false}"
    }
  )
end

提交所有必要函数结果后继续后端:

来源示例 7(javascript):

// [中文] 示例 7:适配函数处理器;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:response.create;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:connection.send;异步调用及事件接收顺序保留。
export function sendUpdate(connection) {
  connection.send({
    type: "response.create",
    event_id: "continue_availability_1",
  });
}

来源示例 8(python):

## [中文] 示例 8:适配函数处理器;以下保留本语言原始示例。
## [中文] 沿原示例执行这些方法:connection.response.create;异步调用及事件接收顺序保留。
from openai.resources.live.live import AsyncLiveConnection
from openai.resources.live.sideband import AsyncSidebandConnection


async def send_update(
    connection: AsyncLiveConnection | AsyncSidebandConnection,
) -> None:
    await connection.response.create(
        event_id="continue_availability_1",
    )

// [中文] 显式请求创建或继续响应,使用本段实际设置的模态、上下文与工具字段;发送请求不等同于收到完成事件。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import (
    "context"
    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/live"
)

// SendUpdate requires a started Live session.
func SendUpdate(ctx context.Context, connection *live.LiveConnection) error {
    return connection.Send(ctx, live.ClientEventUnionParam{OfResponseCreate: &live.ResponseCreateEventParam{
        EventID: openai.String("continue_availability_1"),
    }})
}

// [中文] 显式请求创建或继续响应,使用本段实际设置的模态、上下文与工具字段;发送请求不等同于收到完成事件。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import com.openai.helpers.LiveConnection;
import com.openai.models.live.*;

public static void sendUpdate(LiveConnection connection) {
  connection.send(
      ClientEvent.ofResponseCreate(
          ResponseCreateEvent.builder().eventId("continue_availability_1").build()));
}

## [中文] 显式请求创建或继续响应,使用本段实际设置的模态、上下文与工具字段;发送请求不等同于收到完成事件。
def send_update(connection)
  connection.send_event(type: "response.create", event_id: "continue_availability_1")
end

首次迁移可设置 parallel_tool_calls: false,一次处理一个工具调用。从内部 response.output_item.done 收集调用,保存名称、参数和 call_id,即使后续完成事件包含 output: [] 也要保留记录。等项目完整后才运行处理器,单独的参数完成事件缺少函数名和 call_id。收集、提交输出和错误处理的完整过程见函数结果流程。

保留上下文并应用纠正

Responses 委派会向后端提供相关语音对话上下文。应用维护权威预约状态,包括选中时段、已确认时段、权限、活动操作及结果。Live 历史可能被压缩,不能当作预订记录。

用户说“其实改成周五”时,把周五记为当前请求,清除周四的确认,并为任务使用新版本号,如修订 2,以识别旧请求结果。

预订前检查日期、时段和确认仍匹配当前请求。因用户变更而不执行待处理函数时,返回与实际情况相符的“跳过”或“已取消”结果。继续后端前,每个必要调用都必须有结果。

如果周四预约已成功,先查当前状态并处理更改要求,再尝试另一预约。

原样保存每个转录片段及讲话者、start_ms、end_ms,据此更新正确字幕或气泡,包括片段迟到或双方同时说话的情况。应用选择消息边界,播放器追踪音频;转录时间戳不是精确逐词播放时间。重要日期、姓名或数字意图不明时应澄清。转录与上下文处理见管理会话。

图像与屏幕上下文:如果原 Realtime 应用接收图像,应把图像路由到具备视觉能力的后端,再给 GPT-Live 返回相关文字。两种委派模式都支持。见添加图像与视觉上下文。

保留依赖音频的决策

有些决定必须听声音本身,例如检测语音信箱提示音,或根据时序识别录制的问候。GPT-Live 能听到通话,但委派不会自动把音频发给后端。客户端模式的 session.delegation.created 只含 ID 与时间信息,请求上下文及后端需要的音频由应用提供。

答录机检测应明确把来电音频发送到支持音频的检测器。一种可评估的应用管理架构是,在通话一段时间内并行运行独立 Realtime 会话和 GPT-Live:

  1. 将同一份呼入音频复制给两个会话。
  2. 检测器通过结构化函数调用报告分类。按结构校验结果,拒绝过期结果,证据不足时保留未知状态,允许后续证据修正判断。
  3. 向 GPT-Live 提供相关可信上下文,输出音频播放遵循应用政策。

分别追踪两项决定:对端是人还是机器,以及对端是否已准备好录制留言。检测器可能在问候仍播放时就识别出语音信箱。允许输出音频前,应等待应用所需证据。上下文确认只表示更新被接受,播放决定仍由应用作出。用适配防护规则与播放控制,在应用控制的音频路径执行该决定。

测试短暂“你好”随后变为语音信箱问候、来电筛选提示,以及留言过程中真人接听的情形。若计划在通话结束前停掉检测器,还需测试此后真人接听的情况。结合结果与额外费用决定检测时长,也应包含最初判断为真人、后续因更多音频而修正的案例。

由文本智能体或串联流水线迁移

迁移前:文本智能体接收书面请求,使用自身工具与已保存状态。串联式或级联式语音流水线,在智能体前添加语音转文字,在后添加文字转语音。

迁移后:GPT-Live 提供语音界面,将任务委派给既有智能体。对于串联流水线,它替代独立的语音转文字和文字转语音阶段。后端仍适用的模型、指令、工具、工作流与持久状态均予以保留。

连接既有智能体

设置会话时将 delegation 配置为 {"type":"client"}。应用收到如下通知:

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

{
  "type": "session.delegation.created",
  "offset_ms": 1000,
  "delegation": {
    "id": "item_appointment_1",
    "type": "delegation",
    "target": "client"
  }
}

用此通知启动应用委派处理器。保留 delegation.id,把结果关联到同一请求。处理器依据双方转录及应用任务记录准备智能体输入;通知本身不含请求文字或工具参数。

例如,预约智能体可以收到:

来电者:“其实改成周五。”

当前请求:寻找来电者所在时区的周五预约。

先前结果:曾提供周四下午两点。

确认状态:尚未确认任何周五时段。

任务修订:2。

通知可能早于整句转录到达。应暂存通知,等上下文足够,或在行动前请用户澄清。

文本应用可能直接把用户最新消息传给智能体;GPT-Live 中应增加适配器,提供上述上下文,并返回简明、已验证的结果。

调用适配器前记录委派 ID,确保只有一个处理器为其启动工作。请求不清楚时,可在上下文就绪后再次调用适配器。

授权、确认、操作 ID 与重试仍由后端负责。更改预约前检查当前任务修订号。适配器后面的修订检查只能防止播报过时结果,不能撤销已完成预约。

将客户端委派连接到智能体:

来源示例 10(javascript):

// [中文] 示例 10:连接既有智能体;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:session.commentary.append;不要将构造载荷等同于收到成功确认。
// [中文] 委派 ID 与响应、工具调用 ID 不同;追加上下文时,非空 delegation_id 须对应客户端委派,null 用于会话级上下文。
async function handleDelegation(event, app) {
  if (
    event.type !== "session.delegation.created" ||
    event.delegation?.target !== "client"
  )
    return;

  const context = app.readContext();
  if (!context) return; // Retain the notice; resolve the request before acting.

  const summary = await app.runAgent({
    revision: context.revision,
    recentConversation: context.recentConversation,
    task: context.task,
  });

  if (app.currentRevision() !== context.revision) return;

  app.send({
    type: "session.commentary.append",
    event_id: crypto.randomUUID(),
    delegation_id: event.delegation.id,
    content: summary,
  });
}

来源示例 11(python):

## [中文] 示例 11:连接既有智能体;以下保留本语言原始示例。
## [中文] 沿原示例执行这些方法:connection.session.commentary.append;异步调用及事件接收顺序保留。
## [中文] 委派 ID 与响应、工具调用 ID 不同;追加上下文时,非空 delegation_id 须对应客户端委派,null 用于会话级上下文。
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from uuid import uuid4

from openai.resources.live.live import AsyncLiveConnection
from openai.resources.live.sideband import AsyncSidebandConnection
from openai.types.live.server_event import ServerEvent


@dataclass(frozen=True)
class Context:
    revision: int
    recent_conversation: str
    task: str


async def handle_delegation(
    event: ServerEvent,
    connection: AsyncLiveConnection | AsyncSidebandConnection,
    *,
    read_context: Callable[[], Context | None],
    run_agent: Callable[[Context], Awaitable[str]],
    current_revision: Callable[[], int],
) -> None:
    if (
        event.type != "session.delegation.created"
        or event.delegation.target != "client"
    ):
        return
    context = read_context()
    if context is None:
        return  # Retain the notice; resolve the request before acting.
    summary = await run_agent(context)
    if current_revision() != context.revision:
        return
    await connection.session.commentary.append(
        event_id=str(uuid4()),
        delegation_id=event.delegation.id,
        content=summary,
    )

// [中文] 保留原例中客户端、输入和返回值的处理顺序;本段需结合所在小节的连接前提使用,未通过真实API调用验证。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import (
    "context"
    "crypto/rand"
    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/live"
)

type Context struct {
    Revision           int
    RecentConversation string
    Task               string
}

func handleDelegation(ctx context.Context, event live.ServerEventUnion, connection *live.LiveConnection,
    readContext func() *Context, runAgent func(context.Context, Context) (string, error), currentRevision func() int) error {
    if event.Type != "session.delegation.created" || event.AsDelegationCreatedEvent().Delegation.Target != "client" {
        return nil
    }
    snapshot := readContext()
    if snapshot == nil {
        return nil
    } // Retain the notice; resolve the request before acting.
    saved := *snapshot
    summary, err := runAgent(ctx, saved)
    if err != nil {
        return err
    }
    if currentRevision() != saved.Revision {
        return nil
    }
    return connection.Send(ctx, live.ClientEventUnionParam{OfSessionCommentaryAppend: &live.CommentaryAppendEventParam{
        EventID: openai.String(rand.Text()), DelegationID: openai.String(event.AsDelegationCreatedEvent().Delegation.ID), Content: summary,
    }})
}

// [中文] 保留原例中客户端、输入和返回值的处理顺序;本段需结合所在小节的连接前提使用,未通过真实API调用验证。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
import com.openai.helpers.LiveConnection;
import com.openai.models.live.*;
import java.util.UUID;
import java.util.concurrent.CompletionStage;
import java.util.function.*;

public record Context(int revision, String recentConversation, String task) {}

public static CompletionStage<Void> handleDelegation(
    ServerEvent event,
    LiveConnection connection,
    Supplier<Context> readContext,
    Function<Context, CompletionStage<String>> runAgent,
    IntSupplier currentRevision) {
  if (!event.isSessionDelegationCreated()
      || !event.asSessionDelegationCreated().delegation().target().toString().equals("client"))
    return java.util.concurrent.CompletableFuture.completedFuture(null);
  var snapshot = readContext.get();
  // Retain the notice; resolve the request before acting.
  if (snapshot == null) return java.util.concurrent.CompletableFuture.completedFuture(null);
  return runAgent
      .apply(snapshot)
      .thenAccept(
          summary -> {
            if (currentRevision.getAsInt() != snapshot.revision()) return;
            connection.send(
                ClientEvent.ofSessionCommentaryAppend(
                    CommentaryAppendEvent.builder()
                        .eventId(UUID.randomUUID().toString())
                        .delegationId(event.asSessionDelegationCreated().delegation().id())
                        .content(summary)
                        .build()));
          });
}

## [中文] 把应向用户说明的已核实内容作为commentary追加;委派ID关联对应任务,会话级更新使用null,生成与实际播放仍需分别核实。
require "openai"
require "securerandom"
Context = Data.define(:revision, :recent_conversation, :task)

def handle_delegation(event, connection, read_context:, run_agent:, current_revision:)
  return unless event.type == :"session.delegation.created" && event.delegation.target == :client

  context = read_context.call
  return if context.nil? # Retain the notice; resolve the request before acting.

  summary = run_agent.call(context)
  return unless current_revision.call == context.revision

  connection.send_event(
    type: :"session.commentary.append", event_id: SecureRandom.uuid,
    delegation_id: event.delegation.id, content: summary
  )
end

在应用中实现上下文与智能体回调。上下文回调返回近期对话和当前任务,请求仍不清楚时不返回值。智能体回调运行既有后端,返回最多 500 个词元的已验证摘要。JavaScript 中,由应用提供的 send 回调将 JSON 事件发送到 Live 连接;Python 中,适配器直接通过 SDK connection 发送更新。

预约助手的上下文应明确所需日期、时区、此前提供的时段、已确认时段与最新纠正。可用性结果要说明时段可用且尚未预订,只有实际成功后才返回预订确认。完整设置与返回流程见客户端委派。

路由更新与纠正

结构化工具输出和工作流细节留在后端,向 GPT-Live 返回简短事实更新:

  • session.thinking.append:尚在运行的查询等后台进度。
  • session.commentary.append:用户应听到的已验证结果。
  • session.instructions.append:应用编写的行为指导。

三者的纯字符串 content 最多 500 个词元,并要求 delegation_id。相关工作使用原客户端委派 ID,一般会话上下文使用 null。通过 client_event_id 匹配确认与命令,确认只代表更新被接受。助手转录反映生成语音,播放器状态反映播放。见发送正确类型的更新。

用户说“其实改成周五”时,把周五存为当前请求、递增版本号、清除周四的确认,并将纠正发给现有智能体。决定请求取消周四查询、修改查询,或允许完成后丢弃结果。

将查询报告为已取消前,先追踪实际状态。即使用户插话已让助手停止讲话,后端决定仍需处理。

后端工作可能比语音会话持续更久,状态应持久化在应用中。后续语音交互用相关已保存上下文创建新会话。见管理会话。

保持键入输入与智能体相连

键入输入继续连接现有后端。键入的纠正应更新同一任务,并给语音会话发送相关已验证上下文。见接受键入输入与保持更新准确且有用。

适配文本与语音防护措施

文本智能体或串联流水线可以在显示或播放前验证整段回复。GPT-Live 中,对话与后端工作并行进行。如果每段语音都必须先通过检查,应把检查放在应用控制的播放路径上;仅扣住后端结果不会暂停全部讲话。

按适配防护规则保留现有检查,并考虑连续语音。

适配防护规则

无论从哪种架构迁移,都保留原应用的输入输出防护。GPT-Live 可以在后端工作与政策检查运行时继续说话,因此对话和后端操作都要检查。

服务器需要监控或控制浏览器 WebRTC 会话时,附加旁路 WebSocket,接收转录并发送纠正指令,音频继续走 WebRTC。服务器已通过主 WebSocket 流式处理音频时,就用该连接的事件流检查。选择 Responses 委派本身并不意味着必须使用旁路。

  1. 监控用户与助手转录事件,并行运行检查。
  2. 在应用代码阻断相关工具与外部操作,按支持情况取消应用负责的工作,防止迟到结果让被阻断请求继续。
  3. 发送 session.instructions.append 引导助手,并在应用中记录决定。

例如,来电者要求未经许可修改他人预约,应在预订操作执行前阻止它,再指示助手说明无法修改。同时验证预订记录未变和语音回复正确;仅口头拒绝不能强制执行授权。

纠正指令无法收回用户已听到的音频。需要播放前检查时,缓冲、批准、打断和恢复见播放前检查语音。操作控制及纠正示例见应用对话防护规则。开场必需措辞见播报告知声明。

验证迁移

用现有应用的代表性对话比较迁移后助手。保持场景、后端工具和成功标准一致,重复测试,并同时记录有意行为变化与回归:

  • 操作与口头确认:检查可用性、询问确认,只预订已确认时段。分别验证后端结果、口头答案和客户端播放。
  • 纠正与防重复:待处理请求期间将周四改为周五,丢弃过时结果,确保重试不会产生第二个预约。
  • 权限:尝试未授权操作与未确认预约,检查应用政策实际阻止执行。
  • 防护干预:在讲话及工具执行中触发检查,验证助手收到纠正、迟到工具结果不能解除阻断、播放按预期恢复。核对活动操作是否真的停止,并包含慢检查和误判。
  • 打断:助手说话或工作时插话,分别验证对话、音频播放与后端任务状态。
  • 失败与重连:测试工具错误、结果丢失与断连。预订请求响应丢失时,重试前检查是否已成功。下一次语音会话用已保存任务上下文启动,并确认从已确立的结果继续。

用降低后端延迟调整迁移后的后端,结合语音智能体评估 Cookbook比较有用语音响应时间与任务成功率,用成本优化比较用量与费用。

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

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号