LangChain
Use Confident AI for LLM observability and evals for LangChain
Overview
LangChain is a framework for building LLM applications. Confident AI traces and evaluates your LangChain applications automatically through confident-trace, Confident AI's OpenTelemetry-native tracing SDK for Python and TypeScript — call init() once and your chain code stays exactly as it is.
The integration captures the following spans from your LangChain application:
- Chain and runnable spans — one span per chain and each intermediate runnable inside it, with their inputs and outputs
- LLM spans — model name, token usage, finish reasons, and input/output messages (including tool calls made by the model)
- Tool spans — tool name, input parameters, and output, nested under the chain that ran them
- Retriever spans — query input and retrieved document text
| Runtime | Requirements | Setup |
|---|---|---|
| Python | Python 3.10+, LangChain 1.x | Call init() before running the chain |
| TypeScript | Node.js 22+, @langchain/core >=1.2.9 <2 | Call init() and launch your entry point with the preload |
Auto-Instrument
Install Dependencies
Run the following command to install
confident-tracealongside LangChain:pip install confident-trace 'langchain>=1,<2' 'langchain-openai>=1,<2'tsxis only needed if you run TypeScript source directly.npm install confident-trace '@langchain/core@>=1.2.9 <2' @langchain/openai@1 npm install -D tsxyarn add confident-trace '@langchain/core@>=1.2.9 <2' @langchain/openai@1 yarn add -D tsxSet Your API Keys
Get your Confident AI Project API key and set it as an environment variable, along with your model provider's key:
export CONFIDENT_API_KEY="<your-confident-project-key>" export OPENAI_API_KEY="<your-openai-key>"Instrument LangChain
Call
init()once before running your chain. It detects LangChain automatically and attaches its callback handler for you — there's no handler to pass toinvoke, and no tracing extra to install.main.py from confident_trace import init, shutdown from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_openai import ChatOpenAI init() prompt = ChatPromptTemplate.from_template("Explain {topic} in one sentence.") chain = prompt | ChatOpenAI(model="gpt-4.1-mini") | StrOutputParser() try: print(chain.invoke({"topic": "OpenTelemetry"})) finally: shutdown()src/index.ts import { init } from "confident-trace"; import { ChatPromptTemplate } from "@langchain/core/prompts"; import { StringOutputParser } from "@langchain/core/output_parsers"; import { ChatOpenAI } from "@langchain/openai"; const runtime = init(); const prompt = ChatPromptTemplate.fromTemplate("Explain {topic} in one sentence."); const chain = prompt .pipe(new ChatOpenAI({ model: "gpt-4.1-mini" })) .pipe(new StringOutputParser()); try { console.log(await chain.invoke({ topic: "OpenTelemetry" })); } finally { await runtime.shutdown(); }TypeScript needs one more thing: launch your entry point with the
confident-trace/registerpreload so the SDK can hook@langchain/coreas Node loads it.init()handles export, the preload handles instrumentation — you need both.Run LangChain
Run your script to send the trace to Confident AI:
python main.py# Running TypeScript source directly node --import tsx --import confident-trace/register src/index.ts # Running compiled JavaScript node --import confident-trace/register dist/index.jsTo make this your normal startup command, add it to your
package.jsonscripts:package.json { "scripts": { "start": "node --import confident-trace/register dist/index.js", "dev": "node --import tsx --import confident-trace/register src/index.ts" } }Done ✅. Open the Observatory in your Confident AI project to inspect the trace and its chain, model, and parser spans.
What Gets Captured
The integration mirrors the hierarchy LangChain reports through its callbacks:
- Chains and runnables — one span per chain and each intermediate runnable inside it. These are plain spans; a chain's name alone doesn't mark it as an agent (wrap the invocation in an agent-typed
spanif you want an agent-typed root — see custom application spans). - Model calls — LLM spans with model information, token usage, finish reasons, and normalized input/output messages.
- Tool executions — tool spans that follow their framework parent. The model's tool request appears on the model span's output.
- Retrievers — retriever spans with retrieved document text.
Chain state, tool values, and document text follow the content policy. Size limits are disabled by default, but you can configure a limit or redact content before export.
Streaming
Streaming is traced the same way as invoke; the model span finishes when the stream does. These snippets replace the chain.invoke call inside the quickstart's try block.
stream = chain.stream({"topic": "OpenTelemetry"})
try:
for chunk in stream:
print(chunk, end="", flush=True)
finally:
stream.close()Also supported: ainvoke, astream, batch operations, and astream_events v2.
const stream = await chain.stream({ topic: "OpenTelemetry" });
for await (const chunk of stream) process.stdout.write(chunk);Set Trace Span Properties
Use a trace context to add properties you know before the call starts. It creates no extra span; the trace started by chain.invoke() inherits the tags, metadata, user ID, and customer ID.
from confident_trace import init, trace_context
from langchain_openai import ChatOpenAI
init()
model = ChatOpenAI(model="gpt-4.1-mini")
chain = model
with trace_context(
tags=["support"],
metadata={"release": "2026-09"},
user_id="user-42",
customer_id="customer-7",
):
result = chain.invoke("Explain OpenTelemetry in one sentence.")import { init, traceContext } from "confident-trace";
import { ChatOpenAI } from "@langchain/openai";
init();
const chain = new ChatOpenAI({ model: "gpt-4.1-mini" });
const result = await traceContext(
{
tags: ["support"],
metadata: { release: "2026-09" },
userId: "user-42",
customerId: "customer-7",
},
() => chain.invoke("Explain OpenTelemetry in one sentence."),
);See users and customers to set an optional display name alongside each ID, and trace context for every supported trace property and update behavior.
Instrumenting Multi-Turn
You do not need turn() when one LangChain entry-point call is already one conversational turn—the integration creates that turn's trace automatically. Use turn() when you want to define the boundary yourself, such as grouping two sequential LangChain calls into one turn. Reuse the same thread ID on later turns to group them into one conversation.
from confident_trace import init, turn
init()
with turn("support-turn", thread_id="chat-42"):
context = chain.invoke("Find the relevant account details.")
answer = chain.invoke(f"Answer the user using this context: {context.content}")import { init, turn } from "confident-trace";
init();
const answer = await turn({ name: "support-turn", threadId: "chat-42" }, async () => {
const context = await chain.invoke("Find the relevant account details.");
return chain.invoke(`Answer the user using this context: ${context.content}`);
});See threads for thread I/O, turn IDs, and user IDs.
Troubleshooting
- No trace: make sure
init()runs before the chain executes, and that the process reachesshutdown()so buffered spans are flushed. - Incomplete streams: consume or close streams before
shutdown().
- No trace: make sure
init()runs before the chain executes, that your start command includes--import confident-trace/register, and that the process reachesshutdown()so buffered spans are flushed.runtime.getInstrumentationStatus()tells you whether the LangChain hook attached. - Incomplete streams: consume or close streams before
shutdown(). - Unexpected parentage: callbacks don't wrap your application code. Wrap unrelated work that needs a common parent in an explicit
span, as in set trace span properties.
For general setup issues, see troubleshooting.
Disable LangChain Instrumentation
Pass init() a list of integration identifiers to opt in to only those integrations. The identifier for LangChain is "langchain" in Python and TypeScript; omit it to disable this integration. An empty list disables all automatic instrumentation:
from confident_trace import init
init(instrumentations=())
# Use ("langchain",) to opt in; omit "langchain" to disable it.import { init } from "confident-trace";
init({ instrumentations: [] });
// Use ["langchain"] to opt in; omit "langchain" to disable it.This turns off Confident AI's automatic instrumentation; calls made after initialization are not instrumented by this integration.
Next Steps
Online Evals
Run evaluations on traces and spans in real-time as they're ingested into Confident AI to monitor AI quality in production.
LangGraph Integration
Building agents with LangGraph? The same integration traces graphs, nodes, and checkpointed conversations.
Last updated on