Declarative tools like DSPy and BAML compile prompts from a signature plus a metric; imperative tools like LangChain and LlamaIndex execute the prompts and steps the developer wrote.
Picture two cooks asked to make the perfect omelet. The first cook writes the recipe themselves, three eggs, this much butter, sixty seconds on each side, and follows it exactly. If the omelet is bad, they edit the recipe and try again. The second cook only writes down what counts as a great omelet and hands a robot a basket of eggs. The robot tries hundreds of recipes, keeps the ones the judge liked best, and serves the winner. Cook one knows every detail of how the omelet was made. Cook two never sees the recipe but the omelet usually scores higher. Different tradeoffs, both valid.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
The declarative versus imperative split is the most useful single axis for thinking about LLM frameworks in 2026. It cuts cleaner than the popular tribal lines, LangChain versus LlamaIndex, Python versus TypeScript, agents versus chains, because it names what the developer's artifact actually is.
This deep dive walks through what each family asks of the developer, what each one produces, where the tradeoffs land, and why most serious production systems end up using both at different layers of the stack.
The imperative side: you write the prompt
LangChain and LlamaIndex are imperative frameworks. The developer authors the prompt text, decides what to put in the context window, picks the chain steps, and wires them together with explicit code. The framework provides composition primitives, LCEL's pipe operator, LlamaIndex's QueryEngine, and execution machinery. It does not change what the model sees.
What this looks like in code
In LangChain you write ChatPromptTemplate.from_messages([('system', '...'), ('human', '{query}')]), you wire it into a chain with prompt | model | parser, and what runs is exactly what you wrote. A traced run shows the literal text sent to the model on each call.
What you get from this
The imperative side wins on three things. First, debuggability: every prompt is a string you can read in source, every step is a node in a trace. Second, control: you can branch on any signal at any point because the orchestration is your code. Third, novelty handling: when a task is brand new and you do not know what good looks like yet, the ability to iterate on prompts directly is faster than setting up a metric and an optimizer.
What you give up
The imperative side does not optimize prompts for you. Every improvement is a human edit. The prompt that ships is the prompt the developer typed; if a slightly different phrasing scores 15 percent better on the eval set, the developer has to find that phrasing manually.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
| Axis | Imperative (LangChain, LlamaIndex) | Declarative (DSPy, BAML) |
|---|---|---|
| What developer writes | Prompts plus chain code | Signature or schema plus metric |
| What model receives | What the developer wrote | What the compiler generated |
| Optimization | Manual prompt iteration | Automatic search against a metric or codegen from schema |
| Debuggability | Every step visible | Final prompt is a compiler artifact |
| Best fit | Moving target, no labels, deep custom control | Stable task, labeled data, want prompt to keep improving |
Real products, models, and research that use this idea.
- DSPy 2.6 ships MIPROv2 as the default optimizer, used in production by Databricks and several Anthropic-customer pipelines.
- BAML is used by Vercel and Notion-style teams that want schema-first LLM calls with TypeScript codegen.
What an interviewer would ask next. Try answering before peeking at the approach.
QWalk through how DSPy's MIPROv2 optimizer actually searches the prompt space.
It uses a teacher-student bootstrapping loop: a stronger model proposes candidate instructions and exemplars, the metric scores each candidate against the labeled set, Bayesian-style search narrows toward high scorers; the output is the prompt the cheaper model will run at inference.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Treating DSPy as just another chain builder, then being confused that you never get to write the actual prompt text the model sees.
60 second bullets to scan on the way to the call.
What a DSPy Signature contains and how it differs from a prompt template
What BAML codegen produces and at which point in the build pipeline
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.