<!-- Canonical URL: https://ask.atlascloud.ai/nl/structured-json-output-after-llm-api-migration -->

# Waarom breekt gestructureerde JSON-uitvoer na een LLM API-migratie?

> Gestructureerde JSON breekt meestal na een LLM-API-migratie omdat de oude en nieuwe stacks verschillende contracten hanteren. Vergelijk requestschema's, responsmodi, streaminggedrag, tool-call-enveloppen, weigeringen en validatieregels voordat je de prompt de schuld geeft.

Een migratie verandert meer dan alleen de hostnaam. Deze kan het model, SDK-serialisatie, ondersteunde schematrefwoorden, volgorde van streamingevents, standaard samplingwaarden, veiligheidsgedrag en de exacte locatie van de gegenereerde payload veranderen. Een verzoek dat in applicatiecode equivalent lijkt, kan daardoor een ander contract op de lijn vertegenwoordigen.

De snelste diagnose is om één mislukt verzoek en de ongewijzigde respons ervan van beide providers op te slaan. Vergelijk de werkelijke HTTP-bodies, niet de wrapperobjecten die je SDK blootlegt. Die vergelijking onthult meestal of de breuk optreedt vóór generatie, tijdens generatie, of terwijl je applicatie het resultaat extraheert en valideert.

## Scheid syntaxisfouten van contractfouten

"JSON is stuk" kan verschillende defecten beschrijven. Ze als één probleem behandelen leidt tot promptaanpassingen die de echte oorzaak verbergen.

* Een syntaxisfout produceert tekst die een JSON-parser niet kan lezen.
* Een schemafout produceert geldige JSON met de verkeerde sleutels, typen, nesting of enumwaarden.
* Een extractiefout treedt op wanneer geldige gestructureerde data in een ander responsveld staat.
* Een streamingfout treedt op wanneer gedeeltelijke chunks als complete documenten worden geparseerd.
* Een weigerings- of afkappingsfout vervangt het verwachte object door een veiligheidsbericht of onvolledige payload.
* Een tool-call-fout retourneert argumenten in een tool-envelope terwijl de applicatie assistenttekst verwacht.

Log deze categorieën afzonderlijk. Een parseruitzondering, een ontbrekend verplicht veld en een API-niveau `400` mogen niet één generieke retryteller delen.

## Vergelijk de twee verzoekcontracten

Begin met een veld-voor-veld-migratiematrix. Namen die op elkaar lijken betekenen niet altijd hetzelfde.

| Contractgebied | Oude stack | Nieuwe stack | Testvraag |
|---|---|---|---|
| Uitvoermodus | JSON-object | Schemagebonden object | Garandeert het alleen syntax of het volledige schema? |
| Schemalocatie | Toolparameters | Responsformaat | Is het schema aan het juiste verzoekveld gekoppeld? |
| Striktheid | Impliciet | Expliciete flag | Moet de strikte modus worden ingeschakeld? |
| Niet-ondersteunde trefwoorden | Genegeerd | Afgewezen | Worden unions, formats, defaults of references geaccepteerd? |
| Extra sleutels | Toegestaan | Geblokkeerd | Wordt `additionalProperties` consistent behandeld? |
| Streaming | Tekstdeltas | Getypeerde events | Welke event bevat het voltooide object? |
| Weigeringen | Assistenttekst | Specifiek veld | Kan de extractor weigering onderscheiden van uitvoer? |

Leg het definitieve geserialiseerde verzoek vast na SDK-verwerking. Standaardwaarden die de oude client introduceerde, kunnen tijdens de migratie verdwijnen. Het omgekeerde gebeurt ook: een nieuwe SDK kan een strikte flag toevoegen of een veld voor responsformaat hernoemen zonder duidelijke applicatiefout.

## Verklein het schema voordat je de prompt wijzigt

Test eerst het kleinst mogelijke schema. Begin met één verplichte string en geen optionele vertakkingen. Voeg één voor één integers, arrays, geneste objecten, enums en conditionele structuren toe. Dit isoleert niet-ondersteunde functies veel sneller dan steeds een productieprompt herschrijven.

Een draagbare baseline kan er bijvoorbeeld zo uitzien:

```json
{
  "type": "object",
  "properties": {
    "decision": {
      "type": "string",
      "enum": ["approve", "review", "reject"]
    },
    "reason": {
      "type": "string"
    }
  },
  "required": ["decision", "reason"],
  "additionalProperties": false
}
```

Als dit werkt, zijn het transport en het basale handhavingspad solide. Als het productieschema faalt nadat je één functie hebt toegevoegd, heb je een specifieke compatibiliteitsvraag in plaats van een vaag probleem met modelkwaliteit.

## Inspecteer waar de gestructureerde payload staat

Migraties van providers breken vaak extractiecode. De ene stack retourneert JSON in een assistentbericht, een andere in een geparseerde gemaksproperty, en weer een andere als gestringifyde toolargumenten. Streaming kan een reeks getypeerde events blootleggen in plaats van gewone tekstdeltas.

Maak een genormaliseerd intern resultaat voordat de rest van de applicatie de respons ziet:

```ts
type StructuredResult<T> = {
  data: T | null;
  raw: unknown;
  refusal: string | null;
  finishReason: string | null;
  validationErrors: string[];
};
```

Bewaar `raw` tijdens de migratieperiode. Het is het bewijs dat nodig is om een defect in modeluitvoer te onderscheiden van een adapterdefect. Redigeer gevoelige inhoud voordat je logs opslaat, en stel een bewaartermijn in die passend is voor je applicatie.

## Parseer geen onvoltooide stream

Een JSON-document is doorgaans ongeldig tot de laatste byte arriveert. Elke tekstdelta parseren genereert verwachte fouten die op productiestoringen lijken. Buffer de volledige uitvoer, gebruik een door de provider ondersteunde incrementele JSON-parser, of consumeer een gedocumenteerde event die de gefinaliseerde gestructureerde respons vertegenwoordigt.

Je streamingtest moet meer dan alleen het happy path dekken:

* strings die over chunks zijn gesplitst;
* ge-escapete aanhalingstekens en Unicode-tekens;
* arrays met veel elementen;
* een verbreking vóór de afsluitende accolade;
* een weigeringsevent;
* een geldig eindobject gevolgd door usage-metadata;
* toolargumenten die in meerdere deltas worden geleverd.

Behandel een netwerkonderbreking als een onvolledige generatie, niet als misvormde modeluitvoer. Opnieuw proberen kan veilig zijn voor een alleen-lezen classificatieverzoek, maar het is mogelijk niet veilig als het resultaat een extern neveneffect triggert.

## Valideer twee keer, maar repareer zorgvuldig

De provider kan een schema handhaven, maar je applicatie moet het genormaliseerde resultaat nog steeds valideren op zijn trustgrens. Dit beschermt je tegen adapterfouten, functieregressies en aannames die de provider nooit heeft belooft.

Een praktische volgorde is:

1. Controleer of het HTTP-verzoek is geslaagd.
2. Detecteer weigering, afkapping of afronding van tool-call expliciet.
3. Extraheer de voltooide gestructureerde payload.
4. Parseer het één keer.
5. Valideer het met de schemaversie van de applicatie.
6. Wijs onbekende of onveilige waarden af voordat bedrijfslogica draait.

Vermijd een onbeperkte "fix this JSON"-lus. Een reparatiemodel kan de betekenis veranderen terwijl het de syntax geldig maakt. Als reparatie acceptabel is, beperk het tot één poging, geef de validatiefouten mee, bewaar de oorspronkelijke uitvoer en valideer het gerepareerde object opnieuw. Stuur het geval voor impactvolle acties in plaats daarvan naar beoordeling.

## Bouw een migratie-replaysuite

Stel vóór het routeren van productieverkeer een compact corpus samen uit echte verzoekvormen. Verwijder persoonlijke of vertrouwelijke data en neem vervolgens cases op die de grenzen van je contract testen.

| Casegroep | Wat op te nemen | Slaagvoorwaarde |
|---|---|---|
| Normaal | Veelvoorkomende korte inputs | Geldig object met verwachte waarden |
| Optionele velden | Ontbrekende en aanwezige varianten | Verplicht en optioneel gedrag komt overeen met contract |
| Ambigu | Tegenstrijdige of ondergespecificeerde input | Geldig object plus een toegestane onzekerheidsstatus |
| Lange context | Dicht bij het normale maximum van de applicatie | Geen afkapping en geldige extractie |
| Adversarieel | Tekst die het model vraagt het schema te negeren | Schema blijft intact |
| Weigering | Niet-toegestaan of onveilig verzoek | Weigering wordt gedetecteerd zonder parserverwarring |
| Streaming | Chunkgrenzen en verbrekingen | Alleen voltooide payloads bereiken validatie |

Draai beide providers met stabiele parameters en registreer geldigheidspercentage, semantische overeenstemming, weigeringspercentage, afkappingspercentage, latentie en retryaantal. Exacte semantische gelijkheid wordt niet altijd verwacht, maar schemageldigheid moet een harde poort zijn.

## Zet compatibiliteit achter een adapter

Laat providertypen voor responses niet door de hele codebase lekken. Een kleine adapter moet eigenaar zijn van verzoekconstructie, schemacapabiliteitscontroles, response-extractie, finishredenen, usage-velden en foutnormalisatie. De rest van de applicatie moet één interne interface gebruiken.

Een OpenAI-compatibele gateway zoals [Atlas Cloud](https://www.atlascloud.ai/?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=structured-json-output-after-llm-api-migration) kan herhaald integratiewerk verminderen wanneer een applicatie tekst-, beeld- en videomodellen gebruikt. Compatibiliteit op transportlaag is nuttig, maar haalt modelniveau-tests niet weg. Houd capability-flags bij voor gestructureerde uitvoer, tools, streaming en schemafuncties in plaats van aan te nemen dat elk model achter een compatibel endpoint zich identiek gedraagt.

Versioneer de adapter en het schema samen. Wanneer een schema verandert, sla je de schemaversie op bij de uitvoer zodat downstreamservices weten welk contract ze hebben ontvangen.

## Gebruik een gefaseerde uitrol met duidelijke stopcondities

Begin met offline replay, dan schaduwverkeer, dan een klein live percentage. Vertrouw niet alleen op geaggregeerd succes. Een geldigheidspercentage van 99% kan nog steeds onacceptabel zijn als de 1% fouten clusteren in betalings-, moderatie- of autorisatieverzoeken.

Definieer stopcondities vóór de test:

* een onveilige enum bereikt bedrijfslogica;
* schemageldigheidspercentage daalt onder de huidige baseline;
* omgang met weigeringen wordt ambigu;
* afkapping stijgt boven de afgesproken drempel;
* retries verhogen kosten of latentie boven het budget van de applicatie;
* raw responses kunnen niet worden gereconcilieerd met genormaliseerde outputs.

Draai waar mogelijk terug via routeringsconfiguratie in plaats van een noodcode-implementatie. Houd de oude adapter beschikbaar totdat het nieuwe pad zowel piekbelasting als zeldzame inputklassen heeft doorstaan.

## De kern

Gestructureerde JSON-fouten na een LLM API-migratie zijn meestal contractmismatches, extractiefouten of onvolledige streaminglogica, en niet het bewijs dat het nieuwe model geen instructies kan volgen. Vergelijk de payloads op de lijn, verklein het schema, normaliseer responses, valideer op de applicatiegrens en replay een representatief corpus voordat je verkeer verplaatst. Een compatibele API kan de overstap vereenvoudigen, maar expliciete capability-tests blijven de betrouwbare manier om productiegedrag te beschermen.

## FAQ

### Waarom werkt dezelfde JSON-prompt bij het ene model wel, maar bij het andere niet?

De formulering van de prompt is slechts één laag. Modellen en providers verschillen in native JSON-modi, schemaondersteuning, tokenisatie, weigeringsgedrag en hoe strikt ze beperkingen naleven.

### Is JSON-modus hetzelfde als het afdwingen van JSON Schema?

Nee. JSON-modus garandeert mogelijk alleen syntactisch geldige JSON, terwijl schema-afdwinging ook sleutels, typen, verplichte velden en soms aanvullende eigenschappen beperkt.

### Moet ik gestreamde JSON token voor token parsen?

Meestal niet. Buffer de volledige gestructureerde payload of gebruik de gedocumenteerde structured-streaminggebeurtenissen van de provider, en valideer na de laatste gebeurtenis.

### Kan een OpenAI-compatibele API migratiewerk wegnemen?

Het kan transport- en SDK-wijzigingen verminderen, maar je moet nog steeds modelspecifieke schemafuncties, finishredenen, tool-callformaten en foutgedrag verifiëren.

### Wat moet er gebeuren als validatie mislukt?

Leg het onbewerkte antwoord vast, classificeer de fout, probeer alleen veilige tijdelijke gevallen opnieuw en leid deterministische reparatie via een begrensde validatiestap in plaats van misvormde gegevens stilzwijgend te accepteren.

### Wat is de snelste preproductietest?

Speel een vaste corpus van normale, ambigue, adversariële, weigerings-, long-context- en streamingverzoeken af tegen beide stacks en vergelijk gevalideerde outputs veld per veld.
