Building Production LLM Applications with DSPy Framework

alixpartners · Consulting · 2026 · source Agentic: yes · promotional bias: med · source-backed · extracted with prompt 0.5.5 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Production LLM application development with DSPy programs, document workflows, tool calling, and prompt optimization

AlixPartners needed a way to build many different LLM applications as maintainable Python programs rather than hand-tuned prompt strings, while preserving structured outputs, tool use, model transferability, observability, and optimization across consulting use cases such as contract analysis, file routing, multimodal document processing, web research, and time-entry correction.

Constraints:

Architecture

The architecture centers LLM applications as DSPy programs. Signatures declare typed inputs and outputs; modules compose signatures with Python business logic; tools expose ordinary Python functions to React-style agents; adapters translate signatures into model-facing prompt formats; model configuration and context managers route calls to different LLMs; caching and LiteLLM usage tracking reduce iteration cost; Phoenix and inspect-history tracing expose prompts, responses, tool trajectories, and token usage; and optimizers use metrics and datasets to compile improved DSPy modules. The workshop applies those primitives to sentiment classification, SEC Form 4 processing, contract summarization and boundary detection, multimodal file classification, web-research agents, and time-entry correction.

Diagram confidence: reconstructed (reconstructed from prose).

flowchart LR
  application-use-case[Application use case] --> dspy-signature[DSPy signature]
  dspy-signature --> dspy-module[DSPy module]
  dspy-signature --> adapter[Adapter]
  dspy-module --> tool-functions[Tool functions]
  dspy-module --> model-configuration[Model configuration]
  attachments-processor[Attachments processor] --> dspy-signature
  adapter --> llm-runtime[LLM runtime]
  model-configuration --> llm-runtime
  llm-runtime --> cache[Cache]
  llm-runtime --> observability-stack[Observability stack]
  tool-functions --> trajectory-inspector[Trajectory inspector]
  observability-stack --> trajectory-inspector
  observability-stack --> evaluation-metrics[Evaluation metrics]
  evaluation-metrics --> optimizer[Optimizer]
  optimizer --> dspy-module
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Application use case The business task such as contract review, SEC filing extraction, file classification, time-entry correction, or web research. DSPy signature
DSPy signature Declarative contract for input fields, output fields, field names, Pydantic types, and task intent. DSPy module, Adapter
DSPy module Composable Python abstraction that wraps signatures, model calls, deterministic logic, and built-in modules such as Predict or React. Tool functions, Model configuration, Optimizer
Adapter Prompt formatter that turns signatures and inputs into model-facing formats such as JSON, XML, or BAML. LLM runtime
Tool functions Ordinary Python functions made available to the LLM through DSPy React-style tool calling. DSPy module, Trajectory inspector
Attachments processor Normalizes PDFs, images, markdown, OCR text, and other file inputs into LLM-usable representations. DSPy signature
Model configuration Defines regular, small, and multimodal model choices and switches models for specific workloads. LLM runtime
LLM runtime LiteLLM-backed model execution layer that sends prompts, receives responses, tracks usage, and supports caching. Cache, Observability stack
Cache Reuses unchanged signature/input calls during development and testing instead of repeatedly calling the model. LLM runtime
Observability stack Phoenix, inspect-history, usage tracking, and trajectory inspection for model calls, prompts, responses, tools, and token usage. Trajectory inspector, Evaluation metrics
Trajectory inspector Debug view for React calls showing tool invocations, arguments, observations, and reasoning-like trajectories. —
Evaluation metrics Success functions and LLM-as-judge checks used to measure and optimize DSPy programs. Optimizer
Optimizer MIPRO/JEPA-style optimizer that compiles a better DSPy module by iteratively improving prompts against data and metrics. DSPy module

Data flow

A developer expresses the task as a DSPy signature, optionally backed by Pydantic types and field descriptions. A module wraps the signature and any deterministic business logic, then invokes a DSPy primitive such as Predict, ChainOfThought, or React. Adapters render the signature and runtime inputs into the prompt format required by the selected model. Tools are supplied as Python functions when the React module needs external actions. Inputs such as PDFs or images are normalized through Attachments before entering the signature. DSPy dispatches model calls through LiteLLM, records usage, caches unchanged calls, and exposes execution history and trajectories for debugging. For optimization runs, examples and metrics drive algorithms such as MIPRO/JEPA to produce a compiled module that can be saved, loaded, and reused.

8 supporting quotes
“thing for me personally DSP is a really nice way to decompose your logic into a program that treats LLMs as a first class citizen. So at the end of the day, you're fundamentally just calling a function that under the hood just happens to be an LLM and DSPI gives you a really nice intuitive”transcript, stated
“signatures specify what you want the L what basically what you want your function call to do. This is when you specify your inputs, your outputs.”transcript, stated
“Modules themselves are ways to logically structure your program. They're based off of signatures. So, a module can have one or more signatures embedded within it in addition to uh additional logic. and it's based off of um pietorrch and some of the in terms”transcript, stated
“tools fundamentally as DSPI looks at them are just Python functions. So it's just a way for you to very easily expose Python functions to the LLM”transcript, stated
“adapters are the things that sit in between those two. So, it's how you translate your inputs and outputs into a format”transcript, stated
“it pulled out um PDF plumber. It created markdown from it. Pulled out the images, etc. Again, I don't have to worry about all that.”transcript, stated
“part or or useful part about DSPI comes with a bunch of usage information built in. So um because it's cached, it's going to be an empty object. But when I change it, you can see that I'm using Azure right now, but for each call, you get this nice breakdown. and I”transcript, stated
“for each call, you get this nice breakdown. and I think it's from late LLM, but allows you to very easily track your usage, token usage, etc.”transcript, stated

Why this architecture

The framework-based architecture was chosen because the presenter wants stable program structure, explicit typed contracts, model interchangeability, and quantitative optimization rather than ad hoc prompt editing. DSPy's level of abstraction lets developers keep Python control flow and business logic visible while still letting LLMs fill the semantic steps.

5 supporting quotes
“Most importantly building programs. It's not um it's not kind of iterating with prompts and tweaking things back and forth.”transcript, stated
“allows you to focus on things that actually matter. So you're not writing choices zero messages content. You're not you're not doing string parser. You're not doing a bunch of stuff under the hood. You're just declaring your intent of how you want the”transcript, stated
“retains the control flow uh retains the intent of your system, your program um while allowing you to bounce from model to model”transcript, stated
“you can still understand what's going on under the hood. If you want to, you can go in and tweak things, but it allows you to to kind of focus on just what you want to do while retaining the level of precision that you that I think most of us would like to”transcript, stated
“DSPI gives you the primitives that you need and the organization you need to be able to measure and then quantitatively improve that performance.”transcript, stated

Models used: DSPy · LiteLLM · GPT-4.1 · GPT-4.1 nano · GPT-4.1 mini · Gemini 2.5 Flash · Phoenix · Attachments · Pydantic · MIPRO optimizer · JEPA optimizer

Scale

Alternatives considered (roads not taken)

Ad hoc prompt editing instead of a DSPy program

Rejected because: The presenter explicitly frames the goal as building real Python programs with LLM calls, not iterating on prompt strings.

“Most importantly building programs. It's not um it's not kind of iterating with prompts and tweaking things back and forth.”transcript, stated

Using LangChain as the primary abstraction

Rejected because: The presenter says DSPy sits at a level of abstraction that gets in the way less for his use cases, while acknowledging other libraries can still be good choices.

“it's I I would say it doesn't get in your way as much as a lang chain. And that's not a knock-on lang chain. It's just a different kind of paradigm”transcript, stated

Fine-tuning before prompt optimization

Rejected because: The talk recommends trying DSPy optimizers first because they can improve performance without fine-tuning infrastructure.

“whether you want to go fine-tune and do all of that, nothing stops you. But I would recommend at least trying this first to see how far you can get”transcript, stated

Always using one model for all workloads

Rejected because: The file-processing example routes images to Gemini and other work to GPT-style models based on workload fit.

“Gemini models might be better at image recognition than others. So I might want to defer or use a particular model for a particular workload.”transcript, stated

A fully autonomous file classifier for production

Rejected because: The presenter marks the workshop example as quick-and-dirty and says a production use case would need stronger or multiple classification passes.

“In some type of production use case, you would want much more stringent or maybe even multiple passes of classification, maybe using different models”transcript, stated

Patterns

structured-output-contract (interface-contract)

DSPy signatures and Pydantic output types define the semantic contract for model calls, including field names, field descriptions, typed outputs, and literal choices.

“the names of the fields themselves act almost as like mini prompts. It's part of the prompt itself.”transcript, stated
“because DSPI works on Pyantic, I can define the answer as a literal. So I'm basically forcing it to only give me those three options”transcript, stated

tool-use-orchestration (agent-control)

DSPy React modules expose Python functions as tools, cap the number of rounds, and expose trajectories so developers can inspect tool arguments and observations.

“So, it's wrapping and doing some things under the hood with um basically taking your signatures and uh it's injecting the Python functions that you've given it as tools and basically React is how you do tool calling in DSP. Program with thought is uh is pretty cool.”transcript, stated
“you can get a trajectory back for things like react. So you can see what tools it's calling the arguments that are passed in”transcript, stated

model-routing (runtime-routing)

The file-processing program defines regular, small, and image-oriented model configurations, then routes specific workloads such as image recognition or Form 4 extraction to different models.

“we're setting the regular LM, the small and one we use for an image.”transcript, stated
“So if I detect an image, I will route the request to Gemini. If I detect something else, I'll route it to a 4.1 or whatever it might be.”transcript, stated

semantic-caching (cost-control)

DSPy automatically reuses results when signatures and inputs have not changed, speeding local testing and avoiding unnecessary live calls.

“DSP has caching automated under the hood. So as long as nothing has changed in terms of your uh your signature definitions”transcript, stated
“U but that's another kind of super useful um piece here. Let's see. Okay. Make sure we're up and running. So, if I change this to hello with a space, you can see we're making a live call.”transcript, stated

observability-tracing (operations)

Phoenix, inspect-history, token usage, and trajectory inspection provide visibility into prompts, responses, model usage, tool calls, and optimizer behavior.

“I'll set up Phoenix, which is from Arise, uh, which is basically an obser an observability platform.”transcript, stated
“inspect history will give you the raw dump of what's actually going on. So you can see here the system message”transcript, stated

eval-driven-development (optimization)

The optimizer workflow depends on explicit metrics and example data, then reports metric-level performance so teams can decide whether to adjust the metric or improve the program/data.

“You use your metrics to define basically the contours of how the program works and you optimize all that”transcript, stated
“this can be really telling as to whether you need to tweak your metric, maybe you need to decompose your metric”transcript, stated

cost-aware-routing (runtime-economics)

The talk uses DSPy optimization and model transfer as a cost-control tactic: move work to a smaller model, recover quality through optimization, and keep the program structure stable.

“maybe it's at 70% whatever it might be. But I run the optimizer on 41 nano and I can get the performance back up to maybe 87%.”transcript, stated
“I've now just dropped my cross my cost profile by multiple orders of magnitude.”transcript, stated

fine-tuning-adaptation (model-adaptation)

The talk positions prompt optimization as a lighter-weight adaptation path to try before fine-tuning, especially when teams want performance gains without fine-tuning infrastructure.

“It's been some research um that argues I think that it's just as performant if not in cert in certain situations more performant than fine-tuning”transcript, stated
“See how the optimizers work. Um, but fundamentally what it allows you to do is DSPI gives you the primitives that you need and the organization you need to be able to measure and then quantitatively improve that performance.”transcript, stated

Tradeoffs

Represent LLM behavior as DSPy signatures and modules

Chose Declarative typed programs with composable modules over Hand-written prompt strings and direct response parsing.

Rationale: The presenter values program structure, typed input/output guarantees, and transferability across model changes more than low-level control over every prompt string.

“You are building a program first. It just happens to also use LLMs.”transcript, stated
“retains the control flow uh retains the intent of your system, your program um while allowing you to bounce from model to model”transcript, stated

Use adapters to vary prompt format

Chose Swappable JSON/BAML/XML-style adapters over One fixed prompt rendering format.

Rationale: Adapters let the same program experiment with more readable or token-efficient formats that may improve performance without rewriting the business logic.

“you can format things differently. The the rest of the program wouldn't have changed at all.”transcript, stated
“can actually improve performance by you know five to 10 percent depending on your use case.”transcript, stated

Try prompt optimization before fine-tuning

Chose DSPy optimizers and metrics over Immediately setting up fine-tuning infrastructure.

Rationale: Optimization can recover acceptable performance on cheaper models while avoiding the operational overhead of fine-tuning.

“I would recommend at least trying this first to see how far you can get without having to set up a bunch of infrastructure”transcript, stated
“maybe it's at 70% whatever it might be. But I run the optimizer on 41 nano and I can get the performance back up to maybe 87%.”transcript, stated

Route workloads to specialized models

Chose Different model configurations for regular, small, and image-heavy work over A single global model configuration for all tasks.

Rationale: The examples use smaller models for some structured work and Gemini for image recognition, suggesting model choice should follow task requirements.

“we're setting the regular LM, the small and one we use for an image.”transcript, stated
“Gemini models might be better at image recognition than others. So I might want to defer or use a particular model for a particular workload.”transcript, stated

Mix LLM calls with deterministic Python business logic

Chose Custom modules that interleave model predictions and hard-coded rules over Pure prompt-only applications.

Rationale: DSPy modules can encapsulate LLM calls while still allowing normal Python control flow and business rules where determinism is appropriate.

“you can inter basically intersperse the LLM call which would be the first one and then do some kind of hard-coded business logic beneath it.”transcript, stated
“This was one way to to kind of do that very elegantly, at least in my opinion”transcript, stated

Gotchas (what bit them)

DSPy can look deceptively simple while hiding prompt-shaping details inside field names and adapters.

Root cause: The same typed Python fields that make signatures ergonomic also become part of the prompt, so naming and descriptions still matter.

Resolution: Treat signatures as both code contracts and prompt surfaces; inspect the generated prompt history when behavior is surprising.

“the names of the fields themselves act almost as like mini prompts. It's part of the prompt itself.”transcript, stated
“inspect history will give you the raw dump of what's actually going on.”transcript, stated

Workshop-grade examples are not automatically production-grade systems.

Root cause: The examples are deliberately quick demonstrations with small category sets and obvious files.

Resolution: Add more stringent or multi-pass classification and production checks before applying the same pipeline to ambiguous real-world inputs.

“In some type of production use case, you would want much more stringent or maybe even multiple passes of classification, maybe using different models”transcript, stated
“I mean this is more just like a workshop quick and dirty example. It's only because there's one picture of the street signs.”transcript, stated

Optimization quality depends on examples and metrics, not on the optimizer alone.

Root cause: Optimizers optimize against the provided metric and dataset; poor metrics or low-quality data can steer the compiled prompt toward the wrong behavior.

Resolution: Invest in well-structured input/output examples and inspect metric-level breakdowns to decide whether metrics should be decomposed or changed.

3 supporting quotes
“So for the machine learning folks in the room, which is probably everybody, obviously the quality of your of your data is very important, um you don't need thousands and thousands of examples necessarily, but as long as you have enough, maybe 10 to 100 of inputs and outputs.”transcript, stated
“if you're constructing your metrics in a way that is relatively intuitive and and that, you know, accurately describes what you're trying to achieve”transcript, stated
“as to whether you need to tweak your metric, maybe you need to decompose your metric”transcript, stated

Tool-calling agents can spin beyond the intended scope without explicit bounds.

Root cause: React-style agents are given tools and allowed to act, so the developer needs to set operational limits.

Resolution: Bound the loop explicitly, as in the example that allows only five rounds, and inspect trajectories for unexpected tool use.

“only go five rounds just so it doesn't spin off and do something crazy.”transcript, stated
“you can see what tools it's calling the arguments that are passed in um and the observations for each of those calls”transcript, stated

Framework abstraction can obscure whether a problem really needs DSPy or a simpler structured-output call.

Root cause: DSPy does enforce structured output, but the presenter notes that calling it only structured outputs is reductive and that alternatives can solve similar tasks.

Resolution: Use DSPy when composability, model routing, optimization, tool orchestration, and program structure matter; simpler structured-output APIs may suffice for narrow calls.

“I mean yes, I think that's probably reductive of of like its full potential, but generally that's that's correct.”transcript, stated
“there are absolutely other great libraries out there. Pedantic AI, Langchain, there's many many others that allow you to do similar things.”transcript, stated

Evaluation

The workshop evaluates DSPy programs by defining task-specific metrics, running optimizers against example inputs/outputs, inspecting before/after performance, breaking results down by metric, and using observability tools such as inspect-history, token usage, Phoenix traces, and React trajectories to understand behavior.

Metrics: Optimization performance before and after MIPRO/JEPA runs · Metric-level breakdowns for capitalization, punctuation, and formatting requirements in the time-entry example · Tool trajectory inspection for React calls · Prompt/response inspection through DSPy inspect-history · Token usage tracking from LiteLLM · Cache hit behavior during repeated development runs

5 supporting quotes
“You use your metrics to define basically the contours of how the program works and you optimize all that”transcript, stated
“went from 86 to 89. And then interestingly, this is still in development, this one in particular, but you can break it down by metric.”transcript, stated
“inspect history will give you the raw dump of what's actually going on. So you can see here the system message”transcript, stated
“you can get a trajectory back for things like react. So you can see what tools it's calling the arguments that are passed in”transcript, stated
“for each call, you get this nice breakdown. and I think it's from late LLM, but allows you to very easily track your usage, token usage, etc.”transcript, stated

Outcomes

The talk is a workshop rather than a deployed product case, but it contains concrete scale signals: 10,000-contract search, hundreds of thousands of time entries, five-round tool-call bounds, 10-100 optimization examples, a 13-page contract boundary demo, and optimization results from 86 to 89 or 70% to 87%.

5 supporting quotes
“DSPI has been a really nice way for me personally and my team to iterate really really quickly on building these applications.”transcript, stated
“is it an SEC filing is it a patent filing is the contract city infrastructure pretty different things”transcript, stated
“it said the main document was from page 0 to six and the way and so we zero 1 2 3 4 5 six seems reasonable.”transcript, stated
“In this case, went from 86 to 89. And then interestingly, this is still in development, this one in particular, but you can break it down by metric.”transcript, stated
“I can get the performance back up to maybe 87%. maybe that's okay for my use case, but I've now just dropped my cross my cost profile by multiple orders of magnitude.”transcript, stated