beginner⏱30 minLesson 1 of 5

LangFuse Overview, Setup and SDK Integration

An introduction to LangFuse: what it is, how to set it up, and how to integrate the Python SDK for observability.

LangFuse Overview, Setup and SDK Integration

LangFuse is an open-source observability and evaluation platform for LLM applications. It provides tracing, prompt management, evaluation, and monitoring capabilities designed specifically for projects built with frameworks like LangChain, LlamaIndex, and custom Python pipelines.

This lesson covers the fundamentals: what LangFuse offers, the difference between self-hosted and cloud deployments, project setup, SDK installation, and basic trace creation.


What is LangFuse?

LangFuse helps teams:

  • Trace every step of an LLM call β€” from prompt construction to model response.
  • Evaluate outputs with manual scores, LLM-as-judge, or external metrics.
  • Manage prompts with version control and deployment workflows.
  • Monitor costs, latency, and error rates in real-time dashboards.
⚠️Warning

LangFuse is not a model provider or vector database. It is an observability layer that your application sends data to. You still need your own LLM API keys (OpenAI, Anthropic, etc.) and infrastructure.

ℹ️Note

LangFuse is fully open-source under the MIT license. You can inspect the source code at github.com/langfuse/langfuse, contribute features, and self-host without any licensing fees.

System Architecture

The following diagram shows how LangFuse fits into an LLM application stack:

100%

The SDK buffers data and flushes it asynchronously to the API. The API writes to PostgreSQL (traces, scores, prompt configs) and ClickHouse (aggregated analytics for dashboards). The dashboard UI reads from both stores.

Trace Creation Sequence

When your application makes an LLM call, the following sequence occurs:

100%

Data is batched and flushed periodically (default every 1 second) to minimise network overhead.


Self-Hosted vs Cloud

FeatureSelf-Hosted (OSS)LangFuse Cloud
Setup effortHigh β€” requires Docker, PostgreSQL, and networkingLow β€” sign up and get a project
Data residencyFull controlManaged by LangFuse
MaintenanceYou handle upgrades, backups, scalingHandled by LangFuse
CostInfrastructure cost onlyFree tier + paid plans
Feature updatesManual upgradeAutomatic
ScalabilityManual scalingAuto-scaling
High availabilityYou configure HABuilt-in SLA
Audit loggingConfigurableIncluded
Custom domainSupported with reverse proxyAvailable on paid plans
πŸ’‘Tip

Start with LangFuse Cloud during development. It takes 2 minutes to set up. Migrate to self-hosted later if you need data residency or expect very high volume that makes cloud pricing uneconomical.


Creating a Project and Getting API Keys

  1. Go to cloud.langfuse.com (or your self-hosted instance).
  2. Sign up and create an organization.
  3. Create a project (e.g. "My Chatbot").
  4. Navigate to Settings β†’ API Keys.
  5. Generate a public key and a secret key (also called secret_key).

Keep the secret key secure β€” it authorizes writes to your project.

πŸ“ŒImportant

Rotate your secret keys periodically. LangFuse Cloud allows you to generate multiple key pairs and revoke old ones. Set up a quarterly rotation reminder. If a key is compromised, revoke it immediately from Settings β†’ API Keys.


Installing the Python SDK

bash
pip install langfuse langchain-openai

The langfuse package provides the trace client. The langchain-openai package is used for LangChain integration examples in this course.

Supported SDKs

LanguagePackageStatusKey Features
Pythonlangfuseβœ… StableFull features: traces, spans, scores, datasets, prompts, @observe decorator, LangChain & LlamaIndex callbacks
JavaScript / TypeScriptlangfuseβœ… StableSame feature set as Python; supports LangChain.js, LlamaIndex.ts
Golangfuse-goβœ… CommunityCore tracing and scoring
Rustlangfuse-rsβœ… CommunityCore tracing
REST APIHTTPβœ… Always availableAny language can send traces via POST /api/public/traces
ℹ️Note

This course focuses on the Python SDK, but the concepts are identical across all SDKs. The API contract is the same β€” each SDK is a thin wrapper around the REST endpoints.


Basic Initialization

python
# basic_init.py from langfuse import Langfuse langfuse = Langfuse( secret_key="sk-lf-...", # Replace with your secret key public_key="pk-lf-...", # Replace with your public key host="https://cloud.langfuse.com" # Or your self-hosted URL ) # Verify connection print("LangFuse initialized:", langfuse.auth_check())
⚠️Warning

Never hard-code API keys in production. Use environment variables:

python
import os langfuse = Langfuse( secret_key=os.environ["LANGFUSE_SECRET_KEY"], public_key=os.environ["LANGFUSE_PUBLIC_KEY"], host=os.environ.get("LANGFUSE_HOST", "https://cloud.langfuse.com") )

Configuration Reference

Environment VariableRequiredDefaultDescription
LANGFUSE_SECRET_KEYβœ… Yesβ€”Secret key for API authentication
LANGFUSE_PUBLIC_KEYβœ… Yesβ€”Public key for API authentication
LANGFUSE_HOST❌ Nohttps://cloud.langfuse.comSelf-hosted instance URL
LANGFUSE_DEBUG❌ NofalseEnable debug HTTP logging
LANGFUSE_FLUSH_INTERVAL❌ No1Flush interval in seconds
LANGFUSE_MAX_RETRIES❌ No3Max retries for failed API calls

Environment-Based Setup Decision

100%

Async Initialization

For async applications (FastAPI, Django channels, etc.), LangFuse provides an async-compatible client:

python
# async_init.py import asyncio from langfuse import Langfuse langfuse = Langfuse() async def process_question(question: str) -> str: # The SDK uses an async HTTP client internally trace = langfuse.trace(name="async-chat", input={"question": question}) # ... LLM call ... trace.end(output={"answer": "42"}) # Flush is async-safe await asyncio.to_thread(langfuse.flush) asyncio.run(process_question("What is the meaning of life?"))

Context Manager Patterns

LangFuse supports context manager protocol for automatic span closure:

python
# context_manager.py from langfuse import Langfuse langfuse = Langfuse() with langfuse.trace(name="chat-session", user_id="user_42") as trace: # Trace automatically ends when the block exits with trace.span(name="llm-call") as span: # Automatically ends the span span.end( input={"prompt": "Hello"}, output={"response": "Hi there!"}, usage={"prompt_tokens": 5, "completion_tokens": 3} ) with trace.span(name="retrieval") as retrieval_span: retrieval_span.end(input={"query": "docs"}, output={"count": 3})

This pattern ensures spans are always closed, even if an exception occurs inside the block.

Error Handling

Implement proper error handling around LangFuse calls to avoid crashing your main application:

python
# error_handling.py from langfuse import Langfuse from langfuse.api.core import ApiError langfuse = Langfuse() def safe_trace_llm_call(prompt: str) -> dict: """Trace an LLM call with comprehensive error handling.""" trace = None try: trace = langfuse.trace(name="llm-call", input={"prompt": prompt}) # Your actual LLM logic here response = call_llm(prompt) # May raise an exception span = trace.span(name="response") span.end( output={"response": response}, usage={"prompt_tokens": len(prompt.split()), "completion_tokens": len(response.split())} ) trace.end(output=response) return {"success": True, "response": response} except ApiError as e: # LangFuse API is down or rejected the request print(f"LangFuse API error: {e.status_code} - {e.body}") # Application continues without observability return {"success": True, "response": response} except Exception as e: print(f"Application error: {e}") if trace: span = trace.span(name="error") span.end(level="ERROR", metadata={"error": str(e)}) trace.end() return {"success": False, "error": str(e)} finally: langfuse.flush()
πŸ’‘Tip

If you are experiencing connection issues with LangFuse, enable debug logging to see the raw HTTP traffic:

python
import logging logging.basicConfig(level=logging.DEBUG) langfuse = Langfuse(debug=True)

This prints every request and response to stderr, helping you diagnose TLS, authentication, or network problems.


Creating a Basic Trace

A trace represents a single end-to-end request (e.g. a user question). Inside a trace you can create spans (individual steps).

python
# simple_trace.py from langfuse import Langfuse langfuse = Langfuse() # Start a trace trace = langfuse.trace(name="hello-world", user_id="user_123") # Add a span (an LLM call step) span = trace.span(name="llm-call") # Simulate an LLM response span.end( input={"prompt": "Say hello in French"}, output={"response": "Bonjour!"}, usage={"prompt_tokens": 10, "completion_tokens": 2} ) # End the trace (optional β€” ends when context manager exits) # trace.end() print("Trace ID:", trace.id)

LangFuse vs Other Tools

FeatureLangFuseWeights & BiasesMLflow
LLM-native tracesβœ… YesPartial❌ No
Prompt versioningβœ… Built-in❌❌
LLM-as-judge evalβœ… Native❌❌
Self-hostableβœ… Open-sourceβŒβœ… Open-source
LangChain integrationβœ… First-class❌❌
Cost trackingβœ… Per-trace❌❌
Dataset managementβœ… Built-in❌❌
Alert rulesβœ… Built-in❌❌

Interactive Questions

Practice Question

You are building a RAG chatbot and need to debug why the model sometimes ignores retrieved context. Which LangFuse feature helps you inspect each step of the pipeline?

Practice Question

Which method initializes the LangFuse SDK in a Python application?

Practice Question

An LLM call in a FastAPI route handler raised an unexpected exception. Your LangFuse trace is never closed. How should you handle this?

Practice Question

How should you provide API keys to the LangFuse SDK in production?

Practice Question

Which of the following is NOT a capability of LangFuse?


βœ…Success

Key Takeaways

  • LangFuse is an open-source observability platform built specifically for LLM applications.
  • You can use LangFuse Cloud or self-host with Docker and PostgreSQL.
  • Each project uses a public/secret key pair to authenticate the SDK.
  • A trace represents an entire request; spans represent individual steps within it.
  • LangFuse integrates natively with LangChain, LlamaIndex, and custom Python code.
  • Compared to W&B and MLflow, LangFuse offers LLM-specific features like prompt versioning and LLM-as-judge evaluation.
  • Always use environment variables for API keys and wrap traces in proper error handling.
Progress20%