From d023349699a521277bec875646b757a970bfc08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Thu, 8 Oct 2026 16:13:17 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20spec=E7=AC=AC=E4=BA=94=E8=BD=AE?= =?UTF-8?q?=E8=87=AA=E6=9F=A5=E2=80=94=E2=80=94=E5=88=A4=E5=AE=9A=E6=A0=91?= =?UTF-8?q?=E6=8C=AA=E8=BD=AE=E5=89=8D=E5=90=8C=E8=BD=AE=E5=9B=9E=E6=98=BE?= =?UTF-8?q?/=E5=A4=9A=E6=B8=A0=E9=81=93=E4=BB=85whatsapp=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?/b=E5=88=86=E6=94=AF=E4=B8=A5=E6=A0=BC=E6=80=A7/=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E8=A1=8Ce164/cc=5Freply=E6=BC=8F=E5=A1=AB=E5=85=9C?= =?UTF-8?q?=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- ...2026-10-08-cc-ip-country-confirm-design.md | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/superpowers/specs/2026-10-08-cc-ip-country-confirm-design.md b/docs/superpowers/specs/2026-10-08-cc-ip-country-confirm-design.md index 99ddc57..2f15f69 100644 --- a/docs/superpowers/specs/2026-10-08-cc-ip-country-confirm-design.md +++ b/docs/superpowers/specs/2026-10-08-cc-ip-country-confirm-design.md @@ -17,7 +17,7 @@ | 职责 | 归属 | 理由 | |---|---|---| | 判定(有无码/建议国)、E.164 补全、状态机、邮件渲染 | **Python 确定性**(新模块 `cc_completion` + phonenumberslite) | 状态不可能被幻觉;可离线确定性测试;邮件触发不押在 LLM | -| 客户答语理解(肯定/否定/国名) | **extractor LLM**(schema 加 `cc_reply` 可选字段,单轮无状态分类) | "yeah that's right"/"naur"/"我在迪拜"正则极脆弱,恰是 LLM 强项;extractor 本每轮跑,零额外调用。**双门控**:extractor.md 声明"仅当客户在回应号码确认时填写 cc_reply";Python 侧仅在 `_cc` 等待态(未 confirmed 且 attempts 未耗尽)时消费——防止对无关问题的 yes 被误当确认 | +| 客户答语理解(肯定/否定/国名) | **extractor LLM**(schema 加 `cc_reply` 可选字段,单轮无状态分类) | "yeah that's right"/"naur"/"我在迪拜"正则极脆弱,恰是 LLM 强项;extractor 本每轮跑,零额外调用。**双门控**:extractor.md 声明"仅当客户在回应号码确认时填写 cc_reply";Python 侧仅在 `_cc` 等待态(未 confirmed 且 attempts 未耗尽)时消费——防止对无关问题的 yes 被误当确认;**漏填兜底**(extractor 未识别出客户在答确认)→ 等同无回应,attempts 递增走 fallback | | 话术生成与确认句必出 | 提醒注入 + **既有墙骨架**(白名单放行/缓冲替换——四轮生产实测过的机制) | GLM 对反惯性指令 0/8 服从的血泪教训,确认回显必须墙保 | ## 3. 判定树(`cc_completion.classify(number, ip_iso)`) @@ -25,7 +25,9 @@ ``` 号码 ├─ 以 +/00 开头 ──────────────────► HAS_CC(现有流程直走,不动) - ├─ 以 IP 国码开头且去码后剩余合法 ──► HAS_CC_NAKED → 静默规范化(无对话动作) + ├─ 以 IP 国码开头且去码后剩余合法 ──► HAS_CC_NAKED → 静默规范化(无对话 + │ 动作;此分支无确认防线,依赖剩余段对该国 is_valid 严格校验——碰撞需 + │ "以X码开头+剩余恰为X国合法号"多重巧合,错误率极低,拨错有客户反馈兜底) ├─ phonenumbers region=IP国 解析合法 ─► NEED_CC,建议=IP 国(高置信) └─ 均不匹配(VPN/罕见格式)─────────► NEED_CC,建议=naive(去前导0+IP码,回显靠客户纠错) IP 无效/未知 → NEED_CC 无建议国 → 问"方便发带区号完整号吗"(1 轮为限) @@ -43,9 +45,10 @@ raw_info["_cc"] = { ``` - **canon 组**:phone 与 whatsapp 同号(canon 相同)共享一个确认流,确认一次 - (实现:`_cc` 以 canon 字符串为组键或渠道间 canon 相等时联动,attempts - 以组为计数主体);不同号各自独立——**换号(canon 变化)即重置该组状态机 - 重走判定树**(结构性解决"改号残留":旧补全永不跟随新号) + (attempts 以组为计数主体);**不同号时只有 whatsapp 组走确认流**(主联系 + 渠道,对话永远只确认一个号),phone 组一律 `ip_proposed` 静默补全+标注、 + 不确认(第五轮自查简化)——**换号(canon 变化)即重置该组状态机重走判定树** + (结构性解决"改号残留":旧补全永不跟随新号) - **source 语义钉死**:`prefix_normalized` → **confirmed=true**(码是客户自己 写的,首封**无**"未经确认"标注);`customer_stated`=客户报国名重算后确认; attempts 耗尽落定时 source 改写为 `fallback`(标注保留"未经客户确认"); @@ -101,7 +104,8 @@ v2 核心是让 AI **回显补全号**,而现行提示词全线教的是"不 | 客户确认(号码未变) | **不补发**(首封已可拨;后续渲染自动去标注) | 状态升级透明 | | 客户纠正/换号 | 现有**改号更正通道**(canon 变化自然触发) | 现有机制零新逻辑 | -- 渲染点:email_service(正文联系方式行 + 更正/回头客路径,签名加参取 `_cc`); +- 渲染点:email_service(正文联系方式行 + 更正/回头客路径,签名加参取 `_cc`; + **邮件主题行的号码也用 e164、不加标注**——主题拥挤); lead_push 的 contact 给干净 e164(契约要求"带国际区号且有效"),标注走 profile 派生(出站时由 `_cc` 计算,不落正常键——零 LLM 泄漏面) - `profile_out` 先消费 `_cc` 生成补全 → 再过滤 `_` 键(顺序钉死) @@ -111,11 +115,13 @@ v2 核心是让 AI **回显补全号**,而现行提示词全线教的是"不 ## 6. 管道接入点与 IP 入口(终审钉死) -- **两个钩子**(锚点错了"首封即发补全号"会静默失效): - 1. **轮末**:联系方式四层合并之后、`_maybe_send_lead_email` **之前** - (conversation.py 约 :500-526 区间)同步跑判定树写 `_cc`——首封补全号 - 与推送派生都依赖它 - 2. **轮前**:reminder 构建时读 `_cc`,等待态注入回显确认句(4b-3 让位句) +- **两个钩子**(锚点错了"首封即发补全号"会静默失效;第五轮自查优化—— + 判定树挪轮前,全链同轮完成,客户少等一轮): + 1. **轮前**:即时扫描发现裸号后**同步跑判定树**(纯计算毫秒级)建 `_cc` + → 本轮 reminder 即注入回显确认 → **同轮回显**;与一次性计数写回同事务落库 + 2. **轮末**:消费 `cc_reply` + 状态更新(确认落定/重算/换号重置)——在 + `_maybe_send_lead_email` **之前**(conversation.py 约 :500-526 区间), + 首封补全号与推送派生依赖已建好的 `_cc` - `/session` 路由注入 `Request`,XFF 第一段合并进 `conv.client_info` (**服务端 XFF 优先于客户端自报 ip**——WS 现状是客户端覆盖服务端、可伪造, 一并修正);chat_rest.py:107 只喂限流修不到数据流