三种典型拓扑
拓扑 A:单机一体(开发 / 演示)
1 | ┌──────────────────────────────────────────────────┐ |
- 适合:本地开发、PoC 演示、小并发自用
- 全部走
127.0.0.1,零网络 - 配置最简单
- 缺点:FS 与 ASR/TTS 抢 CPU;并发上不去;单点
拓扑 B:FS 与业务/AI 分离(推荐生产起点)
1 | ┌─────────────────────────┐ ┌────────────────────────────┐ |
- 适合:本项目当前主推的生产模式
- FS 只做软交换与媒体,专注稳定;业务/AI 在一台机器上集中处理
- 单台 application host 8 核 16G 可承载几十路并发
- 横向扩展:起多个 application host,配多个 dialplan /
originate分流
拓扑 C:全分布式(高并发)
1 | ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ |
- 适合:百路并发以上、要求高可用
- 需要前端 LB(haproxy / nginx)做 ESL / HTTP / WS 路由
- ASR / TTS 都是无状态服务,可任意横向扩
- callflow-esl 当前是无业务 sticky 状态(一条通话对应一条 ESL 连接),适合水平扩
端口与防火墙
| 方向 | 协议 | 端口 | 用途 |
|---|---|---|---|
| 外部 → FS | SIP/UDP | 5060 | 呼入 |
| 外部 → FS | RTP/UDP | 16384-32768(FS 默认) | 媒体 |
| FS → callflow-esl | TCP | 9911 | outbound ESL |
| callflow-esl → FS | TCP | 8021 | inbound ESL |
| 调用方 → callflow-esl | HTTP | 9912 | POST /outbound-calls |
| FS (mod_audio_fork) → ASR | WS | 10096 | 音频上行 |
| callflow-esl → TTS | HTTP | 9080 | 合成请求 |
| FS → TTS | HTTP | 9080 | wav 下载 |
| 任意 → ASR | HTTP | 10096 | /health |
跨主机部署时务必把上述端口在防火墙打开。
网络与地址陷阱
注意
部署最容易翻车的两个配置项:
1. callbackHost / callbackPort
在 callflow-esl config.json 的 freeswitch 节:
1 | { |
callbackHost是 FS 进程发起 outbound 回连时用的目标地址- 必须是 FS 进程能 ping 通的 IP
- 千万不要写
127.0.0.1,除非 FS 与 callflow-esl 同机
2. publicBaseUrl(TTS 服务)
在 sherpa-tts-server config.json:
1 | { |
- 返回给 callflow-esl 的
wavUrl用这个前缀拼 - callflow-esl 把
wavUrl交给 FS,FS 用这个 URL 拉 wav - FS 必须能从自己网络访问到
publicBaseUrl - 一旦不通,表现就是接通后没有声音
远程联调模式
本项目工程规范里描述了一个常用调试模式:
本地联调优先使用仓库内可直接运行的
unimrcp/。如需对接远端 FreeSWITCH 环境,可使用ssh debian11登录对应服务器;该服务器上运行 FreeSWITCH。默认场景:本地 ASR/TTS/业务服务 + 远端 FreeSWITCH。
在这种模式下:
1 | 开发机(Windows) 远端服务器(Linux) |
要点:
- 开发机配
listenHost: "0.0.0.0"(所有服务),公网/VPN 可访问 callbackHost填开发机的公网 IPaudioFork.wsUrl填开发机公网 IPpublicBaseUrl填开发机公网 IP- 远端 FS dialplan socket 指向开发机 IP
1 | # 在 FS 端验证开发机可达 |
资源规划
| 资源 | 估算 |
|---|---|
| ASR 单实例内存 | ~600MB(含 zipformer + silero) |
| TTS 单实例内存 | ~800MB(含 vits-aishell3) |
| 单路 ASR 并发 CPU | ~0.3 核(RTF ~0.3 看机器) |
| 单路 TTS 一次合成 | ~0.5 秒/句(RTF ~0.5 看机器) |
| TTS wav 缓存增长 | 平均 50KB/句,按业务积累,需定期清理 |
| callflow-esl 单连接内存 | <2MB |
| MySQL 数据量 | 业务路由表,KB 级 |
并发估算
- 1 台 8 核 16G application host
maxSessions = 16,sessionPoolSize = 16,ttsPoolSize = 4- 可稳定承载 15~20 路同时在线通话(含 ASR + 间歇性 TTS)
要更高并发:增加 application host,按 SIP 域名 / 号段做分流。
TTS wav 缓存管理
sherpa-tts-server 当前没有 LRU / TTL,wav 会持续累积在 build/Release/public/wav/。
生产建议:
- 设定时任务每日/每周清理
wav/下超过 N 天的文件 - 由于命名是文本 hash,删除老文件不会破坏服务,下次请求会重新生成
- 如果业务场景文本高度收敛(IVR 固定话术),缓存命中率会非常高,wav 增长非常慢
示例清理脚本(PowerShell,删 7 天前的 wav):
1 | Get-ChildItem "C:\...\public\wav\" -Filter "*.wav" | |
高可用 / 平滑升级
当前局限:
注意
- ASR / TTS / callflow-esl 都没有 graceful shutdown:直接 SIGTERM / Ctrl+C 会中断在途请求与连接
- 没有内置健康检查 + auto restart;建议用 systemd / supervisor / nssm 托管
- 没有内置鉴权;务必置于内网或加反代鉴权层(nginx + basic auth / mTLS)
推荐做法:
- 后端 ASR / TTS 起多实例 + LB(按 hash 或 round-robin)
- callflow-esl 按号段分流,单实例宕机只影响新连接,老连接由 runtime 兜底清理
- 升级时先把流量切走,等 ESL 连接全部断开,再重启
- 模型升级:放新目录,改配置,重启服务;旧 wav 缓存可清也可留(覆盖时同 hash 同文件)
安全建议
| 风险 | 措施 |
|---|---|
| ASR / TTS 接口被外部探测 / 占用 | 仅监听内网 IP;外网入口加 nginx + basic auth / mTLS |
| MySQL 弱口令 | 改强口令;只允许 application host 访问 |
| FS ESL 暴露公网 | inbound ESL 8021 必须严禁公网;用 VPN / 内网 |
POST /outbound-calls 滥用 |
加 API key / IP 白名单(nginx 层) |
| TLS 自签证书 | 内网部署可接受;公网部署必须正规证书 |