fix(engine): 非中/西语轮注入 other 语言提醒——英文漂中文镜像修复(Task 11 对向)

历史护栏: 中文/西语会话纯拉丁轮不注入(护住 Task 11 场景);wall other 为
可选变体(存量快照/auto/生成器回退 DEFAULT_WALL,引擎部署即全租户生效)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-11-03 10:01:23 +08:00
parent 9b2a1ae5d0
commit 77f90d951d
5 changed files with 104 additions and 13 deletions
+23 -1
View File
@@ -496,10 +496,32 @@ def test_reminder_language_note_follows_customer_language():
assert "跟随客户语言自然表达" in es
assert "号码逐字照抄" in es
assert "英文原版" not in es and "绝不翻译" not in es # 旧规则清零
# 英文客户不带语言提醒(默认英语,无需提醒)
# 2026-11-03 修正: 英文轮注入 other 语言提醒(默认英语方向此前无当轮
# 强制,system.md 压不住——中文语境+短英文查询整轮漂中文,与 Task 11
# 中文漂英文同款机理的镜像)
en = ConversationManager._build_context_reminder(
{}, "how much is the DN800 pipe?", [])
assert "语言提醒" in en and "不要出现汉字" in en
assert "全程使用中文" not in en and "西语" not in en
def test_language_note_other_history_guard():
"""2026-11-03 历史护栏: 中文/西语会话中的纯拉丁轮(DN800/ok/型号)
维持无注入——历史语言自然延续;无条件注入 other 会把 Task 11 修好的
中文规格混排场景反向掰成英文。护栏只看客户消息(role=user)。"""
zh_hist = [{"role": "user", "content": "你们做DN800的HDPE双壁波纹管吗"},
{"role": "assistant", "content": "做的,您大概需要多少?"},
{"role": "user", "content": "300米"}]
r = ConversationManager._build_context_reminder({}, "DN800", zh_hist)
assert "语言提醒" not in r # 中文会话纯拉丁轮: 不注入(现状保持)
es_hist = [{"role": "user", "content": "¿Cuál es el precio?"},
{"role": "assistant", "content": "Depende de la especificación"}]
r2 = ConversationManager._build_context_reminder({}, "DN110", es_hist)
assert "语言提醒" not in r2 # 西语会话纯拉丁轮: 同护栏
en_hist = [{"role": "user", "content": "how much for PE100?"},
{"role": "assistant", "content": "Need your specs first"}]
r3 = ConversationManager._build_context_reminder({}, "DN800", en_hist)
assert "语言提醒" in r3 # 纯英文会话: 照常注入
# 有画像时同样生效(挂 parts 尾部)
zh2 = ConversationManager._build_context_reminder(
{"意向品类": "波纹管"}, "多少钱一米?", [])
+40
View File
@@ -160,6 +160,46 @@ def test_template_with_literal_braces_rejected():
assert "reminders.boundary.normal" in str(ei.value)
# ---- 2026-11-03 英文漂中文修复: language_follow.other 可选变体 ----
def test_language_follow_other_optional_variant():
"""other 为可选变体: 在场则校验,缺省合法(auto 墙/生成器产出/生产 DB
快照无此键;运行期 _lang_note_for 回退 DEFAULT_WALL 文案)。设为必填
会让新代码编译旧生产快照即炸全部租户运行时——绝不改为必填。"""
import copy
base = _load("jiancai")
assert "other" in base["reminders"]["language_follow"] # 出厂墙已有
compile_wall(base) # 在场: 合法
without = copy.deepcopy(base)
del without["reminders"]["language_follow"]["other"]
compile_wall(without) # 缺省: 合法
bad = copy.deepcopy(base)
bad["reminders"]["language_follow"]["other"] = ""
with pytest.raises(WallConfigError):
compile_wall(bad) # 空串: 显性拒绝
def test_language_follow_other_text_pinned():
"""other 文案钉死关键语义: 纯反漂中文(不提任何语言分类——无重音符的
西/葡语客户会落进本桶,分类断言会把他们误导去英语)+模板句跟随+号码
照抄(与 zh/es 两条同款条款)。"""
note = _load("jiancai")["reminders"]["language_follow"]["other"]
assert "不要出现汉字" in note
assert "无法确定时用英语" in note
assert "跟随客户语言自然表达" in note and "逐字照抄" in note
assert "西语" not in note # 措辞禁区: 不做语言分类断言
def test_language_note_other_wall_fallback():
"""租户墙无 other 键(auto/存量生产快照)→ _lang_note_for 回退
DEFAULT_WALL 文案——引擎部署即全租户生效,无需推配置。"""
from app.engine.services import conversation as conv
auto = compile_wall(_load("auto"))
assert "other" not in auto.reminders["language_follow"] # 前提钉死
note = conv._lang_note_for("how much?", history=[], wall=auto)
assert "语言提醒" in note and "不要出现汉字" in note
def test_template_with_unknown_placeholder_rejected():
"""I-2: 白名单外占位符({name})编译期拒绝——原属运行期 KeyError。"""
cfg = _load("jiancai")