ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hindsight 实战指南:用 Pipecat 构建跨通话记住来电者的语音 Agent

Hindsight 实战指南:用 Pipecat 构建跨通话记住来电者的语音 Agent Hindsight 实战指南用 Pipecat 构建跨通话记住来电者的语音 Agent【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsightHindsight 的 Pipecat 集成将长期记忆注入实时语音管线一个HindsightMemoryServiceFrameProcessor 插在用户聚合器与 LLM 服务之间在每一轮对话前召回相关记忆、在回合完成后异步保留对话内容。本指南聚焦跨通话连续性这一核心场景讲解如何把记忆银行bank的作用域绑定到来电者身份而非单次通话并给出针对语音场景的召回预算调优、验证方法与常见踩坑点读完即可在你的 Pipecat 管线中落地二次来电无需重新自我介绍的能力。本文是一篇策略指南假设你已经将HindsightMemoryService接入可运行的管线未接入可先看 Pipecat 记忆接入指南重点讨论按来电者划分 bank、保留什么内容、何时召回以及决定语音场景下召回有用还是有害的取舍。快速答案从来电者而非通话推导一个稳定的 bank ID —— 例如电话号码或账户 ID。以该bank_id将HindsightMemoryService接在user_aggregator与llm_service之间。在通话开始时让召回执行使 Agent 能用上下文迎接再次来电的用户。让 retain 在每轮完成后以 fire-and-forget 方式运行使下一次通话拥有本次通话的细节。用同一身份拨打两次确认第二次通话记得第一次通话即验证成功。为什么语音 Agent 会忘记再次来电的用户一条默认的语音管线在会话之间是无状态的。每次通话都会创建一个全新的 LLM 上下文因此来电者一挂断他们所说的一切就都消失了。下一次通话从零开始请问您的姓名和账号是多少 —— 又是同样的开场白。这对一次性 IVR 来说没问题但对一个应该像是认识来电者的 Agent 来说恰恰是错的。解决办法不是把历史转录全部塞进系统提示词它们会无限增长并击穿你的延迟预算而是引入一个记忆存储只召回与当前回合相关的内容并在通话进行中保留新的事实。Hindsight 就是这个存储而HindsightMemoryService是把它与 Pipecat 连接起来的 FrameProcessor。从源码实现看HindsightMemoryService继承自 Pipecat 的FrameProcessor见 memory.py在process_frame中拦截LLMContextFrame以及更新的LLMContextFrame协议只对下行DOWNSTREAM方向的上下文帧做处理其余帧原样透传memory.py。这正是管线级记忆的含义记忆逻辑发生在帧流转的管道中而不是写在提示词里。按来电者划分记忆银行bankHindsight 中的记忆按 bank 严格隔离。如果两个来电者共用一个 bank他们的记忆就会互相泄漏进对方的上下文——这是让语音 Agent 瞬间坏掉的最快方式。因此这里唯一最重要的决策是bank_id映射到什么身份要实现跨通话记忆bank 必须绑定到人而不是会话电话号码是电话传输场景最自然的键——它跨通话稳定且 Agent 甚至接听前就已经拿到。账户或客户 ID在有认证身份时更优因为一个人可能用多个号码来电。避免使用瞬时的通话/会话 ID。按通话划分的 bank 意味着每次通话都是第一次通话——这正是你要解决的问题。from hindsight_pipecat import HindsightMemoryService # caller_number 来自你的传输层 / 电信服务商 memory HindsightMemoryService( bank_idfcaller-{caller_number}, # 稳定的按来电者键 hindsight_api_urlhttps://api.hindsight.vectorize.io, api_keyhsk_..., # 或设置 HINDSIGHT_API_KEY 环境变量 )由于 bank 严格隔离caller-15551234567只会召回该来电者的历史。选择你信任的最稳定身份并做归一化处理保持格式一致确保同一个人始终解析到同一个 bank。从源码看bank_id是HindsightMemoryService的唯一必填参数memory.py它在每次arecall读取与aretain写入时被原样传给 Hindsight 客户端memory.py是记忆读写的唯一作用域边界。集成测试中也验证了这一点configure()的全局配置只兜底连接信息URL、API key、召回预算而 bank 必须在每个服务实例上显式指定见 config.py。通话开始时召回结束时保留先召回、后保留的循环是把按来电者划分的 bank 变成连续性的关键。下面看它如何落进管线。HindsightMemoryService在每个OpenAILLMContextFrame以及更新的LLMContextFrame上执行两个动作Retain保留——任何新完成的 userassistant 回合对被异步、fire-and-forget地发送给 Hindsight绝不阻塞响应路径。Recall召回——最新一条用户消息被用作搜索查询结果以hindsight_memories系统消息的形式注入在 LLM 看到上下文之前插入。from pipecat.pipeline.pipeline import Pipeline pipeline Pipeline([ transport.input(), stt_service, user_aggregator, memory, # ← 在 LLM 之前召回回合完成后保留 llm_service, assistant_aggregator, tts_service, transport.output(), ])放置位置是承重的memory必须位于user_aggregator之后这样它才能看到已组装好的用户上下文用于查询和llm_service之前这样召回内容才能在模型生成前到达。如果放在 LLM 之后召回就再也无法影响回复了。源码证实了这一行为memory.pyRetain 的去重与增量机制_extract_new_turn_pairs只扫描尚未处理的消息区间靠_last_retained_count游标跳过已保留的回合对只有用户消息紧跟着助手消息的完整回合对才会被格式化为User: ...\nAssistant: ...并保留memory.py。单元测试test_already_retained_pairs_not_re_retained验证了同一批消息不会重复调用 retain见 test_memory.py。Retain 的非阻塞实现每个回合对通过asyncio.create_task(self._retain(...))调度_retain内部捕获一切异常并仅记录 warning因此写记忆失败绝不会让调用链报错memory.py。Recall 的降级策略_recall使用最新用户消息作为查询调用arecall(bank_id, query, budget, max_tokens)若返回为空则跳过注入若调用本身抛异常如网络错误同样吞掉并继续转发帧——测试test_recall_error_swallowed_frame_forwarded专门验证了召回失败时帧仍被转发、通话不受影响test_memory.py。对于跨通话记忆最重要的时刻是新一次通话的第一个回合。当再次来电者开口说话时召回会针对他们的 bank 执行并浮出关键信息——姓名、未解决的工单、声明的偏好——于是 Agent 的第一个真实回复就已经体现了他是谁你无需再问任何重复问题。在 retain 一侧想清楚一次通话应该留下什么。你不需要存储每一个嗯和插话。Hindsight 保留的回合对承载的是实质内容来电者的请求、做出的决定、表达的偏好、Agent 做出的承诺——这些才是下一次通话应该召回的东西。如果你的通话充斥着可丢弃的废话与其事后过滤不如收紧喂给 Agent 的内容——干净的回合保留出干净的记忆。把 Pipecat 连接到 Hindsight本指南假定集成已安装并接入。如果还没做请先阅读设置指南为 Pipecat 添加 Hindsight 语音 Agent 记忆。它覆盖了pip install hindsight-pipecat、指向 Hindsight Cloud 或本地服务器以及基础管线接线然后回到这里继续按来电者划分的策略。仓库中的参考实现可以直接对照集成 README包含快速开始、自托管配置http://localhost:8888与全局configure()用法。基本管线示例完整的 Deepgram STT OpenAI LLM Cartesia TTS Daily 传输管线展示了LLMContextAggregatorPair与HindsightMemoryService的接入方式。交互式文本模拟器无需真实电话即可手工测试 recall/retain。关于连接参数的细节集成支持两种配置方式。一是直接在构造函数传入hindsight_api_url/api_key/client优先二是先调用from hindsight_pipecat import configure; configure(...)设置全局配置之后创建HindsightMemoryService(bank_id...)时省略连接参数即可。API key 会从HINDSIGHT_API_KEY环境变量兜底读取默认的云端点 URL 定义在 config.py。自托管时把hindsight_api_url指向http://localhost:8888并省略api_key即可。语音专属考量延迟与召回预算语音对延迟的容忍度比文本聊天苛刻得多——来电者会明显感知到冷场。这决定了你如何配置记忆。Retain 天生非阻塞。完成的回合被异步保留存储记忆永远不会加到响应路径上。你不需要为延迟去调它只需要确保它是开启的。Recall 处于关键路径上。召回在 LLM 之前运行其成本计入首 token 时间time-to-first-token。这正是召回预算发挥作用的地方。HindsightMemoryService暴露recall_budgetlow/mid/high与recall_max_tokens。memory HindsightMemoryService( bank_idfcaller-{caller_number}, hindsight_api_urlhttps://api.hindsight.vectorize.io, api_keyhsk_..., recall_budgetlow, # 实时语音场景优先低延迟 recall_max_tokens2048, # 限制注入上下文让 TTS 尽快开口 )对实时电话通话从recall_budgetlow和一个适度的recall_max_tokens开始。语音 Agent 很少需要一整面墙的召回上下文——它需要的是让来电者感到被记住的那两三个事实。只有在你能测量出延迟预算有富余、或面向非实时渠道时才考虑mid/high。如果召回感觉迟钝几乎总是预算对语音来说设得太激进而不是存储慢。源码中的默认值可供参照recall_budget默认mid、recall_max_tokens默认4096memory.pyconfig.py。这两个默认值针对通用场景语音场景建议按上文收紧。recall_budget会直接透传给 Hindsight 的arecall(budget...)接口控制召回阶段检索与重排的资源投入。你还可以用enable_recall与enable_retain独立开关这两个半区——例如在灰度发布期间先静默 retain确认无误后再打开 recall。验证跨通话记忆整件事的核心是第二次通话记得第一次。直接测试它用已知身份呼入或用--bank caller-demo运行文本模拟器说出一个 Agent 应该记住的事实——账户细节、偏好、一个未完成的请求。结束通话让最后几轮完成 retain。用同一身份再次呼入使同一个bank_id被解析。提出一个依赖先前事实的追问——不要复述它。确认 Agent 的回答用到了第一次通话的细节。如果第二次通话召回了第一次按来电者记忆就生效了。如果没有确认两次通话解析到完全相同的bank_id确认memory位于llm_service之前并确认第一次通话的 retain 确实完成打开 debug 日志。包内的examples/interactive_chat.py模拟器让你无需开通电话线路即可跑通这个闭环python examples/interactive_chat.py --bank caller-demo这个模拟器以文本形式逐轮驱动HindsightMemoryService每轮都会标注[RECALL]Hindsight 对当前查询返回的内容、[INJECT]注入的hindsight_memories系统消息、[LLM]助手回复与[RETAIN]被发送给 Hindsight 的完整回合对还支持:memories直接转储 bank 中所有记忆、:reset重置上下文保留 Hindsight bank、:bank查看当前 bank ID见 interactive_chat.py。跑完一轮后调用dump_memories可以直观看到 retain 落库的事实。常见错误把通话/会话 ID 用作 bank。每次通话都变成第一次通话。作用域应指向来电者电话号码或账户而不是会话。把memory放在 LLM 之后。召回内容将再也无法影响回复。它必须位于user_aggregator与llm_service之间。召回预算对语音设得太高。激进的召回会增加首 token 时间制造可感知的冷场。实时通话从low开始。没有归一化身份。如果同一个电话号码有时解析成不同的字符串它就会落进不同的 bank来电者看起来又像新用户了。FAQ我需要 Hindsight Cloud 吗不需要。自托管的 Hindsight 服务器工作方式完全一样——把hindsight_api_url指向http://localhost:8888并去掉api_key即可。Cloud 只是帮你省去了运行后端的工作。bank 应该一个电话号码一个吗通常是的——当号码能干净地映射到一个人时。如果你有认证身份账户或客户 ID 更健壮因为一个人可能用多个号码来电。保留通话内容会拖慢来电者的体验吗不会。Retain 是 fire-and-forget 且异步执行绝不会阻塞响应路径。只有 recall 处于关键路径上而你用recall_budget来调它。通话之间到底记住了什么完成的回合对的实质内容——请求、决定、表达的偏好、承诺。召回只浮出与当前回合相关的部分而不是重放整份历史转录。这与 test_memory.py 中验证的行为一致注入采用替换旧记忆系统消息的方式hindsight_memories标记去重每轮只保留一份最新召回块避免上下文无限膨胀memory.py同时多模态用户消息如语音转写产生的{type: text}内容块会被正确提取为查询文本test_memory.py。下一步尚未安装集成的话先跟随 Pipecat 记忆接入指南完成基础接线阅读 Pipecat 集成文档 与 集成 README 获取完整配置说明参照 基本管线示例 搭建生产管线用 交互式模拟器 无电话验证跨通话记忆深入 Hindsight 的 recall / retain 语义时可结合 Hindsight API 客户端 了解arecall/aretain的参数契约budget、max_tokens、bank_id需要自托管后端时参考 本地开发启动脚本 或在 docker 部署目录 中选择合适的编排方案。【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表