feat: CC强制墙——触发轮整段缓冲+流末country code判定+模板句整段替换
场景①三轮提示词修复 0/8 后的需求方决策(增补设计 §2): GLM 对反惯性的 CC 重发追问结构性无视,升级为输出侧确定性强制。 - 触发: 本轮 completion_marks == ["_cc_asked"](裸号在场且未问过) - 流式无法撤回 → 触发轮跳过逐句流出,整段缓冲(缓冲期间价格/零号码/ 再索要三墙照常逐句检查,优先级不变);流末统一判定 - 完整回复含 "country code"(中文轮认"国家代码",与注入的逐字追问句 同词)→ 零干预原样流出;不含 → 整段替换为 CC 模板句正文,logger.warning 留痕 - 模板句与 _CC_NOTE_* 同源化: _CC_ASK_* 抽出为共享正文,_CC_WALL_EN 加 "Got it — " 衔接头(_CC_WALL_ZH 与正文同句)——注入/替换两处 逐字锚点不漂移 - _cc_asked 计数照常流前落库,一次性消耗不受替换影响 - 测试 5 项: 替换(EN/ZH)+计数落库 / 含 country code 零干预(EN/ZH) / 非触发轮三形态(带前缀号/已耗/双渠道齐)原样流出 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -98,15 +98,24 @@ def _lang_note_for(msg: str) -> str:
|
||||
# Task 3(spec §4.1-2/§4.4, 2026-10-08): 缺失渠道轻补逐字模板——与 system.md
|
||||
# 联系方式引导策略节同源。注入的是"缺失渠道"(客户没给过的),与再索要墙的
|
||||
# 渠道精确化(Task 1)配套: 墙只拦已在手渠道的索要,这些话术恰好问缺失渠道。
|
||||
# CC 强制墙(2026-10-08 增补设计 §2)复用同源正文: _CC_ASK_* 是注入指引里
|
||||
# "请逐字使用这句"的正文;_CC_WALL_* 是墙的整段替换句(EN 加 "Got it — "
|
||||
# 衔接头,设计 §2 定稿文案;ZH 与正文同句)——两处逐字锚点不漂移。
|
||||
_CC_ASK_EN = (
|
||||
"Could you send the full number with the country code, "
|
||||
"like +966 5x xxx xxxx? Just so our manager can reach you directly.")
|
||||
_CC_ASK_ZH = (
|
||||
"麻烦重发一下带国家代码的完整号码呗(比如 +966 5x xxx xxxx)?"
|
||||
"客户经理直接加你。")
|
||||
_CC_WALL_EN = "Got it — " + _CC_ASK_EN
|
||||
_CC_WALL_ZH = _CC_ASK_ZH
|
||||
_CC_NOTE_EN = (
|
||||
"⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户留下的号码不含"
|
||||
"国家代码,客户经理无法直接回拨。请逐字使用这句:\"Could you send the "
|
||||
"full number with the country code, like +966 5x xxx xxxx? Just so our "
|
||||
"manager can reach you directly.\" 仅此一次,客户不给就不再提。")
|
||||
"国家代码,客户经理无法直接回拨。请逐字使用这句:\"" + _CC_ASK_EN + "\" "
|
||||
"仅此一次,客户不给就不再提。")
|
||||
_CC_NOTE_ZH = (
|
||||
"⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户留下的号码不含"
|
||||
"国家代码,客户经理无法直接回拨。请逐字使用这句:\"麻烦重发一下带国家代码"
|
||||
"的完整号码呗(比如 +966 5x xxx xxxx)?客户经理直接加你。\" "
|
||||
"国家代码,客户经理无法直接回拨。请逐字使用这句:\"" + _CC_ASK_ZH + "\" "
|
||||
"仅此一次,客户不给就不再提。")
|
||||
_EMAIL_NOTE_EN = (
|
||||
"⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户已留号码但还没"
|
||||
@@ -285,6 +294,11 @@ class ConversationManager:
|
||||
# (confirmed/suspect 已在 Task 3 写回处算好,此处复用)
|
||||
has_contact = bool(_confirmed_now)
|
||||
_confirmed_channels = set(_confirmed_now)
|
||||
# CC 强制墙(2026-10-08 增补设计 §2): 本轮注入的是国家代码追问时,
|
||||
# 输出侧确定性强制。流式无法撤回 → 触发轮不逐句流出,整段缓冲到
|
||||
# 流末统一判 "country code" 在场与否(缓冲期间价格/零号码/再索要
|
||||
# 三墙照常逐句检查,优先级不变)。提示词层全部保留,墙只是兜底。
|
||||
cc_wall = completion_marks == ["_cc_asked"]
|
||||
|
||||
yield {"type": "stream_start"}
|
||||
emitted = ""
|
||||
@@ -292,6 +306,7 @@ class ConversationManager:
|
||||
violated = False
|
||||
dropped_ask = False # Task 5b: 本轮是否有索要句被再索要墙丢弃
|
||||
dirty = ""
|
||||
cc_buffer: list[str] = [] # CC 触发轮: 已过墙句子的延迟流出缓冲
|
||||
# 15.3: 双墙裁决——价格墙检查在前: 同句双违规时价格路径话术优先
|
||||
# (职能边界话术更具体,且自带留资引导);仅纯号码/邮箱违规时
|
||||
# violation=="no_contact",用零号码墙替换句
|
||||
@@ -318,6 +333,9 @@ class ConversationManager:
|
||||
conv.id, sentence[:60])
|
||||
dropped_ask = True
|
||||
continue
|
||||
if cc_wall:
|
||||
cc_buffer.append(sentence) # 墙照检,流出延后到流末
|
||||
continue
|
||||
for i in range(0, len(sentence), 40):
|
||||
yield {"type": "stream_chunk", "content": sentence[i:i + 40]}
|
||||
emitted += sentence
|
||||
@@ -337,6 +355,8 @@ class ConversationManager:
|
||||
logger.warning("Re-ask wall dropped tail (conv=%s): %r",
|
||||
conv.id, pending[:60])
|
||||
dropped_ask = True
|
||||
elif cc_wall:
|
||||
cc_buffer.append(pending)
|
||||
else:
|
||||
for i in range(0, len(pending), 40):
|
||||
yield {"type": "stream_chunk", "content": pending[i:i + 40]}
|
||||
@@ -361,6 +381,29 @@ class ConversationManager:
|
||||
for i in range(0, len(closing), 40):
|
||||
yield {"type": "stream_chunk", "content": closing[i:i + 40]}
|
||||
emitted += closing
|
||||
# CC 强制墙裁决(2026-10-08 增补设计 §2): 触发轮缓冲全文在此判定——
|
||||
# 含 "country code"(中文轮认 "国家代码",与 _CC_NOTE_ZH 注入的逐字
|
||||
# 追问句同词)→ GLM 自发服从,缓冲原样流出,零干预;不含 → 整段替换
|
||||
# 为 CC 模板句正文。violated(价格/零号码墙)优先于本墙——沿用双墙
|
||||
# 裁决"更具体话术优先"惯例;_cc_asked 已在流前落库,一次性消耗不受
|
||||
# 替换影响。缓冲轮全部实义句被再索要墙丢弃时 cc_buffer 为空 → 同样
|
||||
# 走替换(模板句即本轮唯一实义输出,天然不触发下方兜底)。
|
||||
if cc_wall and not violated:
|
||||
cc_full = "".join(cc_buffer)
|
||||
if "country code" in cc_full.lower() or "国家代码" in cc_full:
|
||||
for i in range(0, len(cc_full), 40):
|
||||
yield {"type": "stream_chunk", "content": cc_full[i:i + 40]}
|
||||
emitted = cc_full
|
||||
else:
|
||||
logger.warning(
|
||||
"CC enforcement wall replaced reply (conv=%s): %r",
|
||||
conv.id, cc_full[:60])
|
||||
cc_template = (_CC_WALL_ZH if _CJK_RE.search(content or "")
|
||||
else _CC_WALL_EN)
|
||||
for i in range(0, len(cc_template), 40):
|
||||
yield {"type": "stream_chunk",
|
||||
"content": cc_template[i:i + 40]}
|
||||
emitted = cc_template
|
||||
# Task 5b 评审修正: 整条回复只有索要句(全被丢)→ 兜底流出"经理主动
|
||||
# 联系"句,绝不空回复。与上方墙收尾互斥——violated 路径已自带收尾,
|
||||
# 此处仅在无任何实义内容流出时接管;已流出的纯空白前缀一并作废,
|
||||
|
||||
Reference in New Issue
Block a user