This release is a pre-release and may not be stable for production use.
OpenTelemetry 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.
Installation
pip install opentelemetry-instrumentation-genai-langchain
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 opentelemetry.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": "",
}
)
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: pip install opentelemetry-util-genai[upload]), or pass a custom CompletionHook programmatically, which takes precedence over the environment variable:
LangChainInstrumentor().instrument(completion_hook=my_hook)
Known Limitations
Context propagation to nested calls (such as auto-instrumented HTTP clients or database queries within tools) is not supported when using LangChain async API.
References
Release files for opentelemetry-instrumentation-genai-langchain 1.2b0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| opentelemetry_instrumentation_genai_langchain-1.2b0.tar.gz | 94.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| opentelemetry_instrumentation_genai_langchain-1.2b0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 126.3 kB
Release files / opentelemetry_instrumentation_genai_langchain-1.2b0.tar.gz
| Download URL | opentelemetry_instrumentation_genai_langchain-1.2b0.tar.gz |
|---|---|
| Size | 94.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ee9ef08066a57f8cb1130932faab4d857154da28dc90286fc054e635bf7f7348
|
|
BLAKE2b-256 checksum How to use checksums |
cebf45a30d515effc8e4fdb95a1c6ffeababdf0292ff14819fd29a5d74a9c151
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / opentelemetry_instrumentation_genai_langchain-1.2b0-py3-none-any.whl
| Download URL | opentelemetry_instrumentation_genai_langchain-1.2b0-py3-none-any.whl |
|---|---|
| Size | 31.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ddb3cbbaa3304798a53385defc6414ae6a3ea706b3163363cd829f5bfdfbdead
|
|
BLAKE2b-256 checksum How to use checksums |
cb62ac0acbd8442d74d1778cc0b91b3adfb92b7a9834a29d363b44d4ce4ddd9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log