AI i udviklingsprocessen
Eksempelprojekter fra kurset
Disse repositories kan have været brugt på kurset til forskellige tests og demonstrationer:
Mange erfarne udviklere kan godt se, at AI fylder mere, uden at have gjort det til en reel del af deres egen udviklingsproces endnu. Det er fornuftigt nok. Branchen er fuld af hype, hurtige produktlanceringer og påstande om, at alt nu kan automatiseres. Men for udviklere, der har ansvar for drift, kvalitet og arkitektur, er en flot demo ikke nok. Det skal være nyttigt, kontrollerbart og teknisk forsvarligt.
Artiklen er skrevet til erfarne udviklere, arkitekter og tekniske leads, som gerne vil forstå, hvad der faktisk ændrer sig, hvilke værktøjer der er relevante, og hvordan AI kan bruges pragmatisk uden at sænke kravene til kvalitet, sikkerhed og faglighed.
Warning
AI-værktøjer ændrer sig hurtigt. Navne, prismodeller, funktioner og integrationsmuligheder kan have flyttet sig, siden artiklen blev skrevet. Fokus her er derfor ikke på bestemte produktfunktioner, men på arbejdsformer, mønstre og begreber, som er mere stabile.
Hvad er en sprogmodel egentlig?
AI i denne sammenhæng handler især om Large Language Models, forkortet LLM'er. De driver blandt andet ChatGPT, GitHub Copilot, Claude og Gemini. En sprogmodel er grundlæggende et statistisk system, der er trænet til at forudsige det næste token ud fra mønstre i store mængder tekst og kode.
Resultatet kan ligne forståelse, fordi modellen kan generalisere fra de mønstre, den har set. Den kan eksempelvis foreslå en funktion til parsing af ISO 8601-datoer uden at have set netop din opgave før. Men den forstår ikke problemet på menneskelig vis og kontrollerer ikke automatisk sine påstande mod virkeligheden.
Derfor kan modellen opfinde API'er, metoder, biblioteker eller fakta, som lyder plausible. Det kaldes ofte hallucinationer. Det er ikke en sjælden kantfejl, der bare kan fjernes, men en konsekvens af måden generative modeller producerer svar på. God kontekst, værktøjer og verificering kan reducere risikoen, men ikke fjerne behovet for faglig kontrol.
Myter og virkelighed
| Myte | Virkelighed |
|---|---|
| AI erstatter udvikleren | AI er et værktøj. Ansvar, prioritering og kvalitetsvurdering er stadig menneskeligt arbejde. |
| AI ved alt | Modeller har begrænset og muligvis forældet viden, og de kan tage fejl med stor overbevisning. |
| Alle kan nu kode uden erfaring | AI sænker barrieren for at producere kode, men erfaring er afgørende for at vurdere, styre og validere resultatet. |
| Den bedste model giver altid det bedste resultat | Relevant kontekst, gode værktøjer og tydelige kvalitetskrav betyder ofte mere end små forskelle mellem modeller. |
Fra søgedrevet udvikling til dialogbaseret udvikling
I mange år har standardarbejdsgangen været nogenlunde den samme: læs en fejlmeddelelse, søg på nettet, find en tråd på Stack Overflow, læs dokumentationen, prøv et par forslag, ret koden, kør testene, og iterer. Den arbejdsgang forsvinder ikke, men AI ændrer tempoet og formen.
Det nye er, at en stor del af denne undersøgelses- og syntesefase kan ske i dialog med en model. I stedet for kun at lede efter eksisterende svar kan du beskrive problemet direkte: en fejlsituation, en arkitektur, et datasæt, en pull request eller et ældre modul. Modellen kan så hjælpe med at formulere hypoteser, foreslå refaktoreringer, forklare fremmed kode og generere et første udkast til tests og dokumentation.
Det afgørende er, at AI ikke først og fremmest flytter værdien væk fra udvikleren. Den flytter værdien væk fra ren syntaksproduktion og hen mod forståelse, afgrænsning, evaluering og teknisk dømmekraft. Den erfarne udviklers rolle bliver derfor ikke mindre vigtig, men mere koncentreret om det, der faktisk er svært: valg af retning, kvalitetskriterier, domæneforståelse og risikovurdering.
Moderne AI-værktøjer for udviklere
Når man taler om AI til softwareudvikling, er det nyttigt at skelne mellem tre typer værktøjer.
Den første kategori er automatiske kodeforslag, hvor værktøjet foreslår kode, mens du skriver eller direkte i editoren. GitHub Copilot er det mest kendte eksempel, men lignende funktioner findes mange steder. Her er gevinsten typisk høj på trivielle eller gentagne opgaver: teststubber, dataobjekter, oversættelse mellem datamodeller, regulære udtryk, SQL-udkast og lignende.
Den anden kategori er chatbaserede værktøjer, hvor du kan stille spørgsmål til kode, fejl, design og dokumentation. Her fungerer AI som en teknisk sparringspartner, som hurtigt kan forklare, sammenligne, opsummere eller generere udkast.
Den tredje kategori er agentbaserede værktøjer. Her beder du ikke blot om et svar, men om en opgave: analyser denne kodebase, find årsagen til fejlen, opret en test, opdater filerne og vis ændringerne. Værktøjer som Copilot Agent, Cline, Cursor, Windsurf, Aider, Gemini CLI og Codex-lignende kommandolinjeværktøjer falder i varierende grad i denne kategori.
Det er især den sidste kategori, der ændrer udviklingsprocessen mærkbart, fordi værktøjet ikke kun genererer tekst, men arbejder i flere trin med kontekst og handlinger.
AI-værktøjer i demoerne
- GitHub Copilot i Visual Studio Code bruges til inline-kodeforslag, spørgsmål i Ask, planlægning i Plan og ændringer i Agent. VS Code samler kode, diff, terminal og debugger, så resultatet kan kontrolleres samme sted.
- GitHub Copilot CLI bruges som agent i terminalen med adgang til projektets filer og kommandoer. Det er ikke det samme som GitHub CLI, der er et kommandolinjeværktøj til GitHub og ikke i sig selv en AI-agent.
- Claude Code bruges som en anden terminalagent til den samme afgrænsede fejlretning. Sammenligningen handler om kontekst, tilladelser og verificering, ikke om at kåre den bedste model ud fra én opgave.
Fra kodeforslag til agentbaserede arbejdsgange
Det klassiske AI-scenarie i udvikling var længe: "Her er et kodeforslag". Det nye scenarie er tættere på: "Jeg analyserede projektet, fandt det sandsynlige problem, foreslog en ændring, opdaterede testen og bad dig godkende resultatet".
Det betyder ikke, at værktøjet pludselig er autonomt i menneskelig forstand. Det betyder blot, at det kan arbejde sekventielt: læse filer, forstå relationer, anvende værktøjer, udføre kommandoer og vende tilbage med et resultat. Teknisk set er det ofte en kombination af en sprogmodel, et sæt værktøjer og en kontrolsløjfe, der lader modellen arbejde i flere trin mod et mål.
For en erfaren udvikler er det interessante ikke, om det kaldes en "agent", men om arbejdsformen er nyttig. Hvis et værktøj kan tage en konkret, afgrænset opgave og reducere den manuelle friktion uden at skjule for mange beslutninger, så er der reel værdi.
Info
Artiklen bruger nogle få begreber, som det er nyttigt at have på plads fra start. En agent er et AI-værktøj, der kan arbejde i flere trin og bruge værktøjer. En skill er en genbrugelig instruktion eller specialiseret evne, som hjælper modellen med at løse bestemte typer opgaver mere konsistent. MCP er en måde at standardisere forbindelsen mellem modeller og eksterne værktøjer. RAG er en måde at hente relevant materiale ind i svaret, når modellen ikke selv har den nødvendige kontekst. Embeddings bruges typisk til at finde indhold, der ligner det, man spørger efter. Du behøver ikke kende detaljerne på forhånd; pointen i artiklen er, hvad de betyder i udviklingsarbejde.
Hvad en AI-agent faktisk er
Begrebet bliver ofte brugt løst, men i praksis er en AI-agent typisk en model, der har adgang til værktøjer og kan arbejde iterativt med et mål og en kontekst. Det kan være adgang til filsystem, terminal, Git, browserautomatisering, sagsstyring, REST-API'er eller interne systemer.
Forskellen på en chatbot og en agent er derfor ikke intelligensniveau, men handleevne. Chatbotten svarer. Agenten gør noget, eller forsøger i det mindste at gøre noget under kontrollerede rammer.
Et realistisk eksempel kunne være: "Find fejlen i login-flowet, forklar årsagen, foreslå en minimal rettelse og opret en pull request med en regressionstest." Her er det ikke nok at kunne skrive kode. Værktøjet skal kunne læse den rigtige del af systemet, følge kontrolflow, forstå sammenhængen og udføre en serie handlinger i korrekt rækkefølge.
Agentdefinitioner og skills i praksis
I demoerne skriver vi selv en enkel Kravreviewer som en custom agent i VS Code. En Markdown-fil beskriver rolle, arbejdsform og læseværktøjer; vi bygger ikke en ny model eller agentmotor.
devcronberg/pong indeholder projektagenten monogame-dev og skillen add-screen, som bruges til et forløb fra plan til implementering og test. Bogen om C# leverer agenten C# Grundlæggende og skillen csharp-opret-konsolapp. MiniCRM har skillen minicrm-api, som beskriver HTTP-kald til et undervisnings-API med fiktive kunder. MiniCRM-demoen bruger en skill og almindelige HTTP-værktøjer, ikke en MCP-server.
Værktøjer, integrationer og hvorfor kontekst betyder mere end modelvalg
Mange diskussioner om AI låser sig fast i spørgsmålet om, hvilken model der er "bedst". I praksis er det ofte et for snævert fokus. Den model, der har adgang til den rigtige kontekst og de rigtige værktøjer, er i mange situationer mere nyttig end en stærkere model, der kun ser et tekstfelt.
Et værktøj eller en integration kan være adgang til GitHub, en database, en browser, Docker, en intern service, et filsystem eller et sæt organisationsspecifikke kommandoer. AI bliver først rigtig brugbar i udviklingsarbejde, når den både kan se relevant kontekst og handle på den.
Derfor handler moden anvendelse af AI ikke kun om prompts. Den handler også om, hvordan man giver adgang til kodebaser, dokumentation, standardkommandoer, testmiljøer og adgangsmønstre på en måde, der er sikker og brugbar.
MCP og standardiserede integrationer
Et centralt begreb i den udvikling er MCP, Model Context Protocol. Den korte forklaring er, at MCP forsøger at være en standardiseret måde for modeller at bruge eksterne værktøjer og datakilder på.
Det er dog vigtigt at være præcis: MCP er ikke det samme som, at modeller pludselig har fået mulighed for at bruge værktøjer. Det fandtes allerede i forskellige former som tool calling, function calling, plugins og produktspecifikke integrationer. Det nye i MCP er først og fremmest standardisering og genbrug på tværs af klienter og værktøjer.
Den letteste analogi er, at MCP prøver at blive lidt som USB-C for AI-værktøjer: en fælles måde at forbinde modeller med funktioner uden at hver integration skal være et proprietært specialplugin. Teknisk set kan man se det som en standardiseret protokol oven på eksisterende model-funktionalitet, hvor den store gevinst er mere ensartede integrationer og bedre interoperabilitet.
I praksis betyder det, at en model via MCP kan få adgang til funktioner som:
- læsning og skrivning af filer
- opslag i GitHub eller andre kodeplatforme
- browserautomatisering og skærmbilleder
- databaseopslag
- kald til interne eller eksterne services
For udviklere er det vigtigt, fordi værdien af AI stiger markant, når modellen ikke kun svarer ud fra sin træning, men også kan hente aktuelle data og udføre konkrete handlinger i dit miljø.
Konkrete MCP-servere
- GitHub MCP Server giver agenten værktøjer til blandt andet at læse issues og kildekode og skrive kommentarer. I demoen undersøges et Pong-issue, og en kommentar publiceres først efter godkendelse. MCP-forbindelsen bruger sin egen API-autentificering, eksempelvis OAuth eller et personal access token, ikke Git-klientens SSH-nøgle.
- OfficeCLI kan oprette, læse og ændre Word-, Excel- og PowerPoint-filer uden en installeret Microsoft Office-pakke. Produktet har både CLI, skill og en indbygget MCP-server. Demoen bruger MCP til en Excel-testplan med celleændringer, formler og validering. HTML-visning og eventuelt Excel eller LibreOffice bruges til en separat visuel kontrol.
- Context7 er et ekstra udviklerrettet eksempel: Agenten kan finde biblioteker og hente dokumentation og kodeeksempler ind som kontekst, før den foreslår en ændring. Start med projektets faktiske pakkeversion, og kontrollér, om den hentede dokumentation matcher. Context7 tilbyder både MCP og CLI med skills; vælg MCP-varianten, når det er protokollen, der skal demonstreres.
- Serena gør kodebasens struktur tilgængelig for en AI-agent gennem MCP. Værktøjet bruger sprogservere til blandt andet at finde symboler, definitioner, typer og referencer på tværs af projektet. Det er symbolbaseret genfinding, ikke klassisk embedding-baseret RAG.
Serverne giver forskellige muligheder, men ingen af dem garanterer korrekte svar. Dokumentation kan være mangelfuld, og værktøjsadgang skal stadig begrænses til opgaven. Undlad hemmeligheder og unødvendig privat kode i forespørgsler til eksterne tjenester.
Samspillet mellem agent, skills og MCP
De tre begreber løser forskellige dele af en agentbaseret arbejdsgang. Agenten styrer forløbet: den planlægger, vælger handlinger, ændrer filer og vurderer resultatet. Skills giver genbrugelig vejledning til bestemte opgaver, eksempelvis teststrategi, navngivning eller brug af et internt API. MCP standardiserer forbindelsen til eksterne værktøjer og datakilder som GitHub, browsere, databaser og dokumenter.
En skill er altså ikke et værktøj og giver ikke i sig selv adgang til noget. Den beskriver, hvordan en opgave bør løses. Agenten udfører arbejdsgangen med de værktøjer, den har fået adgang til, og MCP er én måde at stille sådanne værktøjer til rådighed på. Filer og terminal kan også være indbyggede værktøjer uden MCP.
Et konkret flow kan være:
- Agenten læser et issue og finder de relevante dele af kodebasen.
- En projektskill beskriver arkitektur, testkrav og standardkommandoer.
- Agenten ændrer koden og kører build, analyzers og tests med sine lokale værktøjer.
- GitHub MCP bruges til at oprette et udkast til en pull request efter menneskelig godkendelse.
Kombinationen virker bedst, når opgaven er afgrænset, kvalitetskravene er tydelige, og værktøjsadgangen følger princippet om færrest mulige rettigheder. For brede opgaver, uklare skills og for mange tilgængelige værktøjer giver let mere støj og en større risikoflade.
Konteksthåndtering er ofte den reelle forskel
I praksis handler mange moderne AI-værktøjer mindre om selve modellen og mere om konteksthåndtering. Det afgørende spørgsmål er ofte ikke kun, hvor god modellen er, men hvilke filer den kan se, hvor meget af kodebasen der er tilgængeligt, hvordan tidligere beslutninger opsummeres, og hvordan relevant information findes igen uden at overskride modellens grænse for, hvor meget tekst den kan arbejde med ad gangen.
Det er her begreber som kontekstvinduer, samtalehukommelse, indeksering af kodebaser, opsummering og genfinding bliver praktiske og ikke bare teoretiske. Hvis værktøjet kun ser få filer uden historik, får du ofte generiske eller misvisende svar. Hvis værktøjet derimod kan kombinere kodeindeks, tidligere beslutninger, relevante dokumenter og de filer, du arbejder i, bliver svarene typisk både mere præcise og mere brugbare.
Det er også vigtigt at skelne mellem hukommelse og genfinding. En models hukommelse i en samtale er ikke det samme som RAG. Hukommelse handler om, hvad værktøjet vælger at bære med videre fra tidligere interaktioner. RAG handler om at hente relevante data ind, når de er nødvendige. Professionelle AI-værktøjer kombinerer ofte begge dele, men de har stadig begrænsninger: store kodebaser må opsummeres, noget kontekst går tabt, og genfindingen rammer ikke altid præcist.
RAG, betydningsvektorer og egne data
For udviklere er det mere interessant at spørge, hvornår RAG faktisk hjælper, end at dvæle for længe ved definitionen. RAG er nyttigt, når svar skal forankres i materiale, der ændrer sig ofte eller kun findes internt: dokumentation, arkitekturbeslutninger, runbooks, interne biblioteker, API-kontrakter, driftsvejledninger eller større kodebaser, som modellen ikke pålideligt kan holde i hovedet alene.
I den type situationer kan RAG gøre en reel forskel. Det kan hjælpe en model med at svare ud fra jeres faktiske materiale i stedet for generel træning, og det kan være forskellen på et generisk svar og et svar, der faktisk tager udgangspunkt i jeres navngivning, mønstre og systemlandskab.
Men RAG er ikke en universalløsning. Det hjælper dårligt, hvis dokumentationen er forældet, hvis det forkerte materiale bliver fundet, eller hvis opgaven i virkeligheden handler om dyb kodeforståelse og konsekvensvurdering mere end om at hente tekst frem. RAG er godt til at finde relevant materiale. Det er ikke det samme som hukommelse, og det er ikke det samme som forståelse.
Bag mange RAG-løsninger ligger embeddings og en vektordatabase eller en anden form for semantisk søgning. Et embedding er groft sagt en matematisk repræsentation af betydning. Det gør det muligt at finde indhold, der ligner det, brugeren spørger efter, selv når ordene ikke matcher direkte.
Fra dokument til svar
En typisk RAG-løsning forbereder først materialet: Dokumenter opdeles i mindre tekststykker, kaldet chunks, som omdannes til embeddings og gemmes sammen med tekst og metadata i et indeks. Når brugeren stiller et spørgsmål, finder systemet de bedst matchende chunks og sender dem til sprogmodellen som kontekst.
dokumenter -> chunks -> embeddings -> indeks
|
spørgsmål -> søgning -> relevante chunks -> LLM -> svar
Sprogmodellen søger normalt ikke selv i databasen. Applikationen omkring modellen udfører søgningen og leverer materialet. Derfor afhænger kvaliteten både af retrieval og af modellens efterfølgende fortolkning. Professionelle løsninger bør kunne vise kilder og respektere adgangsrettigheder, og de bør måle både, om det rigtige materiale blev fundet, og om svaret faktisk bygger på det.
Semantisk søgning kombineres ofte med traditionel nøgleordssøgning i såkaldt hybrid search. Det er særligt nyttigt i kode og teknisk dokumentation, hvor præcise klasse- og metodenavne, fejlkoder og versionsnumre kan være vigtigere end sproglig lighed.
Indeksering af store kodebaser
Store kodebaser kræver ofte mere end embeddings. Et kodeindeks kan kombinere tekstsøgning, syntakstræer, import- og kaldgrafer samt data fra Language Server Protocol om symboler, definitioner, typer og referencer. Aider bygger eksempelvis et kompakt repository map, mens Serena bruger sprogservere til symbolbaseret navigation og redigering.
Et lokalt indeks er ikke det samme som en lokal sprogmodel. Selve søgningen kan foregå på udviklerens maskine, mens de fundne kodestykker stadig sendes til en cloud-baseret model. Hvis koden ikke må forlade miljøet, kræver det derfor kontrol over hele dataflowet, ikke kun retrieval-laget.
Den praktiske pointe er derfor enkel: brug RAG, når du vil gøre AI mere forankret i aktuelle, interne eller domænespecifikke data. Brug det ikke som en undskyldning for dårlig dokumentation eller som en erstatning for teknisk vurdering.
HP-34C som konkret RAG-eksempel
Artiklen Embedding - i praksis og koden i devcronberg/ai-artikler-embedding viser flowet med HP-34C-manualen. Python-koden bruger blandt andet Sentence Transformers til lokale embeddings og OpenRouter til LLM-kald. De relevante chunks sendes med spørgsmålet som kontekst; modellen bliver ikke genoptrænet. Lokale embeddings betyder altså ikke, at hele løsningen kører lokalt.
Gode prompts minder om specifikationer
Udviklere, der kommer til AI uden tidligere erfaring, undervurderer ofte, hvor meget kvaliteten afhænger af det, de giver modellen. En vag prompt giver et vagt svar. En præcis prompt giver et mere nyttigt arbejdsresultat.
For udviklere kan det at skrive prompts ses som en form for letvægts-specifikation. Du beskriver mål, begrænsninger, kontekst, kvalitet, teknologistak og succeskriterier. Jo mere præcist du gør det, jo mindre overlader du til modellens gætteri.
En stærk prompt til kodearbejde indeholder ofte:
- formålet med ændringen
- tekniske begrænsninger og arkitekturvalg
- relevante filer, grænseflader eller uddrag
- ønsket kvalitetsniveau
- krav til tests, performance eller sikkerhed
I stedet for at skrive "omskriv denne service" er det ofte langt bedre at skrive noget i stil med: "Omarbejd denne ASP.NET Core-service til tydeligere afhængighedsinjektion, asynkron behandling hele vejen, bedre adskillelse af ansvar og en struktur, der er let at enhedsteste. Bevar det offentlige API og den eksisterende forretningslogik." Det er ikke bare en bedre prompt. Det er også en bedre opgaveformulering.
Et simpelt før/efter-eksempel viser forskellen ret tydeligt.
En vag prompt kunne være:
Det giver ofte et svar i stil med: "Her er en mere ren version af din service", efterfulgt af en generel omskrivning, hvor modellen gætter på struktur, tests og ansvar uden at kende dine egentlige krav.
En mere brugbar prompt kunne være:
Omarbejd denne ASP.NET Core-service, så den bruger tydelig afhængighedsinjektion,
bevarer det offentlige API, flytter domænelogik ud af controlleren og gør koden lettere
at enhedsteste. Tilføj også forslag til 3 relevante tests og peg på eventuelle
risici ved ændringen.
Det giver typisk et langt bedre arbejdsresultat: modellen foreslår en mere konkret struktur, peger på testbare enheder og gør det lettere at vurdere, om ændringen faktisk passer til den arkitektur, du ønsker.
Fra enkeltprompts til genbrugelige instruktioner
En god prompt løser én opgave. Når de samme krav skal gælde igen og igen, bør de flyttes til genbrugelige projektressourcer. I GitHub Copilot kan .github/copilot-instructions.md beskrive teknologistak, arkitektur, kodestil samt build- og testkommandoer for hele projektet. Prompt-filer under .github/prompts/ kan samle tilbagevendende opgaver som sikkerhedsgennemgang, testgenerering eller changelogs.
Custom agents beskriver en specialiseret rolle og dens tilladte værktøjer, mens skills pakker vejledning, scripts og andet materiale til en bestemt arbejdsgang. VS Code kan hjælpe med at oprette dem via /create-agent og /create-skill, men det genererede indhold skal stadig gennemgås som anden kode og konfiguration.
GitHub Spec Kit er et mere struktureret eksempel, hvor arbejdet opdeles i Specify, Plan, Tasks og Implement. Awesome GitHub Copilot samler genbrugelige agents, skills, instruktioner og prompt-filer. Tredjepartsressourcer bør altid kontrolleres for scripts, værktøjsadgang og skjulte antagelser, før de bruges i et projekt.
AI ændrer ikke behovet for kodekvalitet
AI er stærk til acceleration, men den verificerer ikke automatisk, at resultatet er korrekt. Den kan skrive tests, men ikke garantere at testen faktisk dækker det vigtige. Den kan generere en overbevisende forklaring, men stadig tage fejl i sine antagelser. Den kan lave en elegant refaktorering, men samtidig indføre en subtil regression.
Derfor skal AI ikke forstås som en erstatning for ingeniørdisciplin, men som en multiplikator for den disciplin, der allerede er til stede. Har teamet gode tests, tydelig arkitektur, gode kodegennemgange og driftsmæssig feedback, kan AI løfte produktiviteten betragteligt. Har teamet derimod uklare krav, fraværende testdækning og svag kodehygiejne, kan AI lige så effektivt accelerere problemerne.
Et overset punkt er statisk kodeanalyse. Hvis AI skal bruges i en professionel arbejdsgang, bør den ikke kun bedømmes på, om koden kompilerer, men også på om den respekterer de analyseværktøjer, teamet allerede bruger. I C# vil det ofte være Roslyn-baserede analyzers, de indbyggede .NET-analyzers, StyleCop eller SonarQube og SonarLint. I Java er SonarQube, SpotBugs, PMD, Checkstyle og Error Prone blandt de mest udbredte. Hvis AI foreslår kode, der straks udløser advarsler i disse værktøjer, er det et tegn på, at den ikke arbejder inden for teamets faktiske kvalitetskrav.
Det gælder især i agentbaserede arbejdsgange. Her bør en god opsætning instruere AI'en i at tage hensyn til eksisterende analyzers, køre dem som en del af valideringen og behandle advarsler som reelle signaler frem for kosmetiske detaljer. Ellers får man kode, der måske ser overbevisende ud i editoren, men som ikke består teamets normale kvalitetskontrol.
Kode- og kontrolværktøjer i demoerne
Pong er skrevet i C# med MonoGame. .NET SDK og CLI bruges til build, test og kørsel, NuGet til pakker, xUnit til tests og IDisposableAnalyzers til kontrol af ressourcehåndtering. Den lille konsolapp bruger Serilog til logging.
Git bruges til at gennemgå ændringer i diffen, og PowerShell til kommandoer og HTTP-kald, eksempelvis Invoke-RestMethod. MiniCRM's Swagger-side viser API-kontrakten. Det er almindelige udviklerværktøjer, ikke AI-modeller; deres output og manuel afprøvning bruges til at efterprøve agentens påstande.
De mest oplagte anvendelser i en moden udviklingsproces er typisk:
- refaktorering af kedelig eller repetitiv kode
- generering af første udkast til enheds- og integrationstest
- dokumentation og forklaring af ældre kode
- migrationsopgaver mellem biblioteker eller framework-versioner
- analyse af stacktraces, logs og fejlscenarier
Men mennesket skal fortsat validere, prioritere og beslutte.
Mennesket er stadig i kontrol
I professionelle udviklingsmiljøer er den mest robuste model sjældent fuld autonomi. Den er snarere "AI-genereret, menneskeligt godkendt". AI kan analysere, foreslå, skrive og omstrukturere, men det er stadig mennesker, der godkender ændringer, bærer ansvaret og vurderer konsekvenserne.
Det gælder både i små og store arbejdsgange. En udvikler kan bruge AI til at foreslå en refaktorering, men skal stadig vurdere arkitekturen. Et team kan lade en agent oprette et udkast til en pull request, men bør stadig have kodegennemgang, godkendelsestrin og klare ansvarspunkter. Jo større rækkevidde AI får, desto vigtigere bliver det, at beslutningsretten ikke bliver diffus.
Evaluering af AI kræver egne testformer
Når AI bliver en del af udviklingsprocessen, opstår der også et behov for at teste AI-adfærd mere systematisk. Mange teams arbejder derfor med såkaldte evals: kontrollerede testsager og faste scenarier, der bruges til at måle kvaliteten af prompts, agenter og AI-genererede arbejdsgange.
Det kan være alt fra benchmark-opgaver til regressionstests for prompts og agenter. Hvis et team bruger AI til kodeforslag, dokumentation eller analyse, er det nyttigt at kunne måle, om kvaliteten faktisk bliver bedre eller dårligere over tid. Ellers ender man let med at diskutere AI ud fra mavefornemmelser i stedet for målbar kvalitet.
Værktøjer til evals
Promptfoo kan sammenligne prompts og modeller samt køre evaluering og red teaming i CI/CD. DeepEval tilbyder testlignende evaluering af LLM-applikationer og agenter, mens Ragas især fokuserer på RAG-løsninger. Arize Phoenix kombinerer evaluering med tracing og observability. Værktøjerne erstatter ikke et godt eval-datasæt med repræsentative opgaver og tydelige succeskriterier.
Risici og hvor AI typisk fejler
Hvis man vil bruge AI professionelt, er det lige så vigtigt at kende styrkerne som at kende fejlbillederne. Modeller er ofte overbevisende, også når de tager fejl, og de er sjældent gode til at markere usikkerhed præcist. Derfor giver det mening at se tekniske fejl, sikkerhed og styring som dele af det samme risikobillede i stedet for som adskilte diskussioner.
De mest almindelige svagheder er typisk:
- at opfinde API'er, metoder eller biblioteker, som lyder plausible
- at undervurdere særtilfælde og driftsmæssige konsekvenser
- at foreslå arkitektoniske ændringer uden at forstå alle afhængigheder
- at generere tests, der bekræfter implementeringen uden at udfordre den
- at give generiske svar på problemer, der i virkeligheden er domænespecifikke
Det gør AI mindre egnet til opgaver, hvor domæneforståelse, ansvar og konsekvensvurdering er helt centrale. Strategiske arkitekturvalg, sikkerhedskritiske beslutninger, vurderinger af data og efterlevelse af regler samt ændringer med stor produktionsrisiko bør stadig ejes tydeligt af mennesker.
For professionelle udviklingsmiljøer er det derfor ikke nok at spørge, om AI virker. Man skal også spørge, hvilke risici man introducerer.
De typiske problemområder er velkendte:
- læk af kode eller data til eksterne tjenester
- generering af usikker kode
- hallucinationer og fejlagtige tekniske anbefalinger
- licensspørgsmål og overholdelse af regler
- afhængighed af genereret kode eller pakker uden tilstrækkelig kontrol
AI skal derfor indgå i den samme styring som resten af udviklingsprocessen. Det betyder blandt andet klare retningslinjer for hvilke data der må deles, hvilke værktøjer der er godkendt, hvordan resultater gennemgås, og hvordan logning, sporbarhed og adgangskontrol håndteres.
Der er også en mere jordnær faktor, som tekniske leads og arkitekter er nødt til at forholde sig til: økonomi. Tokenforbrug, API-priser, seat-licenser, build-minutter og omkostninger ved selv at drive modeller kan hurtigt blive en reel del af beslutningen. Det er værd at forstå prismodellen bag det valgte værktøj tidligt, især hvis AI skal bruges bredt i et team eller integreres i automatiserede arbejdsgange.
I nogle miljøer vil cloud-baserede modeller være acceptable. I andre vil lokale eller selvhostede modeller være nødvendige. Det er et af de første spørgsmål mange enterprise-teams stiller: skal vores kode overhovedet forlade vores eget miljø?
Her er det relevant at kende retningen, også selv om man ikke går i dybden i første omgang. Værktøjer som Ollama, LM Studio og vLLM gør det muligt at køre modeller lokalt eller i eget driftsmiljø, og markedet for lokale coding-modeller udvikler sig hurtigt. Det løser ikke automatisk alle sikkerheds- eller kvalitetsproblemer, men det giver et alternativ for organisationer, der ønsker mere kontrol over data, adgang og drift.
Det rigtige valg afhænger af domæne, regulatoriske krav, dataklassifikation og risikovillighed. Den vigtige pointe er, at AI ikke bør være et parallelt skyggesystem udenfor de eksisterende sikkerheds- og kvalitetsprocesser.
Sikkerhed og governance i praksis
OWASP Top 10 for LLM and Generative AI Applications beskriver konkrete risici som prompt injection, datalækage og overdreven handleevne. NIST AI Risk Management Framework giver en bredere metode til at kortlægge, måle og håndtere AI-risici. For europæiske organisationer giver EU-Kommissionens oversigt over AI Act et udgangspunkt for roller, risikokategorier og krav.
Deterministiske værktøjer som CodeQL, Semgrep og SonarQube kan fungere som quality gates omkring agentens arbejde. De gør ikke AI-output korrekt, men de kan kontrollere kendte fejlklasser mere reproducerbart end endnu en vurdering fra en sprogmodel.
Praktiske arbejdsgange der giver værdi hurtigt
Hvis man vil i gang uden at vende hele udviklingsprocessen på hovedet, er det klogt at starte med opgaver, hvor værdien er tydelig og risikoen overskuelig.
Et godt første spor er at bruge AI som sparringspartner under kodning. Bed værktøjet om at forklare en service, opsummere et modul, pege på sandsynlige forbedringer eller formulere en plan for en refaktorering, før du selv ændrer koden.
Et andet oplagt spor er testarbejde. AI er ofte nyttig til at generere testtilfælde, finde særtilfælde og foreslå datavarianter, især når du allerede har en tydelig struktur for testene.
Et tredje spor er dokumentation og onboarding. En model kan hurtigt omsætte kode og struktur til introduktioner, arkitekturopsummeringer og udkast til README'er, som ellers sjældent bliver prioriteret.
Derudover er AI ofte stærk til debugging. Ikke fordi den magisk kender årsagen, men fordi den kan hjælpe med at strukturere fejlsøgningen: formulere hypoteser, forbinde symptomer med mulige fejlkilder og foreslå, hvilke observationer der vil afklare næste skridt.
Det er også her multimodale arbejdsgange begynder at blive interessante. Når et værktøj kan kombinere kode med skærmbilleder, browserkørsel, UI-inspektion, diagrammer eller tale og video, åbner det for nye typer analyse og fejlsøgning. Det er endnu ikke lige modent overalt, men det er relevant nok til, at udviklere bør kende retningen.
En pragmatisk startmodel for teams
Hvis et team vil i gang uden at gøre AI til endnu et diffust transformationsprojekt, er en enkel model ofte nok.
Start med opgaver, der er afgrænsede, reversible og lette at validere. Brug AI til analyse, testudkast, dokumentation, støtte til kodegennemgang og mindre refaktoreringer før I bruger den til bredere kodegenerering. Hold menneskelig godkendelse som fast led i kæden, og vurder effekten på konkrete mål som gennemløbstid, kvaliteten af kodegennemgange og antal fundne regressionsrisici.
Det vigtigste er ikke at indføre AI overalt. Det vigtigste er at finde de steder, hvor værktøjerne reducerer friktion uden at sløre ansvar.
Sådan kommer erfarne udviklere godt i gang
Den bedste start er sjældent at bede et værktøj om at bygge et helt system. Det er bedre at begynde med små, kontrollerede opgaver i en kodebase, du allerede forstår.
Prøv for eksempel at bruge AI til disse typer opgaver:
- Forklar denne service og tegn de vigtigste afhængigheder op.
- Skriv forslag til tests for denne metode, inklusive særtilfælde.
- Gennemgå denne pull request og peg på regressionsrisici.
- Foreslå en refaktorering, der reducerer kompleksitet uden at ændre adfærd.
- Forklar denne stacktrace og giv tre sandsynlige årsager i prioriteret rækkefølge.
Den type opgaver passer godt til erfarne udviklere, fordi de kan bedømme kvaliteten af svaret. Det er her den reelle læring opstår: ikke ved blind tillid til output, men ved at bruge modellen som en hurtig samarbejdspartner, der hele tiden udfordres af faglig vurdering.
En praktisk tommelfingerregel er enkel: jo lettere en ændring er at teste, gennemgå og rulle tilbage, jo bedre egner den sig som tidlig AI-opgave.
Hvad er allerede i gang?
Det mest ærlige er nok at sige, at ingen ved præcist, hvordan AI i udviklingsarbejde ser ud om to år. Til gengæld er der flere ting, man allerede kan se tydeligt nu.
Værktøjerne bliver mere agentbaserede. Udviklingsmiljøer får dybere AI-integration. Test, kodegennemgang, dokumentation og analyse bliver i stigende grad assisteret. Flere teams eksperimenterer med værktøjer, der kobler modeller sammen med kode, dokumentation, opgaver og produktionsdata.
Man kan også allerede se en bevægelse væk fra enkeltstående prompts og hen mod arbejdsgange i flere trin: planlægning, udførelse og efterfølgende kontrol. Nogle af disse forløb er korte og lokale i editoren. Andre er længere, mere orkestrerede og delvist asynkrone. Det er ikke modent eller ensartet overalt, men retningen er tydelig nok.
Netop derfor er det værd at holde fast i det, der er mere stabilt end værktøjslandskabet. Arkitektur, domæneforståelse, kritisk tænkning, kommunikation og ansvar for kvalitet er ikke blevet mindre vigtige. Tværtimod er det sandsynligvis de kompetencer, der bliver mest afgørende, når resten ændrer sig.
AI gør ikke den erfarne udvikler irrelevant. Den gør forskellen mellem stærk og svag teknisk dømmekraft tydeligere.
Konklusion
AI er på vej til at blive en integreret del af udviklingsprocessen. Ikke som en erstatning for udviklere, men som et produktivitetsværktøj, en analytisk hjælper og i stigende grad en teknisk samarbejdspartner, der kan arbejde i flere trin.
For erfarne udviklere uden AI-erfaring er det vigtigste ikke at lære alle nye værktøjer på én gang. Det vigtigste er at forstå arbejdsformen: hvordan kontekst, instruktioner, værktøjer, validering og styring spiller sammen.
De udviklere, der får mest ud af AI, bliver næppe dem, der ukritisk accepterer alt output. Det bliver dem, der kombinerer klassisk softwarehåndværk med en evne til at styre, afgrænse og validere AI-assisterede arbejdsgange.
AI i egne applikationer
AI behøver ikke kun være et værktøj, vi bruger under udviklingen. Det kan også være en funktion i de applikationer, vi bygger, eksempelvis til opsummering, oversættelse eller kategorisering af tekst.
I Chrome kan webapplikationer bruge browserens indbyggede AI gennem JavaScript-API'er. JavaScript sender en opgave til en lokal model og modtager resultatet, uden at teksten behøver at blive sendt til en ekstern AI-tjeneste. Det kræver dog understøttelse i browseren, passende hardware og download af modellen, så applikationen skal kontrollere, om funktionen er tilgængelig.
En anden mulighed er at kalde en AI-tjeneste over nettet. OpenRouter giver adgang til modeller fra flere udbydere gennem ét fælles API. Her er et AI-kald grundlæggende et almindeligt HTTP-kald: applikationen sender modelvalg, instruktioner og tekst som JSON og modtager et svar, den kan bruge videre. Det kan ske fra JavaScript på serveren, PowerShell, C# eller andre sprog med HTTP-understøttelse. Et særligt AI-SDK er ikke nødvendigt.