Frank Mogensen

Til stiftere · 1. september 2026 · 9 min

Agenten foreslår, koden bestemmer

En dygtig model kan skrive din software. Den kan ikke stå på mål for den. Her er, hvad jeg byggede i stedet, og den ene sætning hele designet hviler på.

Jeg gav en meget dygtig model et repository og en opgave. Den arbejdede i omkring fyrre minutter og leverede noget, der kørte, bestod sine egne tests og lignede det, jeg havde bedt om.

Jeg kunne ikke pege på en eneste del af det, jeg stolede på.

Ikke fordi koden var dårlig. Men fordi der ikke var noget at pege på. Intet trin, jeg kunne udpege som det, der gik galt. Intet sted, hvor noget blev efterprøvet og fundet i orden. Ingen måde at køre det igen og få det samme resultat. Jeg havde fyrre minutters samtale og en mappe med filer, og det eneste ærlige, jeg kunne sige om resultatet, var, at agenten var holdt op med at skrive.

Det er det problem, jeg har brugt året på. Det er ikke et modelproblem, og en bedre model løser det ikke.

To opstillinger ved siden af hinanden. Til venstre en enkelt agent, der ejer sin egen løkke, uden fasegrænser og uden acceptkriterier. Til højre ejer kæden løkken: fire afgrænsede fasetyper — agent, kode, panel og menneske — hver efterfulgt af en port, hvor en fejlet port sender en rettelse tilbage til den samme session.
Hvem der ejer løkken, er hele argumentet.

Maskinen uden samlinger

Giver du en dygtig model hele dit udviklingsforløb, får du noget uden led i. Fire ting følger af det. De er alle governance-problemer, før de er ingeniørproblemer.

Du kan ikke sige, hvilket trin der fejlede. Der er ingen trin. Der er ét langt stykke arbejde, og når resultatet er forkert, er den eneste diagnose agenten gjorde det forkert. Det fortæller dig intet om, hvad du skal ændre.

Færdig betyder, at agenten holdt op med at skrive. Der blev ikke aftalt et acceptkriterium på forhånd, så der blev heller ikke tjekket noget til sidst. Modellens egen opsummering er det eneste bevis på, at noget lykkedes — og det er det mindst uafhængige vidne, du kan vælge.

Et nyt forsøg starter forfra. Noget går galt efter femogtredive minutter, og standardløsningen er at køre det hele igen fra ingenting. Alt, hvad modellen lige har lært om kodebasen, ryger ud, og du betaler for det en gang til.

Det eneste spor er en samtale. Man læser den som en roman. Den kan ikke søges i, den kan ikke sammenlignes med andre kørsler, og den kan ikke lægges foran en revisor, en bestyrelse eller en kunde, der med rimelighed spørger, hvordan deres software blev til.

Og så det, der afslutter diskussionen: kør kæden to gange på den samme opgave, og du får to forskellige systemer.

Én sætning, og resten følger

Løsningen er ikke en bedre prompt. Det er én beslutning, truffet bevidst og derefter håndhævet:

Koden ejer rækkefølge, gentagelser og accept. En model ejer kun arbejdet inde i én afgrænset fase.

Resten af designet følger af den sætning.

Fasen bliver sporets enhed, fordi den nu er det mindste, der har en begyndelse og en slutning. Konvolutten bliver den eneste måde, kontekst kan krydse en samling på, fordi der nu er en samling. Porten definerer færdig, fordi accepten er flyttet ud af modellens hænder og over i kode, der kører bagefter. Og en rettelse bliver billigere end en genstart, fordi sessionen stadig er åben, når kontrollen kommer tilbage rød.

Der er en følgesætning, som ofte bliver sprunget over. Det er der, pengene ligger:

Kan du skrive kaldet ned, er det ikke et modelkald.

bun test er ikke en vurdering. Der er én rigtig måde at køre den på og ingen fortolkning. Derfor kører den som et kodetrin, og resultatet når frem til den næste agent gennem den samme konvolut, som en models rapport ville have brugt — gennem den samme dør, i den samme form. Modtageren kan ikke se forskel. Du er ganske enkelt holdt op med at betale en model for at regne.

En kæde er en fil

Én kæde, der løber fra venstre mod højre på en deterministisk skinne: syv faser — spec, plan og build som agentfaser, test som kodefase, review og document som agentfaser og til sidst commit som den kodefase, der stempler kørslens id ind i commit-beskeden — hver med en port under sig, og hver fase lægger hændelser i en tracer, der skriver dem til en database, som grænsefladen læser.
Syv faser, syv porte, ét spor. Billedet genereres ud fra filen, så det kan ikke komme til at afvige fra den.

Det er den del, folk synes er mærkelig. Og det er den del, der betyder mest. Rækkefølgen er ikke noget, modellen bestemmer. Den er en fil:

export default chain('prompt', [
  agent('answer', {
    role: 'scout',
    description: 'answer the request from what is actually in the repository',
    gates: ['artifactsExist'],
  }),
  code('confirm', {
    run: 'test -s "{{handoffDir}}/answer.md"',
    description: 'confirm the answer file exists and is not empty, with our own command rather than the agent\'s word',
    gates: ['testsPass'],
    retries: 0,
  }),
])

Den kører i dag. Læg mærke til, hvad den anden fase gør: den spørger ikke agenten, om den skrev filen. Den kigger efter.

Kæden er bevidst tynd. Den erklærer grafen og intet andet. Derfor fylder den én skærm, og en gennemlæser kan se en manglende fase med det samme. Der er ikke plads til en betingelse, fordi det er dér, rækkefølgen begynder at blive en holdning. Der findes fire slags faser: én kalder en model, én kører en kommando, én spreder arbejdet ud til et panel, og én stopper kørslen og spørger et menneske.

Hver fase skal beskrive sin hensigt. En tom beskrivelse — eller en, der blot gentager fasens eget navn — bliver afvist, når filen indlæses, før der er betalt for et eneste modelkald. Et forkert stavet portnavn fanges i samme gennemløb. Ikke ved fase fem, fyrre minutter og adskillige euro inde. Ved import.

Succes skal fortjenes, ikke meldes

Én form krydser hver samling, uanset hvem der har lavet den:

type Envelope = {
  status: 'success' | 'fail'
  summary: string
  artifacts: string[]
  notesForNextAgent: string
}

En fase er som udgangspunkt fejlet. Den melder ikke succes; den fortjener den. En konvolut, der parser perfekt og siger fail, fejler stadig fasen. Det lyder indlysende, indtil man opdager, hvor mange agentsystemer der behandler velformet output som bevis på godt arbejde.

Porte efterprøver påstande, aldrig forudsigelser. Ingen ved, hvilke filer en model vil røre, før den er færdig. Derfor kører en port bagefter, op imod det, konvolutten faktisk erklærede. Der følger ni med. Hver returnerer ét resultat pr. ting, den kiggede på, så en grøn port siger ikke bare bestået — den siger, hvad den efterprøvede.

Og når en port kommer tilbage rød, starter intet forfra. Motoren stiller den samme levende session spørgsmålet igen og siger præcis, hvad der var galt. En kold genstart smider alt væk, som modellen lige har lært om kodebasen; en rettelse koster én besked. Det er forskellen på et system, der er dyrt at køre, og et, der ikke er.

Dømmekraft er et flertal, ikke en stemme

En plan bliver vurderet før byggeriet. Af et hold, ikke bagefter af én gennemlæser.

Rådgiverne sendes af sted i én samlet omgang, så ingen af dem ser en andens svar først. Hver returnerer en holdning med sit belæg. Et flertal af dem, der svarer, afgør sagen — og svarer færre end to, fejler fasen i stedet for at afgøre noget på én stemme. En reel uenighed går videre til en rolle, der handler på operatørens vegne. Den dømmer efter forfatningen først og præference bagefter — og skal sige, hvilken af de to den brugte.

Hvis det lyder som en bestyrelse, er det ikke tilfældigt. Det er det samme instrument af den samme grund: når fornuftige mennesker er uenige, er en beslutning truffet af flere mere troværdig end en truffet af én. Og begrundelsen overlever mødet.

En regel, ingen håndhæver, er pynt

Ti direktiver styrer alle roller. Find det egentlige problem bag anmodningen. Enhver handling skal være mere værd, end den koster. Sikkerhed indbygget fra start, som en forudsætning frem for et efterfølgende eftersyn. Efterprøv alt input og output mod virkeligheden, også dit eget. Ved konflikt vinder det laveste nummer.

De lægges foran hver rolle, før dens egne instruktioner. Det betyder, at hver eneste byte betales ved hvert kald i hver fase. Derfor er de skrevet korte.

Men den linje, jeg vil forsvare hårdest, er denne: et direktiv, der kun bliver fremsagt, er pynt. Alle kan skrive et værdidokument til deres AI-system. Spørgsmålet er, hvad der sker, når det bliver overtrådt. Derfor er hvert direktiv, der kan håndhæves, en kontrol, der kan stoppe bygget — en nægter at lade én operatørs opsætning følge med i en motor, der skal være generisk; en anden nægter at lade dokumentationen henvise til en fil, der ikke findes. Og de direktiver, som intet håndhæver, står opført ved navn som direktiver, som intet håndhæver.

Fabrikken må gerne være uenig med sin egen forfatning. En fase, der på forhånd erklærer, at den agter at ændre den, må gøre det — på kørslens egen gren, med den tidligere ordlyd bevaret, og med kørslen sat på pause til et menneske, før den gren betyder noget. Den kan ikke selv vedtage sit eget argument. Det er designet, ikke en begrænsning.

Hvad jeg ikke vil påstå

Skrivegrænsen er den del, jeg oftest bliver spurgt om. Det er også den del, hvor det ville være lettest at overdrive.

En liste over rettigheder er ikke en grænse. En shell kører hvad som helst; et skriveværktøj når enhver sti. Ingen tildeling af rettigheder gør denne fase ændrer intet sandt. Det, der faktisk findes, er en efterfølgende kontrol: filtræet fotograferes før kaldet, og alt, der bliver skrevet uden for fasens erklærede stier, rulles tilbage, med indholdet gemt, så man kan se, hvad den forsøgte.

Den opdager og ruller tilbage. Den forhindrer ikke. Isolationen er ikke fuldstændig, og jeg vil ikke beskrive den som fuldstændig.

Det skriver jeg ned, fordi det er den samme disciplin som ovenfor. Et system, der fortæller dig, hvad det ikke har efterprøvet, er mere værd end et, der antyder, at det har efterprøvet det hele — og på det her område er der lige nu næsten ingen, der skriver den sætning.

Hvorfor det er en bestyrelsessag

Bestyrelser bliver bedt om at godkende AI i udviklingen af software. Spørgsmålet, der når op til dem, bliver som regel stillet som et spørgsmål om formåen: kan den skrive koden? Det spørgsmål er afgjort, og det var det lette.

Det spørgsmål, der ikke er afgjort, er et spørgsmål, enhver bestyrelse allerede ved, hvordan man stiller om resten af forretningen. Hvem besluttede det her? Hvad blev der efterprøvet? Hvad er sporet? Hvad sker der, når det er forkert? Kan I gøre det igen og få det samme svar?

En model kan ikke bære noget af det. Den har ingen erindring om beslutningen, ingen uafhængig kontrol af sit eget output og ingen forpligtelse, den kan holdes til. Ansvaret må derfor ligge et andet sted — i kode, der ejer rækkefølgen, i porte, der definerer færdig, og i et spor, der overlever samtalen.

Det er hele idéen, og den fylder fire ord: agenten foreslår, koden bestemmer.

Det interessante arbejde inden for AI lige nu er ikke at gøre modellen dygtigere. Det er at beslutte, hvad modellen ikke må bestemme.


Jeg hedder Frank Mogensen. Jeg har bygget og solgt tre teknologivirksomheder, senest Cloudeon til Devoteam i 2021. I dag bygger jeg systemer som det ovenfor, og jeg arbejder med bestyrelser, der har brug for AI-erfaring med en governance-rygrad, og med stiftere, der har brug for en teknisk medstifter, som har været det igennem. Er noget af det også dit problem, hører jeg gerne fra dig — frank@fmogensen.dk.

Mere

Alt det andet, i begge spor.