Files
ai-kefu-jc/docs/2026-09-08-stop-reasking-contact-changelog.md
T
2026-09-29 14:15:12 +08:00

7.4 KiB

改动文档:客户已留资后不再重复索要联系方式

  • 日期:2026-09-08
  • 分支:chany_dev_dev
  • 状态:160 项测试全绿(基线 133,净增 27);真机 GLM 冒烟未执行(清单见 §6,部署前置项)
  • 实施档案:superpowers/plans/2026-09-08-stop-reasking-contact.md(经独立评审两轮+自查实证一轮收敛;执行期评审又抓出 4 处计划级缺陷,见 §5)

1. 背景与问题

客户已发 WhatsApp 号码后继续聊,AI 仍反复索要 WhatsApp/邮箱(生产实测:客户被迫三次重发同一号码,AI 五次开口要号)。逐轮取证定位六条根因:

# 根因 一句话
1 捕获缺口 倒装("0712 345 678 is my whatsapp")/无is/msg-me/wa冒号等形态正则漏收,extractor 再漏则画像恒空,全防线失效
2 同轮竞态 提醒/has_contact 用上一轮画像,发号当轮完全不设防
3 App 脚本打架 已留资仍无条件注入逐字"Drop your WhatsApp"脚本,与同提醒里"禁止再索要"互相矛盾(GLM 听逐字不听抽象)
4 触发词过宽 "I'll call you later" 误命中索要触发 → 莫名注入要号脚本
5 零号码墙自破 墙替换句不看 has_contact,文案本身就是索要——回显形态稍有出入即在刚发号后再要一次
6 生产日志主因 4 次违规索要全部是 GLM 自由生成(逐字背 system.md 留资模板),确定性门控零拦截,提醒禁令被无视

2. 三层实现

2.1 数据层(尽早尽全地看见"已留资")

  • 同轮即时扫描(conversation.py):构建提醒前对当前消息跑一次纯正则 scan_user_messages,只并入本轮内存视图(提醒/has_contact 路由),不落库——持久化与邮件触发时序零变化
  • 正则补四形态(contact_pipeline.py):倒装(仅显式渠道词 whatsapp/wa/wechat/微信,防"2500000 is my number one choice"排位表述误绑)、my number X(无is)、text/msg/ping me X、wa: X、中文倒装"13800138000 我的微信"
  • key 模糊归一:精确别名优先 + contains 兜底——extractor 即兴 key("联系电话"/"WhatsApp账号")不再静默丢值

2.2 提醒/过滤层(拆掉三条确定性索要引擎)

  • App 提醒门控:已留资(confirmed/suspect)时索要脚本换成"经理会主动联系你"版,与"禁止再索要"不再打架;web 分支不动
  • 零号码墙路由:已留资时替换句用新常量 NO_CONTACT_ALREADY(F6 同款修法)
  • 再索要墙(核心新增):has_contact 时输出流中的索要句逐句静默丢弃(丢句不掐断);整条回复全是索要句时兜底流出 NO_CONTACT_ALREADY 防空回复;模式集与 system.md 全部留资模板+生产日志 4 句原话逐字对齐(实证 13 命中/12 放行);未留资闸门全关——首次合法索要不受影响
  • 触发词收窄:第一人称将来时(i'll/i will/let me,含弯引号变体)定宽负向后顾排除

2.3 prompt 层(软加固)

  • system.md"假称已留过号"改为先回看记录:确有号码→确认收到绝不要求重发
  • 提醒"已提供"段附逐字话术(直接引用 NO_CONTACT_ALREADY 常量,与墙替换句同源不漂移)

3. 文件清单

文件 动作
app/services/conversation.py 同轮扫描/App门控/墙路由/再索要墙接线/触发词/逐字话术
app/services/contact_pipeline.py 正则四形态+倒装正则+key模糊归一(含 PHONE_ADJACENCY_SCAN_RE 仅扫描层)
app/services/boundary_filter.py NO_CONTACT_ALREADY + REASK_PATTERNS/asks_contact
app/prompts/system.md 先查记录话术(1 处)
tests/test_contact_pipeline.py +11
tests/test_lead_email_trigger.py +13
tests/test_boundary_filter.py +3

前端零改动、无 schema、无新配置。提交序列(逐个可回滚): 06a758f 同轮扫描 → 2ec78cd+cecb804 正则扩充(+评审修正) → 3f87f03 key归一 → 7ccef5a App门控 → 519d280 墙路由 → 92a5bb6+694246b+7b96491 再索要墙(+评审修正) → ca935db 触发词 → 7492274 prompt → bc4e02b 逐字话术 → 0aa0cef 端到端。

4. 效果对账(对生产日志场景)

用 2026-09 生产日志逐句重放:首次问价要号(合法)保留;后续 4 次违规索要——App 脚本/墙替换句类由 §2.2 门控根除,GLM 自由生成类由再索要墙确定性丢弃;客户仅需发一次号码。三条索要引擎(价格墙替换句、App脚本/零号码墙替换句、GLM 生成句)全部确定性关闭,残余仅剩"正则未覆盖表述的当轮失守(下一轮兜底)"与"再索要墙模式漏拦(GLM 改写措辞)"。

5. 执行期评审抓出的计划缺陷(记录防重蹈)

  1. 计划原版裸 my number X 分支放进共享正则会授予 latest_stated_contacts 覆盖权,击穿改号更正邮件链(实证复现 ['lead'] != ['lead','fix','fix'])→ 拆为仅扫描层 PHONE_ADJACENCY_SCAN_RE
  2. whats app 双空格/NBSP 变体 KeyError 会崩溃每消息热路径 → 归一化 helper + 回归测试
  3. 计划的 web 分支测试断言 "...WhatsApp button" in text.lower() 永不通过(needle 大写)→ 修正
  4. 再索要墙首版无闸门反向钉死/全丢兜底 → 补三测试(闸门双向变异验证)

6. 已知限制与残余(原样转录计划"残余风险")

  1. 同轮扫描仍是正则——未覆盖表述当轮失守,下一轮轮末管道兜底;正则永远不是全集
  2. prompt 层不可单测——GLM 依从性靠真机冒烟;确定性防线才是主修
  3. NO_CONTACT_ALREADY 英文单语——与既有 WEB/APP 常量一致(如需中英路由属独立增强)
  4. 墙路由 confirmed-only——suspect 时墙仍可能问一次,有意(suspect 本该礼貌确认)
  5. contains 兜底可能误绑怪 key(如"无email")——概率极低且 value 仍过 split_validate
  6. 新正则进入 latest_stated_contacts 即获覆盖权——倒装只收显式渠道词,排位表述风险已实证排除并钉死
  7. 同轮改号当轮视图显示旧值——"已存优先"方向的两害取轻(不影响禁令触发)
  8. "We will call you" 仍触发——we 形将来时不排除,已留资时被 App 门控兜住
  9. 再索要墙是模式匹配不是语义理解——GLM 改写措辞可能漏拦/误拦;护栏:仅已留资启用、渠道词强制、丢句不掐断(误拦只损失一句);拦截日志 Re-ask wall dropped sentence(warning 级)回流补模式
  10. 再索要墙 tail 位闸门的 has_contact=False 分支无独立测试钉死(loop 位已钉;两处共享同一表达式,风险极低,记录在案)

7. 部署与回滚

重启生效(prompt/代码启动加载);无迁移、无配置、无前端;回滚 = revert 对应 commit(见 §3 序列)。

8. 真机 GLM 冒烟清单(⚠️ 未执行——部署前置项)

场景 期望
发号后继续问价(同轮:"my whatsapp is +86..., how much?") 确认收到 + 不再要号,报价转经理话术
倒装发号("0712 345 678 is my whatsapp")后闲聊 2 轮 全程零索要
App 会话发号后再问"how can I contact you" "经理会主动联系你"版话术,无 Drop your WhatsApp
"I'll call you later" 不触发索要脚本,正常道别
发号后说 "I gave you my number already" 先查记录确认收到,不要求重发
生产日志复现:how the price → 发号 → BYD Song L → zero → 续聊 仅首次要号,后续零索要(与 2026-09 日志逐句比对)