How to Build a Great Schema

Consensus is Retab’s approach to schema validation: it makes multiple parallel AI requests using the same schema and compares the results. Why consensus matters: When multiple AI responses disagree, it reveals ambiguities in your schema or prompt. This lets you understand failure modes and fix them before production. Instead of hoping your schema works reliably and experimenting blindly, consensus shows you exactly where it might fail.

The Schema Building Process

  1. Define/Update Schema—Create your data structure with field names, types, and descriptions
  2. Execute with n_consensus = 4—Run 4 parallel extractions using the same schema to see where responses differ
  3. Review Likelihood Metrics—Check which fields have low consensus scores (below 0.75 means problems)
  4. Adjust Prompt·Types·Structure—Fix the problematic fields by changing descriptions, types, or breaking them into smaller parts
  5. Repeat—Keep iterating until all fields hit +0.75 likelihood scores

Visualizing Consensus on the Retab Dashboard

The Retab dashboard provides powerful visualization tools to help you understand consensus patterns and optimize your schemas. Query parameters:
ParameterDescriptionDefault
extraction_idUnique identifier for the extractionRequired
include_responsesInclude individual response detailsfalse
formatResponse format (summary or detailed)summary
thresholdMinimum likelihood threshold for filtering0.0

Schema Improvement Levers

LeverWhen to apply (typical consensus patterns)Root causeConcrete fix
Change field namesDiverging values because models mix up concepts (e.g. organizer vs event title)Ambiguous or overloaded labelRename nameevent_name; clarify: “Do not include organizer.”
Enhance field descriptionsCorrect data, wrong format · Empty vs filled arrays · Varying data across requestsInstructions too vagueAdd examples: “Return price in USD, two decimals (e.g. 1234.56).” / “Include items only if stock > 0.”
Adjust field typesNumbers arrive as strings/ints/floats · Date/time fields vary wildlyFormat ambiguity or loose typingamount: Decimal instead of str; date: datetime.date with ISO-8601 requirement
Restructure data hierarchySingle field conflates multiple concepts (address, full name, etc.)Ambiguous formattingReplace address: str with nested Address model (street, city, zip_code, country)
Add reasoning promptsSimple computations fail or values inconsistent even with clear schemaModel needs step-by-step reasoning spaceAdd “Convert the weight to kg” as reasoning prompt to weight
Remove problematic fieldsField stays low-likelihood after multiple iterations and isn’t criticalUnnecessary complexityDrop the field entirely or defer to a later version

Example of a schema building process

Step 1 — Draft an Initial Schema

class CalendarEvent(BaseModel):
    name: str
    date: str
    address: str

Step 2 — Execute with Consensus

from retab import Retab

client = Retab()

result = client.documents.extract(
    model="gpt-4o-mini",
    messages=messages,
    json_schema=CalendarEvent.model_json_schema(),
    n_consensus=4,
)

print(json.dumps(result.likelihoods, indent=2))
Sample output:
# Obtained from result.choices[0].message.content
{
  "name": "Science Fair",
  "date": "Friday",
  "address": "123 Main St, Anytown, USA"
}
Interpretation of the consensus likelihoods:
  • The name field is reliable (perfect consensus)
  • The date field requires format unification (mixed formats)
  • The address field is unstable (high variation in structure)

Step 3 — Rank Fields by Likelihood

FieldLikelihoodStatusRecommended Action
name1.0✅ GoodRetain current configuration
date0.5⚠️ Needs workClarify format or tighten type
address0.25❌ PoorRedesign field data structure
Production threshold: Likelihood ≥ 0.75 is recommended for production deployment.

Step 4 — Enhance schema

PriorityLeverUse CaseExample Modification
1Prompt clarificationExtraction varies across runs”Name is the event title, not the organizer’s name”
2Type constraintsParsing errors, format issuesConvert strdatetime.date
3Structural revisionField conflates multiple conceptsBreak address into street, city, zip_code, country
Revised schema:
class Address(BaseModel):
    street: str
    city: str
    zip_code: str
    country: str

class CalendarEvent(BaseModel):
    name: str
    date: datetime.date
    address: Address
Improved outputs:
# Obtained from result.choices[0].message.content
{
  "name": "Science Fair",
  "date": "2024-03-15",
  "address": {
    "street": "123 Main St",
    "city": "Anytown",
    "zip_code": "12345",
    "country": "USA"
  }
}
Repeat these steps until all fields achieve high likelihood scores.

Best Practices

  1. Start with n_consensus=5 for development and testing
  2. Target likelihood ≥ 0.95 on every field for production readiness
  3. Fix lowest consensus scores first — maximize improvement impact
  4. Test with diverse documents — different formats reveal different issues
Consensus reveals where your schema is brittle. Fix the ambiguities that consensus exposes, and you’ll build robust schemas that work reliably in production.