Langfuse joins ClickHouse! Learn more β†’
DocsPrompt ManagementFeaturesLink to Traces

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.

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 generation

There 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

Was this page helpful?