关于 openai-realtime-voice
面向实时语音产品构建者的 OpenAI Realtime 开发技能,适用于需要持续会话、轮流对话和工具调用的语音 Agent。它涵盖架构选择、传输方式、会话配置与打断处理,并区分实时交互和文件式音频任务。
主要功能
- 01规划语音对话架构与传输方式
- 02配置实时会话和语音参数
- 03设计语音检测与轮次管理
- 04处理打断、工具调用和交接
- 05考虑隐私、安全及成本
适用场景
- 01构建浏览器实时语音助手
- 02实现电话式语音支持 Agent
- 03设计可被用户打断的语音交互
- 04为实时语音会话接入工具
MCP 相关
Realtime 会话可使用远程 MCP 服务提供的工具,也可使用应用执行的函数工具和内置连接器。技能说明如何规划工具配置与执行责任。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ calesthio/ generative-media-skills --skill openai-realtime-voice安装后在 Claude Code 中输入/openai-realtime-voice确认已加载。
附带文件EVAL.md
详细介绍
OpenAI Realtime 语音
当交付内容是实时语音交互时,请使用此技能:例如浏览器语音助手、电话式 Agent、低延迟语音到语音支持流程、引导式面试、辅导对话、实时自助终端,或能够聆听、推理、说话、打断对话并可能调用工具的实时语音 UI。
不要将此技能用于批量语音转文本、离线 TTS、配音生成、音频编辑、配音、音乐或基于文件的音频任务。这些任务应使用单独的 OpenAI 音频/请求 API 或其他语音/音频技能。界限很简单:如果持久实时会话和轮流发言行为是产品的一部分,请使用此技能;如果任务是“将此文件/文本转换为文本/音频”,则不要使用。
以下所有 OpenAI API 事实均已于 2026-07-10 根据 OpenAI 第一方文档核实。由于 Realtime 功能变化很快,正式发布前请重新核对模型标识符、价格、会话限制、语音、API 对象字段、数据保留和政策要求。
每项设计都应考虑的来源依据事实
已记录的事实:
- OpenAI 将 Realtime 会话定位为适用于需要低延迟的实时音频;基于请求的音频 API 则适用于文件、有明确边界的请求,或无需实时会话的语音生成。来源:Realtime 和音频概览。
- 语音 Agent 会话适用于模型需要在
/v1/realtime上响应用户、调用工具并管理对话状态的应用。翻译和转录会话是独立的 Realtime 会话类型。来源:Realtime 和音频概览。 - OpenAI 的语音 Agent 指南区分了语音转语音实时音频会话与串联式 STT -> 文本推理 -> TTS 工作流。实时音频是实现插话、低首段音频延迟、自然轮流对话和实时工具调用的起点。来源:语音 Agent。
- 文档说明的浏览器接入方式是 WebRTC,建议使用 Agents SDK 辅助工具,例如
RealtimeAgent和RealtimeSession;服务器到服务器的集成则使用 WebSocket。来源:语音 Agent、WebRTC 指南、WebSocket 指南。 - Realtime 语音转语音会话包含一个 Session 对象、一个 Conversation 和多个 Responses。Session 控制模型、语音和配置;Conversation 包含用户和模型 Items;Responses 是模型生成的音频或文本 Items。来源:Realtime 对话。
- 服务器发送
session.created后,客户端可以使用session.update。大多数会话属性都可以随时更新,但在模型于会话中首次以音频作出响应后,便无法更改语音。文档规定的 Realtime 会话最长时长为 60 分钟。来源:Realtime 对话。 - 使用 WebSocket 传输音频时,客户端需通过输入音频缓冲区事件手动发送 base64 编码的音频;WebRTC 会处理大部分媒体传输。来源:Realtime 对话。
- 语音转语音 Realtime 会话默认启用 VAD,可在
session.audio.input.turn_detection中进行配置。文档列出的 VAD 模式为server_vad和semantic_vad;服务器 VAD 可调整阈值、前缀填充和静音时长。来源:语音活动检测。 - Realtime 会话可以使用由应用执行的函数工具、由远程 MCP 服务提供的 MCP 工具,以及内置连接器。工具可以附加到会话级别,也可以仅用于一次响应。来源:使用工具的 Realtime。
- Realtime 语音 Agent 会话会对文本、音频和图像模态的输入与输出令牌计费;翻译和转录流式会话则按时长计费。后续对话轮次的费用更高,因为每次 Response 的输入都包含整个服务器端对话。OpenAI 说明的音频令牌计算方式为:用户消息音频每 100 毫秒计 1 个令牌,助手消息音频每 50 毫秒计 1 个令牌。来源:管理成本。
- 输入音频转录是独立于 Realtime 模型原生音频理解的 ASR 过程;OpenAI 提醒,转录文本可能与模型的理解不同。应将转录文本视为可观测性和无障碍辅助材料,而非精确的推理输入。来源:Realtime API 参考。
- OpenAI 声明,除非组织明确选择加入,否则不会使用发送至 API 的数据来训练或改进模型。来源:OpenAI 平台的数据控制。
- OpenAI 的使用政策和安全最佳实践仍适用于 Realtime 语音体验,包括有害内容、冒充、隐私、高影响决策和用户保护方面的限制。来源:使用政策、安全最佳实践。 本技能中的生产实践启发并非 OpenAI 的承诺,而是为基于已记录的 API 功能构建语音产品的 Agent 提供的实用设计指导。
架构选择
在编写提示词或代码之前,先选择架构。
在以下情况下,使用语音到语音的 Realtime 语音 Agent 会话:
- 延迟和自然的对话流程是产品的核心;
- 用户应能打断助手;
- 助手需要在实时音频交流过程中调用工具;
- 语音行为、时机和轮流发言方式都是质量的一部分;
- 会话可以安全地承载对话状态。
在以下情况下,则使用串联的 STT -> 文本 Agent -> TTS 流程:
- 每项工具操作都必须由应用明确安排顺序;
- 与自然语音到语音的时序相比,可确定的转录文本更重要;
- 现有产品已有文本 Agent,语音只是输入/输出层;
- 合规要求在语音合成前存储、检查或审批文本;
- 真正的任务是批处理、文件、长录音、旁白或配音。
只有在产品需要流式转录文本增量、且不需要模型生成语音回复时,才使用 Realtime 转录模式。只有在产品是口译工具时,才使用 Realtime 翻译。不要将这些模式混入语音 Agent 架构。
会话与传输模式
围绕三个边界设计每种实现:客户端媒体、可信服务器和 OpenAI Realtime 会话。
对于浏览器或移动设备:
- 仅在用户明确同意后,才在本地采集麦克风音频。
- 请求可信服务器启动或授权 Realtime 会话。
- 尽可能使用 WebRTC 传输媒体和数据通道事件。
- 将标准 OpenAI API 密钥保存在服务器上。如果使用临时密钥流程,仅为预期会话签发短期凭证。
- 呈现助手音频,并显示明确的说话/聆听状态和醒目的停止/静音控件。
对于服务器到服务器的连接:
- 将音频采集和播放保留在受控基础设施、电话桥接或后端进程中。
- 仅从安全服务器使用标准 API 密钥连接到
wss://api.openai.com/v1/realtime?model=...。 - 明确发送会话更新、输入音频缓冲区事件和工具结果。
- 如果应用会分配稳定且保护隐私的安全标识符,请按 OpenAI 对 WebSocket 连接的文档添加相应请求头。
- 记录事件 ID、项目 ID、响应 ID、工具调用和用户可见结果,但不要记录原始密钥或不必要的音频。
不要将标准 API 密钥放入浏览器、移动应用、桌面软件包或可下载客户端。除非有意接受相关身份验证和媒体方面的权衡,否则应将浏览器发起的 WebSocket 连接视为特殊情况下的原型方案。
模型、语音和会话配置
已于 2026-07-10 验证:OpenAI 当前的语音 Agent 示例使用 gpt-realtime-2.1。文档和模型页面中可能还存在较旧或其他实时模型名称;实现时,请从当前模型参考中选择模型,并在日志和产物中记录确切的模型名称。
启动前需要记录的最低限度会话决策:
model:确切的 Realtime 模型标识符和验证日期;transport:WebRTC、WebSocket,或适用时使用的 SIP/电话桥接;session_type:语音 Agent、转录或翻译;voice:确切的语音标识符;记录会话收到第一个音频响应后便无法更改语音;modalities:输出为音频、文本还是两者兼有;- 手动处理音频时的
input_audio_format和output_audio_format; turn_detection:server_vad、semantic_vad或禁用/手动;input_audio_transcription:是否启用、使用哪个 ASR 模型,以及转录文本是否对用户可见;tools:工具列表、架构、执行负责人、审批策略和副作用;retention/logging:是否存储原始音频、转录文本、事件和工具载荷;存储时长;以及有权访问的人员。
经验法则:在创建会话时设置语音,而不是连接后再设置。通话中途收到更改语音的请求时,应将其视为“使用新语音启动新会话”,除非当前文档明确更改了关于首次音频后语音不可变的说明。
轮次交接和打断设计
如果系统没有明确显示轮次状态,语音 UX 就会失效。请明确实现以下状态机:
- idle:麦克风权限未启用或通话尚未开始;
- listening:正在传输用户音频;
- user_speaking:VAD 检测到语音开始;
- thinking:用户轮次已提交,正在生成响应;
- assistant_speaking:正在传输音频输出;
- interrupted:用户插话或 UI 停止操作已取消/截断助手输出;
- tool_pending:模型请求执行外部操作;
- handoff_or_escalation:需要人工介入或切换到其他工作流;
- ended:会话已关闭,摘要和产物已封存。
在普通环境中,默认的对话式助手可使用 server_vad。请调整以下参数:
- 当用户希望快速来回对话且经常打断时,降低
silence_duration_ms; - 对于会在思考时停顿的用户、无障碍场景、语言学习者或复杂的支持案例,提高
silence_duration_ms; - 在嘈杂环境中提高
threshold; - 设置足够的
prefix_padding_ms,避免截掉第一个音节。
当基于静音的分段会截断长时间停顿的用户发言,或短语完整性比速度更重要时,可以考虑使用 semantic_vad。请务必结合真实口音、背景噪声和领域词汇进行充分测试。
只有在 UI 采用有意设计的按住说话或操作员控制工作流时,才应禁用自动 VAD 并手动提交轮次。如果关闭 VAD,应用程序就要负责管理轮次边界,并避免将意外采集的背景语音作为用户输入发送。
打断规则:
- 提供清晰可见的“停止发言”或“将助手静音”控件。
- 除非产品有法律或安全方面的理由,否则应允许用户语音打断较长的助手音频。
- 被打断后,只总结实际说出的内容;不要假设用户听到了后续内容。
- 对于工具调用,要区分打断语音播放和取消具有副作用的工具操作。副作用需要单独的取消语义。
语音 Agent 的提示词与指令设计
实时语音提示词需要明确约束行为,而这些行为往往是文本提示词默认隐含的。
在相关情况下,请加入以下指令块:
- 角色与目标:Agent 能提供哪些帮助,以及哪些事情不能处理。
- 语音风格:亲和度、正式程度、语速、简洁程度和填充词使用策略。
- 轮次长度:每次回答的最大句数或时长。
- 对话修复:如何请求用户重复、澄清不确定的音频,以及如何应对背景噪音。
- 工具策略:何时调用工具、何时征求许可,以及如何描述等待状态。
- 安全边界:受监管领域的建议、紧急情况、未成年人、身份验证,以及财务/法律/医疗免责声明。
- 隐私行为:除非必要,否则绝不索取敏感信息;遮盖秘密信息或避免大声读出。
- 语言策略:支持的语言、语码转换、发音,以及用户切换语言时的应对方式。
- 升级与转接:何时联系人工人员或结束会话。
- 输出风格:不使用 Markdown;除非口头表达自然,否则不使用列表;不说“作为一个 AI 语言模型”;工具结果返回前,不得假装已完成工具操作。
语音 Agent 启发式原则:
- 优先给出简短回答:直接回答一个问题,再提出一个后续问题。
- 避免密集罗列;如果答案包含三个以上步骤,请询问用户是否要继续。
- 使用听起来自然的确认语:“我找到了这笔订单。它昨天已发货。”而不是“工具返回的状态等于已发货。”
- 不要过度道歉;反复道歉会让语音对话显得拖沓。
- 如果自动语音识别(ASR)结果不确定或名称有歧义,请确认关键信息:“您说的是订单 3917 吗?”
- 面对情绪化的对话,先简短回应,再推进到有帮助的下一步。
- 工具响应延迟时,只说明一次当前状态:“我现在查一下。”不要用猜测填补沉默。
工具和函数调用
只有在语音 Agent 需要实时数据或执行副作用时,才附加工具。工具不能替代提示词指令。
在以下情况下,请使用由应用执行的函数工具:
- 应用拥有私有业务逻辑、凭据或策略检查;
- 可能需要人工审批;
- 操作会更改状态、花费资金、发送消息、预约、解锁门或修改记录;
- 工具结果在播报前需要脱敏。
只有在组织批准了远程工具服务/连接器、授权边界明确,且日志记录了可能离开应用边界的数据时,才使用 MCP 或连接器工具。
工具设计规则:
- 保持架构简洁明确。语音用户只需补充一个缺失字段,就能更快纠正错误。
- 准确标记必填字段;不要强迫模型编造 ID。
- 即使模型输出的 JSON 符合架构,也要在服务端验证参数。
- 返回简洁、适合语音播报的结果,以及机器可读的状态字段。
- 如果没有应用侧审批规则,绝不要让模型执行不可逆操作。
- 对于支付、合同、医疗预约、账户变更或法律/财务决策,请在产生副作用前立即征求明确确认。
- 如果工具失败,请说明发生了什么,并提供一个后续步骤;不要暴露堆栈跟踪信息。
工具审批策略示例:
Read-only tools may run automatically after user intent is clear.
Drafting tools may create but not send.
Side-effecting tools require explicit user confirmation in the same turn as execution.
High-impact tools require human operator approval outside the model.
The assistant must never claim completion until function_call_output confirms success.
延迟、成本和上下文控制
延迟预算是体验要求,而不只是工程指标。至少跟踪以下指标:
- 麦克风权限授予到连接就绪;
- 语音开始到 VAD
speech_started; - 语音停止到创建响应;
- 创建响应到助手首次输出音频;
- 首段音频到最终音频;
- 发出工具调用到返回工具结果;
- 发出中断指令到音频停止。
成本控制:
- 保持系统指令简洁而完整;冗长的指令会在会话上下文中反复出现。
- 如果长会话不需要逐字保留历史记录,请总结或截断过时的对话 Items。
- 避免为非语音或背景噪声创建 Responses;依靠 VAD 和 UI 静音。
- 使用工具仅获取必要字段。
- 及时结束空闲会话。
- 判断是否需要转录文本;输入转录会按照 ASR 模型定价单独计费,而非按照 Realtime 模型定价计费。
- 根据 OpenAI 文档中的经验法则估算音频 token 消耗:用户音频每 100 毫秒 1 个 token,助手音频每 50 毫秒 1 个 token,另加特殊 token 的差异。
经验法则:在生产仪表板中,按会话、用户轮次、助手音频时长、工具耗时以及放弃/空闲时间拆分成本。语音团队经常发现,助手长篇独白既是成本最高的部分,也是 UX 中最不实用的部分。
同意、权利、隐私和安全
采集语音前:
- 明确说明使用麦克风的相关事宜,并在适用时说明是否会录音或存储转录文本。
- 说明是否可能由人工审核音频/转录文本。
- 适当时提供静音、停止、删除/结束会话和联系人工支持的途径。
- 除非已落实法律/合规控制措施,否则避免收集儿童个人数据。
- 除非产品针对特定用途已获得明确同意、具备法律依据,并得到服务提供方支持,否则避免通过语音识别生物特征。
对于生成的语音:
- 除非确实是真人且已明确披露,否则不要将 Agent 说成真人。
- 不要冒充他人、名人、员工、临床医生或公职人员。
- 除非已依据适用的语音政策和当地法律记录相关权利和同意,否则不要克隆或模仿他人的声音。
- 如果 Agent 代表某个品牌,请明确说明其品牌角色。
对于隐私:
- 尽量减少原始音频的保留时间。如果事件元数据和经过脱敏的转录文本足以用于 QA,请优先使用这些数据。
- 切勿记录 API 密钥、临时客户端密钥、Authorization 标头、连接器 token 或用户说出的未经脱敏的机密信息。
- 将转录文本视为敏感信息,因为即使不存储音频,其中也可能包含 PII。
- 如果使用工具/连接器,请记录从用户音频中提取的数据会发送到哪些外部系统。
- 在应用程序中提供数据保留和删除机制,而不只是写在内部文档中。
对于安全:
- 针对医疗、法律、金融、就业、住房、教育、紧急情况和自我伤害相关情境,添加特定领域的拒绝和升级处理机制。
- 使用 OpenAI 建议的稳定且保护隐私的用户标识符作为安全标识符。
- 使用对抗性音频进行评估:背景人声、第三方说出的提示词注入、附近有儿童、侮辱性言论、情绪困扰以及滥用工具的尝试。
审批、日志记录与产物保管
对于任何生产环境中的语音 Agent,都应创建可审计的运行记录。至少存储以下内容:
- 模型/API 验证日期;
- 模型、语音、传输方式、会话类型和会话配置;
- 提示词/指令版本;
- VAD 配置;
- 工具架构、工具审批策略和连接器清单;
- UI 中显示的用户同意文案;
- 原始音频、转录文本、事件、工具载荷和摘要的保留策略;
- 测试矩阵和结果;
- 已知限制和升级处理途径。
每个会话都应记录:
- 会话 ID 或应用程序关联 ID;
- 用户安全标识符或内部用户 ID 哈希;尽可能避免记录原始个人身份信息;
- 连接、语音事件、响应、中断、工具调用和关闭的时间戳;
- API 事件中的令牌/时长用量;
- 错误和恢复操作;
- 产物保管信息:音频/转录文本/事件日志的存储位置、保留期限和访问级别。
切勿将评估或评分产物存储在生产 Agent 上下文中。产品提示词、测试夹具和评分材料应分开存放。
完整示例:浏览器客户支持语音 Agent
示例意图:已登录的电商用户可以通过语音查询订单状态、中断助手并请求转接人工客服。助手可以查询订单,但未经明确确认和服务器审批,不得取消订单或退款。
已记录并于 2026-07-10 验证的 API 选择:
- 会话类型:语音 Agent Realtime 会话;
- 模型:如果构建时的模型文档仍显示其为当前型号,则使用
gpt-realtime-2.1; - 传输方式:通过 Agents SDK 辅助工具使用浏览器 WebRTC;
- VAD:
server_vad,经嘈杂环境测试后调整; - 工具:由应用程序执行的
lookup_order、create_refund_draft、request_human_handoff; - 日志记录:保留事件元数据和经脱敏的转录文本;默认不保留原始音频,除非用户选择参与 QA 审核。
语音 Agent 指令:
# Role & objective
You are Acme Retail's voice support assistant. Help authenticated customers understand orders, shipping, returns, and simple account questions.
# Spoken style
Use a warm, calm retail-support voice. Keep answers to 1-2 short sentences, then ask one useful follow-up question. Do not use markdown or numbered lists unless the user asks for steps.
# Audio uncertainty
If a name, order number, address, or amount is uncertain, ask the user to confirm it before using a tool. If background noise may have changed intent, ask a clarifying question.
# Tools
Use lookup_order for order status. It is read-only and may run automatically after intent is clear.
Use create_refund_draft only after explaining the refund reason you heard. It creates a draft, not a refund.
Before any cancellation, refund, message send, or account change, ask for explicit confirmation. Never say an action is complete until the tool result says success.
# Privacy
Do not read full addresses, payment details, tokens, or secrets aloud. Mask sensitive fields. If the user starts sharing a card number or password, stop them and explain that you do not need it.
# Boundaries
For threats, self-harm, legal claims, medical issues, or harassment, move to the approved escalation route. If the user wants a human, call request_human_handoff.
服务器端临时会话创建模式:
// Example only. Re-check current OpenAI SDK and REST shapes before production.
import express from "express";
import OpenAI from "openai";
const app = express();
app.use(express.json());
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
app.post("/voice/session", requireLoggedInUser, async (req, res) => {
const realtimeSession = await openai.beta.realtime.sessions.create({
model: "gpt-realtime-2.1",
voice: "alloy",
instructions: SUPPORT_VOICE_INSTRUCTIONS,
audio: {
input: {
turn_detection: {
type: "server_vad",
threshold: 0.55,
prefix_padding_ms: 300,
silence_duration_ms: 650
}
}
},
tools: [
{
type: "function",
name: "lookup_order",
description: "Look up an authenticated customer's order status.",
parameters: {
type: "object",
properties: {
order_number: { type: "string" }
},
required: ["order_number"]
}
}
]
});
audit.log("realtime_session_created", {
user_hash: hashUser(req.user.id),
model: "gpt-realtime-2.1",
voice: "alloy",
raw_audio_retention: "off"
});
res.json({ client_secret: realtimeSession.client_secret });
});
浏览器连接模式:
// Example only. Prefer current Agents SDK docs at implementation time.
import { RealtimeAgent, RealtimeSession } from "@openai/agents/realtime";
const agent = new RealtimeAgent({
name: "Acme Support",
instructions: SUPPORT_VOICE_INSTRUCTIONS,
});
const session = new RealtimeSession(agent, {
model: "gpt-realtime-2.1",
});
async function startVoice() {
await showConsentAndGetMicPermission();
const auth = await fetch("/voice/session", { method: "POST" }).then(r => r.json());
await session.connect({ apiKey: auth.client_secret.value });
ui.setState("listening");
}
session.on("transport_event", (event) => {
auditClientEvent(event);
updateVoiceUI(event);
});
此示例采用这种结构的原因:
- 浏览器不会接触标准 API 密钥。
- 助手的角色范围有限,语音回复简短。
- 工具副作用与只读查询分开处理。
- 同意和数据保留规则都明确规定。
- 虽然配置了 VAD,但仍需使用真实音频进行测试。
可能的故障模式:
- 助手大声读出敏感的订单详情。
- VAD 将犹豫用户报出的订单号截断。
- 工具返回过多 JSON,导致助手逐字读出。
- 前端记录了临时密钥。
- 模型声称已完成退款,但实际上只创建了退款草稿。
完整示例:服务端访谈筛选器
示例意图:一个研究团队进行一场经同意的语音访谈,收集产品反馈。Agent 提出准备好的问题,自然地追问,为回答添加标签,并在每个环节结束后调用 save_answer。除非后端确认用户符合资格,否则不得声称用户会获得报酬。
架构:
- 服务端到服务端的 WebSocket,因为研究平台通过受控基础设施录制访谈;
- VAD:如果当前文档和模型支持所选会话,则使用
semantic_vad;否则使用调优后的server_vad; - 输出:音频,以及供主持人仪表板使用的可选文本摘要;
- 仅在用户同意的情况下,将原始音频保留 14 天;脱敏后的文字稿保留用于研究分析。
指令:
# Role & objective
You are a voice research moderator. Run a 12-minute interview about a beta productivity app. Ask one question at a time, listen actively, and save concise answer notes after each topic.
# Interview method
Use the approved topic order: onboarding, first useful moment, confusing moments, trust concerns, pricing reaction, final recommendation.
Ask one follow-up when an answer is vague. Do not argue, persuade, or defend the product.
# Spoken style
Sound curious and neutral. Keep your turns under 12 seconds. Leave space for the participant to think.
# Consent and privacy
If the participant asks about recording, say: "We record only if you opted in on the consent screen. You can stop at any time." Do not request passwords, payment details, or medical information.
# Tools
After each topic, call save_answer with topic, concise_summary, notable_quote_if_any, and sentiment. Do not invent quotes. If you are uncertain, omit the quote.
Call flag_for_human_review if the participant withdraws consent, reports a safety issue, or asks to delete data.
服务端 WebSocket 模式:
// Example only. Match event names and fields to the current Realtime API reference.
import WebSocket from "ws";
const ws = new WebSocket("wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1", {
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"OpenAI-Safety-Identifier": hashParticipant(participantId),
},
});
ws.on("open", () => {
ws.send(JSON.stringify({
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1",
voice: "alloy",
instructions: INTERVIEW_INSTRUCTIONS,
audio: {
input: {
turn_detection: {
type: "server_vad",
threshold: 0.5,
prefix_padding_ms: 400,
silence_duration_ms: 900
}
}
},
tools: [{
type: "function",
name: "save_answer",
description: "Save a concise research note for the current interview topic.",
parameters: {
type: "object",
properties: {
topic: { type: "string" },
concise_summary: { type: "string" },
notable_quote_if_any: { type: "string" },
sentiment: { type: "string", enum: ["positive", "neutral", "negative", "mixed"] }
},
required: ["topic", "concise_summary", "sentiment"]
}
}]
}
}));
});
ws.on("message", async (raw) => {
const event = JSON.parse(raw.toString());
logRealtimeEventMetadata(event);
if (event.type === "response.function_call_arguments.done") {
const result = await executeApprovedTool(event.name, event.arguments);
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: event.call_id,
output: JSON.stringify(result)
}
}));
ws.send(JSON.stringify({ type: "response.create" }));
}
});
此示例采用这种结构的原因:
- 提示词强调研究方法,而不是客服角色设定。
- 较长的
silence_duration_ms给参与者留出思考时间。 save_answer仅用于补充,且可审计,不是隐藏的决策引擎。- 撤回同意有专门的工具调用路径。
可能的失败模式:
- 助手过快地填补沉默,影响访谈结果。
- 将意译内容保存为引语。
- 因未测试相关路径而漏掉撤回同意的请求。
- 生成了精炼的摘要,却没有附带证据链接的研究记录。
发布前检查清单
只有满足以下条件,才能发布:
- 已根据 OpenAI 文档重新核实模型、API 字段、价格假设、会话时长、语音列表、传输路径和政策限制,并注明日期。
- 已记录架构选择,并将其与基于文件的 OpenAI 音频 API 区分开。
- 标准 API 密钥仍保留在服务端;客户端凭证是临时的,或已通过其他方式限定权限。
- 音频采集前,用户会看到有关麦克风使用和录音/转录的同意说明。
- UI 提供静音/停止/结束控件,并清晰显示正在聆听/说话状态。
- 已使用真实麦克风测试 VAD,涵盖不同口音、噪声、串音、停顿和打断情况。
- 工具架构简洁,并在服务端验证;具有副作用的操作设有审批关卡。
- 日志记录足够的信息以便调试、滥用审查和成本分析,同时不保留不必要的原始音频或机密信息。
- 已通过对抗性语音场景测试安全、升级处理和人工接管行为。
- 成本仪表板显示每个会话和每轮交互的用量,包括音频令牌数/时长和转录成本。
- 团队已为会话失败、模型不可用、工具失败、音频卡住、用户撤回同意和数据删除请求准备运行手册。
快速故障排查
如果 Agent 抢在用户说话前开口:
- 增大
silence_duration_ms,考虑使用语义 VAD,缩短助手的回答,并确保抢话时会取消音频播放。
如果开头的音节被截掉:
- 增大
prefix_padding_ms,检查客户端麦克风缓冲,并使用轻声说话者进行测试。
如果 Agent 响应缓慢:
- 分别测量首段音频延迟和回答总时长,精简冗长的提示词,缩短口头回答,减少不必要的工具,并在浏览器/移动设备上使用 WebRTC。
如果转录内容与模型的实际行为不一致:
- 请记住,输入转录是独立的 ASR 流程;转录内容用于可观测性,而不能证明模型对音频的确切理解。
如果会话中的成本不断上升:
- 检查对话内容是否不断增长、助手音频是否过长、是否有不必要的 Responses、是否存在背景噪声,以及转录设置。
如果工具操作不安全:
- 将审批移至模型之外,要求明确确认,缩小架构范围,并返回适合语音播报的工具结果。
如果用户不信任语音:
- 说明这是 AI 语音 Agent,告知用户录制或存储的内容,避免伪装成人类,并提供联系人工人员的途径。