400 lines
16 KiB
Markdown
400 lines
16 KiB
Markdown
# BigWo 智能语音对话系统 — 系统架构文档
|
||
|
||
> 版本:2.0 | 更新日期:2026-03-13
|
||
|
||
---
|
||
|
||
## 1. 系统概述
|
||
|
||
BigWo 是一个**企业级智能客服对话系统**,支持**语音通话**和**文字对话**两种交互模式,可无缝切换且保持上下文连续。
|
||
|
||
### 核心能力
|
||
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 实时语音对话 | Native WebSocket + S2S 端到端语音大模型,混合编排模式 |
|
||
| 知识库问答 | Function Calling → 方舟私域知识库 → 本地知识库 |
|
||
| 文字对话 | Coze v3 Chat API,支持 SSE 流式输出 |
|
||
| 语音↔文字切换 | 同一 sessionId 贯穿,MySQL 持久化完整历史 |
|
||
| 工具调用 | 知识库检索、天气、订单、时间、计算 |
|
||
|
||
### 技术栈
|
||
|
||
- **前端**:React 18 + Vite 5 + TailwindCSS 4 + Lucide Icons
|
||
- **后端**:Node.js + Express 4 (port 3012)
|
||
- **语音**:Native WebSocket (`wss://openspeech.bytedance.com/api/v3/realtime/dialogue`) + S2S 端到端 + 方舟 LLM
|
||
- **文字**:Coze v3 Chat API(流式 SSE)
|
||
- **知识库**:方舟 Chat Completions API + knowledge_base metadata
|
||
- **数据库**:MySQL 8 (mysql2/promise)
|
||
- **部署**:PM2 (cluster) + Nginx 反向代理 + 宝塔面板
|
||
|
||
---
|
||
|
||
## 2. 系统架构图
|
||
|
||
```
|
||
┌───────────────────────────────────────────────────────────┐
|
||
│ 浏览器客户端 │
|
||
│ ┌────────────┐ ┌───────────┐ ┌────────────────────┐ │
|
||
│ │ VoicePanel │ │ ChatPanel │ │SessionHistoryPanel │ │
|
||
│ └─────┬──────┘ └─────┬─────┘ └────────────────────┘ │
|
||
│ │ │ │
|
||
│ ┌─────▼──────────┐ ┌──▼───────┐ ┌────────────────┐ │
|
||
│ │useNativeVoice │ │ chatApi │ │ voiceApi │ │
|
||
│ │ Chat (Hook) │ │(HTTP/SSE)│ │ (HTTP 封装) │ │
|
||
│ └─────┬──────────┘ └──┬───────┘ └────────────────┘ │
|
||
│ │ │ │
|
||
│ ┌─────▼──────────────┐ │ │
|
||
│ │nativeVoiceService │ │ │
|
||
│ │ (WebSocket+Audio) │ │ │
|
||
│ └─────┬──────────────┘ │ │
|
||
└────────┼────────────────┼─────────────────────────────────┘
|
||
│ WebSocket │ HTTPS
|
||
│ PCM 音频流 │ REST/SSE
|
||
▼ ▼
|
||
┌──────────────────────────────────────────────────┐
|
||
│ Express 后端 (port 3001) │
|
||
│ │
|
||
│ /ws/realtime-dialog — Native 语音网关 (核心) │
|
||
│ routes/voice.js — 语音配置、直连会话 │
|
||
│ routes/chat.js — 文字对话 (Coze SSE) │
|
||
│ routes/session.js — 会话列表、历史、删除 │
|
||
│ │
|
||
│ services/nativeVoiceGateway.js — WebSocket 网关 │
|
||
│ services/realtimeDialogProtocol.js — 二进制协议 │
|
||
│ services/realtimeDialogRouting.js — 意图路由 │
|
||
│ services/toolExecutor.js — 工具执行器 │
|
||
│ services/arkChatService.js — 方舟 LLM │
|
||
│ services/cozeChatService.js — Coze Chat │
|
||
│ db/index.js — MySQL CRUD │
|
||
│ │
|
||
└──────┬───────────────┬────────────────────────────┘
|
||
│ │
|
||
│ WebSocket │
|
||
▼ ▼
|
||
┌───────────────┐ ┌─────────────────┐ ┌──────────────┐
|
||
│ 火山 Realtime │ │ MySQL 8 │ │ 方舟知识库 │
|
||
│ Dialog 服务 │ │ sessions 表 │ │ (远程 API) │
|
||
│ (S2S + LLM) │ │ messages 表 │ └──────────────┘
|
||
└───────────────┘ └─────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 目录结构
|
||
|
||
```
|
||
test2/
|
||
├── client/ # 前端(React + Vite)
|
||
│ ├── src/
|
||
│ │ ├── App.jsx # 主应用,模式切换 + 会话管理
|
||
│ │ ├── components/
|
||
│ │ │ ├── VoicePanel.jsx # 语音通话界面
|
||
│ │ │ ├── ChatPanel.jsx # 文字对话界面(SSE 流式)
|
||
│ │ │ ├── SessionHistoryPanel.jsx # 会话历史侧边栏
|
||
│ │ │ ├── SettingsPanel.jsx # 语音参数设置面板
|
||
│ │ │ └── SubtitleDisplay.jsx# 实时字幕展示
|
||
│ │ ├── hooks/
|
||
│ │ │ └── useNativeVoiceChat.js # Native WebSocket 语音 Hook
|
||
│ │ └── services/
|
||
│ │ ├── nativeVoiceService.js # WebSocket 语音服务(音频采集/播放)
|
||
│ │ ├── voiceApi.js # 语音/会话 HTTP 请求
|
||
│ │ └── chatApi.js # 文字 HTTP/SSE 请求
|
||
│ └── vite.config.js
|
||
├── server/ # 后端(Express)
|
||
│ ├── app.js # 入口,启动 HTTP + WebSocket 服务
|
||
│ ├── routes/
|
||
│ │ ├── voice.js # 语音配置、直连会话、知识库查询
|
||
│ │ ├── chat.js # 文字对话(Coze SSE 流式)
|
||
│ │ └── session.js # 会话列表、历史、删除、模式切换
|
||
│ ├── services/
|
||
│ │ ├── nativeVoiceGateway.js # WebSocket 语音网关(核心)
|
||
│ │ ├── realtimeDialogProtocol.js # 二进制协议编解码
|
||
│ │ ├── realtimeDialogRouting.js # 意图路由 + 工具调度
|
||
│ │ ├── toolExecutor.js # 工具执行器
|
||
│ │ ├── arkChatService.js # 方舟 LLM
|
||
│ │ └── cozeChatService.js # Coze Chat API(文字主服务)
|
||
│ ├── db/index.js # MySQL CRUD
|
||
│ └── .env # 环境变量
|
||
└── ecosystem.config.js # PM2 部署配置
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 语音通话模块(Native WebSocket 方案)
|
||
|
||
### 4.1 混合编排模式
|
||
|
||
S2S 端到端模型处理普通闲聊(低延迟),方舟 LLM 同时决策是否需要调用工具。两者并行运行。
|
||
|
||
### 4.2 会话生命周期
|
||
|
||
```
|
||
客户端 WebSocket 连接 → /ws/realtime-dialog
|
||
↓
|
||
nativeVoiceGateway 创建会话 → 连接上游 Realtime Dialog 服务
|
||
↓
|
||
客户端采集麦克风 PCM → 发送音频帧 → 上游 ASR + S2S
|
||
↓
|
||
上游返回字幕/音频 → realtimeDialogRouting 意图路由
|
||
↓
|
||
工具调用或闲聊回复 → ChatTTSText 注入语音流 → 客户端播放
|
||
↓
|
||
客户端断开 WebSocket → 会话结束 → 可切换文字模式
|
||
```
|
||
|
||
### 4.3 语音相关端点
|
||
|
||
| 端点 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `/ws/realtime-dialog` | WebSocket | **核心**,Native 语音网关 |
|
||
| `/api/voice/config` | GET | 获取模型、音色列表 |
|
||
| `/api/voice/direct/session` | POST | 创建直连会话 |
|
||
| `/api/voice/direct/message` | POST | 添加消息 |
|
||
| `/api/voice/direct/query` | POST | 知识库直接查询 |
|
||
| `/api/voice/stop` | POST | 停止会话 |
|
||
|
||
### 4.4 核心服务文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `nativeVoiceGateway.js` | WebSocket 网关,管理客户端↔上游连接、音频流转发、消息持久化 |
|
||
| `realtimeDialogProtocol.js` | 二进制协议编解码(消息类型、标志位、序列化/反序列化) |
|
||
| `realtimeDialogRouting.js` | 意图路由(规则+LLM 双层决策)、工具调度、语音播报 |
|
||
|
||
---
|
||
|
||
## 5. 语音意图路由与工具调用
|
||
|
||
### 5.1 数据流
|
||
|
||
```
|
||
用户语音 ASR 识别文本
|
||
│ 上游 Realtime Dialog 服务返回
|
||
▼
|
||
nativeVoiceGateway 接收字幕 → 持久化用户语音到 DB
|
||
▼
|
||
realtimeDialogRouting.resolveReply()
|
||
│
|
||
├─ 规则路由:时间/天气/订单/计算 → 直接工具调用
|
||
├─ search_knowledge → 方舟知识库 API
|
||
└─ chat → 方舟 LLM 闲聊回复
|
||
│
|
||
▼
|
||
工具结果/LLM回复 → ChatTTSText 注入上游语音流
|
||
▼
|
||
AI 语音播报 + 持久化到 DB
|
||
```
|
||
|
||
### 5.2 关键设计
|
||
|
||
| 问题 | 解决方案 |
|
||
|------|----------|
|
||
| 意图识别 | 规则路由 + LLM 路由双层决策 |
|
||
| S2S 与工具冲突 | ChatTTSText 注入工具结果覆盖 S2S 直连回复 |
|
||
| 音频编解码 | realtimeDialogProtocol 自定义二进制协议 |
|
||
| 语音文本分段 | 按标点切分,估算播报时长,分段 TTS |
|
||
|
||
---
|
||
|
||
## 6. 文字对话模块
|
||
|
||
### 6.1 架构
|
||
|
||
通过 **Coze v3 Chat API** 实现,Coze Bot 内置知识库插件。
|
||
|
||
```
|
||
用户输入 → POST /api/chat/send-stream
|
||
↓
|
||
cozeChatService.chatStream()
|
||
│ 首次对话注入语音历史作为上下文
|
||
│ Coze 自动管理 conversation_id
|
||
↓
|
||
SSE 流式返回 → 前端逐字展示
|
||
```
|
||
|
||
### 6.2 文字 API 端点(chat.js)
|
||
|
||
| 端点 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/api/chat/start` | POST | 创建会话,注入语音历史上下文 |
|
||
| `/api/chat/send` | POST | 非流式发送 |
|
||
| `/api/chat/send-stream` | POST | SSE 流式发送 |
|
||
| `/api/chat/history/:id` | GET | 获取会话状态 |
|
||
| `/api/chat/:id` | DELETE | 删除会话 |
|
||
|
||
---
|
||
|
||
## 7. 会话管理与模式切换
|
||
|
||
### 7.1 统一 sessionId
|
||
|
||
同一个 sessionId 贯穿语音和文字模式,所有消息持久化到 MySQL messages 表。
|
||
|
||
### 7.2 消息来源标记
|
||
|
||
| source 值 | 说明 |
|
||
|-----------|------|
|
||
| `voice_asr` | 语音 ASR 识别的用户文本 |
|
||
| `voice_bot` | AI 语音回复字幕 |
|
||
| `voice_tool` | 语音场景工具调用结果 |
|
||
| `chat_user` | 文字对话用户输入 |
|
||
| `chat_bot` | 文字对话 AI 回复 |
|
||
|
||
### 7.3 会话管理 API(session.js)
|
||
|
||
| 端点 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/api/session/list` | GET | 获取会话列表(带最后消息预览) |
|
||
| `/api/session/:id/history` | GET | 获取完整历史(支持 llm/full 格式) |
|
||
| `/api/session/:id/switch` | POST | 切换模式,返回上下文历史 |
|
||
| `/api/session/:id` | DELETE | 删除会话及其消息 |
|
||
|
||
### 7.4 数据库表
|
||
|
||
**sessions**:`id(PK)`, `user_id`, `mode(voice/chat)`, `created_at`, `updated_at`
|
||
|
||
**messages**:`id(AI PK)`, `session_id`, `role(user/assistant/tool/system)`, `content`, `source`, `tool_name`, `created_at`
|
||
|
||
---
|
||
|
||
## 8. 客户端组件
|
||
|
||
### 8.1 组件树
|
||
|
||
```
|
||
App.jsx # 模式切换 + 全局设置 + 会话管理
|
||
├── VoicePanel.jsx # 语音通话 UI(开始/结束/静音/时长)
|
||
│ └── SubtitleDisplay # 实时字幕(definite/interim 区分)
|
||
├── ChatPanel.jsx # 文字对话 UI(消息列表 + SSE 流式显示)
|
||
├── SessionHistoryPanel.jsx # 会话历史侧边栏(新建/切换/删除会话)
|
||
└── SettingsPanel.jsx # 设置面板(模型/音色/系统角色/VAD)
|
||
```
|
||
|
||
### 8.2 useNativeVoiceChat Hook
|
||
|
||
管理 Native WebSocket 语音通话完整生命周期:
|
||
|
||
- **start(options)**:连接 WebSocket → 采集麦克风 PCM → 发送音频帧
|
||
- **stop()**:断开 WebSocket → 返回字幕和 sessionId
|
||
- **toggleMute()**:静音/取消静音
|
||
- **状态**:isActive, isMuted, isConnecting, subtitles, duration, error
|
||
|
||
### 8.3 nativeVoiceService.js
|
||
|
||
封装 Native WebSocket 语音连接:
|
||
|
||
- **connect(options)**:建立 WebSocket 连接,初始化音频采集(getUserMedia + Web Audio API 降采样)
|
||
- **disconnect()**:关闭连接、停止音频
|
||
- **setMuted(muted)**:控制麦克风
|
||
- **事件回调**:onSubtitle(字幕)、onConnectionStateChange(连接状态)、onError(错误)
|
||
- **音频播放**:接收 PCM 音频帧,通过 Web Audio API 播放
|
||
|
||
---
|
||
|
||
## 9. 环境变量
|
||
|
||
### 必需
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `VOLC_S2S_APP_ID` | S2S 端到端语音 AppID |
|
||
| `VOLC_S2S_TOKEN` | S2S Token |
|
||
| `VOLC_ARK_ENDPOINT_ID` | 方舟 LLM 推理接入点 ID |
|
||
|
||
### 可选
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `COZE_API_TOKEN` | Coze 智能体 Token(文字对话) |
|
||
| `COZE_BOT_ID` | Coze Bot ID |
|
||
| `VOLC_ARK_KNOWLEDGE_BASE_IDS` | 方舟私域知识库数据集 ID(逗号分隔) |
|
||
| `VOLC_ARK_API_KEY` | 方舟 API Key |
|
||
| `VOLC_WEBSEARCH_API_KEY` | 联网搜索 Key |
|
||
| `VOLC_S2S_SPEAKER_ID` | 自定义音色 ID |
|
||
| `ENABLE_NATIVE_VOICE_GATEWAY` | 语音网关开关(默认开启,设 false 关闭) |
|
||
| `MYSQL_HOST/PORT/USER/PASSWORD/DATABASE` | MySQL 配置 |
|
||
|
||
---
|
||
|
||
## 10. 部署架构
|
||
|
||
```
|
||
互联网用户
|
||
│
|
||
▼ HTTPS (443) + WSS
|
||
┌──────────────┐
|
||
│ Nginx │ ← 宝塔面板管理
|
||
│ (反向代理) │
|
||
│ SSL 终止 │
|
||
└──────┬───────┘
|
||
│ http://localhost:3001
|
||
▼
|
||
┌──────────────┐
|
||
│ PM2 │ ← ecosystem.config.js
|
||
│ bigwo-server│
|
||
│ (Node.js) │
|
||
└──────┬───────┘
|
||
│
|
||
├── MySQL 8 (localhost:3306)
|
||
├── 火山 Realtime Dialog (wss://openspeech.bytedance.com)
|
||
├── 方舟 LLM API (ark.cn-beijing.volces.com)
|
||
└── Coze API (api.coze.cn)
|
||
```
|
||
|
||
### PM2 配置
|
||
|
||
- 进程名:`bigwo-server`
|
||
- 工作目录:`/www/wwwroot/demo.tensorgrove.com.cn/server`
|
||
- 日志路径:`/var/log/bigwo/server-out.log`、`server-error.log`
|
||
- 内存限制:512M 自动重启
|
||
|
||
---
|
||
|
||
## 11. 工具定义(tools.js)
|
||
|
||
系统定义了 5 个 Function Calling 工具:
|
||
|
||
| 工具 | 参数 | 说明 |
|
||
|------|------|------|
|
||
| `search_knowledge` | query: string | **核心工具**,强制优先调用 |
|
||
| `query_weather` | city: string | 天气查询(Mock) |
|
||
| `query_order` | order_id: string | 订单查询(Mock) |
|
||
| `get_current_time` | 无 | 当前时间 |
|
||
| `calculate` | expression: string | 数学计算 |
|
||
|
||
### search_knowledge 查询链
|
||
|
||
```
|
||
方舟私域知识库 (30s 超时)
|
||
│ POST https://ark.cn-beijing.volces.com/api/v3/chat/completions
|
||
│ metadata.knowledge_base: { dataset_ids, top_k: 3, threshold: 0.5 }
|
||
│
|
||
│ 失败 ↓
|
||
▼
|
||
本地知识库 (即时,关键词匹配)
|
||
│ 覆盖:退货、退款、配送、保修、会员
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 安全与限制
|
||
|
||
- **API 签名**:所有火山引擎 API 调用使用 AK/SK HMAC 签名
|
||
- **FC 回调签名**:ServerSignature 校验(当前信任模式)
|
||
- **计算工具防注入**:仅允许 `0-9 + - * / ( ) . %` 字符
|
||
- **CORS**:已开启(`cors()` 中间件)
|
||
- **Body 限制**:1MB
|
||
- **会话过期**:文字对话 30 分钟自动清理
|
||
- **环境变量**:敏感信息存于 `.env`,启动时校验
|
||
|
||
---
|
||
|
||
## 13. 已知问题与优化方向
|
||
|
||
1. **天气和订单工具为 Mock**:queryWeather 和 queryOrder 使用硬编码数据,可接入真实 API
|
||
2. **本地知识库简陋**:searchLocalKnowledge 仅 5 条硬编码记录,需接入真实知识库
|
||
3. **方舟 LLM Mock 模式**:未配置 VOLC_ARK_ENDPOINT_ID 时返回硬编码回复
|
||
4. **文字对话依赖 Coze**:Coze 未配置时文字对话模式不可用,可考虑 fallback 到 arkChatService
|
||
5. **知识库冷启动**:方舟 KB 首次查询较慢(~10s),后续查询 ~3-5s
|