Skip to Content

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 at init(). Anything that runs through LangChain’s callbacks is traced: LCEL chains, agents and LangGraph nodes.
  • The integration attaches asynchronously. init() returns a client, and await client.ready resolves with the names of the integrations that attached. Await it before your first chain call, and check that langchain is 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 serviceName option sets service.name. The Agents page groups the agent under it, or under RIUS_AGENT_NAME if you set that variable.
  • instrumentModules does not apply to LangChain. The page on integrations describes it for serverless deployments with file tracing, but only openai and anthropic accept modules. langchain attaches differently.

Set it up

  1. Install the SDK, the LangChain instrumentation and the OpenTelemetry API. LangChain.js needs @langchain/core, which your application already has. @langchain/core 1.x requires Node 20 or newer.
npm install @glassflow-ai/rius @opentelemetry/api npm install @arizeai/openinference-instrumentation-langchain
  1. Call init() once at module level, then inside your handler await client.ready, run your chain, and await client.flush() in a finally block. The finally block 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') } }
  1. Choose the agent name. Use one stable serviceName per agent, such as support-agent. Every trace from that service is grouped under it. To change the grouping without changing the service name, set RIUS_AGENT_NAME.

  2. 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 set RIUS_HEARTBEAT=false instead of the option.

  3. Flush at the invocation boundary only, never inside a hot path in the middle of a request. flush() blocks until the export completes. It returns false on a timeout or when the latest export was rejected, such as a 401 from a bad API key. A false therefore means your spans did not leave.

  4. 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 false from flush() 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 (BaseLLM subclasses) 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.

Still stuck? Get help

Last updated on