PraisonAI Call Docker:用 Docker 部署基于 Twilio + OpenAI Realtime 的 AI 语音呼叫服务器
【免费下载链接】PraisonAIPraisonAI 🦞 — Hire a 24/7 AI Workforce. Stop writing boilerplate and start shipping autonomous self-improving agents that research, plan, code, and execute tasks. Deployed in 5 lines of code with built-in memory, RAG, and support for 100+ LLMs.项目地址: https://gitcode.com/GitHub_Trending/pr/PraisonAI
本文以仓库 docker/call/README.md 为核心骨架,讲解如何基于 docker/call/Dockerfile 构建并运行 PraisonAI 的语音呼叫服务器(praisonai call)。读完本文,你将掌握镜像构建、容器启动、API Key 注入、常用环境变量调优,以及该服务器从「来电 → Twilio 媒体流 → OpenAI Realtime API → 语音回复」的完整运行原理,并了解如何在容器中为其叠加自定义工具与安全限流能力。
一、PraisonAI Call 是什么
PraisonAI 提供了一整套「AI 员工」运行时,其中call子命令(CLI 入口定义于 src/praisonai/praisonai/pyproject.toml 中的praisonai-call = "praisonai.api.call:main")实现的是一个可接听真实电话的 AI 语音助手服务器:
- 通过Twilio接收来电,并把电话音频桥接到 WebSocket 媒体流;
- 通过OpenAI Realtime API(WebSocket)完成语音识别、语音合成与对话生成;
- 最终把 AI 的语音回复原路传回电话另一端。
也就是说,你只需要一个 Twilio 电话号码 + 一个 OpenAI API Key,就能让 AI 7×24 小时接电话。该功能的核心实现在 src/praisonai/praisonai/api/call.py,而 docker/call/ 目录则是它的官方容器化入口。
二、构建 PraisonAI Call 镜像
官方文档给出的构建命令非常简单:
docker build -t praisonai-call .在docker/call/目录下执行即可生成名为praisonai-call的镜像。其背后 Dockerfile 的关键步骤如下:
- 基础镜像:使用
python:3.11-slim,保证镜像体积小、攻击面少; - 环境预设:设置
PYTHONDONTWRITEBYTECODE=1(不落盘.pyc)与PYTHONUNBUFFERED=1(日志实时输出),便于容器化日志收集; - 系统依赖:安装
build-essential,为后续编译型 Python 依赖(如 flaml/automl 相关包)提供编译工具链,安装后清理 apt 缓存; - 安装 PraisonAI:执行
pip install --no-cache-dir --upgrade "praisonai[call]",即安装带callextra 的最新版 PraisonAI。根据 src/praisonai/praisonai/pyproject.toml,callextra 会额外引入twilio、fastapi、uvicorn、websockets、pyngrok、rich以及flaml[automl]等依赖——这正是运行语音呼叫服务所需的完整依赖集; - 暴露端口:
EXPOSE 8090,与服务器默认监听端口一致; - 启动命令:
CMD ["praisonai", "call"],容器启动即运行语音呼叫服务器。
三、运行 PraisonAI Call 容器
官方 README 给出的运行命令为:
docker run -d -p 8090:8090 praisonai-call -e OPENAI_API_KEY=your_api_key_here需要特别指出:文档中的命令存在一处笔误——-e是docker run的环境变量参数,必须放在镜像名之前,正确的写法是:
docker run -d -p 8090:8090 -e OPENAI_API_KEY=your_api_key_here praisonai-call请务必将your_api_key_here替换为你真实的 OpenAI API Key。由于 call.py 在启动时会校验OPENAI_API_KEY是否存在(缺失则抛出ValueError: Missing the OpenAI API key...),因此这个环境变量是必需项,并且要求该 Key 具备 OpenAI Realtime API 的访问权限。
启动后,可通过http://localhost:8090/或/status访问服务器首页(返回 "Praison AI Call Server is running!" 的 HTML 页面),以此验证容器已正常运行。
除 Docker 方式外,也可直接用 CLI 启动等效服务(仅本机开发场景):
praisonai call --port 8090 --host 127.0.0.1CLI 支持的参数与对应环境变量如下(见 call.py):
| CLI 参数 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
--port | PORT | 8090 | 监听端口 |
--host | — | 127.0.0.1 | 绑定地址(使用--public时自动改为0.0.0.0) |
--public | PUBLIC=true | false | 通过 ngrok 暴露公网地址,便于 Twilio 回调 |
四、关键环境变量配置
除了OPENAI_API_KEY,从源码 call.py 可以整理出以下可直接通过docker run -e注入的配置项:
| 环境变量 | 默认值 | 作用 |
|---|---|---|
OPENAI_API_KEY | 无(必填) | OpenAI API Key,需具备 Realtime API 权限 |
PORT | 8090 | 服务器监听端口 |
PUBLIC | false | 设为true时启用 ngrok 公网隧道 |
NGROK_AUTH_TOKEN | 无 | ngrok 账户令牌,用于自定义域名/固定隧道(call.py) |
CALL_SERVER_TOKEN | 无(建议必设) | 来电与媒体流接入的共享认证令牌,未配置时/路由直接返回 503 |
MAX_CONCURRENT_CONNECTIONS | 5 | 同时最大活动通话数,超限返回 1013 |
MAX_REQUESTS_PER_WINDOW | 100 | 单个 IP 每小时最大连接数,超限返回 4029 |
PRAISONAI_REALTIME_URL | 无 | 自定义 Realtime WebSocket 地址(可指向 Azure/自建网关,优先于默认值) |
PRAISONAI_REALTIME_MODEL | gpt-4o-realtime-preview-2024-10-01 | 默认 OpenAI 端点使用的实时模型 |
PRAISONAI_REALTIME_API_KEY | 取OPENAI_API_KEY | Realtime 端点的 Bearer Key |
PRAISONAI_CALL_PUBLIC_BASE | 无(生产必须配置) | 对外可访问的wss://媒体流基地址,Twilio 据此回连媒体流 |
PRAISONAI_ALLOW_LOCAL_TOOLS | false | 设为true才允许加载工作目录下的tools.py自定义工具 |
PRAISONAI_CALL_LOAD_DOTENV | false | 设为true时在导入阶段加载.env文件 |
LOGLEVEL | INFO | 日志级别 |
其中PRAISONAI_CALL_PUBLIC_BASE尤其重要:出于安全考虑,服务器不会从请求的Host头推导对外地址(避免 SSRF/通话音频被重定向到任意主机),因此生产环境必须显式配置,例如:
docker run -d -p 8090:8090 \ -e OPENAI_API_KEY=sk-xxx \ -e CALL_SERVER_TOKEN=your_shared_secret \ -e PRAISONAI_CALL_PUBLIC_BASE=wss://your-public-domain.example \ praisonai-call注意:_validate_public_base会强制要求非本机地址使用wss://(ws://明文只允许 localhost),否则拒绝启动媒体流。
五、工作原理解析:一条语音链路的完整旅程
从 call.py 的源码结构看,整条语音链路由三个核心路由协同完成:
1.GET/POST /—— 来电接入(handle_incoming_call)
Twilio 收到来电后回调该接口。服务器先校验CALL_SERVER_TOKEN(支持?token=查询参数、Authorization: Bearer/Basic头三种携带方式,使用常量时间比较防时序侧信道),随后基于PRAISONAI_CALL_PUBLIC_BASE生成指向/media-stream的媒体流 URL,并签发一个一次性、60 秒 TTL的会话令牌(见CallAppState.mint_stream_token),最后返回 TwiML:<Connect><Stream url="wss://.../media-stream?session=xxx"/></Connect>。会话令牌绝不嵌入共享密钥,避免密钥泄露进访问日志与浏览器历史。
2.WS /media-stream—— 音频桥接(handle_media_stream)
Twilio 建立 WebSocket 连接后,服务器依次执行三道关卡:
- 认证:校验一次性会话令牌(或
x-call-token头); - 限流:按客户端 IP 统计窗口内连接数,超出
MAX_REQUESTS_PER_WINDOW关闭连接(code 4029); - 并发控制:在
asyncio.Lock保护下原子检查并递增活跃连接数,超出MAX_CONCURRENT_CONNECTIONS关闭连接(code 1013),防止并发竞态超卖连接额度。
随后服务器建立到 OpenAI Realtime API 的上游 WebSocket(_resolve_realtime_endpoint决定目标地址),并通过asyncio.gather双向转发:
receive_from_twilio:把 Twilio 的media事件负载转为input_audio_buffer.append消息发给 OpenAI;send_to_twilio:把 OpenAI 的response.audio.delta音频帧经 base64 处理后以media事件发回 Twilio;同时监听response.done以处理函数调用。
3. 会话初始化(send_session_update)
握手成功后,服务器向 OpenAI 发送session.update,配置语音会话参数:
- 语音:
alloy; - 音频格式:入/出均为
g711_ulaw(与 Twilio 电话链路匹配的 G.711 μ-law 编码); - 语音活动检测:
server_vad,阈值 0.5、前缀填充 300ms、静音判定 200ms; - 多模态:
["text", "audio"],温度 0.8; - 系统提示词:内置了一个"喜欢讲冷笑话、保持积极"的客服型人格,并以 "Hi! I'm Praison AI. How can I help you today?" 开场。
此外,Twilio 侧还会对上游 WebSocket 设置 10s 连接超时、20s 心跳间隔与 1 MiB 帧上限,避免死链长期占用电话号码资源。
六、为通话中的 AI 挂载自定义工具
语音对话不只是聊天——call.py 完整实现了函数调用回路:OpenAI 输出function_call事件后,服务器在本地工具注册表(CallAppState.tools)中按名称查找并执行对应函数,把结果以conversation.item.create(function_call_output)回传,并触发response.create生成下一轮回复。
自定义工具通过工作目录下的tools.py注入。在容器中使用时,需要:
- 将包含
tools.py的目录挂载进容器工作目录:
docker run -d -p 8090:8090 \ -e OPENAI_API_KEY=sk-xxx \ -e CALL_SERVER_TOKEN=xxx \ -e PRAISONAI_CALL_PUBLIC_BASE=wss://your-domain.example \ -e PRAISONAI_ALLOW_LOCAL_TOOLS=true \ -v /host/path/to/tools:/app/tools \ -w /app \ praisonai-call- 在
tools.py中定义工具:每个工具为(schema_dict, async_callable)二元组,schema_dict描述 OpenAI function schema,callable接收参数并返回结果。
安全边界:PRAISONAI_ALLOW_LOCAL_TOOLS默认关闭,且import_tools_from_file仅允许加载当前工作目录下的文件(通过_safe_loader.load_user_module_strict严格加载),防止任意路径模块被执行。
七、安全与生产部署建议
综合源码中的设计,生产部署应至少落实以下要点:
- 必配
CALL_SERVER_TOKEN:未配置时来电接口直接 503,防止服务裸奔; - 必配
PRAISONAI_CALL_PUBLIC_BASE(wss://):对外媒体流地址只来自配置而非请求头,杜绝音频外泄与 SSRF; - 限流参数按容量调整:默认
MAX_CONCURRENT_CONNECTIONS=5适合个人小规模场景,高并发需结合上游配额上调; - Twilio 侧配置:在 Twilio Console 中把电话号码的 Voice 回调 URL 指向
http(s)://<服务器>/,并确保服务器公网可达(容器内可用--public+NGROK_AUTH_TOKEN走 ngrok 隧道); - 密钥管理:不要在镜像中固化 Key,通过
docker run -e或 Docker Secrets 注入;会话令牌为一次性、60 秒过期,进一步缩小泄露窗口。
八、延伸阅读
- 完整的语音服务器实现:src/praisonai/praisonai/api/call.py
- CLI 兼容层(实现已迁移至 praisonai-code):src/praisonai/praisonai/cli/commands/call.py
callextra 依赖清单与praisonai-call入口定义:src/praisonai/praisonai/pyproject.toml- 容器镜像定义:docker/call/Dockerfile
- 仓库顶层容器编排与多服务说明:docker/README.md
按上述步骤构建并运行镜像后,把 Twilio 号码回调指向服务器,即可在 5 行命令内获得一个 7×24 在线的 AI 语音助手。
【免费下载链接】PraisonAIPraisonAI 🦞 — Hire a 24/7 AI Workforce. Stop writing boilerplate and start shipping autonomous self-improving agents that research, plan, code, and execute tasks. Deployed in 5 lines of code with built-in memory, RAG, and support for 100+ LLMs.项目地址: https://gitcode.com/GitHub_Trending/pr/PraisonAI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考