A retrieval-augmented generation request is a chain of very different operations, and each one degrades for its own reasons. Collapsing them into a single "request took 4.2 seconds" number tells you nothing about which vendor to call or which query to rewrite.
- Query embedding. Turning the user's text into a vector is a network call to an embedding model. It fails slowly when the provider is rate limiting you or when your client retries without backoff.
- Vector search. This is an approximate nearest neighbor lookup, and its latency depends on index size, vector dimensionality, filter conditions, and memory pressure on the database host, as the OneUptime guide to vector database monitoring with OpenTelemetry lays out.
- Reranking. A cross-encoder scores each query-document pair individually, which is more accurate than vector similarity but costs a forward pass per candidate, so its cost scales with how many candidates you pass in, per Pinecone's explanation of two-stage retrieval.
- The model call. Generation latency grows with output tokens and prompt length, and it is the stage most likely to be the dominant cost when retrieval is healthy.
Because these four have different scaling laws, a single aggregate latency number will move for reasons you cannot see. Separate spans make the movement attributable.
OpenTelemetry's own primer defines the mechanics: a span holds a name, time-related data, structured events, and attributes, and spans with the same trace ID and a parent ID form a trace, per the OpenTelemetry observability primer. The traces concept page puts it plainly: a trace is a collection of structured logs with context, correlation, and hierarchy baked in, which can come from different processes and services. That is exactly the shape of a RAG pipeline, where the embedding call, the database, and the model provider are three different networks.
One warning before you instrument: the OpenTelemetry overview is explicit that instrumentation is a cross-cutting concern and that library authors must not reference SDK packages directly, only the API. In practice, this means your vector store wrapper and your model client wrapper should depend on the tracing API, and the SDK config should live at the application's entry point. Get this backwards and every library upgrade becomes a tracing migration.



