Files
portal/docs/superpowers/experiments/2026-07-17-operator-mentor/stand4.py
T
Дмитрий 6ed30ff042 docs(golos): эксперимент оператор+наставник v4/v5 — гибрид-маршрут, замок фактов, фикс долг/долгий
- v4 (stand4.py): наставник=всегда хайку, оператор=лёгкий промпт с маршрутом эталона (флэш на простое/хайку на сложное). На диалоге продаж флэш не включается — всё сложное; выигрыш скорости даёт лёгкий промпт (10x), а не смена модели.
- v5 (stand5.py): ПРИГВОЖДЁННЫЕ ФАКТЫ (числа дословно, запрет арифметики/производных) — баг с домысленными числами закрыт для haiku-оператора; +3 простых хода → флэш включился (ход-подтверждение ~0.8с), качество вровень/лучше эталонного флэша.
- фикс ловушки STOP_RE: долг(?![оаие]) — долгая/надолго/недолго больше не считаются горем (только в стенде; эталон на сервере не тронут).
- дописан раздел 4а + обновлены шапка/стартовый блок в находках.

FLOOR-ESCAPE: владелец разрешил коммит.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 10:54:01 +03:00

94 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""СТЕНД v4 — ГИБРИД-МАРШРУТ, как просил владелец.
• наставник = ВСЕГДА хайку (умный, вне пути; из v2 mentor_hint2);
• оператор = ЛЁГКИЙ промпт (OP2_SYS из v2), но модель выбирается маршрутом ЭТАЛОНА:
простой ход → флэш-лайт (шустрая, дёшево)
сложный/«стоп»/1-й → хайку (умная подхватывает тяжёлое)
То есть «хайку на сложное, флэш на простое» + острая подсказка хайку-наставника.
Рядом кладём ЭТАЛОН (толстый промпт, тот же маршрут) — владелец судит качество.
Один диалог (демо-стоматолог). Сервер/эталонный движок/Cartesia не трогаем.
"""
import os
import stand as S
import stand2 as S2
SMART, FAST = S.SMART, S.FAST
NICHE, BRIEF = S.NICHE, S.BRIEF
def pick_operator_model(client_turn, turn_idx):
"""Маршрут эталона, но правит моделью ОПЕРАТОРА (лёгкий промпт)."""
kind = S.classify(client_turn)
m = S.mood(client_turn)
hard = (m == "СТОП" or kind == "СЛОЖНЫЙ" or turn_idx == 0)
return (SMART if hard else FAST), kind, m
def main():
out = []
def P(s=""):
print(s, flush=True); out.append(s)
P(f"СТЕНД v4 «гибрид-маршрут» · ниша={NICHE}")
P("наставник=ВСЕГДА хайку · оператор=лёгкий промпт, модель: простой→флэш, сложный/стоп/1й→хайку")
P(f"АЛЕКСАНДРА (приветствие): {S.GREETING}\n")
hist_old = [{"role": "assistant", "content": S.GREETING}]
hist_new = [{"role": "assistant", "content": S.GREETING}]
agg = {"old_pt": 0, "old_t": 0.0, "op_pt": 0, "op_t": 0.0,
"men_t": 0.0, "men_pt": 0, "pospel": 0, "flash": 0, "haiku": 0}
for i, ct in enumerate(S.CLIENT_TURNS):
cdur = S.dur_of(ct)
# ── ЭТАЛОН (толстый промпт, тот же маршрут) ──
op_model, kind, m = pick_operator_model(ct, i)
msgs_old = [{"role": "system", "content": S.build_sys_old(NICHE, BRIEF)}] + hist_old + [{"role": "user", "content": ct}]
old_txt, old_pt, _, old_dt = S.chat(op_model, msgs_old, max_tokens=400)
# ── наставник (всегда хайку, вне пути) ──
hint, men_pt, _, men_dt = S2.mentor_hint2(hist_new, ct)
pospel = men_dt <= cdur
use_hint = S2.HINT0 if i == 0 else hint # ход 1 — заготовка (наставник не поспевает)
# ── оператор (лёгкий промпт, модель по маршруту) ──
op_sys = S2.OP2_SYS.format(hint=use_hint)
msgs_op = [{"role": "system", "content": op_sys}] + hist_new[-2:] + [{"role": "user", "content": ct}]
op_txt, op_pt, _, op_dt = S.chat(op_model, msgs_op, max_tokens=400, temperature=0.6)
agg["old_pt"] += old_pt; agg["old_t"] += old_dt
agg["op_pt"] += op_pt; agg["op_t"] += op_dt
agg["men_t"] += men_dt; agg["men_pt"] += men_pt; agg["pospel"] += int(pospel)
agg["flash" if op_model == FAST else "haiku"] += 1
tag = "флэш" if op_model == FAST else "ХАЙКУ"
P(f"━━━━━━━━━━ ХОД {i+1} ━━━━━━━━━━")
P(f"КЛИЕНТ: {ct} (речь ~{cdur:.1f}с)")
P(f"🧭 маршрут: {kind}/{m} → оператор на «{tag}» ({op_model})")
P(f"🧑‍🏫 ПОДСКАЗКА{' [заготовка]' if i==0 else ''}: {use_hint}")
if i == 0:
P(f" (наставник вживую: {men_pt}т, {men_dt:.2f}с — не поспел за {cdur:.1f}с → заготовка)")
else:
P(f" (наставник хайку вне пути: {men_pt}т, {men_dt:.2f}с · поспел? {'ДА' if pospel else 'НЕТ'})")
P(f"🐌 ЭТАЛОН [толстый, {op_model}, {old_pt}т, {old_dt:.2f}с]:\n {old_txt}")
P(f"⚡ НОВЫЙ [лёгкий, {op_model}, {op_pt}т, {op_dt:.2f}с]:\n {op_txt}")
P("")
hist_old += [{"role": "user", "content": ct}, {"role": "assistant", "content": old_txt}]
hist_new += [{"role": "user", "content": ct}, {"role": "assistant", "content": op_txt}]
n = len(S.CLIENT_TURNS)
P("═══════════════ ИТОГО ═══════════════")
P(f"Маршрут оператора: флэш {agg['flash']} ходов, хайку {agg['haiku']} ходов из {n}")
P(f"Горячий путь ПРОМПТ: ЭТАЛОН {agg['old_pt']//n}т → НОВЫЙ(оператор) {agg['op_pt']//n}т")
P(f"Горячий путь ВРЕМЯ: ЭТАЛОН {agg['old_t']/n:.2f}с → НОВЫЙ(оператор) {agg['op_t']/n:.2f}с")
P(f"Наставник (хайку, вне пути): {agg['men_pt']//n}т, {agg['men_t']/n:.2f}с · поспел {agg['pospel']}/{n}")
P("Судья — владелец: качество НОВОГО против ЭТАЛОНА по каждому ходу.")
open(os.path.join(S.HERE, "rezultat4.txt"), "w", encoding="utf-8").write("\n".join(out))
print("\n[записано в rezultat4.txt]", flush=True)
if __name__ == "__main__":
main()