how-to

How to Trace a LlamaIndex RAG App in 2026 - Three Ways, With Setup

Trace a LlamaIndex pipeline end-to-end - retrieval, reranking, and generation as nested spans - three ways - a native callback handler, OpenTelemetry via OpenInference, and eval hooks that attach RAG scores to spans.

Published:

Tracing a single OpenAI call is easy. Tracing a LlamaIndex app is a different problem, because one query is not one call - it is a pipeline of retrieval, reranking, and generation. When a RAG answer comes back wrong, you need to see each stage on its own, and that is exactly what a good trace gives you.

This guide shows three ways to instrument a LlamaIndex pipeline, with working setup for each, plus how to wire in eval hooks so your traces carry quality scores. If you want the concept first, see what LLM tracing is.

Why a RAG trace is a tree, not a line

A plain LLM app produces one span per call. A LlamaIndex query produces a tree:

  • A parent query span.
  • A child retrieval span - embed the question, search the vector store, return chunks.
  • Often a rerank span.
  • A child synthesis / LLM span - generate the answer over the retrieved chunks.

The whole reason to trace RAG is to see those stages separately. A bad answer with a clean retrieval span points at the model. A bad answer with junk in the retrieval span points at the retriever. Without the tree, you are guessing. That is the same retriever-or-generator diagnosis behind RAG evaluation metrics.

The three approaches

ApproachSetupVendor-neutral?Best tool here
Native callback handlerOne registration at startupNoLangfuse / Opik
OpenTelemetry via OpenInferenceOTel instrumentor setupYesArize Phoenix
Manual spansWrap stages yourselfDependsAny

Most teams want the first. The second is for OTel-standardized stacks. The third is a fallback for custom pipelines.

LlamaIndex ships an instrumentation system, and observability tools hook into it with a global handler. Register it once at startup and every query is traced automatically - no changes to your query code.

Both Langfuse and Opik provide a LlamaIndex integration built on this pattern. The setup shape is three steps (illustrative - verify against current docs, this category ships breaking changes monthly):

pip install langfuse llama-index
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
# Register the handler once, at app startup (illustrative)
from langfuse.llama_index import LlamaIndexInstrumentor

LlamaIndexInstrumentor().start()

# Your normal LlamaIndex code - unchanged
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

docs = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(docs)
response = index.as_query_engine().query("What is the refund window?")

That single registration is the whole integration. Every query() from then on fans out into the retrieval and generation spans described above, with inputs, outputs, token counts, cost, and latency captured per stage. Opik works the same way with its native LlamaIndex integration and its own SDK.

Why this wins for most stacks - near-zero code, and the tool observes rather than sits in your request hot path, so a tracing backend hiccup does not break your query. The same argument we make for the SDK-wrapper pattern in how to trace OpenAI API calls.

Approach 2 - OpenTelemetry via OpenInference (the standards-clean route)

If your organization has standardized on OpenTelemetry, instrument LlamaIndex through the OpenInference conventions and emit standard OTel spans. Arize Phoenix is built on OpenTelemetry and its own OpenInference semantic-convention project, and it is framework-agnostic - it works well beyond LangChain, which makes it a natural fit for LlamaIndex. It also runs locally in under a minute, so you get a trace UI on your laptop fast.

The setup shape (illustrative):

pip install arize-phoenix openinference-instrumentation-llama-index llama-index
# Illustrative - register the OpenInference instrumentor
import phoenix as px
from openinference.instrumentation.llama_index import LlamaIndexInstrumentor

px.launch_app()  # local trace UI
LlamaIndexInstrumentor().instrument()

# LlamaIndex code below is unchanged and now emits OTel spans

The payoff is portability - your instrumentation is standard OTel, so you can repoint it at any OTLP backend later without touching app code. Both Langfuse and Opik also expose OTLP ingestion, so you are not locked to Phoenix. The cost is that OTel is more setup than a one-line handler, so reach for it when OTel is already a requirement. One license note - the Phoenix server is Elastic License 2.0, source-available rather than OSI open source, which only bites if you plan to resell it as a hosted service. For internal use it behaves like open source. More context in how to set up LLM tracing.

Approach 3 - manual spans (the fallback)

If you have a heavily customized pipeline that does not fit the callback handler, you can wrap each stage in a span yourself using the tool’s SDK - a parent span for the query, child spans for retrieval and generation. This is the most code and the most error-prone, so treat it as a fallback for the cases the automatic instrumentation cannot reach.

Wiring in eval hooks

Tracing tells you what happened. Evaluation tells you how good it was. The power move is to attach scores to the spans you just captured. Once retrieval and generation are separate spans, run RAG metrics against each and attach the scores back to the trace - faithfulness on the generation span to catch hallucination, and context precision and recall on the retrieval span.

Both Langfuse and Opik support scoring traces this way, with LLM-as-judge scorers or custom functions, and both can run online evaluation on live production traffic - Opik markets online evaluation as a core feature, and Langfuse lets you attach LLM-as-judge and custom scores to any trace. That closes the loop - the trace shows the pipeline, the scores grade it, and together they tell you which stage to fix. The full workflow is in how to evaluate RAG.

Which tool for LlamaIndex tracing?

  • You want the cleanest setup, actively developed, free to start - the native handler on Langfuse (MIT, self-host free, $29/mo cloud) or Opik (Apache-2.0, cheapest cloud at $19/mo, native LlamaIndex integration). This is the default.
  • You have standardized on OpenTelemetry - instrument via OpenInference into Arize Phoenix or any OTLP backend, mindful of the ELv2 license on the server.
  • You want tracing plus built-in online RAG scoring - Opik or Langfuse, which attach eval scores to the same spans.

Bottom line - trace LlamaIndex with a native callback handler, get the full retrieval-plus-generation span tree for one line of setup, then attach RAG scores so every trace carries a quality signal. For the wider field, see best LLM tracing tools and best RAG evaluation tools. Code shapes here follow each tool’s standard integration pattern - verify against current docs, and every price was read from each vendor’s own pages on 23 July 2026.

Frequently Asked Questions

How do I trace a LlamaIndex application?

The cleanest way is a native callback handler. Tools like Langfuse and Opik ship a LlamaIndex integration that hooks into LlamaIndex's instrumentation system, so once you register the handler at startup, every query fans out into nested spans - retrieval, reranking, LLM generation - with inputs, outputs, tokens and latency, and no per-call code changes. The alternative is OpenTelemetry - Arize Phoenix instruments LlamaIndex through the OpenInference conventions and emits standard OTel spans. Both give you the full RAG trace tree; the callback handler is less setup, OTel is more vendor-neutral.

Why is tracing a RAG app harder than tracing a single LLM call?

Because a RAG query is not one call - it is a pipeline. A single LlamaIndex query triggers an embedding of the question, a vector search, often a reranking step, then an LLM generation over the retrieved chunks. When the answer is bad, you need to see each stage separately to know whether retrieval pulled the wrong chunks or the model ignored good ones. Tracing captures that as a tree of nested spans - a parent query span with child spans for retrieval and generation - so you can open the exact stage that failed instead of guessing.

Can I trace LlamaIndex with OpenTelemetry?

Yes. Arize Phoenix instruments LlamaIndex through the OpenInference semantic conventions and emits standard OpenTelemetry spans, which you can send to Phoenix or any OTLP-compatible backend. Langfuse and Opik also expose OTLP ingestion endpoints alongside their native LlamaIndex handlers. The OpenTelemetry route is the most vendor-neutral - your instrumentation is standard OTel, so you can repoint it at a different backend later without touching app code - but it is more setup than a one-line callback handler.

How do I add evaluation to a traced LlamaIndex app?

Trace first, then attach scores to the spans. Once retrieval and generation are captured as separate spans, you can run RAG metrics - faithfulness on the generation span, context precision and recall on the retrieval span - and attach the scores back to the trace. Langfuse and Opik both support scoring traces this way, either with LLM-as-judge scorers or custom functions, and they can run online evaluation on live production traffic. That closes the loop - the trace shows you what happened, and the attached scores tell you how good each stage was.

Explore More

Free Newsletter

Get the LLM Evals Newsletter

Platform comparisons, pricing changes and eval technique deep-dives. No spam.

Related Articles