尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI通话助手从0搭建:ASR+LLM+TTS+拨号全链路实战

AI通话助手从0搭建:ASR+LLM+TTS+拨号全链路实战 如果你关注 AI 语音、本地部署和电话自动化这次我们来拆一个非常有画面感的场景“给他打电话我帮你”。这句话听起来像一句生活服务口号但它背后其实是一类很实际的 AI 通话助手项目用户只需要说一句话系统就能自动发起呼叫接通后用语音合成说话再通过语音识别和大模型生成回复完成一通完整的智能电话对话。它适用在联系人关怀、客户回访、会议通知、团队成员催办以及各类需要重复拨打、批量通知的自动化场景。这类项目的核心能力可以概括成四个模块ASR 语音识别、大模型对话引擎、TTS 语音合成、拨号通话网关。把四个模块串起来以后它就不再是“只会播报语音”的固定脚本而是一个能听、能理解、能自然回复的 AI 电话专员。硬件门槛其实不算夸张。如果只做语音合成和拨号CPU 就能跑如果要接入语音识别和本地大模型建议准备一张显存不太低的 NVIDIA 显卡或者使用在线的 ASR 和 LLM API。比较实用的做法是“本地 TTS 在线大模型 本地语音识别”的混合部署性能要求更灵活也能兼顾隐私和响应速度。本文会完整拆解这套 AI 通话助手的搭建思路先给核心模块清单再讲环境准备和部署启动接着做功能测试、API 调用和批量任务演示最后给出资源占用观察方法和常见问题排查表。无论你是要做智能客服、个人自动化助手还是研究语音链路这篇文章都能给你一套可落地的验证路径。1. AI 通话助手核心能力速览先给一张速览表后面所有操作都围绕这些能力展开。能力项说明项目类型AI 语音电话助手覆盖拨号、通话、语音识别、对话生成、语音合成核心模块ASR 语音识别 LLM 对话引擎 TTS 语音合成 拨号通话网关主要功能一句话拨号、智能对话、批量外呼、通话录音、接口集成推荐硬件CPU 可跑基础模块ASR 和本地 LLM 建议搭配 NVIDIA GPU显存占用取决于所选模型常见配置从低到高都有需按本机实际测试支持平台Windows / Linux / macOS拨号侧涉及 SIP 网关或 Android 设备启动方式分模块命令行启动也可封装为整合脚本一键拉起API 支持TTS、ASR、LLM 均可封装为 HTTP 接口支持业务系统调用批量任务支持按名单批量外呼但必须满足合法授权和通信管理要求适合场景联系人关怀、业务回访、智能客服、个人自动化、开发者研究从这张表可以看出这个项目真正有价值的地方不是单个模块而是把语音识别、对话生成、语音合成和真实电话线路串成一条完整链路。单独听 ASR、TTS 都会真正难的是在“电话音质”和“实时对话”这两个限制条件下面把链路跑稳定。2. 适用场景与使用边界2.1 适合谁这类 AI 通话助手最合适的用户有三类第一类是开发者想研究语音链路或做智能语音 Demo。通过这个项目可以把 ASR、LLM、TTS、SIP 四条技术栈串起来理解一通电话在软件里到底经历了什么。第二类是业务运营人员需要做大规模回访、通知、满意度调查。传统人肉打电话效率低AI 通话助手可以做名单导入、批量外呼、自动记录通话结果。第三类是个人自动化玩家想给手机或电脑加一个“语音秘书”。比如设置一个快捷键对着麦克风说“给老王打个电话”系统识别后自动拨号或者先发一条语音消息。2.2 不适合什么如果要做“未授权营销电话”这个项目不适合。自动外呼在通信管理上非常敏感运营商和监管对高频外呼、营销号码有明确限制没有资质或授权的情况下批量外呼轻则号码被封重则涉及违规。做技术研究可以直接拿去打骚扰电话绝对不行。另外如果要做“冒充真人”的客服或诈骗电话更不适合。合规的做法是在通话开头明确提示“本次通话由 AI 助理发起”录音也必须在通话双方知情的前提下保存。这个边界一定要守住。2.3 边界提醒涉及人脸、声音、通信号码等敏感信息时必须遵守以下原则通话双方必须知情并同意录音。外呼对象必须是授权名单不能从黑灰色渠道购买号码。不能利用 AI 合成声音冒充他人。不能把通话能力用于绕过验证码、窃取账号、破坏系统等行为。上线前建议做法律合规评估尤其是面向真实用户的外呼场景。写代码容易边界控制才是工程化落地里最容易被忽视的部分。下面的部署和测试步骤默认前提是“本人设备测试”或“已获得明确授权的联系人测试”。3. 环境准备与前置条件3.1 基础环境真实项目通常由多个开源组件拼接而成建议先准备一个干净的基础环境。下面是一份通用检查清单实际版本号需要按你选用的具体组件来调整。检查项建议操作系统Windows 10/11、Ubuntu 20.04/22.04、macOS 均可Python3.9 或 3.10 较稳妥音频依赖FFmpeg、PortAudio、麦克风/声卡驱动GPU 驱动NVIDIA 驱动需支持 CUDA通话线路SIP 软电话账号或 Android 手机开启 ADB 自动化磁盘空间ASR 模型和本地 LLM 模型合计可能占用数十 GB需预留充足空间3.2 组件选型通话助手不是单一仓库而是组合方案。这里有几种常用选型功能可选方案说明ASR 语音识别faster-whisper、FunASR支持本地部署中文效果较好对话引擎 LLMQwen、ChatGLM 或在线大模型 API本地部署需要 GPU在线 API 更省资源TTS 语音合成CosyVoice、GPT-SoVITS、edge-tts本地模型效果好在线接口更轻量拨号模块SIP 软电话、Android ADB 自动拨号负责真正把电话打出去选型时建议遵循一个原则第一次跑通链路优先选“部署最简单”的方案。比如 TTS 先用在线接口或小模型ASR 先用 faster-whisper 的 base 或 small 模型LLM 先用 API 或量化小模型。链路通了之后再逐步替换成效果更好的模型避免一开始被环境问题劝退。3.3 安装基础依赖下面是一个通用安装示例具体包名和版本请以实际项目为准。# 创建虚拟环境 python -m venv ai-call-env source ai-call-env/bin/activate # Windows 下使用 ai-call-env\Scripts\activate # 安装基础依赖 pip install --upgrade pip pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu118 pip install faster-whisper edge-tts requests sounddevice pyaudio# 检查 FFmpeg 是否可用 ffmpeg -version如果 FFmpeg 缺失需要单独安装并确保ffmpeg命令能在终端直接运行否则 ASR 处理音频时会报错。4. 安装部署与启动方式这一部分我们把四个模块分开启动。先跑通单个模块再连链路。4.1 启动 ASR 语音识别服务先验证语音识别模块。以 faster-whisper 为例可以起一个最简单的本地服务# asr_server.py from faster_whisper import WhisperModel model WhisperModel(small, deviceauto, compute_typeint8) def transcribe(audio_path: str): segments, info model.transcribe(audio_path, languagezh) text .join(segment.text for segment in segments) return text if __name__ __main__: print(transcribe(test_audio.wav))启动方式很简单python asr_server.py如果终端能打印出识别文本说明 ASR 模块可以工作。实际部署时可以把它封装成 HTTP 服务提供给上层调用。4.2 启动 TTS 语音合成服务语音合成可以直接使用边缘接口快速验证。以 edge-tts 为例可以先这样测试# 生成一句测试语音 edge-tts --voice zh-CN-XiaoxiaoNeural --text 你好我是你的 AI 电话助理 --write-media test_output.mp3如果希望用本地模型可以运行 CosyVoice 或 GPT-SoVITS 的 WebUI 或 API 服务。不同项目的启动命令差异较大以项目自带脚本为准。4.3 启动大模型对话引擎对话引擎是决定通话质量的关键。本地部署可以使用 Qwen 或 ChatGLM 系列通常需要通过对应项目的启动脚本加载模型并开放接口。这里给出一个通用调用思路# llm_client.py import requests def chat(question: str, history: list None): # 这是示例接口地址实际地址需要按你部署的 LLM 项目调整 url http://127.0.0.1:8000/v1/chat/completions payload { model: local-llm, messages: [ {role: system, content: 你是一个电话助理请用简洁、礼貌的语气回答用户。}, {role: user, content: question} ] } response requests.post(url, jsonpayload, timeout60) return response.json()[choices][0][message][content]4.4 启动拨号通话模块拨号模块有两条路线。路线一是 SIP 软电话。先注册一个 SIP 账号然后用 pjsua 或 Linphone 命令行发起呼叫# 使用 pjsua 命令行发起呼叫的示意实际参数按 SIP 服务商提供的信息填写 pjsua --id sip:your_accountyour_provider --registrar sip:your_provider --username your_username --password your_password sip:callee_numberyour_provider路线二是 Android 设备 ADB 自动化。手机开启 USB 调试后可以用 ADB 调起拨号界面adb shell am start -a android.intent.action.CALL -d tel:10086这条命令会直接在手机上拨号适合做个人自动化测试。注意只对授权号码进行测试。4.5 整合链路四个模块都单测通过后写一个调度脚本。链路顺序是收到指令 - TTS 播报 - 对方说话 - ASR 识别 - LLM 生成回复 - TTS 继续播报。def run_call_loop(call_duration_seconds: int 30): # 伪代码示意重点是链路顺序 # 1. 通过 SIP 或 ADB 拨号 dial() # 2. 播放开场白 play_audio(tts(您好我是 AI 通话助理本次通话将被录音。)) # 3. 循环监听、识别、生成回复 while time_elapsed call_duration_seconds: audio record_audio(segment_duration2) user_text asr(audio) if not user_text: continue reply llm(user_text) play_audio(tts(reply)) # 4. 挂断 hangup()这就是整个项目的主流程。实际工程里需要加上状态机处理静音、打断、超时、重复播放等情况但骨架就是上面这六步。5. 功能测试与效果验证5.1 TTS 合成测试测试目的确认语音合成可以生成清晰、自然、可播放的音频文件。操作步骤准备一段测试文本。调用 TTS 生成音频。手动播放或使用程序播放音频。检查是否存在明显断句、噪音、吞音问题。判断成功标准音频文件能正常播放文本内容完整语速适中。常见失败原因音频编码不兼容、网络接口超时、本地模型未正确加载。5.2 ASR 识别测试测试目的确认系统能识别电话音质下的中文语音。操作步骤准备一段带背景噪音的电话录音。用 ASR 模型转写。对比人工转写结果。判断成功标准核心关键词识别正确整句通顺没有大规模的识别串词。常见失败原因采样率不匹配、音频格式错误、模型过小导致准确率不足。电话线路常用 8kHz 采样率如果模型对低采样率不友好需要先做重采样。5.3 对话链路测试测试目的验证 ASR、LLM、TTS 能串成完整问答。操作步骤用文字模拟用户输入“请问你们几点下班”。经 LLM 生成回答。将回答转为 TTS 音频。判断成功标准文本语义合理语音输出自然延迟控制在可接受范围内。常见失败原因LLM 返回超时、返回内容过长导致 TTS 播报冗长、上下文没有传递导致答非所问。5.4 真实拨号测试这是最需要谨慎的测试。只允许拨打以下号码自己的另一个手机号。已明确授权测试的同事或朋友号码。测试运营商回声测试号码。操作步骤启动拨号模块。呼叫测试号码。接通后检查 AI 开场白是否正常。对方说话后检查 ASR 是否能识别。检查 LLM 回复和 TTS 播报是否完整。判断成功标准接通率达 100%语音清晰可辨对话流程能自动化跑完一轮以上。常见失败原因SIP 账号配置错误、网络对 RTP 音频端口限制、Android 权限未开启、通话音频路由被系统打断。5.5 批量外呼测试批量测试前必须确认名单合法。操作步骤准备 10 个以内的授权测试号码 CSV 文件。用脚本逐条读取名单。对每个号码发起呼叫。记录每条通话的成功、失败、未接状态。判断成功标准脚本能按名单顺序执行不遗漏不重复失败记录可回溯。常见失败原因并发数过高导致线路占线、号码格式不标准、网络超时未释放资源。6. 接口 API 与批量任务真实业务系统不可能直接操作 Python 对象所以要把通话能力封装成 HTTP 接口。6.1 接口设计一个最小可用的通话接口包含参数类型说明callee_phonestring被叫号码caller_idstring主叫号码标识scriptstring开场白脚本max_durationint最大通话时长单位秒callback_urlstring通话结束后的回调地址请求示例{ callee_phone: 13800138000, caller_id: 4001234567, script: 您好这里是 AI 回访助理想了解您最近的使用体验。, max_duration: 60, callback_url: http://your-server.com/call_callback }6.2 Python 调用示例这里给出通用 API 调用模板实际接口路径和请求参数需要按你的服务调整。import requests url http://127.0.0.1:8080/api/agent/call payload { callee_phone: 13800138000, caller_id: 4001234567, script: 您好这里是 AI 回访助理。, max_duration: 60, callback_url: http://your-server.com/call_callback } try: response requests.post(url, jsonpayload, timeout30) data response.json() print(call_id:, data.get(call_id)) print(status:, data.get(status)) except requests.exceptions.Timeout: print(请求超时请检查通话服务状态) except Exception as e: print(调用失败:, e)返回结果设计可以包含{ call_id: call_20250101_001, status: queued, message: 任务已进入队列 }6.3 批量任务队列设计批量外呼最容易出的问题不是模型效果而是任务调度。建议把任务拆成三层第一层是名单层用 CSV 或数据库存储号码、备注、状态。phone,remark,status 13800138000,授权回访,pending 13900139000,授权回访,pending 13700137000,未授权,skip第二层是队列层每一次呼叫生成一个任务对象持有pending、ringing、completed、failed四种状态。第三层是调度层控制并发数。优先从 1 到 2 路并发开始跑稳以后再逐步增加。并发过高会导致线路模块崩溃、网络拥塞、号码被限制。import time import threading class CallQueue: def __init__(self, max_concurrent2): self.queue [] self.max_concurrent max_concurrent self.active 0 def add(self, call_task): self.queue.append(call_task) def worker(self): while self.queue: task self.queue.pop(0) self.active 1 try: # 这里调用真实通话接口 result task.execute() print(call done:, result) except Exception as e: print(call failed:, e) finally: self.active - 1 time.sleep(1) def start(self): threads [] for _ in range(self.max_concurrent): t threading.Thread(targetself.worker) threads.append(t) t.start() for t in threads: t.join()批量任务要做失败重试但重试次数建议控制在 2 次以内并且对“未接”和“通话失败”做不同处理。未接可以延后再次呼叫通话失败则优先排查线路配置。7. 资源占用与性能观察7.1 显存和内存观察方式本地跑 ASR 和 LLM 时显存占用是核心指标。观察方式nvidia-smi -l 2在 Linux 下也可以用top或htop观察内存。Windows 下打开任务管理器在“性能”标签里看 GPU 专用内存。需要强调一点显存占用不是固定值它跟模型大小、量化精度、推理批次、输入音频时长、并发路数都有关。同一个模型在不同框架下显存占用也可能差一倍。所以看到任何博客给出具体数字都只能作为参考最终还是要以本机实测为准。7.2 CPU 推理与 GPU 推理的差异CPU 推理的优势是兼容性好、部署简单不需要安装 CUDA 环境劣势是延迟高尤其在 whisper 这类模型上几秒钟的音频可能需要十几秒才能完成转写很难满足实时通话要求。GPU 推理的优势是速度快能够支撑流式识别和实时对话劣势是需要额外配置驱动和显存并且模型切换时存在加载开销。推荐做法ASR 和本地 LLM 放 GPUTTS 放 CPU 或单独进程避免长时间占用显存。7.3 影响性能的关键参数参数影响ASR 模型尺寸模型越大准确率越高延迟和显存占用也越高LLM 上下文长度上下文越长生成延迟越高TTS 音频长度每次合成文本越长等待时间越久并发路数并发增加CPU、内存、网络带宽呈线性上升采样率电话音频 8kHz 转写延迟低于 44.1kHz但准确率可能下降音频编码压缩格式会增加解码开销7.4 降低延迟和资源占用的方法精简思路如下ASR 优先选 small 或 base 模型先跑通再换大模型。LLM 使用量化版本优先保证首字延迟低。TTS 在接通前预生成开场白音频避免拨通后再等合成。同一时间只跑一路真实通话压测再用多路。使用流式 ASR按片段识别而不是等整段说完。定期重启长驻服务释放内存碎片。8. 常见问题与排查方法这里整理一张排查表基本覆盖从安装到拨号的常见故障。问题现象可能原因排查方式解决方案启动 ASR 报错 CUDA out of memory模型过大或显存不足nvidia-smi 查看显存占用换更小的模型或使用 int8 量化ASR 识别结果为空音频路径错误或采样率不匹配检查输入文件格式统一转成 16kHz 或 8kHz WAVTTS 合成没有声音音频设备问题或生成文件损坏播放生成文件确认检查文件编码重新安装音频驱动LLM 回答超时模型未加载完成或请求队列阻塞检查服务日志重启 LLM 服务降低并发SIP 拨号失败账号配置错误或端口未开放查看 SIP 注册日志核对 SIP 地址、账号、密码ADB 自动拨号无反应手机未开启 USB 调试adb devices 检查设备开启开发者选项并授权通话中听不到 AI 声音音频路由错误检查声卡设备在 SIP 客户端里选择正确的麦克风/扬声器批量任务卡住单路通话未超时释放检查任务状态给每次呼叫加最大超时时间接口调用超时通话服务未启动或端口错误curl 检查接口连通性确认服务进程存在端口未被占用输出音质差麦克风质量差或网络抖动录制测试音频回放更换设备或改用 SIP 服务器转发对方反馈 AI 太机械提示词设计不合理查看对话日志优化 system prompt增加场景示例号码被运营商限制外呼频率过高查看通话记录降低外呼频率检查号码资质9. 最佳实践与使用建议9.1 先小参数测试第一次部署不要把目标定成“完美电话秘书”。先做一件小事用 TTS 生成一句话再用 ASR 把这句话识别回来。这个方法能快速验证环境、音频、模型链路是否正常比直接拨号调试要快得多。9.2 保留最小可运行配置把已经跑通的依赖版本和启动命令记录下来保存成一份requirements.txt和start.sh。后续改模型、改代码时如果改坏了随时可以回滚到最小可运行版本。9.3 分目录管理文件建议目录结构ai-call-assistant/ ├── models/ │ ├── asr/ │ └── llm/ ├── audio/ │ ├── inputs/ │ └── outputs/ ├── config/ │ ├── config.yaml │ └── .env ├── data/ │ ├── call_records/ │ └── batch_lists/ ├── logs/ └── src/ ├── asr_service.py ├── tts_service.py ├── llm_service.py └── call_controller.py模型、输入音频、输出结果、日志分目录管理排查问题时能省很多时间。9.4 批量任务必须加日志和重试批量外呼的日志至少要记录号码、呼叫时间、接通状态、通话时长、失败原因、重试次数。没有日志的批量任务等于盲跑出问题无法回溯。9.5 接口服务限制访问范围通话接口涉及真实验呼能力默认只监听127.0.0.1。如果需要给局域网其他服务调用要加 IP 白名单和鉴权。不要把通话接口直接暴露到公网。9.6 合规红线不能碰再强调一次涉及人脸、声音、通信号码时必须确认合法授权。不能拿别人的语音克隆、不能骚扰号码、不能冒充客服。如果你使用的 TTS 模型支持声音克隆务必只克隆自己或已授权人的声音。10. 总结与下一步这个项目最值得尝试的点是把 ASR、LLM、TTS 和真实拨号链路打通。单独看每一个模块都成熟但组合在一起会面临音频格式、通话延迟、上下文管理、并发调度等一系列工程问题。能跑通一通完整电话你对整个语音链路就会有非常直观的理解。建议最先验证的功能不是拨号而是“TTS 生成音频 ASR 识别音频”这个小闭环。这个闭环通了整个项目就算是成功了一半。之后再逐步加入 LLM 和拨号模块不要一步到位。最容易踩的坑有三个一是音频采样率不统一导致识别失败二是 SIP 端口被防火墙拦截导致拨号无声三是批量外呼时并发过高把号码跑进限制名单。这三个问题在路径中都有对应排查方法。后续扩展方向可以考虑接入流式 ASR 降低对话延迟用 RAG 给 LLM 补充业务知识库增加通话结束后的分析摘要把批量外呼任务接入消息队列提供更稳定的调度能力。如果你只需要“一句话拨号”这种轻量功能也可以基于 ADB 或手机快捷指令单独实现不必跑完整链路。文章内容到这里结束建议先在本地测试环境把链路跑通再考虑接真实电话线路。
返回列表