18 KiB
Jak hodnotit běžící LLM model v nanobotu
Deep research, 2026-09-20. Otázka: jak navrhnout hodnocení modelu, který už běží jako agent v nanobotu — ne offline benchmark kandidáta před nasazením.
Shrnutí
Běžící model se hodnotí z protokolů, které po sobě zanechal, ne z re-runu — a musí se měřit dvěma známkami, ne jednou: úspěch výsledku (outcome) a kvalita trajektorie, protože ty dvě se rozcházejí [1]. Hlavní metodologický problém v nanobotu ale není statistika ani judge — je to, že nanobot sám je harness, a ten se mění každý den (skilly, MEMORY.md, SOUL.md, tool schémata). Změna skóre mezi dvěma okny je proto ve skutečnosti nejčastěji změna scaffoldu, ne modelu — harness umí posunout výsledek o 7–34 procentních bodů při identických vahách [2][3]. Praktický závěr: neporovnávat skóre v čase, ale párovat na stejných úlohách, drift hlídat zvlášť jako signál, a hodnotit pass^k, ne pass@1 — model se 90 % pass@1 má při osmi opakováních ~43 % [4].
Zjištění
1. Co „běžící model" mění
Tři strukturální rozdíly proti offline evalu:
- Nemůžeš opakovat vstup. Produkční snímek (co uživatel poslal) se nedá znovu vyvolat. Zbývá replay ze záznamu — a ten je věrný jen do chvíle, kdy se změní nástroje nebo stav okolí [5].
- Váhy nejsou zmrazené. Vendor mění checkpoint pod stejným ID; pinning ID zamrazí jen část chování, serving stack, batching a decoding se mění bez čísla verze [6][7]. Detekce: canary prompt s hashí, output-shape metriky [8][9].
- Hodnotíš i sebe. Model, který dělá evaluaci, je tentýž model, který je hodnocený —
a LLM judge favorizuje vlastní styl výstupu (self-preference bias, mechanismus =
perplexity familiarita, ne vědomé rozpoznání) [10]. To se týká přímo mě: každý eval,
který spustím v turnu na
deepseek, je self-eval.
2. Jaké důkazní zdroje už v nanobotu jsou
Tohle je konkrétní inventura téhle instance (ne obecná rada):
| Zdroj | Co v něm je | Použitelné pro |
|---|---|---|
session JSONL (<config-dir>/sessions/<workspace-id>/) |
plná historie tahů včetně tool_calls, reasoning_content [11] |
trajectory eval, failure clustering |
memory/history.jsonl |
denormalizované distilly tahů | levná klasifikace témat |
db/ollama_usage.sqlite (samples) |
přesné per-model request counts + % kvóty | cost/usage scorecard |
.nanobot/tool-results/<session>/call_*.txt |
raw tool výstupy (cap 16 000 znaků) | forenzika selhání tool callu |
tasks/done/, tasks/archive/ |
frontmatter s model: a duration_seconds |
attribuce výsledku na model |
results/ |
reporty včetně deep-research výstupů | outcome grading |
reflect/findings.jsonl |
už existující store klasifikovaných vzorců chyb | failure clustering, hotový |
log/reflect_cron.log |
běhy nočního scriptu | provozní telemetrie |
webui token-usage.json |
tokeny + requesty po source (user/api/cron/dream/system) | rozpad spotřeby kvóty |
Co v nanobotu chybí: žádná OpenTelemetry/GenAI instrumentace — grep na gen_ai,
otlp, opentelemetry v nanobot/ nic nenajde. Standard pro agentní traces přitom
existuje: spany invoke_agent → chat → execute_tool, atributy gen_ai.request.model,
gen_ai.usage.input_tokens/output_tokens, metrika gen_ai.client.operation.duration
[12][13]. Je to stále pre-stable, bez 1.0 [12] — ale tvar je dobrý a je to jediná
cesta, jak dostat trajectory eval bez ad-hoc parsování JSONL. Nanobot má naštěstí
AgentHook s after_iteration a usage [14] — což je přesně to místo, kam OTel span
patří, aniž by se musel sáhnout do core loopu.
3. Co měřit: dvě známky, ne jedna
Outcome-only hodnocení řadí modely ve špatném pořadí [1]. Konkrétně:
- Správná odpověď po rozbitém plánu, který trefil výsledek náhodou (lucky pass).
- Špatná odpověď ze správného plánu, kterému poslední tool vrátil 503 (unlucky fail).
- Policy/konvenční porušení, které výsledek nezmění — τ-bench zavedl policy adherence jako first-class metriku právě proto: agent, který vrátí peníze bez ověření identity, má outcome pass a policy fail [15].
Trajektorie se skóruje po vrstvách: kvalita plánu, volba nástroje (včetně správného
nerozhodnutí volat), správnost argumentů, recovery po chybě, finální odpověď [1].
U nás je „správné nerozhodnutí volat" přesně to, co testuje scénář S6 v
projects/ai/artifacts/ollama-toolcall-test.py — a co vyřadilo deepseek-v3 [16].
Klíčová metrika je pass^k, ne pass@1. τ-bench ji zavedl jako reliability measure: podíl úloh, kde uspěje všech k opakování. Neklesá ke středu, ale dolů, protože přesně odhaluje nekonzistenci [15][4]. Čísla: GPT-4o v retailu pod 50 % na pass^1, ale pod 25 % na pass^8 [15]; model s 90% pass@1 padá na ~43 % při pass^8 a ~19 % při pass^16 (při nezávislých pokusech) [4]. Model, který získá pass@1 a ztratí pass^4, je pro provoz regrese, i když se leaderboard pohnul nahoru [4].
4. Statistika: velikost vzorku a co je ještě šum
Tohle je nejvíc podceňovaná část. Konkrétní čísla z runnable receptu [17]:
- Wilson interval, ne Wald. Wald na 7/10 hlásí [0,42; 0,98], Wilson [0,40; 0,89] — Wald slibuje jistotu, kterou data neunesou [17][18].
- Clusterované SE. Když se skóre měří na víc otázkách z jednoho tématu/ session, naive SE podstřeluje; v příkladu vyšlo clusterované 1,45× naive. Čím větší cluster, tím větší nafouknutí — v některých případech přes 3× [17]. U nás jsou clustery přirozeně session a reminder/note kategorie.
- Párový test (McNemar). Vzorek 200 párových úloh detekoval +9,5 pb rozdíl na p=0,032; nezávislý design by na totéž potřeboval 388 úloh na rameno [17]. Párování je tedy 2× úspora vzorku — a to je přesně argument pro replay stejných úloh na obou modelech místo porovnávání dvou náhodných řezů provozem.
- „27 z 30" je statisticky téměř ticho [19]. Eval sety o 50–200 příkladech, které hlásí signifikanci, ji většinou nemají [20].
Praktický důsledek pro nás: náš reálný objem je desítky relevantních tahů za den, ne tisíce. To stačí na detekci hrubých rozdílů (S6 fail, CJK drift, 2× latence), ale ne na rozlišení 2–3 pb rozdílu ve kvalitě. Cokoli jemnějšího je u nás měření šumu.
5. Jak to nasadit bez re-runu
Tři režimy a co který umí [21]:
| Režim | Co dostaneš | Co nedostaneš |
|---|---|---|
| Replay ze záznamu | chování na reálné distribuci vstupů, nulové riziko | žádný signál o uživatelském výsledku |
| Shadow | totéž, ale živě, paralelně s produkcí | pořád žádný user-outcome signál — nikdo jeho odpověď nevidí |
| Canary / A/B | skutečný outcome uživatele | riziko na řezu provozu |
Pro nanobot je canary triviálně dostupný a to je jeho největší výhoda: detach --model <preset> pustí úlohu izolovaně na jiném presetu, cron joby mají vlastní preset,
/model přepíná za běhu. Assignace varianty se ale musí dělat hashem stabilního ID
(session/chat), ne per-request náhodou — jinak se model v rámci jedné konverzace
přepne uprostřed a test se kontaminuje crossoverem [21]. A promote/rollback se gatuje
na deltě proti připnutému baseline s tolerancí, ne na absolutním čísle; je to otázka
signifikance, ne verdiktu [21].
Pozor na slepou uličku: standardní canary controller (error rate, p99) na LLM regresi nikdy nezabliká, protože ta nemá error code — horší model vrátí HTTP 200, v limitu, s plynulou a sebevědomou chybnou odpovědí. Signál se musí vyrobit (LLM judge na 1–10 % provozu) a teprve ten skóre je rollback trigger [21].
6. Drift: dvě různé věci se stejným jménem
Rozlišovat input drift / output drift / judge-score drift [8]:
- Input drift = uživatelé začali posílat něco, na co systém nebyl testovaný. Bývá první signál reálného failure clusteru [8].
- Output drift = odpovědi změnily tvar. Odpojený od input driftu je to nejhlasitější signál „model se nám změnil pod rukama" — typicky tiché přetrénování u providera [8]. U nás konkrétně měřitelné: podíl odpovědí s CJK znaky, refusal rate, tool-call rate, platnost struktury, medián délky odpovědi, poměr thinking:response tokenů.
- Judge-score drift = nejblíž kvalitnímu canary, ale je downstream od stability judge — judge se musí pinovat zvlášť [8].
Referenční okno je verzovaný artefakt, ne „včera" nebo „minulý týden": je to okno, proti kterému byl aktuální model validovaný, content-hashed a svázané s releasem [8]. Bez toho se párové srovnání rozpadá.
7. Pasti specifické pro tenhle případ
Tohle je jádro odpovědi — čtyři věci, které se u nás pokazí, i kdyby metodika byla jinak správná:
- Harness churn je u nás dominantní, ne okrajový.
git logv workspace má záznam skoro každý den (naposledy974b37a2026-09-20 12:21) a mění se přitom skilly, MEMORY.md, SOUL.md, AGENTS.md — tedy systémový prompt, instrukce i tool popisy. Harness sensitivity je 7–34 pb při identických vahách [2][3]; prompt a tool popisy samy o sobě 5–15 pb [3]. Porovnávat skóre napříč týdny je proto neplatné. Párování musí být na úrovni úlohy, ne období. - Self-eval. Vyhodnocovací smyčka běží na stejném modelu, který hodnotí. Mitigace
jsou známé a levné [10]: cross-model judging (jiná rodina než contestant), double-swap
s filtrem konzistence (swap consistency je u judge modelů jen 70,5–77,3 %, tj. hrubě
každý čtvrtý verdikt se překlopí jen podle pořadí [10]), length-controlled scoring
(všechny testované LLM mají silný length bias, +17 pb nad lidskými hodnotiteli [10]).
Prakticky: hodnotit
deepseekjudge modelem z jiné rodiny (glm), a každou dvojici proběhnout dvakrát s prohozeným pořadím. - Kvóta je součástí měření. Ollama Cloud má max 3 paralelní dotazy a usage tiers
(Medium u
deepseek-v4.1-flashvs High uglm); 4. souběžný dotaz čeká ve frontě a to čekání spadne do wall-clocku [16][22]. Naměřená latence z paralelního běhu je proto nadhodnocená a musí se měřit izolovaně. - Sandbox brání čtení záznamů. Session JSONL jsou mimo workspace
(
<config-dir>/sessions/<workspace-id>/, migrace ve v0.3.5 [11]) arestrict_to_workspacemi blokuje exec na~/.nanobot/...— ověřeno dnes, guard to odmítl. Scripty spouštěné cronem (jakoreflect_auto.py) přístup mají. Eval harness tedy musí být script pod cronem nebodetach, ne pár tool callů v mém turnu.
Rozpory a nejistoty
- Harness sensitivity: čísla se rozcházejí. „7–34 pb" [2] vs „10–20 pb" [3] vs „10–20 pb, scaffold gap přes 28 pb" [23]. Rozsah je konzistentní, přesná hodnota závisí na benchmarku a definici scaffoldu. Pro nás je podstatné, že efekt je větší než typická mezera mezi modely, ne konkrétní číslo.
- τ-bench je zmrazený. Oficiální board je zamrzlý na modelech z konce 2024 (Claude 3.5 Sonnet 69,2 % retail / 46,0 % airline); každé číslo z let 2025–26 na „τ-bench" je vendor self-report nebo successor τ2/τ3 [15]. Konkrétní čísla tedy nepoužívat jako srovnávací bod — použitelná je metodika (pass^k, policy adherence, user simulator), ne hodnoty.
- OTel GenAI konvence jsou pre-stable, bez 1.0, GenAI repo nemá tagovaný release,
každý agent span má status Development [12]. Doporučení „instrumentovat proti
gen_ai.*" je tedy investice do pohyblivého cíle. Alternativa OpenInference existuje paralelně a trace z jedné konvence nepoplní atributy druhé [12]. - Nemám ověřené, že session JSONL na téhle instanci skutečně obsahují
usageper tah. Session manager ukládátool_calls,reasoning_content,thinking_blocks[24]; token usage jde do separátníhotoken-usage.jsonv webui dir [25]. Per-tah token rozpad na thinking vs response, který bych chtěl pro verbositu, může být potřeba dopočítat nebo vzít z response objektu providera — to jsem neověřil. - Sierra má komerční zájem na τ-bench [15] — metodika je dobrá, ale je to benchmark postavený tak, aby vyhovoval jejich typu agenta. Nekopírovat slepě.
- „LLM judge ≈ lidský hodnotitel" je slabší tvrzení, než se cituje. Kappa se často reportuje bez konfidenčního intervalu [26]; agregátní korelace mohou maskovat rozptyl [27]. Judge je pro nás nástroj na hrubé filtrování, ne ground truth.
Konkrétní návrh pro nanobot
Kdybych to stavěl, minimální funkční varianta:
- Scorecard per tah, ne per model. Skript (cron) přečte nové session JSONL a pro
každý tah zapíše do
db/eval.sqlite: preset, tool cally, tokeny in/out, thinking:response poměr, wall-clock izolovaně, stop_reason, počet iterací. Bez tohohle je jakákoli další úvaha dohad. - Připnutá párová sada ~50 úloh, ne jednorázové testy: remind CRUD, note lookup, wiki search, krátký multi-step edit, deep-research. Každá úloha má deterministický check na stavu disku plus rubrici pro trajektorii. Spouští se na obou presetech z téhož commitu workspace — jinak se měří scaffold.
- pass^k = 4 jako primární metrika, Wilson interval a McNemar na párových výsledcích. Clusterovat na session, ne na tah.
- Deterministické checky první, agent-as-judge až na to, co deterministicky ověřit nelze. Judge z jiné modelové rodiny, double-swap, length-controlled.
- Drift watchdog jako samostatný hlídač: input drift (délka promptu, jazyk, téma) a output drift (CJK podíl, refusal rate, tool-call rate, poměr thinking:response) proti připnutému referenčnímu oknu, s prahy nastavenými na toleranci false positives [8].
- Vlastní harness fingerpint. Hash (systémový prompt + seznam skillů + tool schéma) při každém běhu. Když se změní, scorecard se označí jako nepárovatelný s předchozím. Tohle je u nás ta jediná věc, bez které je zbytek měření neplatný.
Krok 1 a 6 jsou přitom levné a dají se udělat hned; kroky 2–4 vyžadují tu párovou sadu, což je ta skutečná práce.
Zdroje
[1] Trajectory-level evaluation (outcome vs trajectory, 2×2 matice) — https://www.aievals.co/learn/agentic-evals/trajectory-vs-outcome
[2] Agent Harness Benchmark Score: The Point-Swing Data (7–34 pb) — https://alatirok.com/agent-harness-benchmark-score/
[3] AI Agent Benchmarks: Why Harness Sensitivity Matters — https://halmob.com/blog/ai-agent-benchmarks-harness-sensitivity-guide
[4] Pass^k: the metric that catches inconsistent agents — https://www.aievals.co/learn/agentic-evals/pass-k-and-consistency
[5] A/B Testing and Shadow Deployments for Agents (eval/regression boundary) — https://www.skillveris.com/learn/agent-evaluation-observability/a-b-testing-and-shadow-deployments-for-agents
[6] Your Model ID Is Not a Lockfile: Silent Updates and Reproducibility — https://www.zustis.com/blog/model-id-not-a-lockfile.html
[7] How to Handle AI Model Version Changes in Production (2026) — https://www.aimadetools.com/blog/ai-model-version-changes-production/
[8] Drift detection for production AI (input/output/judge-score, referenční okno) — https://www.aievals.co/learn/production/drift-detection
[9] How to Catch a Silent Model Upgrade: Version Pinning, Canary Prompts — https://dreaming.press/posts/how-to-catch-a-silent-model-upgrade-hosted-endpoint-drift.html
[10] LLM Judge Biases: Position, Verbosity, Self-Preference (swap consistency 70,5–77,3 %, length bias +17 pb, perplexity mechanismus) — https://ai-tldr.dev/learn/evaluation-safety/llm-as-judge/llm-judge-biases/
[11] nanobot-internals.md (sessions storage, v0.3.5 migrace) — workspace/knowledge/nanobot-internals.md
[12] OpenTelemetry GenAI Semantic Conventions: Tracing AI Agents in Production (invoke_agent/chat/execute_tool, pre-stable bez 1.0, OpenInference paralelně) — https://veraexmachina.com/tech/opentelemetry-genai-agent-observability-production/
[13] Inside the LLM Call: GenAI Observability with OpenTelemetry — https://opentelemetry.io/blog/2026/genai-observability/
[14] nanobot nanobot/agent/hook.py (AgentHook, after_iteration, usage) — tmp/nanobot
[15] Tau-Bench 2026: Customer-Service Agent Eval, Methodology, Tiers (policy adherence, pass^k, zamrzlý board, vendor interest) — https://benchmarkingagents.com/tau-bench/
[16] projects/ai/memory.md (tool-call testy, S6 over-eager calling u deepseek-v3) a develop/knowledge.md (max 3 paralelní dotazy, usage tiers) — workspace/
[17] Error Bars for LLM Evals: Wilson, clustered SE, párový McNemar, power (200 párových vs 388 na rameno) — https://www.aievals.co/cookbook/adding-error-bars
[18] LLM Eval Sample Size Confidence Intervals (Wilson math, „27 z 30 je téměř ticho") — https://qaskills.sh/blog/llm-eval-sample-size-confidence-intervals
[19] How Many Eval Examples Do You Need? Sample Size for LLM Tests — https://ai-tldr.dev/learn/evaluation-safety/evaluation-basics/llm-eval-sample-size/
[20] Your LLM Eval Is Lying to You: The Statistical Power Problem — https://tianpan.co/blog/2026/04/15/statistical-power-llm-evals
[21] How to Roll Out a New LLM in Production: Shadow vs Canary vs A/B (200 bez error code, hash stabilního ID, delta vs baseline) — https://dreaming.press/posts/how-to-roll-out-a-new-llm-shadow-vs-canary-vs-ab.html
[22] ollama.com/library/deepseek-v4.1-flash/tags (Medium Usage, 1M ctx, vision+tools+thinking) — https://ollama.com/library/deepseek-v4.1-flash/tags
[23] LLM Benchmark Methodology 2026: Reading Leaderboards (contamination, harness multiplier, governance types) — https://www.digitalapplied.com/blog/llm-benchmark-methodology-2026-contamination-leaderboard-guide
[24] nanobot nanobot/session/manager.py (ukládané klíče zpráv) — tmp/nanobot
[25] nanobot nanobot/webui/token_usage.py (workspace-scoped token telemetrie) — tmp/nanobot
[26] Your LLM-as-judge eval set is too small. Here is the math (kappa bez CI) — https://medium.com/@maya.andersson/your-llm-judge-eval-set-is-too-small-here-is-the-math-da21cdde24f1
[27] Beyond correlation: The impact of human uncertainty in measuring LLM-as-Judge — https://openreview.net/forum?id=E8gYIrbP00