Files
bigwo/test2/ARCHITECTURE.md

400 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 会话管理 APIsession.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