In Langfuse, what does compile() do to a fetched prompt, and what placeholder syntax does it use?
answer
- Fetching is not the same as rendering
- Double braces, not single
- Text in, string out; chat in, messages out
- Missing variable does not raise
- Substitution is local and offline
basics
~20 scompile() substitutes values into a Langfuse prompt's double-curly-brace placeholders, such as {{question}}. A text prompt compiles to a plain string; a chat prompt compiles to a list of role/content message dicts, ready to pass straight to a model SDK.
solid answer
~40 s`langfuse.get_prompt(...)` returns a prompt client, not a ready-to-send string — the stored template still contains placeholders written as `{{variable}}`. Calling `prompt.compile(question="Where is my order?")` replaces them with the values you pass. For a text prompt the result is a plain string; for a chat prompt (`get_prompt(name, type="chat")`) the result is a list of `{"role": ..., "content": ...}` dicts you can hand directly to a chat completions call. The double-brace syntax is deliberate: it does not collide with Python f-strings or `str.format`, and it survives user content containing single braces. The failure mode to know is that `compile()` is forgiving — forgetting a variable does not raise, so a typo'd keyword ships a prompt with an unfilled slot to the model instead of failing the request. Validate inputs yourself if the variable is load-bearing.
code
python · 13 linesfrom langfuse import Langfuse
langfuse = Langfuse()
# Text prompt -> plain string
prompt = langfuse.get_prompt("support-reply")
text = prompt.compile(question="Where is my order?")
# Chat prompt -> list of role/content dicts
chat = langfuse.get_prompt("support-chat", type="chat")
messages = chat.compile(question="Where is my order?")
# [{"role": "system", "content": "..."},
# {"role": "user", "content": "Where is my order?"}]go deeper
Remember the two steps: fetch the prompt, then call compile() with the variables. Know that placeholders are written {{like_this}} and that a chat prompt compiles to a list of messages.
Explain why double braces are used, what each prompt type compiles to, and the forgiving-substitution behaviour — a missing variable does not raise, it ships an unfilled slot to the model.
Talk about the operational consequence: the variable set is an interface that can now change without a deploy, so you validate required keys at the call site and record the compiled prompt in the trace so silent gaps are diagnosable.
Frame it as contract management between prompt authors and application code — who is allowed to introduce a new variable, how that change is reviewed, and whether the organisation wants a schema check enforced before a version can be promoted.
## What you get back from get_prompt `langfuse.get_prompt("support-reply")` does not return a string. It returns a prompt client object holding the stored template on `.prompt`, plus metadata: `.name`, `.version`, `.labels` and `.config`. The template is what a human authored in the Langfuse UI or via `create_prompt`, and it usually contains slots for the runtime data. ## The placeholder syntax Langfuse uses **double curly braces**: `{{question}}`, `{{customer_name}}`, `{{retrieved_context}}`. This choice is not cosmetic: - Single braces are extremely common inside prompt bodies — JSON examples, code samples, format specifications. A single-brace template would break the moment a prompt included `{"role": "user"}` as an illustration. - Python's own f-strings and `str.format` use single braces, so a double-brace template can be stored, logged and moved around without any Python string machinery accidentally interpreting it. ## Compiling a text prompt ``` prompt = langfuse.get_prompt("support-reply") text = prompt.compile(question="Where is my order?") ``` `compile()` takes keyword arguments named after the placeholders and returns a plain `str` with each `{{name}}` replaced by the corresponding value. That string is what you send to the model. ## Compiling a chat prompt A chat prompt is authored as an ordered list of messages, each with a `role` and `content`. Fetch it with `type="chat"`: ``` chat = langfuse.get_prompt("support-chat", type="chat") messages = chat.compile(question="Where is my order?") ``` The result is a list of `{"role": ..., "content": ...}` dicts, with substitution applied inside each message's content. This shape matches what the major chat completion APIs expect, so it usually goes straight into the `messages` argument with no adapter in between. Asking for the wrong `type` is a real mistake: fetching a chat prompt without `type="chat"` gives you the wrong client shape and the compile result will not be what your call site expects. ## The forgiving-substitution trap `compile()` does not enforce that you supplied every variable the template declares. Forgetting one — or misspelling the keyword — does not raise a `KeyError`; it produces a prompt with an unfilled or empty slot, which then goes to the model and comes back as a confidently wrong answer. Nothing crashes, so nothing pages anyone. Mitigations, in rough order of cost: - Build the variable dict in one place and assert on its keys before the call. - Add a thin wrapper around `compile()` in your own code that checks the required keys for that prompt. - Include the compiled prompt in the trace so the unfilled slot is visible when you investigate a bad answer, rather than invisible. The general lesson: because the prompt now changes without a deploy, the set of variables it expects can also change without a deploy. An author who adds `{{tone}}` to the template has silently added a new contract that your code does not fulfil. Treat the variable list as an interface between the prompt author and the application, and review changes to it as you would review a function signature. ## Where compilation sits in the flow The full runtime path is: fetch by name (usually from the local cache) → compile with this request's variables → send to the model → record the generation with a link back to the prompt version used. Compilation is deliberately the cheap, local, synchronous step in the middle; it does no network I/O and does not depend on the Langfuse backend being reachable. ## Framework interop When the downstream consumer is a framework whose own template objects use single braces, the prompt client exposes `get_langchain_prompt()`, which converts the double-brace form into the single-brace form that framework expects. The important point for an interview is the direction of responsibility: Langfuse owns the storage and the `{{...}}` convention, and offers a conversion at the boundary rather than adopting the framework's syntax internally.
- What is stored in a Langfuse prompt's config field, and why keep it there rather than in your code?`config` is an arbitrary JSON blob saved and versioned alongside the prompt text — typically the model name, temperature, max tokens, or a JSON schema. Keeping it there means a prompt rewritten for a different model ships with that model setting attached, so the two cannot drift apart or half-apply. You read it as `prompt.config` at call time and pass the values into your model call.
- Why does Langfuse use {{variable}} rather than single braces?Prompt bodies routinely contain single braces — JSON examples, code snippets, format instructions — and Python's f-strings and str.format also claim single braces. Double braces let a template hold literal `{}` characters and survive being passed through ordinary Python string handling without accidental interpretation or escaping.
- A prompt author adds a new {{tone}} placeholder but the service never passes it. What happens?Nothing fails loudly. `compile()` does not raise for a variable you did not supply, so the model receives a prompt with an unfilled slot and answers anyway — usually plausibly, sometimes wrongly. That is why the variable list should be treated as an interface: assert on required keys in your wrapper, and make the compiled prompt visible in the trace so the gap is diagnosable after the fact.
saying these in an interview costs you the question
- Thinks get_prompt already returns a ready-to-send string
- Uses single braces for Langfuse prompt variables
- Assumes compile() raises when a variable is missing
- Expects a chat prompt to compile down to one string
- Believes compile() makes a network call to Langfuse