How do I trace an agent built with LlamaIndex and deployed to Vercel functions?
Rius traces a LlamaIndex agent on Vercel functions when you call rius.init once, flush spans at the end of every invocation, and set service_name to name the agent. The LlamaIndex integration is Python only, so it applies to a Python function. It turns on automatically at init and records retrieval steps, embedding calls and model calls with tokens and cost. Cost is computed by Rius from the spans.
How it works
- Init. With a default
rius.init(), every installed integration is enabled automatically. The LlamaIndex instrumentation then records each query as a nested trace: retrieval steps as RETRIEVER spans, embedding calls as EMBEDDING spans, and synthesis model calls as LLM spans with model, token usage and messages. - Export. Spans are queued in the process and exported in batches from a background thread. A serverless runtime freezes the process between invocations, and a frozen background thread exports nothing. So you flush explicitly at the end of each invocation.
- Heartbeat. By default the SDK pings Rius for the process’s whole lifetime. A serverless runtime suspends the process between invocations, so the pings stop and the instance flaps between alive and stale or gone. Turn the heartbeat off in this runtime.
- Agent name. Rius finds agents from traces, with no registration. The agent is grouped under the name you give
service_name, or underRIUS_AGENT_NAMEif you set it.
The LlamaIndex integration page covers what lands in the trace. The Integrations page lists every supported library and framework.
Set it up
- Install the instrumentation next to LlamaIndex. The extra installs the instrumentation, not
llama-indexitself:
pip install "glassflow-rius[llama-index]" llama-index- Call
rius.initonce, before you build indexes and query engines, and keep it outside the code that runs on each request so a warm function reuses it. Setservice_nameto the name you want on the Agents page, and turn the heartbeat off withheartbeat=False. - Flush at the end of every invocation, in a
finallyblock so a failed run still exports its spans. Flush at the invocation boundary only. It blocks until the export completes, so never call it inside request handlers or other hot paths.
import rius
client = rius.init(
api_key="ri_...",
service_name="my-agent",
heartbeat=False,
)
# build indexes and query engines exactly as before
def run(query): # your own function, called once per invocation
try:
return query_engine.query(query)
finally:
client.flush(timeout_millis=30_000)- Invoke the function once, then open the trace in the console. The query appears as nested spans, with the LLM leaf carrying model, tokens and cost.
The shutdown and retry behavior behind step 3 is on the Reliability page. A failed export is dropped, never buffered for later, and a failure never raises into your code.
What you get
- One trace per query, with retrieval, embedding and model-call spans nested the way LlamaIndex runs them.
- Tokens and a cost per model call, as a list-price estimate in US dollars.
- A retriever span whose output shows what the model was given to work with, which is where RAG debugging usually starts.
- An agent named by your
service_name, with its traces, cost and errors in one place. - With the heartbeat off, the agent is marked no heartbeat and lists no instances. Its traces, cost and errors still appear.
- If the
openaiextra is also installed, the underlying call is traced as a second LLM span under the LlamaIndex span. Sinceglassflow-rius1.1.1 the call is counted once in tokens and cost.
When something else fits
- If your function uses LlamaIndex.TS, there is no LlamaIndex integration in TypeScript. The OpenAI integration still traces provider calls made through the OpenAI client, and manual generations cover the pipeline around them.
- If the work runs in a long-lived process rather than a frozen function, you can keep the heartbeat on and skip the per-invocation flush.
Related
Last updated on