Hindsight × Vapi 集成指南:为语音 AI 通话注入持久化长期记忆
2026/9/14 19:02:20 网站建设 项目流程

Hindsight × Vapi 集成指南:为语音 AI 通话注入持久化长期记忆

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

本指南讲解如何在 Vapi 语音 AI 平台上,通过一个轻量级 Webhook 处理器(hindsight-vapi)把 Hindsight 的持久化长期记忆接入每一通电话:来电开始即自动召回与来电者相关的历史记忆并注入助手系统提示,通话结束时将完整对话记录异步写入记忆库。读完本文,你将掌握 Webhook 的接入方式、全部配置参数、来电/去电两条记忆注入路径,以及不依赖真实 Vapi 账号的手动联调方法。

为什么 Vapi 需要专门的 Webhook 集成

Vapi 是语音 AI 平台,其服务端会在通话生命周期中触发 Webhook 事件。与 Pipecat(提供按轮次的 FrameProcessor)不同,Vapi 不暴露按轮次(per-turn)的钩子——这意味着无法在对话每一轮都动态注入记忆,只能在每通电话开始时注入一次(见 webhook.py 的模块注释)。

hindsight-vapi(仓库路径 hindsight-integrations/vapi)正是为这一架构差异设计的:它把"召回记忆"与"写入记忆"两个动作分别挂在 Vapi 的两个服务端事件上,用一个类HindsightVapiWebhook完成全部接线。它本身框架无关,可嵌入 FastAPI、Flask、aiohttp 等任意 HTTP 服务,只需两行即可接入(见 CHANGELOG.md)。

快速开始:五分钟接入 Webhook

安装与最小示例

pip install hindsight-vapi

一个完整的 FastAPI 接入如下(直接取自 README.md 与 webhook.py 的用法示例):

from fastapi import FastAPI, Request from hindsight_vapi import HindsightVapiWebhook app = FastAPI() memory = HindsightVapiWebhook( bank_id="user-123", hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_your_token_here", ) @app.post("/webhook") async def vapi_webhook(request: Request): event = await request.json() response = await memory.handle(event) return response or {}

把 Vapi 控制台的Server URL指向这个端点,记忆功能即生效。

自托管替代

若使用本地 Hindsight 实例,只需把 URL 换成http://localhost:8888省略api_key

memory = HindsightVapiWebhook( bank_id="user-123", hindsight_api_url="http://localhost:8888", )

客户端解析逻辑

从源码看,构造函数通过_resolve_client(webhook.py)按优先级解析 Hindsight 客户端:显式传入client=优先;其次从hindsight_api_url=/api_key=参数构造;两者都没有则回落到全局配置;仍无 URL 时抛出HindsightVapiError("No Hindsight API URL configured...")(errors.py)。底层客户端来自hindsight-client>=0.4.0依赖(见 pyproject.toml)。

工作原理:一次通话中的记忆闭环

Incoming call └─ Vapi fires "assistant-request" webhook └─ Recall memories (query = caller's phone number) └─ Return as assistantOverrides with <hindsight_memories> system message └─ Vapi merges into assistant config before the call begins Call ends └─ Vapi fires "end-of-call-report" webhook └─ Retain full transcript (fire-and-forget — webhook responds immediately)

整个闭环由handle()方法(webhook.py)路由:它读取event["message"]["type"],仅处理assistant-requestend-of-call-report两类事件,其余事件一律返回None(对应 HTTP 200 空响应体)。

来电开始:assistant-request 召回

_handle_assistant_request(webhook.py)的逻辑:

  1. msg["call"]["customer"]["number"]取出来电者电话号码作为召回查询词(query);号码缺失时使用兜底查询词"returning caller"(这一点有测试专门验证,见 test_webhook.py);
  2. 调用客户端arecall()进行语义召回;
  3. 无结果或召回禁用时返回{},Vapi 不会因此报错;
  4. 有结果时通过_build_overrides(webhook.py)构造assistantOverrides,其中注入一条 system 消息,内容以<hindsight_memories>标记开头、以</hindsight_memories>结尾,内部为带编号的记忆条目列表。

从客户端 SDK 看,arecall()(hindsight_client.py)的budget参数即召回预算("low"/"mid"/"high",默认"mid"),max_tokens默认 4096(hindsight_client.py)——Webhook 的recall_budgetrecall_max_tokens参数正是透传给这两个底层参数。

通话结束:end-of-call-report 保留

_handle_end_of_call(webhook.py)从msg["artifact"]["transcript"]取出完整通话记录,若非空则通过asyncio.create_task(self._retain(transcript))**异步(fire-and-forget)**提交aretain()写入记忆库——Webhook 响应体不被延迟。底层aretain()(hindsight_client.py)会把通话记录交给 Hindsight 后台做事实抽取与记忆沉淀。

优雅失败设计

  • 召回阶段:异常被捕获并logger.warning,返回{},通话照常进行("continuing without memories"),见 webhook.py;
  • 保留阶段:异常同样被吞掉仅记日志,见 webhook.py;
  • 测试 test_webhook.py 验证了召回网络错误时返回空 dict 不抛异常,test_webhook.py 验证保留失败不向上传播。

记忆随通话累积:同一来电者打到第二、三次电话时,Hindsight 就会自动浮现相关历史信息。

去电(Outbound Calls):没有 Webhook,就在建呼时注入

Vapi 的去电没有assistant-requestWebhook,因此必须在调用 Vapi 创建通话 API 时,用build_assistant_overrides()(webhook.py)在建呼时刻注入记忆:

overrides = await memory.build_assistant_overrides("Ben from Vectorize") vapi.calls.create( assistant_id="...", assistant_overrides=overrides, customer={"number": "+15555550100"}, )

该方法以你提供的查询词(如对方姓名或通话主题描述)召回记忆,返回可直接作为assistantOverrides传入的 dict;当召回被禁用或无结果时返回{}(有测试覆盖,见 test_webhook.py)。

前置条件:准备一个可用的 Hindsight 实例

自托管

pip install hindsight-all export HINDSIGHT_API_LLM_API_KEY=your-api-key hindsight-api # starts on http://localhost:8888

Hindsight Cloud

直接注册获取 API Key,免去自托管部署,随后在配置中使用https://api.hindsight.vectorize.iohsk_开头的 API Key。

配置参数详解

实例级配置

HindsightVapiWebhook( bank_id="user-123", # Required: memory bank to use hindsight_api_url="...", # Hindsight API URL api_key="hsk_...", # API key (Hindsight Cloud) recall_budget="mid", # "low", "mid", or "high" recall_max_tokens=4096, # Max tokens for recall results enable_recall=True, # Inject memories at call start enable_retain=True, # Store transcript at call end memory_prefix="Relevant memories from past conversations:\n", )

各参数在构造函数(webhook.py)中的实际语义:

参数默认值作用
bank_id必填读写的 Hindsight 记忆库(memory bank)ID
clientNone预配置的 Hindsight 客户端(优先使用)
hindsight_api_urlNoneAPI 地址,未传client时用于构造客户端
api_keyNoneHindsight Cloud 的 API Key
recall_budget"mid"召回预算档位"low"/"mid"/"high",透传给arecall(budget=...)
recall_max_tokens4096召回结果最大 token 数,透传给arecall(max_tokens=...)
enable_recallTrue关闭后完全不召回(来电与去电均返回{}
enable_retainTrue关闭后通话结束不写入记忆
memory_prefix"Relevant memories from past conversations:\n"注入系统提示中记忆块的前缀文案

全局配置:configure()

多个 Webhook 共享同一连接信息时,用configure()避免重复传参(config.py):

from hindsight_vapi import configure configure( hindsight_api_url="http://localhost:8888", api_key="hsk_...", recall_budget="mid", ) # Now create webhooks without repeating connection details memory = HindsightVapiWebhook(bank_id="user-123")

实现细节:

  • configure()返回HindsightVapiConfigdataclass(config.py),其中hindsight_api_url默认https://api.hindsight.vectorize.io
  • api_key未显式传入时自动回落到HINDSIGHT_API_KEY环境变量(config.py);
  • Webhook 构造时,recall_budget/recall_max_tokens若传空值也会从全局配置补齐(webhook.py);
  • 配套提供get_config()reset_config()(测试在 test_webhook.py 中验证了全局 URL 会被客户端解析器采用)。

Vapi 控制台配置三步走

  1. 在 Vapi dashboard 中把Server URL设置为你的 Webhook 端点;
  2. 启用assistant-requestend-of-call-report两种事件类型;
  3. 来电场景下,Vapi 触发assistant-request时记忆即自动召回注入。

不注册 Vapi 账号也能联调:交互式 Webhook 模拟器

examples/目录提供了一个交互式 Webhook 模拟器(interactive_webhook.py),可模拟assistant-requestend-of-call-report事件,无需真实 Vapi 账号或电话号码即可观察记忆的保留与召回全过程:

python examples/interactive_webhook.py --bank demo-user

命令行参数:

  • --bank <id>:记忆库 ID(默认vapi-demo-<USER>);
  • --hindsight-url <url>:Hindsight API 地址(默认取HINDSIGHT_API_URL环境变量,兜底http://localhost:8888);
  • --hindsight-api-key <key>:API Key(默认取HINDSIGHT_API_KEY环境变量)。

交互命令:

  • :script:引导式演示——先结束一通带完整对话记录的电话,等待约 8 秒让异步事实抽取完成并dump_memories展示沉淀出的记忆,再模拟第二通来电,观察是否成功召回 Alex 的偏好(interactive_webhook.py);
  • :end <transcript>:模拟通话结束,触发end-of-call-report保留对话(脚本会等待数秒供后台任务推进,见 interactive_webhook.py);
  • :call <number>:模拟来电,触发assistant-request召回并打印注入的系统提示内容;
  • :memories:直接调用GET /v1/default/banks/{bank}/memories/list接口列出记忆库全部条目;
  • :bank:显示当前记忆库 ID;
  • :quit/:q:退出。

典型演示序列(来自脚本头部示例):

vapi> :end User: My name is Alex. Assistant: Hi Alex! User: I prefer email. Assistant: Got it. vapi> :memories vapi> :call +15551234567

运行测试

仓库自带完整单元测试套件,覆盖客户端解析、来电召回注入、去电 overrides 构建、通话结束保留、未知事件忽略等场景:

uv sync uv run pytest tests/ -v

测试要点(test_webhook.py):

  • 记忆正确注入assistantOverrides的 system 消息,且包含<hindsight_memories>标记与记忆正文(L89-L99);
  • 空召回、召回异常、禁用召回三种情况下均返回{}且不抛错(L101-L138);
  • 电话号码作为召回查询词、缺失时用"returning caller"(L115-L130);
  • 通话记录以 fire-and-forget 方式异步保留、空记录为 no-op、禁用保留时跳过(L151-L194);
  • call-startedspeech-updatetranscript等未知事件一律返回None且不触发任何 Hindsight 调用(L232-L238)。

项目配置要求 Python >= 3.10,采用 pytest-asyncio 的asyncio_mode = "auto",代码以 ruff 按 line-length 100、target py310 约束(见 pyproject.toml)。

延伸阅读

  • 完整实现:webhook.py、config.py
  • 底层 Python 客户端arecall/aretain的完整参数:hindsight_client.py
  • 交互式模拟器:interactive_webhook.py
  • 集成包变更记录:CHANGELOG.md
  • 同类的语音 Agent 记忆集成(按轮次注入的对比实现)可参考仓库中的 pipecat 集成 目录。

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询