Ga naar inhoud

Gestructureerde output: betrouwbare JSON uit een taalmodel halen

Blog / Gepubliceerd 

De eerste versie van elke LLM-integratie ontleedt proza. U vraagt naar "de drie belangrijkste risico's, één per regel", opgesplitst in nieuwe regels, en het werkt tot de dag dat het model eerst een inleidende zin schrijft. Er bestaan gestructureerde outputs om die lus te beëindigen: je geeft het model een JSON-schema, de decoder is beperkt zodat hij niets kan uitzenden dat dit schendt, en je krijgt een payload terug met de velden waar je om hebt gevraagd. Die garantie is reëel, maar beperkter dan het klinkt, en het verschil zit in waar de bugs leven.

Wat de garantie eigenlijk dekt

Beperkte decoderingsgaranties vorm. Het antwoord wordt geparseerd als JSON, het bevat uw sleutels, de typen komen overeen en de opsommingsvelden bevatten een van uw vermelde waarden. Dat is een grote verbetering ten opzichte van prompt-and-hope.

Het garandeert niets over inhoud. Een veld dat als string wordt getypt, zal een string bevatten; of die string accuraat is, of uitgevonden om aan het schema te voldoen, is onveranderd ten opzichte van voorheen. In feite maakt een strikt schema de uitvinding iets waarschijnlijker, omdat een verplicht veld met iets moet worden gevuld en het model niet kan zeggen "niet aanwezig in de bron". Dit is de meest voorkomende storing in de productie: een vereiste invoice_number in een document dat er geen heeft.

Ontwerp eromheen. Sta null toe waar afwezigheid mogelijk is, voeg expliciet toe found: boolean of een "unknown" enum lid, en maak nooit een veld verplicht, tenzij het antwoord echt in elke invoer voorkomt.

Een schema ontwerpen dat een model kan vullen

Schema's die zijn geschreven voor validatie en schema's die zijn geschreven voor generatie zien er anders uit. Een paar regels die gelden voor alle providers:

Providers beperken ook welke JSON Schema-trefwoorden ze ondersteunen in de strikte modus: oneOfPatroonbeperkingen, numerieke grenzen en recursie worden doorgaans beperkt of genegeerd. Ga ervan uit dat het schema alleen de structuur beperkt en handhaaf zelf uw bedrijfsregels na het parseren.

Hoe dan ook valideren

Zelfs met een strikte modus moet u elk antwoord valideren voordat het uw database raakt. De strikte modus kan worden uitgeschakeld door een configuratiewijziging, een terugvalpad kan een model raken dat dit niet ondersteunt, een nieuwe netwerkpoging kan een foutobject retourneren en het antwoord kan worden afgekapt door een tokenlimiet in het midden van het object - wat ongeldige JSON produceert die geen schemamodus verhindert.

Wanneer een payload faalt, is de nuttige vraag welk veld en waarom. De JSON Schema-validator neemt het document en het schema en rapporteert één regel per probleem, met het JSON Pointer-pad, het trefwoord dat is mislukt en de daadwerkelijk gevonden waarde. Dat is precies de vorm die u nodig heeft voor twee doeleinden: uw schema corrigeren tijdens de ontwikkeling en terugkoppelen bij een nieuwe poging. Een mislukt validatierapport dat in een vervolgbericht wordt geplakt, is een opmerkelijk effectieve reparatieprompt, omdat het model precies kan zien wat er fout is gegaan.

Beperk de nieuwe pogingen tot één of twee. Een model dat twee keer niet voldoet aan een schema, wordt meestal gevraagd om iets dat de invoer niet bevat, en bij de derde poging zal het worden uitgevonden.

Van een voorbeeldpayload tot code

De meeste schema's beginnen als een voorbeeldreactie die iemand in een chat heeft geplakt. Dat handmatig omzetten in getypte, gevalideerde code is vervelend en foutgevoelig, dus doe dat niet.

Plak het monster erin JSON naar Zod-schema en je krijgt een Zod-schema plus het afgeleide TypeScript-type. Het concludeert per veld in plaats van alles als een tekenreeks te typen: waarden die op e-mails, URL's, UUID's of ISO-datums lijken, krijgen .email(), .url(), .uuid() En .datetime() in plaats van kaal z.string(), arrays dragen hun elementtype, en een veld waarvan het type varieert tussen gebeurtenissen, wordt een unie in plaats van stilletjes het eerste te kiezen dat het ziet. Dat laatste gedrag is de moeite waard om bewust te voeden: plak drie of vier echte antwoorden aaneengeschakeld, niet één, zodat optionele en polymorfe velden verschijnen als vakbonden in plaats van vast te zitten aan wat de eerste steekproef toevallig bevatte.

Als je alleen typen nodig hebt en geen runtime-validatie – omdat de payload afkomstig is van een bron die je al vertrouwt – JSON naar TypeScript produceert de interfaces rechtstreeks, waarbij geneste objecten worden opgesplitst als benoemde subinterfaces in plaats van inline anonieme blobs.

Houd de richting van de waarheid recht: één schemadefinitie, waaruit al het andere voortkomt. Een Zod-schema en een JSON-schema dat afzonderlijk wordt onderhouden, zullen binnen een maand het oneens zijn, en het meningsverschil zal naar voren komen als een productieparseerfout in plaats van als een testfout.

Lezen wat er terugkwam

Modelreacties komen verkleind op één regel binnen, wat het bekijken ervan ellendig maakt. De JSON-formatter springt in en sorteert ze in iets leesbaars, en de validatie vangt het geval van afkapping onmiddellijk op - een payload die halverwege de tekenreeks eindigt, is de handtekening van een hit-tokenlimiet, en de oplossing is een hogere uitvoerlimiet of een kleiner schema, geen snelle wijziging.

Wanneer u vergelijkt wat twee modellen met dezelfde invoer produceerden, of controleert of een snelle wijziging de uitvoer veranderde op een manier die u niet bedoelde, kunt u de geformatteerde payloads differentiëren in plaats van beide te lezen. Structurele verschillen die onzichtbaar zijn in een muur van JSON – een veld dat stilletjes een reeks cijfers is geworden in plaats van een getal – vallen meteen op in een diff.

Versiebeheer

Schema's veranderen en de modeluitvoer verandert mee. Plaats vanaf de eerste dag een versieveld in de payload, zodat opgeslagen records de vorm behouden waarin ze zijn geschreven. Dat achteraf inbouwen nadat je een miljoen rijen ongetagde JSON hebt, is het soort migratie waar niemand tijd voor plant.

Al deze tools draaien lokaal in uw browser, wat belangrijker is dan normaal voor deze workflow: de voorbeeldpayloads die u omzet in schema's zijn meestal echte API-reacties met echte klantgegevens erin, en ze mogen niet worden geüpload naar een opmaakservice om te worden verfraaid.

Geschreven door Ján Turský

Maker van TextArray — bouwt gratis tools waarbij de privacy centraal staat en die volledig in uw browser worden uitgevoerd.