Link Prompts to Traces
Linking prompts to traces enables tracking of metrics and evaluations per prompt version. It's the foundation of improving prompt quality over time.
After linking prompts and traces, navigating to a generation span in Langfuse will highlight the prompt that was used to generate the response. To access the metrics, navigate to your prompt and click on the Metrics tab.
How to Link Prompts to Traces
There are three ways to create traces with the Langfuse Python SDK. For more information, see the SDK documentation.
Decorators
from langfuse import observe, get_client
langfuse = get_client()
@observe(as_type="generation")
def nested_generation():
prompt = langfuse.get_prompt("movie-critic")
langfuse.update_current_generation(
prompt=prompt,
)
@observe()
def main():
nested_generation()
main()Context Managers
from langfuse import get_client
langfuse = get_client()
prompt = langfuse.get_prompt("movie-critic")
with langfuse.start_as_current_observation(
as_type="generation",
name="movie-generation",
model="gpt-4o",
prompt=prompt
) as generation:
# Your LLM call here
generation.update(output="LLM response")Manual observations
from langfuse import get_client
langfuse = get_client()
prompt = langfuse.get_prompt("movie-critic")
generation = langfuse.start_generation(
name="movie-generation",
model="gpt-4o",
prompt=prompt
)
# Your LLM call here
generation.update(output="LLM response")
generation.end() # Important: manually end the generationThere are three ways to create traces with the Langfuse JS/TS SDK. For more information, see the SDK documentation.
Observe wrapper
import { LangfuseClient } from "@langfuse/client";
import { observe, startObservation } from "@langfuse/tracing";
const langfuse = new LangfuseClient();
const callLLM = async (input: string) => {
const prompt = langfuse.prompt.get("my-prompt");
updateActiveObservation({ prompt }, { asType: "generation" });
return await invokeLLM(input);
};
export const observedCallLLM = observe(callLLM);Context manager
import { LangfuseClient } from "@langfuse/client";
import { updateActiveObservation } from "@langfuse/tracing";
const langfuse = new LangfuseClient();
startActiveObservation(
"llm",
async (generation) => {
const prompt = langfuse.prompt.get("my-prompt");
generation.update({ prompt });
},
{ asType: "generation" },
);Manual observations
import { LangfuseClient } from "@langfuse/client";
import { startObservation } from "@langfuse/tracing";
const prompt = new LangfuseClient().prompt.get("my-prompt");
startObservation(
"llm",
{
prompt,
},
{ asType: "generation" },
);from langfuse.openai import openai
from langfuse import get_client
langfuse = get_client()
prompt = langfuse.get_prompt("calculator")
openai.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": prompt.compile(base=10)},
{"role": "user", "content": "1 + 1 = "}],
langfuse_prompt=prompt
)Please make sure you have OpenTelemetry already set up for tracing.
import { observeOpenAI } from "@langfuse/openai";
import OpenAI from "openai";
const langfusePrompt = await langfuse.prompt.get("prompt-name"); // Fetch a previously created prompt
const res = await observeOpenAI(new OpenAI(), {
langfusePrompt,
}).completions.create({
prompt: langfusePrompt.prompt,
model: "gpt-4o",
max_tokens: 300,
});from langfuse import get_client
from langfuse.langchain import CallbackHandler
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI, OpenAI
langfuse = get_client()
# Initialize the Langfuse handler
langfuse_handler = CallbackHandler()Text prompts
langfuse_text_prompt = langfuse.get_prompt("movie-critic")
## Pass the langfuse_text_prompt to the PromptTemplate as metadata to link it to generations that use it
langchain_text_prompt = PromptTemplate.from_template(
langfuse_text_prompt.get_langchain_prompt(),
metadata={"langfuse_prompt": langfuse_text_prompt},
)
## Use the text prompt in a Langchain chain
llm = OpenAI()
completion_chain = langchain_text_prompt | llm
completion_chain.invoke({"movie": "Dune 2", "criticlevel": "expert"}, config={"callbacks": [langfuse_handler]})Chat prompts
langfuse_chat_prompt = langfuse.get_prompt("movie-critic-chat", type="chat")
## Manually set the metadata on the langchain_chat_prompt to link it to generations that use it
langchain_chat_prompt = ChatPromptTemplate.from_messages(
langfuse_chat_prompt.get_langchain_prompt()
)
langchain_chat_prompt.metadata = {"langfuse_prompt": langfuse_chat_prompt}
## or use the ChatPromptTemplate constructor directly.
## Note that using ChatPromptTemplate.from_template led to issues in the past
## See: https://github.com/langfuse/langfuse/issues/5374
langchain_chat_prompt = ChatPromptTemplate(
langfuse_chat_prompt.get_langchain_prompt(),
metadata={"langfuse_prompt": langfuse_chat_prompt}
)
## Use the chat prompt in a Langchain chain
chat_llm = ChatOpenAI()
chat_chain = langchain_chat_prompt | chat_llm
chat_chain.invoke({"movie": "Dune 2", "criticlevel": "expert"}, config={"callbacks": [langfuse_handler]})If you use the with_config method on the PromptTemplate to create a new
Langchain Runnable with updated config, please make sure to pass the
langfuse_prompt in the metadata key as well.
Set the langfuse_prompt metadata key only on PromptTemplates and not
additionally on the LLM calls or elsewhere in your chains.
Please make sure you have OpenTelemetry already set up for tracing.
import { LangfuseClient } from "@langfuse/client";
import { CallbackHandler } from "@langfuse/langchain";
import { PromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI, OpenAI } from "@langchain/openai";
const langfuseHandler = new CallbackHandler({
secretKey: "sk-lf-...",
publicKey: "pk-lf-...",
baseUrl: "https://cloud.langfuse.com", // πͺπΊ EU region
// baseUrl: "https://us.cloud.langfuse.com", // πΊπΈ US region
});
const langfuse = new Langfuse();Text prompts
const langfuseTextPrompt = await langfuse.prompt.get("movie-critic"); // Fetch a previously created text prompt
// Pass the langfuseTextPrompt to the PromptTemplate as metadata to link it to generations that use it
const langchainTextPrompt = PromptTemplate.fromTemplate(
langfuseTextPrompt.getLangchainPrompt()
).withConfig({
metadata: { langfusePrompt: langfuseTextPrompt },
});
const model = new OpenAI();
const chain = langchainTextPrompt.pipe(model);
await chain.invoke({ movie: "Dune 2", criticlevel: "expert" }, { callbacks: [langfuseHandler] });Chat prompts
const langfuseChatPrompt = await langfuse.prompt.get(
"movie-critic-chat",
{
type: "chat",
}
); // type option infers the prompt type as chat (default is 'text')
const langchainChatPrompt = ChatPromptTemplate.fromMessages(
langfuseChatPrompt.getLangchainPrompt().map((m) => [m.role, m.content])
).withConfig({
metadata: { langfusePrompt: langfuseChatPrompt },
});
const chatModel = new ChatOpenAI();
const chatChain = langchainChatPrompt.pipe(chatModel);
await chatChain.invoke({ movie: "Dune 2", criticlevel: "expert" }, { callbacks: [langfuseHandler] });Link Langfuse prompts to Vercel AI SDK generations by setting the langfusePrompt property in the metadata field:
import { generateText } from "ai";
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
const fetchedPrompt = await langfuse.prompt.get("my-prompt");
const result = await generateText({
model: openai("gpt-4o"),
prompt: fetchedPrompt.prompt,
experimental_telemetry: {
isEnabled: true,
metadata: {
langfusePrompt: fetchedPrompt.toJSON(),
},
},
});If a fallback prompt is used, no link will be created.
Metrics Reference
Once prompts are linked to traces, Langfuse automatically aggregates the following metrics per prompt version. You can compare them across prompt versions in the Metrics tab in the Langfuse UI:
- Median generation latency
- Median generation input tokens
- Median generation output tokens
- Median generation costs
- Generation count
- Median score value
- First and last generation timestamp