mcpField
B
Banjo

Banjo

本地服务
github.com通信协作2今天更新

关于 Banjo

Banjo 是可自托管的单租户语音助手,可拨打真实电话处理预约、询问和交谈。它会依据日历核对预约时间,并且只有在明确确认后才记录预订。

主要功能

  1. 01通过电话预约
  2. 02向商家提出最多五个问题
  3. 03安排稍后拨出的电话
  4. 04处理语音信箱、电话菜单和等待队列
  5. 05可选的来电预约线路
  6. 0611 个 MCP 工具管理通话和联系人

适用场景

  1. 01根据日历空档安排预约
  2. 02致电商家询问营业时间或价格
  3. 03安排稍后拨出的电话
  4. 04让来电者通过接入线路预约或改期

MCP 相关

为 Claude Code 提供 11 个 MCP 工具,用于拨打、查询、取消和停止通话、读取转录及管理联系人。通话结束后,也可将带签名的 JSON 事件发送到配置的 webhook。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shatch-banjo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"DATABASE_URL",
"-e",
"MCP_API_KEY",
"-e",
"ASSISTANT_PRINCIPAL_NAME",
"-e",
"PUBLIC_HOSTNAME",
"-e",
"VOICE_AI_PROVIDER",
"-e",
"OPENAI_API_KEY",
"-e",
"TWILIO_ACCOUNT_SID",
"-e",
"TWILIO_AUTH_TOKEN",
"-e",
"TWILIO_PHONE_NUMBER",
"-e",
"NOTIFICATION_CHANNEL",
"ghcr.io/shatch/banjo:0.1.16"
],
"env": {
"DATABASE_URL": "<DATABASE_URL>",
"MCP_API_KEY": "<MCP_API_KEY>",
"ASSISTANT_PRINCIPAL_NAME": "<ASSISTANT_PRINCIPAL_NAME>",
"PUBLIC_HOSTNAME": "<PUBLIC_HOSTNAME>",
"VOICE_AI_PROVIDER": "<VOICE_AI_PROVIDER>",
"OPENAI_API_KEY": "<OPENAI_API_KEY>",
"TWILIO_ACCOUNT_SID": "<TWILIO_ACCOUNT_SID>",
"TWILIO_AUTH_TOKEN": "<TWILIO_AUTH_TOKEN>",
"TWILIO_PHONE_NUMBER": "<TWILIO_PHONE_NUMBER>",
"NOTIFICATION_CHANNEL": "<NOTIFICATION_CHANNEL>"
}
}
}
}
启动命令docker run -i --rm -e DATABASE_URL -e MCP_API_KEY -e ASSISTANT_PRINCIPAL_NAME -e PUBLIC_HOSTNAME -e VOICE_AI_PROVIDER -e OPENAI_API_KEY -e TWILIO_ACCOUNT_SID -e TWILIO_AUTH_TOKEN -e TWILIO_PHONE_NUMBER -e NOTIFICATION_CHANNEL ghcr.io/shatch/banjo:0.1.16
需要配置的环境变量
DATABASE_URL密钥Postgres connection URL. Migrations run on boot.
MCP_API_KEY密钥Bearer token MCP clients must send (at least 32 characters, e.g. openssl rand -hex 32).
ASSISTANT_PRINCIPAL_NAMEThe name of the person Banjo calls on behalf of.
PUBLIC_HOSTNAMEPublic hostname Twilio reaches this server on (no scheme), e.g. a tunnel or reverse proxy.
VOICE_AI_PROVIDERVoice AI vendor. openai is the one carrying live traffic.
OPENAI_API_KEY密钥OpenAI API key, for VOICE_AI_PROVIDER=openai or openai-live.
TWILIO_ACCOUNT_SIDTwilio account SID.
TWILIO_AUTH_TOKEN密钥Twilio auth token.
TWILIO_PHONE_NUMBERThe Twilio number Banjo calls from, in E.164 (+15551234567).
NOTIFICATION_CHANNELHow Banjo tells you a call's outcome. twilio_sms also needs NOTIFY_TO_PHONE_NUMBER and NOTIFY_FROM_PHONE_NUMBER; pushover needs PUSHOVER_APP_TOKEN and PUSHOVER_USER_KEY.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/shatch/banjo:0.1.16

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Banjo 标志

Banjo

**Banjo 会替你打那些一直拖着没打的电话。**让它帮你预约理发、预订周五 Luigi's 的餐桌,或催一催一直没回电话的承包商——它会拨打电话、与接听的人沟通、根据你的日历协商时间并完成预约。

它是开源的,你可以自行运行,使用自己的 Twilio 号码和语音 AI 账户。它的设计是单租户的:你的电话、凭据和数据,以及你可以阅读和修改的代码,都由你掌控。

Banjo 是一对工具中的电话部分。另一部分是 Claude Code 技能 (skills/schedule-appointment/),它会判断能否在线完成待办事项——只有不能在线完成时才会拨打电话。

如果你愿意,它也可以接听打到你号码的电话:可选的呼入线路,来电者可以通过它与你预约、确认或改期;它还能识别已保存在你的 Google 或 CardDAV(Fastmail、iCloud)联系人中的来电者。

听听它的表现

https://github.com/user-attachments/assets/c599a672-8d4e-46f9-8868-64e0840c589b

收听一段真实通话(2:11):Banjo 为一只狗预约美容服务。通话和日历都是真实的;美容师由角色扮演者模拟。Banjo 会在被问到时说明自己是 AI,利用已知的狗狗信息,拒绝与会议冲突的时间,在获得明确同意后才预约,并将预约写入日历。这是一次早期通话。此后,Banjo 会在挂断前复述预约信息(#47),并且每次通话一开始就说明自己是 AI,而不是等别人询问(#8)。

通话记录(自动转录,稍作整理)

Banjo: 你好,我代表 Steve 来电,想为他的狗 Banjo 预约美容服务。请问这里是 Claudia's Fabulous Dog Grooming 吗?

Claudia: 是的,不好意思。这里是 Claudia's Fabulous Dog Grooming,本次通话可能会被录音。我是 Claudia,请问有什么可以帮您?

Banjo: 你好,Claudia,谢谢你接听。我代表 Steve 来电,想为他的狗 Banjo 预约美容服务。希望预约全套美容。他是新客户,性格友善,但不太喜欢弄湿,也可能会怕推子,所以如果能温柔一些就太好了。请问你们什么时候有空?

Claudia: 不好意思,请问我是在和真人通话吗?

Banjo: 我是代表 Steve 来电的 AI 助手。如果你愿意继续沟通,我可以帮忙安排。请问你们有哪些时间可以为 Banjo 做全套美容?

Claudia: 等一下,这只狗叫什么名字?

Banjo: 它叫 Banjo,是 Steve 的狗。

Claudia: 它是什么品种?大概有多大?

Banjo: Banjo 是一只小型梗犬混种,可能是凯恩梗。它个头小,性格友善,而且这是它第一次来这里。

Claudia: 要做全套美容,还是只洗澡?

Banjo: 希望做全套美容。如果你觉得有必要,可以根据对它最合适的方式调整。我们只是想给它清洁一下、修剪一下。

Claudia: 我可以安排在 24 日星期四下午 3:30。

Banjo: 请稍等。……谢谢,这个时间 Steve 不方便。可以看看其他时间吗?如果可以的话,上午早些时候开始会更好。

Claudia: 星期五的话,我或许能在上午 10 点安排它。让我查一下。

Banjo: 好的,请稍等。……星期五上午 10 点 Steve 应该有空。你要为 Banjo 预约这个时间做全套美容吗?

Claudia: 嗯,应该可以。

Banjo: 好的,再确认一下,你要为 Banjo 预约星期五上午 10 点做全套美容吗?

Claudia: 好的,没问题。25 日星期五上午 10 点,全套美容,90 分钟。就预约这个时间吧。

Banjo: 请稍等。……太好了,谢谢确认。我来完成预约。

功能介绍

通过电话

  • 预约。 它会根据你的日历(Google Calendar,或 Fastmail、iCloud 等任何 CalDAV 日历)协商时间,并且只有在你明确同意后才会预约。Postgres 记录预约是否确实完成,而不是模型口头上说了什么。
  • 进行对话。 mode: conversation 调用会传达消息或讨论某件事,不以预约为目标。
  • 查询信息。 mode: ask 调用会致电商家,提出最多 5 个问题(营业时间、价格、是否有货),并以结构化数据返回每个答案,或说明问题未得到回答。它不会预约,也不会同意任何事。
  • 稍后致电。 place_call 的 scheduledFor 会在设定时间拨号,即使重启后也会保留。
  • 处理语音信箱和电话菜单。 它会留言并确认留言确实已说出,还会按下数字以通过电话菜单。
  • 等待接听。 它会在等待队列中静静等候(最长为 HOLD_MAX_MINUTES,默认 20),在开始等待时通知你,并在人接听后继续通话,首先说明自己是 AI。启用 RECORD_CALLS 后,等待开始时会停止录音:接听的人不会听到录音通知。
  • 将通话转给你。 当对方要求联系真人时,可选择转接,并通过筛选你的线路,确保只有按下 1 才会接通(TRANSFER_ENABLED)。设置 TRANSFER_MODE=warm 后,Banjo 会通过第二条线路给你打电话,在等待对方的同时向你介绍情况;如果你不接听,它会继续与对方通话。
  • 在通话中询问你。 如果对方询问任务未涵盖的内容,Banjo 会说它会确认一下,并通过链接把问题发给你;你在那里输入的内容会转告对方(ASK_OWNER_ENABLED)。
  • 保留转接后的通话内容。 可选择将你和对方在冷转接后的对话转录到通话记录中,双方听到录音通知后才会开始;转录完成后音频会被删除(TRANSCRIBE_TRANSFERS)。
  • 接听打给你号码的电话。 可选的来电线路支持他人预约、查询或改期,并会向它从你的 Google 或 CardDAV 联系人中识别出的来电者问候(INBOUND_BOOKING_ENABLED)。

安全措施

  • 说明自己是 AI。 每次外拨都会以 DISCLOSURE_LINE 开场,其中必须提到“AI”,并且每次通话都会记录是否已说明。
  • 仅在通知后录音。 录音为可选功能(RECORD_CALLS),并且只有在 Banjo 说出录音通知后才会开始。
  • 不会反复打扰任何人。 任意滚动 24 小时内,对同一个号码最多拨打 3 次,且不能覆盖此限制。
  • 保留你选择保存的内容。 只有在你启用相应选项后才会保存转录内容(PERSIST_TRANSCRIPTS);默认情况下,转录内容和录音会在 30 天后删除。日志会隐藏电话号码和通话内容。

配合使用

  • 为 Claude Code 提供 11 个 MCP 工具: 发起、查询、取消和停止通话,读取转录内容,以及管理联系人。
  • 告知通话结果: 每次通话结束后,通过 SMS 或 Pushover 发送结果摘要。
  • 也会通知你的 Agent: 设置 TASK_WEBHOOK_URL 后,每次通话结束都会 POST 一个已签名的 JSON 事件,因此 OpenClaw 或 Hermes Agent 等 Agent 无需轮询也能收到通知。
  • 了解你的偏好: 每次通话都会附上包含常用备注的用户资料(参见下文)。
  • 易于运行: npm run setup 会写入经过检查的 .env,而 docker compose up 会运行已发布的 amd64/arm64 镜像。若要在笔记本电脑休眠时继续运行,请参阅在常开 Linux 主机上运行 Banjo。 完整设计请参阅 docs/ARCHITECTURE.md,后续计划请参阅 docs/ROADMAP.md,连接 Claude Code、Hermes Agent 或 OpenClaw 的说明请参阅 docs/AGENT_SETUP.md,运维流程请参阅 docs/RUNBOOKS.md,以及 Banjo 与该领域其他 开源项目的对比,请参阅 docs/COMPETITIVE_LANDSCAPE.md。

Banjo 运行时架构

已知局限

Banjo 会实际拨打电话并预约,而且一直可靠运行。它也是一个较新、规模较小的项目。在基于它构建之前,值得了解以下事项:

  • 实际上只有一个语音服务提供商经过验证。 OpenAI Realtime 是唯一承载实时流量的适配器。openai-live (GPT-Live) 已在真实通话中测试,但不是默认选项。Gemini Live 和 ElevenLabs 仅搭建了框架,尚未验证——此外,Gemini 完全不会生成通话对方的转录文本。
  • AI 披露是提示词规则,通话后检查,而非强制执行。 Banjo 会收到指示,要求每次通话开场都说 DISCLOSURE_LINE(默认值:"你好,我是代表 {name} 致电的 AI 助手。"),之后会检查它的第一句话。若未按要求说出,会在通话尝试记录中标记,并在通知中注明,但不会阻止通话。 如果你所在的司法辖区有 AI 披露或双方同意规则(TCPA/FCC、加利福尼亚州 AB 2905),请自行检查通话。 (#8)
  • 录音和转录文本仅涵盖外拨电话。 录音(双声道)保存在你的 Twilio 账户中,转录文本保存在 Postgres 中。两者默认均关闭。来电绝不会被录音。 (#6)
  • 电话转接是冷转接,且只能转给一个固定号码。 只有在对方同意后,Banjo 才会转接;模型不会选择要接通的人。接通前你不会收到通话摘要,Banjo 也无法继续留在线上。如果你没有接听,来电者会听到 TRANSFER_FALLBACK_MESSAGE,随后通话结束。对于来电线路,只有已在你联系人中的来电者才能接通;其他要求找你的人会被标记为需要你回拨,因此自动拨号电话无法打到你的手机。 (#7, #66)
  • 向美国号码发送短信需要运营商注册。 如果没有 A2P 10DLC 注册,运营商会拦截结果通知短信。Pushover 无需注册。请参阅 docs/RUNBOOKS.md 中的“未收到 SMS 通知”。
  • 日志经过脱敏,但没有访问控制。 电话号码只记录末尾 4 位;语音留言文本和原始工具参数则记录其长度。供应商的错误消息仍可能包含号码,而 LOG_TRANSCRIPTS=true 会刻意记录完整通话文本。请将日志视为敏感信息。
  • 一次只能处理一通电话。 另有通话正在进行时,来电线路会拒接所有新来电。
  • 需要一个可从公网访问的主机名,因为 Twilio 会通过 HTTPS 和 WebSocket 回连到该主机。请参阅快速入门,以及 docs/spikes/2026-09-21-outbound-registration-worker.md 了解为什么难以移除此要求。
  • 永久采用单租户模式。 一个实例只服务一个人。Banjo 明确不打算实现的其他功能,请参阅 CONTRIBUTING.md。

一通电话的费用

您直接向供应商付费。单位价格,核验日期:2026-09-21:

项目价格来源
Twilio 美国本地号码外呼语音$0.0140 / 分钟Twilio 语音定价
Twilio 美国本地号码呼入语音$0.0085 / 分钟同上
Twilio 美国本地电话号码$1.15 / 月同上
OpenAI gpt-realtime 音频输入$32.00 / 1M 个令牌OpenAI API 定价
OpenAI gpt-realtime 音频输出$64.00 / 1M 个令牌同上
OpenAI gpt-4o-mini-transcribe(来电方转录)每 1M 个令牌,输入 $1.25 / 输出 $5.00同上
Twilio 短信通知(如已启用)按条计费,美国Twilio 短信定价

将实时音频令牌换算成每分钟费用并不可靠:输入量会随着对话时长增加,静音仍会计费,而且模型每通电话的发言量各不相同。根据实际通话测算,供应商总支出约为每分钟 $0.11–$0.17,主要来自语音 AI,而非电话服务。一通 3 分钟的预约电话,费用约为 $0.35–$0.50。

通话转接(TRANSFER_ENABLED)会增加一条 Twilio 计费线路:按上述外呼费率,呼叫 TRANSFER_TO_PHONE_NUMBER,持续时间为通话时长;这笔费用会叠加在原通话线路费用之上,原线路在通话期间仍保持接通。通话转接后,语音 AI 即停止计费。

有两点需要如实说明。选择 gpt-realtime-mini 可将音频费用降低约三分之二,但质量也会有所下降。别为了省钱而用 Banjo 替代 SaaS 订阅——按这个费率,您需要拨打很多电话才能省下钱,而且省下的钱还抵不上您花一小时精力的成本。使用它,是因为它属于您。

不用电话也能试用

npm run sim 会在终端中运行一次通话:Banjo 呼叫商家,您输入回复,扮演接听者。除电话线路外,这就是实际运行:使用相同的系统提示词、工具和通话处理方式,并在 Postgres 中记录相同的任务。不会拨出电话,不会写入日历(预约会写入一个虚拟日历,开放时间为 9 到 6),也不会通知任何人。只需 OpenAI API 密钥和 Postgres。

docker compose up -d postgres
echo "OPENAI_API_KEY=sk-..." >> .env    # skip if your .env already has it
npm install
npm run sim
Banjo is calling Claudia's Dog Grooming for Alex.
[The phone rings. You pick up.]
You: Claudia's Dog Grooming, how can I help?
Banjo: Hi, I'm an AI assistant calling on behalf of Alex. We'd like to book a full grooming for Banjo, a golden retriever...

选项:--business、--goal、--mode conversation、--mode ask(搭配一个或多个 --question,检查方式与 place_call 相同:1 到 5 个问题,每个问题占一行)、--duration(仅限预约)、--transfer(或搭配 --owner accept|decline|no-answer 使用 --warm),以及 --script <file>,用于从文件中播放您这边的对话(以 ~ 开头的行会像录音一样播放,可用于菜单和等待队列)。运行 npm run sim -- --help,或查看 scripts/sim.ts 文件顶部的说明。sim 会将记录保存在独立的 banjo_sim 数据库中,每次运行开始时都会清空该数据库,并且绝不会触碰您的实际数据库。

文本不是音频。sim 测试的是 Banjo 说什么、做什么,而不是通话听起来如何:双方抢话、背景噪声和时序问题,只有实际通话时才会显现。

快速开始

在拨打实际电话之前,Banjo 需要准备好四样东西——请先获取以下内容:

  1. Twilio 账号和电话号码。 在 twilio.com 注册,购买一个支持语音通话的电话号码,并记下 Account SID、Auth Token 和电话号码本身。若要向美国号码发送短信,发送号码还必须完成美国 A2P 10DLC 注册。否则,运营商会静默拦截每条短信(Twilio 错误 30034)。请参阅 docs/RUNBOOKS.md 中的“短信通知未送达”。也可以完全跳过短信,改用 Pushover 推送通知接收结果(NOTIFICATION_CHANNEL=pushover),无需运营商注册。

  2. 语音 AI 提供商。 OpenAI Realtime 是这里经过最多实战检验的选项,也是推荐的默认选择——支持 Gemini Live 和 ElevenLabs Conversational AI,但由于它们尚未像 OpenAI 方案那样承载过实时通话流量,因此有几处标注为 NEEDS VERIFICATION(请参阅 docs/ARCHITECTURE.md 的“未解决风险”部分)。请从所选提供商获取 API 密钥。

  3. 日历和联系人访问权限,如果你希望使用实时日历感知预约和来电显示。可以选择使用应用专用密码的 CalDAV/CardDAV(Fastmail、iCloud、Nextcloud)——设置 CALENDAR_PROVIDER=caldav 和/或 CONTACTS_PROVIDER=carddav,请参阅 docs/RUNBOOKS.md 中的“连接 Fastmail 日历和联系人”——也可以选择下文介绍的 Google。Google 是默认选项。CalDAV 已在 Fastmail 上成功完成实际预约(#70)。

    Google OAuth 客户端和刷新令牌,如果你希望集成 Google Calendar 和/或 Google Contacts(来电显示个性化、find_contact 回退)——两者共用一个客户端和一个刷新令牌,并且该令牌一次性通过两个范围生成。具体步骤请参阅 docs/RUNBOOKS.md 中的“生成 GOOGLE_OAUTH_REFRESH_TOKEN”操作手册;各自的接入方式请参阅 docs/ARCHITECTURE.md 中的 Calendar 和 Google Contacts 部分。可以跳过此步骤——Calendar 和 Google Contacts 会安全地关闭功能(记录日志并不执行操作),而不会崩溃,因此 Banjo 的其他功能仍可正常使用。

  4. 本地服务可公开访问的主机名。 Twilio 会通过普通 HTTPS(Webhook)和 WebSocket(音频 Media Stream)回连 Banjo,因此即使在本地开发环境中,也需要一个可从互联网访问的真实主机名——localhost 不可用。最快的方法是:

    ngrok http 3000   # or whatever PORT you set
    

    取 ngrok 显示的主机名(例如 abcd1234.ngrok-free.app,不要加 https:// 前缀),并将其设置为 .env 中的 PUBLIC_HOSTNAME。其他选项大致按所需工作量排序:

    选项适用场景
    ngrok本地开发,设置最快。免费套餐的 URL 每次重启都会更换——每次都要更新 PUBLIC_HOSTNAME,或使用付费静态域名。
    Cloudflare Tunnel(cloudflared)本地开发,提供由你控制的稳定主机名,免费使用,并绑定到你在 Cloudflare 拥有的域名。
    通过实际部署进行反向代理(例如 .env.example 默认值所示的 ALB)当 Banjo 作为持久服务运行,而不是在你的笔记本电脑上运行时——请参阅 docs/RUNBOOKS.md 中的“在始终在线的 Linux 主机上运行 Banjo”。

然后,在 Docker 中运行整个项目:

npm install
npm run setup          # asks for everything from steps 1-3 above and writes .env
docker compose up      # Postgres + Banjo; migrations are applied on boot

npm run setup 会在你输入每项内容时进行检查(E.164 格式的电话号码、纯 PUBLIC_HOSTNAME),可通过相应服务验证你的 Twilio 和 Pushover 凭据,生成 MCP_API_KEY,并在写入任何内容前运行与 Banjo 启动时相同的验证。再次运行即可更改设置:它会将当前值作为默认值,并先备份旧的 .env。想手动编辑?运行 cp .env.example .env,然后填写内容。

docker compose up 会拉取已发布的镜像 ghcr.io/shatch/banjo,该镜像会在每次发布时为 amd64 和 arm64 构建。在 .env 中设置 BANJO_VERSION 以固定版本,例如 0.1.0。默认值为 latest。若要改为运行自己的检出版本,请使用 docker compose up --build。 或者在本地开发,并启用热重载:

npm install
npm run setup                   # or: cp .env.example .env, and fill it in
docker compose up -d postgres   # just the database
npm run dev                     # applies migrations, then starts on $PORT

然后将你的 Agent 连接到 Banjo 的 MCP 服务:https://<PUBLIC_HOSTNAME>/mcp(Streamable HTTP), 并使用 MCP_API_KEY 作为 bearer token。对于 Claude Code:

claude mcp add --transport http banjo https://YOUR-HOSTNAME/mcp \
  --header "Authorization: Bearer $MCP_API_KEY"

只支持已弃用的 HTTP+SSE 传输方式的旧版客户端,可以改用 /mcp/sse。

测试数据库

npm test 中需要数据库的测试套件会使用同一 Postgres 实例上的独立 banjo_test 数据库,而不是上文的 banjo 开发数据库。Compose 会在首次运行时为你创建该数据库 (scripts/init-test-db.sql);只需迁移一次:

DATABASE_URL=postgresql://banjo:banjo@localhost:5432/banjo_test npm run db:migrate

启动时的迁移只会操作 DATABASE_URL 指定的数据库,因此测试数据库始终需要像这样显式迁移——不会自动迁移。

Schema 变更

迁移文件存放在 drizzle/ 中,并纳入版本控制。Banjo 会在启动时应用所有尚未应用的迁移 (默认开启 RUN_MIGRATIONS_ON_BOOT),因此拉取 schema 变更后重启即可。只有 banjo_test 数据库需要按上文所述显式执行 db:migrate。

如果你要编写 schema 变更,请运行 npm run db:generate,并将生成的 SQL 与 src/**/schema.ts 的修改一同提交。

让它成为你的专属助手:所有者资料

呼叫提示词有意保存在代码中(src/voice/systemPrompt.ts、src/tasks/promptBuilder.ts):其中大部分内容都来自真实呼叫的经验——说明自己是 AI、只在对方明确同意后才预约、确认时区无误——并由测试加以保障。升级 Banjo 时,这些内容也会一并升级。

你可以自行修改的内容放在所有者资料中:一份简短的 Markdown 文件,其中记录长期有效的备注,并会附加到每次外呼中,置于上述规则之后。

cp banjo-profile.example.md banjo-profile.md    # git-ignored — edit it
echo 'PROMPT_PROFILE_FILE=./banjo-profile.md' >> .env

写下你接电话前会告诉人工助手的内容:关于你和你要预约的人士的信息(“Pepper 是一只讨厌修剪指甲的比格犬”)、你的偏好,以及你希望通话听起来是什么样子。Banjo 会利用这些信息完成任务,并且只会在通话需要时透露相关信息。

  • 除非对方是家人或朋友,否则一律保密。 对其他人(企业,或没有设置 relationshipTier 的联系人),Banjo 会礼貌地拒绝回答任务不需要了解的关于你的问题,即使对方直接询问也是如此。标记为 family 或 friend 的联系人可以询问你的情况,Banjo 会根据资料回答。若要允许某人询问,请在 Banjo 首次保存对方之前,将其加入 Google Contacts 中的“Family”或“Friends”群组,或者自行设置其层级(运行手册)。 没有任何 MCP 工具可以更改此设置,因此,Agent 即使读取了通话文本,也无法被诱导放宽限制。

  • 规则仍然优先。 提示词会告知模型,资料中的任何内容都不能凌驾于身份披露、明确同意或时区要求之上。资料可以让 Banjo 显得更友善,但不能让 Banjo 谎称自己是人类。

  • 每次通话的备注优先于资料。 place_call 的 constraints.notes 更具体。

  • 启动时检查,每次通话时重新读取。 路径无效或文件超过 4,000 个字符都会导致启动失败。此后,编辑会在下次通话时生效,无需重启。

  • 使用 Docker 时,请挂载该文件:取消 docker-compose.yml 中 app 下方 volumes: 行的注释,或将它们放入被 git 忽略的 docker-compose.override.yml。

  • 目前仅支持外呼。 接听预约电话的号码会接听陌生来电,因此不会使用你的个人备注。

配套技能

Banjo 只负责“把这件差事办成”的电话环节。另一半是判断该在线预约还是打电话预约,并通过浏览器自动化完成在线预约;这部分由一个 Agent Skill 实现,随本仓库一同提供,位于 skills/schedule-appointment/。它适用于任何支持 Agent Skills 和远程 MCP 服务的 Agent。安装后,将 Agent 连接到 Banjo 的 MCP 服务(参见快速入门)。

由于 ClawHub 的要求,技能文件采用 MIT-0 许可证(MIT,但不要求署名);仓库其余部分采用 MIT 许可证。

任何 Agent,使用 skills CLI:

npx skills add shatch/banjo --skill schedule-appointment

Claude Code。 使用符号链接而非复制,这样后续对技能的修改会立即生效,无需单独同步:

ln -s "$(pwd)/skills/schedule-appointment" ~/.claude/skills/schedule-appointment

OpenClaw(尚未与 Banjo 一同测试),可从 ClawHub 安装,也可使用本地检出:

clawhub install @shatch/banjo-schedule-appointment
openclaw skills install ./skills/schedule-appointment --global

Hermes Agent(没有终端可供确认时,例如使用 docker compose exec -T,请添加 --yes):

hermes skills install shatch/banjo/skills/schedule-appointment

技能会读取 $ASSISTANT_PRINCIPAL_NAME,以确定如何称呼你;Banjo 后端使用的也是同一个环境变量。在 shell 或 .env 中设置一次,即可让两部分保持一致。

技术栈

Node 22、TypeScript(严格模式、ESM)、Hono(HTTP)+ 原始 ws(媒体流音频)、Drizzle ORM + Postgres、Zod、Vitest、Docker。

脚本

命令功能
npm run setup交互式设置:询问必需的设置项、检查设置,并写入 .env
npm run sim文本模式模拟器:扮演商家,Banjo 会致电联系。无需电话,也不使用真实日历
npm run eval场景评估:使用真实 OpenAI 进行脚本化模拟通话并评分,会产生费用。通过的运行记录下来,并在 npm test 中免费重放(参见 docs/ARCHITECTURE.md)
npm run dev以热重载模式运行服务(tsx watch)
npm run build进行类型检查并编译到 dist/
npm test运行 Vitest 测试套件
npm run typecheck进行类型检查,不生成输出
npm run db:generate / db:migrate / db:studioDrizzle 迁移

db:generate/db:migrate 会先自动运行 npm run build(参见 package.json 中的 pre* 钩子)—— drizzle-kit 0.28.x 无法解析本项目源码使用的带 .js 后缀的相对导入(这是确保 Node ESM 运行时正确解析所必需的),因此 drizzle.config.ts 指向编译后的 dist/db/schema.js,而非 TS 源码。如果你看到 relation "..." does not exist,几乎总是因为迁移从未生成或应用。

目录结构

src/
  voice/         vendor-agnostic Voice AI provider abstraction (OpenAI/Gemini/ElevenLabs)
  telephony/     outbound call origination + media streams (Twilio)
  tasks/         task/call-attempt data model, phone-path orchestration
  contacts/      contact directory
  calendar/      Google Calendar or CalDAV integration (phone-path only — see docs/ARCHITECTURE.md)
  googleContacts/ contacts cache (sync/lookup/reconciliation) — feeds contacts/ and inbound/
  carddavContacts/ CardDAV address-book sync into that cache (Fastmail, iCloud, Nextcloud)
  lib/dav/       shared WebDAV plumbing for CalDAV and CardDAV
  transcripts/   opt-in call transcript storage and retention
  recordings/    call recording retention
  inbound/       inbound call handling: booking flow + caller-ID resolution for greeting personalization
  mcp/           remote MCP server for tool-calling clients (e.g. Claude Code)
  session/       per-call state machine wiring telephony <-> voice AI <-> tools
  notifications/ outcome notifications (SMS by default, or Pushover)
  sim/           text-mode simulator (npm run sim): fake phone line and calendar for the real call path
skills/
  schedule-appointment/  companion Agent Skill — decides online vs. phone, drives online
                          booking via browser automation, calls into src/mcp/ for the phone path

贡献

CONTRIBUTING.md 开头说明了 Banjo 有意不做什么——开始编写任何内容前,值得花两分钟读一读。安全问题请通过 SECURITY.md 私下报告,而不要提交到问题跟踪器。

许可证

MIT — 详见 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。