86 lines
5.6 KiB
Python
86 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
"""Диагностика + демонстрация ДЕТЕРМИНИРОВАННОГО рычага коэффициента канон-консистентности
|
||
(follow-up к adaptive_incontext.py по запросу владельца: «раз не идём в гибрид — долбить
|
||
детерминированную сторону»).
|
||
|
||
Два вопроса:
|
||
1. ДИАГНОЗ: промахи в arm B_glossary (напр. 王胡) — это РЕАЛЬНЫЙ провал adherence
|
||
(модель не использовала утв. форму) или АРТЕФАКТ моего accept-регэкспа (напр. `Ван\b`
|
||
не ловит склонённое «Вана/Вану»)? Печатаем реальный вывод + два матча (строгий \b vs
|
||
склонение-толерантный стем).
|
||
2. РЫЧАГ: post-check находит промах → точечный re-ask («используй утв. формы X,Y») →
|
||
повторный перевод → коэффициент до/после. Это verifier-gated single-pass correction
|
||
(research/14 §6, M2) — тот самый детерминированный рычаг, а не дообучение.
|
||
|
||
deepseek-v4-flash, тот же чанк 阿Q. INDICATIVE (малый N). Usage: eval/.venv/bin/python eval/adaptive_reask.py
|
||
"""
|
||
from __future__ import annotations
|
||
import json, re, sys
|
||
from pathlib import Path
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
import refusal_bench as rb
|
||
|
||
ROOT = Path(__file__).resolve().parent
|
||
SRC = ROOT / "data" / "samples" / "zh" / "luxun-ah-q-ch5-9.txt"
|
||
CHUNK = SRC.read_text(encoding="utf-8")[6360:6360 + 650]
|
||
|
||
# canonical dst + СТРОГИЙ (\b, как в adaptive_incontext) и СКЛОНЕНИЕ-ТОЛЕРАНТНЫЙ стем-матч
|
||
ENT = {
|
||
"阿Q": ("А-кью", r"А[-\s]?кью", r"А[-\s]?кью"),
|
||
"未庄": ("Вэйчжуан", r"Вэйчжуан", r"Вэйчжуан"),
|
||
"赵太爷": ("почтенный Чжао", r"Чжао", r"Чжао"),
|
||
"王胡": ("Бородатый Ван", r"Ван\b", r"Ван[аоуые]?\b|Бород"),
|
||
"小D": ("Маленький Дэн", r"Дэн", r"Дэн"),
|
||
"假洋鬼子": ("Поддельный заморский чёрт", r"заморск\w+ чёрт|поддельн", r"заморск|поддельн|чёрт"),
|
||
"吴妈": ("У-ма", r"У[-\s]?ма", r"У[-\s]?ма"),
|
||
"邹七嫂": ("тётушка Цзоу Седьмая", r"Цзоу", r"Цзоу"),
|
||
}
|
||
SYSTEM = ("Ты профессиональный литературный переводчик. Переведи фрагмент на русский язык. "
|
||
"Сохрани все реплики и детали; стиль — живой литературный русский. Выведи ТОЛЬКО перевод.")
|
||
GLOSS = "ГЛОССАРИЙ (используй эти утверждённые переводы последовательно):\n" + \
|
||
"\n".join(f"{z} → {v[0]}" for z, v in ENT.items())
|
||
PRESENT = [z for z in ENT if z in CHUNK]
|
||
|
||
|
||
def score(out, strict):
|
||
idx = 1 if strict else 2
|
||
return [z for z in PRESENT if re.search(ENT[z][idx], out)]
|
||
|
||
|
||
def translate(user):
|
||
t, err, _ = rb.call_provider({"name": "deepseek", "base_url": "https://api.deepseek.com/v1",
|
||
"model": "deepseek-v4-flash", "api_key_env": "DEEPSEEK_API_KEY",
|
||
"max_tokens": 8000}, SYSTEM, user, timeout=180)
|
||
return t or ""
|
||
|
||
|
||
def main():
|
||
print(f"present entities ({len(PRESENT)}): {PRESENT}\n")
|
||
for rep in range(2):
|
||
print(f"================= REP {rep+1} =================")
|
||
out = translate(GLOSS + "\n\nФРАГМЕНТ:\n" + CHUNK)
|
||
strict, tol = score(out, True), score(out, False)
|
||
print(f"[B_glossary] строгий-матч {len(strict)}/8={len(strict)/8:.3f} | склонение-толерантный {len(tol)}/8={len(tol)/8:.3f}")
|
||
print(f" промах(строгий): {[z for z in PRESENT if z not in strict]}")
|
||
print(f" промах(толерантный, = РЕАЛЬНЫЕ провалы adherence): {[z for z in PRESENT if z not in tol]}")
|
||
# показать фактический рендер спорных сущностей
|
||
for z in ["王胡", "假洋鬼子", "吴妈"]:
|
||
can = ENT[z][0]
|
||
frag = re.findall(r".{0,4}(?:Ван|Бород|заморск|поддельн|У-ма|У ма|Ху|Хо)\w*.{0,6}", out)
|
||
print(f" {z}→канон «{can}»: фрагменты вывода {frag[:3]}")
|
||
# РЫЧАГ: re-ask по реальным промахам
|
||
miss = [z for z in PRESENT if z not in tol]
|
||
if miss:
|
||
terms = "; ".join(f"{z} = {ENT[z][0]}" for z in miss)
|
||
reask = (GLOSS + "\n\nФРАГМЕНТ:\n" + CHUNK +
|
||
f"\n\nВАЖНО: в переводе ОБЯЗАТЕЛЬНО используй утверждённые формы: {terms}. Перепиши перевод, применив их.")
|
||
out2 = translate(reask)
|
||
tol2 = score(out2, False)
|
||
print(f" → post-check re-ask по {miss}: {len(tol)}/8 → {len(tol2)}/8 (толерантный)")
|
||
else:
|
||
print(" → промахов (толерантных) нет — re-ask не нужен")
|
||
print()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|