Skip to main content

PRD:全渠道 Specialist 连续性 —— 共享记忆 / KB / Skill(文本 × Tavus 视频)

  • 状态:Reviewed —— O1–O5 已由 Franky 于 2026-07-14 拍板(见 §9 决策记录);2026-07-15 代码走查修订(要点:文本侧长期记忆 specialist_memories 已存在 → D4 改为默认扩展该表;新增 R1.5 Active Directives 达视频、R2.7 组装位序;§5 基线表多处更新——各处均带"复核"标注);待建 Epic 拆解
  • 作者:Franky(PM)+ Claude
  • 日期:2026-07-14(决策同日)
  • 语言:中文为主;英文镜像:omnichannel-specialist-continuity-prd.md(两版保持同步)
  • 相关:docs/specs/tavus-integration.md · ADR-008(KB K1/K2) · ADR-006(移除旧 memory 模块;注意:specialist_memories 是其后新建的,见 §5) · #646(Tavus 账号级 KB 跨租户风险) · #1387(persona 一次性预置) · #2058(client 按需视频通话) · #2059(WeeklyCallSchedulerService 定时呼叫;§11 邻接 epic) · #1197/#3131(specialist_memories 既有跨会话记忆层) · #3692(Active Directives) · #4399(chat 路径工具接线,W3 前置)

1. 问题陈述

产品目标:client 无论通过哪个渠道(webchat、Slack、Email、视频通话)与自己的 Specialist 沟通,感受到的都是同一个真人专家 —— 他记得之前聊过什么、知道客户上传的资料、会做同样的事。

现状与目标的落差(2026-07 代码探查结论,详见 §5 基线表):

  1. 视频 AI 不读 KB。文本 Specialist 每轮实时检索租户 KB(K1/K2,api/src/kb/kb-retrieval.service.ts);Tavus 视频 AI 的"知识"只是每次通话注入的 conversational_context 字符串(brief 快照 / onboarding 通用脚本 / 近 7 天会话摘要)。client 上传给 Specialist 的私有文档,文本里他"读过",视频里他"没见过"
  2. 跨渠道记忆:文本侧已有一个浅层实现,视频侧完全没有(2026-07-15 复核修正——原文"文本侧自己也没有"不成立)。文本侧存在两层:per-conversation 的 agent_context(history_summary/facts/preferences,JSONB + Redis 1h,换 thread/渠道即断)和 org × specialist 粒度的 specialist_memories(#1197/#3131:跨会话长期记忆,已注入 draft/stream/regenerate 三条 chat 路径,20 条 / 4000 字符预算,Expert workspace 已有查看/删除 UI)。但后者提取端是玩具级——仅 4 个英文正则句式、只在会话 resolve 时触发,实际沉淀量 ≈ 0。视频通话则完全无跨通话记忆,每次都是一次性快照。
  3. Skill/工具两套且不对齐。文本 draft 路径不带工具(工具只在 agentic/AgentRun 路径、且按 org 绑定 tool_permissions);Tavus persona 挂的是全体 persona 相同的固定工具并集(tavus_function_definitions + 3 个硬编码 in-call 工具),与 Specialist 无关。
  4. 架构上刻意解耦:视频 AI 由 Tavus 自己的 LLM 驱动,h.work Python agent 不在环(spec §6.2);persona 提示词离线烘焙、"不再与 Python agent 共享模板"(#1390)。唯一共享的是 persona 身份(同一 catalog 行派生的名字/角色/能力描述)——且该共享会漂移:文本侧现读平台侧 config-assets 的已发布 Soul(发布后下一轮生效),Tavus persona 仍从 catalog 行离线烘焙,Soul 发布后若不重新 provision,两渠道人格即分叉(见 §5)。
  5. Active Directives 只达文本渠道(合规级断裂)。#3692 已上线:Expert 设置的情境指令(压过 KB 的红线级内容)注入文本 prompt;视频通路完全不感知。危机场景下("已发生黑客事件,不得谈安全措施")客户开一通视频会 = 红线穿透。

其中 (2) 是根因级问题:目标不是"把视频对齐到文本",也不是从零造共享层,而是把既有的 specialist_memories 升级为渠道无关的共享层(提取 LLM 化、补视频写入端、补治理字段),然后所有渠道(含文本自身)都接上去。(5) 的红线类内容一致性优先于 facts 记忆。

2. 目标(可度量)

#目标度量
G1视频 AI 能召回租户 KB视频通话中针对"KB 中已有答案"的问题,召回率 ≥ 文本侧同题的 80%(抽样评测)
G2跨渠道记忆连续client 在渠道 A 陈述的事实(facts),渠道 B 的下一次会话可被引用;评测集通过率 ≥ 90%
G3视频记忆回写每次视频通话结束后 ≤ 5min,transcript 摘要写入共享记忆层(BullMQ job 成功率 ≥ 99%)
G4零跨租户泄露KB/记忆的所有读写路径均带 org × specialist 隔离过滤;新增路径 100% 有对应 spec 断言
G5用户感知客户满意度调研中"感觉像同一个专家"命题得分(基线待首次调研建立)

3. 非目标

  • 不使用 Tavus 平台的 documents/knowledge_base API(#646 账号级共享 → 跨租户泄露;现有三层硬禁不动)。
  • 不引入向量/embedding 检索升级(现状 KB 为词法打分;检索质量升级另行立项)。
  • 不做 Expert(人)侧的记忆工具(Expert 看到的上下文改进另行立项)。
  • 不改变 HITL 默认(autoRespondThreshold=101)与 draft 审核流。
  • v1 不做文本 draft 路径的工具注入(见 W3 讨论 —— 文本侧"工具故事"本身需先厘清)。

4. 用户故事

  • 作为 client 员工,我上周在 Slack 里告诉过 Specialist 我们的结算周期改为月结;这周视频通话时他主动按月结口径讨论,而不是再问一遍。
  • 作为 client 员工,我在视频里问"你们之前给我们整理的供应商清单里 X 公司的条款",Specialist 能当场引用 KB 里那份文档回答。
  • 作为 Expert,我审核文本草稿时能看到该 client 的共享记忆(facts),不会放行与既有事实矛盾的回复。
  • 作为 AM,我能查看/纠正某 (org × specialist) 的沉淀事实,错误记忆可删除且立即全渠道生效。
  • 作为 SuperAdmin,我确信任何记忆/KB 通路都不会把 A 客户的信息带给 B 客户。

5. 现状基线(代码证据)

维度文本 Specialist(/v1/chat)Tavus 视频 AI一致?
KB每轮 HTTP 拉 /kb/retrieval,过滤 specialist_id = $1 AND org_id IN (org, HP_GLOBAL)(K1/K2);注入 system prompt无 KB 检索;Tavus documents API 被 DTO/client/service 三层硬禁(#646);TavusContextBuilderService.buildFromClientKb 为已注册但无调用方的死代码
记忆last-12 轮历史 + per-conversation agent_context(Redis 1h TTL)+ specialist_memories(org × specialist 长期记忆,已注入 prompt;但提取端仅 4 个英文正则、resolve 时触发,沉淀 ≈ 0)无跨通话记忆;per-call 快照(reporting=brief JSON、按需=7 天会话摘要、onboarding=通用 9-bucket 脚本)⚠️ 文本有浅层实现,视频缺位
情境指令(Active Directives)注入 prompt、压过 KB(#3692)不感知❌(合规级)
Skill/工具draft 路径无业务工具(#4399 已立项接 toolsManifest);文件生成工具集已启用(#3944,HW_ATTACHMENT 出站);agentic 路径按 org 绑定(tool_permissionsAgentRun.toolsManifest)persona 固定工具并集(全 persona 相同);in-call 工具直读 DB(get_client_history/get_current_goals/escalate_to_chat)
系统提示/身份Specialist.system_prompt(回退)+ 模板 + config-assets 已发布 Soul(getPublishedSoulMd 单一渲染器,发布后下一轮生效;SOUL.md 文件已退役为回退),Python 端分层组装buildSystemPrompt(catalogRow) 同一 catalog 行派生,离线烘焙⚠️ 身份同源但会漂移:Soul 发布仅文本侧生效,persona 需重新 provision 才更新
运行时h.work Python agent(Hermes)Tavus 自有 LLM,h.work agent 不在环

关键文件:api/src/kb/kb-retrieval.service.ts · agent/kb_client.py · agent/prompts_loader.py · api/src/tavus/tavus.client.ts · api/src/tavus/video-call-tools.service.ts(修正:原误写 video-calls/ 目录)· api/src/tavus/video-call-tool-definitions.ts · api/src/meetings/conversation-starter.service.ts · api/src/specialists/specialist-memory.service.ts · api/src/specialists/specialist-memory-extraction.job.ts · api/src/conversations/agent-context-cache.service.ts · api/scripts/provision-tavus-personas.ts。实现时按 HEAD 复核行号。

6. 方案:三条工作流

W1 — 视频接入租户 KB(P0,最快见效)

机制:function-call 工具,而非预注入。 给 Tavus persona 新增 search_knowledge_base 工具;Tavus LLM 在通话中发起 function-call → 现有 …/tavus/webhooks/function-call 回调 → 新 handler 调 KbRetrievalService.retrieve(orgId, specialistId, query, topK)(K1/K2 过滤原样复用)→ 结果回给 Tavus。

  • 为什么是工具:完全绕开 Tavus 账号级 KB(#646 红线不碰);in-call 工具通路已被 3 个现有工具验证;检索是实时的,不受 context 长度约束。
  • 辅助(P1):通话创建时把 top-N KB 文档的 title+snippet 拼进 conversational_context 作为零延迟兜底(注意 per-call context 尺寸预算)。
  • 要求:
    • R1.1 新增 search_knowledge_base 工具定义(入 tavus_function_definitions 库)+ webhook handler;org/specialist 取自 video_call/meeting 行,绝不信任 Tavus 回传的租户参数
    • R1.2 handler 复用 KbRetrievalService(含 kb_retrieval_enabled 开关语义);为视频通路增加独立开关 video_kb_enabled(按 org × OSA 粒度)。
    • R1.3 检索调用写审计(orgId、specialistId、query、docIds、meetingId/videoCallId)。
    • R1.4 persona 工具集更新走重新 provision/PATCH 脚本(persona 是离线烘焙的)。
    • R1.5(2026-07-15 复核新增,合规级) Active Directives 达视频:通话创建时把该 (org × specialist) 的生效 directives 注入 conversational_context 顶部(复用 conversation-starter 已有的顶部 directive 块先例),内容标注"最高优先、压过其余上下文、不得向客户复述";红线类内容的跨渠道一致优先于 facts 记忆交付。可选:in-call 刷新工具(长通话中 directive 变更)列 v1.1。

W2 — 跨渠道共享记忆层(P0,架构核心)

存储:默认在既有 specialist_memories 上扩展(#1197/#3131;D4 于 2026-07-15 复核修订——原文误判"文本侧无长期记忆",实际该表已存在、已接入 chat 注入路径与 Expert 治理 UI):按 expand-contract 补 source_channelsource_user_idconfidencestatus(active/retracted) 字段与 rolling_summary 存储;仅当开发论证扩展不可行时才新建 specialist_client_memory。粒度 org × specialist(团队共享)(D1 拍板,与既有表天然一致;含已知隐私风险,见下),多租户矩阵行:Org × Specialist(specialist_id NOT NULL,RLS 双 GUC + service 层双过滤)。

⚠️ D1 已知隐私问题(产品有意接受,须让实现者与运营知晓):记忆按 org × specialist 团队共享 —— 同一 client org 内,员工 A 对 Specialist 说的内容(沉淀为 facts/摘要后)可能在员工 B 与同一 Specialist 的任意渠道会话中被引用。v1 接受此行为以换取"同一个真人专家"的连续体验;尚无按员工的私密隔离。缓解:facts 带 source_user_id 溯源(R2.3 的纠正/删除以此定位);敏感场景由 AM 在启用 shared_memory_enabled 时按 org 评估。后续如需"用户私有档",在 v2 增加 visibility: team|private 字段(expand 兼容,不需要重建表)。

  • 结构(草案):facts[](带来源渠道、来源用户 source_user_id、时间戳、置信度、状态 active/retracted)、preferences[]rolling_summary(分渠道 + 汇总)、updated_at。表设计走 expand-contract。
  • 写入端:
    • R2.1 文本:合并两条既有写入线——per-conversation agent_context 沉淀 与 specialist-memory-extraction job(现为 resolve 时 4 个英文正则句式)——升级为 LLM 化提取(复用 LlmService,保留键白名单与"仅 org 级事实"守卫)写入共享层;agent_context 保留为会话内工作记忆,双写过渡。
    • R2.2 视频:通话结束回调触发 BullMQ job(稳定 jobId,幂等)→ transcript 摘要/事实抽取 → 写共享层,来源标 video⚠️ 共享管线要求(§11):通话后 transcript 处理必须是一条管线、多路输出 —— 同一次 LLM 抽取同时产出 ① 共享记忆 facts/摘要(本 PRD)和 ② 行动项 → client_briefs.data.follow_ups(邻接 epic 的"通话后自动跟进")。两个立项不得各建一条 transcript 管线。
    • R2.3 记忆治理:facts 可由 AM/Expert 查看、纠正、删除(retract 即全渠道立即失效);写入治理按 D2(自动写入 + 低置信标记;强事实过 Expert 队列)。纠正/删除依 source_user_id + 来源渠道定位。注:Expert workspace 已有记忆查看/删除 UI(workspace.service)——在其上补纠正/retract 与置信度展示,不另起页面。
  • 读取端:
    • R2.4 文本 /v1/chat:注入已存在(appendSpecialistMemoryContext,draft/stream/regenerate 三路)——本项工作为预算复核(现 20 条 / 4000 字符)、格式与新字段(置信度/状态)对齐,及与 agent_context 的叠加语义梳理。
    • R2.5 视频:通话创建时把共享记忆摘要拼进 conversational_context;并新增 recall_memory in-call 工具做深查。⚠️ 共享注入点(§11):通话创建时的 context 组装应收敛为一个可组合的 builder(记忆摘要 + 每日摘要/议程 + KB 快照各为一段),邻接 epic 的"摘要注入 + 主动开场"(改造 buildOpeningPhrase 的冷启动)复用同一 builder,不另起炉灶。开场白从"有什么可以帮你?"改为按注入内容主动汇报,两个立项共同受益。
    • R2.6 Slack/Email 通路复用文本读写端(它们最终都走 conversations → /v1/chat,天然获益)。
    • R2.7(2026-07-15 复核新增) 组装位序:共享记忆在 prompt 组装中的优先级低于红线/Active Directives/golden answers,高于一般会话历史——与 prd-specialist-value-output 的 R5.1 优先级链对齐;记忆内容按不可信数据包裹注入(参照 #3190/#3406 先例),防止"记忆"被用作指令注入面。
  • 一致性:记忆写入为 best-effort(不阻塞业务回复);读侧容忍分钟级延迟。

W3 — Skill/工具一致性(P2,v2)

  • 目标:Tavus persona 工具集按 Specialist 派生(与文本侧同一来源),替代固定并集;Specialist 工具变更 → persona PATCH 同步。
  • 前置:文本侧"工具故事"收敛已立项 —— #4399(chat 路径 toolsManifest + 工具回调)就是该工作;draft 路径今天无业务工具、agentic 绑定是 per-org 而非 per-specialist。在 #4399 落地前对齐视频是空中楼阁,故降为 v2,先出设计文档(可另立 ADR)。
  • 补充范围:config-assets 的 skill 结构化红线段(Phase 3 组装器消费)属红线类内容,应与 R1.5(directives)同级纳入视频对齐范围——红线在文本侧生效而视频侧穿透,与 directives 是同一类合规断裂。

7. 安全与隔离(硬约束)

  1. Tavus documents/knowledge_base API 保持三层硬禁,本 PRD 所有知识注入都走我们自己的检索 + 回调。
  2. 记忆存储(既有 specialist_memories 扩展,或备选新表)属"Customer PII"隔离等级(ADR-020 矩阵需登记/复核):RLS 双 GUC + service 层 org×specialist 双过滤;新增/变更实体必须带矩阵 docstring(repo 规约)。
  3. webhook handler 的租户上下文一律从我们自己的 video_calls/meetings 行反查,Tavus 回传参数仅作校验。
  4. 记忆内容属客户数据:导出/删除需纳入(未来)数据删除流程;facts 带来源渠道 + source_user_id 可追溯。
    • D1 隐私标注:记忆为 org × specialist 团队共享(见 §6 W2 的风险框)。这是产品有意的 v1 取舍,不是实现疏漏;任何面向 client 的说明材料在提及记忆功能时应如实描述"你的团队与该 Specialist 的沟通会被共同记住"。
  5. Tavus webhook 鉴权维持共享 token 机制(勿改回 HMAC —— Tavus 不签名,repo 安全规则第 6 条)。

8. 依赖与阶段

阶段内容依赖
v1(P0)W1(search_knowledge_base 工具)+ W2 骨架(记忆存储 + 视频回写 + 文本读)O1/O2 拍板(已决策,见 §9 D1/D2);ADR-020 矩阵登记
v1.1(P1)通话前 KB/记忆快照注入;记忆治理 UI(AM/Expert 查看纠正);Expert 审稿页展示 factsv1
v2(P2)W3 工具一致性(先 ADR);记忆质量评测与召回策略优化文本侧工具故事收敛

9. 决策记录(2026-07-14,Franky 拍板)

原为开放问题 O1–O5,现均已决策(D1–D5)。实现与拆解以此为准:

  • D1 记忆身份键 → org × specialist(团队共享)。为换取"同一个真人专家"的连续体验,v1 采用团队共享粒度。已知且被接受的隐私问题:同 org 员工间信息会经由共享记忆扩散(员工 A 说的,B 的会话可能被引用)—— 详见 §6 W2 的风险框与 §7.4;facts 记录 source_user_id 以便溯源纠正;如后续需要用户私有档,v2 以 visibility 字段扩展。
  • D2 记忆写入人审 → v1 自动写入 + 治理。自动沉淀 + 低置信度标记 + AM/Expert 可查看/纠正/删除(retract 全渠道即时生效);强事实(金额、日期、承诺类)进 Expert 审核队列确认后才生效。
  • D3 视频 KB 召回形态 → v1 纯工具,v1.1 加预注入。v1 仅 search_knowledge_base in-call 工具;v1.1 增加通话前 top-N 快照注入 conversational_context 作零延迟兜底。
  • D4 W2 数据模型归属 → 默认扩展既有 specialist_memories(2026-07-15 复核修订)。原文建议新建 specialist_client_memory,基于"文本侧无长期记忆"的误判;复核发现 specialist_memories(#1197/#3131)已存在且已接入 chat 注入路径(appendSpecialistMemoryContext)与 Expert 治理 UI,粒度同为 org × specialist。修订为:默认在该表上 expand-contract 扩展(source_channel/source_user_id/confidence/status + rolling_summary);新表降为备选,仅当开发论证扩展不可行时采用。原理由中"client_briefs 语义混用会腐化"仍然成立。产品语义(粒度、字段、治理)不变。
  • D5 保留与配额 → v1 保守默认值,随合规对齐。初始建议:facts ≤ 200 条/键(超限按置信度+时间淘汰)、rolling_summary ≤ 4KB、保留期暂随会话数据同周期;上线前与合规确认,参数做成配置而非硬编码。对齐既有机制:specialist_memories 已有 expires_at/enabled 字段与删除 API——过期与禁用走既有字段,勿另设平行开关;注入预算沿用现有 20 条 / 4000 字符起步,按评测调参。

10. 成功度量与验收

  • G1–G4 的评测方式:构造 (org, specialist, KB 文档, 既有 facts) 的种子数据集,文本与视频各跑同题问答;隔离断言进单测(视频 handler 的 org 过滤、跨 org 负例)。
  • 上线开关:video_kb_enabledshared_memory_enabled 按 org × OSA 灰度,默认关闭,先在内部演示 org 开启。

11. 邻接工作整合:每日摘要 + 可配置排期通话(Terence 反馈,2026-07)

Terence 的产品反馈(定期汇报电话 + "AI 进通话没有上下文、干等提问")与本 PRD 部分汇合。经核对:定时呼叫基建已存在(WeeklyCallSchedulerService,#2059:BullMQ 按主 Specialist 分配扇出、建排期通话、发邮件),但节奏写死(每周一 10 点)、无去重、无 Expert 单次预约 UI/API、排期通话无议程字段;且所有通话(含定时周会)都是冷启动房间 —— persona 只会 buildOpeningPhrase 式的"Hi,有什么可以帮你?"。

立项边界:摘要页(/dashboard/daily + client_daily_digests)、Expert 可配置排期(cadence/议程模板/去重)属独立邻接 epic(挂 Tavus/video-calls 区域),不并入本 PRD。但两个立项在以下组件上必须共享,分工如下:

共享组件本 PRD 负责邻接 epic 负责约束
通话创建时的 context 组装可组合 builder 骨架 + 记忆摘要段 + KB 快照段(R2.5 / R1 系)每日摘要段 + 排期议程段单一 builder,分段可插拔;禁止两套 context 拼装代码
主动开场(buildOpeningPhrase 冷启动改造)开场引用共享记忆("上次我们聊到…")开场播报每日摘要/议程("昨天以来发生了 X、Y、Z…")同一开场机制,内容按注入段生成
通话后 transcript 处理facts/摘要 → 共享记忆层(R2.2)行动项 → client_briefs.data.follow_ups一条 BullMQ 管线、一次 LLM 抽取、多路输出
每日摘要的数据源共享记忆层可作为摘要的输入之一(facts 变化、待跟进)client_daily_digests 生成任务摘要任务读记忆层走正式 service 接口,不直查表

排序建议(合并两边视角):摘要任务+存储 → 摘要页+呼叫按钮 → 共享 context builder(本 PRD W1/W2 读侧 + 摘要注入一起落)→ 主动开场 → Expert 可配节奏 → 共享 transcript 管线(本 PRD R2.2 + follow-ups 一起落)。人力:Alex K(scheduler)、Alex D(前端)、Emanuele(新 worker 涉 infra)。

对本 PRD 的影响:W1/W2 的范围与优先级不变;R2.2 与 R2.5 增加"共享管线/共享注入点"约束(见对应条目)。建 Epic 时两边子 issue 需互相引用,共享组件各出一条明确归属的 issue,避免并行造轮子。