feat: 再索要墙渠道精确化——索要缺失渠道放行(双要前置)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -273,6 +273,39 @@ REASK_PATTERNS = [
|
||||
]
|
||||
|
||||
|
||||
def asks_contact(sentence: str) -> bool:
|
||||
"""输出句是否在索要联系方式(仅在客户已留资时用于丢弃)。"""
|
||||
return any(p.search(sentence or "") for p in REASK_PATTERNS)
|
||||
# 渠道精确化(2026-10-08 spec §4.4): REASK 模式命中后按渠道词分辨——
|
||||
# 索要已在手的渠道才丢,索要缺失渠道放行(双要补邮箱场景);泛渠道词
|
||||
# 只要手上有任何号码渠道即丢(宁丢勿放);精确+泛同句共存时按①②自然
|
||||
# 实现任一命中判丢。中文泛词不用 \b(CJK 无词边界,"电话"前 \b 永不成立)。
|
||||
_PRECISE_CHANNEL_RE = re.compile(r"whatsapp|e-?mail|邮箱|微信|wechat", re.I)
|
||||
_GENERIC_CONTACT_RE = re.compile(r"\b(?:number|phone|contact)\b|电话|联系方式|号码", re.I)
|
||||
|
||||
|
||||
def _precise_channels_in(s: str) -> set:
|
||||
out = set()
|
||||
for m in _PRECISE_CHANNEL_RE.finditer(s):
|
||||
w = m.group(0).lower()
|
||||
out.add("email" if w in ("e-mail", "email", "邮箱")
|
||||
else "wechat" if w in ("微信", "wechat") else "whatsapp")
|
||||
return out
|
||||
|
||||
|
||||
def asks_contact(sentence: str, confirmed_channels: set | None = None) -> bool:
|
||||
"""输出句是否在索要联系方式(已留资时用于丢弃)。
|
||||
|
||||
confirmed_channels=None → 原行为(命中即丢,向后兼容);
|
||||
传入已确认渠道集合 → 渠道精确化(①②③④判定,见上注释)。"""
|
||||
s = sentence or ""
|
||||
hit = any(p.search(s) for p in REASK_PATTERNS)
|
||||
if confirmed_channels is None or not hit:
|
||||
return hit
|
||||
has_number = bool(confirmed_channels & {"whatsapp", "phone", "wechat"})
|
||||
precise = _precise_channels_in(s)
|
||||
has_generic = bool(_GENERIC_CONTACT_RE.search(s))
|
||||
if precise & confirmed_channels: # ① 句中有在手精确渠道词
|
||||
return True
|
||||
if has_number and has_generic: # ② 泛词 + 手上有号码渠道
|
||||
return True
|
||||
if not precise and not has_generic: # ③ 命中但无渠道词 → 保守丢
|
||||
return True
|
||||
return False # ④ 精确词全缺失/泛词但无号码 → 放行
|
||||
|
||||
@@ -207,8 +207,12 @@ class ConversationManager:
|
||||
# 方案B'(13.7): 句子粒度门控——干净句子逐句流出(恢复打字机),
|
||||
# 违规句永不流出:已流出内容全部干净,违规时接过渡话术收尾并掐断生成。
|
||||
# F6(D6联动): 客户已留联系方式时,收尾话术不得再索要——路由 contact 版
|
||||
has_contact = bool(split_validate(
|
||||
normalize_contacts(effective_raw.get("联系方式")))[0])
|
||||
# 渠道精确化(2026-10-08): confirmed 渠道集合传给再索要墙——
|
||||
# 索要缺失渠道(如已有 phone 问邮箱)放行,是 Task 3 邮箱轻补的前提
|
||||
_confirmed_contacts, _ = split_validate(
|
||||
normalize_contacts(effective_raw.get("联系方式")))
|
||||
has_contact = bool(_confirmed_contacts)
|
||||
_confirmed_channels = set(_confirmed_contacts)
|
||||
|
||||
yield {"type": "stream_start"}
|
||||
emitted = ""
|
||||
@@ -235,8 +239,9 @@ class ConversationManager:
|
||||
violation = "no_contact"
|
||||
break
|
||||
# Task 5b 再索要墙: 已留资时索要句静默丢弃(丢句不掐断,
|
||||
# 其余句子照常流出——软于两墙的掐断+替换)
|
||||
if has_contact and asks_contact(sentence):
|
||||
# 其余句子照常流出——软于两墙的掐断+替换);
|
||||
# 渠道精确化: 只丢索要已在手渠道的句子
|
||||
if has_contact and asks_contact(sentence, _confirmed_channels):
|
||||
logger.warning("Re-ask wall dropped sentence (conv=%s): %r",
|
||||
conv.id, sentence[:60])
|
||||
dropped_ask = True
|
||||
@@ -255,7 +260,7 @@ class ConversationManager:
|
||||
violated = True
|
||||
dirty = pending
|
||||
violation = "no_contact"
|
||||
elif has_contact and asks_contact(pending):
|
||||
elif has_contact and asks_contact(pending, _confirmed_channels):
|
||||
# Task 5b 再索要墙: 尾巴是索要句 → 静默丢弃(不流出不掐断)
|
||||
logger.warning("Re-ask wall dropped tail (conv=%s): %r",
|
||||
conv.id, pending[:60])
|
||||
|
||||
Reference in New Issue
Block a user