Structured Data Extraction With LLMs: When It Beats Hand-Written Parsers

Matt George

Fractional CTO · Founder of Injuria.ai

Extracting structured data from unstructured text is a foundational problem in software engineering. For decades, developers have needed to pull specific fields like names, dates, and invoice totals from emails, PDFs, and web pages. The traditional solution involves writing parsers using tools like regular expressions[1] or document-scraping libraries. This approach is powerful but notoriously brittle. A small change in the input format can break the entire process, leading to a constant cycle of maintenance and fixes. Today, Large Language Models (LLMs) offer a fundamentally different approach, one that operates on semantic meaning rather than rigid character patterns.

This new method promises to handle variation and ambiguity in text, reducing the need for fragile, hand-written code. Yet it introduces its own set of tradeoffs involving cost, latency, and probabilistic accuracy. For engineers and technical leaders, understanding the precise mechanism behind LLM-based extraction is essential for making sound architectural decisions. This isn't a magic bullet. It's a powerful tool with a specific and growing domain of applicability, and knowing when to choose it over a traditional parser requires a clear view of how it works, what it costs, and where it fails.

The Classic Challenge of Parsing

The internet and enterprise systems are filled with semi-structured and unstructured text. An email confirmation contains an order number, a PDF invoice has a due date, and a product review on a webpage has a star rating. The goal of parsing is to convert this human-readable text into a machine-readable format like JSON[2] for use in databases, APIs, or other software systems.

The classic toolkit includes:

  • Regular Expressions: For finding simple patterns like email addresses or dates in a specific format. They are fast and efficient but struggle with nested data or even slight variations in wording.
  • DOM and HTML Parsers: Libraries like Beautiful Soup[3] for Python or JSDOM[4] for Node.js traverse the structure of an HTML[5] or XML[6] document. They are excellent for web scraping but are useless for plain text or PDF content and are still vulnerable to changes in a website's layout.
  • Custom State Machines: For complex, non-standard formats, engineers sometimes build bespoke parsers that read the input character by character or line by line, changing state based on the content. This is a time-consuming and error-prone process.

The shared weakness of these methods is their brittleness. They codify a set of assumptions about the input's structure. When those assumptions are violated, for example when a website changes its <div> structure or an invoice template is updated to say “Amount Payable” instead of “Total Due”, the parser breaks. This creates a significant maintenance burden, especially for systems that interact with many third-party data sources.

How LLMs Extract Structured Data: The Mechanism

Using an LLM for data extraction is not a form of fuzzy pattern matching. It's a sophisticated process of instruction following, semantic understanding, and constrained generation. The reliability of modern techniques comes from combining the model's language capabilities with rigid output schemas.

Step 1: Prompting with a Schema

Everything starts with the prompt. A well-crafted prompt provides the LLM with the three things it needs: the unstructured input text, a clear instruction, and a precise description of the desired output structure. The most critical part is the schema definition. Simply asking for “a JSON object” is unreliable. A production-grade prompt specifies the fields, data types, and whether fields are required or optional. This can be done by including a textual representation of a JSON Schema[7] or a type definition from a language like TypeScript or Python.

Step 2: Tokenization and Semantic Embedding

When the prompt is sent to the model, it's first broken down into smaller units called tokens. This process, known as tokenization, typically uses an algorithm like Byte-Pair Encoding (BPE)[8]. The model does not see words or characters, it sees a sequence of these tokens.

Each token is then mapped to a high-dimensional vector called an embedding. This embedding represents the token's semantic meaning in the context of the input text. This is the core of how LLMs overcome the brittleness of regex. The embeddings for “Total Due”, “Amount Payable”, and “Balance” will be mathematically close in the vector space, allowing the model to recognize them as the same concept. This is a feat of semantic understanding, not character matching.

Step 3: The Transformer's Attention

The token embeddings are processed through a Transformer architecture[9], which was first introduced in a 2017 paper titled “Attention Is All You Need”[10]. The key innovation of the Transformer is the self-attention mechanism. As the model generates the output token by token, the attention mechanism allows it to dynamically weigh the importance of all the input tokens.

When asked to fill the invoice_total field, the attention mechanism will assign a high weight to tokens in the input that are semantically related to that concept, like “$54.99”, “Total”, and “USD”. This allows the model to locate the correct value in the text, even if its position changes from one document to the next.

Step 4: Constrained Generation via Function Calling

This final step is what makes LLM extraction reliable enough for many production use cases. Instead of just generating a JSON string and hoping it's valid, modern LLM APIs use a technique often called “function calling” or “tool use”. This feature was popularized by OpenAI's GPT models[11] and has been adopted by others, including Google's Gemini API[12].

Here’s how it works: you provide the model with a formal schema of a “function” you want it to call, including its name, a description, and the parameters it accepts (which is your desired JSON schema). The LLM's task is not to generate JSON directly. Its task is to generate a special object indicating it wants to call your function, along with the arguments that fit the schema you provided. The API provider's backend ensures that the arguments are a syntactically valid JSON object that conforms to your schema. This is achieved by masking the model's output probabilities (logits) at each step of generation, permitting only tokens that maintain the valid JSON structure. This completely eliminates syntax errors and schema validation failures, leaving only the possibility of semantic errors (extracting the wrong value).

A Concrete Example: Extracting Invoice Data

Let's consider a practical example. Imagine you need to process thousands of plain-text invoices that look something like this:

Invoice #INV-00123
Date: 2024-07-26
From: Global Supplies Inc.
To: Acme Corp

Description | Qty | Unit Price | Total
-------------------------------------------------
Standard Widget | 2 | $25.00 | $50.00
Shipping | 1 | $4.99 | $4.99

Total Amount Due: $54.99

A traditional parser for this would be fragile. If Total Amount Due: changes to Balance:, it breaks.

Here’s how you would solve this using Python, the OpenAI client, and the function calling feature. First, we define our desired data structure using Pydantic[13], a popular data validation library.

import os
from openai import OpenAI
from pydantic import BaseModel, Field
from typing import Optional

# Define the desired data structure using Pydantic
# This serves as the schema for the LLM.
class Invoice(BaseModel):
 invoice_id: str = Field(description="The unique identifier for the invoice, e.g., INV-00123")
 issue_date: str = Field(description="The date the invoice was issued, in YYYY-MM-DD format")
 customer_name: str = Field(description="The name of the recipient of the invoice")
 total_amount: float = Field(description="The total amount due on the invoice")
 currency: Optional[str] = Field(default="USD", description="The currency of the total amount, e.g., USD")

# Initialize the OpenAI client
# Assumes OPENAI_API_KEY environment variable is set
client = OpenAI()

invoice_text = """
Invoice #INV-00123
Date: 2024-07-26
From: Global Supplies Inc.
To: Acme Corp

Description | Qty | Unit Price | Total
-------------------------------------------------
Standard Widget | 2 | $25.00 | $50.00
Shipping | 1 | $4.99 | $4.99

Total Amount Due: $54.99
"""

def extract_invoice_data(text: str) -> Invoice:
 response = client.chat.completions.create(
 model="gpt-4o",
 messages=[
 {"role": "system", "content": "You are an expert data extraction system. Extract information from the user's text and format it according to the provided schema."},
 {"role": "user", "content": text}
 ],
 tools=[{"type": "function", "function": {"name": "save_invoice", "description": "Save the extracted invoice data", "parameters": Invoice.model_json_schema()}}],
 tool_choice={"type": "function", "function": {"name": "save_invoice"}}
 )

 # The API returns the arguments for the function call as a JSON string
 tool_call_args = response.choices[0].message.tool_calls[0].function.arguments
 
 # Parse the JSON string into our Pydantic model
 # This validates the data and gives us a clean Python object
 extracted_data = Invoice.model_validate_json(tool_call_args)
 return extracted_data


# Run the extraction
invoice_data = extract_invoice_data(invoice_text)
print(invoice_data.model_dump_json(indent=2))

This code will reliably produce the following JSON output, even if the input text has variations:

{
 "invoice_id": "INV-00123",
 "issue_date": "2024-07-26",
 "customer_name": "Acme Corp",
 "total_amount": 54.99,
 "currency": "USD"
}

The key is that we've delegated the semantic understanding to the LLM while enforcing a rigid output structure through code. This combination is what makes the technique powerful.

The Decision Lens: Tradeoffs and Costs

Choosing between an LLM and a hand-written parser is an economic and architectural decision. There is no single right answer; the correct choice depends entirely on the context.

When to Use LLMs for Extraction

  1. High Input Variability: The source text format is inconsistent, changes frequently, or is expressed in natural, human language. Examples include processing emails from different senders, extracting information from customer support chats, or summarizing legal clauses from various contracts.
  2. Rapid Prototyping and Low Volume: You need to get a solution working quickly for an internal tool, a one-off data migration, or a proof-of-concept. The development time for an LLM-based extractor is often hours, versus days or weeks for a complex custom parser.
  3. Complex, Semantic Data: The data you need to extract is defined by its meaning, not its format. For example, extracting the “primary complaint” from a user review or the “key objection” from a sales call transcript. Regex cannot capture intent.
  4. “Good Enough” is Sufficient: The application can tolerate a small error rate (e.g., 1 to 5 percent), or there is a human-in-the-loop to review and correct errors. The goal is automation and efficiency, not 100 percent perfection.

When to Use Hand-Written Parsers

  1. Well-Defined, Stable Formats: The input is a machine-generated, standardized format like JSON, XML, CSV[14], or a fixed-width text file. Using an LLM for this is slow, expensive, and unnecessary. A dedicated library parser will be orders of magnitude more efficient.
  2. Extreme Performance and Throughput: Your system needs to process thousands of documents per second with sub-millisecond latency. A call to an LLM API can take from 500 milliseconds to several seconds. A compiled regex or a local parser operates in microseconds.
  3. 100 Percent Accuracy is Non-Negotiable: The system handles mission-critical financial transactions, medical data, or other information where a single error has severe consequences. Hand-written parsers are deterministic: for a given input, they produce the same output every time. LLMs are probabilistic.
  4. Data Sovereignty and Privacy: The data is highly sensitive and cannot be sent to a third-party API for compliance or privacy reasons (e.g., GDPR[15], HIPAA[16]). While you can run open-source models on your own infrastructure, this involves significant operational overhead compared to using a simple, local parsing library.

A Mental Model for Cost

The Total Cost of Ownership (TCO) is a useful lens.

  • Parser TCO = (High Initial Dev Time + High Maintenance Dev Time) * Dev Rate + Very Low Runtime Cost.
  • LLM TCO = (Low Initial Dev Time) * Dev Rate + (API Cost Per Token * Volume) + Latency Cost.

For low-volume, high-variability tasks, the LLM approach is almost always cheaper. For high-volume, stable-format tasks, the parser is cheaper. The decision hinges on where your specific use case falls on that spectrum.

Correcting Common Misconceptions

Several myths persist about this technology that can lead to poor decisions.

Myth: It's just a fuzzy regular expression.
Correction: This is incorrect. Regex operates on character patterns. LLMs operate on semantic meaning captured in vector embeddings. An LLM understands that “due by” and “payment date” are related concepts, something regex has no capacity to do.

Myth: You just ask for JSON and hope for the best.
Correction: Early, naive approaches did this. Modern, reliable extraction uses constrained generation through function calling or tool use. The API guarantees the output structure is valid and conforms to your schema. The model's job is only to fill in the values, which it does with high but not perfect accuracy.

Myth: It's too unreliable for production.
Correction: This depends on the production system. For a core banking transaction system, it is absolutely too unreliable. For an internal tool that summarizes customer feedback for a product manager, it's often more than reliable enough and provides immense value by automating a previously manual task.

Myth: You need to fine-tune a model for good performance.
Correction: For structured data extraction, prompt engineering is almost always more effective and cost-efficient than fine-tuning[17]. Providing a clear schema, good instructions, and a few examples in the prompt (few-shot learning) will typically yield excellent results. Fine-tuning is better suited for teaching a model a new skill, style, or a deep body of new knowledge, not for enforcing an output format.

The State of the Art and What's Next

This statement is outdated. The article is being reviewed in October 2026. The state of the art in LLMs has advanced significantly since 2024, with newer models like GPT-6, Claude 5.5, Llama 4, and others now leading the field. OpenAI's function calling API set a de facto standard, which has been influential. This list of models is outdated for late 2026. While these models were state-of-the-art in 2024, newer generations have been released. As of October 2026, leading models include OpenAI's GPT-6 series, Anthropic's Claude 5.5 series, Meta's Llama 4, and Google's Gemini 3/4. These newer models represent the current state of the art.

Libraries like instructor in Python have emerged to make this process even cleaner, tightly integrating Pydantic schema validation with LLM calls into a single, elegant workflow. These tools handle the boilerplate of API calls, retries, and validation, letting developers focus on defining the data they need.

The future points toward even more capable systems. Multimodal models are beginning to extract structured data directly from images, such as reading an invoice from a photo without a separate OCR step. Additionally, the concept of LLM-powered agents will combine extraction with action. An agent could extract an email address from a support ticket, validate its existence in a CRM via an API call, and then draft a reply, orchestrating multiple tools to complete a workflow. While the classic parser will always have its place for well-defined, high-performance tasks, the trajectory shows that for the vast, messy world of unstructured text, LLM-based extraction is becoming an essential and powerful engineering primitive.

Sources (17)
  1. Regular expression - Wikipedia
  2. JSON
  3. Beautiful Soup Documentation
  4. JSDOM
  5. HTML Standard
  6. Extensible Markup Language (XML) 1.0 (Fifth Edition)
  7. JSON Schema
  8. Byte-pair encoding - Wikipedia
  9. Transformer (machine learning model) - Wikipedia
  10. Attention Is All You Need
  11. Function calling | OpenAI
  12. Function calling with Gemini models | Google Cloud
  13. Pydantic
  14. Common Format and MIME Type for Comma-Separated Values (CSV) Files
  15. General Data Protection Regulation (GDPR)
  16. Health Insurance Portability and Accountability Act of 1996 (HIPAA)
  17. Fine-tuning | OpenAI

Recommended reading

Context Windows: What They Cost and How to Use Them Well13 min readA context window is the measure of text an AI model can consider at once to process a request and generate a response. Understanding its technical mechanisms, costs, and failure modes is critical for making sound engineering decisions about when to use large contexts versus alternative architectures like RAG.Building LLM-Powered ETL Pipelines: Beyond Simple Text Processing11 min readHow we built an AI-powered data extraction system that transforms unstructured documents into structured data with 95% accuracy, and the architectural decisions that made it scalable.How to Evaluate a RAG Pipeline12 min readA comprehensive guide for technical leaders on evaluating Retrieval-Augmented Generation (RAG) systems, covering component-wise metrics, end-to-end testing, failure modes, and the strategic tradeoffs involved.Web Scraping vs Web Crawling: What Is the Difference13 min readWeb crawling and web scraping are often confused, but they serve fundamentally different purposes: crawling is a broad search for URLs to index the web, while scraping is a targeted extraction of specific data from a known set of pages.How Attention Works in Large Language Models13 min readA technical explanation of the attention mechanism in LLMs, from its conceptual origins to the mathematical details of Scaled Dot-Product Attention and its practical implications for engineering leaders.Can I Just Use ChatGPT to Scrape a Website?7 min readCan ChatGPT scrape a website? For one page maybe, but here is why it breaks at real scale and where AI genuinely earns its keep in a data pipeline.