Call Input Smoke
0. 这份 smoke 要回答什么
Task Accuracy Baseline v1 证明的是:AI 能不能把 contact / call / message / lead / task context 转成正确的 taskDecisions[]。
Call Input Smoke 在它前面检查一层:
单次 call analysis 写进
calls表的 structured facts 是否够准、够完整、够可解释。
如果 task 错了,先不要马上怪 taskDecisions[] prompt。可能是上游 call facts 已经歪了:
- Call analysis 把
member_package误导成别的业务意图。 customerType写错,导致后续 contact lifecycle 判断跑偏。followUpNeeded/followUpReasons没写,导致 unresolved objective 被当成已解决。direction/fromPhoneNumber/toPhoneNumber/storeId归因不清,导致 AI 用错门店上下文。
这不是完整的 Call Accuracy Foundation。它是 demo 前的 lightweight upstream sanity check:确认 Task Accuracy 依赖的 call facts 没有明显错。
1. 它在 pipeline 里的位置
这份 smoke 覆盖的是:
它不测试 raw audio transcription 质量,也不测试 Vapi。demo 前可以直接用已转写 transcript 或已落库 call row 来验证。
2. 当前 production context 已经喂了什么
contacts-analyzer 看到的 RECENT CALLS 是半结构化文本:
这些字段来自 ai-analysis-processor 的 call analysis output,再被 contacts-analyzer 当成 Layer 1 evidence 使用。
所以要分开验证:
- Call analysis 是否把 transcript 理解成正确 taxonomy。
calls表是否持久化了正确字段。contacts-analyzerprompt 是否真的拿到了这些字段。- Prompt 里的 enum values 是否来自
@retaintive/common/taxonomy/call-analysis,不要手写漂移。
3. Smoke 的 review 原则
不要做所有全排列。这里按 call decision point 覆盖:
- Source identity:这是 inbound call、outbound call、voicemail call,还是系统/非客户流量?
- Recency:
startTime是否格式正确,是否能和 contact 的 current time / last activity 对上。 - Direction:Inbound / Outbound 是否影响 attribution 和 follow-up 判断。
- Taxonomy:
primaryCategory、primarySubcategory、outcome、customerType、followUpReasons是否符合 common taxonomy。 - Outcome:客户目标是否已解决,还是 attempted / pending follow-up。
- Safety:wrong number、vendor、corporate inquiry、DNC signal 是否保留。
这个 smoke 不是看模型“会不会编一个合理故事”,而是看 production call facts 是否足够支撑后续 contact / task 判断。
4. 第一批 smoke scenario set
每个 scenario 至少检查三件事:
DB facts:callsrow 里的字段是否写对。Prompt context:contacts-analyzer的RECENT CALLSline 是否带到了这些字段。Expected implication:这些 call facts 是否足够支持后续 contact / task decision。
C-01 Additional class pack / add-on purchase
业务状态
现有会员打电话,说自己本月课包用完,想买一次额外 class 或 package。
必须看到的 call facts
calls.primaryCategory = revenue_impactingcalls.primarySubcategory = member_packagecalls.customerType = existing_membercalls.primaryOutcomeResult = attempted或successRECENT CALLS里出现revenue_impacting/member_packageexecutiveSummary说明是 package / add-on / extra class,不是 membership renewal
Expected implication
Task taxonomy 上更接近 upgrade,不是 renewal。短期 UI label 可以显示成 Upgrade / Add-on;长期再把 typeCategory 抽象成更通用的 objectiveType。
C-02 Billing / failed payment recovery
业务状态
会员的付款方式失败、卡过期,或需要补付款来恢复服务连续性。
必须看到的 call facts
calls.primarySubcategory = billing_issuecalls.customerType = existing_membercalls.followUpNeeded = yeswhen unresolvedfollowUpReasons只能来自 common taxonomy,例如needs_manager_approval或complaint_feedbackexecutiveSummary说明是 payment / billing continuity,不只是普通 service note
Expected implication
这类更接近 renewal / continuity recovery。AI 不应该把它当作普通 service note 忽略。
C-03 Downgrade / freeze / cancel risk
业务状态
会员表达想 downgrade、freeze 或 cancel,但还没最终确认。
必须看到的 call facts
primarySubcategory是membership_downgrade、membership_freeze或membership_cancel- cancellation 语义要进
topic_type = cancellationwhen customer explicitly wants to cancel outcome.result = pending_follow_upwhen unresolvedexecutiveSummary说明客户的真实意图和 unresolved next step
Expected implication
如果 objective 未解决,后续 task 应该偏向 cancellation_risk 或 retention,而不是 renewal。
C-04 Existing lead books intro
业务状态
Lead 接通电话并确认预约 intro / first class。
必须看到的 call facts
- Call direction 和 summary 能证明是 booking,不只是 generic inquiry。
primarySubcategory = intro_bookingcustomerType = prospective_clientprimaryOutcomeResult = successwhen booking is confirmedexecutiveSummary说明已经 booked,不只是 interested
Expected implication
已有 lead task 应该 close as booked。不要因为已经 booked 再创建 intake、waiver、arrival logistics task。
C-05 Outbound no-answer
业务状态
员工对一个 open objective 打电话,没人接。
必须看到的 call facts
calls.direction = OutboundcallState = no_answer或 summary 能证明 no answer- 没有客户新表达的 objection / DNC / close outcome
- 如果没有 transcript 或只有 no-answer metadata,summary 不应该伪造客户意图
Expected implication
通常只是给 existing task record_progress,不是 create new task,也不是随便 close。
C-06 Wrong number / non-customer business inquiry
业务状态
来电是 wrong number、vendor、corporate sponsorship、partner、marketing pitch,和健身 customer lifecycle 无关。
必须看到的 call facts
customerType = other,或历史 row 可能仍是 legacywrong_number- category/subcategory 能体现
corporate_inquiry、other或 wrong-number 语义 executiveSummary保存有用事实,但不要伪造成 lead/member
Expected implication
后续 contacts-analyzer 应该把普通 fitness task no-op,或 close invalid existing task。历史 cust=wrong_number 也必须被当作 hard stop。
C-07 Referral / bring-a-friend opportunity
业务状态
现有会员主动说要带朋友、问 guest pass、推荐家人,或留下 referral opportunity。
必须看到的 call facts
primarySubcategory = referral_program或 summary 明确提 referral / guest / friendcustomerType = existing_member或有明确 customer identityexecutiveSummary说明 referral opportunity 是否需要 staff follow-up
Expected implication
这可以支持后续 referral task。若同一个 contact 还有另一个 open task,Contact / Task UI 要能让 staff 看见 related open tasks。
C-08 Churned member asks to rejoin
业务状态
前会员主动来电,说想重新加入或回来上课。
必须看到的 call facts
customerType = former_member- inbound customer-initiated re-engagement evidence
primarySubcategory = reactivation_purchase- 如果 interaction 当场完成 rejoin,outcome 要能显示 success;否则 follow-up remains open
Expected implication
后续 task 应该偏向 win_back。这不是 cold outbound win-back;是 customer-initiated reactivation。
5. 当前已发现的 call prompt contract 风险
5.1 Call taxonomy prompt drift
ai-analysis-processor 的 Zod schema 已经大量引用 @retaintive/common/taxonomy/call-analysis。但 classify base prompt 曾经还有手写 enum 文案,例如 customer type、category、outcome、follow-up reason、secondary topic forbidden list。
这类手写列表的风险不是 DB 不认,而是 prompt contract 和 common taxonomy 漂移:模型读到旧定义,Zod 却按新 schema 校验。
处理原则:
- enum values / allowed values / forbidden list 必须从 common taxonomy 生成。
- 业务判断规则和例子可以留在 prompt,但值本身不要手写成第二份 source of truth。
- Prompt snapshot 必须让 assembled system prompt diff 可 review。
5.2 Legacy call rows 要保留解释
历史 call rows 可能还带旧的 customerType value,例如 existing、prospect、non_member、wrong_number。在完成数据迁移或 renderer normalization 前,prompt 必须告诉模型这些 legacy aliases 怎么理解。
最重要的是:cust=wrong_number 必须还是 hard-stop non-customer,不能因为新 taxonomy 只写 other 就失去保护。
5.3 Call Accuracy Foundation v1 的长期形态
#1132 里讨论的 subcategory -> primary category 方向长期是对的,但它不应该做成 prompt 里又一份手写 if-else。更稳的形态是:
这和 AI Agent Foundation 的关系是:
Facts:transcript、direction、from/to phone、storeId、duration、recording metadata。Tenant / Vertical Taxonomy Registry:当前是 gym taxonomy;未来 fraud、医疗、BPO 可以换自己的 taxonomy pack。AI Decision:LLM 提出候选 topic,不直接拥有最终 canonical category。Deterministic Canonicalizer:用@retaintive/common/taxonomy/call-analysis做 source of truth,避免 prompt 和 schema 漂移。Eval / Replay:Call Accuracy smoke / golden eval 验证 candidate extraction 和 canonical output 是否稳定。
6. Demo 前怎么用这份 smoke
每个 demo candidate 至少检查这一条链:
建议最小操作:
- 从 8-12 个 demo candidate 里选 3 个真实端到端 case。
- 对每个 case 保存一份 prompt context 或 OpenRouter log。
- 在 DB 里确认
calls的关键 structured fields。 - 如果错了,先归因:call transcript 错、call taxonomy 错、prompt contract 错,还是 downstream contact / task decision 错。