Phone Call Agent
An open-source, self-hosted AI voice call agent. Give it a phone number and a task — it calls the person, has a natural conversation, and returns the full transcript and outcome back to you.
Works in two modes:
- - Outbound — agent dials a real phone number via SIP, or generates a browser call link
- Inbound — agent answers incoming calls from your SIP trunk
Quick Start
CODEBLOCK0
Services started:
| Service | URL | Purpose |
|---|
| Backend API | http://localhost:8001 | FastAPI + MCP server |
| Web UI |
http://localhost:3000 | Dashboard + share-link landing page |
| LiveKit | ws://localhost:7880 | WebRTC media server |
Public URL (needed for share links to work on other devices)
CODEBLOCK1
Configuration (.env)
CODEBLOCK2
How Share Links Work
The core workflow: Claude generates a browser call link → sends it to anyone → they click and talk to the AI → Claude gets the transcript back.
CODEBLOCK3
Step 1 — Start the tunnel so the link works for others
By default the link points to localhost — only works on your machine. To make it work for anyone:
CODEBLOCK4
Step 2 — Set PUBLIC_URL in .env
CODEBLOCK5
Restart the backend so it uses the new URL:
CODEBLOCK6
Step 3 — Ask Claude to make a call
CODEBLOCK7
The person receiving the link just opens it in a browser — no app, no phone number, no account needed.
MCP Server Setup
After docker compose up, connect the MCP server to Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
CODEBLOCK8
Install the MCP dependency first:
cd phone-call-agent && pip install mcp>=1.0.0
MCP Tools
Once connected, Claude has access to these tools:
list_skills
List all available call skills (loaded from
skills/*.md).
CODEBLOCK10
create_share_link(skill_id, mode?)
Generate a browser-based call URL — no phone number needed.
- -
mode: "outbound" → AI speaks first (agent initiates the conversation) - INLINECODE7 → user speaks first (agent waits and responds)
- Default: use the skill's own mode setting
Returns share_url, room_name, mode, expires_in.
make_voice_call(to, skill_id, context)
Dial a real phone number via SIP. Requires
SIP_OUTBOUND_TRUNK_ID in
.env.
- -
to: E.164 phone number e.g. INLINECODE16 - INLINECODE17 : fills
{{variable}} placeholders in the skill's system prompt
get_call_result(room_name, wait_seconds?)
Retrieve the transcript and summary of a completed call.
- -
wait_seconds: long-poll up to 300 seconds — returns the moment the call ends - Returns:
transcript[], summary.outcome, summary.summary, INLINECODE24
get_skill(skill_id)
Get a skill's details including context variables.
check_pending_inbound / accept_inbound_call(room_name, skill_id)
Handle incoming SIP calls — list pending calls and accept them with a chosen skill.
Skills
Skills are Markdown files in skills/ — YAML frontmatter + LLM system prompt:
CODEBLOCK11
No code changes needed. Add a file → restart → immediately available via MCP.
Typical Agent Workflow
CODEBLOCK12
Architecture
CODEBLOCK13
Supported Providers
| Component | Options |
|---|
| LLM | OpenAI (gpt-4o, gpt-4o-mini), Volcengine Doubao, any OpenAI-compatible |
| STT |
OpenAI Whisper, Volcengine ASR (recommended for Chinese) |
| TTS | OpenAI TTS, Volcengine TTS (recommended for Chinese) |
| Phone | Any LiveKit SIP trunk provider |
| WebRTC | LiveKit (self-hosted, included in docker compose) |
电话呼叫代理
一个开源、自托管的AI语音通话代理。给它一个电话号码和任务——它会呼叫对方,进行自然对话,并将完整的通话记录和结果返回给你。
支持两种模式:
- - 外呼 — 代理通过SIP拨打真实电话号码,或生成浏览器通话链接
- 呼入 — 代理接听来自SIP中继的来电
快速开始
bash
git clone https://github.com/Littlesheepxy/phone-call-agent
cd phone-call-agent
cp .env.example .env
在.env中填写你的API密钥(见下方配置)
docker compose up
启动的服务:
| 服务 | URL | 用途 |
|---|
| 后端API | http://localhost:8001 | FastAPI + MCP服务器 |
| Web界面 |
http://localhost:3000 | 仪表盘 + 分享链接落地页 |
| LiveKit | ws://localhost:7880 | WebRTC媒体服务器 |
公网URL(分享链接在其他设备上工作时需要)
bash
无需账户 — 临时URL,适合测试:
docker compose --profile quick-tunnel up quick-tunnel
永久URL(免费Cloudflare账户):
在.env中设置CLOUDFLARE_TOKEN=,然后:
docker compose --profile tunnel up tunnel
配置 (.env)
env
LiveKit(包含在docker compose中 — 默认配置开箱即用)
LIVEKIT_URL=ws://localhost:7880
LIVEKIT
APIKEY=devkey
LIVEKIT
APISECRET=secret
LLM — 选择一个
LLM_PROVIDER=openai
LLM
APIKEY=sk-...
LLM_MODEL=gpt-4o-mini
STT(语音转文字)
ASR
PROVIDER=openaiwhisper # 或:volcengine(中文延迟更低)
TTS(文字转语音)
TTS_PROVIDER=openai # 或:volcengine
TTS_VOICE=alloy
火山引擎 / 豆包(推荐用于中文 — 更低延迟,更高质量)
VOLCENGINE
LLMAPI_KEY=...
VOLCENGINE
LLMMODEL=doubao-pro-32k-241215
VOLCENGINE
ASRAPP_ID=...
VOLCENGINE
ASRTOKEN=...
VOLCENGINE
TTSAPP_ID=...
VOLCENGINE
TTSTOKEN=...
SIP中继(仅真实外呼电话需要)
SIP
OUTBOUNDTRUNK_ID=... # LiveKit SIP中继ID
可选:每次通话结束时,附带通话记录和摘要JSON调用
WEBHOOK_URL=https://your-app.com/call-webhook
分享链接的公网基础URL(设置为你的隧道/域名)
PUBLIC_URL=https://your-tunnel.trycloudflare.com
分享链接如何工作
核心工作流程:Claude生成浏览器通话链接 → 发送给任何人 → 对方点击并与AI对话 → Claude获取通话记录。
Claude(通过MCP)
│
├── createsharelink(follow_up, mode=outbound)
│ └── 返回:https://abc123.trycloudflare.com/call/web-xxx?token=...
│
│ [你将此URL发送给想通话的人]
│
├── 对方在任何浏览器中打开链接(手机、笔记本 — 无需安装应用)
│ └── WebRTC音频通话立即开始
│
└── getcallresult(roomname, waitseconds=300)
└── 对方挂断后立即返回通话记录和摘要
第一步 — 启动隧道,使链接对他人可用
默认情况下链接指向localhost — 仅在你的机器上有效。要让任何人都能使用:
bash
选项A:无需账户(临时URL,适合演示)
docker compose --profile quick-tunnel up quick-tunnel
输出类似:https://abc123.trycloudflare.com
选项B:永久URL(免费Cloudflare账户)
1. 在dash.cloudflare.com → Zero Trust → Tunnels获取隧道令牌
2. 添加到.env:CLOUDFLARE_TOKEN=your-token-here
3. 运行:
docker compose --profile tunnel up tunnel
第二步 — 在.env中设置PUBLIC_URL
env
PUBLIC_URL=https://abc123.trycloudflare.com
重启后端以使用新URL:
bash
docker compose restart agent
第三步 — 让Claude发起通话
你:帮我跟进一下张三的Q1合同签署
Claude:
→ createsharelink(follow_up, mode=outbound)
→ 请点击此链接,AI会主动跟进合同事宜:https://abc123.trycloudflare.com/call/web-xxx?token=...
→ [等待通话结束]
→ 张三确认将于本周五提交合同。
收到链接的人只需在浏览器中打开——无需应用、无需电话号码、无需账户。
MCP服务器设置
docker compose up之后,将MCP服务器连接到Claude Desktop:
~/Library/Application Support/Claude/claudedesktopconfig.json(macOS):
json
{
mcpServers: {
phone-call-agent: {
command: python,
args: [-m, backend.mcp_server],
cwd: /path/to/phone-call-agent,
env: {
AGENTAPIURL: http://localhost:8001
}
}
}
}
先安装MCP依赖:
bash
cd phone-call-agent && pip install mcp>=1.0.0
MCP工具
连接后,Claude可以访问以下工具:
list_skills
列出所有可用的通话技能(从skills/*.md加载)。
→ follow_up:跟进待处理事项(外呼)
→ appointment_reminder:提醒联系人即将到来的预约(外呼)
→ customer_survey:服务后进行简短满意度调查(外呼)
createsharelink(skill_id, mode?)
生成基于浏览器的通话URL — 无需电话号码。
- - mode: outbound → AI先说话(代理发起对话)
- mode: inbound → 用户先说话(代理等待并回应)
- 默认:使用技能自身的模式设置
返回shareurl、roomname、mode、expires_in。
makevoicecall(to, skill_id, context)
通过SIP拨打真实电话号码。需要在.env中设置SIP
OUTBOUNDTRUNK_ID。
- - to:E.164格式电话号码,例如+8613800138000
- context:填充技能系统提示中的{{variable}}占位符
getcallresult(roomname, waitseconds?)
获取已完成通话的通话记录和摘要。
- - wait_seconds:长轮询最多300秒 — 通话结束时立即返回
- 返回:transcript[]、summary.outcome、summary.summary、summary.sentiment
getskill(skillid)
获取技能的详细信息,包括上下文变量。
checkpendinginbound / acceptinboundcall(roomname, skillid)
处理呼入的SIP通话 — 列出待处理通话并用选定的技能接听。
技能
技能是skills/目录中的Markdown文件 — YAML前置元数据 + LLM系统提示:
markdown
name: my_skill
description: 简短描述
language: zh # zh | en | auto
mode: outbound # outbound | inbound | both
max_duration: 300
context_variables:
- contact_name
- topic
你是Relay,一个AI助理。联系人:{{contact_name}}。话题:{{topic}}。
无需修改代码。添加文件 → 重启 → 立即通过MCP可用。
典型代理工作流程
用户:帮我跟进一下张三的Q1合同签署
Claude:
1. listskills() → 找到followup
2. createsharelink(follow_up, mode=outbound)
→ share_url:https://your-tunnel.../call/web-xxx?token=...
3. 把链接发给用户:
请点击此链接,AI会主动跟进您的合同事宜:[链接]
4. getcallresult(roomname, waitseconds=300)
→ 通话结束后立即返回
5. 总结并回复:
张三确认将于本周五提交合同。通话时长2分18秒。
架构
用户提示
│
▼
Claude(MCP客户端)
│ tools:createsharelink / getcallresult
▼
phone-call-agent后端(