Skip to main content

Overview

In this tutorial we will build a retrieval agent using LangGraph. LangChain offers built-in agent implementations, implemented using LangGraph primitives. If deeper customization is required, agents can be implemented directly in LangGraph. This guide demonstrates an example implementation of a retrieval agent. Retrieval agents are useful when you want an LLM to make a decision about whether to retrieve context from a vectorstore or respond to the user directly. By the end of the tutorial we will have done the following:
  1. Fetch and preprocess documents that will be used for retrieval.
  2. Index those documents for semantic search and create a retriever tool for the agent.
  3. Build an agentic RAG system that can decide when to use the retriever tool.
Hybrid RAG

Concepts

We will cover the following concepts:

Setup

Let’s download the required packages and set our API keys:
Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph.

1. Preprocess documents

  1. Fetch documents to use in our RAG system. We will use three of the most recent pages from Lilian Weng’s excellent blog. We’ll start by fetching the content of the pages with a minimal helper built on requests and BeautifulSoup.
  1. Split the fetched documents into smaller chunks for indexing into our vectorstore:

2. Create a retriever tool

Now that we have our split documents, we can index them into a vector store that we’ll use for semantic search.
  1. Use an in-memory vector store and OpenAI embeddings:
  1. Create a retriever tool using the @tool decorator:
  1. Test the tool:

3. Generate query

Now we will start building components (nodes and edges) for our agentic RAG graph. Note that the components will operate on the MessagesState—graph state that contains a messages key with a list of chat messages.
  1. Build a generate_query_or_respond node. It will call an LLM to generate a response based on the current graph state (list of messages). Given the input messages, it will decide to retrieve using the retriever tool, or respond directly to the user. Note that we’re giving the chat model access to the retriever_tool we created earlier via .bind_tools:
  1. Try it on a random input:
Output:
  1. Ask a question that requires semantic search:
Output:

4. Grade documents

  1. Add a conditional edgegrade_documents—to determine whether the retrieved documents are relevant to the question. We will use a model with a structured output schema GradeDocuments for document grading. The grade_documents function will return the name of the node to go to based on the grading decision (generate_answer or rewrite_question):
  1. Run this with irrelevant documents in the tool response:
  1. Confirm that the relevant documents are classified as such:

5. Rewrite question

  1. Build the rewrite_question node. The retriever tool can return potentially irrelevant documents, which indicates a need to improve the original user question. To do so, we will call the rewrite_question node:
  1. Try it out:
Output:

6. Generate an answer

  1. Build generate_answer node: if we pass the grader checks, we can generate the final answer based on the original question and the retrieved context:
  1. Try it:
Output:

7. Assemble the graph

Now we’ll assemble all the nodes and edges into a complete graph:
  • Start with a generate_query_or_respond and determine if we need to call retriever_tool
  • Route to next step based on whether the model made tool calls:
    • If generate_query_or_respond returned tool_calls, call retriever_tool to retrieve context
    • Otherwise, respond directly to the user
  • Grade retrieved document content for relevance to the question (grade_documents) and route to next step:
    • If not relevant, rewrite the question using rewrite_question and then call generate_query_or_respond again
    • If relevant, proceed to generate_answer and generate final response using the ToolMessage with the retrieved document context
Visualize the graph:
SQL agent graph

8. Run the agentic RAG

Now let’s test the complete graph by running it with a question: