mrkeyoor.com_
Sat 19 Sept 21:38 UTC
PyPIAI / MLupdated 19 Sept 2026

langfuse review

Langfuse 4.14.5 is the Python client for sending LLM traces to Langfuse Cloud or a self-hosted Langfuse server. Its OpenTelemetry-based observations capture nested spans and model generations, while integrations instrument OpenAI and LangChain calls. The same client fetches versioned prompts, submits scores, runs dataset experiments, and exposes the platform REST API. This release fixes serialization of `NaN` and infinite floats nested inside Pydantic models and refreshes the generated API specification. Our measured 4.14.4 install shipped typing metadata and imported successfully.

Verdict

Langfuse 4.14.4 installed in 0.7 seconds, used 24 MB in our sandbox, imported in 1.05 seconds, and had 0 audit findings. Adopt the current 4.x API when a team needs hosted or self-hosted LLM tracing and evaluations; skip it if operating a telemetry backend and flushing background events exceeds the problem.

We installed it

Lab card: what happened when we installed langfuseScreenshot of langfuse documentation
Install✓ · 0.7s26 packages on disk · 24 MB
Importimport langfuse in 1.05s · pure Python · py.typed · requires Python >=3.10, <4.0
Known vulns0(pip-audit)

Answers from our run

Does langfuse install cleanly?

Yes. In a fresh container with an empty cache, pip install langfuse finished in 0.7s, leaving 26 packages and 24 MB on disk. pip-audit reported no known vulnerabilities.

What does langfuse need to run?

Python >=3.10, <4.0, and nothing compiled: it is pure Python. In our run import langfuse succeeded in 1.05s, and the package ships py.typed for type checkers.

langfuse or langsmith: which should you use?

langsmith: Choose it when LangChain and LangGraph are the application core and first-party tracing matters most. Langfuse 4.14.4 installed in 0.7 seconds, used 24 MB in our sandbox, imported in 1.05 seconds, and had 0 audit findings.

When should you not use langfuse?

You want a local library with no backend. The SDK only becomes useful after connecting to Langfuse Cloud or operating the separate server stack.

API stability3/5The SDK reached version 4 through a rewrite released in March 2026, after the v3 line had already changed earlier integrations. Current code centers on OpenTelemetry observations, `get_client()`, context managers, and `@observe`; older `trace()` examples do not describe that contract. Version 4.14.2 preserved a legacy score creation alias, evidence that maintainers do carry selected compatibility paths, but two recent major migrations justify pinning versions and testing trace output during upgrades.
Docs5/5The official Python SDK site covers manual observations, the decorator, OpenAI and LangChain integrations, attribute propagation, scores, prompts, datasets, experiments, flushing, and the generated REST client. A dedicated v3-to-v4 migration page names removed and replacement APIs. The README also states that v4 was rewritten in March 2026, which helps readers reject stale samples. Operational details are spread between SDK and self-hosting sections, so deployment planning still needs both documentation trees.
Maintenance5/5GitHub showed an unarchived repository pushed on August 25, 2026, with 90 open issues and pull requests. Version 4.14.5 shipped on August 24 and fixed nested Pydantic serialization for `NaN` and infinite values while updating the generated API spec. Releases 4.14.2 through 4.14.5 also contain integration and tracing fixes. That cadence is active, although frequent generated-client updates increase the value of a locked dependency and upgrade tests.
Ecosystem4/5The PyPI download figure supplied for this guide is 6,325,417 per week, and GitHub reports 456 stars for the Python SDK repository. The README names OpenAI and LangChain integrations, OpenTelemetry tracing, datasets, experiments, evaluation, prompt management, and the full REST API client. Those pieces cover a complete Langfuse workflow, but they are tied to the Langfuse platform rather than functioning as interchangeable local libraries. Alternative observability backends require new exporters or instrumentation choices.

Use it if

  • Production debugging needs linked traces, nested generations, model metadata, token usage, latency, and application attributes.
  • OpenAI or LangChain calls should be instrumented through maintained integrations instead of custom logging at each call site.
  • Prompt versions and labels need to change independently of an application deployment, with a local cache for reads.
  • The team will operate Langfuse itself for data control or use its hosted service and accept the telemetry boundary.
Skip it if

Setup reality

We installed langfuse 4.14.4 in a fresh Python 3.12 Bookworm sandbox in 0.7 seconds. The environment ended with 26 packages and 24 MB on disk; pip-audit found 0 known vulnerabilities. The pure-Python distribution declares 8 direct dependencies, requires Python 3.10 through the 3.x line, includes py.typed, and completed import langfuse in 1.05 seconds.

A working client needs LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY. Set the base URL for the chosen cloud region or self-hosted endpoint rather than assuming the default host matches your deployment. The Python package does not contain the Langfuse service. Self-hosting means deploying and securing the platform's database, analytics store, cache, and object storage dependencies separately.

Version 4 builds tracing on OpenTelemetry context. Use start_as_current_observation, @observe, or a maintained integration, and follow the v3-to-v4 guide before copying older examples. Attribute propagation affects nested observations, so user IDs, sessions, tags, and environment labels should be attached at the intended scope. Treat captured prompts and outputs as production telemetry and configure masking before sending sensitive application data.

Events are queued and exported in the background. Long-running services can batch normally, but scripts, cron jobs, tests, and serverless handlers must call flush() before returning if delivery matters. Call shutdown() during a controlled process stop. A flush adds exit latency and may encounter network failure, so do not confuse an instrumented request succeeding with its trace reaching the server.

Patterns

Create nested spans and generations trace-spans-generations

# env: LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_BASE_URL
from langfuse import get_client

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="process-request") as span:
    span.update(input={"query": "user question"})

    with langfuse.start_as_current_observation(as_type="generation", name="llm-response", model="gpt-4o") as generation:
        # your LLM call here
        generation.update(output="Generated response")

    span.update(output="Processing complete")

langfuse.flush()

These are 4.x observation calls. The context managers close their spans; v2 `trace()` examples are not compatible.

Trace functions with the @observe decorator observe-decorator

from langfuse import observe, get_client

@observe()
def retrieve(query: str) -> list[str]:
    return ["doc1", "doc2"]

@observe()
def answer(query: str) -> str:
    docs = retrieve(query)
    return f"answer based on {len(docs)} docs"

answer("what is caching?")
get_client().flush()

Decorated calls nest under the active observation. Arguments and returns are captured unless that behavior is disabled.

Trace OpenAI calls with the drop-in wrapper openai-drop-in

from langfuse.openai import openai  # instead of: import openai

client = openai.OpenAI()
resp = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

Changing the import instruments synchronous, asynchronous, and streaming OpenAI clients with model and usage data.

Trace LangChain with the CallbackHandler langchain-callback

from langfuse.langchain import CallbackHandler

handler = CallbackHandler()

chain = prompt | model | parser
result = chain.invoke(
    {"topic": "observability"},
    config={"callbacks": [handler]},
)

Pass this handler in each invocation config so chains, tools, and retrievers appear under the same trace.

Attach user, session, and tags to all spans user-session-attributes

from langfuse import get_client, propagate_attributes

langfuse = get_client()

with propagate_attributes(user_id="user-123", session_id="chat-42", tags=["beta"]):
    with langfuse.start_as_current_observation(as_type="span", name="handle-message") as span:
        ...  # everything in here carries user_id and session_id

`propagate_attributes` is the 4.x route for these trace attributes, and a session groups related conversations in the UI.

Score output for evals or user feedback score-a-trace

from langfuse import get_client

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="qa") as span:
    span.update(output="the answer")
    span.score(name="user-feedback", value=1, data_type="BOOLEAN")

# or later, detached, using ids you stored:
langfuse.create_score(name="accuracy", value=0.9, trace_id="<trace-id>")

A score can be numeric, boolean, or categorical. Store the trace ID when feedback will arrive after the observation closes.

Fetch and compile a managed prompt prompt-management

from langfuse import get_client

langfuse = get_client()

prompt = langfuse.get_prompt("movie-critic", label="production")
text = prompt.compile(movie="Dune 2")

# prompt.config can carry model settings alongside the template
model = prompt.config.get("model", "gpt-4o")

Prompt labels select a version without a code change. The client cache can serve a prior value during a fetch failure.

Do not lose traces in scripts and serverless flush-short-lived

from langfuse import get_client

langfuse = get_client()

def handler(event, context):
    with langfuse.start_as_current_observation(as_type="span", name="lambda-job") as span:
        span.update(output="done")
    langfuse.flush()  # blocks until queued events are sent
    return {"ok": True}

Exports are buffered. `flush()` blocks until the queue is sent, which short jobs need before returning.

Run an experiment against a dataset datasets-experiments

from langfuse import get_client, Evaluation

langfuse = get_client()
dataset = langfuse.get_dataset("qa-golden-set")

def my_task(*, item, **kwargs):
    return my_app(item.input)

def exact_match(*, input, output, expected_output, **kwargs):
    return Evaluation(name="exact_match", value=float(output == expected_output))

result = dataset.run_experiment(
    name="prompt-v2",
    task=my_task,
    evaluators=[exact_match],
)
print(result.format())

Each result links back to its dataset item, letting the Langfuse UI compare the same cases across experiment runs.

Use the raw REST API client rest-api-client

from langfuse import get_client

langfuse = get_client()

traces = langfuse.api.trace.list(limit=10)
for t in traces.data:
    print(t.id, t.name, t.latency)

The generated synchronous and async clients cover platform operations missing from the higher-level helpers.

Alternatives

PackageRegistryPick it when
langsmithPyPIChoose it when LangChain and LangGraph are the application core and first-party tracing matters most.
arize-phoenixPyPIChoose it for local OpenTelemetry traces and evaluations centered on the Phoenix application.
logfirePyPIChoose it when LLM calls should sit beside ordinary Python logs, metrics, and application traces.

More ai / ml guides

openai · mcp · huggingface-hub · @modelcontextprotocol/sdk · scikit-learn · tiktoken · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.