For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主导航
2026年3月25日 音频

Perplexity 如何通过 Realtime API 为数百万人带来语音搜索

使用 Realtime API 构建 Perplexity Computer 语音智能体的经验。

作者: Paul Fryzel (Perplexity), Charu Jaiswal (OpenAI)

Perplexity 如何通过 Realtime API 为数百万人带来语音搜索

在 Perplexity,我们非常重视打造使用体验出色的产品。对于我们的智能体浏览器 Perplexity Comet 和功能强大的通用数字员工 Perplexity Computer,其中很重要的一环就是让用户能够完全通过语音来使用它们。只需说出需求、交出任务,然后看着它执行,这种体验有一种独特的满足感。我们看好语音作为交互界面的前景,因为它让实际交互多了一点魔法般的感觉。

我们在生产环境中使用 Realtime-1.5,为 Perplexity 每月处理的数百万次语音会话带来了这种神奇的体验。看着 Computer 界面中的语音使用量不断增长,我们既兴奋,也学到了很多。下面我们将分享一些迄今为止出乎意料的收获。也欢迎您尝试 Realtime-1.5,与我们分享您的心得。

1. 明确上下文管理策略

长篇内容,尤其是信息密集、长达数小时的播客,是最能检验我们上下文管理能力的场景之一。我们希望用户能通过语音查询播客转录文本,随时提问,比如问播客播放到两个半小时处的某个具体时刻在讲什么,并得到连贯的回答。

上下文容纳不下整份转录文本。我们最初尝试将其分成大块发送,但很快发现,大块更新一旦失败,就会导致此前的历史记录全部丢失。如果您尝试向只剩 5,000 个 Token 空间的窗口发送一段 10,000 个 Token 的更新,模型就会丢失此前的全部历史记录。因此,大块更新的风险高得多:一次过大的更新就可能清空整段上下文,而无法让系统更平缓地逐步遗忘。

于是我们改变了做法。我们不再发送大块更新,而是将所有内容拆分成每块 2,000 个 Token 的小块,逐步输入。这会增加开销,但行为稳定得多。即使发生截断,也只会裁掉少量历史记录,而不是清空全部内容。

我们还发现了一个微妙之处:不同的上下文不应该都以同一种方式输入模型。使用 conversation.item.create 更新上下文时,item.type: "message" 有三种角色:systemuserassistant。这些角色告诉模型它看到的是什么类型的消息。system 用于提供指令和引导行为,user 用于最终用户的输入,assistant 用于模型生成的输出。

这一步处理不当时,交互就开始显得不自然。如果过多上下文以 user 的形式输入,模型就会表现得像是用户在逐段讲述所有文本,包括网页片段和评论,而不是仅仅基于这些材料提出问题。如果过多内容以 system 的形式输入,则会出现相反的问题。模型无法再区分哪些是它本来就“知道”的内容,哪些是外部提供的上下文,以及用户此刻究竟在问什么。

浏览网页的过程就是一个很好的例子。用户滚动页面时,我们会持续将屏幕上的内容提供给模型。如果把所有这些内容都作为用户输入,模型就会表现得像是用户把每一段文字都念了出来。这种理解方式并不正确。我们希望系统给人的感觉是:它在后台了解页面内容,并在用户提问时自然地作答。最终我们发现,关键与其说是上下文的数量,不如说是正确表达对话中各类信息的含义。

2. 统一各产品端的音频处理

Perplexity 有多个产品端,例如 Ask、Comet 和 Computer,每个都基于不同的客户端技术栈构建。Swift、TypeScript、Rust 和 C++ 都可能生成不同的原生音频缓冲区。当我们让每个客户端将各自的原始或原生格式音频发送给 Realtime API 时,性能表现就出现了不一致。

我们最终用 Rust 构建了一个 SDK,封装这些平台差异,确保每个客户端都按同一套音频规范向 API 发送数据。具体来说,就是在波形到达服务器之前进行处理:重采样为 48 kHz 单声道,以匹配 Opus 编解码器偏好的采样率和 WebRTC 的内部采样率;再通过 WebRTC APM 进行回声消除、自动增益控制、降噪和高通滤波;最后编码传输。有了这个 SDK,我们可以在一处统一音频常量、进行重采样并配置完整的处理流水线,无需为每个客户端单独实现。

3. 针对复杂的真实环境进行调优

在用户实际所处的环境中对 VAD 进行调优非常重要。这意味着要根据真实的麦克风、扬声器音量和背景噪声进行校准。我们的一个内部测试场景是旧金山一家嘈杂的酒吧,因为这很像用户实际使用产品的时刻。有人问:“你试过新的 Perplexity 应用吗?”朋友拿出手机,如果语音功能失灵,我们就一下失去了两位用户。如果顺利运行,对方的反应则更接近“卧*”。这个场景有效地推动我们解决问题。在理想条件下运行良好的功能,到了现实环境中往往会出问题。最好先针对复杂的真实环境进行调优。

语音用户体验中最难处理的问题之一,是正确应对停顿。人们自然会停下来思考、在屏幕上调出内容,或者准备朗读一段文字。模型很容易把这种停顿当作当前轮次结束,从而过早接话。我们就遇到过这样的情况:用户请模型协助进行数学推导,停下来寻找公式,问题还没问完,模型就抢先回答了。这促使我们设计了语音锁定功能。传统的按键说话方式默认关闭语音,用户必须按下按钮才能说话,而我们的做法恰好相反。默认情况下,语音交互持续待命;但当用户暂时不想被打断时,可以锁定语音,掌握当前轮次的发言权。我们也认为,这不只是一项独立功能。随着语音界面进入更复杂的工作流,我们相信,这种交互模式的某种形式会成为标准。

4. 仅保留核心工具,并使其符合模型的训练数据分布

将工具集缩减到最重要的少数工具。在我们的场景中,这意味着少于十个。我们专注于一小组核心工具,覆盖价值最高的操作。这种取舍是合理的,而且随着更新的模型快照不断改进,效果可能会更好。

我们在系统提示中加入了明确指令,说明每个工具应在何时、以何种方式调用。我们也仔细确保工具模式和输出都符合模型的训练数据分布。具体来说,就是将工具输出格式化为普通的结构化工具数据,而不是助手的对话内容。我们返回字段划分清晰的结构化 JSON,例如用 response_text 存放面向用户的话语,用 require_repeat_verbatim 等标志控制行为,而不是将要说的内容与内嵌指令混在一起。这样让工具使用更加稳定,也让交互模式更接近模型在训练期间可能见过的形式。

// Good:
{
  "response_text": "I kicked-off the task to create a market research dashboard",
  "require_repeat_verbatim": true
}
// Avoid:

I kicked-off the task to create a market research dashboard

# Response Instructions

Read the above instructions EXACTLY as they are

Realtime 已准备就绪

Realtime-1.5 是行业的一个转折点。在处理长上下文、更多工具以及对智能能力要求较高的任务方面,确实还有改进空间。但我们相信模型会不断进步。在 Perplexity,我们思考的是如何从今天开始为这样的未来构建产品。我们希望让当下的系统切实可用,同时为下一代 Realtime 模型及其带来的全新语音体验做好准备。