3ed12b274d
Arkitekturdoc sa fortfarande Gemini 2.5 Flash; koden kor gemini-3.5-flash-lite. ASCII-boxen forkortad till 3.5 Flash for att halla radbredden. scale-batch.sh RORDES EJ (medvetet val?).
130 lines
6.4 KiB
Markdown
130 lines
6.4 KiB
Markdown
# Del 9 – AI-integration (AAMOS + Gemini-lärar-tier)
|
||
|
||
> Uppdaterad 2026-08-08 efter scouting: AAMOS Core v1 är autentiseringsmässigt
|
||
> nåbar men saknar konfigurerad matmodell (`/v1/detect` faller tillbaka på YuNet
|
||
> ansiktsdetektering). Tills vidare används **Gemini 3.5 Flash Lite** som
|
||
> lärar-tier för kylskåpsskanning, bakom samma `AamosClient`-gränssnitt.
|
||
> AAMOS/prod rörs inte.
|
||
|
||
Appen når AI **uteslutande via backend** (beslut 2026-08-02). Mobilappen har
|
||
aldrig direktkontakt och innehåller inga AI-hemligheter (spec §31, §61.13).
|
||
|
||
## Kontraktet (`packages/ai-contracts`)
|
||
|
||
Appen definierar ett versionerat, Zod-validerat kontrakt per uppgiftstyp. Input
|
||
valideras FÖRE nätverksanropet, output valideras EFTER – ett svar som bryter kontraktet
|
||
behandlas som fel och når aldrig användardata. Modeller, prompts och leverantörer kan
|
||
bytas fritt bakom kontraktet ("Food API ska få stabila kontrakt oavsett modell").
|
||
|
||
```
|
||
┌─────────┐ signed image URL ┌──────────┐ AamosClient ┌─────────────────┐
|
||
│ App │ ───────────────────→ │ Food API │ ───────────────→│ Worker adapter │
|
||
└─────────┘ └──────────┘ └─────────────────┘
|
||
│
|
||
┌──────────────────┬──────────┴──────────┐
|
||
│ AAMOS_MODE=http │ AAMOS_MODE=gemini │
|
||
│ HttpAamosClient │ GeminiAamosClient │
|
||
│ → AAMOS Core v1 │ → Gemini 3.5 Flash │
|
||
└──────────────────┴─────────────────────┘
|
||
```
|
||
|
||
`createAamosClient()` väljer adapter utifrån `AAMOS_MODE`. Inga anropare behöver
|
||
ändras. App→Food API→leverantörsgränsen är oförändrad.
|
||
|
||
## AAMOS Core v1-status
|
||
|
||
Reella endpoints (ingen `/v1/tasks` fiktion):
|
||
|
||
```text
|
||
POST /v1/detect POST /v1/verify POST /v1/compare
|
||
POST /v1/segment POST /v1/classify POST /v1/authenticate
|
||
POST /v1/score POST /v1/explain POST /v1/extract
|
||
POST /v1/track GET /v1/health
|
||
```
|
||
|
||
Scouting 2026-08-08 visade:
|
||
|
||
- `amos-core.service` på server-2 anropar `http://localhost:3207`.
|
||
- Värdport `3207` ägs av `aamos-identity-rust`, inte AI-inferens.
|
||
- AI-inferenscontainern `amos-ai-inference:latest` exponerar **värdport 3209**.
|
||
- Port mismatch gör att AAMOS Core aldrig når inferens.
|
||
- Även efter hypotetisk port-fix saknas `FOOD`/`GROCERY`/`VISION_MODEL`
|
||
konfiguration i `.env.amos-core`; `/v1/detect` defaultar till `yunet`.
|
||
|
||
**Beslut:** rör inte AAMOS-prod. AAMOS kan återaktiveras i framtiden när en
|
||
matmodell finns konfigurerad, via `HttpAamosClient`.
|
||
|
||
## Gemini-lärar-tier (Skiva 1)
|
||
|
||
Aktiveras med `AAMOS_MODE=gemini` + `GEMINI_API_KEY`. Endast workern anropar
|
||
Gemini; API:et når aldrig nyckeln.
|
||
|
||
### Hanterade uppgiftstyper
|
||
|
||
- `ANALYZE_FRIDGE_IMAGE`
|
||
- `ANALYZE_PANTRY_IMAGE`
|
||
|
||
Övriga task types (`READ_RECEIPT`, `READ_NUTRITION_LABEL`, etc.) svarar
|
||
`failed` i Skiva 1 och faller tillbaka på appens befintliga flöden.
|
||
|
||
### Flöde
|
||
|
||
1. App laddar upp bild → Food API skapar `scan_job` (status `queued`).
|
||
2. Workern plockar jobbet, hämtar bilden från lagring (S3/mock).
|
||
3. `GeminiAamosClient` skickar bilden + svensk livsmedelsprompt till
|
||
`generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL}:generateContent`.
|
||
4. Gemini svarar med JSON: produkt, varumärke, kvantitet, enhet, kategori,
|
||
bäst-före/sista-förbruk (om läsbart), konfidens, imageQualityIssues.
|
||
5. Workern mappar detekterade namn mot `canonical_ingredients` (mjuk matchning).
|
||
6. Resultatet sparas i `scan_jobs` som `awaiting_confirmation`.
|
||
7. Användaren granskar och bekräftar i appen. Aldrig auto-commit.
|
||
8. AI är aldrig facit för allergener/näring — mjölkprincipen orörd.
|
||
|
||
### Kostnadskontroll
|
||
|
||
- `scan_jobs.costUsd` lagrar verklig kostnad per anrop.
|
||
- `ai_usage_counters.ai_cost_usd_microcents` ackumulerar månadskostnad per
|
||
användare (utan PII).
|
||
- Hushållskvoten `aiScans` respekteras (befintlig entitlements-logik).
|
||
- Global dagsbudget `GEMINI_DAILY_BUDGET_USD` via `BudgetStore`. Workern använder
|
||
Redis-backed budget; tester använder in-memory budget. När budgeten är
|
||
förbrukad nekar adaptern nya anrop.
|
||
- Loggning: status, latens, tokens, kostnad, taskType. Ingen bild, inget
|
||
fritext, inga PII-fält.
|
||
|
||
### Säkerhet
|
||
|
||
- Nyckeln finns i `.env` på workerservrar (SSM i produktion) och checkas aldrig
|
||
in.
|
||
- App/API validerar att `AAMOS_MODE=gemini` kräver `GEMINI_API_KEY` i produktion.
|
||
- `REQUIRE_REAL=1` i deploy-grinden gör att start failar om nyckel saknas.
|
||
|
||
## Routing & specialister (framtida)
|
||
|
||
Skiva 2 kommer lägga premium-eskaleringsstier (Gemini Pro / GPT-4o / Claude)
|
||
internt i adaptern vid låg konfidens, med eval/guldset som beslutar billig vs
|
||
dyr modell. Fram till dess: Gemini 3.5 Flash Lite för allt i Skiva 1.
|
||
|
||
## Feedback → träning (Skiva 3)
|
||
|
||
Varje användarkorrigering i granska-flödet sparas som `ai_corrections`
|
||
(AI-utdata + korrigering + modell/promptversion + **samtyckessnapshot**).
|
||
Veckojobbet `BUILD_TRAINING_SAMPLE` exporterar endast rader där
|
||
`anonymized_improvement = granted` vid korrigeringstillfället; bilder kräver
|
||
separat `image_training`-samtycke. Personligt minne är aldrig träningsdata (§32).
|
||
|
||
## Evals (spec §34)
|
||
|
||
- `pnpm test`: hermetiska tester med inspelad Gemini-fixture, når aldrig nätet.
|
||
- `pnpm --filter @app/worker eval:scan`: live-eval mot litet guldset. Rapporterar
|
||
precision, recall, kostnad, latens. Kräver `AAMOS_MODE=gemini` + nyckel.
|
||
- Regel: **ingen modell-/promptändring tas i produktion utan grön eval**.
|
||
|
||
## Lägen
|
||
|
||
| `AAMOS_MODE` | Användning |
|
||
| ------------ | --------------------------------------------------------------- |
|
||
| `mock` | dev/test utan nätverk. Produkten vägrar starta i mock. |
|
||
| `http` | Riktig AAMOS Core när matmodell finns. |
|
||
| `gemini` | Gemini 3.5 Flash Lite som lärar-tier för kylskåpsskanning (Skiva 1). |
|