从语音到答案:实时语音客服机器人技术实践

从语音到答案:实时语音客服机器人技术实践

面向技术博客发布的项目梳理稿。本文按业务逻辑与核心能力分节,说明「为什么这么做」与「关键怎么跑通」。


一、项目定位:语音客服为什么难

文本客服可以接受秒级延迟;语音场景则要求:

  • 低首包延迟:用户说完后尽快听到回应
  • 可打断(Barge-in):播报中途插话,旧答案必须立刻停掉
  • 答案可信:政策、计费、作业等问题必须基于内部客服 Wiki,不能靠模型「编」

本项目 voice-robot 的定位是:客服场景的实时语音/文本对话助手。

一句话链路:

text 复制代码
浏览器采集语音 → WebSocket 编排 → 腾讯 ASR → DeepAgent(强制 Wiki 工具)→ 火山 TTS 播报

它不是物理机器人控制,也不是端到端 Speech-to-Speech 单模型,而是一条可控、可观测、可审计的 ASR → LLM → TTS 级联流水线。

产品侧目标(摘自 PRD):

指标 目标
端到端首包 P50 ≤ 900ms / P95 ≤ 1500ms
打断生效 P95 ≤ 300ms
同轮重复提交 < 0.1%

二、总体架构:前端采集 + 后端编排

2.1 技术栈

层级 选型
前端 React 18、TypeScript、Vite、Web Audio API、端侧 VAD
后端 FastAPI、Uvicorn、Pydantic Settings
Agent LangGraph / DeepAgents、langchain-openai
ASR 腾讯实时语音识别
LLM 火山方舟 Ark(OpenAI 兼容接口)
TTS 火山引擎 TTS v3 双向 WebSocket
知识库 Markdown Wiki + jieba 关键词检索
可观测 Prometheus、可选 LangSmith、审计流水(默认 SQLite)

2.2 模块关系

text 复制代码
┌─ frontend/ ─────────────────────────────────────────────┐
│  VoicePage · audioCapture(VAD) · TypewriterText · Ops   │
└──────────────────────┬──────────────────────────────────┘
                       │  /ws/voice
┌──────────────────────▼──────────────────────────────────┐
│  FastAPI:voice_endpoint → Orchestrator                 │
│    ├─ TencentAsrClient          (语音转写)              │
│    ├─ DeepAgent + query_kefu_wiki(推理 + 知识检索)     │
│    ├─ PunctuationBuffer → TTS   (标点切句播报)         │
│    └─ TurnManager / Audit       (幂等轮次 + 审计)      │
└─────────────────────────────────────────────────────────┘

业务上,Orchestrator 是唯一编排中枢:ASR 结果、轮次提交、LLM 流、TTS 切段、打断取消,都汇聚于此,避免「前端直接调 LLM / TTS」带来的状态分裂。


三、核心业务链路:一轮对话怎么走完

3.1 建连与开场白

  1. 前端连接 ws://host:8000/ws/voice
  2. 发送 session_init
  3. 后端流式下发 greeting_delta → greeting_complete(可选 TTS)
  4. 开场白不经 LLM ;同会话首轮推理时,再把开场白注入为历史 AIMessage

设计意图:开场白固定、可控、零推理成本;同时保证多轮上下文语义连贯。

3.2 语音一轮(Happy Path)

text 复制代码
用户开口
  → 前端 VAD speech_start → vad_event
  → 后端预建腾讯 ASR(规避 15s 空闲超时)
  → audio_chunk(PCM s16le / 16k / 单声道)
  → ASR → asr_partial / asr_final(字幕)

用户停说
  → VAD speech_end → 关闭 ASR
  → turn_commit_request(input_mode=voice)
  → TurnManager 幂等 commit → turn_committed(generation_id)
  → Orchestrator.run_turn:
       链接增强(OCR / 网页正文)
       → DeepAgent 流式(可调 Wiki 工具)
       → llm_delta(打字机)
       → 标点切段 → TTS → tts_chunk
       → audio_complete

3.3 文本旁路

同一套 turn_commit_request,input_mode=text 时跳过 ASR,适合调试与无麦场景。

3.4 打断(Barge-in)

  1. 用户插话或点取消 → 前端停播 + cancel(generation_id)
  2. TurnManager 清空当前 generation
  3. Orchestrator 轮询 is_generation_active,停止继续推 LLM/TTS
  4. 仅把已产出的 partial 文本写回 thread,避免「未播完长文」污染多轮上下文

状态机可概括为:

text 复制代码
listening → thinking → speaking
              ↘ interrupted → listening

同一 turn_id 只允许一次成功 commit,从协议层杜绝双触发 LLM。


四、核心功能点拆解

4.1 端侧采集与 VAD

  • getUserMedia 开启回声消除 / 噪声抑制 / 自动增益
  • Float32 → 16k Int16 → base64 分片上行(约 100~200ms)
  • Analyser 能量阈值产出 speech_start / speech_end

关键文件:frontend/src/audio/audioCapture.ts

4.2 WebSocket 协议与幂等轮次

上下行事件统一携带 session_id / turn_id / seq / trace;上行用 Pydantic 校验。

方向 关键事件 作用
上行 session_init 触发开场白
上行 vad_event / audio_chunk 语音起停与 PCM
上行 turn_commit_request 提交本轮用户文本
上行 cancel 按 generation_id 打断
下行 asr_partial / asr_final 实时字幕
下行 turn_committed / turn_rejected 提交结果
下行 llm_delta 助手增量文本
下行 tts_chunk / audio_complete 播报与结束

权威协议:docs/protocol.md

幂等实现:backend/app/services/turn_manager.py((session_id, turn_id) 只 commit 一次)

4.3 实时 ASR 与预建连

腾讯实时 ASR 有「约 15 秒未发音频则超时」的约束。实践做法是:

  • 收到 speech_start 立刻建连
  • 再边收 audio_chunk 边 append_audio
  • speech_end 后关闭连接并汇总 final

关键文件:backend/app/services/asr/tencent_ws_client.py

4.4 DeepAgent 流式推理

  • 火山方舟 ChatOpenAI,streaming=True
  • LangGraph stream_mode=messages 逐 token 推送
  • 系统提示词约束:政策/计费/API/作业等问题必须先调 query_kefu_wiki;禁止口头提「知识库」;答复控制在约 100 token 内,利于 TTS

关键文件:backend/app/services/agents/deepagent_runner.py

4.5 客服 Wiki RAG(防幻觉核心)

知识库形态对齐「分类 / 概念 / FAQ」Markdown Wiki:

text 复制代码
backend/kefu-know/wiki/
  index.md
  categories/   # 主题页
  concepts/     # 概念页
  faqs/         # 标准问答

检索主入口 retrieve_kefu_wiki 的策略:

  1. jieba 抽关键词(停用词 + 用户词典)
  2. 优先匹配 index.md 路由到分类/概念;命中则不回退全库扫描
  3. 未命中再全量扫 categories/、concepts/
  4. 链接递归扩展(wikilink,深度约 2)补齐关联页与 FAQ
  5. 统一置信度排序(标题权重大于正文;分类/概念高于 FAQ)
  6. 可选 LLM 兜底:规则无结果时,让模型读 index 选页
python 复制代码
from pathlib import Path

from app.services.wiki_query import retrieve_kefu_wiki

result = retrieve_kefu_wiki(
    question="账号被限流怎么办",
    wiki_root=Path("backend/kefu-know/wiki"),
)
print(result.keywords)
print(result.retrieval_notes)  # 如 index_match / global_scan / index_llm_select
print(result.to_prompt_text())  # 供 Agent 合成答复的上下文

关键文件:backend/app/services/wiki_query.py、wiki_query_tool.py

4.6 用户消息链接增强

用户文本里若含 URL:

  • 图片:视觉 OCR / RapidOCR 兜底
  • 网页:抽取正文再拼入本轮上下文

关键文件:backend/app/services/user_content_enricher.py

4.7 标点切句 + 流式 TTS

LLM token 边出边进 PunctuationStreamBuffer:遇到句读或超长强制切句,再送火山 TTS v3 双向 WebSocket。这样播报可与打字机并行,缩短「听到第一句」的等待。

关键文件:text_punctuation_buffer.py、tts/volcano_ws_client.py

4.8 前端体验

  • ASR 字幕实时刷新
  • llm_delta / greeting_delta 驱动 TypewriterText
  • 运维页对接 Admin API(摘要、审计、导出)

4.9 Mock → Live 工程化

VOICE_ROBOT_MOCK_STREAMING_ENABLED=true 时可本地跑通全链路,不调外网。联调时再填腾讯 ASR / 火山 TTS / Ark 凭证。/readyz 会在 live 缺密钥时返回 503,避免「假健康」。


五、业务逻辑亮点

5.1 为什么不用端到端语音模型

客服场景强依赖可审计的知识来源 与可打断的中间态。级联架构虽然多一跳,但:

  • ASR / LLM / TTS 可独立替换与限流
  • Wiki 工具调用可强制、可日志
  • 打断粒度为 generation_id,不会误杀新一轮

5.2 双端点判停,但只允许服务端 commit

前端 VAD + 腾讯 ASR VAD 共同感知「说完了」,但 LLM 触发必须由服务端 commit_turn_once 完成。这是把「感知」和「决策」拆开,避免双端各跑一次推理。

5.3 意图不靠独立 NLU

没有单独意图分类器。意图由 DeepAgent + 系统提示词 + 强制 Wiki 工具完成:能答的题先检索,答不了的题也不编造事实。工具侧允许轻度补全指代以便检索,但禁止杜撰政策条款。

5.4 打断后的历史修补

取消时用「提交前历史 + HumanMessage + 已播 partial AIMessage」覆盖 checkpoint。否则用户打断后,未播完的长回答仍会留在多轮记忆里,下一轮会「答非所问」。


六、HTTP 运维面(旁路能力)

接口 说明
GET /healthz 存活探活
GET /readyz 凭证就绪检查
GET /metrics Prometheus
GET /admin/ops/summary 运维摘要(需 Admin Key)
GET /admin/audit/... 会话/轮次查询与 CSV 导出

主业务仍在 WebSocket;HTTP 负责健康检查与审计运营。


七、配置与运行方式(读者可复现)

环境:Python ≥ 3.11,Node ≥ 18。变量前缀多为 VOICE_ROBOT_。

bash 复制代码
# 后端
cd backend
cp .env.example .env
pip install -e ".[dev]"
uvicorn app.main:app --host 127.0.0.1 --port 8000

# 前端
cd frontend
npm install
npm run dev

常见踩坑(适合博客「实践笔记」小节):

  1. ASR 15 秒超时 → 必须在 speech_start 预建连
  2. 打字机一次蹦整段 → 查 LLM streaming、stream_mode=messages 与前端 Typewriter
  3. 总是返回 mock 占位文案 → 检查 MOCK 开关与 Ark Key / 模型配置

八、总结:可复制的设计取舍

本项目把「实时语音客服」拆成四条可独立演进的能力:

  1. 协议层:幂等 turn + generation 级打断
  2. 感知层:端侧 VAD + ASR 预建连
  3. 认知层:DeepAgent + 强制 Wiki RAG,拒绝幻觉
  4. 表达层:标点切句 TTS + 前端打字机,缩短感知延迟

若只记三点:服务端统一编排、知识库强制检索、打断可恢复上下文。这三点决定了它能上线做客服,而不是 demo 聊天机器人。

项目地址

相关推荐
深蓝AI2 小时前
旗舰被小弟反超:Claude Sonnet 5.5 智能体编码凭什么压过 Opus 5.5
agent·ai编程
Ticnix2 小时前
MCP 上个月把自己推翻重写了:Session 没了、Sampling 废了——你学的教程还停在 2025
python·agent·全栈
咬代码的兽2 小时前
OpenAI DevDay 今晚开场:常驻助手"o"曝光,500 美元一个月的 AI 员工你会买吗
agent
DigitalOcean3 小时前
AI Agent 时代的云:计算、推理和数据必须重新整合
agent
小爷毛毛(卓寿杰)3 小时前
【Agent 意图识别】输出协议、评估与置信度
人工智能·算法·大模型·prompt·大语言模型·agent
Ticnix4 小时前
你的 Agent 聊到第 20 轮就"失忆"?你管理的是历史,高手管理的是上下文
后端·python·agent
云上先途5 小时前
对话智能体和普通聊天机器人有什么区别?能不能对接企业自有知识库?
大数据·人工智能·机器人
李福春5 小时前
markdown表格标题渲染判定B
agent·架构师同盟·腾讯云架构师同盟
zhangrelay5 小时前
ROS2 Lyrical实验5导航Nav2
linux·笔记·学习·ubuntu·机器人