Files
ai-kefu-admin/tests/test_site_import_template.py
浅念 70e1355489 feat(site-import): 行为骨架模板与 few-shot 语料
- template/ 四件套:system/extractor/evaluator 骨架 + placeholders.json 占位符清单
  (system 15 个占位符,固定段与 jiancai 原文逐字一致——行级来源审计 0 缺失)
- fewshot/ 语料摘录:yotaienergys/televicsic 两生产租户四件套行业化片段
  (10592 字节 ≤18000 上限),README 含来源声明与数据治理记档
- tests/test_site_import_template.py:行业残留黑名单/占位符对称/红线锚点/
  行级来源/fewshot 尺寸与用途段守卫,7 条

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-20 19:35:08 +08:00

71 lines
3.4 KiB
Python

"""site_import 骨架模板与 few-shot 语料守卫(Task 4)。"""
import json
import re
from pathlib import Path
TPL_DIR = Path(__file__).resolve().parents[1] / "app" / "platform" / "site_import" / "template"
FS = Path(__file__).resolve().parents[1] / "app" / "platform" / "site_import" / "fewshot" / "fewshot_excerpts.md"
JIANCAI_SYSTEM = Path(__file__).resolve().parents[1] / "seed_profiles" / "jiancai" / "prompts" / "system.md"
# 行业专属词黑名单(jiancai 管道 / yotai 储能 / televics 炉辊三行业的专属词;
# WhatsApp、manager、quotation 等通用外贸词不在其列)
INDUSTRY_WORDS = [
"管道", "pipe", "HESUPIPE", "储能", "storage", "炉辊", "roller",
"TELEVIC", "YOTAI", "HDPE", "PVC", "PE100", "SDR", "DN110",
"给水", "燃气", "排污", "灌溉", "波纹管", "球墨铸铁",
]
class TestTemplatePurity:
def test_骨架无行业残留(self):
for fname in ("system", "extractor", "evaluator"):
t = (TPL_DIR / f"{fname}_template.md").read_text(encoding="utf-8")
low = t.lower()
for w in INDUSTRY_WORDS:
assert w.lower() not in low, f"{fname}_template.md 行业残留: {w}"
def test_占位符与清单一致(self):
ph = json.loads((TPL_DIR / "placeholders.json").read_text(encoding="utf-8"))
assert set(ph) == {"system", "extractor", "evaluator"}
for fname, keys in ph.items():
t = (TPL_DIR / f"{fname}_template.md").read_text(encoding="utf-8")
for k in keys:
assert "{{" + k + "}}" in t, f"{fname} 缺占位符 {k}"
# 反向:模板中每个 {{xxx}} 都在清单
for fname, keys in ph.items():
t = (TPL_DIR / f"{fname}_template.md").read_text(encoding="utf-8")
found = set(re.findall(r"\{\{([^}]+)\}\}", t))
assert found == set(keys), f"{fname} 占位符不对称: {found ^ set(keys)}"
def test_红线段锚点齐全(self):
t = (TPL_DIR / "system_template.md").read_text(encoding="utf-8")
for anchor in ["语言规则(最高优先级)", "职能边界", "红线(任何情况下不可违反)",
"不能出现任何价格数字", "施压", "禁止说的话", "联系方式引导策略",
"12 hours", "国家代码"]:
assert anchor in t, f"缺锚点: {anchor}"
def test_固定段行级来源(self):
"""非占位行应逐字存在于 jiancai 原文(允许空行/标题差异 ±5% 行)。"""
j = JIANCAI_SYSTEM.read_text(encoding="utf-8").splitlines()
jset = set(l.strip() for l in j)
t = (TPL_DIR / "system_template.md").read_text(encoding="utf-8").splitlines()
missing = [l.strip() for l in t
if l.strip() and "{{" not in l and "#" not in l[:2]
and l.strip() not in jset]
# 允许少量结构性改写(拆段标题等)——阈值 ≤8 行,且打印出来人工可核
assert len(missing) <= 8, f"来源外行过多: {missing}"
class TestFewshot:
def test_尺寸上限(self):
assert len(FS.read_bytes()) <= 18000
def test_两租户都在(self):
s = FS.read_text(encoding="utf-8")
assert "yotaienergys" in s and "televicsic" in s
def test_用途段落齐(self):
s = FS.read_text(encoding="utf-8")
for sec in ["身份", "追问", "好差", "事实卡", "提取器", "评估器"]:
assert sec in s, f"fewshot 缺用途段: {sec}"