portfolio-optimiser/docs/2026-08-13-fase1a-lokal-ende-til-ende.md
Kjell Tore Guttormsen cb809b683c docs(fase1a): «uansett modell» hvilte på en måling jeg aldri leste ferdig
Advisor felte påstanden ETTER at forrige commit var pushet. Rapporten sa at
600 s-taket er bindende «UANSETT modell», med `llama3.2:1b brukte OGSÅ >10 min»
som belegg. Men den målingen sprengte Bash-timeouten, gikk til bakgrunnen, og
ble aldri lest til slutt — «>10 min» var det jeg SÅ ved én kikk, ikke et resultat.

Målt nå ved manuell stopp: prosessen sto på 18 min 54 s UTEN å fullføre, og
loggen har ingen `POST "/api/generate"` for kallet. Det gir en NEDRE grense
(kallet oversteg taket med god margin) og ingen øvre.

Påstanden er derfor snevret til «på denne maskinen i denne tilstanden», med
konfunderingen uttalt: CPU-en strupet seg 62 % → 54 % underveis, og to fremmede
Python-prosesser holdt ~1,8 kjerner. Et generelt utsagn om modellstørrelse ville
krevd en ren maskin og en fullført måling; ingen av delene finnes her.
Verifiseringsloggen har fått raden + en eksplisitt «ikke verifisert»-note.

Samme defektklasse som grep-en samme økt, ett nivå opp: der var instrumentet i
stykker, her var det i orden og jeg leste det bare aldri.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X737cbkG2uAXJ2Bvhf6X5M
2026-08-13 20:19:31 +02:00

11 KiB
Raw Blame History

Fase 1a — første ende-til-ende-kjøring mot en levende modell (lokal)

Dato: 2026-08-13 · Tre: 5871e39 (v1.0.0 + de to presentasjonsfilene) · Profil: local

Rammeverket hadde aldri kjørt mot en levende språkmodell — bare mot skriptede stand-ins. Denne rapporten er den første målingen av hva som faktisk skjer når en ekte modell settes inn i loopen. Fase 1a er den gratis halvdelen: en lokal Ollama-kjøring feller alt som ikke er autentisering, slik at den betalte Foundry-kjøringen (1b) bare har RBAC, token og deployment-navn igjen å feile på.

Ærlighetsgrense. Alt under er målt på ÉN maskin (Intel i9-9880H, CPU-only) med SMÅ lokale modeller. Tallene beskriver denne maskinen og disse modellene — ikke rammeverkets ytelse generelt, og ikke hva en Foundry-modell vil gjøre.

Miljø

Maskin Intel Core i9-9880H, 16 logiske kjerner, ingen GPU-akselerasjon for Ollama
Ollama 0.16.3
Python / MAF 3.12.13 / agent-framework-core 1.9.0
Kunnskapsbase shared/examples/bygg-energi-mikro, prosjekt BYGG-KONTOR-NORD
Tak max_rounds=3, max_tokens=100000 (kompilert inn, se funn 3)

Stigen: fire trinn, der de tre første er gratis

Rekkefølgen er ikke tilfeldig. Hvert trinn gjør neste trinns feil attribuerbar.

# Hva Utfall
1 Endepunkt nås (GET /api/tags) http 200
2 --live-dry-run — bygger klient, stopper før første kall exit 0, models={proposer: qwen3:4b, checker: qwen3:4b}
3 --scripted-replies — HELE loopen, null modellkall exit 0, ValidatedProposal (decision=approved)
4 Ekte kjøring mot levende modell se under

Trinn 3 er det som gjør rapporten verdt noe: det beviser at argumentrekka, kunnskapsbasen, debatten, den deterministiske validatoren og domsavsigelsen henger sammen uten en modell i bildet. Enhver feil i trinn 4 er dermed forårsaket av levende modell-output, ikke av oppsettet.

Merk at et grønt trinn 2 ikke beviser at endepunktet virker: --live-dry-run bygger klienten og stopper før første kall, så det går grønt også med serveren nede. Trinn 1 er derfor en egen måling, ikke en formalitet.

Kjøring 1 — den shippede konfigurasjonen (qwen3:4b)

uv run python -m portfolio_optimiser.run BYGG-KONTOR-NORD --profile local \
  --docs-dir shared/examples/bygg-energi-mikro \
  --bundle-dir shared/examples/bygg-energi-mikro

Utfall: exit 1 etter 1804 sekunder (30 minutter), null forslag produsert.

agent_framework.exceptions.ChatClientException: OpenAIChatCompletionClient service failed
to complete the prompt: Request timed out. (APITimeoutError)

Årsakskjeden er målt hele veien, ikke resonnert:

  1. Ollamas logg viser tre kall, hvert avbrutt på nøyaktig 10m0s. 3 × 600 s = 1800 s, som er de 1804 sekundene kjøringen brukte. Det er OpenAI-SDK-ens standard timeout på 600 s pluss dens to standard retries — ingen av delene er valgt av oss (funn 1).
  2. Modellen rakk aldri å svare. Målt direkte på samme maskin: qwen3:4b genererer 4,0 tokens/sekund. Et 600-sekunders vindu rommer altså ~2400 tokens.
  3. Og den brukte alt på å tenke. qwen3 er en resonnerende modell. I en kontrollmåling med 256 tokens til rådighet var svaret tomt — hele budsjettet gikk med til den interne tankerekka <think>, før ett eneste tegn av det faktiske svaret ble skrevet (funn 2).

Funn

Funn 1 — den lokale klienten har ingen timeout-søm (rammeverket)

backends.py:130 konstruerer OpenAIChatCompletionClient(model=..., api_key=..., base_url=...). Målt mot klassens signatur: den tar ingen timeout- eller max_retries-parameter. Eneste vei inn er å bygge og sende inn en egen async_client.

Konsekvensen er at enhver maskin som er tregere enn modellen krever, feiler etter 30 minutter med en melding som ser ut som et nettverksproblem. Det er ikke en nettverksfeil — det er et tak ingen har valgt.

Ikke fikset her. Det er produksjonskode og krever en feilende test først (Iron Law), altså egen økt. Formen på fiksen er kjent: la create_chat_client bygge AsyncOpenAI(timeout=…, max_retries=…) med verdier fra env, og la en load-bearing test bli rød når sømmen kobles fra.

Funn 2 — en resonnerende modell bruker hele budsjettet på å tenke

Dette er ikke en defekt i rammeverket, men det er en forutsetning ingen hadde skrevet ned: modell-mappets lokale rolle pekte på qwen3:4b, og en resonnerende modell på treg maskinvare når aldri fram til svaret. For den lokale profilen bør standardvalget være en modell uten tankemodus — eller tankemodus må skrus av eksplisitt.

Funn 3 — planens token-tak-mekanisme finnes ikke i CLI-en

Planens fase 1b foreskriver «harde token-tak (--max-*-flaggene i run.py)». Målt: slike flagg finnes ikke. Takene er kompilert inn — _DEFAULT_MAX_ROUNDS = 3, _DEFAULT_MAX_TOKENS = 100_000 (run.py:110-111) — og kan ikke settes fra kommandolinjen.

Gratis og uvesentlig lokalt. For 1b er det bærende: en betalt kjøring vil ellers gå under et 100 000-tokens tak ingen har tatt stilling til. Dette er en beslutning for operatøren før den første Foundry-kjøringen, ikke noe som skal oppdages under den.

Funn 4 — kunnskapsbasen sprengte standard kontekstvindu, stille

Ollamas logg, kjøring 1:

level=WARN msg="truncating input prompt" limit=4096 prompt=4388 keep=4 new=4096

Ollamas standard kontekstvindu er 4096 tokens; prompten fra den navigerte kunnskapsbasen er 4388. Overskytende ble kuttet — og keep=4 betyr at bare fire tokens fra starten ble bevart, altså at instruksjonene om svarformat sto først i det som røk.

Advarselen står i Ollamas logg, ikke i vår. En operatør som kjører lokalt ser den ikke. Rettet for kjøring 2 ved å starte serveren med OLLAMA_CONTEXT_LENGTH=16384; at dette må gjøres bør stå i den lokale oppskriften.

Kjøring 2 — med funn 2 og 4 kompensert

Modell byttet til qwen2.5:3b (uten tankemodus) via en modell-map utenfor treet (PORTFOLIO_MODEL_MAP), og serveren restartet med OLLAMA_CONTEXT_LENGTH=16384. Repoets egen konfig er urørt — dette er en erklært overstyring, ikke den shippede oppsettet.

Utfall: samme vegg. To kall, begge avbrutt på nøyaktig 10m0s. Kjøringen ble stoppet manuelt framfor å brenne det tredje forsøket mot et kjent utfall.

Ett funn ble likevel lukket: null trunkering i loggen. Det større kontekstvinduet løser funn 4.

Diagnosen flyttet seg, og det er den viktigste setningen i rapporten: flaskehalsen er ikke tankemodusen. Det er at 600-sekunders-taket er bindende på denne maskinen i denne tilstanden, også for modeller som er langt mindre enn den shippede.

Kontrollmålingen: llama3.2:1b — en modell på 1,3 GB — sto 18 min 54 s uten å fullføre ett enkelt kall med denne kontekststørrelsen, og ble så stoppet manuelt. Presist hva dette er: den nedre grensen er målt (kallet overskred 600-sekunders-taket med god margin), men den øvre er det ikke — målingen ble aldri lest til slutt, så det finnes ikke noe totaltall for den.

Og påstanden er bevisst snevret til denne maskinen i denne tilstanden, ikke «uansett modell»: målingen er konfundert av at CPU-en strupet seg fra 62 % til 54 % klokkefrekvens underveis, og at to fremmede Python-prosesser holdt ~1,8 kjerner samtidig. Et generelt utsagn om modellstørrelse ville krevd en ren maskin og en fullført måling; ingen av delene finnes her.

Hva som er bevist, og hva som ikke er

Bevist: loopen henger sammen fra ende til annen og produserer et validert forslag — men med skriptede svar, null modellkall (trinn 3).

IKKE bevist: at en levende modell produserer noe loopen kan konsumere. Null vellykkede modellkall. Dermed står disse fortsatt åpne, og de var hele grunnen til at 1a finnes:

  • om prompt-formene gir parsebar JSON fra en ekte modell
  • om checkeren faktisk avslutter med VERDICT:-linja
  • om runde-taket oppfører seg som forutsatt
  • om validatoren avviser kandidater av riktig grunn

Hva dette betyr for 1b

Fase 1a har levert funn, ikke beviset. Den lokale halvdelen kan ikke fullføre på denne maskinvaren uten at funn 1 fikses først — timeout-sømmen er dermed en forutsetning for lokal ende-til-ende, ikke en forbedring.

To veier videre, og de utelukker ikke hverandre:

  1. Bygg timeout-sømmen (egen økt, feilende test → fiks → målt mutasjon). Da blir lokal profil kjørbar på treg maskinvare, og 1b arver en klient med et tak noen har valgt.
  2. Gå til 1b. En Foundry-modell svarer på sekunder, ikke minutter — 600 s er ikke bindende der. Ende-til-ende blir da bevist mot ekte modell, som er det operatøren opprinnelig ba om.

Kostnad er ikke en begrensning for 1b. Regnet på Anthropics egen prisliste for Claude Haiku 4.5 ($1,00/MTok inn, $5,00/MTok ut — Claude er tilgjengelig på Microsoft Foundry til standard API-priser): ~54 000 input-tokens + ~5 000 output-tokens per full kjøring ≈ $0,08, altså under én krone. Ti kjøringer er en tier. Det som gjenstår for 1b er ikke penger, men Azure-oppsettet: ressurs, prosjekt, én billig deployment og rollen Foundry User — portal-steg bare operatøren kan gjøre.

Uverifisert, må måles før det bygges på: om MAFs FoundryChatClient kan binde en Claude-deployment. Foundry-tilgjengeligheten er dokumentert; klient-kompatibiliteten er det ikke.

Verifiseringslogg

Påstand Kilde
Trinn 13 grønne; trinn 4 exit 1 etter 1804 s egne kjøringer, stdout/stderr fanget ordrett
3 × 600 s timeout + 2 retries er SDK-standard Ollamas logg (500 | 10m0s × 3) + agent_framework traceback
Klienten har ingen timeout-parameter inspect.signature(OpenAIChatCompletionClient.__init__)
qwen3:4b gir 4,0 tok/s; 256 tokens ga tomt svar /api/generate med eval_count/eval_duration
Prompt 4388 tokens, kuttet mot 4096 Ollamas truncating input prompt-advarsel
_DEFAULT_MAX_ROUNDS = 3, _DEFAULT_MAX_TOKENS = 100_000 run.py:110-111; CLI-en har ingen --max-*
Haiku 4.5-priser; Claude på Foundry til standard API-rater Anthropics modell-/prisdokumentasjon (claude-api-skillen)
llama3.2:1b 18 min 54 s uten å fullføre — nedre grense, ikke totaltid ps -o etime= ved manuell stopp; ingen POST "/api/generate" i loggen for kallet

Ikke verifisert, uttalt: at taket ville vært bindende på en URØRT maskin, eller for en vilkårlig liten modell. Kontrollmålingen ble kjørt under termisk struping og fremmed last, og ble aldri fullført. Påstandene over gjelder denne maskinen i denne tilstanden.