Skip to main content

Schema Enforcement

Schema Enforcement ensures your LLM outputs conform to a defined JSON schema. Perf validates responses, auto-repairs common issues, applies semantic corrections (like fixing negative prices), and guarantees you receive properly structured data.

Why Schema Enforcement?

LLMs are unreliable at producing consistent JSON:
  • Missing required fields
  • Wrong data types (string instead of number)
  • Extra fields not in schema
  • Malformed JSON syntax
  • Markdown code blocks wrapping JSON
Perf’s Schema Enforcement:
  • Validates outputs against your JSON Schema
  • Auto-repairs common issues (type coercion, format fixes)
  • Semantic correction fixes domain-specific errors (negative prices, invalid ratings)
  • Retries with better prompts if validation fails
  • Guarantees schema-compliant responses

Using Schemas in Requests

Inline Schema

Pass a JSON Schema directly in your request:
curl -X POST https://api.withperf.pro/v1/chat \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "Extract contact info: John Smith, john@example.com, 555-1234"
      }
    ],
    "schema": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string", "format": "email" },
        "phone": { "type": "string" }
      },
      "required": ["name", "email"]
    }
  }'

Schema by ID

Reference a saved schema by ID or slug:
curl -X POST https://api.withperf.pro/v1/chat \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "Extract contact info..."}],
    "schema_id": "contact-extraction"
  }'

Project Default Schema

Set a default schema for your project in the Dashboard. All requests without an explicit schema will use it.

Schema Parameters

ParameterTypeDescription
schemaobjectInline JSON Schema (Draft 2020-12)
schema_idstringID or slug of a saved schema
schema_strictbooleanDisable auto-repair, fail on any mismatch (default: false)

Response

When schema enforcement is active, responses include validation metadata:
{
  "choices": [{
    "message": {
      "content": "{\"name\": \"John Smith\", \"email\": \"john@example.com\", \"phone\": \"555-1234\"}"
    }
  }],
  "perf": {
    "schema_validation": {
      "enabled": true,
      "passed": true,
      "repaired": false,
      "schema_source": "inline"
    }
  }
}

Validation Fields

FieldTypeDescription
enabledbooleanSchema validation was active
passedbooleanFinal output passed validation
repairedbooleanAuto-repair was applied
schema_sourcestringinline, schema_id, or project_default

Auto-Repair

When schema_strict: false (default), Perf attempts to repair common issues:
IssueRepair Action
String instead of numberParse to number ("42"42)
Number instead of stringConvert to string (42"42")
String instead of booleanParse ("true"true)
Markdown code blocksExtract JSON from json ...
Extra whitespaceTrim and normalize
Missing optional fieldsLeave as undefined

Example: Auto-Repair in Action

LLM returns:
Here's the extracted data:
```json
{"name": "John", "age": "25"}

With schema requiring `age` as number, Perf:
1. Extracts JSON from markdown
2. Coerces `"25"` → `25`
3. Returns valid JSON

## Semantic Validation

Go beyond structural validation with semantic type hints. Add `x-semantic-type` to your schema fields to auto-correct common LLM errors like negative prices, out-of-range ratings, and invalid dates.

### Using x-semantic-type

```json
{
  "type": "object",
  "properties": {
    "price": {
      "type": "number",
      "x-semantic-type": "currency_positive"
    },
    "rating": {
      "type": "number",
      "x-semantic-type": "rating_1_5"
    },
    "customer_age": {
      "type": "integer",
      "x-semantic-type": "human_age"
    }
  }
}

Supported Semantic Types

TypeDescriptionAuto-Correction
currency_positivePrices, amounts (must be positive)-$999$999
currency_allow_negativeValues that can be negativeValidates magnitude only
human_agePerson ages (0-130)Clamps to valid range
percentagePercentages (0-100 or 0-1)Normalizes scale
rating_1_55-star ratings125 (clamps to max)
rating_1_1010-point ratingsClamps to 1-10 range
emailEmail addressesFormat validation
urlURLsFormat validation
date_pastHistorical datesFlags future dates
date_futureUpcoming datesFlags past dates

Example: Semantic Correction in Action

Request with semantic types:
curl -X POST https://api.withperf.pro/v1/chat \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{
      "role": "user",
      "content": "Extract: iPhone 15 Pro costs -$999, rating 12/5 stars"
    }],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "product",
        "schema": {
          "type": "object",
          "properties": {
            "name": { "type": "string" },
            "price": { "type": "number", "x-semantic-type": "currency_positive" },
            "rating": { "type": "number", "x-semantic-type": "rating_1_5" }
          },
          "required": ["name", "price", "rating"]
        }
      }
    }
  }'
Response with corrections:
{
  "choices": [{
    "message": {
      "content": "{\"name\": \"iPhone 15 Pro\", \"price\": 999, \"rating\": 5}"
    }
  }],
  "perf": {
    "semantic_validation": {
      "result": "corrected",
      "corrections": [
        {
          "field": "price",
          "original": -999,
          "corrected": 999,
          "reason": "currency_positive values must be non-negative",
          "confidence": 1.0
        },
        {
          "field": "rating",
          "original": 12,
          "corrected": 5,
          "reason": "rating_1_5 clamped to maximum value",
          "confidence": 1.0
        }
      ],
      "latency_ms": 3.2
    }
  }
}

Semantic Validation Response Fields

FieldTypeDescription
resultstringpass, corrected, or failed
correctionsarrayList of auto-corrections applied
warningsarrayNon-blocking issues detected
latency_msnumberValidation latency in milliseconds

Strict Mode

Enable strict mode to disable auto-repair:
{
  "messages": [...],
  "schema": {...},
  "schema_strict": true
}
In strict mode:
  • No type coercion
  • No format repairs
  • Validation fails on any mismatch
  • Returns error if validation fails after retries

Managing Schemas

Create Schema (Dashboard API)

curl -X POST https://api.withperf.pro/v1/dashboard/projects/{projectId}/schemas \
  -H "Authorization: Bearer <clerk_jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Contact Extraction",
    "slug": "contact-extraction",
    "description": "Schema for extracting contact information",
    "schema": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string", "format": "email" },
        "phone": { "type": "string" }
      },
      "required": ["name", "email"]
    },
    "is_default": false
  }'

List Schemas

curl https://api.withperf.pro/v1/dashboard/projects/{projectId}/schemas \
  -H "Authorization: Bearer <clerk_jwt>"

Test Schema

Test a schema against sample data:
curl -X POST https://api.withperf.pro/v1/dashboard/projects/{projectId}/schemas/test \
  -H "Authorization: Bearer <clerk_jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "schema": {
      "type": "object",
      "properties": {
        "name": { "type": "string" }
      },
      "required": ["name"]
    },
    "data": {"name": "John"}
  }'

Supported JSON Schema Features

Perf supports JSON Schema Draft 2020-12 with these features:

Types

  • string, number, integer, boolean, null
  • object, array

String Formats

  • email, uri, date, date-time, uuid

Validation Keywords

  • required, properties, additionalProperties
  • minLength, maxLength, pattern
  • minimum, maximum, exclusiveMinimum, exclusiveMaximum
  • minItems, maxItems, uniqueItems
  • enum, const

Composition

  • allOf, anyOf, oneOf
  • $ref (local references only)

Best Practices

1. Keep Schemas Simple

{
  "type": "object",
  "properties": {
    "sentiment": { "enum": ["positive", "negative", "neutral"] },
    "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
  },
  "required": ["sentiment", "confidence"]
}

2. Use Descriptive Names

Add title and description to help the LLM understand:
{
  "type": "object",
  "title": "Product Review Analysis",
  "properties": {
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5,
      "description": "Star rating from 1-5"
    }
  }
}

3. Prefer Enums for Categories

{
  "category": {
    "type": "string",
    "enum": ["bug", "feature", "question", "documentation"]
  }
}

4. Set Reasonable Defaults

Use default for optional fields:
{
  "properties": {
    "priority": {
      "type": "string",
      "enum": ["low", "medium", "high"],
      "default": "medium"
    }
  }
}

Error Handling

Validation Failed

If validation fails after retries:
{
  "error": {
    "type": "schema_validation_failed",
    "message": "Output failed schema validation after 2 attempts",
    "details": {
      "errors": [
        { "path": "/email", "message": "must match format \"email\"" }
      ]
    }
  }
}

Invalid Schema

If your schema is invalid:
{
  "error": {
    "type": "invalid_schema",
    "message": "Schema validation error: 'type' must be a string"
  }
}

Plan Limits

TierMax SchemasAuto-RepairSemantic Validation
Starter3NoNo
Pro10YesYes
Growth50YesYes
EnterpriseUnlimitedYesYes