外观
部署参考(Debian 12 主机)
当前生产拓扑:
aliyun公网节点运行 FreeSWITCH(已有常驻实例)、callflow-esl业务编排服务、FRPS、coturn、Nginx 以及三个 Web 前端 SPA 静态站点与文档站; WSL 本地环境(/data/ai-voice)运行三个 Bun 服务端(callflow-server、callout-server、callai-server)、三个 ONNX 语音服务(ASR、TTS、Emotion)与 FRPC 客户端。 FRP 端口见deploy/aliyun/frp/README.md与deploy/wsl-docker/README.md,公网 HTTP/WSS 配置见deploy/aliyun/nginx/ai-voice-public.conf。
跨项目调用链、通用单机 / 分层 / 每服务独立 / 多 cell 方案及当前双主机端口映射统一见 部署网络拓扑与配置手册。本文聚焦 Debian 12 与 WSL 构建、分发、 服务落地与生效操作,避免重复维护拓扑和字段定义。
本手册说明如何把仓库中的服务和配置落到生产与本地主机。当前阿里云上的 FreeSWITCH 软交换中心已存在且运行正常,无需再次部署。构建、文件分发、进程托管、依赖安装、升级与回滚按本手册指导进行。
本地开发测试请参考 development-testing.md,跨平台启动和健康检查 参考 setup-deployment.md,配置目录边界参考 ../deploy/README.md。
1. 准备运行环境
目标主机按实际启用的组件准备:
- Bun 1.x,用于运行 Bun/TypeScript 后端或构建独立可执行文件;
- CMake、Ninja、C++ 编译器和各 ONNX 服务所需运行库;
- FreeSWITCH 1.10.x,并安装、启用
mod_audio_fork;流式 MP3 播放还需mod_shout; - PostgreSQL、Redis,以及 OpenAI 兼容推理后端和其中已加载的模型(供
callai-server与llm-chat-business调用); ffmpeg,供流式 TTS 的 PCM → MP3 链路使用;- 用于托管前端静态文件和媒体文件的 HTTP 服务或反向代理(按需)。
仅启用部分组件时,可以省略不在调用链上的依赖。所有监听端口、数据库、媒体目录和模型路径 都应在上线前显式确认,不要依赖配置样例中的机器特定值。
2. 构建与分发
ONNX C++ 服务
仓库提供 onnx-platform/Dockerfile.debian12 作为 Debian 12 x64 编译工具链镜像。 该镜像仅用于生成与 Debian 12 系统运行库兼容的原生产物,不是生产部署镜像。运行期的容器化 编排是另一套资产,见 deploy/wsl-docker/(Dockerfile + docker-compose.yml,业务二进制与 模型均外部挂载)。
在仓库根目录构建并进入工具链容器:
bash
docker build \
-f onnx-platform/Dockerfile.debian12 \
-t ai-voice-platform-debian12 \
onnx-platform
docker run --rm -it \
-v "$PWD:/workspace/ai-voice-platform" \
-w /workspace/ai-voice-platform/onnx-platform \
ai-voice-platform-debian12 \
bash容器内先清理其他发行版可能遗留的 CMake 缓存,再分别构建三个服务:
bash
rm -rf build/asr-linux_x64 build/tts-linux_x64 build/emotion-linux_x64
bash sherpa-tts-server/build.sh
bash sherpa-asr-online-server/build.sh
bash sherpa-asr-offline-server/build.sh
bash fanasr-asr-online-server/build.sh
bash fanasr-asr-offline-server/build.sh
bash emotion-analysis-server/build.sh产物位于各服务的 target/linux_x64/。模型默认来自 onnx-platform/models/;分发产物时必须 同时保证模型、ONNX Runtime / sherpa-onnx 运行库和配置中的相对路径能够解析。Linux 构建环境 和运行库兼容性详见 ../onnx-platform/README.md。
Bun 后端与前端
各 Bun 服务的构建命令和独立可执行文件配置路径以模块 README 为准。三个 Quasar/Vite 前端的 API 根地址在构建期注入,默认值均为同域 /api。从仓库根目录构建:
bash
bun run --cwd apps/callflow-webpage build
bun run --cwd apps/callout-webpage build
bun run --cwd apps/callai-webpage build前端产物分别位于 apps/callflow-webpage/dist/spa/、apps/callout-webpage/dist/spa/ 和 apps/callai-webpage/dist/spa/。使用默认值时,生产环境必须将 callflow 前端站点的同域 /api 转发到 callflow-server(默认 127.0.0.1:9913),callout 前端站点转发到 callout-server(默认 127.0.0.1:9920),callai 前端站点转发到 callai-server(默认 127.0.0.1:9930),并保留 /api 路径。多个前端应使用能够分别 配置 upstream 的站点或 origin。需要自定义代理前缀或浏览器可访问的后端地址时,在构建前 设置对应的 VITE_CALLFLOW_API_BASE_URL、VITE_CALLOUT_API_BASE_URL 或 VITE_CALLAI_API_BASE_URL,然后重新构建前端。
仓库不会把后端、前端、ONNX 可执行文件和模型自动装配到统一目录。部署方应建立自己的版本目录, 并保留上一个可运行版本以便回滚。
3. 使用部署配置
将 deploy/aliyun/*/ 与 deploy/wsl-docker/configs/*.json 复制到相应服务实际读取的位置,再按目标环境校准。不要让多个 服务直接共享一份可写配置,也不要在仓库样例中保存生产密码或 token。
重点检查:
callflow-esl.config.json:FreeSWITCH inbound ESL、callbackHost、ASR WebSocket、TTS endpoints、 PostgreSQL、Redis、录音和日志目录;必填businessConfig["llm-chat-business"]的endpoint / apiKey / model / requestTimeoutMs, endpoint 是 OpenAI 兼容后端的完整/v1/chat/completions地址;启用kb-audio-chat-business时还要把businessConfig["kb-audio-chat-business"].endpoint指向 callai-server 的/api/v1/conversation,校准strategy(样例kb-mock)与内部鉴权 token;同时校准callout.calloutServer / nlu / chat三组服务的baseUrl / token / requestTimeoutMs(后两组都指向 callai-server 的9930);callflow-server.json:FreeSWITCH / callflow 数据库、callflowEsl.baseUrl、鉴权与turn;callout-server.json:PostgreSQL、Redis、FreeSWITCH ESL、callai、Emotion、媒体公开地址、鉴权与turn;callai-server.json:PostgreSQLcallai连接、server.authToken、callout.baseUrl与用量记录; 推理后端可写死在llm.openaiUrl与各领域模型,也可留空由数据库callai.ai_llm_configs中启用的记录提供;sherpa-asr-online-server.json:监听地址、模型 / VAD 路径、并发、日志和录音目录;sherpa-asr-offline-server.config.json:监听地址(10095)、SenseVoice 模型路径、并发队列、ffmpeg 与日志目录;fanasr-asr-online-server.config.json:监听地址(10099)、2-pass 双流模型路径、热词配置、日志和录音目录;fanasr-asr-offline-server.config.json:监听地址(10094)、Paraformer 离线模型路径、热词配置、ffmpeg 与日志目录;sherpa-tts-server.json:监听地址、publicBaseUrl、模型、缓存、日志和 ffmpeg 路径; 当前公网播放基址为https://tts.wangijun.com;emotion-analysis-server.json:监听地址、文本 / 音频模型、并发和输出目录。
阿里云主机通过回环 FRPS 使用 ASR 12010、TTS 12008、Emotion 12009、统一 AI 决策中台 12013, 与本地开发默认端口不完全相同。所有调用方必须使用同一套最终端口和可达地址。
4. 部署 FreeSWITCH 配置
deploy/freeswitch/ 是 FreeSWITCH 配置参考树(当前线上现场快照另见 deploy/aliyun/freeswitch/),包含拨号计划、directory、SIP profiles、ESL、 模块加载、会议和 TLS 等配置。部署时按现场 FreeSWITCH 的 conf_dir 合并,重点核对:
autoload_configs/event_socket.conf.xml的监听地址、端口、密码和 ACL;autoload_configs/modules.conf.xml中mod_audio_fork、mod_shout等所需模块;dialplan/中 outbound socket 地址是否指向 callflow-esl 的 ESL 监听端口;sip_profiles/、directory/、网关、分机、域名、外网地址和 RTP 范围;tls/证书是否属于目标环境,生产环境不要直接复用样例证书。
不要直接覆盖已有生产配置。先备份现场 conf_dir,合并后执行 FreeSWITCH 配置校验和 reload; 涉及模块、SIP profile 或核心监听参数时应安排维护窗口重启。ESL 端口不得直接暴露到公网。
FreeSWITCH 的监听地址与 SDP 广告地址必须分离:当前线上 sip-ip / rtp-ip 绑定 172.21.38.245,ext-sip-ip / ext-rtp-ip 广告 123.57.205.60。FreeSWITCH RTP 范围为 30000–30199/UDP;不要把公网 IP 配到本机绑定字段。
SIP WebSocket 由同机 Nginx 终止公网 TLS 后,通过 https://172.21.38.245:7443 重新加密 转发给 FreeSWITCH。不要降级代理到 5066/WS,否则浏览器 SIP Via: WSS 与 Sofia 看到的 实际传输不一致,REGISTER 可能在握手成功后超时。WebRTC profile 必须使用 local-network-acl=none,否则生成的 SDP 仍会包含私网媒体地址。同时通过 apply-candidate-acl=softphone-turn-relay 只允许 coturn 公网地址;FreeSWITCH 1.10 默认会优先选手机的 srflx 而不是 relay,在运营商 NAT 下会 表现为 ICE 已创建但 DTLS 一直停在 HANDSHAKE、双方无声。
4.1 公网 coturn
浏览器软电话跨运营商网络时使用 coturn REST 短期凭据。coturn 直接运行在公网主机 aliyun,不经过高负载 FRP:
3478/UDP:STUN 与 TURN/UDP;3478/TCP:TURN/TCP 回退;31000–31040/UDP:relay allocation,与 FreeSWITCH RTP 范围分离;external-ip=123.57.205.60/172.21.38.245;realm=softphone.ai-voice-platform,启用use-auth-secret与fingerprint,不启用 TLS/TURNS。
配置参考见 deploy/aliyun/coturn/turnserver.conf.example(同目录另有 coturn.service 与 README)。真实 shared secret 只能放在 coturn 私有 配置,以及 CALLFLOW_SERVER_TURN_SHARED_SECRET / CALLOUT_TURN_SHARED_SECRET 环境变量 或两个后端的服务器私有配置中。FRP 只承载 12000-12013 的数据和应用上游, 不承载 SIP WebSocket、FreeSWITCH RTP 或 TURN。
仓库内两个后端及部署样例均默认 turn.enabled=false,适用于浏览器与 FreeSWITCH 之间 host candidate 可达的本地直连。生产环境启用 coturn 时,必须在私有配置中同时改为 enabled=true 并注入真实 shared secret;只开启开关而缺少必要字段时,短期凭据接口会返回 503 ICE_CONFIG_UNAVAILABLE。
5. 初始化与启动顺序
首次部署或 schema 变化时,在注入目标数据库 URL 后同步 callflow / callout / callai 三个 schema(各自 drizzle.config.ts 读取的环境变量不同,缺省时回落到 postgres://postgres:postgres@localhost:5432/freeswitch):
bash
CALLFLOW_DB_URL=<callflow-database-url> bun run --cwd apps/callflow-esl db:push
CALLOUT_DB_URL=<callout-database-url> bun run --cwd apps/callout-server db:push
CALLAI_DB_URL=<callai-database-url> bun run --cwd apps/callai-server db:push建议按依赖顺序启动:
- PostgreSQL、Redis、OpenAI 兼容推理后端;
- ASR、TTS、Emotion;
- callai-server、callai-webpage;
- callflow-esl、callflow-server、callout-server;
- FreeSWITCH;
- 前端静态站点和媒体文件服务。
生产环境应使用 systemd、Docker Compose 或既有运维平台托管进程,配置运行用户、工作目录、 环境变量、日志轮转、失败重启和开机自启。deploy/aliyun/ 下提供了当前生产节点在用的 callflow-esl.service、frps.service、coturn.service 等 unit,deploy/wsl-docker/ 下提供 docker-compose.yml 与 frpc.service;它们绑定了本套拓扑的路径与账号,套用到新环境前必须逐项校准。
6. 健康检查
以下端口按 deploy/wsl-docker/ 当前编排列出(WSL 集群统一使用 2xxxx 段,避免与 Windows 本地开发端口冲突);若已修改配置,以最终值为准:
bash
curl http://127.0.0.1:20096/health # ASR
curl http://127.0.0.1:29080/health # TTS
curl http://127.0.0.1:29090/health # Emotion
curl http://127.0.0.1:29930/health # callai-server
curl http://127.0.0.1:29913/health # callflow-server
curl http://127.0.0.1:29920/health # callout-server阿里云节点上则通过 FRP 回环端口探测,例如 curl http://127.0.0.1:12013/health。
健康检查通过后,再依次验证 TTS 返回 URL 能被 FreeSWITCH 访问、ASR WebSocket 能返回 partial / final、 FreeSWITCH 能连接 callflow-esl outbound ESL,以及一次真实呼叫的识别、播报、录音和结果回写链路。
7. 升级与回滚
- 升级前备份数据库、实际生效配置、FreeSWITCH
conf_dir和当前可执行文件; - 在非生产环境完成 typecheck、构建和链路验证,再按依赖顺序滚动替换;
- FreeSWITCH 或 callflow-esl 变更会影响在途通话,应安排维护窗口;
- 配置、模型和二进制作为一组版本化,回滚时一并恢复,避免接口或路径不匹配;
- 前端 API 根地址变化后必须通过对应
VITE_*_API_BASE_URL重新构建前端;使用默认/api时只需校准静态站点的反向代理 upstream。
故障定位见 troubleshooting.md。