
九秒钟的沉默。用户问了一个简单问题,比如"结核病检测流程是什么?",然后就是漫长的等待——久到大多数人都会以为电话断了,直接挂掉。
我们把这个时间缩短到了1.5秒左右。这篇文章说说一个原本简单的平台集成任务,是怎么演变成从零设计内部语音AI架构的,以及延迟问题是如何成为真正工程挑战的。
快速总结:
项目最初只是想集成VAPI,一个做对话式电话AI的平台,接入现有系统。目标很明确:自动化用户 onboarding,让来电者能直接问AI助手问题,不用再等人工客服。
集成本身挺顺利的。后来客户提了个需求,VAPI没法轻易满足——想要更自然、更有表现力的声音。结果一个 workaround 引出另一个,直到我们意识到迟早要自己搭平台。
项目出现了一个有意思的转折:客户提出了更多定制化需求。
其中一个主要需求是更自然、更有表现力的声音,能在对话中传达情感。那时候直接通过VAPI实现这些需求并不像我们需要的那么简单。
为了解决这个问题,我写了个临时方案:从Cartesia获取可用声音,把voice ID存到JSON配置里,在声音选择流程中直接集成Cartesia。
这只是其中一个定制需求的例子。
随着定制需求越来越多,完全依赖第三方平台的弊端越来越明显。相信很多开发者都有这种体验——用托管平台或现成方案时,需求越具体,定制就越困难。
于是冒出了一个简单的问题:
为什么不自己搭一套语音AI平台?
有了这个想法,第一步是评估成本和技术选型。
想到的第一个平台是Twilio。提到电话系统和通讯服务,Twilio基本上是第一个被提起的名字。
不过电话通讯只是拼图的一块。
语音AI系统要处理的问题包括:
调研这些问题时,我看了Deepgram——一个广泛使用的语音转文字(STT)服务,用深度学习模型把原始音频转成文字。
继续研究下去,我发现Twilio、Deepgram、Cartesia这几个平台组合起来,能提供VAPI的大部分能力。
这就引出了另一个重要决策。
就用一个平台?不太行。如果完全依赖单一平台,又回到当初集成VAPI那种模式了。
组合多个平台?那又回到成本问题。
我做了份成本估算文档,比较不同组合方案,汇报给客户。有意思的是,客户选了被戏称为"顶配"的组合:
目标是让每个平台做它最擅长的事,同时编排层完全自己掌控。
一开始我以为这只是又一个集成项目。
这个假设很快就被推翻了。
我的技术负责人指出,把三个大平台集成到一个统一的语音AI系统,绝不是简单任务。项目需要设计一套架构,能够协调多个实时服务,同时保持自然的对话体验。
深入研究需求后,一个挑战立刻凸显出来:延迟。
语音对话对延迟极其敏感。哪怕只等几秒钟,AI助手就会显得迟钝、不自然,甚至像坏掉了。
第二个主要挑战是通过RAG(检索增强生成)管道高效获取企业特定信息。
我先从整体架构设计开始。
第一个决策是:Twilio不会直接和Deepgram或Cartesia通信。我们的内部语音AI平台会作为整个对话的中心编排器。
每个电话进来时,Twilio通过WebSocket与我们的语音AI服务器建立双向媒体流,音频实时双向传输。
简单理解就是:Twilio充当电话线,我们的语音AI服务器成为智能层,协调整个管道。
管道大概是这样的:
Deepgram → LLM → Cartesia
系统还需要这些能力:
通话流程大致如下:
转录文本到达后,系统决定对话该走哪条路——闲聊、企业相关问题、还是预约相关请求。
对于闲聊,转录和对话历史直接发给LLM。对于企业查询,先通过RAG服务检索相关信息,再发给LLM。对于预约交互,先收集预约相关上下文,再生成回答。
因为系统需要访问企业知识,实现RAG管道就成了必要的。
整体流程挺直接的:
这样AI助手就能用企业特定信息来回答问题,而不是只靠它的一般训练数据。
虽然实现概念听起来简单,但要做到实时语音对话那么快的检索速度,又是一套挑战。这就开始了真正的延迟优化之旅。
语音对话和普通应用不一样。
网页应用加载等几秒,用户可能还能忍受。电话对话不一样。用户停止说话后,期望AI几乎立刻回应。
最重要的指标是首次音频时间:来电者要等多久才能听到AI回答的第一部分。
我们最初的管道是串行的:
来电者停止说话 ↓
等待完整转录 ↓
生成查询嵌入 ↓
搜索向量数据库 ↓
等待完整LLM回复 ↓
发给语音合成 ↓
开始播放
每一步单独看都挺合理。串在一起,助手就显得很慢了。
一个典型的知识查询大概是这样的:

单独看这些数字,没有哪个看起来很糟糕。但加在一起,"结核病检测流程是什么?"这种问题之后,可能要等大约9秒。
电话里9秒的沉默感觉比网页上9秒漫长得多了。这成了真正的挑战。
一个设计决策改变了一切:我们不再优化生成完整回复的总时间,而是开始优化首次音频时间。
看两个场景。第一个,AI生成4秒的回复,但在1.5秒后就开始说话。第二个,生成2秒的回复,但要等4秒才开始说话。
第一个感觉快得多。来电话的人不在乎AI还在生成剩下的回答——他们在乎的是对话自然地继续。
这改变了我对整个管道的思考方式。
RAG想要更多上下文。语音想要少等待。
如果我们检索信息、等完整LLM回复、然后才开始生成语音,那知识检索路径就成了对话中最慢的部分之一。
而且不是每个对话都需要RAG。来电话的人说"你好,你好吗?"不需要触发向量搜索。"好的。"或"谢谢,就这样。"也不需要。
所以线上管道变得更加智能——之前的路由决策现在决定了是否真的需要检索。
核心思路:RAG是对话的一个分支,不是默认路径。这既是延迟优化,也是质量提升。
第一个实现把每个对话轮次几乎当成批处理:
检索 → 生成 → 说话
来电者要到最后一步才能听到任何声音。对语音场景来说,这不行。
对于知识问题,检索仍然需要在生成有依据的回答之前完成。但一旦相关上下文可用,LLM就可以开始流式输出了。
不等完整回答,而是把生成的文字缓冲起来,直到有一个完整句子。一旦句子可用,立刻通过实时连接发给Cartesia。
所以不是等完整回答——"结核病检测需要在入职流程完成前完成。你可以在……"——系统可以开始说"结核病检测需要在入职流程完成前完成。"同时剩下的回答还在生成。
管道因此变成了这样:
Twilio 音频 ↓
Deepgram ↓
部分转录 + 轮次结束信号 ↓
轻量路由 ↓ ┌───────────────┐ │ 闲聊 │ │ 知识问题 │ │ 工具调用 │ └───────────────┘ ↓
需要时检索上下文 ↓
LLM 流式输出 ↓
句子缓冲 ↓
Cartesia ↓
Twilio
"轻量路由"是一个快速、轻量的分类器,看转录内容然后决定对话该走哪条路——闲聊、知识问题、还是工具调用——然后才动用检索或LLM这些昂贵的操作。因为它在每个回复的关键路径上,必须快、低成本。
三大组件——Deepgram、LLM、Cartesia——不再是简单的一个接一个跑。它们开始重叠了。这个区别带来了巨大改善。
这听起来像是个小实现细节。其实不是。
第一个版本反复支付连接建立成本。LLM连接可能空闲,需要重新建立。语音合成也是每个回复开一个新的请求。
这些延迟在本地开发环境里不明显。在实际打电话时就明显了。
我们改了连接策略。LLM连接在多个轮次间保持热状态,后续请求复用已有会话,不用反复建立连接。对于Cartesia,用持久WebSocket覆盖整个通话生命周期,而不是每个句子新建HTTPS请求。服务器还维护一小池热连接,这样初始问候语不需要支付完整连接建立成本——那时候来电者已经在等了。
这可能不是搭建语音AI系统最激动人心的部分。但这些小延迟会累积。有时候"几乎即时"和"稍微有点慢"的差别,就藏在那些没人会单独注意的几百毫秒里。
实时的onboarding通话里,知识问题只是其中一部分。来电话的人可能说"你好,你好吗?"或"好的。"或"能约周四两点吗?"这些都不应该自动触发向量搜索。
只有事实性的、企业特定的问题才应该进入检索路径。这改善了延迟,也改善了回复质量。"谢谢。"跑RAG可能检索到无关的企业信息,给LLM不必要的上下文。同样,预约请求不应该让模型去搜企业文档——它实际需要的是实时的预约信息。
再说一遍核心架构原则:检索是有条件的。
另一个有意思的优化来自看什么时候生成查询嵌入。
最初,嵌入只在语音转文字确认来电者说完话之后才开始。这意味着我们还没开始嵌入步骤,就已经支付了轮次结束延迟。
但在实际对话中,来电者还在说话时我们就能收到部分转录。那些部分转录是有用的。一旦有足够的有意义词汇,就可以从当前假设speculatively生成嵌入。到轮次结束信号到来时,嵌入可能已经准备好了。
我们还引入了嵌入缓存。"嗯"、"呃"这些填充词不会实质性改变查询,可以在生成缓存键之前去掉。这意味着"嗯什么是入职"和"什么是入职"可以共享同一个缓存嵌入。
向量搜索本身从来不是最大瓶颈。嵌入步骤才是。对于实时检索,我们最终把查询嵌入搬到本地,用一个小模型本地运行,把这部分降到大约10-30毫秒,而不是在关键路径上再加一次云端往返。
语音回答通常应该简洁。
往LLM塞大段文档不只是增加模型要处理的信息量——还可能让助手听起来不自然。想象你打电话问了个简单问题,结果AI开始给你念一整篇政策文件。那可不是什么好语音体验。
所以我们把检索到的上下文保持得很小。用小的top-k,限制检索段落的大小,在适当的地方用更快的模型处理口语化知识回复。我们还用相似度阈值——如果检索到的信息关联度不够高,就不强行塞进prompt。有时候"我没有这个细节,可以帮你转接团队成员。"比一个慢的或可能错误的回答好得多。
这是聊天机器人的RAG和语音系统RAG最大的区别之一。在文字界面里,加点上下文相对便宜。在电话对话里,加的上下文会直接影响来电者在听到第一个词之前等多久。
RAG在语音AI里还有另一个不那么明显的问题:查询不是用户打出来的,是从语音转出来的。这意味着检索系统要处理转录错误和对话上下文。
想象来电者说"那个要多久?"这句话本身作为搜索query不太有用。但如果之前的对话是关于结核病检测的——真正的问题是"结核病检测要多久?"
语音识别还会引入另一个问题。来电者可能说"结核病检测",但转录出来是"TV检测"。直接把那个原始转录扔进向量搜索,会降低检索质量。
我们没有加一个昂贵的LLM调用来重写查询,而是引入了一个轻量重写层。它可以:
比如"那个要多久?"可以变成类似"结核病检测要多久?"重要的是,这是在不往关键路径加一个昂贵模型调用的情况下完成的。
另一个架构决策是把知识摄入和实时检索分开。这是两个完全不同的工作负载。文档摄入可以慢慢来。打电话不能等。
上传文档时,我们可以:
这些工作在摄入阶段完成,不是在有人打电话等着的时候。实时检索路径应该简单得多:
用户查询 ↓
查询嵌入 ↓
向量搜索 ↓
小上下文块 ↓
LLM ↓
流式回复
电话不应该等着PDF解析、文档分块或其他摄入工作。这个分离是让RAG在实时语音系统中实用的关键。
助手范围划分在这里也很重要。我们不会为每个问题去搜整个公司的知识库——只搜处理这个电话的特定助手关联的文档。除了正确性问题,搜不必要的数据也意味着做不必要的工作。
基本管道跑起来之后,几个问题就浮现出来了。
轮次检测。如果AI在来电者暂停后等太久,对话就显得慢。如果反应太快,又会打断来电者。我们用对话式语音转文字配合轮次结束信号,加上一个eager轮次结束机制,让系统可以稍微早一点开始响应——省下几百毫秒。但这又引入另一个问题:同一句话有时候会收到多次,第二次转录包含更多词。编排器因此需要理解新事件是同一句话、还是延续、还是全新问题。不然助手可能回答同一个问题两次。
打断处理。真人会打断。当来电者在AI说话时开始说话,系统需要停止当前回复。我们中止当前LLM轮次、取消飞行中的语音、指示Twilio丢弃残余音频。但不会关闭Cartesia连接——通话中重连TTS会引入另一个延迟问题。打断后加个短暂退避,防止在来电者和助手互相抢话时管道不断启动停止。
回应词。人们听的时候自然会说一些小词——"好的。"、"嗯嗯。"、"知道了。"这些不一定是打断。但"不。"或"停。"可能是。系统因此需要区分对话式回应词和真正的打断。
这些细节在架构图里看起来不怎么起眼。但这就是语音AI demo和真正能打电话用的东西之间的差别。
不是每个交互都是知识问题。预约、查询、改签、取消,以及类似操作通过连接现有后端的工具来处理。转接也遵循路由规则——紧急情况可能需要人工客服,另一个对话可能需要转给不同的AI助手。
但工具调用需要时间。如果来电者在后端检查预约可用性时听到完全沉默,系统就感觉像卡住了。所以助手可以在工具执行时先说一句简短的对话填充语,然后再继续说实际结果。填充语不是替代结果——只是cover后端操作需要的时间。
转接意图也要考虑延迟处理。简单的短语匹配可以先检查,因为成本低。措辞不那么明显时再用语义相似度。有些决策需要的数据也可以在通话早些时候提前准备,这样第一个有意义轮次不用支付全部成本。
语音AI不只是从LLM获取答案。系统还需要安全过滤。有些指令通过系统prompt处理。其他模式可以在本地检测,拦截或修改不安全的输入输出。
重要的是这些检查需要融入同一个实时管道。如果安全过滤慢到产生明显停顿,就成了另一个延迟问题。
这是个重要的区分。当我说把延迟从大约9秒降到1.5秒,指的是典型知识轮次的首次音频时间。前提是走热路径:
不是说每个可能的语音AI交互都在1.5秒内完成。比如冷的预约请求可能需要检查可用性、确认信息、调用后端服务、生成多个时间槽——那是不同的延迟指标。
也不是说完整回答的语音时长。那些是独立的指标。
重要的改变是来电者实际感受到的体验。不再是问完问题后干等,助手可以在后台继续工作的同时开始响应。对话又开始感觉像真正的对话了。
当然,这些优化都不是免费的。
流式输出第一个句子意味着系统有时候会在完整回答确定之前就开始说话。我们用更短的回答和检索置信度阈值来缓解,而不是等完整回复。
本地嵌入快得多,但需要和文档摄入阶段生成的嵌入保持对齐。
启发式查询重写在我们面对的特定领域效果很好,但需要维护,不一定完美泛化到每个行业。
也许最大的权衡就是我们整个旅程开始时提到的那个:一旦不再完全依赖托管语音AI平台,就拥有了整个编排层。这意味着要自己处理:
这就是自建语音AI系统真正的成本。
这个项目最大的收获其实不是Twilio、Deepgram、Cartesia、RAG,甚至不是LLM。那些组件都是可以替换的。
真正的产品是决定以下问题的编排循环:
最重要的是:多快能让来电者听到有用的东西?
这才是最终决定语音AI系统是真正的对话,还是只是套着电话壳的API管道。
如果你正在做或评估语音AI——不管是用托管平台还是自己掌控编排层——我很想交流经验。有想法欢迎留言或私信交流。