Hoppa till innehåll

Strukturerade utgångar: få tillförlitlig JSON ur en språkmodell

Blog / Publicerad 

Den första versionen av varje LLM-integration analyserar prosa. Du frågar efter "de tre huvudriskerna, en per rad", delas upp på nyrader, och det fungerar tills den dagen modellen skriver en inledande mening först. Strukturerade utgångar finns för att avsluta den slingan: du ger modellen ett JSON-schema, avkodaren är begränsad så att den inte kan avge något som bryter mot den, och du får tillbaka en nyttolast med fälten du bad om. Den garantin är verklig men smalare än den låter, och skillnaden är var insekterna bor.

Vad garantin faktiskt täcker

Begränsad avkodningsgaranti form. Svaret kommer att tolkas som JSON, det kommer att ha dina nycklar, typerna kommer att matcha och enum-fält kommer att innehålla ett av dina listade värden. Det är en stor förbättring jämfört med snabb-och-hopp.

Det garanterar ingenting om innehåll. Ett fält som skrivits som en sträng kommer att innehålla en sträng; huruvida den strängen är korrekt, eller uppfunnen för att uppfylla schemat, är oförändrad från tidigare. I själva verket gör ett strikt schema uppfinning något mer sannolikt, eftersom ett obligatoriskt fält måste fyllas med något, och modellen har inget sätt att säga "inte närvarande i källan". Detta är det enskilt vanligaste felet i produktionen: ett obligatoriskt invoice_number i ett dokument som inte har något.

Design runt det. Tillåt null där frånvaro är möjlig, lägg till en explicit found: boolean eller a "unknown" enum-medlem, och gör aldrig ett fält obligatoriskt om inte svaret verkligen finns i varje inmatning.

Att designa ett schema som en modell kan fylla

Scheman skrivna för validering och scheman skrivna för generering ser olika ut. Några regler som gäller för alla leverantörer:

Leverantörer begränsar också vilka JSON Schema-sökord de stöder i strikt läge: oneOf, mönsterbegränsningar, numeriska gränser och rekursion är vanligtvis begränsade eller ignoreras. Anta att schemat endast begränsar strukturen och tillämpa dina affärsregler själv efter analys.

Bekräfta ändå

Även med ett strikt läge, validera varje svar innan det rör din databas. Strikt läge kan inaktiveras av en konfigurationsändring, en reservväg kan träffa en modell som inte stöder den, ett nätverksförsök kan returnera ett felobjekt och svaret kan trunkeras av en token-gräns mitt-objektet - vilket ger ogiltig JSON som inget schemaläge förhindrar.

När en nyttolast misslyckas är den användbara frågan vilket fält och varför. De JSON Schema validator tar dokumentet och schemat och rapporterar en rad per problem, med JSON Pointer-sökvägen, nyckelordet som misslyckades och värdet som faktiskt hittades. Det är exakt det formuläret du vill ha för två syften: att fixa ditt schema under utvecklingen och återkoppla till ett nytt försök - en misslyckad valideringsrapport som klistrats in i ett uppföljningsmeddelande är en anmärkningsvärt effektiv reparationsuppmaning, eftersom modellen kan se exakt vad det blev fel.

Begränsa försöken till ett eller två. En modell som misslyckas med ett schema två gånger blir vanligtvis tillfrågad om något som inmatningen inte innehåller, och det tredje försöket kommer att uppfinna det.

Från ett exempel på nyttolast till kod

De flesta scheman börjar livet som ett exempelsvar som någon klistrat in i en chatt. Att förvandla det till maskinskriven, validerad kod för hand är tråkigt och felbenäget, så gör det inte.

Klistra in provet i JSON till Zod-schema och du får ett Zod-schema plus den härledda TypeScript-typen. Det drar slutsatsen per fält snarare än att helt enkelt skriva allt som en sträng: värden som ser ut som e-postmeddelanden, webbadresser, UUID eller ISO-datum får .email(), .url(), .uuid() och .datetime() istället för en bar z.string(), matriser bär sin elementtyp, och ett fält vars typ varierar mellan förekomster blir en förening snarare än att tyst välja den första den såg. Det sista beteendet är värt att mata medvetet: klistra in tre eller fyra riktiga svar sammanlänkade, inte ett, så valfria och polymorfa fält dyker upp som fackföreningar istället för att vara låsta till vad det första provet råkade innehålla.

Om du bara behöver typer och inte körtidsvalidering – eftersom nyttolasten kommer från en källa som du redan litar på – JSON till TypeScript producerar gränssnitten direkt, med kapslade objekt uppdelade som namngivna undergränssnitt snarare än infogade anonyma blobbar.

Håll sanningens riktning rak: en schemadefinition, med allt annat genererat från den. Ett Zod-schema och ett JSON-schema som underhålls separat kommer inte att överensstämma inom en månad, och oenigheten kommer att dyka upp som ett produktionsanalysfel snarare än ett testfel.

Läser vad som kom tillbaka

Modellsvar kommer förminskad på en rad, vilket gör att de blir olyckliga. De JSON-formaterare drar in och sorterar dem till något läsbart, och dess validering fångar trunkeringsfallet omedelbart - en nyttolast som slutar mitt på strängen är signaturen för en träfftokengräns, och fixen är ett högre utdatatak eller ett mindre schema, inte en promptändring.

När du jämför vad två modeller producerade från samma ingång, eller kontrollerar om en snabb ändring ändrade utdata på ett sätt som du inte hade för avsikt, ändra de formaterade nyttolasterna istället för att läsa båda. Strukturella skillnader som är osynliga i en vägg av JSON - ett fält som tyst blev en sträng av siffror istället för ett nummer - sticker ut direkt i en skillnad.

Versionering

Scheman ändras, och modellens utdata ändras med dem. Lägg ett versionsfält i nyttolasten från första dagen, så att lagrade poster bär den form de skrevs under. Efter att du har en miljon rader otaggad JSON i efterhand är den typ av migrering som ingen schemalägger tid för.

Alla dessa verktyg körs lokalt i din webbläsare, vilket betyder mer än vanligt för det här arbetsflödet: exempel på nyttolaster du förvandlar till scheman är vanligtvis riktiga API-svar med riktiga kunddata i dem, och de bör inte laddas upp till en formateringstjänst för att förfinas.

Skrivet av Ján Turský

Skapare av TextArray — bygger kostnadsfria, integritetsinitierade verktyg som körs helt i din webbläsare.