"I used to write prompts. Now I write type signatures and let a compiler argue with the language model on my behalf."
A Prompt Engineer Who Learned to Love the Schema
Overview
The previous chapter introduced vibe coding as the practice of steering AI through natural language while a model generates the code. Vibe coding is powerful, but its outputs are fragile: free-form text goes in, free-form text comes out, and any downstream system that consumes the model's response must parse, validate, and hope. This chapter shows how to replace hope with guarantees.
The core idea is simple: treat a language model call not as a chat message, but as a function call with typed inputs and typed outputs. Once you do that, an entire software engineering toolkit becomes available. You can define schemas, validate responses at compile time, compose calls into pipelines, and even optimize prompts automatically by treating them as parameters in a search problem. The journey goes from raw prompts to structured outputs, from structured outputs to typed agent interfaces, and from typed interfaces to compiled programs that optimize their own instructions.
This chapter sits at the pivot point of Part II. Everything before it (Chapters 7 through 9) treats AI as an assistant that generates code for humans to review. Everything after it (Chapters 11 through 24) treats AI as a component in engineered systems. The transition happens here, when prompts become programs.
Prerequisites
You should be comfortable with the foundations from Chapter 4 (reasoning in language models, chain-of-thought prompting) and Chapter 9 (vibe coding workflows and specification practices). Familiarity with Python type hints, dataclasses, and basic API usage (REST, JSON) is assumed. If you have used Pydantic for data validation, Section 10.1 will feel natural; if not, we introduce the essentials from scratch. The Discovery Workbench from Chapter 6 provides the scaffold that this chapter extends with typed agent interfaces.
Learning Outcomes
After completing this chapter, you will be able to:
- Use JSON Schema and structured output modes to guarantee that LLM responses conform to a typed contract.
- Build typed agent interfaces with Pydantic models, function calling, and tool use across the Anthropic and OpenAI SDKs.
- Define DSPy signatures and modules that separate program logic from prompt text.
- Explain prompt optimization as discrete search and apply DSPy optimizers to improve program quality automatically.
- Convert a brittle prompt chain into a compiled, testable DSPy program for a literature discovery task.
Sections
10.1 Structured Outputs and Tool Use
JSON Schema, constrained generation, function calling, and the Model Context Protocol. How to guarantee that every LLM response is machine-readable, composable, and validated at the type level. Typed agent interfaces with Pydantic across the Anthropic SDK, OpenAI Agents SDK, and MCP.
10.2 Programmatic Prompt Optimization
DSPy signatures, predictors, and modules. Prompt optimization as discrete search over instruction space. Compiling prompts with BootstrapFewShot, MIPROv2, and quality metrics. When optimization helps and when it does not.
10.3 Building a DSPy Literature Program
Recipe: convert a brittle prompt chain into a typed, compiled DSPy program that retrieves papers, extracts claims, and synthesizes findings. Integration with the Discovery Workbench, evaluation, and deployment patterns.
What's Next
The next bottleneck is what the model sees. Chapter 11: Context Engineering at Repository Scale tackles the problem of assembling the right context window for large codebases and scientific corpora. You will learn retrieval strategies, chunking, reranking, and the art of fitting a million-line repository into a hundred-thousand-token window, using the typed interfaces from this chapter as the plumbing that connects retrieval to generation.
Bibliography
Foundational Papers
The foundational DSPy paper. Introduces signatures, modules, teleprompters (optimizers), and the idea that prompt engineering should be replaced by prompt compilation. Core reading for Sections 10.2 and 10.3.
Introduces MIPROv2, DSPy's second-generation optimizer that jointly searches over instructions and demonstrations using Bayesian surrogate models. The optimizer of choice for production DSPy programs.
Demonstrates self-supervised tool-use learning, where models decide when and how to call external APIs. Conceptual ancestor of structured function calling.
Tools and Libraries
The de facto standard for runtime data validation in Python. Used throughout this chapter for defining structured output schemas and agent interfaces.
Official reference for structured outputs and tool use with Claude. Covers JSON Schema constraints, tool definitions, and multi-turn tool-use patterns.
Introduces the OpenAI Agents SDK with typed tool definitions, handoffs, and guardrails. Reference for the multi-SDK comparison in Section 10.1.
The open standard for connecting LLMs to external tools and data sources. Section 10.1 shows how MCP tool schemas map onto structured function calling.
Official DSPy documentation and tutorials. The primary reference for the programming model in Sections 10.2 and 10.3.
Tutorials and Guides
The official tutorial for JSON Schema, the constraint language underlying structured outputs in every major LLM API.
Comprehensive survey of LLM agent architectures, covering tool use, planning, memory, and multi-agent coordination. Provides the broader context for the typed agent interfaces built in this chapter.
Extends DSPy with runtime assertions that constrain LLM outputs programmatically. Shows how to build self-correcting pipelines that retry on constraint violations.