There’s a moment in almost every AI project where you need structured data out of unstructured text. A document, an email, a scraped webpage, a user message — something that has meaning you need to extract and work with programmatically.
The first instinct is to ask the model. Write a prompt, ask for JSON, parse the response. It works. You ship it.
Then three weeks later it breaks in production, and you spend two hours debugging a parsing error caused by a model response that wrapped the JSON in a markdown code block, for reasons you cannot explain.
The question isn’t whether you can get structured data from a prompt. You can. The question is when that’s the right approach, and when you need something more disciplined.
What prompt engineering for extraction actually looks like
A typical extraction prompt looks something like this:
Extract the following fields from the text below and return them as JSON:
- company_name (string)
- founded_year (integer or null)
- employee_count (integer or null)
- headquarters (string or null)
Text:
{{document}}
Return only valid JSON, no explanation.
This works well. For a lot of use cases, it works reliably. The model understands the schema, returns valid JSON most of the time, and handles cases where fields are absent by returning null.
But “most of the time” and “works well” are different from “production-reliable.”
Where pure prompt engineering breaks
Output format consistency. Models are not JSON parsers. They’re trained on text, and when you ask for JSON, they produce text that looks like JSON. The difference matters when:
- The model wraps output in ```json code fences
- The model adds an explanation before or after the JSON
- The model uses single quotes instead of double quotes
- The model hallucinates extra fields not in your schema
- The model truncates a long response mid-object
You can handle most of these with post-processing, but you’re now maintaining a parser on top of a prompt, and the edge cases are unbounded.
Schema evolution. When your schema changes — a new field, a field that’s now required, a type change — the only feedback mechanism is a runtime error in production. There’s no static validation, no type checking, no way to catch the mismatch at build time.
Nested and relational structures. Getting a list of strings out of a prompt is easy. Getting a nested object with arrays of objects, each with their own optional fields and type constraints, becomes a prompt engineering exercise that grows in complexity with every schema change.
Confidence and provenance. When a prompt-extracted value is wrong, you have no signal. The model hallucinated a value that wasn’t in the source text, or misinterpreted an ambiguous phrase, or confidently extracted from the wrong part of the document. You find out when a downstream system acts on bad data.
Volume and consistency. At low volume, prompt extraction is fine. At high volume, you’re paying model inference costs for output that includes lots of tokens that aren’t your data. You’re also subject to variance — the same document processed twice might return slightly different output depending on temperature and model state.
What a structured extraction pipeline adds
A proper extraction pipeline addresses these problems with a few distinct mechanisms.
Schema-first validation. You define your output schema explicitly — using JSON Schema, Pydantic, Zod, or a purpose-built extraction schema. The pipeline validates every output against the schema before returning it to you. Invalid outputs trigger retries with corrective prompting, not runtime errors in your application.
Typed output guarantees. When you call an extraction endpoint with a defined schema, you get back typed data you can trust. founded_year is an integer or it’s null. It’s not a string representation of a number. It’s not missing. It’s not “circa 1998.”
Retry and correction logic. When a model produces invalid output — wrong format, missing required field, type mismatch — the pipeline can automatically retry with a correction prompt that includes the validation error. This happens transparently, without your application seeing it.
Confidence signals. A well-designed extraction system can return confidence scores alongside extracted values, flag fields that couldn’t be found in the source text (vs. fields that were found but ambiguous), and surface cases where the extraction is uncertain.
Provenance. For each extracted field, you can know where in the source document the value came from. This is essential for auditability in regulated industries, useful everywhere for debugging.
The practical decision
The choice between prompt engineering and a structured extraction pipeline isn’t really about capability — it’s about where you sit on the reliability curve.
Use prompt engineering when:
- You’re prototyping or in early exploration
- The schema is simple and stable (3–5 scalar fields)
- Occasional extraction failures are acceptable and you’ll review outputs manually
- You’re processing low volumes and cost sensitivity is high
- The extracted data is used for soft decisions, not hard system state
Use a structured extraction pipeline when:
- Your schema has more than ~5 fields, or includes nested structures
- You’re processing at any meaningful volume (hundreds+ documents)
- Extraction failures have downstream consequences (database writes, user-visible data, automated decisions)
- Your schema evolves and you need validation to catch mismatches
- You need confidence signals or provenance for auditability
The crossover point is earlier than most teams expect. A schema with six fields and two nested arrays is already at the edge of what pure prompt engineering handles gracefully. At that complexity, the debugging overhead of fragile JSON parsing often exceeds the cost of setting up a proper extraction pipeline.
A note on hybrid approaches
The most pragmatic approach for many teams is neither pure prompt engineering nor a full purpose-built pipeline — it’s using a model provider’s structured output feature (function calling, structured outputs, constrained decoding) combined with explicit schema validation on your side.
This gives you:
- Output that’s constrained to your schema at the model level
- Runtime validation that catches anything that slips through
- A clear contract between the extraction layer and the rest of your system
It doesn’t give you everything a full pipeline provides — confidence scores, provenance, multi-step correction logic — but it eliminates the most common failure modes and is straightforward to implement.
The key insight is the separation of concerns: the model’s job is to understand the source text and identify the relevant information; the extraction layer’s job is to ensure that information is delivered in a form your system can rely on. When those two things are conflated into a single prompt, both become fragile.
Structr is a structured data extraction API that handles schema validation, type enforcement, and retry logic — so your extraction pipeline is reliable by default.