bc903a273e
- scripts/extract_config.py: AST 解析两老项目源码取常量(不 import 源模块),
生成 seed_profiles/<slug>/{wall.json, brand_values.json, prompts/};幂等可重跑
- app/engine/wall_schema.py: compile_wall(json)→CompiledWall,坏结构/坏 regex
编译期显性失败(WallConfigError 含字段路径)
- boundary_filter/conversation: 墙词表/话术数据源切换为 DEFAULT_WALL
(jiancai 出厂 seed),函数逻辑不动、常量名保留为 wall 视图(既有测试零修改);
wall 数据化新增 pivots/pivots_contact/zero_number/reask_patterns 字段
- 脆锚点迁移: test_inline_prohibitions 断言对象从 conversation.py 源码改为
wall.json 数据文件,语义等价(唯一允许的测试修改)
- 回归: 322 既有全绿 + 10 新增 wall_schema 测试 = 332;提取脚本两遍无 diff
Co-Authored-By: Claude Code <noreply@anthropic.com>
232 lines
17 KiB
JSON
232 lines
17 KiB
JSON
{
|
||
"price_patterns": [
|
||
"\\$\\s?\\d",
|
||
{
|
||
"pattern": "\\d[\\d,.]*\\s*(usd\\b|美元|块钱|万块?(?!\\s*(公里|km)))",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "\\d[\\d,.]*\\s?k\\b(?!\\s*(km|kilometers?|kilometres?|miles?|mi\\b|公里))",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(price|cost|quote)[^.\\d]{0,20}(?<![a-z])(?!(?:19|20)\\d\\d(?!\\d))\\d",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "\\d+\\s*[- ]?(day|week|month)s?\\b",
|
||
"flags": "i",
|
||
"comment": "# 时间承诺: 去掉 warranty 豁免(政策变更 2026-09-10——保修期限是编造的\n# 公司政策承诺,不再白名单)"
|
||
},
|
||
{
|
||
"pattern": "\\d+\\s*years?\\b[^.!?]{0,15}warranty",
|
||
"flags": "i",
|
||
"comment": "# 年限保修定向(双向): year 不能进时间模式(使用年限 \"under 5 years old\" 会误杀),\n# 只收 数字+年 与 warranty/质保/保修 的组合(含倒装\"质保3年\"/\"warranty of 8 years\")"
|
||
},
|
||
{
|
||
"pattern": "warranty\\s*(?:of|for|:)?\\s*\\d+\\s*years?\\b",
|
||
"flags": "i"
|
||
},
|
||
"\\d+\\s*年[^。!?]{0,8}(?:质保|保修)",
|
||
"(?:质保|保修)[^。!?]{0,8}\\d+\\s*年",
|
||
{
|
||
"pattern": "\\d+\\s*(?:天|周|个月)",
|
||
"comment": "# 中文时限承诺: 天/周/个月(年不收——裸 \"2024年\" 是年份/项目日期,\n# 带质保/保修的年限由上方定向组收)"
|
||
},
|
||
{
|
||
"pattern": "(budget|预算)[^\\d\\n]{0,12}\\d",
|
||
"flags": "i",
|
||
"comment": "# 裸预算复述(F3,方案B旗舰形态——冒烟 6/6 破防即此形,原模式完全漏检)"
|
||
},
|
||
"(两|三|四|五|六|七|八|九|十)\\s*万(?!\\s*(公里|km))",
|
||
{
|
||
"pattern": "(down\\s+payment|monthly\\s+payment|首付|月供)[^\\d\\n]{0,10}\\d",
|
||
"flags": "i",
|
||
"comment": "# 金融裸数(F4)"
|
||
},
|
||
{
|
||
"pattern": "[€£]\\s?\\d",
|
||
"comment": "# ---- 多语言墙(建材市场: 欧/英/南美/俄语区/中东) ----\n# 货币符号: €/£(参考项目只有 $)"
|
||
},
|
||
{
|
||
"pattern": "\\b(?:precio?s?|costo?s?|custo?s?|preço?s?|цен[аы]?|стоимость|(?:ال)?سعر|(?:ال)?أسعار|(?:ال)?ثمن)\\b[^\\d\\n]{0,20}(?<![a-z])\\d",
|
||
"flags": "i",
|
||
"comment": "# 价格名词前置(西/葡/俄/阿): 词后 0-20 非数字字符内出现数字\n# ⚠️ 拉丁词必须加 \\b 词边界——custo 是英文 customs 的子串,外贸高频,\n# \"customs paperwork for 20ft\" 会被误杀(Task 3 质量审查发现)\n# ⚠️ 阿语定冠词 ال 与词连写(السعر): 词首 \\b 落在 ل|س 之间(两者皆 \\w)\n# 不成立,备选须收 (?:ال)? 形态——裸 \\bسعر\\b 实测漏检 \"السعر 500 دولار\"\n# ⚠️ (?<![a-z]) 字母后顾(与英文组 (?<![a-z]) 同款): 建材规格数字永远\n# 跟在拉丁字母后(DN800/SDR11/PN16/SCH40),后顾天然放行——实测\n# \"El precio del DN800 PE100...\" 旧形态误杀,加后顾全放行且 HITS 全保\n# ⚠️ 复数/变格(spec 审查加固): precio?s?/costo?s?/custo?s?/preço?s?\n# (西葡 +s 复数;preço 的 ç 是词干,只放开 s——避免 \"preç\" 类\n# 错拼形态);俄语 цен[аы]?(цена/цены/цен);阿语复数 أسعار。\n# \\b 包裹不受影响——\"customs\" 中 costo?s? 无子串匹配(c 后是 u),\n# 词边界防线依旧成立\n# ⚠️ 无英文组的年份排除 (?!(?:19|20)\\d\\d): \"precios 2025\" 会命中\n# ——有意为之(价格词在前的宁拦勿放,与英文组从严方向一致但更保守)"
|
||
},
|
||
{
|
||
"pattern": "\\d[\\d,.]*\\s*(?:d[óo]lares?|euros?\\b(?!\\s*pallets?)|рублей|руб\\.?|доллар(?:ов|а|ы)?)",
|
||
"flags": "i",
|
||
"comment": "# 货币名词后置(数字+货币词): dólares/euros/рублей/долларов\n# ⚠️ 西里尔 долларов 变格必须单列(质量审查发现): 前置组只有名词\n# стоимость,动词句 \"стоит 500 долларов\"/\"будет стоить 800\n# долларов\" 前无价格名词,靠前置组兜不住\n# ⚠️ euros 排除 pallets 邻接——\"50 euro pallets\"(欧标托盘)是建材\n# 物流高频词,非价格"
|
||
},
|
||
{
|
||
"pattern": "\\d+\\s*[- ]?(?:d[ií]as?|semanas?|дн(?:ей|я)|недел[ьи]|أيام)\\b",
|
||
"flags": "i",
|
||
"comment": "# 多语言时间承诺(西/葡 dias|semanas,俄 дн/недел,阿 أيام;与英文\n# days/weeks 组同构)\n# ⚠️ 不收 horas/hours/小时——system.md 的 \"reply within 12 hours\"\n# 依赖此豁免(响应时效承诺非交期承诺)\n# ⚠️ 俄语变格只收 дн(ей|я)/недел[ьи] 主形态,其余变格(дню/неделю\n# 等)不收——宁可少而准\n# ⚠️ re.I 必须有——大写形态 '15 Días'/'30 SEMANAS' 实测要拦(质量审查),\n# 与英文时间组 re.I 对齐"
|
||
}
|
||
],
|
||
"deflections": {
|
||
"en": [
|
||
"Prices vary a lot by config and shipping — our manager will prepare an exact quote for you. What's your WhatsApp or email?",
|
||
"For an exact price our manager needs your config and destination — drop your WhatsApp and you'll have the quote today.",
|
||
"I'd rather give you an exact number than a rough guess — leave your WhatsApp and our manager will send it over."
|
||
],
|
||
"zh": [
|
||
"价格要看配置和目的地,客户经理会给你准确报价——留个WhatsApp或邮箱?",
|
||
"我让客户经理按你的情况出准确报价,留个联系方式,今天就能发你。"
|
||
],
|
||
"es": [
|
||
"El precio exacto depende de la especificación y el flete — nuestro gerente te lo prepara. ¿Me dejas tu WhatsApp o correo?",
|
||
"Para un precio exacto, nuestro gerente necesita tu especificación y destino — déjame tu WhatsApp y lo tienes hoy.",
|
||
"Prefiero darte una cifra exacta y no un estimado — déjanos tu WhatsApp y nuestro gerente te lo envía."
|
||
]
|
||
},
|
||
"deflections_contact": {
|
||
"en": [
|
||
"Our manager will send the exact quote to your WhatsApp shortly. Anything else about our pipes?"
|
||
],
|
||
"zh": [
|
||
"客户经理稍后会把准确报价发到你的 WhatsApp。还想了解什么管道产品?"
|
||
],
|
||
"es": [
|
||
"Nuestro gerente te enviará el precio exacto a tu WhatsApp en breve. ¿Algo más sobre nuestras tuberías?"
|
||
]
|
||
},
|
||
"pivots": {
|
||
"en": [
|
||
"Actually, for the exact price — what's your WhatsApp? Our manager will send it over."
|
||
],
|
||
"zh": [
|
||
"具体的报价,客户经理会发给你——留个WhatsApp或邮箱?"
|
||
],
|
||
"es": [
|
||
"Para el precio exacto — ¿cuál es tu WhatsApp? Nuestro gerente te lo envía."
|
||
]
|
||
},
|
||
"pivots_contact": {
|
||
"en": [
|
||
"Our manager will send the exact price to your WhatsApp shortly."
|
||
],
|
||
"zh": [
|
||
"客户经理稍后会把准确报价发到你的 WhatsApp。"
|
||
],
|
||
"es": [
|
||
"Nuestro gerente te enviará el precio exacto a tu WhatsApp en breve."
|
||
]
|
||
},
|
||
"no_contact": {
|
||
"web": "Just tap the WhatsApp button at the top of this chat — our manager will reply within 12 hours!",
|
||
"app": "Drop your WhatsApp and our manager will reach out to you directly with the full quote!",
|
||
"already": "Got it — our manager will reach out to you at your WhatsApp shortly with the full quote!"
|
||
},
|
||
"zero_number": {
|
||
"long_number": "\\+?\\d[\\d\\s\\-().]{8,17}\\d",
|
||
"any_email": "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
|
||
},
|
||
"reask_patterns": [
|
||
{
|
||
"pattern": "(?:what|which)['′]?s\\s+(?:your|the)\\s+(?:whatsapp|number|phone|e-?mail|contact|号码|联系方式)",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:got|have)\\s+(?:your|the)\\s+(?:whatsapp|number|phone|e-?mail|contact)[^!?.]{0,60}\\?",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:i['′]ll\\s+|i\\s+)?(?:need|want)\\s+(?:your|the)\\s+(?:whatsapp|number|phone|e-?mail|contact|号码|联系方式)",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "tell\\s+me\\s+(?:your\\s+)?(?:whatsapp|number|phone|e-?mail|contact|号码|联系方式)",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:could|can|would|may)\\s+you\\s+(?:leave|drop|share|give|provide|type|post)[^.!?\\n]{0,30}(?:whatsapp|number|phone|e-?mail|contact|号码|联系方式|微信|邮箱)",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:leave|drop|share|give)\\s+(?:me\\s+)?(?:your|us\\s+your?|a)\\s+(?:whatsapp|contact|number|e-?mail|联系方式)",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:drop|leave)\\s+yours\\b",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?:whatsapp|e-?mail|contact)\\s+or\\s+(?:whatsapp|e-?mail|contact)\\s*\\?",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "(?<!reach )(?<!reached )(?<!got )(?<!sent )(?<!did )(?<!to )your\\s+(?:whatsapp|number|phone|e-?mail|contact)\\b[^.!?]{0,20}[??]",
|
||
"flags": "i"
|
||
},
|
||
{
|
||
"pattern": "留[个下]?\\s*(?:你的?)?\\s*(?:whatsapp|微信|邮箱|联系方式|号码|电话)|给[我一]?个?\\s*(?:联系方式|whatsapp|微信|号码|邮箱|电话)|你的?\\s*(?:whatsapp|号码|电话|微信|邮箱|联系方式)[^。!?]{0,10}(?:是多少|多少|\\?)",
|
||
"flags": "i"
|
||
}
|
||
],
|
||
"triggers": {
|
||
"boundary": {
|
||
"pattern": "price|pricing|how\\s+much|\\bcost\\b|discount|cheaper|expensive|\\bfee\\b|quote|quotation|shipping\\s+(fee|cost|time)|freight|tariff|customs\\s+fee|best\\s+offer|any\\s+offer|free\\s+shipping|sample|certificat|\\bmoq\\b|minimum\\s+order|min\\s+order|container\\s+loading|fit\\s+in|per\\s+container|warranty|质保|保修|book(ing)?\\s|reserv|arrange|delivery|lead\\s+time|arriv|how\\s+long\\s+(does|will|would|to).*(take|arriv|deliver|ship)|roughly|ballpark|just\\s+tell|come\\s+on|at\\s+least\\s+(a|some|give)|budget|预算|价格|价钱|多少钱|报价|优惠|折扣|便宜|贵|划算|总价|落地|运费|关税|免费|到货|多久能到|交货|时效|发货|样品|证书|装柜|起订|预约|下单|定金|安排|大概|估个|估一|随便说|说个|求你|求了",
|
||
"flags": "i"
|
||
},
|
||
"budget": {
|
||
"pattern": "budget|预算",
|
||
"flags": "i"
|
||
},
|
||
"contact_ask": {
|
||
"pattern": "(your|our)\\s+(whatsapp|number|phone|email|contact)|(?<!i'll )(?<!i’ll )(?<!i will )(?<!let me )(contact|reach|call|email)\\s+(you|us)|你(们)?的?\\s?(whatsapp|号码|电话|微信|邮箱|联系方式)|(怎么|如何)联系|给我.{0,4}(号码|电话|联系方式)",
|
||
"flags": "i"
|
||
}
|
||
},
|
||
"reminders": {
|
||
"boundary": {
|
||
"budget": "⚠️ 职能边界提醒:客户报预算求推荐。推荐产品方案但绝不复述预算数字、不报价格 → 反问意向产品与需求规格 → 顺势引导留联系方式。",
|
||
"normal": "⚠️ 职能边界提醒:客户正在询问价格/优惠/交付时效/实质安排。绝对禁止给出任何价格数字(包括复述客户自己的预算)、交付时间或任何承诺,按职能边界对应话术处理。"
|
||
},
|
||
"contact_ask": {
|
||
"app_already": "⚠️ 客户正在索要我方联系方式,且客户已留过自己的联系方式。请逐字使用这句:\"Our manager will reach out to you at your WhatsApp shortly with the full quote!\"(中文同理)。绝对禁止输出任何号码或邮箱,也绝对禁止再索要客户已提供过的联系方式(缺失渠道可按轻补指引提一次;号码缺国家代码时按系统提醒回显补全后的完整号码请客户确认——仅系统提供的号码,禁止自编)。",
|
||
"app": "⚠️ 客户正在索要我方联系方式(最高意向信号)。当前为 App 会话,没有页面按钮——禁止使用任何 tap/button 按钮话术!请逐字使用这句:\"Drop your WhatsApp and our manager will reach out to you directly with the full quote!\"(中文同理引导客户留联系方式)。绝对禁止输出任何号码或邮箱。",
|
||
"web": "⚠️ 客户正在索要我方联系方式(最高意向信号)。请逐字使用这句指路:\"{no_contact_web}\"(邮箱同理指 Email 按钮)。绝对禁止口头报出任何号码或邮箱。"
|
||
},
|
||
"language_follow": {
|
||
"zh": "⚠️ 语言提醒:客户这条消息是中文——你的回复必须全程使用中文,一个英文单词都不能出现;模板句跟随客户语言自然表达(系统提醒提供的逐字话术优先用其语言版本,无则自然翻译保持意思与礼貌度);系统提供的补全号码逐字照抄,绝不改动数字。",
|
||
"es": "⚠️ 语言提醒:客户这条消息是西语——你的回复全程用西语,模板句跟随客户语言自然表达(系统提醒提供的逐字话术优先用其语言版本,无则自然翻译保持意思与礼貌度);系统提供的补全号码逐字照抄,绝不改动数字。"
|
||
},
|
||
"lead_given": {
|
||
"forbidden": "⚠️ 客户已提供联系方式({shown})。绝对禁止再索要客户已提供过的联系方式;缺失渠道仅可按轻补指引提一次;号码缺国家代码时按系统提醒回显补全后的完整号码请客户确认(仅系统提供的号码,禁止自编)。",
|
||
"respond_script": "需要回应时可直接逐字使用:\"{no_contact_already}\"(中文同理)。确认收到后继续解答客户问题即可,不必急着结束对话。",
|
||
"boundary_tail": "客户已留过联系方式——边界请求直接告知'客户经理会把准确报价/安排发到你 WhatsApp'即可,禁止再索要联系方式(缺失渠道可按轻补指引提一次;号码缺国家代码时按系统提醒回显补全后的完整号码请客户确认——仅系统提供的号码,禁止自编)。",
|
||
"suspect": "⚠️ 客户疑似已提供联系方式({shown})。禁止重新索要;可礼貌地请客户确认一次。"
|
||
},
|
||
"cc_guide": {
|
||
"echo": "⚠️ 号码确认指引(系统指令,绝对不要向客户提及这段说明):客户留下的号码不含国家代码,系统已按 IP 推测补全为 {intl}。请逐字使用这句:\"{cc_script}\" 本轮回复绝不写出任何号码数字——唯一例外是上面系统提供的补全号原文(逐字照抄,禁止自编或改动数字)。客户答复确认或纠正后,致谢即可,不再追问号码。",
|
||
"ask": "⚠️ 号码确认指引(系统指令,绝对不要向客户提及这段说明):客户留下的号码不含国家代码,且系统无法按 IP 推测补全。请逐字使用这句:\"{cc_script}\" 仅此一次,客户不给就不再提。客户答复后致谢即可,不再追问号码。"
|
||
},
|
||
"email_light": {
|
||
"en": "⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户已留号码但还没留邮箱。请逐字使用这句:\"Got it! And an email address would help too — our manager will send the formal quotation PDF there.\" 仅此一次,客户不给就不再提。",
|
||
"zh": "⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户已留号码但还没留邮箱。请逐字使用这句:\"收到!邮箱也留一个呗?客户经理把正式报价单 PDF 发你邮箱。\" 仅此一次,客户不给就不再提。"
|
||
}
|
||
},
|
||
"cc_templates": {
|
||
"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.",
|
||
"zh": "麻烦重发一下带国家代码的完整号码呗(比如 +966 5x xxx xxxx)?客户经理直接加你。",
|
||
"es": "¿Puedes enviar el número completo con el código de país, como +966 5x xxx xxxx? Así nuestro gerente puede contactarte directamente."
|
||
},
|
||
"wall": {
|
||
"en": "Got it — Could you send the full number with the country code, like +966 5x xxx xxxx? Just so our manager can reach you directly.",
|
||
"zh": "麻烦重发一下带国家代码的完整号码呗(比如 +966 5x xxx xxxx)?客户经理直接加你。",
|
||
"es": "Entendido — ¿Puedes enviar el número completo con el código de país, como +966 5x xxx xxxx? Así nuestro gerente puede contactarte directamente."
|
||
},
|
||
"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.\" 仅此一次,客户不给就不再提。",
|
||
"zh": "⚠️ 轻补指引(系统指令,绝对不要向客户提及这段说明):客户留下的号码不含国家代码,客户经理无法直接回拨。请逐字使用这句:\"麻烦重发一下带国家代码的完整号码呗(比如 +966 5x xxx xxxx)?客户经理直接加你。\" 仅此一次,客户不给就不再提。"
|
||
},
|
||
"echo": {
|
||
"en": "Got it — just to confirm: our manager will reach you at {intl} — is that right?",
|
||
"zh": "收到——跟您确认下:客户经理会通过 {intl} 联系您,这个号码对吗?",
|
||
"es": "Entendido — solo para confirmar: nuestro gerente te contactará al {intl} — ¿es correcto?"
|
||
}
|
||
}
|
||
}
|