← Back to DevBytes

How to Parse Unstructured LLM Outputs Safely

How to Parse Unstructured LLM Outputs Safely

Large Language Models (LLMs) are incredibly powerful at generating human-like text, but they are inherently non-deterministic. When building applications that rely on LLMs, you often need their output in a machine-readable format like JSON. However, LLMs frequently wrap their responses in conversational filler, markdown code blocks, or deviate from the requested schema entirely. Safely parsing this unstructured output is a critical skill for any AI developer.

What is Unstructured LLM Output?

Unstructured LLM output refers to any response generated by a language model that does not strictly conform to a predefined, machine-readable format. Even when you explicitly ask an LLM to "return only JSON," it might return something like this:

Sure, here is the JSON you requested:

json
{
  "name": "John Doe",
  "age": 30
}
Let me know if you need anything else!

While a human can easily read this, passing this entire string directly into a JSON parser will result in a syntax error. Unstructured outputs can also include hallucinated keys, incorrect data types, or truncated responses due to token limits.

Why Safe Parsing Matters

If your application assumes the LLM will always return perfect JSON, your code will inevitably crash in production. Safe parsing matters for several reasons:

How to Safely Parse LLM Outputs

To safely parse LLM outputs, you should use a multi-layered approach. This involves prompting the model correctly, utilizing native API features, and implementing robust fallback parsing logic in your code.

1. Leverage Native JSON Modes

Many modern LLM providers (like OpenAI and Anthropic) offer native JSON modes or structured output features. When enabled, the API guarantees that the output will be valid JSON. Here is an example using the OpenAI Python SDK:

import json
from openai import OpenAI

client = OpenAI(api_key="your-api-key")

response = client.chat.completions.create(
    model="gpt-4o",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "You are a helpful assistant designed to output JSON. Extract the user's name and age."},
        {"role": "user", "content": "My name is Jane and I am 28 years old."}
    ]
)

# Because we used json_object mode, this is generally safe
try:
    parsed_data = json.loads(response.choices[0].message.content)
    print(parsed_data)
except json.JSONDecodeError as e:
    print(f"Failed to parse JSON: {e}")

While native JSON modes guarantee valid JSON syntax, they do not guarantee that the JSON will match your specific schema (e.g., having the exact keys you need). You still need to validate the payload.

2. Implement Fallback Regex Extraction

If you are using an LLM that does not support native JSON modes, or if the model still wraps the JSON in markdown code blocks (json ... ), you need a fallback parser. You can use regular expressions to extract the JSON block from the surrounding text.

import json
import re

def extract_json_from_text(text):
    # Attempt to find JSON wrapped in markdown code blocks
    match = re.search(r"(?:json)?\s*([\s\S]*?)\s*", text)
    if match:
        text = match.group(1)
    
    # Attempt to find raw JSON objects in the text
    match = re.search(r"\{[\s\S]*\}", text)
    if match:
        text = match.group(0)
        
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return None

raw_llm_output = "Here is your data: \njson\n{\"status\": \"success\", \"count\": 42}\n\nThanks!"
parsed_data = extract_json_from_text(raw_llm_output)

if parsed_data:
    print("Successfully parsed:", parsed_data)
else:
    print("Could not extract valid JSON.")

3. Validate with Pydantic

Once you have successfully parsed the JSON string into a Python dictionary, you must validate its structure. Pydantic is the industry standard for data validation in Python. It ensures that the required fields are present and that the data types are correct.

from pydantic import BaseModel, ValidationError

class UserSchema(BaseModel):
    name: str
    age: int

# Assume this came from the LLM parsing step
llm_dict_output = {"name": "Alice", "age": "thirty"}  # Age is a string, which is wrong

try:
    # Pydantic will attempt to coerce "thirty" to an int and fail
    user = UserSchema(**llm_dict_output)
    print("Validated user:", user)
except ValidationError as e:
    print("Schema validation failed:")
    print(e.json())

Best Practices for Robust Parsing

Conclusion

Parsing unstructured LLM outputs safely is the bridge between experimental AI scripts and production-ready applications. By combining native API JSON modes, robust regex fallbacks, and strict schema validation with tools like Pydantic, you can handle the inherent unpredictability of language models. Remember that the goal is not to force the LLM to be perfect, but to build resilient systems that can gracefully handle and recover from its inevitable mistakes.

— Ad —

Google AdSense will appear here after approval

← Back to all articles