Zenaique

What is the core difference between declarative frameworks (DSPy, BAML) and imperative ones (LangChain, LlamaIndex) in terms of what the developer writes and what the framework produces?

Flashcard·Easy·4.0 · 0·~30s·Asked atDifyInfosysNotion
Attempt it
TL;DR

Declarative tools like DSPy compile prompts from a signature plus a metric, and BAML generates typed clients from a schema; imperative tools like LangChain and LlamaIndex run the prompts the developer wrote.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

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 wrote 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.

The declarative versus imperative split is the most useful single axis for thinking about LLM frameworks. It separates frameworks more cleanly than the usual lines, LangChain versus LlamaIndex, Python versus TypeScript, agents versus chains, because it names what the developer's artifact is.

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.

The declarative side: you write the spec
Why the analogy with SQL matters
How serious teams mix the two
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.
AxisImperative (LangChain, LlamaIndex)Declarative (DSPy, BAML)
What developer writesPrompts plus chain codeSignature plus metric (DSPy), or typed schema plus prompt template (BAML)
What model receivesWhat the developer wroteWhat the compiler generated (DSPy), or the template filled from the schema (BAML)
OptimizationManual prompt iterationAutomatic search against a metric or codegen from schema
DebuggabilityEvery step visibleFinal prompt is a compiler artifact
Best fitMoving target, no labels, deep custom controlStable task, labeled data, want prompt to keep improving

Real products, models, and research that use this idea.

  • DSPy's MIPROv2 optimizer (Opsahl-Ong et al., EMNLP 2024) proposes instructions and few-shot demos together and searches their combinations with Bayesian optimization.
  • BAML, from Boundary, declares typed LLM functions in .baml files and generates typed clients for Python, TypeScript, Go and other languages.
Sign in to see more production examples.

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.
A

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.

2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Treating DSPy as just another chain builder, then being confused that you never get to write the actual prompt text the model sees.

Sign in to see all red flags and common mistakes.

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

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
How does AutoGen 0.2 UserProxyAgent human_input_mode change the loop?
MCQ·Medium