Observability & Tracing for Langchain (Python & JS/TS)
Langfuse Tracing integrates with Langchain using Langchain Callbacks (Python, JS). Thereby, the Langfuse SDK automatically creates a nested trace for every run of your Langchain applications. This allows you to log, analyze and debug your LangChain application.
Add Langfuse to your Langchain Application
You can configure the integration via (1) constructor arguments or (2) environment variables. Get your Langfuse credentials from the Langfuse dashboard.
pip install langfuse
# Initialize Langfuse handler
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler(
secret_key="sk-lf-...",
public_key="pk-lf-...",
host="https://cloud.langfuse.com", # 🇪🇺 EU region
# host="https://us.cloud.langfuse.com", # 🇺🇸 US region
)
# Your Langchain code
# Add Langfuse handler as callback (classic and LCEL)
chain.invoke({"input": "<user_input>"}, config={"callbacks": [langfuse_handler]})
Also works for run
and predict
methods.
chain.run(input="<user_input>", callbacks=[langfuse_handler]) # Legacy
conversation.predict(input="<user_input>", callbacks=[langfuse_handler])
Done. Now you can explore detailed traces and metrics in the Langfuse dashboard.
Prefer end-to-end examples?
Supported LangChain interfaces
Feature/interface | Python | JS/TS |
---|---|---|
LCEL | ✅ | ✅ |
invoke() | ✅ | ✅ |
run() | ✅ | ✅ |
call() | ✅ | ✅ |
predict() | ✅ | ✅ |
async | ✅ | ✅ |
batch() | ✅ | (✅) |
streaming | ✅ | ✅ |
We are interested in your feedback! Raise an issue on GitHub to request support for additional interfaces.
Supported LangChain features
- 🕸️ LangGraph: Works with Langfuse Integration. Requires Python 3.11+ (GH issue). See notebook for example integration.
- 🏓 LangServe: See notebook for example integration.
Additional Configuration
Optional constructor arguments
When initializing the Langfuse handler, you can pass the following optional arguments to use more advanced features.
Python | JS/TS | Type | Description |
---|---|---|---|
user_id | userId | string | The current user. |
session_id | sessionId | string | The current session. |
release | release | string | The release tag of your application. |
version | version | string | The version of your application. |
trace_name | string | Customize the name of the created traces. Defaults to name of chain. | |
enabled | enabled | boolean | Enable or disable the Langfuse integration. Defaults to true . |
sample_rate | - | float | Sample rate for tracing. |
Dynamic Trace Attributes in Chain Invocation
You can also set the trace_name
, user_id
, session_id
, and tags
for a trace that corresponds to a LangChain execution through the runnable configuration of the chain without instantiating a new CallbackHandler
each time. This allows you to dynamically set these attributes for each specific execution. Here’s an example:
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler()
trace_name = "langchain_trace_name"
session_id = "random-session"
user_id = "random-user"
tags = ["random-tag-1", "random-tag-2"]
# Your existing Langchain code to create the chain
# Pass config to the chain invocation to be parsed as Langfuse trace attributes
chain.invoke(
{"animal": "dog"},
config={
"callbacks": [langfuse_handler],
"run_name": trace_name,
"tags": tags,
"metadata": {
"langfuse_session_id": session_id,
"langfuse_user_id": user_id,
},
},
)
Predefined Trace ID + Add Evaluation or User Feedback Score
Predefined Trace ID
To query traces or add evaluation and feedback scores, you need to know the ID of a trace. The LangChain integration automatically assigns the trace_id
to the run_id
of the LangChain run. You can set a predefined run_id
through the run configuration.
import uuid
predefined_run_id = str(uuid.uuid4())
langfuse_handler = CallbackHandler()
# Your existing Langchain code to create the chain
# Pass run_id to the chain invocation
chain.invoke({"person": "Ada Lovelace"}, config={
"run_id": predefined_run_id,
"callbacks": [langfuse_handler],
}
)
Add Score to Trace
Evaluation results and user feedback are recorded as scores in Langfuse. You can add them to a trace via the trace_id
. Scores do not need to be numeric, see scores documentation for more details.
from langfuse import Langfuse
langfuse = Langfuse()
langfuse.score(
trace_id=predefined_run_id,
name="user-feedback",
value=1,
comment="This was correct, thank you"
)
Interoperability with Langfuse SDKs
Use the Langchain integration in combination with the regular Langfuse SDKs if you want to:
- Add non-Langchain related observations to the trace.
- Group multiple Langchain runs into a single trace.
Learn more about the structure of a trace here.
from langfuse.decorators import langfuse_context, observe
# Create a trace via Langfuse decorators and get a Langchain Callback handler for it
@observe() # automtically log function as a trace to Langfuse
def main():
# update trace attributes (e.g, name, session_id, user_id)
langfuse_context.update_current_trace(
name="custom-trace",
session_id="user-1234",
user_id="session-1234",
)
# get the langchain handler for the current trace
langfuse_handler = langfuse_context.get_current_langchain_handler()
# Your Langchain code
# Add Langfuse handler as callback (classic and LCEL)
chain.invoke({"input": "<user_input>"}, config={"callbacks": [langfuse_handler]})
main()
Limitation (decorator + langchain): The input/output of the Langchain code will not be added to the trace or span created by the decorator but to a child. Adding them would cause unwanted side-effects if they are set manually or if you add multiple Langchain runs.
If you pass these callback handlers to your Langchain code, the events will be nested under the respective trace or span in the Langfuse.
See the Langchain observability cookbook for an example of this in action (Python).
Queuing and flushing
The Langfuse SDKs queue and batch events in the background to reduce the number of network requests and improve overall performance. In a long-running application, this works without any additional configuration.
If you are running a short-lived application, you need to shutdown Langfuse to ensure that all events are flushed before the application exits.
langfuse_handler.shutdown()
If you want to flush events synchronously at a certain point, you can use the flush
method. This will wait for all events that are still in the background queue to be sent to the Langfuse API. This is usually discouraged in production environments.
langfuse_handler.flush()
Serverless environments (JS/TS)
Since Langchain version > 0.3.0, the callbacks on which Langfuse relies have been backgrounded. This means that execution will not wait for the callback to either return before continuing. Prior to 0.3.0, this behavior was the opposite. If you are running code in serverless environments such as Google Cloud Functions, AWS Lambda or Cloudflare Workers you should set your callbacks to be blocking to allow them time to finish or timeout. This can be done either by
- setting the
LANGCHAIN_CALLBACKS_BACKGROUND
environment variable to “false” - importing the global
awaitAllCallbacks
method to ensure all callbacks finish if necessary
Read more about awaiting callbacks here in the Langchain docs.
Azure OpenAI model names
Please add the model
keyword argument to the AzureOpenAI
or AzureChatOpenAI
class to have the model name parsed correctly in Langfuse.
from langchain_openai import AzureChatOpenAI
llm = AzureChatOpenAI(
azure_deployment="my-gpt-4o-deployment",
model="gpt-4o",
)
FAQ
- How to customize the names of observations within a Langchain trace?
- Langsmith Alternative? Langfuse vs. Langsmith
- What is LangChain Expression Language (LCEL)?