语音Agent并非简单拼接STT→LLM→TTS,需解决音频传输、轮流检测、流式响应延迟等问题。文章给出五层职责划分和sandwich架构,适合想在应用中集成语音能力的开发者。
构建语音智能体不仅仅是把语音转文字连接到 LLM,再加个文字转语音那么简单。
一个生产级的语音智能体必须解决一个更难的问题:
如何让 AI 系统做到倾听、推理、使用工具、记住上下文,并且响应足够快,让对话仍然感觉自然?
LangChain 可以处理智能体和工具编排层,但实时体验很大程度上取决于它周围发生的事情。
一个实用的架构如下:
用户麦克风
↓
音频流
↓
语音转文字(STT)
↓
转录文本 / 轮次检测
↓
LangChain 智能体
↓
工具 / API / 业务逻辑
↓
流式响应
↓
文字转语音(TTS)
↓
用户听到回复
LangChain 当前的语音智能体文档将此称为"三明治"架构:STT → 智能体 → TTS。优势在于每一层都可以独立替换,而智能体可以继续使用更广泛的 LangChain 生态。
在写代码之前,将语音智能体拆分为五个职责:
音频传输 — 将麦克风音频传输到后端,再将音频响应传回客户端。
语音识别 — 将音频转换为文本。
智能体推理 — 判断用户想要什么以及采取什么行动。
工具执行 — 与数据库、CRM、日历、API 或内部系统交互。
语音合成 — 将回复重新转换为音频。
这种分离很重要,因为这些组件具有不同的性能特征。
例如,更换 TTS 提供商不应该需要重写业务逻辑。类似地,更换 LLM 不应该需要重建音频传输。
这种模块化是用级联架构而不是把所有东西塞进一个模型的最强理由之一。
构建语音智能体有两种主要方式。
音频
↓
STT
↓
文本
↓
LangChain 智能体
↓
文本
↓
TTS
↓
音频
这让你对每个组件都有控制权。
你可以选择一个 STT 提供商、另一个 LLM,以及一个完全不同的 TTS 提供商。
这也让调试更容易,因为你可以独立检查转录文本、智能体决策、工具调用和最终响应。
代价是额外的基础设施和潜在的延迟。
音频
↓
多模态语音模型
↓
音频
这可以减少移动部件的数量,并可以保留更多关于说话方式的信息,比如语调。
然而,它会减少你对单个组件的控制,并可能引入提供商特定的约束。
对于工具执行、可观测性、提供商灵活性以及确定性工作流很重要的业务应用,级联架构仍然非常实用。
这是许多语音智能体实现出错的地方。 naive 实现会等待整条链路:
录制完整句子
↓
转录
↓
等待完整 LLM 响应
↓
生成完整音频
↓
播放响应
用户会遇到一次长延迟。而流式架构则是:
音频块
↓
STT 立即开始
↓
转录文本到达
↓
智能体开始生成
↓
首批响应 token 到达
↓
TTS 开始
↓
音频开始播放
系统不会等待每个阶段完成后再开始下一阶段。
LangChain 的官方语音智能体示例使用异步流式处理和 RunnableGenerator 来连接 STT、智能体和 TTS。文档指出,在合适的 STT 和 TTS 提供商下,这条管道可以实现低于 700 毫秒的延迟。
重要的一课是:
实时语音主要是一个管道设计问题,而不仅仅是模型选择问题。
实时语音智能体的研究同样将跨 STT、LLM 和 TTS 的流式处理和管道化确定为减少感知延迟的核心机制。
一旦语音被转换为文本,语音层就可以将请求交给一个普通的 LangChain 智能体。
当前的 LangChain 应用使用 create_agent 作为主要入口。
一个最小的智能体可以是这样:
from langchain.agents import create_agent
def check_order_status(order_id: str) -> str:
"""返回订单的当前状态。"""
return f"订单 {order_id} 当前正在处理中。"
agent = create_agent(
model="openai:gpt-5.4",
tools=[check_order_status],
system_prompt="""
你是一个客户支持语音智能体。
回复要简短。
缺少信息时主动询问,而不是猜测。
当用户询问账户相关信息时使用工具。
"""
)
重要的部分不是那五行代码。
而是工具边界。
语音智能体不应该通过模型生成的任意文本来直接操作你的数据库或业务系统。
用户:
“我的订单 4821 到哪了?”
↓
智能体
↓
check_order_status("4821")
↓
业务系统
↓
结构化结果
↓
智能体
↓
“您的订单正在处理中。”
LangChain 智能体可以推理可用的工具并作为智能体循环的一部分执行它们。当前的智能体实现建立在 LangGraph 的运行时之上。
这是语音智能体工程中一个被忽视的部分。
一个对文本聊天机器人好用的工具,对语音智能体可能设计得很差。
例如,避免给智能体返回一个这样的工具:
{"customer_id": 1827,
"subscription_status": "active",
"plan": "enterprise",
"billing_cycle": "annual",
"last_payment": "...",
"payment_method": "..."}
而用户问的只是:
“我的订阅激活了吗?”
取而代之,让工具返回智能体可以快速推理的信息。
def get_subscription_status(customer_id: str) -> str:
"""检查客户的订阅是否处于激活状态。"""
...
语音智能体就可以回复:
“是,您的订阅是激活的。”
围绕决策而非数据库表来设计工具。
这减少了不必要的推理,并使口语响应更容易控制。
为书面聊天优化的大型语言模型可以输出一整段话。
语音智能体不应该。
“当然,我可以帮您处理。根据您账户中的信息,您的订单已处理成功,目前正在运输中。预计将在接下来的两到三个工作日内送达……”
“您的订单已在运输中。预计两到三个工作日内送达。”
语音需要不同的响应策略。
一个有用的系统指令是:
你是一个语音助手。
说话要自然简洁。
每次回复优选一两句。
不要朗读 JSON、URL、ID、表格或长列表。
一次只问一个问题。
如果工具失败,简要解释问题并提供下一个操作建议。
永远不要捏造工具无法提供的信息。
这不是单纯的提示词优化,而是接口设计。
如果智能体忘记五秒钟前说的话,语音对话就会变得尴尬。
用户:“我想预约明天的appointment。” 智能体:“什么时间?” 用户:“大概 4 点。”
请确保智能体理解"4"指的是预约时间。
LangChain 的语音智能体示例使用带检查点和唯一线程 ID 的会话状态,这样智能体可以在多轮对话中保留上下文。
用户
↓
语音会话 ID
↓
会话状态
↓
LangChain 智能体
↓
响应
对于生产系统,要区分:
短期会话状态
当前通话期间说过的事情。
长期业务记忆
应该跨越通话保留的信息。
不要把每个客户数据都塞进 LLM 的会话历史中。
只检索当前决策所需的信息。
这是聊天机器人和语音智能体之间最大的区别之一。
想象智能体正在说:
“您的预约安排在周四——”
“改成周五吧。”
真正的语音界面应该停止说话。
这意味着你的系统需要支持打断(barge-in)。
一个简化的流程是:
智能体正在说话
↓
用户开始说话
↓
检测到打断
↓
停止 TTS 播放
↓
取消/忽略剩余音频
↓
处理新的用户输入
没有打断处理,系统感觉不像对话,更像是 IVR 朗读脚本。
这就是为什么音频传输、轮次检测和取消逻辑与 LLM 同样重要。
对于基于浏览器的实现,WebSocket 是一个实用的传输层。
客户端捕获麦克风音频:
浏览器麦克风
↓
PCM 音频块
↓
WebSocket
↓
后端
后端通过同一连接将合成音频发送回来:
后端
↓
TTS 音频块
↓
WebSocket
↓
浏览器
↓
扬声器
LangChain 的参考语音应用使用 WebSocket 进行双向音频流传输,并指出相同的总体架构可以适配到电话或 WebRTC。
重要的设计决策是使传输层与智能体解耦。
你的智能体不应关心请求来自哪里:
它应该接收输入事件并返回智能体事件。
简化的 LangChain 管道在概念上可以这样表示:
from langchain_core.runnables import RunnableGenerator
pipeline = (
RunnableGenerator(stt_stream)
| RunnableGenerator(agent_stream)
| RunnableGenerator(tts_stream)
)
每个阶段消费流并产生流。
STT events
↓
Agent events
↓
TTS events
这比将语音智能体视为一个巨大的函数更有用。
每个阶段都可以独立测量。
Audio received
↓
STT first transcript 180 ms
↓
Agent first token 220 ms
↓
TTS first audio 160 ms
↓
User hears response ~560 ms
这些测量数据告诉你真正的瓶颈在哪里。
不要只测量总 API 响应时间。
对于语音系统,至少要追踪:
首字转录时间
系统理解用户语音的速度有多快?
智能体开始响应的速度有多快?
用户听到响应的速度有多快?
总响应时长
智能体完成说话需要多长时间?
外部 API 调用需要多长时间?
User finishes speaking
│
├── STT: 210 ms
│
├── Agent starts: 35 ms
│
├── CRM API: 420 ms
│
├── LLM first token: 180 ms
│
└── TTS first audio: 140 ms
如果你的首音频延迟是 1.2 秒,但真正的瓶颈是 700 ms 的 CRM API,那么更换 LLM 可能无法解决问题。
语音智能体会立即暴露慢速后端系统。
Voice input
↓
Agent
↓
CRM
↓
Database
↓
Payment API
↓
Agent
↓
TTS
即使你的 LLM 非常快,由于下游服务的原因,对话也会感觉很慢。
可能的优化方向:
例如,如果智能体需要客户信息和预约可用性,这些查询可能并不总是需要按顺序进行。
但在使用并行执行时要小心,因为工具可能有副作用。
并行读取两个系统与同时创建两个预约是非常不同的。
语音智能体的失败方式与聊天机器人不同。
潜在失败包括:
智能体应该有明确的降级行为。
Tool timeout
↓
Retry if operation is safe
↓
Still failing?
↓
Tell the user
↓
Offer alternative action
永远不要让模型通过假装成功来隐藏失败的事务。
对于支付、预订、取消或账户更改等操作,系统应在确认完成之前验证实际的后端结果。
LangChain 适用于:
但 LangChain 不是你完整的语音基础设施。
你仍然需要解决:
把 LangChain 看作是推理和编排层,而不是整个语音技术栈。
一个简单的语音助手可能只需要:
User → Agent → Tool → Response
业务工作流可能会变得更复杂:
Incoming call
↓
Identify customer
↓
Understand intent
↓
Check account
↓
Determine eligibility
↓
Call external system
↓
Human approval?
↙ ↘
Yes No
↓ ↓
Human Complete
review
这正是基于图的编排变得有价值的地方。
LangChain 当前的 create_agent 实现已经在底层使用了 LangGraph,而直接使用 LangGraph 工作流在需要更明确地控制状态、分支、持久化、中断或复杂工作流时很有用。
重要的一点是:
不要仅仅因为你在构建语音智能体就添加 LangGraph。只有当工作流实际需要图级编排时,才添加它。
一个实际的生产架构可能是这样的:
┌──────────────────┐
│ Web / Mobile │
│ / Phone Client │
└────────┬─────────┘
│
Audio Stream
│
▼
┌──────────────────┐
│ Audio Gateway │
│ WebSocket/WebRTC │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ STT │
└────────┬─────────┘
│
Transcript
│
▼
┌──────────────────┐
│ LangChain Agent │
│ │
│ State + Tools │
└───────┬──────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
CRM/API Database Calendar
│ │ │
└───────────┼───────────┘
│
▼
Agent Response
│
▼
┌──────────────────┐
│ TTS │
└────────┬─────────┘
│
▼
Audio Stream
│
▼
User
这个架构有一个重要特性:
每一层都可以独立演进。
你可以替换 STT 提供商而无需重建智能体。你可以替换 LLM 而无需重建音频网关。
你可以替换 CRM 而无需更改语音界面。这正是该架构适合生产环境的原因。
使用 LangChain 构建语音智能体主要不是关于编写 LLM 提示词。
围绕 LLM 的困难工程工作包括:
LangChain 为你提供了强大的智能体和工具编排层,而语音基础设施处理实时 UI 接口。它当前的文档通过流式 STT → LangChain 智能体 → TTS 架构演示了这种分离。
如果你计划将这个架构超越原型,构建具有自定义工作流、后端集成、多语言支持、监控和低延迟交互的生产级语音系统,可以探索 Ciphernutz 的 AI Voice Agent Development 服务。
目标不是让 LLM 说话。目标是让业务工作流变得会话化,而不使其不可靠。