Langfuse Guide 2025: Open-Source LLM Observability & Tracing
Langfuse is the leading open-source platform for LLM observability. It captures traces, spans, and generations for every AI call — tokens, cost, latency, model params — and layers on prompt management, dataset evals, and LLM-as-judge scoring. Self-host it or use the cloud; your data stays under your control.
What Is Langfuse?
Langfuse (MIT license) gives AI engineers full visibility into what their LLM application is doing. Every call is captured as a trace — a tree of spans and generations with timestamps, input/output text, token counts, cost, and model metadata. The dashboard lets you filter, search, and drill into any call within seconds.
Beyond tracing, Langfuse includes: prompt management (versioned prompts fetched at runtime), evaluations (LLM-as-judge + programmatic scoring), and datasets (curate test cases from production traces, run batch evals across model/prompt versions). It competes with LangSmith but is fully open-source and self-hostable.
Install Langfuse SDK
pip install langfuse
Quickstart: First Trace with @observe
Set your API keys (from cloud.langfuse.com or your self-hosted instance), then decorate any function with @observe. Langfuse automatically captures inputs, outputs, and timing.
Set env vars
export LANGFUSE_PUBLIC_KEY="pk-lf-..." export LANGFUSE_SECRET_KEY="sk-lf-..." export LANGFUSE_HOST="https://cloud.langfuse.com" # or your self-hosted URL
first_trace.py
from langfuse.decorators import observe
from langfuse.openai import openai # drop-in OpenAI wrapper
@observe()
def answer_question(question: str) -> str:
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": question},
],
)
return response.choices[0].message.content
result = answer_question("What is LLM observability?")
print(result) That's it. Open the Langfuse dashboard and you'll see the trace — inputs, output, token usage, cost, and latency — with zero additional instrumentation code.
Automatic Tracing: OpenAI, LangChain & LlamaIndex
Langfuse offers drop-in integrations for the most popular frameworks — one import or one callback, and all LLM calls are traced automatically.
OpenAI SDK — drop-in replacement
# Replace this:
# from openai import openai
# With this — all API calls auto-traced:
from langfuse.openai import openai
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Explain embeddings."}],
) LangChain — callback handler
from langfuse.callback import CallbackHandler
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
langfuse_handler = CallbackHandler()
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("Tell me a fact about {topic}")
chain = prompt | llm
response = chain.invoke(
{"topic": "observability"},
config={"callbacks": [langfuse_handler]},
)
print(response.content) LlamaIndex — global handler
from llama_index.core import Settings
from langfuse.llama_index import LlamaIndexCallbackHandler
langfuse_callback = LlamaIndexCallbackHandler()
Settings.callback_manager.add_handler(langfuse_callback)
# All subsequent LlamaIndex queries are now traced automatically
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
docs = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine()
response = query_engine.query("What is RAG?") Manual Tracing: trace(), span(), generation()
For custom pipelines not covered by automatic integrations, use the low-level SDK to create traces and nest spans manually. This gives full control over trace structure and metadata.
manual_trace.py
from langfuse import Langfuse
langfuse = Langfuse()
# Create a top-level trace (represents one user request)
trace = langfuse.trace(
name="rag-pipeline",
user_id="user-123",
metadata={"environment": "production"},
)
# Retrieval span
retrieval_span = trace.span(
name="vector-retrieval",
input={"query": "What is PagedAttention?"},
)
# ... run retrieval ...
retrieval_span.end(output={"chunks": 5, "top_score": 0.92})
# LLM generation
generation = trace.generation(
name="answer-generation",
model="gpt-4o-mini",
model_parameters={"temperature": 0.2, "max_tokens": 512},
input=[{"role": "user", "content": "What is PagedAttention?"}],
)
# ... call LLM ...
generation.end(
output="PagedAttention is a memory management algorithm...",
usage={"input": 45, "output": 89},
)
langfuse.flush() # Ensure all events are sent before process exits Prompt Management
Langfuse stores prompts with full version history. Create and edit prompts in the UI, then fetch the latest version at runtime — no code deploys needed to update prompts. Supports A/B testing by linking a trace to the prompt version it used.
Fetch and use a managed prompt
from langfuse import Langfuse
from langfuse.openai import openai
langfuse = Langfuse()
# Fetch the production prompt (latest version by default)
prompt = langfuse.get_prompt("customer-support-system")
# Compile with variables
compiled = prompt.compile(product_name="Pulse", tone="friendly")
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": compiled},
{"role": "user", "content": "How do I reset my password?"},
],
langfuse_prompt=prompt, # Links this call to the prompt version in the trace
)
print(response.choices[0].message.content)
Fetch a specific version with langfuse.get_prompt("name", version=3) or a label with label="staging" for safe rollout.
Evaluations: LLM-as-Judge & Programmatic Scoring
Langfuse supports two scoring modes: LLM-as-judge evals configured in the UI (no code), and programmatic scores attached to any trace via the SDK.
Programmatic scoring — attach a score to a trace
from langfuse import Langfuse
langfuse = Langfuse()
# After running and evaluating a response:
langfuse.score(
trace_id="trace-abc123", # ID from the trace you created
name="faithfulness", # Metric name (shows in dashboard)
value=0.87, # 0.0–1.0 or any numeric scale
comment="Grounded in retrieved context, minor hallucination on date.",
)
# You can also score at the observation (span/generation) level:
langfuse.score(
trace_id="trace-abc123",
observation_id="gen-xyz789",
name="answer-relevance",
value=4, # 1-5 Likert scale
) For LLM-as-judge: go to Evaluations → Configure in the Langfuse UI, choose a judge model (e.g. GPT-4o), write your evaluation prompt template, and select which traces to score. Results appear alongside your traces automatically.
Datasets: Curate, Evaluate, Compare
Datasets in Langfuse are collections of input/expected-output pairs. You can create them manually, import from CSV/JSON, or add individual traces directly from the dashboard. Then run batch evaluation experiments to compare model versions, prompt versions, or retrieval strategies.
Run a dataset evaluation experiment
from langfuse import Langfuse
from langfuse.openai import openai
langfuse = Langfuse()
# Fetch the dataset
dataset = langfuse.get_dataset("qa-golden-set")
for item in dataset.items:
# Create an experiment run linked to this dataset item
with item.observe(run_name="gpt-4o-mini-v2") as trace:
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": item.input["question"]}],
)
answer = response.choices[0].message.content
# Score against expected output
is_correct = item.expected_output["answer"].lower() in answer.lower()
langfuse.score(
trace_id=trace.id,
name="exact-match",
value=1.0 if is_correct else 0.0,
)
langfuse.flush()
print("Experiment complete — view results in Langfuse dashboard") The dashboard's Experiments view lets you compare runs side-by-side — mean scores, score distributions, and individual trace diffs across model/prompt versions.
Self-Hosting: Docker Compose & Kubernetes
Langfuse is designed to be self-hosted. The stack requires PostgreSQL (trace storage) and ClickHouse (analytics queries). The official docker-compose brings everything up in one command:
Docker Compose quickstart
# Download the official compose file curl -LO https://raw.githubusercontent.com/langfuse/langfuse/main/docker-compose.yml # Start all services (Langfuse app + PostgreSQL + ClickHouse) docker compose up -d # Open the UI at http://localhost:3000 # Default credentials: create on first sign-in
Kubernetes with Helm
helm repo add langfuse https://langfuse.github.io/langfuse-k8s helm repo update # Install with default values (PostgreSQL + ClickHouse as sub-charts) helm install langfuse langfuse/langfuse \ --set langfuse.nextauth.secret="your-secret-here" \ --set langfuse.salt="your-salt-here" \ --set postgresql.auth.password="pg-password" \ -n langfuse --create-namespace
Point the SDK at your instance with LANGFUSE_HOST=https://your-domain.com. The self-hosted version has no feature restrictions compared to the cloud offering.
Langfuse vs LangSmith vs Helicone vs Weave
| Tool | Open-source | Self-host | Free tier | Best for |
|---|---|---|---|---|
| Langfuse | Yes (MIT) | Yes | 50k obs/mo | Open-source, any framework, self-host |
| LangSmith | No | No | 5k traces/mo | Deep LangChain integration |
| Helicone | Yes | Yes | 100k req/mo | Proxy-based, cost analytics, caching |
| W&B Weave | No | No | Limited | ML experiment tracking + LLM evals |
See also: LangChain guide · LlamaIndex guide · MLflow guide
Keep Your Entire AI Stack Healthy
Langfuse shows you what your LLM is doing. Prismix shows you when your LLM provider goes down — together they keep your AI app healthy.
Monitor LLM Provider Status →