Realtime Voice Agent 实战:电话客服 / 语音助手场景的 Realtime API + function calling
把 GPT-Realtime-2.1 接到电话 / 语音助手做实时语音 agent:WebRTC / WebSocket 选型 + VAD(server_vad)调优 + mid-conversation function calling + 双工/打断 + 通话质量监控。
操作步骤
准备 Twilio 号码 + 媒体流
在 Twilio 控制台买一个号码,启用 Media Streams。在 TwiML 里把电话转接到 wss://your-server/realtime-twilio,把 μ-law 8kHz 音频直接 forward 给 WebSocket。
实现 WebSocket 服务端
Node.js + ws:收到 audio chunk 就 forward 到 OpenAI Realtime WebSocket,建立双向流。注意 Twilio 的 audio 是 base64 编码的 μ-law,OpenAI 期望 PCM16 24kHz——中间要重采样。
配置 server_vad 参数
在 session.update 里设置 server_vad:silence_duration_ms=350、prefix_padding_ms=250、threshold=0.5。客服场景偏短停顿。threshold 可以先用默认,嘈杂时再调。
挂上 function calling
声明 tools 数组:query_order(order_id)、change_address(order_id, new_address)。设置 tool_choice='auto'。function 返回结果走 conversation.item.create 回传到模型。
开打断 + 监控
interrupt_response=true。监控三个数:TTFB、turn latency、WER。挂个 Prometheus exporter 把数字打到 dashboard,> 阈值告警。
Realtime Voice Agent 跟 Chat Completions API 是两套东西——前者流式处理音频、能在用户说话时就开始生成回复、能在中途调 function。本文是给已经在做或准备做电话 / 语音助手场景的人写的实战指南:WebRTC vs WebSocket 选型、VAD 调参、mid-conversation function calling、打断处理、通话质量监控。文末有可复用 production 模板。
什么时候用 Realtime Voice Agent
先判断要不要用——不是所有语音场景都需要:
- 电话客服:用户在电话里问『我的快递到哪了』,AI 边听边查订单。适合 Realtime——用户预期是『真人一样快』,传统 ASR+LLM+TTS 流水线 3-5s 延迟会让人觉得『机器人』。
- 语音助手:智能音箱 / 车载 / 智能家居。用户说『帮我把客厅灯调亮点』,AI 立刻执行 + 回应。适合 Realtime——延迟敏感,且经常需要中途调 function。
- 会议记录:把会议录音转文字 + 摘要。不适合 Realtime——用 Whisper + GPT-4o 批处理就行,Realtime 太贵。
- 有声书 / 配音:纯 TTS。用 TTS API,Realtime 也行但更贵。
WebRTC vs WebSocket 选型
| 维度 | WebRTC | WebSocket |
|---|---|---|
| 浏览器 / 移动 App | 原生支持 | 需要 AudioWorklet 抓流 |
| NAT 穿透 | 自动(ICE) | 需要 STUN/TURN |
| 服务端到 PSTN | 麻烦(需要网关) | 简单(直接接 Twilio Media Streams) |
| Codec | opus(默认) | 灵活(直接吃 μ-law / PCM) |
| 延迟 | 低(200-500ms) | 中(400-800ms) |
| 复杂度 | 信令服务器 + STUN/TURN | 一个 WS 服务就行 |
- 浏览器 / App:WebRTC。MediaStream → RTCPeerConnection → DataChannel → Realtime API。
- 电话集成(Twilio / Vonage):WebSocket。Twilio Media Streams 把 μ-law 8kHz 推到 wss://,你 forward 给 Realtime API。
- IVR / 自建电话:WebSocket + SIP gateway。
server_vad 调参
Realtime API 的 VAD(voice activity detection)是 server-side 的,由模型判断用户什么时候说完。三个关键参数:
session.update({
turn_detection: {
type: 'server_vad',
threshold: 0.5, // VAD 触发阈值(0-1)
silence_duration_ms: 350, // 用户停顿多久算说完(ms)
prefix_padding_ms: 250, // 音频前缀缓冲(ms)
},
});
按场景调:
| 场景 | silence_duration_ms | prefix_padding_ms | threshold | 理由 |
|---|---|---|---|---|
| 电话客服 | 300-400 | 200-300 | 0.5 | 用户停顿短(急着说下一句) |
| 语音助手(智能家居) | 500-700 | 300-400 | 0.5 | 平衡 |
| 语音笔记 / 会议 | 800-1200 | 400-600 | 0.6 | 允许长停顿思考 |
| 嘈杂环境(咖啡馆 / 车内) | 400-500 | 200-300 | 0.7-0.8 | 提高 threshold 减少误触发 |
调参后用 Whisper 把录音转写,统计 WER(word error rate)——目标 < 5%。WER > 10% 基本不能用。
mid-conversation function calling
这是 Realtime Voice Agent 相对传统流水线最大的优势——模型能在语音流中触发 function,且 TTS 同步说『让我查一下』。
session.update({
tools: [
{
type: 'function',
name: 'query_order',
description: '查询订单状态。Trigger:当用户问「我的订单 X 到哪了」或类似问题时调用。',
parameters: {
type: 'object',
properties: {
order_id: { type: 'string', description: '订单号' },
},
required: ['order_id'],
},
},
],
tool_choice: 'auto',
});
// 监听 response.function_call_arguments.done
ws.on('response.function_call_arguments.done', async (event) => {
const args = JSON.parse(event.arguments);
const result = await queryOrder(args.order_id);
// 把结果回传到模型
ws.send(JSON.stringify({
type: 'conversation.item.create',
item: {
type: 'function_call_output',
call_id: event.call_id,
output: JSON.stringify(result),
},
}));
});
实际效果:
User: 帮我查订单 12345 到哪了
AI: 好的,让我查一下。 ← TTS 立刻说(不等 function 返回)
[function_call: query_order(12345)] ← 模型同时调工具
[function 返回:已到达 XX 网点,预计今天下午送达]
AI: 您的订单已经到 XX 网点,预计今天下午送达。
幻觉防护:三层——
- function description 写明 trigger 条件,避免乱调。
- function 返回值当不可信输入。订单号 / 金额 / 地址要再校验。
- 高风险操作(扣款 / 改地址)必须人工确认。AI 说完『即将为您改地址到 XX』,等用户说『确认』才执行。
打断(barge-in)
用户打断 AI 是自然对话的一部分——你说『订单已到 XX 网点,预计』,用户插嘴『不用了我要改地址』。要处理:
session.update({
turn_detection: {
type: 'server_vad',
interrupt_response: true, // 开启打断
},
});
打断流程:
- 用户开始说话 → server_vad 检测到
- 立刻停止 TTS 输出
- 把音频 stream 重置到 last user turn(丢弃 AI 已说但未播完的部分)
- 继续处理用户的新输入
打断延迟 < 200ms 用户才感觉自然。如果超过 500ms,用户会觉得自己『插不上话』。
通话质量监控
上 production 必须监控三个数:
# 伪代码
def record_call(call_id):
return {
'ttfb_ms': time_to_first_byte, # 用户说完到 AI 开始说
'turn_latency_ms': turn_latency, # 整 turn 延迟
'wer': compute_wer(audio, transcript), # ASR 准确率
'interrupt_count': interrupt_count, # 打断次数(> 5/分钟 说明模型太长)
}
| 指标 | 健康 | 警告 | 失败 |
|---|---|---|---|
| TTFB | < 600ms | 600-1000ms | > 1000ms |
| turn latency | < 1.2s | 1.2-2.0s | > 2.0s |
| WER | < 3% | 3-5% | > 5% |
| 打断次数 / 分钟 | < 3 | 3-5 | > 5 |
WER > 5% 说明 VAD 参数或麦克风有问题;turn latency > 2s 说明 Realtime API 限流或网络问题。
实战模板:Twilio + Realtime
import { WebSocketServer } from 'ws';
import OpenAI from 'openai';
const wss = new WebSocketServer({ port: 8080, path: '/realtime-twilio' });
wss.on('connection', async (twilioWs) => {
// 1. 连接 OpenAI Realtime
const openaiWs = new WebSocket(
'wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1',
{ headers: { 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}` } }
);
// 2. session 配置
openaiWs.send(JSON.stringify({
type: 'session.update',
session: {
voice: 'alloy',
turn_detection: {
type: 'server_vad',
threshold: 0.5,
silence_duration_ms: 350,
prefix_padding_ms: 250,
interrupt_response: true,
},
tools: [{
type: 'function',
name: 'query_order',
description: '查询订单状态',
parameters: { /* ... */ },
}],
input_audio_format: 'g711_ulaw', // Twilio 是 μ-law 8kHz
output_audio_format: 'pcm16',
},
}));
// 3. Twilio → OpenAI
twilioWs.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.event === 'media') {
openaiWs.send(JSON.stringify({
type: 'input_audio_buffer.append',
audio: msg.media.payload, // base64 μ-law
}));
}
});
// 4. OpenAI → Twilio
openaiWs.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.type === 'response.audio.delta') {
twilioWs.send(JSON.stringify({
event: 'media',
streamSid: '...',
media: { payload: msg.delta },
}));
}
});
});
常见坑
- Codec 不匹配:Twilio 是 g711_ulaw 8kHz,OpenAI Realtime 默认 pcm16 24kHz。中间不重采样会听起来像机器人。处理:在
session.update里设input_audio_format: 'g711_ulaw',OpenAI 自动处理重采样。 - 打断后 AI 重复说:打断后 audio stream 没正确重置,导致 AI 接着说刚才未完的句子。处理:打断时主动 send
response.cancel。 - function 调用卡死:function 5s 没返回,模型会等,用户以为 AI 卡了。处理:设 function 超时(建议 3s)+ 返回 fallback(如『抱歉系统忙,稍后回复您』)。
- WebRTC 防火墙阻断:企业网络经常阻断 UDP,导致 WebRTC 失败。处理:配 TURN server,fallback 到 WebSocket。
下一步
- 想了解 Realtime API 的入门?读 《Realtime Voice 完全指南:gpt-realtime 与 Voice Mode》。
- 想做 latency 极致优化?读 《Advanced Voice 深度使用手册:GPT-Realtime-2.1 实战与延迟优化》。
- 想了解背后的模型家族?读 《GPT 模型完全指南(2026-07):GPT-5.6 Sol / Terra / Luna 选型》。
关键要点
- WebRTC 适合客户端(浏览器 / 移动 App),自动处理 NAT / 信令;WebSocket 适合服务端(电话集成 / IVR),需要 Twilio / Vonage 媒体栈;选型错了 latency 直接翻倍
- server_vad 是 Realtime API 的关键参数:silence_duration_ms(默认 500ms 判定停顿)、prefix_padding_ms(音频前缀缓冲,默认 300ms)、threshold(VAD 触发阈值,默认 0.5);不同场景需要不同调参
- mid-conversation function calling:模型在语音流中触发 function(查订单),TTS 同步说『让我查一下』,用户在等的时候 UI 显示 progress——这种『AI 在说话的同时在调工具』是 Realtime 相对传统 ASR+LLM+TTS 流水线最大的优势
- 打断(barge-in)必须开启 interrupt_response=true;当用户打断 AI 时,立刻停止 TTS、把音频 stream 重置到 last user turn、继续对话。打断延迟 < 200ms 用户才感觉自然
- 通话质量要监控三个数:TTFB(time to first byte,< 800ms 才自然)、turn latency(用户说完到 AI 开始说,< 1.2s)、WER(word error rate,ASR 准确率要 < 5% 才不掉单)
常见问题
官方参考
相关文章
Realtime API 多语言实战:zh / en / ja 自动识别 + 跨语言对话 + 方言鲁棒性
GPT-Realtime-2.1 多语言能力:自动识别用户语言(zh / en / ja / ko / es 等)、跨语言对话(中英混说)、方言鲁棒性(粤语 / 四川话)、translate mode 自动翻译。
阅读全文Advanced Voice 深度使用手册:GPT-Realtime-2.1 实战与延迟优化
GPT-Realtime-2.1 + ChatGPT Advanced Voice 全栈实战:WebRTC 与 WebSocket 选型、Turn Detection 调优、中途函数调用、VAD 参数、延迟优化与生产部署。
阅读全文Realtime Voice 完全指南:gpt-realtime 与 Voice Mode
用 gpt-realtime / gpt-realtime-mini 构建低延迟语音 AI:WebRTC 与 WebSocket 选型、对话中的 function calling,以及 Voice Mode 最佳实践。
阅读全文订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。