Skip to course content
Free LangChain course

LangChain for LLM Applications and RAG

Unit 03.04: Schemas that survive a model change

Schemas change. Which direction they change in determines whether in-flight data still validates.

Optional additions, and the enum trap

Adding an optional field is backward compatible. Widening an enum is not, in the direction people expect it to be.

The code validates old output against a new schema and a new value against an old one.

from pydantic import BaseModel
from typing import Literal, Optional


class TriageV1(BaseModel):
    category: Literal["billing", "technical", "other"]


class TriageV2(BaseModel):
    """Added a category and an optional field. Old outputs still validate."""
    category: Literal["billing", "technical", "account", "other"]
    confidence: Optional[float] = None


old_output = {"category": "billing"}
print("old output against V2:", TriageV2(**old_output))

try:
    TriageV1(**{"category": "account"})
except Exception as exc:
    print("new value against V1: rejected -- widening is not backward compatible")

print("""
Two rules that keep a schema survivable:
  - new fields are optional with a default, so old responses still validate
  - widening an enum breaks OLD code reading NEW data, so deploy readers first
""")

The old output validates fine against V2 because the new field is optional. The new value is rejected by V1 - which means the breakage is in *old code reading new data*, not the other way round.

That has a deployment consequence worth remembering: deploy the readers before the writers. If a new category starts being produced while some instances still run the old schema, those instances reject valid data, and the failure looks like a model problem.

The mistake this prevents

The mistake is treating a schema change as a code change and deploying it everywhere at once. During any rolling deploy both versions run simultaneously, and the schema has to be valid for both for the length of that window.

Takeaway

New fields optional with defaults; widened enums need readers deployed first. During a rolling deploy both schema versions run at once, and both must accept the data in flight.