12 juli 2026 · 8 min
Fem agent-haverier som lärde mig var autonomin slutar
Det svåra med AI-agenter är inte att få dem att agera. Vilken kompetent ingenjör som helst kan koppla en språkmodell till verktyg och se den skriva, boka, ta betalt och skicka. Det svåra är att bestämma vad den får slutföra på egen hand. Jag bygger och driver produktionsagenter för svenska företag — innehållspipelines, en webbutik, orderflöden med riktiga pengar i sig — och allt jag faktiskt kan om den gränsen kommer från haverier, inte framgångar. Här är de fem som lärde mig mest: vad som hände, den felaktiga mentala modellen jag bar på, fixen, och regeln varje incident lämnade efter sig. Inget av det här är hypotetiskt. Allt finns i min git-historik.
Haveri 1: den tysta trunkeringen
Min artikelskrivande agent producerar lång, strukturerad JSON — hela artiklar med metadata, sektioner och källor. En morgon fallerade varenda körning med samma fel: schema_validation_failed, "the response did not match the schema". Så jag gjorde det uppenbara och började gräva i schemat — lättade på fältgränser, breddade enums. Det hjälpte ingenting, för schemat var aldrig problemet. Runnern hade aldrig satt maxOutputTokens, och API:ets standardtak för output var 4 096 tokens. Varje artikel klipptes av mitt i sin JSON — och trunkerad JSON går inte att parsa, vilket valideringslagret plikttroget rapporterade som ett schemafel.
Den felaktiga mentala modellen: jag litade på felmeddelandet. Ett felmeddelande berättar var ett fel upptäcktes, inte var det orsakades. Ledtråden som faktiskt knäckte fallet fanns inte i någon logg — den fanns i kostnadstelemetrin. Varje misslyckad körning kostade nästan exakt lika mycket: $0.0590 eller $0.0583, körning efter körning. Slumpmässigt fallerande genereringar borde ha slumpmässigt varierande kostnad; identisk kostnad betyder att varje körning slår i samma hårda tak. Min fakturadata kände till grundorsaken före mina loggar.
Fixen var liten: varje agentdefinition deklarerar nu sitt eget output-tak, och runnern skickar det vidare till modellanropet — artikelagenten fick ett tak på 16k tokens, med ett värsta fall som fortfarande ligger under dess kostnadstak per körning. De överförbara reglerna är större. Standardvärden är tysta mördare: varje gräns du inte satt uttryckligen är ett beslut någon annan har fattat åt ditt produktionssystem. Och kostnadstelemetri är en felsökningssignal — nästan identisk kostnad vid varje fel är fingeravtrycket av ett tak, inte av en nyckfull modell.
Haveri 2: den fejkade bekräftelsen
Min butiks kassa anropar ett betal-API och faller i demoläge — innan Stripe är konfigurerat — tillbaka till ett exempelflöde: generera en orderreferens, töm varukorgen, visa bekräftelsesidan. Buggen: varje API-fel hamnade i samma gren. Ett 500-svar, ett nätverksfel, en felkonfigurerad nyckel — kunden fick ändå ett nypräglat ordernummer, en tömd varukorg och ett glatt "order bekräftad". Inget debiterat, ingen order registrerad, ingen informerad.
Den felaktiga mentala modellen: jag behandlade det lyckade flödet som produkten och felvägen som rörmokeri. Det är exakt tvärtom. Felvägen är produktytan — ögonblicket när något går snett är precis när kunden avgör om ditt företag går att lita på. En snygg bekräftelseskärm ovanpå ett tomrum är det sämsta tänkbara svaret.
Fixen: framgångsgrenen kräver nu att svaret är OK och att servern uttryckligen säger vilket flöde det är — en checkout-URL för riktig betalning, eller mock === true för det deklarerade demoflödet. Allt annat behåller varukorgen och visar ett ärligt felmeddelande med möjlighet att försöka igen. Regeln: en fallback får aldrig gå att nå av misstag. Finns ett demoläge måste servern aktivt deklarera det — härleds det ur frånvaron av ett riktigt svar kommer varje driftstörning att utge sig för att vara demot. Ärligt fel slår snyggt fel.
Haveri 3: den svalda ordern
När en betalning går igenom skickar Stripe en webhook, och min hanterare vidarebefordrar den betalda ordern till fulfilment-plattformen. Det anropet låg i en try/catch vars catch-block inte gjorde någonting — och hanteraren returnerade 200 OK oavsett. Vilket betyder: om vidarebefordran fallerade hade en kund betalat, och ordern upphörde tyst att existera. Inget fel, ingen kö, inget spår utanför Stripes egen dashboard.
Den felaktiga mentala modellen: "ordern är redan säkrad i Stripe, så vidarebefordran är best effort." Jag behandlade at-least-once-leverans som något Stripe tillhandahåller, när det i själva verket är ett kontrakt med två sidor. Stripe försöker leverera webhooks igen med backoff i flera dagar — men bara om du talar sanning. Ett 200 är ett kvitto. Det säger levererat, sluta försöka. Returnera det vid ett fel och du har omvandlat ett omkörbart fel till permanent, tyst dataförlust.
Fixen är nästan pinsamt liten: en misslyckad vidarebefordran returnerar nu 5xx, och Stripe levererar om tills det lyckas. Regeln är inte liten: tillförlitlighet är retry-semantik, inte upptid. Ingen märker dina fem nior; alla märker den betalda ordern som försvann. Hela maskineriet kring at-least-once fungerar bara om varje led vägrar ljuga för den som försöker igen.
Haveri 4: vakten som blockerade sin egen skapare
Min utvecklingsmiljö har en deterministisk spärr: en kort lista kommandomönster som aldrig är legitima och därför blockeras före körning. Ett av dem är exfiltrationssignaturen — att läsa en credential-fil och prata med nätverket i samma kommando. Tre dagar efter att jag byggt den blockerade den mig. Jag skulle trigga ett CI-flöde, och mitt kommando läste en token ur en credential-fil och anropade API:et på samma rad: exakt den kombination spärren finns till för att stoppa. Min första reflex var att göra ett undantag för mig själv. Den reflexen är själva incidenten.
Den felaktiga mentala modellen: spärrar är till för angripare, och operatören är betrodd. Men en spärr du kringgår när den är obekväm är ingen spärr — den är dekoration. Och med agenter i loopen är "operatören" en luddigare kategori än den ser ut: prompt injection innebär att varje text en agent läser försöker bli operatör. Försvaret fungerar bara om varje extern sträng behandlas som data, aldrig som instruktioner — och om deny-reglerna vid verktygsgränsen håller oavsett vem som frågar, inklusive upphovsmannen med en deadline.
Så spärren fick stå kvar. Jag delade upp arbetet i två kommandon — hämta in tokenen i miljön först, anropa API:et sedan — en form som bryter exfiltrationssignaturen. Trettio sekunders friktion. Regeln: agentplattformar behöver deny-by-default-sömmar just därför att även operatören kommer att frestas. Om en regel överlever sin egen upphovsman — det är testet på om den är på riktigt.
Haveri 5: det dubbla trycket
Webhook-omleverans — det som räddade haveri tre — har en skuggsida: at-least-once betyder ibland två gånger. En omlevererad checkout-händelse kunde skapa en andra order i min print-on-demand-pipeline, och ett andra tryckjobb hos leverantören. En betald kassa, två hoodies tryckta, packade och skickade till en förbryllad kund.
Den felaktiga mentala modellen: "jag deduplicerar vid ingången, alltså är jag säker." Dedupe i ett led överlever inte pipelinen — en retry kan smita in i vilken söm som helst, och kontroller i applikationslagret förlorar kapplöpningen i samma ögonblick som två förfrågningar anländer samtidigt. Idempotens är inte en egenskap hos en funktion. Det är en egenskap hos hela kedjan, och den är aldrig starkare än sitt svagaste led.
Fixen trär en nyckel genom allting. Stripe-sessionens id följer ordern som dess externalId; databasen upprätthåller ett partiellt unikt index på (creator_id, external_id), så att inte ens två kapplöpande inserts båda kan vinna; förlorarens constraint-fel — Postgres 23505 — omvandlas till ett lugnt "den här ordern finns redan" i stället för ett fel; och samma id skickas till tryckleverantören som orderReferenceId, så att även sista ledet kan vägra en dubblett. Regeln: en idempotensnyckel måste följa hela pipelinen, präglad av betalningen och respekterad av varje led — och unikheten upprätthålls i databasen, för bara databasen ser båda kapplöparna.
Var autonomin slutar
Lägg märke till vad de fem har gemensamt. Inte ett enda haveri är modellen som "går rogue". Ingen agent fattade ett dåligt beslut; intelligensen var felfri och rörmokeriet ljög. Ett standardvärde ingen satt, en fallback nåbar av misstag, en statuskod som smickrade fel, en regel jag själv ville bryta, en nyckel som stannade ett led för tidigt. Agent-tillförlitlighet, som jag praktiserar den i dag, är mest gränsdragning: för varje handling en agent kan utföra, fråga vad som händer när den fallerar halvvägs — och vem som märker det.
Arbetsregeln jag har landat i: en agent får slutföra på egen hand det som är reversibelt, observerbart och idempotent. Utkast till innehåll, förberedda ändringar, att hålla en bokningsbar tid med kapplöpningssäker unikhet under — samma gräns jag drar när jag bygger bokningssystem för tjänsteföretag. I samma stund en handling är irreversibel, osynlig eller flyttar pengar ändras designplikten: framgång måste deklareras uttryckligen, aldrig härledas; fel måste vara högljudda hela vägen till både omsändaren och människan; och dubbletter måste vara strukturellt omöjliga, inte bara osannolika.
Det jag fortfarande inte litar på agenter med
En ärlig lista, per i dag. En punkt lämnar listan först när en specifik mekanism gör dess felläge högljutt eller reversibelt — inte för att modellerna blivit smartare.
- Flytta pengar utåt. En agent får bekräfta arbete som utlösts av en signerad, idempotent betalhändelse. Den får inte initiera utbetalningar eller återköp; en människa godkänner varje enskild transaktion.
- Tala i mitt namn med främlingar. Agenter skriver utkast; jag skickar. Ett utgående mejl som är fel kostar förtroende som ingen retry kan leverera om.
- Kunddata utanför sin uppgift. En agent får den smalaste skiva data uppgiften kräver, inom samma ramar jag går igenom i GDPR och AI kring kunddata — EU-behandling, minimal åtkomst, raderbart.
- Sina egna skyddsräcken. Deny-reglerna ligger utanför agentens räckvidd. Ett system som kan redigera sina egna gränser har inga.
- Något som inte går att återställa. Raderingar, migreringar utan rollback, force-pushar. Kan historiken inte hämta tillbaka det, slutför ingen agent det ensam.
Jag bygger och driver den här stacken själv för svenska företag — agenterna, butiken, skyddsräckena och jourlistan, som är en person lång. Det är samma upplägg jag beskriver i AI-konsult mot AI-byrå: en ansvarig människa, ingen utspädning av ansvaret. Sätter ditt team agenter nära pengar eller kunder, och vill du jämföra anteckningar med någon som redan betalat den här läropengen — hör av dig.
Vanliga frågor
Ska AI-agenter få boka och ta betalt automatiskt utan en människa?
Min regel: en agent får slutföra på egen hand det som är reversibelt, observerbart och idempotent. Boka en avbokningsbar tid, med kapplöpningssäker unikhet i databasen — ja. Flytta pengar utåt — nej. Betalningar ska utlösas av en signerad händelse, som en betald Stripe-checkout, skyddas av en idempotensnyckel, och allt därutöver — återköp, utbetalningar — godkänns av en människa per transaktion.
Hur felsöker man en AI-agent som fallerar tyst?
Börja i telemetrin, inte i felmeddelandet — felet berättar var det upptäcktes, inte var det orsakades. Den mest användbara signalen jag hittat är kostnad: nästan identisk förbrukning på varje misslyckad körning betyder att du slår i ett hårt tak, till exempel en output-gräns som aldrig sattes — inte att modellen är nyckfull. Logga kostnad, tid och outputstorlek per körning, och behandla enformighet som ett fingeravtryck.
Vad bör ett team granska innan en AI-agent får röra pengar?
Fyra saker. Varje fallback-gren: kan ett fel nå en framgångsskärm? Retry-semantiken: returnerar varje hanterare ärliga statuskoder, så att avsändaren levererar om? Idempotensen: följer en och samma nyckel hela pipelinen, upprätthållen med ett unikt index i databasen? Och skyddsräckena: ligger deny-reglerna utanför agentens räckvidd, och håller de även mot operatören?
Hur skyddar man AI-agenter mot prompt injection?
Behandla varje extern sträng — webbsidor, mejl, API-svar — som data, aldrig som instruktioner, och utgå från att modellen förr eller senare låter sig luras. Därför måste de avgörande spärrarna vara deterministiska och sitta vid verktygsgränsen, utanför modellens räckvidd: deny-by-default-regler som håller oavsett hur övertygande texten är — och oavsett vem som frågar. En spärr som gör undantag för operatören gör snart undantag för en angripare som låter som operatören.
Varför är retries viktigare än upptid för agent-tillförlitlighet?
För att fel i distribuerade flöden är normala, inte undantag. En betald order som försvinner för att en hanterare returnerade 200 vid ett fel är värre än en timmes driftstopp: driftstopp syns, svalda händelser gör det inte. At-least-once-leverans plus ärliga felkoder plus idempotent hantering slår fem nior — den kombinationen gör ett fel till en fördröjning i stället för en förlust.
Sätter ni agenter nära pengar?
Jag bygger och driver produktionsagenter med riktiga betalflöden, ensam, och varje misstag i den här texten kommer ur min egen stack. Boka ett samtal — jag delar gärna det jag lärt mig, oavsett om vi jobbar ihop eller inte.
Boka ett samtal →