ThunderPhone 2.0 正式上线。全程自助,低至2美分/分钟。查看发布公告

Connect tools & data

将 ThunderPhone 与 OpenAI Realtime 客户端配合使用

使用已保存的智能体或内联会话配置,将兼容 OpenAI Realtime 的服务器客户端连接到 ThunderPhone。

ThunderPhone 实现了 OpenAI Realtime 事件模型中经过聚焦的一个子集。 现有服务端客户端可以在使用 ThunderPhone 语音智能体时,保留其 WebSocket、音频、会话和响应事件流。

连接前准备

您需要 ThunderPhone 组织密钥 API 密钥,以及能够打开 WebSocket 的服务器运行环境。请勿从浏览器代码连接,也不要将密钥暴露给浏览器。若要使用已保存的智能体,请先部署该智能体并复制其数字智能体 ID。

连接至:

wss://api.thunderphone.com/v1/realtime

从您的服务器对 WebSocket 升级进行身份验证:

Authorization: Bearer sk_live_YOUR_API_KEY

对于无法设置握手标头的客户端,可以使用查询字符串身份验证,但 URL 更容易泄露到日志中。

选择配置由谁负责

模式连接方式配置来源
已保存的智能体?agent_id=12已部署的提示词、语音、产品、语言、知识库,以及兼容的服务器端运行工具
内联无 agent_id客户端首次被接受的 session.update

已保存的智能体

使用已部署的智能体 ID 连接:

wss://api.thunderphone.com/v1/realtime?agent_id=12

智能体会在套接字连接时启动。其问候语仍然可用, 但 Realtime 会禁用其语音静默确认,并省略 transfer_call 和 send_keypad_input。其他兼容工具将在 ThunderPhone 上运行。请勿为此模式发送内联指令或由客户端执行的工具。

在智能体启动前,通过 input_audio_format、 output_audio_format、input_rate 和 output_rate 查询参数设置传输音频。连接后,您无法更改已保存的配置或音频格式。

内联会话

不使用 agent_id 时,请等待 session.created,然后发送 session.update:

{
  "type": "session.update",
  "session": {
    "type": "realtime",
    "instructions": "Answer questions clearly and keep responses brief.",
    "audio": {
      "input": {
        "format": { "type": "audio/pcm", "rate": 24000 }
      },
      "output": {
        "format": { "type": "audio/pcm", "rate": 24000 },
        "voice": "olivia"
      }
    },
    "config": {
      "product": "bolt"
    }
  }
}

首次被接受的更新会创建通话。session.updated 表示 会话已激活。此后,指令、语音、产品、工具和音频格式均无法更改。

内联会话没有自动问候语或语音静默确认。若要让智能体先说话,请追加一条系统或用户消息,并发送 response.create。完全空闲的会话仍会在平台的静默通话限制时结束,默认限制为 600 秒。

使用官方 OpenAI SDK

传入以 /v1 结尾的 WebSocket 基础 URL;SDK 会追加 /realtime。model 值是兼容性名称,不会选择 ThunderPhone 产品。请在会话配置或已保存的智能体中选择产品。

此连接检查会创建一个内联 Bolt 会话,持续打印事件直到第一个 session.updated,然后关闭。使用最简 Python 客户端流式传输音频。

import asyncio
import os
 
from openai import AsyncOpenAI
 
 
async def main():
    client = AsyncOpenAI(
        api_key=os.environ["THUNDERPHONE_API_KEY"],
        websocket_base_url="wss://api.thunderphone.com/v1",
    )
 
    async with client.realtime.connect(
        model="thunderphone-realtime"
    ) as connection:
        await connection.session.update(session={
            "type": "realtime",
            "instructions": "Listen to the caller and help them complete the call.",
            "config": {"product": "bolt"},
        })
        async for event in connection:
            print(event.type)
            if event.type == "session.updated":
                break
 
 
if __name__ == "__main__":
    asyncio.run(main())

保留您现有的输入音频追加、响应音频增量、中断、函数调用、错误处理以及套接字正常关闭逻辑。内联自定义函数在您的客户端中执行;请通过 Realtime 协议返回其结果。已保存智能体的工具在 ThunderPhone 上执行。

会话生命周期和失败情况

一个 WebSocket 对应一个通话。无效的智能体 ID 或被拒绝的内联配置会产生 error 事件。请在收到 session.updated 后再将会话视为已启动。声明实际的输入和输出格式以及采样率:PCM 采样率不匹配会导致音频播放过快或过慢,而不会产生验证错误。

会话启动后,请在您的应用完成时正常关闭套接字。内联会话可以使用由客户端执行的函数。已保存智能体会话使用由 ThunderPhone 运行的兼容工具,且不提供转接或按键输入功能。

测试集成

请从最简 Python WAV 客户端开始,并使用与其声明采样率相同的单声道 PCM16 WAV。验证:

  1. 服务器接受配置并发送 session.updated。
  2. 输入以预期速度生成转录和响应音频事件。
  3. 中断和响应取消会停止剩余的输出音频。
  4. 内联函数结果或已保存智能体工具结果会返回给模型。
  5. 无效输入会产生由您的客户端处理的 error 事件。
  6. 您的客户端关闭套接字,且该通话显示在通话记录中。

Realtime WebSocket 参考列出了可接受的事件、音频格式、会话字段和完整示例。

费用

Realtime 通话采用所选产品的常规每分钟费率。启用实时转录增量会为整个会话增加每分钟附加费用;有关费率,请参阅实时转录,有关产品费率,请参阅定价。

POST /v1/realtime/sessions 是独立的托管 LiveKit 路径。它会创建房间和作用域参与者令牌;直接 WebSocket 连接不需要它。

如需框架集成,请参阅从 Pipecat 使用 ThunderPhone和从 LiveKit Agents 使用 ThunderPhone。