Skip to main content

Observe LangChain Instrumentation

This library traces LangChain and LangGraph applications. It hooks into LangChain’s callback manager to emit spans that mirror the structure of your application:

  • Workflow spans for a graph or chain run — for example an invocation of a LangGraph StateGraph — capturing the overall input and output of the run.

  • Agent spans for agent invocations nested inside a workflow, including the agent name, id, description, and conversation/session id when available.

  • Tool spans for tool calls made during a run.

  • Retrieval spans for retriever invocations, capturing the query and retrieved document IDs and relevance scores when available.

The spans nest to reflect the graph, so a single graph invocation produces a workflow span with the agent, tool, and model calls it triggered as children.

This package is Observe’s replacement for upstream’s opentelemetry-instrumentation-genai-langchain, not an addition to it. The two distributions install to the same paths, so an environment holding both gets a per-file mix of them and uninstalling either one breaks the other. This package depends on observe-util-genai, which replaces upstream’s opentelemetry-util-genai in the same way. Uninstall both upstream packages first; an upstream instrumentation that still needs opentelemetry-util-genai cannot share an environment with this one.

Installation

pip uninstall opentelemetry-instrumentation-genai-langchain opentelemetry-util-genai
pip install observe-instrumentation-genai-langchain

LangGraph is optional. Graph node boundaries are instrumented from LangGraph 0.3.18 on; an older LangGraph still runs, with a warning that context is not propagated across its nodes.

See the examples directory for runnable workflow, agent, tools, and zero-code scenarios.

Usage

Call LangChainInstrumentor().instrument() once during startup, then build and invoke your graph as usual. The example below traces a simple two-node LangGraph StateGraph (START → researcher → summariser → END); the graph.invoke(...) call is recorded as a workflow span with the node model calls nested underneath.

from typing import Annotated, TypedDict

from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages

from observeinc.instrumentation.genai.langchain import LangChainInstrumentor

LangChainInstrumentor().instrument()

llm = ChatOpenAI(model="<your-model>", temperature=0)


class State(TypedDict):
    messages: Annotated[list, add_messages]
    research: str


def researcher(state: State) -> dict:
    response = llm.invoke(
        [
            SystemMessage(content="Provide 2-3 factual sentences."),
            HumanMessage(content=state["messages"][-1].content),
        ]
    )
    return {"research": response.content, "messages": [response]}


def summariser(state: State) -> dict:
    response = llm.invoke(
        [
            SystemMessage(content="Condense the text into one sentence."),
            HumanMessage(content=state["research"]),
        ]
    )
    return {"messages": [response]}


builder = StateGraph(State)
builder.add_node("researcher", researcher)
builder.add_node("summariser", summariser)
builder.add_edge(START, "researcher")
builder.add_edge("researcher", "summariser")
builder.add_edge("summariser", END)
graph = builder.compile()

# Recorded as a workflow span with the two node LLM calls nested underneath.
graph.invoke(
    {
        "messages": [HumanMessage(content="What is the capital of France?")],
        "research": "",
    }
)

Using with model-provider instrumentations

This package records a chat span for each LangChain chat model call. If the provider SDK underneath is instrumented too, each call is recorded twice: once here, and again by the SDK’s instrumentation, nested under it. Token usage and duration metrics count the call twice as well. Known cases:

  • observe-instrumentation-genai-openai, under ChatOpenAI

  • opentelemetry-instrumentation-botocore, under ChatBedrock and ChatBedrockConverse. opentelemetry-bootstrap -a install installs it whenever boto3 is present.

  • other tools that instrument the provider SDK, such as OpenInference or OpenLLMetry

opentelemetry-instrument enables every installed instrumentation, so having both installed is enough. Turn off the provider’s instrumentation, for example:

export OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=openai,botocore

or uninstall it. Disabling botocore removes spans for every AWS call (S3, DynamoDB, and so on), not just Bedrock. If you set up instrumentation in code, don’t call instrument() on the provider’s instrumentor.

Keep the provider’s instrumentation if the same process also needs it:

  • calls to the SDK outside LangChain

  • LangChain features this package doesn’t trace, such as embeddings (for example OpenAIEmbeddings)

  • openai-agents, whose model spans come only from the OpenAI instrumentation

LangChain chat calls are then still counted twice.

Retrieval Spans and Document Scores

When invoking LangChain retrievers (e.g., vectorstores, knowledge bases, or contextual compression retrievers), retrieval spans are recorded with the query and retrieved document IDs and scores.

When message content capture is enabled (OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY or SPAN_AND_EVENT), the retrieved documents are serialized into the gen_ai.retrieval.documents span attribute using the shared RetrievalDocument model, as a JSON array of objects with only id and score. Document text (previously recorded as content) and metadata are not captured. Query text capture is unchanged.

When available, relevance and similarity scores are captured in each document object under score:

  • Direct retrieval scores: extracted from metadata["score"] (populated by retrievers such as AmazonKnowledgeBasesRetriever, TavilySearchAPIRetriever, and vectorstore score-threshold searches).

  • Reranking scores: extracted from metadata["relevance_score"] (populated when retrievers are wrapped with rerankers via ContextualCompressionRetriever, such as CohereRerank).

  • Duck-typed / custom documents: extracted from a top-level score attribute or mapping key.

If a document has no score, or if the score is non-numeric or non-finite (NaN, Infinity), score is recorded as JSON null to ensure RFC 8259 JSON compliance. Missing document IDs are also recorded as null.

Configuration

By default, prompts and completions are not captured. To capture message content, set the environment variable OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT to one of NO_CONTENT, SPAN_ONLY, EVENT_ONLY, or SPAN_AND_EVENT.

Prompts and completions can instead be uploaded to external storage via a completion hook: set OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK=upload with OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH (install the upload extra by changing observe-util-genai to observe-util-genai[upload] in the install command above), or pass a custom CompletionHook programmatically, which takes precedence over the environment variable:

LangChainInstrumentor().instrument(completion_hook=my_hook)

Recording the User

To record user.id, pass it as user_id in the run’s metadata and set OBSERVE_GENAI_CAPTURE_USER_ID_FROM_LIBRARY=true. LangChain passes the metadata on to the run’s children, so every span the instrumentation creates for the run records it:

graph.invoke(inputs, config={"metadata": {"user_id": "user-123"}})

It is off by default. Without it, or when the metadata has no user_id, spans record the id set with observeinc.util.genai.user_id.using_user_id, if any. When both are set, the metadata value wins. With the async API, spans created by other instrumentations under the run, such as HTTP client spans, do not get the metadata value, for the same reason as the context propagation limitation below.

Known Limitations

Custom runnables that override invoke without starting a run do not inherit the parent run’s context in multi-input batch or abatch calls.

References

Metadata

Release files for observe-instrumentation-genai-langchain 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for observe-instrumentation-genai-langchain 0.1.0
File Interpreter ABI Platform Actions
observe_instrumentation_genai_langchain-0.1.0-py3-none-any.whl Python 3 none any Details for observe_instrumentation_genai_langchain-0.1.0-py3-none-any.whl

Release files / observe_instrumentation_genai_langchain-0.1.0-py3-none-any.whl

Download URL observe_instrumentation_genai_langchain-0.1.0-py3-none-any.whl
Size 42.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7cf15e444cad48990db7d765b851805b2b4443dc3365d6e79a83687e3f131937
BLAKE2b-256 checksum
How to use checksums
a102467e278caabdebe3a0eac9232b6d213ab2097db4f72e516dc0e2891f38a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Security for observe-instrumentation-genai-langchain 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page