用 ElevenLabs 和 Twilio 20 分钟搭建语音智能体
- 发布时间
- 最近更新
语音智能体可接听来电,实时转写来电内容,配合
开发者将用到的完整技术栈包括:ElevenLabs 负责语音合成(Flash v2.5)和转写(Scribe v2 Realtime),Twilio 负责电话通信,LLM 可选用 OpenAI 或 Anthropic。这些组件都可互换,可以根据熟悉程度自由选择。
本文将演示如何用 Node.js 和 Typescript 在 20 分钟内搭建语音智能体。如果想要托管版,自动处理轮流说话、中断和电话通信,无需自己维护流程,可前往 ElevenAgents。
语音智能体架构原理
在写代码前,先了解三项服务如何连接。
- Twilio: 负责电话接入和音频传输。
- ElevenLabs: 通过 Scribe v2 Realtime 实现 STT,通过 Flash v2.5 实现 TTS。
- LLM: 负责调用工具并生成回复。
每个环节都是独立适配器,因此可以随时替换服务而不影响其他部分。例如,可以将 OpenAI LLM 换成 Anthropic,无需重写其他组件。
电话通过 Twilio 接入服务器。Twilio 接听 PSTN 电话,建立 WebSocket 连接到服务器,并将来电音频以 base64 编码的 mu-law 流发送。服务器运行流程,并将合成音频通过同一 WebSocket 返回,Twilio 播放给来电者。

搭建语音智能体的流程如下:
来电者拨打 Twilio 号码。Twilio 从 webhook 获取 TwiML 文档。TwiML 指示 Twilio 打开到 WebSocket 端点的 Media Stream。Twilio 以包含 base64 mu-law(ulaw_8000)数据的 JSON 事件流式传输来电音频。
服务器将音频片段转发到 Scribe v2 实时版 进行流式转写。来电者说完后,将转写文本发送给 LLM,再用 Flash v2.5 以 ulaw_8000 合成回复。合成后的 mu-law 数据以 base64 编码通过 WebSocket 返回 Twilio,Twilio 播放给来电者。
Scribe v2 Realtime 部分转写延迟约 150 毫秒,Flash v2.5 推理约 75 毫秒(不含网络和应用延迟)。LLM 是影响首次音频输出延迟的最大因素。为缩短延迟,LLM 输出时按 token 流式传输,模型未结束时即可开始合成。
搭建语音智能体前的准备
本指南假设已准备好以下四项,均可快速配置,缺少任意一项都无法运行服务器。
请确认以下前置条件:
- 具备支持语音的 Twilio 电话号码:请记录号码、Account SID 和 Auth Token,可在 Twilio 控制台查看。
- ElevenLabs API 密钥:可在 ElevenLabs 控制台创建。密钥通过 xi-api-key header 传递,属于敏感信息,请仅在服务器端使用。详见
- LLM API 密钥:本教程支持 Anthropic Claude 和 OpenAI,任选其一即可。
- 本地开发用 Ngrok(或其他隧道工具): Twilio 需通过公网 HTTPS 和 WSS 访问服务器,ngrok 可实现,无需部署。
将密钥设置为环境变量,切勿提交到代码库。
然后启动隧道,指向服务器端口:
理解 Twilio Media Streams 协议
Twilio 不直接提供原始音频 socket,而是通过 WebSocket 以结构化 JSON 协议传输。了解四种事件类型和发送格式,有助于后续编写 WebSocket 处理逻辑。
Twilio 连接 WebSocket 后,会发送一系列 JSON 文本消息,共有四种事件类型。
首先收到 connected 事件,确认 WebSocket 已建立。media stream 开始时发送 start 事件,包含需保存的 streamSid(用于回传音频),以及 start.customParameters 和 start.callSid 下的通话元数据。
media 事件为循环事件:media.payload 是 base64 编码的 8kHz mu-law 音频片段,每帧 20 毫秒,media.track 表示来电音频。stream 结束时发送 stop,通常因挂断电话。
回传音频时,发送类型为 media 的消息,带相同 streamSid 和 base64 mu-law 数据。若需中断已排队音频,发送类型为 clear 的消息,带 streamSid,可清空 Twilio 的输出缓冲区。
收发音频编码一致(ulaw_8000)。请求 ElevenLabs 文本转语音时指定 ulaw_8000,直接将字节转发给 Twilio,无需重采样。
第 1 步:提供 TwiML webhook
来电时,Twilio 会向 webhook 发起 HTTP 请求,返回的 TwiML 连接通话到 Media Stream。<Connect><Stream> 标签打开双向 WebSocket。此处用 <Connect> 而非 <Start>,可保持通话持续并支持回传音频,正是本方案的目的。
webhook 返回的 TwiML 如下:
在 Express 中,只需一个 POST 处理器填充 host 并返回文档:
在 Twilio 控制台,将号码的 “A call comes in” webhook 设置为 https://your-subdomain.ngrok.app/incoming-call,使用 HTTP POST。
第 2 步:接收 Media Stream WebSocket
WebSocket 处理器读取 Twilio 事件,驱动流程,并回传音频。
每通电话需保存少量状态:streamSid、STT 连接,以及智能体是否正在说话的标志。处理器将每帧 media 解码为原始 mu-law 字节,直接转发给 STT:
第 3 步:用 Scribe v2 Realtime 转写
Scribe v2 Realtime 支持流式音频片段输入,返回部分和最终转写,且可直接处理 mu-law 编码,因此可直接传递 Twilio 的音频帧。
还支持基于静音的语音活动检测(VAD)进行分段,并可手动提交以完成分段。对于
具体步骤:通话开始时打开 STT 流,推送每个 mu-law 音频片段,转写完成后调用 LLM。
实时 STT 客户端接口仍在迭代,建议用 TypeScript 适配器(openRealtimeStt)对接实时 API,而非依赖固定字段。onFinal 可作为转交已完成说话轮次的钩子。
实时识别延迟约 150 毫秒,能有效缩短来电者说完到智能体开始回复的间隔。批量转写和完整功能见 Speech to Text 文档 以及 实时 Speech to Text 产品页。
第 4 步:用 LLM 生成回复
此阶段生成回复。LLM 接收对话历史,返回助手文本。建议流式输出,便于第一句话生成后立即合成。
此处以 OpenAI 为例:
上述模型 ID gpt-4.1-mini 是低延迟示例;Anthropic 可用 claude-haiku-4-5。两者均可用于 llmReply,只需替换函数体,其他部分无需更改。
系统提示词限制回复长度,电话场景下尤为重要:回复过长会显得慢且难以自然打断。
第 5 步:用 Flash TTS(ulaw_8000)合成语音
文本需转为 Twilio 可播放的音频。请求 Flash v2.5 时指定 outputFormat: "ulaw_8000",确保字节格式与 Twilio 匹配,然后流式传输音频,每段作为 media 事件通过 WebSocket 返回。
将 LLM token 累积为句子片段,片段完成即合成,而非等全部回复生成后再合成。这样可缩短首次音频输出时间,来电者能在模型生成第二句话时听到第一句话。需更细致控制时,可参考实时 TTS WebSocket 指南,单 socket 增量输入文本;下方 HTTP 流式方案适合短对话。
让 AI 语音智能体达到生产级
完成上述五步后,智能体已可运行,但这还不是生产部署。
上线前还需注意以下问题:
校验 Twilio webhook 签名
任何人只要知道 webhook 地址都能 POST,因此需确认请求确实来自 Twilio。Twilio 每次请求都用 Auth Token 生成 X-Twilio-Signature header,校验失败即拒绝。签名基于完整 URL 和 POST 参数,需与 Twilio 算法一致。
Twilio 提供了校验工具:
妥善管理密钥
将 ELEVENLABS_API_KEY、LLM 密钥和 TWILIO_AUTH_TOKEN 存放在密钥管理器中,勿写入源码或明文 env 文件。ElevenLabs 密钥仅授权所需接口,并设置额度,防止泄露造成大范围损失。
企业版还可通过 IP 白名单限制密钥使用范围。本服务端直接用 API 密钥,因为密钥不会离开后端;如有音频逻辑需在浏览器或移动端运行,建议改用一次性 token,避免密钥暴露。
了解并发限制
每个套餐的并发上限按模型系列不同,统计当前同时生成音频的请求数。
电话智能体并发统计有利于你。音频生成速度快于播放,因此每通电话只在合成回复时占用 TTS 并发,不会持续占用。一般来说,5 路并发可支持约 100 路同时对话,因为生成早于播放结束。
建议实时监控余量,不要凭估算。ElevenLabs 响应头包含 current-concurrent-requests 和 maximum-concurrent-requests,建议记录并接近上限时告警。超限时请求按优先级排队,通常增加约 50 毫秒,持续超载会返回 HTTP 429。
收到 HTTP 429 时应短暂重试,若持续出现可在定价页升级套餐,企业版可联系客户经理提升上限。
处理插话和中断
来电者在智能体说话时插话,期望智能体立刻停下。这就是插话,正确处理能让智能体更自然。
用 STT 的 VAD 信号检测来电者说话。检测到后,需做两件事:一是停止转发 TTS 音频(speak 中的 agentSpeaking 标志已实现),二是向 Twilio 发送 clear 消息,清空已排队音频。
若未发送 clear,Twilio 会继续播放缓冲音频,导致智能体与来电者抢话。
日志、监控与容错
为每个环节打点,便于定位通话延迟。统计从最终转写到首个 LLM token、首个 LLM token 到首个 TTS 字节、首个 TTS 字节到发送给 Twilio 的时间。大部分延迟通常在 LLM 阶段,STT 和 TTS 较为稳定。
还需考虑部分失败。LLM 可能超时,STT 流可能断开,ElevenLabs 网络往返延迟因地理位置约 20-200 毫秒。建议服务器靠近来电者,而非仅靠近 ElevenLabs,ElevenLabs 已自动路由到最近的数据中心。
某环节失败时,不要让来电者陷入静音:可合成一句简短兜底语(如“抱歉,请再说一遍?”),保持通话。每个环节都应加超时和异常捕获,避免单次失败导致整个 WebSocket 断开。
上线前还建议设置以下默认项:
- 系统提示词限制回复长度,确保对话简短、易于插话。
- 限制对话历史长度,避免长时间通话导致 LLM 上下文无限增长。
- 设置通话最长时长,防止异常会话持续占用并发。
如需持续优化可控环节,详见 延迟文档,了解首次音频输出的延迟来源,模型概览 介绍速度与质量权衡,实时 TTS WebSocket 指南 展示如何通过增量文本输入进一步降低合成延迟。
用 ElevenAPI 构建生产级语音智能体
现在 20 分钟过去,已经搭建好每一层生产级
如果不想自己维护流程,ElevenAgents 提供轮流说话、中断处理和电话集成的托管服务,底层用的就是你刚刚串联的同款模型。
如需持续优化自有技术栈,可查看 ElevenAPI 产品页,了解套餐、并发限制和声音库。也可直接注册,立即体验首次通话。
.webp&w=3840&q=80)
.webp&w=3840&q=80)

.webp&w=3840&q=80)
