# 大模型 AI 语音机器人(拨 2000)设计说明
## 目标
- 当任何用户在 default 上下文拨打 2000 时,进入 AI 机器人应答流程。
- 初版:接听并播放欢迎提示,留出后续扩展的对话循环接口;呼叫结束时挂断。
- 迭代:集成实时 ASR(语音转文字)、LLM(对话)、TTS(语音合成),实现连续多轮对话。
## 架构选型
- 路由入口:FreeSWITCH Dialplan(XML),目的号码 2000。
- 呼叫控制:mod_httapi(HTTP Telephony API)。
- 拨号计划调用 `httapi`,由本地 HTTP 服务返回 HTTAPI XML 指令。
- 好处:呼叫逻辑在应用层,易于快速迭代、灰度和观测。
- 语音 IO:
- 初版使用播放提示(playback)+ 挂断。
- 完整版可用以下之一:
- DTMF/收号驱动交互(HTTAPI 的 bind + playback)。
- 录音 + 轮询识别(HTTAPI 上传,再调用 ASR)。
- 实时媒体:
- 使用 mod_rtc / mod_verto / mod_sofia + 外部媒体桥接到 WebSocket/UDP,驱动流式 ASR/TTS。
- 或使用外部媒体服务器(如 SignalWire/Janus/rtpengine)桥接。
## 调用流程(2000)
1. 终端注册(alice/bob/1001/1002 等)→ user_context=default。
2. 拨 2000 → 命中 `conf/dialplan/default/200-ai-bot.xml`。
3. 执行 ``。
4. HTTAPI 服务(本地脚本)返回 XML:
- 初版:`answer` → 可选 `playback` 提示 → `hangup`。
- 循环:HTTAPI 每执行完一批 `` 会再次请求,直到 `` 或 ``。
## HTTAPI 返回格式要点
- Content-Type 必须是 `text/xml`。
- 文档根:``,包含可选 `` `` 和必需 ``。
- `` 内支持:`playback`、`pause`、`speak`、`say`、`record`、`execute`(应用调用)、`dial`、`hangup`、`break` 等。
- 权限:`httapi.conf.xml` 的 profile 要允许所需动作(如 `execute-apps` 内允许 `answer`、`playback`)。
## 组件与文件
- Dialplan:`conf/dialplan/default/200-ai-bot.xml`(匹配 2000 → httapi)。
- HTTAPI 配置:`conf/autoload_configs/httapi.conf.xml`(允许 answer/playback)。
- 应用服务(示例):`scripts/ai_bot/server.py`(纯标准库 HTTP 服务器,返回 HTTAPI XML)。
- 文档:本文件与 `scripts/ai_bot/README.md`。
## 环境变量/配置
- 服务监听:`0.0.0.0:18080`(开发环境),路径 `/ai-bot`。
- 可在 dialplan 的 `httapi` data 中改为其他 URL。
- 生产建议:
- 使用 Unix 内网地址、HTTPS、鉴权/白名单。
- 反向代理(nginx)限流、TLS 终止。
## 开发步骤
1. 启用并配置 mod_httapi(确认模块存在且加载,调整权限允许运行 `answer`、`playback`)。
2. 新增拨号计划 `200-ai-bot.xml`,匹配号码 2000,路由至 `httapi`。
3. 编写 HTTAPI 示例服务:
- 初版:返回 `answer → playback(欢迎语) → hangup`。
- 预留:下一次请求识别用户输入、调用 LLM、合成 TTS。
4. 重新加载配置并验证:
- 在 FreeSWITCH 控制台:`fs_cli -x reloadxml`
- 启动 HTTAPI 服务:`python3 /usr/local/freeswitch/scripts/ai_bot/server.py`
- 通过分机拨 2000,观察是否接听并播放提示,然后挂断;在 `fs_cli` 查看 `mod_httapi` 日志。
## 未来演进(AI 能力)
- ASR:接入云厂商或开源(Vosk/Whisper/faster-whisper),实时/非实时两种模式。
- LLM:HTTP API(OpenAI/自建 vLLM/LLama.cpp),维护对话状态与摘要。
- TTS:云 TTS 或本地引擎(eSpeak, Coqui TTS, Piper,或 FreeSWITCH TTS 插件)。
- 实时:
- 通过外部媒体(mod_rtc + WebSocket Gateway)实现双工流式音频,用 LLM Realtime API 实现自然对话。
- 健壮性:超时、重试、降级(改为 IVR 菜单或留言)、回落到人工坐席。
- 监控:
- FreeSWITCH CDR、channel vars、HTTAPI 服务访问日志、时延分布。
- 关键指标:ASR 成功率、轮次、平均响应时延、用户满意度。
## 测试与运维
- 测试:
- 本地注册两个分机,互拨后拨 2000。
- 观察 `log/freeswitch.log`、`fs_cli` 中 HTTAPI 请求日志。
- 运维:
- HTTAPI 服务以 systemd/pm2/supervisor 管理。
- 声音文件缓存(mod_http_cache 或本地化音频)。
- 配置版本化与灰度(新建 `210-ai-bot-v2.xml`,逐步切换)。
## 我打算将 asr、llm、tts 等在另外一个服务 中使用 spring boot 框架搭建,是否可行?
可行,而且是常见落地方案;建议按“先易后难、分层解耦”的思路把 Spring Boot 服务做成对话中枢,FreeSWITCH 只负责媒体采集/播放与会话驱动。
## 两种主线路架构
- 方案A:非实时(最快上线)
- 流程:FS 通过 HTTAPI 驱动交互 → 每轮“说话”用 录音到 WAV → Spring Boot 接口接收音频做 ASR → 调 LLM → 调 TTS 生成 WAV/HTTP 地址 → HTTAPI 返回下一步指令 playback 该音频。
- 依赖与对接:
- FreeSWITCH:mod_httapi(已启用)、mod_sndfile(WAV 播放)、mod_curl/HTTP 文件可选(若要回放 HTTP 音频,推荐 mod_http_cache 或将 TTS 产物落到可访问的 HTTP 存储)。
- Spring Boot:提供 REST 接口(上传录音/返回文本、TTS 产物 URL)。
- 优点:实现简单、易调试;缺点:交互有回合延迟(录音-识别-合成)。
- 方案B:实时双工(更自然)
- 流程:话路媒体实时流式送入 Spring Boot;ASR/LLM 在线推理,TTS 流式回放。
- 对接方式(任选其一):
- WebSocket 音频分流:安装 mod_audio_fork(或等价 WS/UDP 音频 fork 模块),将 16k PCM/Opus 流推送到 Spring Boot WebSocket;服务端回推 TTS 切片,FS 端以广播/插入方式实时播放。
- MRCP 路线:用 UniMRCP(mod_unimrcp)对接第三方 ASR/TTS,Spring Boot 做编排与业务(非必须自己算子)。
- SIP/媒体网关:通过外部媒体服务器(Janus/rtpengine/SignalWire Realtime)桥接到 Spring Boot 的 WS/gRPC。
- 优点:低时延、体验好;缺点:工程复杂度与模块依赖更高。
## Spring Boot 服务职责和接口“契约”
- 统一会话编排
- 输入:会话 id(FS uuid/sip_call_id)、来电号码、轮次、音频切片/录音 URL、用户文本(如 DTMF)。
- 输出:本轮回复(文本)、TTS 音频(URL 或流)、下一步策略(继续/挂断/转人工)。
- ASR
- 非实时:POST /asr transcribe,body=音频URL/上传;返回 text、时间戳。
- 实时:WS /asr-stream,客户端发送 PCM/Opus 帧,服务端持续推送部分转写与最终转写。
- LLM
- POST /llm/chat,输入对话上下文(对话 id、角色消息、工具调用结果),返回回复文本与函数调用意图(可选)。
- TTS
- 非实时:POST /tts synthesize,输入 text、voice、format=wav 16k;返回音频URL。
- 实时:WS /tts-stream,输入 TTS 文本片段,回推音频帧。
- 观测
- 所有接口接受 trace-id 与 FS uuid;返回时附带 RT、token 用量(如有)、错误码。
建议媒体参数
- 采样:16 kHz、单声道、PCM s16le(或 Opus 16k)
- 容器:WAV(便于 FS 直接 playback)
- 时延目标:非实时 0.8–1.5s/轮;实时端到端 < 300ms
## 与 FreeSWITCH 的集成点
- 你当前已用 HTTAPI 驱动(拨 200x → /ai-bot),完全可以把 Spring Boot 路由放在 HTTAPI 背后:
- 版本1(非实时):HTTAPI 返回 work 序列:record → HTTP 回调给 Spring Boot → playback TTS URL → 循环/挂断。
- 如需回放 HTTP 音频:启用 mod_http_cache 或将文件先落本地再 playback。
- 实时优化可选:
- 安装/启用 mod_audio_fork(WebSocket 分流),由 Spring Boot 消费流式音频;TTS 回放可通过 uuid_broadcast 注入已合成的短片段(200–500ms 切片),或用支持回传的双工插件。
- 也可考虑 UniMRCP 方案,Spring Boot 只做业务与策略,ASR/TTS 交给 MRCP 服务。
### Qwen-Audio-Realtime 电话接入状态
- 9205 当前是已验证的 HTTAPI 回合制兜底:record → 后端调用 Qwen-Audio-Realtime → TTS WAV playback → 继续循环。它会持续到客户挂断,但不是实时双工媒体。
- 真正实时双工的后端入口已预留:`/visitor/api/v1/call/voice-agent/qwen-realtime/media`。
- 下行客户端到 Spring Boot:WebSocket binary frame,16 kHz、mono、PCM s16le。
- 上行 Spring Boot 到客户端:Qwen `response.audio.delta` 解码后的 binary PCM 帧,同时用 text frame 转发 Qwen 事件。
- 可选 text 控制帧:`{"type":"commit"}` 提交当前输入并请求响应,`{"type":"response.create"}` 单独请求响应,`{"type":"end"}` 关闭桥。
- 当前 `freeswitch-bytedesk` 容器只加载了 `mod_event_socket`、`mod_httapi`、`mod_sofia`、`mod_unimrcp` 等模块,未加载 `mod_audio_fork` / `mod_audio_stream`。因此不能只靠拨号计划完成电话媒体实时双工;需要先在 FreeSWITCH 镜像中安装/启用一个支持双向 WebSocket 音频的模块,再把该模块连接到上述后端 WebSocket。
- 如果选用只支持单向 fork 的模块,TTS 回灌还需要通过 ESL/`uuid_broadcast` 注入短音频片段;如果选用支持双向 audio stream 的模块,应直接消费后端返回的 binary PCM 帧。
9205 已接入一个默认关闭的实时媒体桥分支:
- 默认:`qwen_realtime_media_bridge_enabled=false`,9205 继续走 HTTAPI 回合制兜底。
- 启用:安装并加载 `mod_audio_stream` 后,将 `qwen_realtime_media_bridge_enabled=true`,或在 Docker 环境中设置 `FREESWITCH_QWEN_REALTIME_MEDIA_BRIDGE_ENABLED=true`。
- WebSocket:默认 `qwen_realtime_media_ws_url` 指向 Spring Boot 的 `/visitor/api/v1/call/voice-agent/qwen-realtime/media`。电话桥接专用端点会在后端默认切换为 `mod_audio_stream` 输出并关闭事件回传。
- 拨号计划:9205 实时分支通过 `api_on_answer=uuid_audio_stream ${uuid} start ... mono 16k ...` 启动媒体桥,然后 `park` 保持通话直到客户挂断。
- 后端返回给 `mod_audio_stream` 的播放帧格式为 `{"type":"streamAudio","data":{"audioDataType":"raw","sampleRate":24000,"audioData":"...base64..."}}`。
## 安全与可靠性
- 认证:HTTAPI 服务器与 Spring Boot 互相鉴权(JWT/TLS 双向),限制来源 IP。
- 重试与降级:ASR/TTS 失败→改 IVR 菜单/回放提示;LLM 超时→返回静态兜底文案。
- 音频缓存:短音频 CDN/本地缓存,避免重复下载;设置缓存控制。
- 监控:以 FS uuid 关联 CDR(你已启用 mod_odbc_cdr),在 Spring Boot 侧记录每轮 ASR/LLM/TTS 时延与错误。
## 最小可行落地路径(建议)
1) 延续现状(HTTAPI 编排)
- Spring Boot 暴露:
- POST /asr(收录音 URL)
- POST /tts(回 URL)
- POST /ai-bot(返回 HTTAPI XML 或业务 JSON,由现有 HTTAPI 服务做翻译)
- HTTAPI 流程:answer → record(5–10s 或端点检测)→ 调 ASR/LLM/TTS → playback(TTS URL) → repeat
- 先做到业务通顺、可观测,后续再引入实时流。
1) 准备实时能力(并行推进)
- 评估/部署 mod_audio_fork 或 UniMRCP;在 Spring Boot 增加 WS/gRPC 流处理通道。
- 把“首句识别”和“打断播放(barge-in)”作为第一批实时特性。
结论:用 Spring Boot 搭 ASR/LLM/TTS 服务完全可行,且与你当前基于 HTTAPI 的编排天然契合;建议先走非实时录音-识别-合成的闭环快速上线,随后迭代接入流式通道以优化时延与体验。如果你定了第一版接口形态,我可以直接更新 HTTAPI 服务与拨号计划、并给出 Spring Boot 控制器示例骨架。