← Portfolio RAG Chatbot →
Exam Materials · Agent Systems

AI Agent Flow
& Token Optimering

Fra brugerinput til AI-svar — hvad sker der i hvert trin, hvad koster det i tokens, og hvornår er ét agent nok?

Udforsk systemet ↓
01 / Fundament

Hvad er et token?

Et token er den mindste enhed af tekst en AI-model arbejder med — ikke et tegn, ikke et ord, men noget midt imellem. Tokens er AI-modellers valuta: alt du sender ind og alt du får tilbage tælles i tokens, og de fleste AI-tjenester begrænser og prisfastsætter præcis på det grundlag.

~4
tegn pr. token
Engelsk tekst og kode svarer ca. til 4 bogstaver pr. token. Dansk er lidt dyrere pga. æ, ø, å og sammensatte ord.
I / O
Input & Output
Input: alt du sender (prompt, historik, systemkontekst). Output: AI-svarene. Begge tæller mod dit limit — men output er typisk dyrere.
Akkumuleres
Hele samtalehistorikken sendes med ved hvert kald. Jo længere samtale, jo større input-pris per svar — selvom du stiller et kort spørgsmål.

Prøv det selv — skriv tekst og se token-estimatet i realtid:

Live token estimator (approx. chars ÷ 4)
0
Tegn
0
Est. tokens
0
Ord
Nøgleindsigt

Dit token-budget dækker hele samtalen — ikke bare ét svar. En lang session med 100 svar bruger langt mere end 100 korte isolerede spørgsmål, fordi historikken gensendes som input ved hvert trin.


02 / Agentflow

Hvad sker der bag kulisserne?

Når du sender en besked til en AI-agent, er der mindst 6 trin — og tokens akkumuleres i hvert af dem. Klik hvert trin for at se, hvad der sker og hvad det koster:

Brugerinput

Alt starter her: din besked og eventuelle vedhæftede filer. Dette er den mindste del af input-tokens — typisk 10–200 tokens for et normalt spørgsmål.

Men din besked er kun toppen af isbjerget. Den pakkes ind i langt mere inden den sendes til modellen.

Du skriver: "Byg en login-side med JWT" → ~9 tokens
Din besked
~9 tok
Historik (tom)
0
System prompt
~200 tok
Total input
~209 tok

Din besked udgør kun ~4% af input ved sessionsstart.

Systemkontekst

Før din besked sendes, pakkes det ind: systemprompten (adfærdsregler, din CLAUDE.md, memory), hele samtalehistorikken, og tool-definitioner. Dette er typisk den største del af input-tokens.

I Claude Code kan systemprompten alene udgøre hundredevis af tokens — og historikken vokser for hvert svar i sessionen.

Typisk input-sammensætning (10 turns inde): System prompt: ~400 tok Samtalehistorik: ~8.000 tok ← vokser! Tool-definitioner: ~1.500 tok Din besked: ~50 tok ────────────────────────────── Total input: ~9.950 tok
System prompt
~400
Historik
~8.000
Tool-def.
~1.500
Din besked
~50

Historikken er oftest den dyreste post — og den vokser ved hvert svar.

Modelkald

Al kontekst sendes til modellen på én gang. Claude læser det hele — fra første token til sidst — ved hvert kald. Det er derfor lange samtaler er dyre: du betaler at "genindlæse" al historik for hvert nyt svar.

Modellen genererer ét token ad gangen i output. Jo mere den skriver, jo dyrere — output-tokens koster typisk 3–5× mere end input-tokens.

Relative priser (Claude Sonnet): Input: $3 / 1M tokens Output: $15 / 1M tokens ← 5× dyrere Cache read: $0.30 / 1M tokens
Claude læser (input):
System Historik Tools Prompt
Claude skriver (output — ét token ad gangen):

Tool Use

En agent kan kalde "tools" — læse filer, køre tests, søge på nettet. Hvert tool-kald er en ekstra round-trip: AI'en genererer et kald (output), tool'et kører, resultatet tilføjes som nyt input, og AI'en fortsætter.

Tool-kald akkumulerer hurtigt. I Habit Tracker-testen lavede standard-agenten 50 tool-kald; The Council lavede 105.

AI → tool_call("read_file", "Main.java") Tool → [indhold: 200 linjer kode] ← ny input AI → [fortsætter generering...] Hvert kald tilføjer: ~50–500 input-tokens (tool-result) ~20–100 output-tokens (tool-call)
Tool-kald i Habit Tracker-testen
Standard
50 kald
Council
105 kald

Council brugte 2× tool-kald — men hvert kald var en specialist-review.

Svargenerering

Modellen genererer sit svar. Det er output-tokens — den dyreste kategori. Her gør token-optimering den største forskel.

Fra testen med identisk opgave (BST i Python + quiz): standard genererede ~1.073 tokens pr. run. v1 optimering: ~357 tokens. En reduktion på 67% i output alene — samme korrekthed, langt kortere svar.

Standard (~1.073 tok): ████████████████████████████████████████ v2 Opt. (~712 tok): ████████████████████████░░░░░░░░░░░░░░░░ v1 Opt. (~357 tok): █████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░
Output tokens pr. BST-opgave
Standard
~1.073
v2 Opt.
~712
v1 Opt.
~357

Samme funktionalitet — dramatisk forskel i output-pris.

Prompt Cache

Claude understøtter prompt caching — gentagen kontekst (system-prompt, lange dokumenter) gemmes og genbruges til en brøkdel af prisen.

I standard-agent Habit Tracker-sessionen over 169 turns akkumuleredes 10M+ cache-read tokens. Cache-creation er lidt dyrere end normal input, men cache-read er 10× billigere.

Cache creation: 1.25× normal input-pris Cache read: 0.10× normal input-pris ← 90% rabat Standard agent session (169 turns): Output tokens: ~73.000 Cache creation: ~165.000 Cache reads: ~10M+ ← kæmpe genanvendelse
Relative omkostninger per token
Output
5.00× (dyreste)
Cache create
1.25×
Normal input
1.00× basis
Cache read
0.10×

03 / Token Optimering

Standard vs. Optimeret — de tre tilstande

Testet med identisk opgave i 5 gentagelser per tilstand: Binary Search Tree i Python + 5-spørgsmåls multiple choice quiz. Tre tilstande, reelle målinger:

~1.073
Standard avg tokens
~712
v2 opt. avg tokens
~357
v1 opt. avg tokens

Vælg en tilstand og se hvad der faktisk ændres — både i tall og i kodeoutput:

5-Run resultater
S1
1.050
S2
1.113
S3
1.038
S4
1.128
S5
1.038

Avg: ~1.073 · Spread: ±38 tok (~8%) · Meget konsistent

Hvad du får
class BinarySearchTree: """A binary search tree.""" def insert(self, value): """Insert value into tree.""" if self.root is None: self.root = Node(value) else: self._insert(self.root, value) if __name__ == "__main__": bst = BinarySearchTree() bst.insert(5) # Q1: Time complexity of BST insert? # B) O(log n) ✓ # Feedback B: Correct! Balanced BST height # is O(log n), so insert traverses O(log n) # nodes. Feedback A: O(1) would mean constant # time — not achievable here.

Fulde docstrings · beskrivende navne · __main__ blok · quiz med forklarende feedback

5-Run resultater
O1
398
O2
333
O3
358
O4
390
O5
305

Avg: ~357 · Spread: ±38 tok (~26%) · Mere variabel

Hvad du får
class BST: def ins(self, v): if not self.r: self.r = Node(v) else: self._ins(self.r, v) # Q1: BST insert complexity? # B) O(log n) ✓ # B: Correct A: Wrong # C: Wrong D: Wrong

Forkortede navne · ingen docstrings · ingen __main__ · kun verdikt i quiz (ingen forklaring)

5-Run resultater
V1
693
V2
702
V3
711
V4
725
V5
728

Avg: ~712 · Spread: ±35 tok (~5%) · Mest konsistent af alle

Hvad du får
class BinarySearchTree: """Binary search tree.""" def insert(self, value): """Insert value.""" if self.root is None: self.root = Node(value) else: self._insert(self.root, value) if __name__ == "__main__": bst = BinarySearchTree() bst.insert(5) # Q1: Time complexity of BST insert? # B) O(log n) ✓ # B: Correct — balanced BST height is O(log n). # A: Wrong — O(1) means constant time.

Fulde navne · én-linje docstrings · __main__ bevaret · quiz med én-sætnings forklaring

Den vigtige pointe om plan-limits

Output-token reduktionen fra 67% (v1) svarer kun til ~49% reduktion i det samlede token-forbrug — fordi input-tokens er de samme i alle tilstande. v1 giver ~1.9× flere interaktioner per plan-periode; v2 giver ~1.3×. Koden er identisk korrekt i alle tre tilstande.


04 / Multi-Agent Systemer

The Council: specialister over generalister

En enkelt agent er en generalist — den ved lidt om alt. The Council er et multi-agent system med 6 specialister der hver ejer et snævert domæne, og en Builder-agent der orchestrerer builds i 4 strukturerede faser. Klik en specialist for at se, hvad de fangede i Habit Tracker-buildet:

🏛️
Architect
System design · API contracts · Data flow
Klik for at se findings ↓
Medium

Fund 1: completedToday manglede i HabitResponse DTO. Frontend ville behøve et separat netværkskald per habit blot for at vise completion-tilstand.

Fund 2: DashboardStatsResponse manglede weeklyData-felt til kalender-widget — ingen datakilde uden det.

🔒
Security Guard
Auth · Input validation · OWASP Top 10
Klik for at se findings ↓
High Risk

Fund 1 (Phase 1): Ownership-tjek skal håndhæves på hvert eneste endpoint. Hvert habit-mutation og toggle skal verificere ejerskab på service-laget — ikke blot de åbenlyse endpoints.

Medium

Fund 2 (Phase 4): JWT secret havde hardkodet fallback i kildekoden. Fix: kast IllegalStateException ved opstart hvis JWT_SECRET env var mangler eller er under 32 tegn.

🗄️
DB Whisperer
Hibernate · Schema design · PostgreSQL · N+1
Klik for at se findings ↓
Medium

Fund 1: List<String> i join-tabel til ugedage = unødvendige rækker og joins. Fix: bitmask-integer med AttributeConverter<Set<DayOfWeek>, Integer> — én kolonne, O(1) reads.

Fund 2: Manglende index på habits(user_id) ville give full table scan på hvert habit-list-kald.

Quality Critic
SOLID · Naming · Lombok · Patterns
Klik for at se findings ↓
Medium

Fund (Phase 4): DashboardService.getStats() kaldte findAllDatesByHabitId() inde i en loop — et N+1 query-problem på service-laget.

Fix: Ét samlet query returnerer Map<UUID, List<LocalDate>> — streaks beregnes i memory fra dette map.

📁
Structure Warden
Package layout · Layering · Class placement
Klik for at se findings ↓
Low

Verificerede: Korrekt 7-lags package-struktur: entity → dao → service → controller → dto → config → util.

Verificerede: @Data bruges ikke på entities — det forårsager StackOverflowError i Hibernate 6 pga. hashCode() på lazy collections.

🎨
UI Artisan
UX · Visuelt design · Accessibility · Performance
Klik for at se findings ↓
Low

Definerede design-system upfront: Mørkt tema (#0f0f13 bg, #6366f1 accent), ProgressRing-komponent, ugentlig kalender-grid, streak-tæller, slide-in drawer til habit-oprettelse.

Specificerede: Optimistisk UI på completion-toggle — lokal tilstand flipper øjeblikkeligt, API-kald sker i baggrunden.

Output tokens — Standard vs. Council (Habit Tracker build)
Standard (build only)
~73k output tok
73k
Standard + debug
~105k output tok
105k
The Council
~119k output tok
119k
Den overraskende konklusion

Standard-agenten leverede 46 filer på 8 minutter — men 2 af dem kompilerede ikke. Debug-sessionen kostede ~31k ekstra output-tokens. Når debug inkluderes, konvergerer standard-agentens samlede pris (~105k) med The Council's (~119k). Hastighedsfordelen falder fra 4× til under 2× — og Council leverede kode der kompilerede første gang.


05 / Beslutningsguide

Det rigtige værktøj til opgaven

Valget afhænger af, hvad du bygger og hvad der er vigtigst. Her er beslutningsrammen baseret på de reelle testresultater:

Scenarie Anbefalet Begrundelse
Første build af nyt systemThe CouncilFanger design-fejl før de eksisterer i kode. Spec hardening.
Ny feature på hærdet specStandard AgentSpec er testet. Hurtigst og billigst på velkendt terræn.
Output skal læses af andreStandard / v2Læsbart kode og forklarende feedback er kritisk.
Du kender basen, quick reviewv1 Optimeret67% færre output-tokens. Du har konteksten i forvejen.
Plan-limit nærmer sig slutningv2 Optimeret34% reduktion uden at ofre kode-kvalitet eller quiz-forklaring.
Kritisk produktionskodeThe CouncilAudit trail + specialistreview > enhver token-besparelse.
Estimeret interaktioner per plan-periode (relativt til standard)
v1 Optimeret
~1.9× baseline
1.9×
v2 Optimeret
~1.3× baseline
1.3×
Standard
1.0× baseline
1.0×
Pro tip fra testen

Den hurtigste måde at bruge Council på er ikke til hvert build — det er til det første build af et nyt system. Lad Council hærde spec'en og fange design-fejl. Brug derefter den hærdede spec med standard-agenter på alle features efter det. Du får Councils korrekthed på arkitekturen og standard-agentens hastighed på eksekvering.