实时智能体指南
本指南介绍OpenAI Agents SDK的实时层如何映射到OpenAI Realtime API,以及 Python SDK 在此基础上添加了哪些额外行为。
从这里开始
如果要使用默认的 Python 路径,请先阅读快速入门。如果正在决定应用应使用服务器端 WebSocket 还是 SIP,请阅读实时传输。浏览器 WebRTC 传输不属于 Python SDK。
概述
实时智能体会与 Realtime API 保持长连接,以便模型能够增量处理文本和音频、以流式方式输出音频、调用工具并处理中断,而无需在每轮对话中重新发起新请求。
主要 SDK 组件包括:
- RealtimeAgent: 单个实时专家智能体的指令、工具、输出安全防护措施和任务转移
- RealtimeRunner: 将起始智能体连接到实时传输层的会话工厂
- RealtimeSession: 用于发送输入、接收事件、追踪历史记录和执行工具的实时会话
- RealtimeModel: 传输抽象。默认实现是OpenAI的服务器端 WebSocket。
会话生命周期
典型的实时会话如下:
- 创建一个或多个
RealtimeAgent。 - 使用起始智能体创建
RealtimeRunner。 - 调用
await runner.run()以获取RealtimeSession。 - 使用
async with session:或await session.enter()进入会话。 - 使用
send_message()或send_audio()发送用户输入。 - 迭代处理会话事件,直到对话结束。
与纯文本运行不同,runner.run() 不会立即生成最终结果。它会返回一个实时会话对象,使本地历史记录、后台工具执行、安全防护措施状态和当前智能体配置与传输层保持同步。
默认情况下,RealtimeRunner 使用 OpenAIRealtimeWebSocketModel,因此默认 Python 路径是连接到 Realtime API 的服务器端 WebSocket。如果传入其他 RealtimeModel,仍会应用相同的会话生命周期和智能体功能,但连接机制可以发生变化。
当 Realtime API 服务器正常关闭默认 WebSocket 连接时,模型传输层会发出一个 disconnected RealtimeModelConnectionStatusEvent,随后发出一个 RealtimeModelEndOfStreamEvent。RealtimeSession 会在 raw_model_event 中转发这两个事件,排空已进入队列的事件,然后结束异步迭代且不会引发异常。调用方发起的 session.close() 不会合成这些服务器断开连接事件。意外的 WebSocket 故障仍会进入会话的异常路径,而不会像服务器正常关闭那样结束迭代。
智能体和会话配置
RealtimeAgent 的设计范围有意比常规 Agent 类型更窄:
- 模型选择在会话级别配置,而不是按智能体配置。
- 不支持Structured outputs。
- 可以配置语音,但会话生成语音音频后便无法更改。
- 指令、函数工具、任务转移、钩子和输出安全防护措施仍然全部可用。
RealtimeSessionModelSettings 同时支持较新的嵌套 audio 配置和较旧的扁平别名。新代码应优先采用嵌套结构,而新的实时智能体应从 gpt-realtime-2.1 开始:
runner = RealtimeRunner(
starting_agent=agent,
config={
"model_settings": {
"model_name": "gpt-realtime-2.1",
"audio": {
"input": {
"format": "pcm16",
"transcription": {"model": "gpt-4o-mini-transcribe"},
"turn_detection": {"type": "semantic_vad", "interrupt_response": True},
},
"output": {"format": "pcm16", "voice": "ash"},
},
"tool_choice": "auto",
}
},
)
实用的会话级设置包括:
audio.input.format、audio.output.formataudio.input.transcriptionaudio.input.noise_reductionaudio.input.turn_detectionaudio.output.voice、audio.output.speedoutput_modalitiestool_choiceprompttracing
RealtimeRunner(config=...) 上实用的运行级设置包括:
async_tool_callsoutput_guardrailsguardrails_settings.debounce_text_lengthtool_error_formattertracing_disabled
有关完整的类型化接口,请参阅 RealtimeRunConfig 和 RealtimeSessionModelSettings。
输入转录设置
在 audio.input.transcription 下配置输入转录。对于低延迟增量转录文本,请使用 gpt-live-transcribe;如果应在提交音频轮次后开始转录,或应用需要检测到的语言输出,请通过 WebSocket 使用 gpt-transcribe。Agents SDK会在嵌套会话配置中转发模型专用的 GA 转录设置:
runner = RealtimeRunner(
starting_agent=agent,
config={
"model_settings": {
"audio": {
"input": {
"transcription": {
"model": "gpt-live-transcribe",
"prompt": "A support call about the OpenAI Agents SDK.",
"keywords": ["RunState", "MCPServerManager"],
"languages": ["en", "ja"],
},
"turn_detection": None,
}
}
}
},
)
对于 gpt-live-transcribe,prompt 提供自由格式的录音上下文,keywords 列出音频中可能出现的原样术语,languages 列出预期输入语言。此模型使用复数形式的 languages,而不是单数形式的 language;请勿同时发送这两个字段。
此 SDK 固定使用的OpenAI客户端版本仅在搭配 gpt-realtime-whisper 时支持 delay。请按如下方式配置该模型在延迟和准确性之间的权衡:
runner = RealtimeRunner(
starting_agent=agent,
config={
"model_settings": {
"audio": {
"input": {
"transcription": {
"model": "gpt-realtime-whisper",
"delay": "low",
},
"turn_detection": None,
}
}
}
},
)
delay 设置接受 minimal、low、medium、high 或 xhigh。较低的值可以更早生成部分文本,而较高的值会为转录模型提供更多音频上下文,并可能提高识别准确性。请使用具有代表性的音频进行基准测试,不要假定任何级别都有固定的时序表现。
仅当应在提交音频轮次后开始转录,或应用需要检测到的语言输出时,才应在通过 WebSocket 建立的实时会话中使用 gpt-transcribe。该模型会自动将先前已转录的轮次用作上下文。gpt-transcribe 完成事件会在其 languages 输出字段中报告检测到的语言。此输出字段不同于上面所示的 gpt-live-transcribe 预期语言输入。
将 audio.input.turn_detection 设置为 None 会禁用自动轮次检测。之后,应用必须按照手动响应控制中的说明提交音频轮次并控制响应创建。有关模型行为、验证规则和延迟指导,请参阅OpenAI API 的实时转录指南。
输入和输出
文本和结构化用户消息
使用 session.send_message() 发送纯文本或结构化实时消息。
from agents.realtime import RealtimeUserInputMessage
await session.send_message("Summarize what we discussed so far.")
message: RealtimeUserInputMessage = {
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "Describe this image."},
{"type": "input_image", "image_url": image_data_url, "detail": "high"},
],
}
await session.send_message(message)
结构化消息是在实时对话中包含图像输入的主要方式。examples/realtime/app/server.py 中的 Web 演示代码示例会通过这种方式转发 input_image 消息。
音频输入
使用 session.send_audio() 以流式方式发送原始音频字节:
如果禁用了服务器端轮次检测,则需自行标记轮次边界。高级便捷用法如下:
如果需要更底层的控制,也可以通过底层模型传输层直接发送 Realtime API 客户端事件,例如 input_audio_buffer.commit。
手动响应控制
session.send_message() 通过高级路径发送用户输入,并为你启动响应。在某些配置中,原始音频缓冲不会自动执行相同操作。
在 Realtime API 层面,手动轮次控制意味着发送一个 session.update 事件,将 turn_detection 设置为 null,然后自行发送 input_audio_buffer.commit 和 response.create。
如果手动管理轮次,可以通过模型传输层发送原始客户端事件:
from agents.realtime.model_inputs import RealtimeModelSendRawMessage
await session.model.send_event(
RealtimeModelSendRawMessage(
message={
"type": "response.create",
}
)
)
此模式适用于以下情况:
turn_detection已禁用,并且需要自行决定模型应何时响应- 希望在触发响应前检查或限制用户输入
- 需要为带外响应提供自定义提示词
examples/realtime/twilio_sip/server.py 中的 SIP 代码示例使用原始 response.create 强制生成开场问候语。
事件、历史记录和中断
RealtimeSession 会发出更高级别的 SDK 事件,同时在需要时仍会转发原始模型事件。
重要的会话事件包括:
audio、audio_end、audio_interruptedagent_start、agent_endtool_start、tool_end、tool_approval_requiredhandoffhistory_added、history_updatedguardrail_trippedinput_audio_timeout_triggerederrorraw_model_event
对 UI 状态最有用的事件通常是 history_added 和 history_updated。它们以 RealtimeItem 对象的形式公开会话的本地历史记录,其中包括用户消息、助手消息和工具调用。
用量统计
当已完成的模型响应包含用量信息时,SDK 的OpenAI RealtimeModel 传输层会在 raw_model_event 中发出一个 RealtimeModelUsageEvent。其 usage 字段包含该响应的 token 数量,而 input_tokens_details 和 output_tokens_details 提供可选的模态明细。
会话还会将每个响应的用量添加到共享的 RunContextWrapper.usage。可以从后续高级事件(例如 agent_end)的 event.info.context.usage 中读取该值,以检查实时会话的累计用量。
from agents.realtime import RealtimeModelUsageEvent
async for event in session:
if event.type == "raw_model_event" and isinstance(
event.data, RealtimeModelUsageEvent
):
response_usage = event.data.usage
print("Response tokens:", response_usage.total_tokens)
print("Input modalities:", event.data.input_tokens_details)
print("Output modalities:", event.data.output_tokens_details)
elif event.type == "agent_end":
session_usage = event.info.context.usage
print("Session tokens:", session_usage.total_tokens)
仅当模型提供商在已完成的响应中包含用量信息时,才会报告用量。累计值涵盖该 RealtimeSession 收到的响应;它不是跨会话总量。
中断和播放追踪
当用户打断助手时,会话会发出 audio_interrupted 并更新历史记录,使服务器端对话与用户实际听到的内容保持一致。
对于低延迟本地播放,默认播放追踪器通常已足够。在远程或延迟播放场景中,尤其是电话场景,请使用 RealtimePlaybackTracker,以便在实际播放位置截断被中断的响应,而不是假设所有已生成的音频都已播放给用户。
examples/realtime/twilio/twilio_handler.py 中的 Twilio 代码示例展示了此模式。
工具、审批、任务转移和安全防护措施
函数工具
实时智能体支持在实时对话期间使用函数工具:
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Get current weather for a city."""
return f"The weather in {city} is sunny, 72F."
agent = RealtimeAgent(
name="Assistant",
instructions="You can answer weather questions.",
tools=[get_weather],
)
工具审批
函数工具可以要求在执行前进行人工审批。发生这种情况时,会话会发出 tool_approval_required 并暂停工具运行,直到调用 approve_tool_call() 或 reject_tool_call()。
如果工具还有输入安全防护措施,这些安全防护措施会在审批后、即将执行前运行。若要在发出审批事件前运行这些安全防护措施,请使用 RealtimeRunner(..., config={"tool_execution": {"pre_approval_tool_input_guardrails": True}}) 创建运行器。通过此预审批检查的调用仍会在审批后、执行前再次接受检查。
async for event in session:
if event.type == "tool_approval_required":
await session.approve_tool_call(event.call_id)
有关具体的服务器端审批循环,请参阅 examples/realtime/app/server.py。人工参与文档也会指向此流程。
任务转移
实时任务转移允许一个智能体将实时对话转交给另一个专家智能体:
from agents.realtime import RealtimeAgent, realtime_handoff
billing_agent = RealtimeAgent(
name="Billing Support",
instructions="You specialize in billing issues.",
)
main_agent = RealtimeAgent(
name="Customer Service",
instructions="Triage the request and hand off when needed.",
handoffs=[
realtime_handoff(
billing_agent,
tool_description_override="Transfer to billing support",
)
],
)
直接用作任务转移的 RealtimeAgent 对象会被自动包装,而 realtime_handoff(...) 可用于自定义名称、描述、验证、回调和可用性。实时任务转移不支持常规任务转移的 input_filter。
安全防护措施
实时智能体支持对智能体响应应用输出安全防护措施,也支持对函数工具调用应用输入安全防护措施。输出安全防护措施检查采用防抖机制:每次检查都基于累积的输出文本和音频转录增量运行,而不是针对每个部分增量运行,并会发出 guardrail_tripped,而不是引发异常。单个增量最多安排一次检查。如果该增量跨越多个 debounce_text_length 边界,SDK 会将下一个边界推进至所有这些边界之后,而不会在后续出现较小增量时安排补偿检查。
from agents.guardrail import GuardrailFunctionOutput, OutputGuardrail
def sensitive_data_check(context, agent, output):
return GuardrailFunctionOutput(
tripwire_triggered="password" in output,
output_info=None,
)
agent = RealtimeAgent(
name="Assistant",
instructions="...",
output_guardrails=[OutputGuardrail(guardrail_function=sensitive_data_check)],
)
当实时输出安全防护措施因音频转录而触发时,会话会中断当前响应、强制执行 response.cancel、发出 guardrail_tripped,并发送一条指出已触发安全防护措施的后续用户消息,以便模型生成替代响应。音频播放器仍应监听 audio_interrupted 并立即停止本地播放,因为触发防护机制时,部分音频可能已被缓冲。使用内置OpenAI实时传输时,如果安全防护措施检查在其检查的响应结束后才完成,会话只会中断该响应的缓冲播放,不会取消之后启动的任何响应。对于纯文本输出,会话会改为发送响应级的 response.cancel;由于没有需要停止的音频播放,因此不会发出 audio_interrupted。使用内置OpenAI实时模型时,纯文本路径也会发出相同的 guardrail_tripped 事件和后续用户消息。
自定义 RealtimeModel 传输必须遵循 RealtimeModelSendInterrupt.response_id 和 playback_only,以提供相同的按来源限定音频中断行为。它们还必须重写 RealtimeModel.send_event_if(),以支持纯文本输出路径的恢复消息。实现必须在传输层实际提交事件的边界处重新检查所提供的条件,或将条件检查与事件提交串行化处理。默认实现会安全地跳过恢复消息,因为如果它只检查一次条件,然后单独发送事件,则可能在该检查与事件提交之间启动另一个响应;响应取消和 guardrail_tripped 事件仍会发生。
SIP 和电话
Python SDK 通过 OpenAIRealtimeSIPModel 提供一流的 SIP 附加流程。
当呼叫通过 Realtime Calls API 到达,并且需要将智能体会话附加到由此产生的 call_id 时,请使用此流程:
from agents.realtime import RealtimeRunner
from agents.realtime.openai_realtime import OpenAIRealtimeSIPModel
runner = RealtimeRunner(starting_agent=agent, model=OpenAIRealtimeSIPModel())
async with await runner.run(
model_config={
"call_id": call_id_from_webhook,
}
) as session:
async for event in session:
...
如果需要先接受呼叫,并希望接受载荷与从智能体派生的会话配置保持一致,请使用 OpenAIRealtimeSIPModel.build_initial_session_payload(...)。完整流程见 examples/realtime/twilio_sip/server.py。
底层访问和自定义端点
可以通过 session.model 访问底层传输对象。
以下情况需要使用此对象:
- 通过
session.model.add_listener(...)添加自定义监听器 - 发送原始客户端事件,例如
response.create或session.update - 通过
model_config自定义url、headers或api_key的处理方式 - 使用
call_id附加到现有实时呼叫
RealtimeModelConfig 支持:
api_keyurlheadersinitial_model_settingsplayback_trackercall_id
此代码仓库随附的 call_id 代码示例使用 SIP。更广泛的 Realtime API 还会在某些服务器端控制流程中使用 call_id,但这里未将这些流程打包为 Python 代码示例。
连接到 Azure OpenAI 时,请传入 GA Realtime 端点 URL 和显式标头。例如:
session = await runner.run(
model_config={
"url": "wss://<your-resource>.openai.azure.com/openai/v1/realtime?model=<deployment-name>",
"headers": {"api-key": "<your-azure-api-key>"},
}
)
对于基于 token 的身份验证,请在 headers 中使用 bearer token:
session = await runner.run(
model_config={
"url": "wss://<your-resource>.openai.azure.com/openai/v1/realtime?model=<deployment-name>",
"headers": {"authorization": f"Bearer {token}"},
}
)
如果传入 headers,SDK 不会自动添加 Authorization。实时智能体应避免使用旧版 beta 路径(/openai/realtime?api-version=...)。