Both SDKs are built on OpenTelemetry, so most of your code maps over directly.Documentation Index
Fetch the complete documentation index at: https://docs.bentolabs.ai/llms.txt
Use this file to discover all available pages before exploring further.
Migrate with an AI coding tool
Install the Bento docs skill so your AI coding tool has full context.
The three paths
Pick the smoothest applicable one and fall through. Most migrations end up using B for the bulk and C for a handful of bespoke decorators.| Path | When | Effort |
|---|---|---|
| A — Google ADK integration | ADK is in use | 3 lines at startup |
| B — Auto-capture with OpenInference | langfuse.openai, langfuse.langchain, Anthropic via instrumentor | Drop one import, register one instrumentor |
| C — Manual translation | Bespoke @observe, start_as_current_observation, custom spans | Per-call-site rename |
Path A: Google ADK integration
If your app runs Google ADK agents, this captures every model call, tool call, and agent step automatically.Path B: Auto-capture with OpenInference
Langfuse’sfrom langfuse.openai import OpenAI (and the langfuse.langchain.CallbackHandler) get replaced by an OpenInference instrumentor registered against a BentoLabsSpanProcessor. Your call sites stay untouched — every LLM call is captured at the SDK level.
from langfuse.openai import OpenAI with the stock import — the instrumentor wraps the client automatically:
CallbackHandler and register LangChainInstrumentor() the same way. For Anthropic / Bedrock: install the matching openinference-instrumentation-* and register it.
Full reference: OTel transport.
Path C: Manual translation
For bespoke@observe() decorators, manual context managers, and identity helpers, translate per the tables.
Setup
| Langfuse | Bento |
|---|---|
pip install langfuse | pip install bentolabs-sdk |
LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_HOST | BENTOLABS_API_KEY |
Langfuse(...) / get_client() | bento.init(api_key=...) |
langfuse.flush() | bento.flush() |
Decorators
| Langfuse | Bento |
|---|---|
@observe() on a handler | @bento.interaction |
@observe() on a tool | @bento.tool |
@observe(as_type="generation", ...) | Replace body with bento.track_ai(...) |
Multi-step / context managers
| Langfuse | Bento |
|---|---|
start_as_current_observation(as_type="span", ...) | with bento.begin(...) as t: |
Nested as_type="span" (tool) | t.tool_span(...) |
Identity
| Langfuse | Bento |
|---|---|
update_current_trace(...) | bento.update_current_trace(...) |
update_current_observation(...) | bento.update_current_span(...) |
propagate_attributes(...) | bento.propagate_attributes(...) |
What’s gone
| Langfuse | Where it goes |
|---|---|
langfuse.score(...) | bento.update_current_trace(properties={"score_<name>": value}) |
langfuse.get_prompt(...) | Move prompts to code or config; stash version in properties |
| Datasets / dataset runs | No primitive yet |
Watch out for
session_idvsconvo_id. Bento usessession_ideverywhere exceptbento.track_ai, which usesconvo_id. Same attribute under the hood.metadata→properties. Direct rename. Langfuse magic keys (langfuse_user_id, etc.) don’t exist; use the real kwargs.- No OpenAI drop-in. Use Path B (OpenInference) instead of trying to find a
from bento.openai import OpenAIequivalent.
Side-by-side
Langfuse
Bento
See also
Configuration
init(), identity getters, env vars.Tracking events
The
bento.track_ai reference.