How do I trace an agent built with LlamaIndex and deployed to a Kubernetes deployment?
Rius traces a LlamaIndex agent in a Kubernetes deployment when you call init once at container startup, before you build your indexes and query engines. Call shutdown when the pod stops, so the last spans leave the process. Give every replica the same agent name, and each pod appears as its own instance of that agent. The LlamaIndex integration is Python only.
How it works
- One init per process. The LlamaIndex instrumentation attaches when
init()runs, and every installed integration is turned on automatically. Put the call in your entrypoint module, not in a request handler, so it runs once per container process. - Spans leave in the background. Rius queues spans in memory and exports them in batches from a background thread, so tracing does not sit on your request path. A pod serving traffic keeps exporting continuously.
- Shutdown is your job in a pod. Pod termination arrives as a
SIGTERM. Rius installs no signal handlers, because a library must not own process signals, and Python’s default response toSIGTERMends the process without running its exit hook. So callclient.shutdown()from your own handler to drain the queue and send the finalstoppedping. - Each pod is an instance. Every process that runs
init()has its own instance ID. Replicas that share one agent name group under that agent on the Agents view as separate instances. If you run gunicorn inside the pod, each worker shows as one instance. - Structure and cost come from the framework. A query becomes a nested trace: retrieval steps as retriever spans, embedding calls as embedding spans, and synthesis model calls as model-call spans with tokens and messages. Rius computes cost from the model and token counts. If the
openaiextra is also installed, a call is still counted once in tokens and cost onglassflow-rius1.1.1 or later.
Set it up
-
Add the integration to your image. Install the extra together with LlamaIndex, for example in your Dockerfile or requirements file. The extra installs only the instrumentation, so
llama-indexmust be in the environment too. Without it,init()logs aDependencyConflictand the integration stays off.pip install "glassflow-rius[llama-index]" llama-index -
Call
init()once at startup, before you build indexes and query engines, and shut the client down onSIGTERM. Theservice_nameis the name your agent is grouped under, so pick one name and use it in every replica. If your server already handlesSIGTERM, such as uvicorn, callclient.shutdown()in its shutdown hook instead, for example a FastAPI lifespan.import signal import sys import rius client = rius.init(service_name="my-agent") # reads RIUS_API_KEY from the environment def on_sigterm(signum, frame): client.shutdown() # drain queued spans, send the stopped heartbeat sys.exit(0) signal.signal(signal.SIGTERM, on_sigterm) # build indexes and query engines exactly as beforeRIUS_AGENT_NAMEis optional and defaults to the service name. SetRIUS_MAIN_AGENT_VERSIONto the version you are rolling out, because the Agents page compares agent versions by it. Keep the heartbeat on, since a deployment is a long-lived process and heartbeats are what give each pod an instance. -
Deploy with the key in a Secret rather than baked into the image. Store the API key in a Secret named
riuswith the keyapi-key, and reference it from the container. Kubernetes sendsSIGTERMand waitsterminationGracePeriodSeconds(30 by default) beforeSIGKILL. A batch export can take up to 30 seconds by default, so give the pod enough time. Start the process in exec form so it receives the signal as PID 1.apiVersion: apps/v1 kind: Deployment metadata: name: my-agent spec: replicas: 2 selector: matchLabels: app: my-agent template: metadata: labels: app: my-agent spec: terminationGracePeriodSeconds: 60 containers: - name: agent image: registry.example.com/my-agent:1.4.0 env: - name: RIUS_SERVICE_NAME value: my-agent - name: RIUS_API_KEY valueFrom: secretKeyRef: name: rius key: api-keyNever call
flush()inside a request handler, because it blocks until the export completes. -
Run one query against your index, then open the trace in the console. You should see the pipeline as nested spans, with the model-call span carrying model, tokens and cost. The LlamaIndex page lists exactly what is captured, and Reliability covers batching, retries and shutdown in full.
What you get
- A nested trace for each query: retriever, embedding and model-call spans, with the retriever’s output showing what the model was given to work with.
- Tokens and a list-price cost estimate in US dollars on each model call, computed by Rius.
- One agent on the Agents view for the whole deployment, with one instance per pod. A pod that stops cleanly reports a
stoppedinstance, while one killed without a shutdown reportsgone, which is the crash signal. - Retrieved document content and messages are content attributes, so Rius privacy controls apply to them. Document ids and scores stay visible even with content stripped.
When something else fits
- If your agent is written with LlamaIndex.TS, there is no LlamaIndex integration in TypeScript. The OpenAI integration still traces the provider calls, and manual generations cover the pipeline around them.
- If a pod’s process is short-lived, such as a batch job or a CronJob, call
flush()before it exits instead of relying on a long-running shutdown path. - For other frameworks and clients, see the Integrations support matrix.