{ "cells": [ { "cell_type": "markdown", "id": "a1b2c3d4", "metadata": {}, "source": [ "# Lesson 05 - Agentic RAG" ] }, { "cell_type": "markdown", "id": "b2c3d4e5", "metadata": {}, "source": [ "## Setup\n", "\n", "This notebook demonstrates the Agentic RAG (Retrieval-Augmented Generation) pattern using the Microsoft Agent Framework.\n", "\n", "**Prerequisites:**\n", "- `AZURE_SEARCH_SERVICE_ENDPOINT` — your Azure AI Search service endpoint\n", "- `AZURE_SEARCH_API_KEY` — your Azure AI Search API key\n", "- Azure OpenAI deployment configured via environment variables\n", "- Azure CLI authenticated (`az login`)" ] }, { "cell_type": "code", "execution_count": null, "id": "c3d4e5f6", "metadata": {}, "outputs": [], "source": [ "%pip install agent-framework azure-ai-projects azure-identity python-dotenv -q" ] }, { "cell_type": "code", "execution_count": null, "id": "d4e5f6a7", "metadata": {}, "outputs": [], "source": [ "import logging\n", "logging.getLogger(\"agent_framework.foundry\").setLevel(logging.ERROR)\n", "\n", "import os\n", "import asyncio\n", "import dotenv\n", "from typing import Annotated\n", "\n", "from agent_framework import tool\n", "from agent_framework.foundry import FoundryChatClient\n", "from azure.identity import DefaultAzureCredential\n", "\n", "dotenv.load_dotenv()\n", "\n", "endpoint = os.getenv(\"AZURE_AI_PROJECT_ENDPOINT\")\n", "deployment_name = os.getenv(\"AZURE_AI_MODEL_DEPLOYMENT_NAME\")\n", "\n", "missing = [k for k, v in {\n", " \"AZURE_AI_PROJECT_ENDPOINT\": endpoint,\n", " \"AZURE_AI_MODEL_DEPLOYMENT_NAME\": deployment_name\n", "}.items() if not v]\n", "\n", "if missing:\n", " raise ValueError(\n", " f\"Missing required environment variables: {', '.join(missing)}. \"\n", " \"Please set them as environment variables (e.g., in your .env file or shell environment).\"\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "e5f6a7b8", "metadata": {}, "outputs": [], "source": [ "# Create the Microsoft Foundry client\n", "client = FoundryChatClient(\n", " project_endpoint=endpoint,\n", " model=deployment_name,\n", " credential=DefaultAzureCredential()\n", ")" ] }, { "cell_type": "markdown", "id": "f6a7b8c9", "metadata": {}, "source": [ "## What is Agentic RAG?\n", "\n", "Traditional RAG follows a fixed pipeline: retrieve documents, then generate a response. **Agentic RAG** goes further by giving the agent autonomy to decide **when** and **how** to retrieve information.\n", "\n", "With Agentic RAG, the agent can:\n", "- **Decide** whether retrieval is needed before answering a question\n", "- **Choose** which data source or tool to query\n", "- **Evaluate** retrieved results and perform follow-up retrievals if the first attempt is insufficient\n", "- **Combine** information from multiple retrieval steps into a coherent answer\n", "\n", "This makes the agent more flexible and accurate compared to a static retrieve-then-generate pipeline." ] }, { "cell_type": "markdown", "id": "a7b8c9d0", "metadata": {}, "source": [ "## Creating a Search Tool\n", "\n", "In Agentic RAG, external data sources are wrapped as **tools** that the agent can invoke on demand. This lets the agent treat retrieval as just another action it can take, rather than a mandatory step.\n", "\n", "Below we define a travel knowledge base and expose it as a tool the agent can call to look up destination information." ] }, { "cell_type": "code", "execution_count": null, "id": "b8c9d0e1", "metadata": {}, "outputs": [], "source": [ "TRAVEL_KNOWLEDGE_BASE = {\n", " \"Barcelona\": \"Barcelona is Spain's cosmopolitan capital of Catalonia. Best visited Mar-May or Sep-Nov. Known for Gaudí architecture, La Rambla, beaches. Average daily cost: $150-200.\",\n", " \"Tokyo\": \"Tokyo is Japan's capital, mixing ultramodern with traditional. Best visited Mar-Apr (cherry blossoms) or Oct-Nov. Known for Shibuya, temples, sushi. Average daily cost: $200-250.\",\n", " \"Paris\": \"Paris is France's capital and a global center for art, fashion, and culture. Best visited Apr-Jun or Sep-Oct. Known for Eiffel Tower, Louvre, cuisine. Average daily cost: $180-250.\",\n", " \"Cape Town\": \"Cape Town sits on South Africa's southwest tip. Best visited Nov-Mar. Known for Table Mountain, wine regions, wildlife. Average daily cost: $100-150.\",\n", "}\n", "\n", "\n", "@tool(approval_mode=\"never_require\")\n", "def search_travel_knowledge(\n", " query: Annotated[str, \"The search query about a travel destination\"]\n", ") -> str:\n", " \"\"\"Search the travel knowledge base for destination information.\"\"\"\n", " results = []\n", " for destination, info in TRAVEL_KNOWLEDGE_BASE.items():\n", " if query.lower() in destination.lower() or any(\n", " word in info.lower() for word in query.lower().split()\n", " ):\n", " results.append(f\"**{destination}**: {info}\")\n", " return (\n", " \"\\n\\n\".join(results)\n", " if results\n", " else \"No matching destinations found in the knowledge base.\"\n", " )" ] }, { "cell_type": "markdown", "id": "c9d0e1f2", "metadata": {}, "source": [ "## Building the RAG Agent\n", "\n", "Now we create an agent that is instructed to **always retrieve information before answering**. The agent uses the `search_travel_knowledge` tool to ground its responses in the knowledge base rather than relying on its own training data." ] }, { "cell_type": "code", "execution_count": null, "id": "d0e1f2a3", "metadata": {}, "outputs": [], "source": [ "agent = client.as_agent(\n", " tools=[search_travel_knowledge],\n", " name=\"TravelRAGAgent\",\n", " instructions=\"\"\"You are a knowledgeable travel advisor. Before answering questions about destinations:\n", "1. ALWAYS search the travel knowledge base first\n", "2. Base your answers on retrieved information\n", "3. If information is not in the knowledge base, say so clearly\n", "4. Provide specific details like costs, best seasons, and highlights.\"\"\",\n", ")\n", "\n", "response = await agent.run(\n", " \"I'm interested in visiting somewhere with great architecture. What destinations would you recommend?\",\n", " )\n", "print(response)" ] }, { "cell_type": "markdown", "id": "e1f2a3b4", "metadata": {}, "source": [ "## Iterative Retrieval — The Maker-Checker Pattern\n", "\n", "A key advantage of Agentic RAG is **iterative retrieval**. The agent can perform multiple rounds of search to verify, refine, or expand on its initial findings — similar to a \"maker-checker\" workflow:\n", "\n", "1. **Maker step**: The agent retrieves initial information and drafts a response.\n", "2. **Checker step**: The agent performs additional retrievals to verify details or fill gaps.\n", "\n", "Below, the agent is asked a question that requires comparing multiple destinations, prompting it to search several times." ] }, { "cell_type": "code", "execution_count": null, "id": "f2a3b4c5", "metadata": {}, "outputs": [], "source": [ "checker_agent = client.as_agent(\n", " tools=[search_travel_knowledge],\n", " name=\"TravelRAGCheckerAgent\",\n", " instructions=\"\"\"You are a meticulous travel advisor who double-checks recommendations.\n", "When answering travel questions:\n", "1. Search for relevant destinations first\n", "2. For each destination found, search again with the destination name to get full details\n", "3. Compare the options using verified information\n", "4. Present a final recommendation with specific costs, best travel times, and highlights\n", "5. If any detail seems incomplete, search once more to confirm before responding.\"\"\",\n", ")\n", "\n", "response = await checker_agent.run(\n", " \"I have a $175/day budget and want to travel in April. Which destinations fit my budget and timing?\",\n", " )\n", "print(response)" ] }, { "cell_type": "markdown", "id": "a3b4c5d6", "metadata": {}, "source": [ "## Summary\n", "\n", "In this lesson you learned how to build an **Agentic RAG** system using the Microsoft Agent Framework:\n", "\n", "- **Agentic RAG** lets agents autonomously decide when to retrieve information, making retrieval dynamic rather than fixed.\n", "- **Tools as data sources**: External knowledge bases (like Azure AI Search) are wrapped as tools the agent can invoke.\n", "- **Iterative retrieval**: The maker-checker pattern enables the agent to perform multiple retrieval rounds — searching, verifying, and refining — before producing a final answer.\n", "\n", "In production, you would replace the in-memory `TRAVEL_KNOWLEDGE_BASE` with a real Azure AI Search index to handle large-scale travel document retrieval." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.13" } }, "nbformat": 4, "nbformat_minor": 5 }