111 lines
6.4 KiB
Python
111 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
||
"""КАКОЕ СИСТЕМНОЕ СООБЩЕНИЕ ВЫЖИВАЕТ У GEMINI — ДЕТЕРМИНИРОВАННАЯ УЛИКА. $0.
|
||
|
||
⚠ ЗАЧЕМ ОТДЕЛЬНЫЙ ФАЙЛ. Вопрос стоял открытым в `docs/experiments/00-provider-quirks.md`
|
||
дословно: «КАКОЕ именно выживает — НЕ УСТАНОВЛЕНО … Расхождение открыто». Закрыт он не новой
|
||
живой пробой (она стоит денег и протухает вместе со слагом), а АРИФМЕТИКОЙ уже купленных клеток.
|
||
Такой вывод обязан иметь исполняемого носителя: иначе через месяц он останется утверждением в
|
||
отчёте, которое никто не может пере-снять.
|
||
|
||
ЛОГИКА ДОКАЗАТЕЛЬСТВА, и она не требует ни одного вызова модели:
|
||
|
||
у арма `RE` на провод уходят ТРИ сообщения —
|
||
system[0] ролевой промт ПОБАЙТНО ОДИН И ТОТ ЖЕ на всех главах
|
||
system[1] глоссарий РАЗНЫЙ на каждой главе (термины берутся из текста главы)
|
||
user исходник разный
|
||
карантинные клетки `RQ` — тот же вызов, у которого вендор что-то выбросил.
|
||
|
||
⇒ если разность `RE.prompt_tokens − RQ.prompt_tokens` ПОСТОЯННА по главам, выброшено
|
||
сообщение постоянного размера, а таково только system[0] — ролевой промт.
|
||
Будь выброшены ОБА системных, разность росла бы вместе с глоссарием и постоянной быть
|
||
не могла; будь выброшено только system[1], постоянной была бы не разность, а сам `RQ`.
|
||
|
||
⛔ ГЕЙТ ПАДАЕТ, ЕСЛИ ВЫВОД НЕ ДЕРЖИТСЯ. Он проверяет ТРИ вещи, и каждая может уронить:
|
||
1. system[0] действительно побайтно постоянен, а system[1] действительно варьирует
|
||
(иначе рассуждение неприменимо — и это надо увидеть, а не предположить);
|
||
2. разность постоянна с точностью до нуля;
|
||
3. остаток `RQ` разложим на глоссарий + исходник: он обязан коррелировать с длиной ГЛОССАРИЯ
|
||
сильнее, чем с длиной исходника.
|
||
|
||
Запуск: eval/.venv/bin/python eval/dovodka/sysmsg.py
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import statistics as st
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ZONE = Path(__file__).resolve().parent
|
||
sys.path.insert(0, str(ZONE))
|
||
|
||
import rol # noqa: E402
|
||
|
||
OUT = Path.home() / "books" / "dovodka"
|
||
|
||
|
||
def _corr(a: list[float], b: list[float]) -> float:
|
||
ma, mb = st.mean(a), st.mean(b)
|
||
num = sum((x - ma) * (y - mb) for x, y in zip(a, b, strict=True))
|
||
den = (sum((x - ma) ** 2 for x in a) * sum((y - mb) ** 2 for y in b)) ** 0.5
|
||
return num / den if den else 0.0
|
||
|
||
|
||
def main() -> int:
|
||
rows = []
|
||
for u in rol.chosen("en"):
|
||
uid = u["uid"]
|
||
pair = OUT / f"dv-n-re-{uid}.json", OUT / f"dv-n-re-{uid}.БЕЗ-ПРОМТА.json"
|
||
if not all(p.exists() for p in pair):
|
||
print(f"⛔ нет пары клеток для {uid[:10]} — улика неполна")
|
||
return 1
|
||
re_, rq_ = (json.loads(p.read_text(encoding="utf-8")) for p in pair)
|
||
msgs, _model, _kw = rol.FOREIGN["RQ"]["wire"](uid)
|
||
if [m["role"] for m in msgs] != ["system", "system", "user"]:
|
||
print(f"⛔ форма вызова не «system·system·user»: {[m['role'] for m in msgs]}")
|
||
return 1
|
||
rows.append({
|
||
"uid": uid[:10],
|
||
"re": re_["prompt_tokens"], "rq": rq_["prompt_tokens"],
|
||
"sys0": len(msgs[0]["content"]), "sys1": len(msgs[1]["content"]),
|
||
"user": len(msgs[2]["content"]),
|
||
})
|
||
|
||
print(f"{'глава':12}{'RE_pt':>7}{'RQ_pt':>7}{'RE-RQ':>7}{'sys0':>7}{'sys1':>6}{'user':>7}")
|
||
for r in rows:
|
||
print(f"{r['uid']:12}{r['re']:>7}{r['rq']:>7}{r['re'] - r['rq']:>7}"
|
||
f"{r['sys0']:>7}{r['sys1']:>6}{r['user']:>7}")
|
||
|
||
bad = 0
|
||
sys0 = {r["sys0"] for r in rows}
|
||
sys1 = {r["sys1"] for r in rows}
|
||
diff = {r["re"] - r["rq"] for r in rows}
|
||
|
||
def ck(ok: bool, what: str) -> None:
|
||
nonlocal bad
|
||
print(f"[{'OK ' if ok else 'ПРОВАЛ'}] {what}")
|
||
bad += 0 if ok else 1
|
||
|
||
ck(len(sys0) == 1, f"ролевой промт постоянен по главам: вариантов длины {len(sys0)} ({sys0})")
|
||
ck(len(sys1) > 1, f"глоссарий по главам РАЗНЫЙ: вариантов длины {len(sys1)}")
|
||
ck(len(diff) == 1, f"разность RE−RQ постоянна: вариантов {len(diff)} ({diff})")
|
||
|
||
d = next(iter(diff)) if len(diff) == 1 else -1
|
||
tok_per_char = d / next(iter(sys0)) if len(sys0) == 1 and d > 0 else 0.0
|
||
c_gl = _corr([float(r["rq"]) for r in rows], [float(r["sys1"]) for r in rows])
|
||
c_src = _corr([float(r["rq"]) for r in rows], [float(r["user"]) for r in rows])
|
||
ck(c_gl > c_src, f"остаток RQ идёт за ГЛОССАРИЕМ, а не за исходником: "
|
||
f"corr {c_gl:+.2f} против {c_src:+.2f}")
|
||
|
||
print(f"\nвыброшено {d} токенов на {next(iter(sys0))} знаков ролевого промта "
|
||
f"= {tok_per_char:.3f} ток/знак русского текста")
|
||
print("⇒ ВЫЖИВАЕТ ПОСЛЕДНЕЕ СИСТЕМНОЕ, ВЫБРАСЫВАЕТСЯ ПЕРВОЕ."
|
||
if not bad else "\n⛔ ВЫВОД НЕ ДЕРЖИТСЯ — пере-открывать, а не подгонять.")
|
||
print("⚠ Это утверждение о ПОВЕДЕНИИ СЛОЯ на дату покупки клеток (21.08.2026). "
|
||
"Слаг ≠ модель, поведение слоя тоже имеет срок годности.")
|
||
return 1 if bad else 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|