目标
从零开始,在一台机器上把 4 个服务全部拉起,拨一通电话验证:用户说话能识别到文本、能听到 TTS 合成的应答。
预计耗时:首次 30 ~ 60 分钟(含模型加载与 FreeSWITCH 安装),熟练后 5 分钟。
环境前提
| 项 | 要求 |
|---|---|
| OS | Windows 10/11(推荐 ASR/TTS 服务) + Linux(推荐 FreeSWITCH 服务) |
| CPU | x64,4 核以上 |
| 内存 | 8GB+(模型加载约 1~2GB) |
| 工具 | Visual Studio 2022(含 C++ 工作负载)、CMake、Bun 1.x、MySQL 8、FreeSWITCH 1.10.x |
| 网络 | 各服务之间能互通对应端口 |
本例为单机部署,全部跑在同一台机器。FS 部署在 Linux + ASR/TTS 部署在 Windows 的常见拓扑见 部署。
Step 1 — 安装 FreeSWITCH + mod_audio_fork
1.1 装 FreeSWITCH
参考 FreeSWITCH 官方文档,本项目验证过 Debian 11 / CentOS 7。装好后能 fs_cli 进 FreeSWITCH 终端。
1.2 编译 mod_audio_fork
1 | git clone https://github.com/Wangijun/mod_audio_fork.git |
完成后 mod_audio_fork.so 会安装到 FS 的 mod 目录。
1.3 启用模块
编辑 conf/autoload_configs/modules.conf.xml:
1 | <load module="mod_audio_fork"/> |
或运行时:
1 | fs_cli -x "load mod_audio_fork" |
验证:
1 | fs_cli -x "module_exists mod_audio_fork" |
返回 true 即成功。
Step 2 — 启动 ASR 服务
2.1 构建
1 | cd C:\path\to\ai-voice-platform\sherpa-asr-online-server |
2.2 检查配置
打开 build\Release\config.json,确认:
1 | { |
模型路径默认相对解析到 ../models/,无需改。
2.3 启动
1 | cd build\Release |
启动成功日志:
1 | [sherpa_asr_online_server] listening on 0.0.0.0:10096 ... |
2.4 验证健康检查
新开一个终端:
1 | curl http://127.0.0.1:10096/health |
返回:
1 | { "ok": true, "service": "sherpa-asr-online-server", "activeSessions": 0, ... } |
Step 3 — 启动 TTS 服务
3.1 构建
1 | cd C:\path\to\ai-voice-platform\sherpa-tts-server |
3.2 检查配置
打开 build\Release\config.json:
1 | { |
注意
publicBaseUrl 必须填 FreeSWITCH 能访问到的地址,不要用 127.0.0.1(除非 FS 与 TTS 同机)。
3.3 启动
1 | cd build\Release |
启动成功日志:
1 | [sherpa_tts_server] loaded TTS worker in 1234 ms |
3.4 验证合成
1 | curl -s -X POST http://127.0.0.1:9080/tts \ |
返回:
1 | { "wavUrl": "http://...:9080/wav/tts-xxx.wav", "fileName": "...", "sampleRate": 16000, "cached": false } |
浏览器打开 wavUrl 能直接播放即正常。
Step 4 — 启动 MySQL + callflow-esl
4.1 准备 MySQL
1 | CREATE DATABASE `ai-voice` DEFAULT CHARSET=utf8mb4; |
记下连接串:mysql://root:password@127.0.0.1:3306/ai-voice
4.2 安装依赖与初始化 schema
1 | cd C:\path\to\ai-voice-platform\callflow-esl |
打开 config.json,按你的环境改:
1 | { |
初始化 schema:
1 | bun run db:generate |
4.3 插入一条测试业务路由
进 MySQL:
1 | USE `ai-voice`; |
4.4 启动服务
1 | bun run dev |
启动日志:
1 | [callflow-esl] ESL TCP listening on 0.0.0.0:9911 |
Step 5 — 配置 FreeSWITCH dialplan
编辑 conf/dialplan/default.xml(或自己挂一段):
1 | <extension name="route-to-callflow"> |
重载:
1 | fs_cli -x "reloadxml" |
Step 6 — 拨打第一通电话
用任意 SIP 客户端(如 Zoiper、MicroSIP)注册到 FreeSWITCH,拨号 1000。
观察 callflow-esl 控制台:
1 | [callflow-esl] outbound session uuid=... |
接通后说一段话(中文/英文都行),ASR 服务会返回 partial / final 文本,callflow-esl 会用 TTS 把你说的话回放回来(这是 default-call-business 的行为:echo 业务)。
ASR 服务控制台会看到:
1 | [sherpa_asr_online_server] ws-1 websocket session started on worker=0 |
TTS 服务控制台:
1 | [sherpa_tts_server] generated public/wav/tts-xxx.wav in 234 ms (rtf=0.45) |
第一通电话成功后
恭喜,端到端链路打通了。下一步:
常见拉起问题速查
| 现象 | 排查方向 |
|---|---|
| FS 拨号没反应 | dialplan socket IP/端口是否正确;callflow-esl 是否监听 0.0.0.0 |
| outbound 连进来立刻断 | 看 callflow-esl 日志业务路由是否失败(无 biz_id 也无号码映射) |
| 接通但没声音 | playbackTarget=wav-url 时检查 FS 能否 HTTP 访问 publicBaseUrl |
| ASR partial 全是乱码 | 检查 audioFork 配置 mixType=mono sampleRate=16k,与 ASR 服务一致 |
| ASR 一直没 final | audioFork.eventSubscriptionMode 改 "all";看 ASR 端日志是否发出 final |
| TTS 失败 503 | maxQueuedRequests 太低,或者 ttsPoolSize 不够 |
| MySQL 连不上 | db.url / db.password / db.database 是否对得上 |
更完整的排查表在 FAQ。