site logo

Marico's space

如何用 LangChain 构建语音智能体

AI技术与应用 2026-08-19 22:59:42 7

最近折腾了一套基于 LangChain 的语音智能体,踩了几个坑,这篇把问题说清楚。

构建语音智能体不是简单地把语音转文字、再接个大模型、最后转回语音就完事了。

真正的难题是:怎么让 AI 系统听得懂、推理得出、调用工具、记住上下文、还得响应够快,让对话保持自然感?

LangChain 能处理智能体和工具编排层,但实时体验很大程度上取决于它周围的东西。一个实用的架构大概长这样:

User microphone ↓
Audio streaming ↓
Speech-to-Text (STT) ↓
Transcript / turn detection ↓
LangChain Agent ↓
Tools / APIs / Business Logic ↓
Streaming response ↓
Text-to-Speech (TTS) ↓
User hears response

LangChain 官方文档把这叫做"三明治"架构:STT → 智能体 → TTS。好处是每层都可以独立替换,同时智能体能继续使用 LangChain 整个生态体系。

你真正需要构建什么

写代码之前,先把语音智能体拆成五个职责:

  1. 音频传输 — 把麦克风音频推到后端,再把音频响应拉回客户端。
  2. 语音识别 — 把音频转成文字。
  3. 智能体推理 — 决定用户想要什么,该采取什么行动。
  4. 工具执行 — 与数据库、CRM、日历、API 或内部系统交互。
  5. 语音合成 — 把响应转回音频。

这种拆分很重要,因为这些组件的性能特征完全不同。比如换 TTS 提供商不应该需要重写业务逻辑,同样换大模型也不应该需要重建音频传输层。这种模块化是用级联架构而不是把所有东西塞进一个模型的主要原因。

1. 先选语音架构

构建语音智能体有两种主要方式。

架构 A:STT → 智能体 → TTS

Audio ↓
STT ↓
Text ↓
LangChain Agent ↓
Text ↓
TTS ↓
Audio

这种方式让你能控制每个组件。可以选一个 STT 提供商、另一个大模型、完全不同的 TTS 提供商。调试也更方便,因为可以独立检查转录文本、智能体决策、工具调用和最终响应。代价是额外的基础设施和潜在的延迟。

架构 B:端到端语音模型

Audio ↓
Multimodal Voice Model ↓
Audio

这种方式可以减少移动部件数量,能保留更多关于说话方式的信息,比如语气。但会降低对各组件的控制力,引入提供商特定的约束。对于工具执行、可观测性、提供商灵活性、和确定性工作流很重要的业务场景,级联架构仍然非常实用。

2. 用流式处理而不是等完整响应

这是很多语音智能体实现出问题的地方。naive 的实现会等待整个链路完成:

Record entire sentence ↓
Transcribe ↓
Wait for complete LLM response ↓
Generate complete audio ↓
Play response

用户会经历一段很长的等待。流式架构应该是这样:

Audio chunk ↓
STT starts immediately ↓
Transcript arrives ↓
Agent starts generating ↓
First response tokens arrive ↓
TTS starts ↓
Audio starts playing

系统不会等每个阶段都完成才开始下一阶段。LangChain 官方示例用异步流式处理和 RunnableGenerator 来连接 STT、智能体和 TTS,文档提到配合合适的 STT 和 TTS 提供商,这个管道可以实现 700 毫秒以下的延迟。重要的一课是:实时语音主要是个管道设计问题,不只是模型选择问题。

3. 创建 LangChain 智能体

语音转换成文字之后,语音层就可以把请求交给普通的 LangChain 智能体处理。当前 LangChain 应用用 create_agent 作为主要入口。一个最简智能体大概长这样:

from langchain.agents import create_agent def check_order_status(order_id: str) -> str: """Return the current status of an order.""" return f"Order {order_id} is currently being processed." agent = create_agent( model="openai:gpt-5.4", tools=[check_order_status], system_prompt=""" You are a customer support voice agent. Keep spoken responses short. Ask for missing information instead of guessing. Use tools whenever the user asks for account-specific information. """
)

重要的不是这五行代码,而是工具边界。语音智能体不应该通过模型生成的任意文本来直接操作数据库或业务系统。正确的做法是:

User:
"Where is order 4821?" ↓ Agent ↓ check_order_status("4821") ↓ Business system ↓ Structured result ↓ Agent ↓ "Your order is currently being processed."

LangChain 智能体可以推理可用工具并作为智能体循环的一部分执行它们。当前的智能体实现基于 LangGraph 的运行时。

4. 为语音设计工具,而不是聊天

这是语音智能体工程中被忽视的部分。适合文本聊天机器人的工具可能对语音智能体设计得很差。比如不要给智能体返回这样的工具:

{"customer_id": 1827, "subscription_status": "active", "plan": "enterprise", "billing_cycle": "annual", "last_payment": "...", "payment_method": "..."}

如果用户只是问:"我的订阅还生效吗?"应该让工具返回智能体能快速推理的信息:

def get_subscription_status(customer_id: str) -> str: """Check whether a customer's subscription is active.""" ...

语音智能体就可以回复:"是的,您的订阅处于生效状态。"规则很简单:围绕决策设计工具,而不是围绕数据库表。这减少了不必要的推理,让口语响应更容易控制。

5. 让语音响应保持简短

针对书面聊天优化的大模型会生成段落。语音智能体不应该这样。

对比一下:

聊天机器人响应:

"当然,我可以帮您处理。根据您账户中可用的信息,您的订单已成功处理,目前正在运输中。预计将在接下来的两到三个工作日内送达..."

语音响应:

"您的订单已在运输中,预计两到三个工作日内送达。"

语音需要不同的响应策略。一个有用的系统指令是:

You are a voice assistant. Speak naturally and concisely. Prefer one or two sentences per response.
Do not read JSON, URLs, IDs, tables, or long lists aloud. Ask one question at a time.
If a tool fails, explain the problem briefly and offer the next action. Never invent information that is unavailable from a tool.

这不只是提示词优化,而是界面设计

6. 谨慎添加对话记忆

如果智能体忘记五秒钟前说的话,对话会变得很尴尬。比如:

用户:"我想预约明天的 appointments。"
智能体:"什么时间?"
用户:"大概4点。"

要确保智能体理解"4"指的是预约时间。LangChain 语音智能体示例用检查点和唯一线程 ID 来维护对话状态,这样智能体可以在多轮对话中保留上下文。概念上:

User ↓
Voice session ID ↓
Conversation state ↓
LangChain agent ↓
Response

对于生产系统,要区分:

短期对话状态

当前通话中说过的事。比如用户名、预约时间、当前订单号、已选产品。

长期业务记忆

应该跨通话存在的信息。比如客户偏好、之前的交互记录、账户信息。

不要把所有客户数据都塞进大模型的对话历史里,按需检索当前决策需要的内容。

7. 处理打断

这是聊天机器人和语音智能体之间最大的区别之一。想象智能体正在说:

"您的预约安排在周四..."

用户打断说:

"改成周五吧。"

真正的语音界面应该停止说话。这就意味着系统需要支持打断介入。简化流程是:

Agent speaking ↓
User starts talking ↓
Detect interruption ↓
Stop TTS playback ↓
Cancel/ignore remaining audio ↓
Process new user input

没有打断处理,系统感觉不像对话,更像是在念脚本。这也是为什么音频传输、轮次检测和取消逻辑和大模型一样重要。

8. 用 WebSocket 做浏览器端流式处理

对于浏览器端实现,WebSocket 是实用的传输层。客户端捕获麦克风音频:

Browser microphone ↓
PCM audio chunks ↓
WebSocket ↓
Backend

后端通过同一连接把合成的音频推回来:

Backend ↓
TTS audio chunks ↓
WebSocket ↓
Browser ↓
Speaker

LangChain 参考语音应用用 WebSocket 做双向音频流,并指出同一套架构可以适配到电话或 WebRTC。重要的设计决策是让传输层和智能体保持独立。智能体不应该关心请求来自哪里——浏览器、移动应用、电话还是 WebRTC 客户端。它应该接收输入事件并返回智能体事件。

9. 用异步管道连接各部分

简化的 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

这些测量数据告诉你真正的瓶颈在哪里。

10. 测量正确的延迟指标

不要只测量总的 API 响应时间。对于语音系统,至少要追踪:

首次转录时间

系统多快理解用户说的话?

首次 token 时间

智能体多快开始响应?

首次音频时间

用户多快听到响应?

总响应时长

智能体说完话要多久?

工具延迟

外部 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 毫秒的 CRM API。

11. 让外部工具够快

语音智能体会立刻暴露慢的后端系统。想象:

Voice input ↓
Agent ↓
CRM ↓
Database ↓
Payment API ↓
Agent ↓
TTS

即使大模型再快,级联的下游服务也会让对话感觉很慢。应该用:超时、重试(安全的情况下)、缓存、并行 API 请求(可能的话)、轻量级工具响应、异步执行。比如智能体需要客户信息和预约时间,这些查询不一定需要按顺序执行。但要注意有副作用的工具并行执行——并行读两个系统和同时创建两个预约完全不同。

12. 上线前添加失败处理

语音智能体的失败方式和聊天机器人不同。潜在的失败包括:STT 漏词、用户和智能体同时说话、网络断开、TTS 失败、工具超时、大模型生成无效的工具参数、用户中途改变请求、外部 API 返回不完整数据。智能体应该有明确的降级行为。比如:

Tool timeout ↓
Retry if operation is safe ↓
Still failing? ↓
Tell the user ↓
Offer alternative action

不要让模型假装成功了来掩盖失败的交易。对于支付、预约、取消、账户变更这类操作,系统应该在确认完成前验证实际的 backend 结果。

13. LangChain 的用武之地和力所不能及

LangChain 适合:智能体编排、工具调用、模型抽象、对话状态、流式智能体输出、集成业务工具、连接基于 LangGraph 的工作流。但 LangChain 不是完整的语音基础设施。你仍然需要解决:麦克风采集、音频编码、WebSocket/WebRTC、语音识别、语音合成、打断处理、延迟管理、电话集成(如果适用的话)、生产监控。把 LangChain 看成推理和编排层,而不是整个语音技术栈。

14. 什么时候 LangGraph 变得重要

一个简单语音助手可能只需要:

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,只有在工作流确实需要时才添加图级别的编排。

15. 生产级语音智能体架构

一个实用的生产架构大概长这样:

 ┌──────────────────┐ │ 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 提供商而不重建智能体,可以换大模型而不重建音频网关,可以换 CRM 而不改变语音界面。这就是让架构适合生产的原因。

总结

用 LangChain 构建语音智能体主要不是写个大模型提示词。困难的工程工作在大模型周围:流式音频、减少首次音频时间、管理对话状态、设计语音专用工具、处理打断、控制外部 API 延迟、验证副作用、从失败中恢复、监控完整对话。LangChain 给你一个强大的智能体和工具编排层,语音基础设施处理实时 UI 界面。其当前文档通过流式 STT → LangChain 智能体 → TTS 架构展示了这种分离。

目标不是让大模型开口说话,而是让业务工作流变得可以对话,同时不降低可靠性。