Skip to content
NLEN
Illustration: Prompt rules or API schema: when to use which output method

Enforcing output: prompt rules or API schema — when to use which

By Ivo Donker — compiled with AI assistance (Claude & Gemini)

Anyone integrating a language model into a software architecture sooner or later runs into the same fundamental problem: how do you force the model to return valid JSON, strict field types, or a fixed syntax format? Within software development there are roughly two approaches to achieve this. On one hand, there's the declarative route via pure prompt design, where you supply context, explicit syntax rules, and few-shot examples. On the other hand, there's the programmatic route via API schemas, JSON Schema definitions, and token-level logit masking.

Both approaches have their own reason to exist, but in practice they're regularly misapplied. Developers sometimes try to prevent a model from drifting off track with dozens of lines of prompt instructions, while a strict API schema offers a 100% syntactic guarantee. Conversely, dynamic, polymorphic data structures are sometimes awkwardly forced into rigid API schemas, causing reasoning power and flexibility to be lost. In this article we thoroughly compare both techniques on reliability, latency, token costs, implementation complexity, and maintainability.

The fundamental distinction: semantic suggestion versus deterministic validation

The core difference between prompt rules and API schemas lies in where validation takes place. When you try to enforce output through prompt rules, you rely entirely on the model's probabilistic sense of language. You're asking the model to take the instruction in the system prompt into account while decoding each subsequent token. At its core, that remains a semantic request: for every token, the model calculates the most logical continuation based on its training data and the supplied context.

With an API schema (such as OpenAI Structured Outputs or Anthropic Tool Use / Tool Calling), the inference engine intervenes directly in the decoding process. Through techniques such as context-free grammars (CFG) or finite state machines (FSM), the engine filters out invalid tokens before sampling takes place. Tokens that are grammatically impossible at that specific point in the JSON structure — such as a letter character when an integer is expected — get a logit value of negative infinity. As a result, the model simply cannot produce syntax errors.

In the article on how to get an LLM to answer in a fixed output format we discuss the general strategies for forcing parsable answers. Where general output steering explores the playing field, this article zooms in on the trade-off between steering via instructions versus steering via schema-based runtime engines.

How prompt rules work: steering via context, examples, and negative constraints

Steering output through prompts rests on three mechanisms: explicit format declaration, type indications, and boundary markers. A typical prompt-based implementation specifies exactly which fields must be present, what data type is expected, and in which JSON structure the result must be cast. To keep the model from using markdown formatting (such as ```json code blocks) or introductory pleasantries, explicit negative instructions are often added.

For those who want to steer purely through prompt text without depending on specific API features, the guide on enforcing form from the prompt itself offers an overview of templates and schema techniques. A basic example of pure prompt-based steering looks like this:

Je bent een data-extractie parser.
Zet de invoertekst om naar een JSON-object met exact deze structuur:
{
  "klant_id": "string (formaat: KLT-XXXX)",
  "factuurbedrag": "number (in euro's)",
  "betaald": "boolean",
  "posten": ["string"]
}

Regels:
1. Geef uitsluitend het JSON-object terug.
2. Geen markdown backticks, geen inleidende tekst, geen afsluiting.
3. Ontbreekt een veld, gebruik dan null.

To eliminate unwanted elements such as introductory pleasantries in pure prompt-based steering, you can apply techniques from the article on negative prompting and constraint enforcement. The downside of this pure prompt-based approach nevertheless remains evident: at high processing volumes or with complex nested structures, the model will statistically still hallucinate, forget commas, or insert invalid characters in a fraction of cases.

How API schemas and grammar-constrained decoding work

API-based structured output shifts responsibility from the language model to the inference runtime. Developers supply a formal JSON Schema (often generated via Pydantic or Zod) along with the API call. The runtime compiles this schema into a grammar. While generating each token, the engine calculates which tokens are syntactically valid according to the grammar and blocks all other options in the vocabulary.

Anyone who wants to see how API providers enforce this at the endpoint level via JSON Schema and tool parameters can read the technical specifications in the overview on getting reliable structured output from APIs. The generation process thereby proceeds deterministically through the steps below:

  1. Schema compilation: The JSON Schema is converted into an internal representation (such as a regex parser or a pushdown automaton).
  2. Context evaluation: The model processes the input tokens and calculates logits for the entire token vocabulary.
  3. Logit masking: The runtime checks which tokens are grammatically allowed based on the current JSON state and masks all invalid tokens.
  4. Sampling: The model picks the most probable token from the filtered subset of valid tokens.
  5. State update: The parser advances to the next position in the schema until the closing brace token has been generated.

For applying grammars to open-source runtime engines such as llama.cpp and vLLM, we refer to the step-by-step guide on enforcing well-formed JSON outputs in local LLMs, where formats such as GBNF (GGML BNF) are explained.

Reliability and error rates: randomness versus mathematical guarantee

The most important selection criterion between the two approaches is the acceptable error rate of the subsystem. In production systems where output is passed directly to downstream APIs, databases, or business-critical pipelines, a syntax error leads directly to an uninterpreted runtime exception.

With pure prompt rules, the syntax error rate for state-of-the-art models (such as GPT-4o or Claude 3.5 Sonnet) on simple schemas is around 0.5% to 3%. For smaller open-source models (7B to 14B parameters) or with deeply nested arrays, the failure rate via prompts can climb above 12%. Errors typically manifest as:

With an API schema, the syntax error rate is literally 0.0%. Mathematically speaking, the parser cannot produce a single byte that conflicts with the compiled JSON Schema. Note, however, that this only concerns syntactic correctness. Semantic errors — such as an incorrectly calculated invoice amount or a hallucinated product name — are not prevented by a schema.

Latency, token usage, and processing costs compared

A common misconception is that API schemas are always faster and cheaper than prompt rules. The reality is more nuanced and depends heavily on caching, schema size, and the initial compilation step.

As for input tokens: with prompt rules, you have to include the full structure description in the prompt text. With API schemas, you send the schema along via the API payload. With providers that support structured outputs, the schema counts toward the input token count. An extensive JSON Schema with type definitions, field descriptions, and required arrays can easily consume 300 to 800 tokens.

As for output tokens and latency: API schemas often generate fewer superfluous tokens because the model doesn't need to be instructed to avoid markdown. The model starts directly with the opening brace {. However, with local implementations and some cloud APIs, the first call with a new schema incurs a small compilation overhead (pre-processing latency). Once the schema is cached, generation speed matches unfiltered sampling exactly.

Property Prompt rules API schema (Constrained Decoding)
Syntax guarantee Probabilistic (97% – 99.5%) Deterministic (100% syntactically valid)
Field validation No strict type enforcement Strict enum, string, and type checking
Setup complexity Very low (prompt text only) Medium (JSON Schema / Pydantic models)
Flexibility Very high (free form, Markdown, CSV) Limited to formal data specifications
Token overhead Fixed in prompt text Fixed in API schema payload
Need for retries Regularly requires try-catch + fallback Retries rarely needed for syntax errors

Flexibility versus rigidity: dynamic structures and polymorphic data

Although API schemas are superior in syntactic reliability, the technique has a clear limitation: rigidity. Most runtime engines require all fields to be explicitly defined in advance (including additionalProperties: false with OpenAI Structured Outputs). This makes enforcing dynamic or polymorphic data structures significantly more complex.

Suppose you ask a model to extract an arbitrary table from a legal contract, where the number of columns and the column names differ per document. In a pure API schema, you can't allow arbitrary keys without falling back to a generic key-value array structure. That forces the model into a less natural data representation, which can come at the expense of semantic accuracy.

Prompt rules, on the other hand, excel in scenarios where the output structure needs to partly move organically with the input. Think of nested document trees with varying depth, annotated markdown tables, or situations where the model itself gets to decide whether an explanatory field is relevant to add.

Reasoning space: the danger of hasty JSON generation

A technical bottleneck with strict schema enforcement is the loss of reasoning space (scratchpad / chain-of-thought). A language model thinks through the tokens it generates. If the schema dictates that the very first output token must be an opening brace, immediately followed by the final conclusion, you deprive the model of the ability to carry out an intermediate calculation or analysis.

For example, if a model needs to perform a complex classification based on conflicting criteria, and the schema directly forces {"classificatie": "..."} , the model has to make that decision in a single forward pass without any intermediate reasoning steps. In practice, this leads to a demonstrable drop in content quality.

When designing API schemas for analytical tasks, it's therefore crucial to place a reasoning field at the front of the schema:

{
  "type": "object",
  "properties": {
    "redenering": {
      "type": "string",
      "description": "Stapsgewijze analyse van de context voordat de conclusie wordt getrokken"
    },
    "classificatie": {
      "type": "string",
      "enum": ["laag", "gemiddeld", "hoog", "kritiek"]
    },
    "betrouwbaarheidsscore": {
      "type": "number"
    }
  },
  "required": ["redenering", "classificatie", "betrouwbaarheidsscore"],
  "additionalProperties": false
}

By defining the field redenering as the first required field, the model generates its thinking steps first. Only after that does it sample the final category and score, which significantly increases accuracy.

Local models versus external cloud APIs: support in practice

The choice between prompt rules and schemas is partly determined by the model's hosting environment. With major commercial cloud providers, structured output via API parameters is now the standard. The implementation there is fully abstracted: you define a model class or JSON Schema, and the provider handles the logit masking.

In local and private cloud environments (such as self-hosted vLLM, Ollama, TGI, or llama.cpp), enforcing schemas requires specific configuration. Although frameworks such as Outlines, Guidance and SGLang support advanced grammar decoding, this brings along operational considerations:

Hybrid architectures: the schema guards the structure, the prompt fills in the content

In professional software development, the opposition between prompt rules and API schemas is often a false dichotomy. The most robust production systems combine both techniques in a layered approach:

1. The API schema defines the contract. The schema guards the syntax, guarantees types (strings, integers, arrays, booleans), blocks unwanted fields, and ensures the response can be deserialized directly into application code without parsing errors.

2. The prompt rules steer the semantics and tone. Within the schema's field descriptions and in the system prompt, you specify the substantive constraints: which criteria apply to a summary, which extraction rules apply to dates, and how to handle missing data.

import { z } from "zod";

// 1. Het schema bewaakt het syntactische contract
export const KlantEvaluatieSchema = z.object({
  analyse: z.string().describe("Korte analyse van het klantsignaal"),
  risicoNiveau: z.enum(["laag", "gemiddeld", "hoog"]),
  actiepunten: z.array(z.string()).min(1).max(5),
  opvolgingVereist: z.boolean()
});

// 2. De prompt stuurt de inhoudelijke interpretatie
export const SYSTEEM_PROMPT = `
Beoordeel het binnenkomende klantbericht strikt op basis van ons servicebeleid.
Markeer een risico alleen als 'hoog' wanneer er sprake is van juridische dreiging of dataverlies.
Formuleer actiepunten altijd als concrete werkwoorden gericht aan het supportteam.
`;

Decision matrix: when do you choose which technique?

To quickly make the right architecture decision for a specific use case, you can follow the decision structure below:

Use Case / Requirement Recommended Method Primary Reason
Direct database insert or API integration API schema (Structured Output) 100% syntax guarantee required to prevent runtime crashes.
Agent Tool Calling / Function Calls API schema (Tools/Functions) The orchestrator must be able to call arguments without a parsing layer.
Generating Markdown reports with tables Prompt rules Markdown is flexible and doesn't require a rigid JSON object structure.
Complex data extraction with unknown structure Prompt rules with Pydantic fallback Dynamic field names are hard to capture in static schemas.
Locally running LLMs with limited compute power Grammar-constrained decoding (GBNF/Outlines) Small models fail more often at prompt-based steering; grammars solve this.
Rapid prototyping and experiments Prompt rules No overhead from schema definitions during exploratory phases.

Conclusion and migration strategy

Prompt rules and API schemas aren't competing methods, but complementary tools in an AI developer's toolbox. Prompt rules are unmatched for flexible, free-form, or rapidly changing interfaces where human readers judge the output. However, as soon as data needs to be processed programmatically by software, API schemas and constrained decoding are the only responsible choice for guaranteeing robustness in production.

For existing codebases that still rely on fragile regex parsers or retry loops around prompt-based JSON, the migration path is clear: translate the desired output structures into formal JSON Schemas or Pydantic models, enable structured outputs at the API integration layer, and move semantic instructions into the field descriptions and system prompt. This results in an architecture that is both flexible in content and technically unbreakable.