AI PLAY玩法更新持续收录
← 回到更新流

2026-10-01 · 原文发布日

n8n模板:用Vapi语音前台自动查档期、预约并记录来电

这套n8n工作流把Vapi语音助手变成电话前台:Vapi发来工具调用后,流程按工具名分流——查档期时读取Google日历近期事件并按营业时段规则算出可约空位,以可朗读的JSON回给语音助手;预约时直接写入日历、把记录追加到Google Sheets并邮件通知店主;留言则记入表格并转发邮件。需在Vapi配置三个服务器工具,并接入日历、Sheets和SMTP凭证,时段、时区、提前量都可在代码节点里改。

原文要点

该n8n工作流接收Vapi语音助手的工具调用webhook:解析出工具名、工具调用ID和参数后按工具名分流。checkAvailability读取Google日历近期事件,按可配置的营业时段规则算出可约空位,以含ISO时间戳的可朗读JSON回给语音助手;bookAppointment在指定开始时间创建日历事件、向Google Sheets追加预约记录并邮件通知店主;takeMessage把留言记入表格并转发邮件;非工具事件返回空确认。需在Vapi建三个server tools,名称与参数为checkAvailability(无参)、bookAppointment(customerName、phoneNumber、service、startTime)、takeMessage(callerName、phoneNumber、message);时区、营业时间、工作日、时段长度、提前量在代码节点的CONFIGURE块里改。模板基于作者为英国居家护理服务商做过的生产系统。

这次做成什么

把Vapi语音助手变成电话前台:来电人问档期能实时报出空位,确认后直接写入日历并通知店主,无人预约的留言也自动记录。练习方案:先在n8n里用合成的工具调用payload逐条测通三个分支,确认日历事件、表格行、邮件各就各位,再去Vapi后台配置正式助手。

准备什么

  • Vapi账号和一个语音助手,能添加server tools并指向webhook URL
  • Google Calendar凭证,模板默认使用primary日历
  • Google Sheets一份,含Timestamp、Type、Caller Name、Phone、Details、When六列表头
  • SMTP凭证用于给店主发预约与留言通知邮件
  • n8n实例已发布该工作流,拿到生产webhook地址

具体怎么做

  1. 建来电登记表

    新建Google Sheet,第一行写入六个表头:Timestamp、Type、Caller Name、Phone、Details、When。两个Sheets节点都指向这份文档的同一工作表,Type列区分booking与message两类记录。

  2. 配置营业时段规则

    打开Compute Open Slots代码节点的CONFIGURE块,设置时区(如Asia/Shanghai)、每天开门与打烊时间、工作日、时段长度SLOT_MINS、最短提前量和一次报出的空位个数。预约时长必须和Create Event节点的事件时长保持一致,否则日历事件和口头承诺对不上。下方给出本站编写的独立示例代码供理解逻辑,原模板代码以其画布为准。

  3. 配置三个工具分支

    流程收到POST后先标准化Vapi负载,取出工具名与参数进Switch节点:checkAvailability分支读日历近期事件、算空位、返回可朗读JSON;bookAppointment分支按startTime创建日历事件、追加表格、发邮件;takeMessage分支追加表格、发邮件、回确认;其余事件回空确认。填好日历、Sheets、SMTP三处凭证和两个邮件节点的收发地址。

  4. 用合成payload逐分支测试

    在n8n测试执行里向webhook POST下方的bookAppointment合成payload,应看到日历新增事件、表格新增一行、店主收到邮件;再测checkAvailability应返回含ISO时间戳的空位列表。

  5. 在Vapi配置三个server tools

    在Vapi助手后台新建三个server tools,URL都填生产webhook地址:checkAvailability无参数;bookAppointment带customerName、phoneNumber、service、startTime四个参数;takeMessage带callerName、phoneNumber、message三个参数。用Vapi的测试通话功能各触发一次。

可直接复制的材料

Vapi三个server tools定义(本站整理)

名称与参数来自原模板说明;在Vapi后台录入时,三个工具的server URL都填同一生产webhook地址。

[
  {"name": "checkAvailability", "description": "查询最近可预约的空位", "parameters": {"type": "object", "properties": {}}},
  {"name": "bookAppointment", "description": "在指定时间创建预约", "parameters": {"type": "object", "properties": {
    "customerName": {"type": "string"},
    "phoneNumber": {"type": "string"},
    "service": {"type": "string"},
    "startTime": {"type": "string", "description": "ISO 8601时间,来自checkAvailability返回的选项"}},
    "required": ["customerName", "phoneNumber", "service", "startTime"]}},
  {"name": "takeMessage", "description": "记录来电留言", "parameters": {"type": "object", "properties": {
    "callerName": {"type": "string"},
    "phoneNumber": {"type": "string"},
    "message": {"type": "string"}},
    "required": ["callerName", "phoneNumber", "message"]}}
]

空位计算逻辑示例(本站独立编写)

本站按模板描述编写的逻辑示意,非原模板代码;正式使用请以画布上Compute Open Slots节点实际代码为准并核对字段名。

// CONFIGURE 块:按业务修改
const CONFIGURE = {
  TIMEZONE: "Asia/Shanghai",
  OPEN_HOUR: 9,
  CLOSE_HOUR: 18,
  WORK_DAYS: [1, 2, 3, 4, 5],   // 周一至周五
  SLOT_MINS: 60,
  MIN_NOTICE_HOURS: 2,
  OFFER_COUNT: 3
};
// 逻辑:从『现在+最短提前量』起,逐SLOT_MINS扫描未来7天,
// 跳过非工作日与非营业时段,与已拉取的日历事件比对冲突,
// 收集满OFFER_COUNT个空位后返回,每项含ISO startTime与可读文本。

bookAppointment合成测试payload

本站虚构测试数据,电话号码为占位号段;Vapi实际负载结构以Vapi文档和你收到的真实请求为准。

{
  "message": {
    "type": "tool-calls",
    "toolCallList": [{
      "id": "call_test_001",
      "name": "bookAppointment",
      "arguments": {
        "customerName": "测试客户王芳",
        "phoneNumber": "+8613800000000",
        "service": "首次到店咨询",
        "startTime": "2026-10-08T14:00:00+08:00"
      }
    }]
  }
}

输入与输出示例

本站虚构演示,空位为按示例规则手工推演的结果,未实际运行工作流。

输入

上午10点有来电问『最近哪天下午有空?』,语音助手调用checkAvailability;配置为营业9点到18点、工作日、时段60分钟、最短提前2小时、报3个空位,日历中10月8日14点到15点已有事件。

对应输出

返回给Vapi的可朗读JSON:{"spoken": "最近的可约时间是:10月8日周四中午12点、下午1点,和10月8日下午3点。您想约哪一个?", "options": [{"startTime": "2026-10-08T12:00:00+08:00", "label": "10月8日中午12点"}, {"startTime": "2026-10-08T13:00:00+08:00", "label": "10月8日下午1点"}, {"startTime": "2026-10-08T15:00:00+08:00", "label": "10月8日下午3点"}]}。上午10点来电加2小时最短提前量,空位从12点开始计算;14点选项因已有日历事件被排除。

做完检查这些

  • POST合成的bookAppointment payload后,primary日历在指定startTime出现新事件且时长与SLOT_MINS一致
  • 同一请求在Sheet新增一行,Type为booking,六个列均有值,店主邮箱收到预约通知
  • checkAvailability返回的每个option都含ISO格式startTime,且全部晚于『当前时间+最短提前量』、不与现有日历事件冲突
  • takeMessage分支新增Type为message的表格行并触发邮件,且回给Vapi确认文本
  • 发送非工具调用类事件(如状态通知)时流程返回空确认,不产生任何日历、表格或邮件副作用

容易卡住的地方

  • Create Event节点的事件时长若忘记与SLOT_MINS同步,口头承诺的时段长度和日历占位会不一致
  • 模板默认用primary日历,多人共用门店日历时需改为指定日历ID,否则约到私人日历上
  • 时区配置错误会让语音助手报出的时间和实际营业时间整体偏移,跨国团队尤其要查CONFIGURE里的TIMEZONE
  • Vapi里工具名或参数名与Switch分支不一致时调用会落入默认分支,看似成功实则什么都没发生
  • webhook必须用生产地址,测试地址在Vapi侧不会持续生效
  • 作者说明模板源自真实生产系统,但不同业务的预约规则需自行改造,未核实的界面与参数以原模板画布为准

原文与作者资料 ↗

本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。

原文标题
Handle voice receptionist bookings with Vapi, Google Calendar and Sheets
原作者
Ali Amin
原始发布日期
2026-10-01T14:33:43.774Z
来源
https://n8n.io/workflows/20302