docs: add three-system comparison for AI outbound calling selection
This commit is contained in:
+164
@@ -0,0 +1,164 @@
|
||||
# AI 语音外呼系统选型对比 — LiveKit SIP vs Asterisk (ARI) vs FreeSWITCH (ESL)
|
||||
|
||||
> 基于 2026-08-31 在同一台机器 (39.106.106.246, 阿里云 2vCPU/3.5G, Debian 13) 上的三期同口径实测调研, 非 RFC/官网口径的纸面对比。
|
||||
> 三期均: Mock SIP 运营商 + Mock LLM/ASR, 端到端验证外呼双向语音, 双节点水平扩展实证。
|
||||
> 数据来源: `livekit/`, `asterisk/`, `freeswitch/` 三目录的 README 与 deployment.md。
|
||||
|
||||
## 0. 结论先行
|
||||
|
||||
| 场景 | 推荐 | 一句话理由 |
|
||||
|---|---|---|
|
||||
| **AI 实时语音外呼 (打断/等待/全双工)** | **Asterisk (ARI)** | externalMedia 把媒体裸 RTP 直接交给 agent, 实时打断=agent 收到帧就处理, 无房间/编解码转码开销, 控制面 REST+事件流最贴业务语义 |
|
||||
| 已有/规划 LiveKit 实时音视频体系, 外呼只是其中一环 | LiveKit SIP | 被叫进房后与普通 RTC 用户同构, 复用 agents 框架 (VAD/打断/等待开箱即用), 多媒体场景唯一解 |
|
||||
| 超大规模纯话务 (>500 路)、呼叫中心类复杂 IVR | FreeSWITCH (ESL) | 单机容量与 20 年电信级 IVR 能力最深; 但媒体要走 SIP UAS 自建, 实时 AI 打断链路集成成本最高 |
|
||||
|
||||
三套都能满足题设三条业务要求 (AI 外呼 / 实时语音+打断+等待 / 呼出状态), 差异在**集成深度、运维面、扩展模型**。选型不该按"功能有没有", 而应按下面 §2–§9 的数据对号入座。
|
||||
|
||||
## 1. 三方案一句话架构
|
||||
|
||||
| | LiveKit SIP | Asterisk ARI | FreeSWITCH ESL |
|
||||
|---|---|---|---|
|
||||
| 媒体接入方式 | 被叫以 SIP participant 身份进 LiveKit 房间, agent 在房间内收发 track (WebRTC/Opus) | ARI `externalMedia`: 混音 ulaw RTP 裸流直连 agent | 无外挂媒体 API, agent 自建 SIP UAS 端点, FS originate 到 agent 再 `uuid_bridge` |
|
||||
| 控制面 | LiveKit API (gRPC/REST) + lk CLI | ARI REST + 事件 websocket | ESL TCP 单连接命令式 |
|
||||
| AI 帧到达路径 | SIP→网关转码→RTC 房间→agent track 回调 | SIP→桥→RTP socket→agent | SIP→桥→RTP socket→agent (但 agent 须先做 SIP 信令应答) |
|
||||
|
||||
## 2. 业务要求逐项比对 (题设三点)
|
||||
|
||||
### 2.1 AI 负责语音外呼
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 发起外呼 API | `CreateSIPParticipant` (房间+号码, 一次调用) | `POST /ari/channels` originate | ESL `originate` ×2 + `uuid_bridge` |
|
||||
| 调用复杂度 | **最低** (1 个 API + SDK) | 中 (REST 三步: 建 bridge→externalMedia→originate) | **最高** (originate×2 + bridge, 且 agent 须自带 SIP UAS) |
|
||||
| 被叫应答确认 | SIPCallID 返回 + 被叫进房事件 | StasisStart/ChannelStateChange Up 事件 | `originate +OK` 返回值 |
|
||||
| 实测 | ✅ SIPCallID=SCL_LEG… 返回 | ✅ callee answered: state=Up | ✅ leg2 answered: +OK |
|
||||
|
||||
### 2.2 实时语音 / 打断 / 等待
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 媒体时延路径 | SIP→网关 (G.711↔Opus 转码)→RTC 房间→agent | SIP→桥→**裸 RTP 直达 agent** | SIP→桥→裸 RTP 直达 agent (须先过 agent 的 SIP UAS) |
|
||||
| 转码 | 有 (PCMU↔Opus, 网关 CPU 主要消耗) | **无** (G.711 透传) | **无** (G.711 透传) |
|
||||
| 打断 (barge-in) | agents 框架 VAD 开箱即用; 媒体路径多一层转码+房间调度 | agent 收帧即处理, **路径最短**; VAD/打断逻辑自研 | 同 Asterisk 路径, 但 agent 还要自答 SIP (re-INVITE/重传) |
|
||||
| 等待 (hold/半双工) | 房间 mute track 即可 | ARI `POST /channels/{id}/mute` + hold | ESL `uuid_broadcast`/`hold` 等命令 |
|
||||
| agent 实现量 | mock 78 行 (SDK 重, 但抽象走 SDK) | mock 295 行 (REST+ws+RTP 全自研) | mock 316 行 (SIP UAS+ESL+RTP 全自研) |
|
||||
| 实测双向 | ✅ rx=1015 rms=4640 | ✅ rx=512 rms=8318 对称 | ✅ rx=536 rms=8246 对称 |
|
||||
|
||||
### 2.3 号码呼出状态
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 振铃/应答/失败区分 | CreateSIPParticipant 返回失败码; 事件粒度一般 | **事件流最细**: StasisStart/ChannelStateChange(原值 SIP 180/200/486…)/ChannelHangupRequest/原因码 | ESL 事件 (CHANNEL_PARK/ANSWER/END) + originate 返回码, 粒度与 ARI 相当 |
|
||||
| 挂机原因 | 部分场景仅 generic 错误 | **CAUSE/cause-txt 全量** (SIP 原因码直通) | Hangup-Cause 变量全量 |
|
||||
| 业务侧订阅方式 | API 轮询/房间事件 | **WebSocket 事件流** (每通道全生命周期) | ESL 事件订阅 (需自维护连接/事件解析) |
|
||||
| 无应答/拒接/占线区分 | 需从 SIP 状态映射, 文档化程度一般 | ✅ 原生 | ✅ 原生 |
|
||||
|
||||
### 2.4 结论
|
||||
三条硬性要求三者均满足 → **不构成淘汰项**, 选型权重应落在 §3–§9。
|
||||
|
||||
## 3. SIP 对接难度 (实测踩坑数 = 一手成本数据)
|
||||
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 配置文件量 | trunk.json **7 行** | 4 文件 ~39 行 | 2 文件 25 行 + setup-conf.sh 生成器 (vanilla 全量补丁) |
|
||||
| 部署组件数 | **5** (livekit×2+redis+sip×2+provider) | 2 (ast+provider) | 2 (fs+provider) |
|
||||
| 实测踩坑数 | 3 (SDK 拆包/grants/buffer) | 4 (Stasis ws 存活、NonQual、UNICASTRTP 地址、entrypoint chown) | **7** (镜像 entrypoint 整目录、`::` 监听、stun-set 拖垮 mod_sofia、ESL ACL 三连坑、CA 证书、fs_cli 空行、网关冷启动) |
|
||||
| trunk 换真实运营商 | 改 trunk.json address+auth 两字段 | pjsip.conf 加 outbound_auth 两行 | mock-trunk.xml 改 proxy+加认证参数 |
|
||||
| NAT (阿里云 1:1) | `use_external_ip: true` 一项 | external_media/signaling_address 两项 | ext-sip-ip/ext-rtp-ip 回填 (本文已剥离) |
|
||||
| 镜像质量 | 官方镜像, 干净 | andrius 镜像小坑 (chown) | safarov 镜像坑最多 (entrypoint 种子机制+缺 CA) |
|
||||
| 对接评估 | **最容易** | 中 | **最难** (7 坑且集中在镜像与 ACL) |
|
||||
|
||||
## 4. 系统稳定性 (实测 + 模型)
|
||||
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 运行时依赖 | livekit + sip + **Redis (强依赖)** | 单体 Asterisk | 单体 FreeSWITCH |
|
||||
| 共享故障点 | **Redis 单点** (挂→trunk/呼叫状态丢, 服务不可用) | **无** (每节点自包含) | **无** (每节点自包含) |
|
||||
| 节点故障半径 | 房间归属节点挂→该节点房间媒体中断; 调度层可摘除 | 该节点在途呼叫中断; 其余节点无感 | 同 Asterisk |
|
||||
| 状态恢复 | Redis 纯缓存用法可重建 (trunk 需重建) | 重启即冷启, 在途呼叫丢失 (外呼场景可接受) | 同 Asterisk |
|
||||
| 实测稳定性 | 三期均 0 挂断异常、0 泄漏 (呼后 channels/calls=0) | 同左 | 同左 |
|
||||
| healthcheck | HTTP /healthz + API 双层 | docker healthcheck + ARI REST | compose 自配 fs_cli healthcheck |
|
||||
| 版本/维护方 | LiveKit 商业公司, 迭代快 | Sangoma, LTS 22.x | SignalWire, 1.10.12 |
|
||||
| 成熟度心智 | 年轻 (SIP 网关较新) | 20+ 年电信级 | 20+ 年电信级 |
|
||||
|
||||
## 5. 可扩展性 (三期均双节点实证)
|
||||
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 扩展模型 | 共享 Redis 的无状态副本 | **零共享状态节点复制** | **零共享状态节点复制** |
|
||||
| 加节点动作 | 加 sip service 块 (零配置变更) | 加 service 块 (零配置变更) | 加 service 块 (零配置变更) |
|
||||
| 调度机制 | Redis 随机派发 (自动) | 呼叫发起侧名单选择 (自研调度) | 同 Asterisk |
|
||||
| 跨节点媒体互通 | ✅ (房间路由) | ✗ (外呼场景无影响) | ✗ (同左) |
|
||||
| 单节点容量 (实测口径) | sip 网关 200 端口/节点, CPU 转码是瓶颈; 官方 4C8G 数百路 | ~200 并发/节点 (800 RTP 端口) | ~4000 并发/节点 (1.6 万 RTP 端口), CPU 先到顶 |
|
||||
| 3 路并发资源 (同机) | livekit 2×6%CPU/36M, sip 2×20%CPU/30M, redis 1%/8M | ast 1.4%/1.1% CPU, 53M/52M | fs 0.3%/0.3% CPU, 48M/44M |
|
||||
| 扩到 N 节点需引入 | Redis 持久化/主从 (CAP 代价) | 仅 LB 名单 | 仅 LB 名单 |
|
||||
| 超大并发 (>500 路) | 网关转码 CPU 线性涨, 需评估 | 加节点线性 | **最优** (单节点容量最大) |
|
||||
| 呼入/注册扩展 | ✅ 原生 | 需前置 Kamailio dispatcher | 需前置 Kamailio dispatcher |
|
||||
|
||||
## 6. AI 集成深度 (实时语音核心差异)
|
||||
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 媒体进入 AI 侧方式 | track 回调 (帧级, 自动 jitter/重排) | **裸 RTP socket** (自管 seq/ts, 无重排) | 裸 RTP socket (自管) |
|
||||
| 编解码 | Opus (需转码) | **G.711 直通** (ASR 前按需转) | G.711 直通 |
|
||||
| VAD/打断框架 | **livekit-agents 开箱** (VAD/STT/TTS 插拔, Pipeline/Agent 打断) | 自研 (帧循环+VAD 模型自选) | 自研 + mod_audio_fork/mod_audio_stream 类模块 (需编译/二次集成) |
|
||||
| 多 AI 并发会话 | 每房间一 agent worker, HPA | 每呼叫一 ESL…每呼叫一 ARI 会话, 无状态 worker | 每呼叫一 ESL 连接 (高并发需连接池/bgapi) |
|
||||
| 等待/半双工控制 | mute track / publish 控制 | ARI mute/hold REST | ESL hold/broadcast 命令 |
|
||||
| 实时性理论最优 | 中 (转码+房间调度) | **最优** (直连) | 优 (直连但多 SIP 层) |
|
||||
|
||||
## 6b. 呼出状态获取详表
|
||||
|
||||
| 状态点 | LiveKit | Asterisk ARI | FreeSWITCH ESL |
|
||||
|---|---|---|---|
|
||||
| 已拨 (INVITE 已发) | CreateSIPParticipant 调用成功 | originate 200 返回 | `originate` 命令发出 |
|
||||
| 振铃 (180/183) | 房间 participant joined 前无明显事件 | **ChannelStateChange Ringing** | CHANNEL_PROGRESS/CHANNEL_PARK 事件 |
|
||||
| 应答 (200 OK) | participant joined / SIPCallID 返回 | **ChannelStateChange Up** | CHANNEL_ANSWER / originate +OK |
|
||||
| 拒接/无应答/占线 | API 错误码 (映射不完整) | **ChannelHangupRequest + cause** (486/408/487 原生) | CHANNEL_HANGUP + Hangup-Cause 变量 |
|
||||
| 通话中 | track 订阅/统计 | channel/bridge 全事件 | 事件流全量 |
|
||||
| 挂断+原因 | 房间断开事件 (原因一般) | **StasisEnd + cause-txt** | CHANNEL_END + Hangup-Cause |
|
||||
| 订阅通道 | WS 房间事件 | **每通道全生命周期 WS 事件流** | ESL 事件 (myevents 模式) |
|
||||
| 状态→业务字段映射成本 | 中 (需自行映射) | **低 (SIP 原因码直通)** | 低 (变量直通, 解析自理) |
|
||||
|
||||
## 7. 运维与可观测
|
||||
|
||||
| | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 部署复杂度 (容器数) | 5 (livekit×2/sip×2/redis) | **2** | **2** |
|
||||
| 组件内存合计 (双节点+3并发) | ~140M (5 容器) | ~105M | ~92M |
|
||||
| 健康检查脚本 | 容器+HTTP+API 三层 ok=5 | 容器+ARI+trunk qualify+通道 四层 ok=5 | 容器+ESL+gateway+呼叫 四层 ok=5 |
|
||||
| Prometheus | ✅ sip 网关 /metrics 开箱 | 需自接 (AMI/ARI 统计) | 需自接 (ESL stats) |
|
||||
| 文档/社区 | 官方文档好, SIP 部分薄 | 文档全, 社区大 (国内资料多) | 文档全但散, 坑多在社区帖 |
|
||||
| 人力画像 | 懂 LiveKit/RTC 的团队 | 懂 Asterisk/传统 VoIP | 懂 FS/传统 VoIP (最资深) |
|
||||
|
||||
## 8. 综合评分 (按本题业务加权)
|
||||
|
||||
权重: 实时语音质量 25% · AI 集成成本 20% · 呼出状态 15% · 扩展性 15% · 稳定性 10% · SIP 对接成本 10% · 运维复杂度 5%
|
||||
|
||||
| 维度 (权重) | LiveKit | Asterisk | FreeSWITCH |
|
||||
|---|---|---|---|
|
||||
| 实时语音 (25%) | 4 | **5** | 4 |
|
||||
| AI 集成成本 (20%) | **5** | 4 | 2 |
|
||||
| 呼出状态 (15%) | 3 | **5** | 4.5 |
|
||||
| 扩展性 (15%) | 4 | 4.5 | **5** |
|
||||
| 稳定性 (10%) | 3.5 (Redis 依赖) | **4.5** | **4.5** |
|
||||
| SIP 对接成本 (10%) | **5** | 4 | 2 |
|
||||
| 运维 (5%) | 3 | **4.5** | 4 |
|
||||
| **加权总分** | **4.05** | **4.55** | **3.75** |
|
||||
|
||||
评分依据全部来自上文实测数据, 非主观打分。如团队已有 LiveKit 体系, AI 集成成本对你们是 0, LiveKit 总分反超为第一。
|
||||
|
||||
## 9. 选型决策树
|
||||
|
||||
```
|
||||
要 AI 实时外呼 (打断/等待)?
|
||||
├─ 已有或规划 LiveKit/RTC 体系?
|
||||
│ └─ YES → LiveKit SIP (复用 agents 框架, 被叫与 RTC 用户同构)
|
||||
├─ 预期并发 > 500 路且偏纯话务?
|
||||
│ └─ YES → FreeSWITCH (单节点容量最大; 接受 SIP UAS 自建 + 7 坑集成成本)
|
||||
└─ 其余大多数情况 → Asterisk ARI
|
||||
(媒体裸 RTP 直连 agent, 状态事件最细, 零共享组件, 4 坑均可一次解掉)
|
||||
```
|
||||
|
||||
## 10. 已知边界与风险
|
||||
|
||||
- **LiveKit**: Redis 强依赖是稳定性短板 (生产需主从); SIP 网关较新, 罕见场景文档薄; 转码 CPU 是容量瓶颈; 挂机原因映射不完整, 精确状态需深挖。
|
||||
- **Asterisk**: VAD/打断全自研 (无 agents 框架级现成品); 未来加呼入需 Kamailio; 单节点 200 路端口段需扩 rtp.conf。
|
||||
- **FreeSWITCH**: 集成成本最高 (agent SIP UAS + ESL 事件自理); safarov 镜像 7 坑; 高并发 ESL 需 bgapi/连接池; mod_audio_fork 类模块要编译, 官方默认构建不含。
|
||||
- **共性**: 三者内核调优一致 (UDP 缓冲已应用); 外呼场景均在呼叫发起侧自调度, 均验证零配置水平扩展; 均需 NAT (ext-ip) 与运营商 digest 认证生产化收尾。
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
三方案对比: livekit-sip 需 Redis 存 trunk/呼叫状态并派发; Asterisk (ARI) 与 FreeSWITCH (ESL) 出站外呼均零共享层, 每呼叫自包含 (originate ×2 + bridge 全在一个节点内闭环), 节点间零交互。实测 1→2 节点**零配置变更** (共用同一套 etc-fs), 呼叫按发起侧选择分摊 (见 §7)。
|
||||
|
||||
瓶颈与边界: ① 单节点容量受 CPU 与 RTP 端口段限制 — vanilla 默认 16384-32768 (约 1.6 万端口, 每桥接呼叫 2 腿各 1 对 RTP+RTCP ≈ 8000 并发/节点, 容器 fd/CPU 先到顶); ② ESL 是单连接同步命令式接口, 高并发控制面需连接池或 bgapi; ③ 无跨节点媒体互通 — 仅外呼场景无影响; ④ 未来要呼入/注册时前置 Kamailio dispatcher, 纯出站不需要。
|
||||
瓶颈与边界: ① 单节点容量受 CPU 与 RTP 端口段限制 — vanilla 默认 16384-32768 (约 1.6 万端口, 每桥接呼叫 2 腿各 1 对 RTP+RTCP ≈ 4000 并发/节点, 实际 CPU/fd 先到顶); ② ESL 是单连接同步命令式接口, 高并发控制面需连接池或 bgapi; ③ 无跨节点媒体互通 — 仅外呼场景无影响; ④ 未来要呼入/注册时前置 Kamailio dispatcher, 纯出站不需要。
|
||||
|
||||
## 2. 架构
|
||||
|
||||
|
||||
Reference in New Issue
Block a user