From 4d7852f466932dd0e3f2d888bd244a7b3ec264c0 Mon Sep 17 00:00:00 2001 From: vegard Date: Wed, 18 Mar 2026 11:06:32 +0000 Subject: [PATCH] Spesifiser robusthet: fallback-kjede, bot-nedetid, function calling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nytt infra-dokument for robusthet og fallback: - LLM fallback-kjede via LiteLLM (Claude → GPT-4 → lokal modell) - Automatisk nedetid-melding til brukere ved bot-feil - Function calling: ekstern API-bot dispatcher CLI-verktøy via portvokteren (structured output → generisk dispatch) - Tilgangskontroll for bot-actions per brukerrolle - Onboarding som statisk dispatch (null LLM-kostnad) - PG som eneste reelle SPOF, mitigering via backup+snapshot Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/infra/robusthet.md | 148 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/infra/robusthet.md diff --git a/docs/infra/robusthet.md b/docs/infra/robusthet.md new file mode 100644 index 0000000..ef6d665 --- /dev/null +++ b/docs/infra/robusthet.md @@ -0,0 +1,148 @@ +# Robusthet og fallback + +## Lagmodell + +``` +Lag 1: LLM-leverandør (Claude API, OpenAI, etc.) → utenfor vår kontroll +Lag 2: LiteLLM (AI Gateway) → lokal Docker +Lag 3: Portvokteren → lokal native (systemd) +Lag 4: CLI-verktøy (synops-*) → per-kall, isolert +Lag 5: PostgreSQL → lokal Docker, SPOF +``` + +## Deteksjon + +### Bot-nedetid + +Portvokteren overvåker `synops-respond` sin exit-kode. Ved feil: + +``` +@bot (ingen respons på 30 sek) + → Portvokteren sender automatisk i chatten: + "⚠ Boten er midlertidig utilgjengelig. + Meldingen din er lagret og blir besvart + når tjenesten er tilbake." + → Oppretter work_item i innboks: "Bot-nedetid" + tagged "bug" + → Logger i ai_usage_log med error-status +``` + +Brukeren vet at meldingen er mottatt. Når boten er tilbake, +kan den prosessere ubesvarte meldinger. + +### Healthcheck + +Portvokteren eksponerer `/health` som sjekker: +- PG-tilkobling +- STDB-tilkobling +- LiteLLM-tilgjengelighet +- Disk-status + +Systemd restarter portvokteren ved gjentatte feil. + +## LLM fallback-kjede + +LiteLLM håndterer modell-fallback. `@bot` fungerer uansett +hvilken modell som svarer: + +``` +synops-respond → LiteLLM + ├── Claude (primær) + ├── GPT-4 (fallback 1) + ├── Gemini (fallback 2) + └── Lokal modell (fallback 3, alltid oppe) +``` + +Brukeren merker kanskje kvalitetsforskjell, men tjenesten er +oppe. Fallback-kjeden konfigureres i LiteLLM — ingen endring +i portvokteren eller synops-respond. + +## Ekstern API-bot og CLI-verktøy + +En LLM via API har ikke shell-tilgang. Den trenger det heller +ikke — portvokteren er mellomleddet. + +### Function calling / tool use + +``` +Bruker: "@bot sjekk om RSS-feeden oppdaterte seg" + → portvokteren → synops-respond → LLM API + +LLM svarer med structured output: + { + "response": "Jeg sjekker RSS-feeden for deg.", + "actions": [ + { "tool": "synops-rss", + "args": { "collection_id": "abc123" } } + ] + } + +Portvokteren: + 1. Poster chat-svaret i samtalen + 2. Spawner: synops-rss --payload-json '{"collection_id":"abc123"}' + 3. Poster resultatet som oppfølgingsmelding +``` + +LLM-en beskriver *hva* som skal gjøres. Portvokteren *gjør* +det. Navnekonvensjonen (`synops-{tool}`) betyr at portvokteren +kan dispatche uten hardkodet mapping — samme generiske dispatch +som jobbkøen (se `docs/retninger/unix_filosofi.md`). + +### Tilgangskontroll for actions + +Ikke alle brukere skal kunne trigge alle verktøy via `@bot`. +Portvokteren sjekker: + +1. Brukerens rolle i konteksten (owner/admin/member/reader) +2. Verktøyets tilgangsnivå (fra `cli_tool`-nodens metadata) +3. Rate limiting per bruker + +En `reader` kan spørre `@bot` om informasjon, men ikke trigge +`synops-render` eller `synops-audio`. + +## Fallback per situasjon + +| Situasjon | Deteksjon | Fallback | Brukeropplevelse | +|-----------|-----------|----------|------------------| +| Claude API nede | LiteLLM timeout | Neste modell i kjeden | Svarer, kanskje litt dårligere | +| Alle LLM-er nede | synops-respond exit != 0 | Statisk "utilgjengelig" + work_item | Vet at meldingen er mottatt | +| Portvokteren nede | Systemd healthcheck → restart | CLI fungerer for Claude Code | Web-brukere venter, terminal funker | +| PG nede | Connection refused | Alt stopper | Eneste reelle SPOF | +| STDB nede | Reconnect-loop | PG-fallback for lesing, skriving bufres | Sanntid borte, data trygt | + +## PG som eneste SPOF + +PostgreSQL er den eneste komponenten der nedetid stopper alt. +Men det er også den mest stabile — PG krasjer sjelden, og +gjenoppbygging fra backup er veldokumentert +(se `docs/setup/produksjon.md`). + +Mitigering: +- Automatisk PG-dump (se oppgave 12.2) +- STDB kan gjenoppbygges fra PG +- `synops-snapshot` sikrer at docs-fallback finnes i repo +- CAS-filer er uavhengig av PG (filsystem) + +## Onboarding som statisk dispatch + +Første `@bot` i en ny brukers velkomst-chat trenger ikke +LLM-roundtrip. Portvokteren gjenkjenner mønsteret og serverer +onboarding-noden direkte: + +```rust +if is_welcome_chat && is_first_bot_mention { + return serve_static_node(ONBOARDING_NODE_UUID); +} +``` + +Null latency, null AI-kostnad, fungerer selv om alle LLM-er +er nede. Onboarding-teksten er en vanlig node — oppdaterbar +uten redeploy. + +Etter første melding fungerer chatten normalt med LLM. + +## Bygger på +- `docs/infra/ai_gateway.md` — LiteLLM fallback-kjeder +- `docs/retninger/unix_filosofi.md` — generisk dispatch +- `docs/retninger/maskinrommet.md` — portvokter-rollen +- `docs/concepts/arbeidstavlen.md` — @bot-konvensjonen +- `docs/concepts/selvdokumenterende_system.md` — onboarding-node