How do I trace an agent built with LangChain and deployed to Vercel functions?
Rius traces a LangChain agent on Vercel functions when you call init() before your chains run, wait for the LangChain integration to attach, and flush spans before each invocation ends. Name the agent with serviceName so it appears under one name in Rius. Chains, tools, retrievers and model calls arrive as a nested trace that mirrors your graph, with model, tokens and cost on each model call.
How it works
- Init before the first chain.
init()is synchronous. It finds@langchain/core’s callback manager and patches it, so nothing is passed in atinit(). Anything that runs through LangChain’s callbacks is traced: LCEL chains, agents and LangGraph nodes. - The integration attaches asynchronously.
init()returns a client, andawait client.readyresolves with the names of the integrations that attached. Await it before your first chain call, and check thatlangchainis in the list. - Export runs in the background. Spans are queued in the process and exported in batches by a background timer. The TypeScript SDK registers no process-exit hook, so nothing is flushed for you.
- Serverless freezes the process. Between invocations the runtime suspends it, and a frozen process exports nothing. The reliability guide says to flush at the end of every invocation in serverless runtimes.
- The agent name is your service name. The
serviceNameoption setsservice.name. The Agents page groups the agent under it, or underRIUS_AGENT_NAMEif you set that variable. instrumentModulesdoes not apply to LangChain. The page on integrations describes it for serverless deployments with file tracing, but onlyopenaiandanthropicaccept modules.langchainattaches differently.
Set it up
- Install the SDK, the LangChain instrumentation and the OpenTelemetry API. LangChain.js needs
@langchain/core, which your application already has.@langchain/core1.x requires Node 20 or newer.
npm install @glassflow-ai/rius @opentelemetry/api
npm install @arizeai/openinference-instrumentation-langchain- Call
init()once at module level, then inside your handlerawait client.ready, run your chain, andawait client.flush()in afinallyblock. Thefinallyblock sends the spans even when the chain throws.
import { init } from '@glassflow-ai/rius'
const client = init({
apiKey: 'ri_...',
serviceName: 'support-agent',
heartbeat: false,
})
export async function POST(request: Request) {
await client.ready // langchain is attached before the first chain call
try {
// build and run your chains exactly as before
return Response.json({ ok: true })
} finally {
const delivered = await client.flush() // export before the invocation ends
if (!delivered) console.warn('the most recent span export failed')
}
}-
Choose the agent name. Use one stable
serviceNameper agent, such assupport-agent. Every trace from that service is grouped under it. To change the grouping without changing the service name, setRIUS_AGENT_NAME. -
Keep
heartbeat: false. The docs recommend it for Lambda-style runtimes, where the process is frozen between invocations and heartbeats stop. The agent still appears from its traces, but it is marked no heartbeat and lists no instances. You can also setRIUS_HEARTBEAT=falseinstead of the option. -
Flush at the invocation boundary only, never inside a hot path in the middle of a request.
flush()blocks until the export completes. It returnsfalseon a timeout or when the latest export was rejected, such as a 401 from a bad API key. Afalsetherefore means your spans did not leave. -
Run one invocation that calls a model, then open the trace in the console. You should see the chain’s structure as nested spans, with the model call carrying model, tokens and cost. Step inputs, outputs and messages are content attributes, so the privacy controls apply to the whole tree.
The LangChain page covers the integration in full.
What you get
- A trace per invocation that reads like your execution graph: chains as CHAIN spans, tools as TOOL, retrievers as RETRIEVER, and model calls with model, token usage and messages.
- Cost per model call, computed by Rius from the model and token counts as a list-price estimate in US dollars. You never send a cost value.
- One stable agent name across invocations, so traces, cost and errors for the function roll up under a single agent.
- Spans that leave the process before the runtime freezes it, and a clear
falsefromflush()when an export fails. - Each model call counted once in tokens and cost when you also install a client-library integration such as OpenAI, while the LangChain span still shows the run’s total. Text-completion models (
BaseLLMsubclasses) are still counted twice.
When something else fits
- If your Vercel function calls the Vercel AI SDK instead of LangChain, follow the Vercel AI SDK recipe on the integrations page.
- If the same agent also runs as a long-lived server, the heartbeat suits that process. Leave it on there and call
client.shutdown()on graceful shutdown.