Gå til innhold

CU-analyzere — fra portal via git til worker⚓︎

Kai bruker Azure AI Content Understanding (CU) til å klassifisere og ekstrahere saksdokumenter. Analyzerne — én classifier + ekstraksjon-analyzere per virkemiddel — er git-eide, immutable og innholds-adresserte. Denne siden forklarer jobbflyten og hvorfor den er som den er.

Prinsippet i én setning

Git er kilde til sannhet, portalen er sandkasse. Ingenting en gjør i CU-portalen påvirker Kai før det er eksportert til git, reviewet i PR og deployet — og deploy sletter aldri noe.

Delene⚓︎

Del Hva Hvor
Analyzer-definisjoner JSON per virkemiddel: classifier.json + analyzers/<logisk-navn>.json contentunderstanding/virkemidler/<vmid>-<slug>/
Deploy-verktøyet export / lock / deploy (rå REST mot CU, idempotent PUT, aldri DELETE) tools/DeployContentUnderstanding
Lockfilen Mapper virkemiddel-id → deployet rot-analyzer-id. Eneste runtime-peker. contentunderstanding/analyzers.lock.json
CU-ressursene Der analyzerne faktisk lever, én per miljø aif-kai-test, aif-kai-prod
Drift-vakter Feiler bygget ved lockfile-drift eller kode↔skjema-avvik AnalyzerSchemaGuardTests (Architecture.Tests)

Innholds-adresserte id-er⚓︎

En analyzer-id er <virkemiddelid>_<slug>_<hash8>, der hashen beregnes av definisjons-innholdet. Classifier-roten hasher også leaf-id-ene den refererer (Merkle-struktur): endres én leaf, får både leafen og roten ny id. Konsekvenser:

  • Immutabilitet — en deployet analyzer endres aldri; en endring blir en ny analyzer ved siden av.
  • Reproduserbarhetcase_document_extractions.analyzer_id bokfører nøyaktig hvilken analyzer som ekstraherte et dokument, og facts-blobene er keyet på analyzer-id (…/facts/{analyzerId}/{filnavn}.json). Samme id ⇒ samme definisjon, alltid.
  • Trygg deploydeploy PUT-er bare id-er som mangler og sletter aldri; gamle analyzere (og sandkasse-prosjekter i portalen) blir stående.

CU-navneregler

CU forbyr - i analyzer-id-er; verktøyet saniterer selv til _. API-versjon: 2025-11-01.

Jobbflyten⚓︎

flowchart LR
    subgraph Sandkasse
        Portal[CU-portalen<br/>aif-kai-test]
    end
    subgraph Git["Git (kilde til sannhet)"]
        Def[contentunderstanding/<br/>definisjons-JSON]
        Lock[analyzers.lock.json]
    end
    subgraph Miljø
        CU[(CU-ressurs<br/>aif-kai-test/-prod)]
        Worker[kai-worker<br/>lockfile innbakt i image]
    end

    Portal -- "1 · export (stdout → fil)" --> Def
    Def -- "2 · PR-review" --> Def
    Def -- "3 · deploy --env" --> CU
    Def -. "deploy/lock skriver" .-> Lock
    Lock -- "4 · merge → kai-worker-pipeline<br/>baker lockfile inn i image" --> Worker
    Worker -- "RotIdFor(virkemiddelId)" --> CU
  1. Forfatt/eksperimenter i portalen (eller rediger JSON-en direkte i git). Portalen er kun et verksted — det du lager der er inert for Kai.
  2. Eksporter til git: dotnet run --project tools/DeployContentUnderstanding -- export <analyzerId> skriver renset definisjon til stdout; redirect til riktig fil under contentunderstanding/virkemidler/…. Commit definisjonen og lockfilen sammen, åpne PR — analyzerne reviewes som all annen kode.
  3. Deploy git → CU: … -- deploy --env test|prod skriver først lockfilen, deretter idempotent PUT av manglende id-er (leaves før rot). Trygt å kjøre før merge: worker peker fortsatt på gammel id via sin innbakte lockfile.
  4. Merge → runtime: kai-worker-pipelinen path-trigges av contentunderstanding/, kjører drift-vaktene og baker den nye lockfilen inn i worker-imaget. Først når det imaget er rullet ut slår FetchDocuments opp den nye rot-id-en (AnalyzerLockOptions.RotIdFor) — dette er byttepunktet.

Rekkefølgen er ikke valgfri

Deploy mot CU-ressursen (steg 3) skje før worker-imaget med ny lockfile rulles ut (steg 4) — ellers peker workeren på en rot-id som ikke finnes i CU. Motsatt rekkefølge er ufarlig: gammel analyzer finnes fortsatt, og ny lockfile uten deploy fanges av drift-vakten.

Eksisterende saker re-ekstraheres ikke automatisk ved analyzer-bytte — ekstraksjoner er bokført per analyzer-id, og re-kjøring er et bevisst valg (re-trigg av ExtractDocument).

Vaktene (automatisk i CI)⚓︎

  • Lockfile_MatchesDefinitions — rebergener rot-id-ene fra definisjonene; har analyzers.lock.json drevet fra innholdet feiler bygget. Fiks: kjør … -- lock og commit.
  • EveryRequiredField_ExistsInSomeAnalyzerDefinition — hvert felt koden faktisk leser (RequiredAnalyzerFields i Application-laget) må finnes i en definisjon. Skjemaet kan dermed ikke drive fra koden uten at bygget sier fra.

Manuelt vs. automatisk i dag⚓︎

Steg Status
Lockfile-drift-vakt + kode↔skjema-vakt Automatisk (CI, path-trigger)
Lockfile bakes inn i worker-image + rulles ut Automatisk (kai-worker-pipelinen)
deploy --env (git → CU-ressursen) Manuelt operatørsteg

Automatisert deploy-pipeline (egen arketype + service principal med Cognitive Services Contributoraif-kai-{test,prod}) er bevisst utsatt og sporet som egen infra-oppgave (AB#21086). Den må også overta forutsetningen som i dag er manuell:

Forutsetning på fersk CU-ressurs

Før første deploy mot en uberørt CU-ressurs må ressursens ModelDeployments-defaults være satt (gpt-4.1, gpt-4.1-mini, text-embedding-3-large) og de tilsvarende Azure OpenAI-deploymentene finnes. Verktøyet rører aldri defaults-endepunktet. Se contentunderstanding/README.md i repoet.

Videre lesning⚓︎