LangWatch captures Retrieval-Augmented Generation (RAG) data for evaluations and agent testing.
Retrieval Augmented Generation (RAG) is a common pattern in LLM applications where you first retrieve relevant context from a knowledge base and then use that context to generate a response. LangWatch provides specific ways to capture RAG data, enabling better observability and evaluation of your RAG pipelines.Capturing the contexts (retrieved documents) used by the LLM enables the following in LangWatch:
You can manually create a RAG span by using tracer.withActiveSpan() with type: "rag". Inside this span, you should perform the retrieval and then update the span with the retrieved contexts.The contexts should be a list of LangWatchSpanRAGContext objects. The LangWatchSpanRAGContext object allows you to provide more metadata about each retrieved chunk, such as document_id, chunk_id, and content.Here’s an example:
import { setupObservability } from "langwatch/observability/node";import { getLangWatchTracer } from "langwatch";import type { LangWatchSpanRAGContext } from "langwatch/observability";// Setup observabilitysetupObservability();const tracer = getLangWatchTracer("rag-example");async function generateAnswerFromContext(contexts: string[], userQuery: string): Promise<string> { return await tracer.withActiveSpan("GenerateAnswerFromContext", async (span) => { span.setType("llm"); span.setRequestModel("gpt-6-luna"); // Simulate LLM call using the contexts await new Promise(resolve => setTimeout(resolve, 500)); const response = `Based on the context, the answer to '${userQuery}' is...`; // You can update the LLM span with model details, token counts, etc. span.setInput("text", `Contexts: ${contexts.join(", ")}\nQuery: ${userQuery}`); span.setOutput("text", response); return response; });}async function performRAG(userQuery: string): Promise<string> { return await tracer.withActiveSpan("My Custom RAG Process", async (span) => { span.setType("rag"); // 1. Retrieve contexts // Simulate retrieval from a vector store or other source await new Promise(resolve => setTimeout(resolve, 300)); const retrievedDocs = [ "LangWatch helps monitor LLM applications.", "RAG combines retrieval with generation for better answers.", "TypeScript is a popular language for AI development." ]; // Update the current RAG span with the retrieved contexts // You can pass a list of strings directly const ragContexts: LangWatchSpanRAGContext[] = retrievedDocs.map((content, index) => ({ document_id: `doc${index + 1}`, chunk_id: `chunk${index + 1}`, content })); span.setRAGContexts(ragContexts); // Alternatively, for simpler context information: // span.setRAGContexts(retrievedDocs.map(content => ({ // document_id: "unknown", // chunk_id: "unknown", // content // }))); // 2. Generate answer using the contexts const finalAnswer = await generateAnswerFromContext(contexts: retrievedDocs, userQuery: userQuery); // The RAG span automatically captures its input (userQuery) and output (finalAnswer) // if dataCapture is not set to "none". return finalAnswer; });}async function handleUserQuestion(question: string): Promise<string> { return await tracer.withActiveSpan("User Question Handler", async (span) => { span.setInput("text", question); span.setAttributes({ "user_id": "example_user_123" }); const answer = await performRAG(userQuery: question); span.setOutput("text", answer); return answer; });}// Example usageasync function main() { const userQuestion = "What is LangWatch used for?"; const response = await handleUserQuestion(userQuestion); console.log(`Question: ${userQuestion}`); console.log(`Answer: ${response}`);}main().catch(console.error);
In this example:
performRAG uses tracer.withActiveSpan() with type: "rag".
Inside performRAG, we simulate a retrieval step.
span.setRAGContexts(ragContexts) is called to explicitly log the retrieved documents.
The generation step (generateAnswerFromContext) is called, which itself can be another span (e.g., an LLM span).