Files
bigwo/test2/ARCHITECTURE.md
2026-03-12 12:47:56 +08:00

17 KiB
Raw Blame History

BigWo 智能语音对话系统 — 系统架构文档

版本1.0 | 更新日期2026-03-09


1. 系统概述

BigWo 是一个企业级智能客服对话系统,支持语音通话文字对话两种交互模式,可无缝切换且保持上下文连续。

核心能力

能力 说明
实时语音对话 火山引擎 RTC + S2S 端到端语音大模型,混合编排模式
知识库问答 Function Calling → 方舟私域知识库 → 本地知识库
文字对话 Coze v3 Chat API支持 SSE 流式输出
语音↔文字切换 同一 sessionId 贯穿MySQL 持久化完整历史
工具调用 知识库检索、天气、订单、时间、计算

技术栈

  • 前端React 18 + Vite 5 + TailwindCSS 4 + Lucide Icons
  • 后端Node.js + Express 4 (port 3012)
  • 语音@volcengine/rtc SDK + S2S 端到端 + 方舟 LLM (API v2024-12-01)
  • 文字Coze v3 Chat API流式 SSE
  • 知识库:方舟 Chat Completions API + knowledge_base metadata
  • 数据库MySQL 8 (mysql2/promise)
  • 部署PM2 (cluster) + Nginx 反向代理 + 宝塔面板

2. 系统架构图

┌─────────────────────────────────────────────────────────┐
│                      浏览器客户端                         │
│  ┌────────────┐  ┌───────────┐  ┌──────────────────┐   │
│  │ VoicePanel │  │ ChatPanel │  │  SettingsPanel   │   │
│  └─────┬──────┘  └─────┬─────┘  └──────────────────┘   │
│        │               │                                │
│  ┌─────▼──────┐  ┌─────▼─────┐  ┌────────────────┐    │
│  │useVoiceChat│  │  chatApi  │  │   voiceApi     │    │
│  │  (Hook)    │  │ (HTTP/SSE)│  │  (HTTP 封装)   │    │
│  └─────┬──────┘  └─────┬─────┘  └────────────────┘    │
│        │               │                                │
│  ┌─────▼──────┐        │                                │
│  │ rtcService │        │                                │
│  │(WebRTC SDK)│        │                                │
│  └─────┬──────┘        │                                │
└────────┼───────────────┼────────────────────────────────┘
         │ WebRTC        │ HTTPS
         │ 音频流         │ REST/SSE
         ▼               ▼
┌────────────────┐  ┌─────────────────────────────────────┐
│ 火山引擎 RTC   │  │       Express 后端 (port 3012)       │
│ 云端服务       │  │                                     │
│ ┌────────────┐ │  │  routes/voice.js  — 语音全生命周期   │
│ │S2S 端到端  │ │  │  routes/chat.js   — 文字对话        │
│ │语音大模型  │ │  │  routes/session.js — 会话管理        │
│ ├────────────┤ │  │                                     │
│ │方舟 LLM   │ │  │  services/volcengine.js  — OpenAPI  │
│ │(工具决策)  │ │  │  services/toolExecutor.js — 工具    │
│ └─────┬──────┘ │  │  services/cozeChatService.js — Coze │
│       │FC 回调  │  │  services/arkChatService.js — 方舟  │
│       │(HTTP)   │  │  config/voiceChatConfig.js — 配置   │
│       ▼         │  │  db/index.js — MySQL                │
│  fc_callback ──►│  │                                     │
│  ◄── Update ────│  └─────────────────────────────────────┘
└────────────────┘           │
                             ▼
                    ┌─────────────────┐     ┌──────────────┐
                    │   MySQL 8       │     │ 方舟知识库   │
                    │ sessions 表     │     │ (远程 API)   │
                    │ messages 表     │     └──────────────┘
                    └─────────────────┘

3. 目录结构

test2/
├── client/                        # 前端React + Vite
│   ├── src/
│   │   ├── App.jsx                # 主应用,语音/文字模式切换
│   │   ├── components/
│   │   │   ├── VoicePanel.jsx     # 语音通话界面
│   │   │   ├── ChatPanel.jsx      # 文字对话界面SSE 流式)
│   │   │   ├── SettingsPanel.jsx  # 语音参数设置面板
│   │   │   └── SubtitleDisplay.jsx# 实时字幕展示
│   │   ├── hooks/
│   │   │   └── useVoiceChat.js    # 语音通话核心 Hook
│   │   └── services/
│   │       ├── rtcService.js      # RTC SDK 封装WebRTC
│   │       ├── voiceApi.js        # 语音 HTTP 请求
│   │       └── chatApi.js         # 文字 HTTP/SSE 请求
│   └── vite.config.js
├── server/                        # 后端Express
│   ├── app.js                     # 入口 + FC 回调 raw body 解析
│   ├── routes/
│   │   ├── voice.js               # 语音全生命周期 + FC 回调(核心)
│   │   ├── chat.js                # 文字对话Coze
│   │   └── session.js             # 会话历史 & 模式切换
│   ├── services/
│   │   ├── volcengine.js          # 火山引擎 OpenAPI 签名调用
│   │   ├── toolExecutor.js        # 工具执行器
│   │   ├── arkChatService.js      # 方舟 LLM文字场景备选
│   │   └── cozeChatService.js     # Coze Chat API文字主服务
│   ├── config/
│   │   ├── voiceChatConfig.js     # StartVoiceChat 配置构建器
│   │   └── tools.js               # FC 工具定义5 个工具)
│   ├── db/index.js                # MySQL CRUD
│   ├── lib/token.js               # RTC Token 生成
│   └── .env                       # 环境变量
└── ecosystem.config.js            # PM2 部署配置

4. 语音通话模块

4.1 混合编排模式OutputMode=1

S2S 端到端模型处理普通闲聊(低延迟 ~300-800ms方舟 LLM 同时决策是否需要调用工具。两者并行运行。

4.2 会话生命周期

POST /prepare  →  创建房间 + 生成 RTC Token + 分配 TaskId
      ↓
客户端 joinRoom()  →  用户进入 RTC 房间、开启麦克风
      ↓
POST /start  →  构建配置 → StartVoiceChat API → AI Bot 进房
      ↓
   实时语音对话S2S 直接回复 + LLM 工具决策)
      ↓
POST /stop  →  StopVoiceChat API → 返回字幕 → 可切换文字模式

4.3 语音 API 端点voice.js

端点 方法 说明
/api/voice/config GET 获取模型、音色列表
/api/voice/prepare POST 创建房间、生成 Token
/api/voice/start POST 启动 AI 语音对话
/api/voice/stop POST 停止对话、返回字幕
/api/voice/fc_callback POST FC 回调RTC 服务端→服务端)
/api/voice/subtitle POST 客户端转发确认字幕
/api/voice/room_message POST 客户端转发 RTC 房间消息

4.4 内存数据映射

voice.js 维护以下 Map 用于会话状态关联:

Map 名称 Key Value 用途
activeSessions sessionId 完整会话对象 会话生命周期管理
roomToBotUserId roomId botUserId FC 回调→UpdateVoiceChat
roomToHumanUserId roomId userId 日志追踪
roomToSessionId roomId sessionId DB 写入关联
roomToTaskId roomId taskId UpdateVoiceChat 必须用此 TaskId
latestUserSpeech roomId {text, timestamp} FC 参数解析兜底
toolCallBuffers TaskID buffer 对象 FC chunk 收集

5. Function Calling 回调处理(核心)

5.1 数据流

RTC 服务 (LLM 触发 tool_call)
    │ HTTP POST无 Content-Typebody 为 JSON
    ▼
app.js 手动读取 raw body → JSON.parse → 分配 _seq 序列号
    │
    ▼
voice.js fc_callback 路由
    │
    ├─ FormatA: Type="tool_calls" → OpenAI 格式数组,流式 chunk
    ├─ FormatB: Type="information" → RTC 原生格式
    └─ FormatC: 会话状态回调 → 记录日志
    │
    ▼FormatA 为主)
chunk 缓冲收集toolCallBuffers Map1s 超时触发)
    │
    ▼ 1s 后
参数解析尝试链:
    ① JSON.parse(拼接 chunks)
    ② latestUserSpeechASR 用户语音兜底)
    ③ extractReadableText从 chunks 提取中文字符)
    │
    ▼
发送 interrupt 打断 S2S 直接回复
    │  UpdateVoiceChat({ Command: "interrupt", TaskId: sessionTaskId })
    ▼
执行工具toolExecutor.js
    │  search_knowledge: 方舟 KB(30s) → 本地 KB
    ▼
回传结果
    │  UpdateVoiceChat({
    │    Command: "function",
    │    TaskId: sessionTaskId,    ← 必须是 StartVoiceChat 的 TaskId
    │    Message: JSON.stringify({ ToolCallID, Content })
    │  })
    ▼
AI 用知识库内容语音回复

5.2 关键设计决策

问题 解决方案
FC 回调无 Content-Type app.js 在 express.json() 之前手动读取 raw body
Chunk 乱序且不完整 1s 定时器收集全部 chunks 后拼接
JSON.parse 失败 用 ASR 用户语音文本作为查询参数方案B
S2S 直接回复覆盖 FC 结果 先发 interrupt 打断,再发 function 结果
TaskId 不匹配 roomToTaskId 存储 StartVoiceChat 的 TaskId
HTTP 响应超时 立即返回 200异步执行工具

5.3 用户语音文本获取方案B

FC 回调的 arguments 经常乱序无法解析,因此需要从其他途径获取用户的原始问题:

客户端 RTC SDK
    │ onSubtitleMessageReceived / onRoomBinaryMessageReceived
    ▼
useVoiceChat.js
    │ 转发 definite=true 的用户字幕
    ▼
POST /api/voice/subtitle    →  latestUserSpeech.set(roomId, text)
POST /api/voice/room_message →  解析二进制消息中的字幕数据

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/:id/history GET 获取完整历史(支持 llm/full 格式)
/api/session/:id/switch POST 切换模式,返回上下文历史

7.4 数据库表

sessionsid(PK), user_id, mode(voice/chat), created_at, updated_at

messagesid(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 流式显示)
└── SettingsPanel.jsx      # 设置面板(模型/音色/系统角色/VAD

8.2 useVoiceChat Hook

管理语音通话完整生命周期:

  • start(options)prepare → joinRoom → startVoiceChat
  • stop()leaveRoom → stopVoiceChat → 返回字幕
  • toggleMute():静音/取消静音
  • 状态isActive, isMuted, isConnecting, subtitles, duration, error

8.3 rtcService.js

封装 @volcengine/rtc SDK

  • init(appId):创建引擎、注册事件监听
  • joinRoom():入房 + 开始音频采集 + 启用字幕
  • 事件监听:字幕(onSubtitleMessageReceived)、房间消息(binary/text)、诊断(音量/流)
  • 方案B 消息转发:所有房间消息 → onRoomMessage 回调 → useVoiceChat → 后端

9. 环境变量

必需

变量 说明
VOLC_RTC_APP_ID RTC 应用 ID
VOLC_RTC_APP_KEY RTC 应用密钥(生成 Token
VOLC_ACCESS_KEY_ID 火山引擎 AKAPI 签名)
VOLC_SECRET_ACCESS_KEY 火山引擎 SK
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
FC_SERVER_URL FC 回调地址
FC_SIGNATURE FC 回调签名
MYSQL_HOST/PORT/USER/PASSWORD/DATABASE MySQL 配置

10. 部署架构

互联网用户
    │
    ▼ HTTPS (443)
┌──────────────┐
│   Nginx      │  ← 宝塔面板管理
│  (反向代理)   │
│  SSL 终止    │
└──────┬───────┘
       │ http://localhost:3012
       ▼
┌──────────────┐
│   PM2        │  ← ecosystem.config.js
│  bigwo-server│
│  (Node.js)   │
└──────┬───────┘
       │
       ├── MySQL 8 (localhost:3306)
       ├── 火山引擎 RTC API (rtc.volcengineapi.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.logserver-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. FC 响应延迟:用户提问到 AI 用知识库回答约需 12-15sLLM 决策 ~8s + KB 查询 ~5s期间有静默
  2. Chunk 乱序RTC FC 回调的 tool_call arguments 被拆成单字符 chunk 且乱序,只能靠 ASR 文本兜底
  3. S2S 与 LLM 并行冲突S2S 会先给出直接回复,需 interrupt 打断后再发 FC 结果
  4. Mock 工具:天气和订单工具目前为 Mock 数据,可接入真实 API
  5. 知识库冷启动:方舟 KB 首次查询较慢(~10s后续查询 ~3-5s