In our last lesson, you learned to wield the fundamental parameters that control a large language model's output—managing creativity with temperature and length with max_tokens. You now have the skills to shape the general character of a model's response. However, for building robust AI agents that connect to other software, "general character" isn't enough. We need precision and reliability.
This lesson addresses that need directly. We will focus on how to get reliable, machine-readable data from an LLM by enforcing a structured output format. You will learn to move beyond simply asking for JSON in a prompt and instead use the dedicated API features of modern models to guarantee a valid, parsable response. For you as a TypeScript developer, this is the key to creating type-safe, predictable interactions between LLMs and the rest of your application stack, a cornerstone of production-grade agent engineering.
From Brittle Parsing to Guaranteed Structure
When you need an LLM to provide data for your application—say, extracting contact information from an email or categorizing a user's request—your code needs that data in a predictable format. For years, the standard approach was to instruct the model in the prompt: "Please respond with a JSON object containing the fields 'name', 'email', and 'category'."
This often works, but it's fundamentally unreliable. The model might:
- Produce invalid JSON (e.g., a trailing comma).
- Add conversational text before or after the JSON block ("Sure, here is the JSON you requested:...").
- Omit a field or invent a new one.
This forces you, the developer, into a defensive loop of string manipulation, regular expressions, and complex try-catch blocks just to safely parse the model's output. This is brittle, error-prone, and a major source of bugs in AI applications.
Modern LLM APIs provide a much better solution: API-enforced structured output. The flowchart below contrasts these two approaches.

Today, we're focusing entirely on the robust path on the right. By providing a formal schema to the API, you offload the responsibility of generating syntactically correct JSON to the model provider, who can enforce it at a much lower level.
Defining Structure with Zod and JSON Schema
To tell the model what structure you expect, you need a way to define that structure. The industry standard for this is JSON Schema. While you can write these schemas by hand, the experience is far better when integrated with a validation library you're already familiar with. For the TypeScript ecosystem, the perfect tool for this is Zod.
With Zod, you can define your desired data structure once, and then use it for both generating the JSON Schema for the LLM and for parsing/validating the LLM's response in your code. This creates a seamless, type-safe workflow.
Let's see how this works in practice with a real-world example: extracting a recipe from a block of text.
Structured outputs | Gemini API - Google AI for Developers
This official documentation from Google provides an excellent, hands-on JavaScript example of using Zod to define a schema and instruct the Gemini model to return a JSON object that matches it.
Focus on the JavaScript example. First, examine how the recipeSchema is defined using Zod. Notice the use of nested objects, arrays, optional fields, and the .describe() method to provide hints to the model. Next, look at the API call configuration. See how the zodToJsonSchema utility converts the Zod object into a format the API understands, which is then passed in the responseFormat parameter. Finally, observe the last line, recipeSchema.parse. This is the crucial step that validates the model's output against your original Zod schema, ensuring type safety and catching any deviations.
The workflow you just studied is a powerful pattern you will use constantly when building agents:
- Define Schema with Zod: Create a Zod schema that represents the exact data structure your application needs. Use
.describe()to give the LLM clear instructions on what each field means. - Convert to JSON Schema: Use a utility like
zod-to-json-schemato translate your Zod schema into the standard JSON Schema format. - Configure API Call: Pass the generated JSON Schema to the LLM API using the appropriate parameter (
response_formatorresponseFormatfor OpenAI/Gemini, or theoutputSchemain some SDKs). - Parse and Validate: Take the resulting text response from the LLM, use
JSON.parse()to turn it into a JavaScript object, and then use your original Zod schema's.parse()method to validate it. If it passes, you have a fully-typed object ready to use.
Structured Outputs Across Different Providers
While the concept is universal, the exact implementation can vary slightly between models and SDKs. The Google example used their @google/genai package. Let's look at how this concept applies in the context of OpenAI's tools.
OpenAI's New TypeScript Agents SDK
This video from Developers Digest showcases OpenAI's TypeScript Agents SDK, which has first-class support for structured outputs. It provides a great conceptual overview of the benefits.
Watch the segment from the introduction to structured outputs. Pay close attention to the speaker's point at 9:16, where he clarifies a critical nuance: the API guarantees the schema (the structure and types of the fields), but it does not guarantee the factual accuracy of the values. The model can still hallucinate a value for a field, but the field itself will exist and have the correct type.
This distinction is vital for building production systems. Structured output solves the parsing and validation problem, but it does not solve the fact-checking problem. You can rely on response.price being a number, but you cannot blindly trust that it's the correct price without further verification, perhaps using a tool.
The Ultimate Pattern: Tools + Structured Output
This brings us to one of the most powerful patterns in agent development: combining tool use with structured output. An agent can use a tool (like a web search or an API call) to fetch raw, unstructured information and then use a second LLM call with a structured output schema to parse that raw information into clean, usable data.
Let's see this in action.
OpenAI's New TypeScript Agents SDK
The same video demonstrates this advanced pattern by building a simple research agent.
Watch the section from structured outputs with tools. The agent performs a web search using the Firecrawl tool, which returns a large amount of raw text from multiple web pages. It then feeds this text into another LLM call, this time with a researchAnalysisSchema, instructing the model to synthesize the raw text into a structured JSON object with key findings, sources, and trends.
This two-step process—gather then synthesize—is a fundamental building block for creating capable agents that can interact with the messy, unstructured world and turn it into the structured data your applications require.
A Quick Clarification: Structured Output vs. Function Calling
As you dive deeper, you'll encounter two terms that seem similar: Structured Output and Function Calling (also known as Tool Calling). Both use JSON schemas, but they serve different purposes. It's crucial to understand the difference.
| Feature | Primary Use Case | Analogy |
|---|---|---|
| Structured Output | To format the final response to the user. | You ask an assistant for a report, and you demand it be delivered in a three-ring binder with specific tabbed sections. |
| Function Calling | For the model to request an action during a conversation. | You ask an assistant for a report, and they reply, "I need to make a phone call to get the latest sales figures. Is that okay?" |
We will dedicate Module 3 entirely to Function Calling, but for now, just remember: use structured output when you want the model's answer to be in a specific JSON format.
Conclusion
You have now bridged the gap between a model's free-form text generation and your application's need for structured, reliable data. This is a transformative step in moving from basic LLM prompting to engineering robust AI agents.
Your key takeaways are:
- Prompt-based JSON is brittle: Relying on prompt instructions alone to get JSON leads to parsing errors and requires extensive defensive coding.
- API-enforced output is robust: Using features like JSON mode or response schemas with a JSON Schema definition guarantees a syntactically valid JSON output.
- Zod enables type-safe workflows: Defining structures with Zod in TypeScript allows you to generate a schema for the LLM and validate its response with a single source of truth.
- Structure is guaranteed, values are not: The model will adhere to your schema, but it can still hallucinate the data within that schema.
- Structured output formats the final answer: It's distinct from function calling, which is used when the model needs to invoke a tool to gather more information before it can formulate a final answer.
In the next module, we'll shift our focus from the output of the LLM to its input and reasoning process. You'll learn advanced prompt engineering techniques to define an agent's persona, guide its thinking with examples, and improve its ability to tackle complex tasks. This, combined with your new ability to get structured data, will prepare you to build truly sophisticated agents.