From c36a157b2f109c3e032e3aa1bc1167fbc6b303a6 Mon Sep 17 00:00:00 2001 From: Matt Gotteiner Date: Mon, 8 Jun 2026 14:00:22 -0700 Subject: [PATCH] Align agentic-retrieval-pipeline-example notebook with validated KB flow - Surface 'Knowledge Bases' and 'Foundry IQ' terminology in notebook title/description - Add AzureKeyCredential support: optional AZURE_SEARCH_API_KEY and AZURE_OPENAI_API_KEY - Add azure_openai_resource_endpoint() helper to normalize endpoint URLs - Use search_credential throughout all Search SDK calls - Add semantic_configuration_name and page_chunk field to knowledge source parameters - Remove KnowledgeRetrievalOutputMode enum; use output_mode='extractiveData' string - Fix MCP endpoint API version: 2025-11-01-Preview -> 2026-05-01-preview - Add endpoint.rstrip('/') to MCP URL construction - Add timeout=60 to requests.get for document download - Fix extra_body key: 'agent_reference' -> 'agent' in responses.create - Fix delete_index(index) -> delete_index(index_name) in cleanup cell - Add optional AZURE_SEARCH_API_KEY and AZURE_OPENAI_API_KEY to sample.env Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../agent-example.ipynb | 44 ++++++++++++------- agentic-retrieval-pipeline-example/sample.env | 2 + 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/agentic-retrieval-pipeline-example/agent-example.ipynb b/agentic-retrieval-pipeline-example/agent-example.ipynb index 0d749175e..68513e7d3 100644 --- a/agentic-retrieval-pipeline-example/agent-example.ipynb +++ b/agentic-retrieval-pipeline-example/agent-example.ipynb @@ -5,11 +5,11 @@ "id": "5e3d4685", "metadata": {}, "source": [ - "# Tutorial: Agentic retrieval using Azure AI Search and Foundry Agent Service\n", + "# Tutorial: Build a Foundry IQ knowledge base using Azure AI Search\n", "\n", - "This notebook creates an agentic retrieval pipeline built on Azure AI Search and Foundry Agent Service. You create a knowledge base, an agent in Foundry Agent Service, and an MCP tool for orchestration.\n", + "This notebook creates a **Foundry IQ knowledge base** — an end-to-end agentic retrieval pipeline built on Azure AI Search and Foundry Agent Service. You create a knowledge base in Azure AI Search, an MCP tool connection in Microsoft Foundry, and an agent that uses the knowledge base for retrieval.\n", "\n", - "For prerequisites and setup instructions, see [Tutorial: Build an end-to-end agentic retrieval solution using Azure AI Search](https://learn.microsoft.com/azure/search/search-agentic-retrieval-how-to-pipeline)." + "For prerequisites and setup instructions, see [Tutorial: Build an end-to-end agentic retrieval solution using Azure AI Search](https://learn.microsoft.com/azure/search/agentic-retrieval-how-to-create-pipeline)." ] }, { @@ -31,22 +31,30 @@ "source": [ "import os\n", "\n", + "from azure.core.credentials import AzureKeyCredential\n", "from azure.identity import DefaultAzureCredential\n", "from azure.mgmt.core.tools import parse_resource_id\n", "from dotenv import load_dotenv\n", "\n", "load_dotenv(override=True) # Take environment variables from .env\n", "\n", + "def azure_openai_resource_endpoint(endpoint):\n", + " \"\"\"Normalize an Azure OpenAI endpoint to the resource root, stripping any /openai/... suffix.\"\"\"\n", + " return endpoint.split(\"/openai/\", 1)[0].rstrip(\"/\")\n", + "\n", "project_endpoint = os.environ[\"PROJECT_ENDPOINT\"]\n", "project_resource_id = os.environ[\"PROJECT_RESOURCE_ID\"]\n", "project_connection_name = os.getenv(\"PROJECT_CONNECTION_NAME\", \"earthknowledgeconnection\")\n", "agent_model = os.getenv(\"AGENT_MODEL\", \"gpt-4.1-mini\")\n", "agent_name = os.getenv(\"AGENT_NAME\", \"earth-knowledge-agent\")\n", "endpoint = os.environ[\"AZURE_SEARCH_ENDPOINT\"]\n", + "search_key = os.getenv(\"AZURE_SEARCH_API_KEY\")\n", "credential = DefaultAzureCredential()\n", + "search_credential = AzureKeyCredential(search_key) if search_key else credential\n", "knowledge_source_name = os.getenv(\"AZURE_SEARCH_KNOWLEDGE_SOURCE_NAME\", \"earth-knowledge-source\")\n", "index_name = os.getenv(\"AZURE_SEARCH_INDEX\", \"earth-at-night\")\n", - "azure_openai_endpoint = os.environ[\"AZURE_OPENAI_ENDPOINT\"]\n", + "azure_openai_endpoint = azure_openai_resource_endpoint(os.environ[\"AZURE_OPENAI_ENDPOINT\"])\n", + "azure_openai_key = os.getenv(\"AZURE_OPENAI_API_KEY\")\n", "azure_openai_embedding_deployment = os.getenv(\"AZURE_OPENAI_EMBEDDING_DEPLOYMENT\", \"text-embedding-3-large\")\n", "azure_openai_embedding_model = os.getenv(\"AZURE_OPENAI_EMBEDDING_MODEL\", \"text-embedding-3-large\")\n", "base_name = os.getenv(\"AZURE_SEARCH_AGENT_NAME\", \"earth-knowledge-base\")\n", @@ -109,7 +117,8 @@ " parameters=AzureOpenAIVectorizerParameters(\n", " resource_url=azure_openai_endpoint,\n", " deployment_name=azure_openai_embedding_deployment,\n", - " model_name=azure_openai_embedding_model\n", + " model_name=azure_openai_embedding_model,\n", + " api_key=azure_openai_key\n", " )\n", " )\n", " ]\n", @@ -129,7 +138,7 @@ " )\n", ")\n", "\n", - "index_client = SearchIndexClient(endpoint=endpoint, credential=credential)\n", + "index_client = SearchIndexClient(endpoint=endpoint, credential=search_credential)\n", "index_client.create_or_update_index(index)\n", "print(f\"Index '{index_name}' created or updated successfully\")" ] @@ -163,9 +172,9 @@ "from azure.search.documents import SearchIndexingBufferedSender\n", "\n", "url = \"https://raw.githubusercontent.com/Azure-Samples/azure-search-sample-data/refs/heads/main/nasa-e-book/earth-at-night-json/documents.json\"\n", - "documents = requests.get(url).json()\n", + "documents = requests.get(url, timeout=60).json()\n", "\n", - "with SearchIndexingBufferedSender(endpoint=endpoint, index_name=index_name, credential=credential) as client:\n", + "with SearchIndexingBufferedSender(endpoint=endpoint, index_name=index_name, credential=search_credential) as client:\n", " client.upload_documents(documents=documents)\n", "\n", "print(f\"Documents uploaded to index '{index_name}'\")" @@ -207,11 +216,16 @@ " description=\"Knowledge source for Earth at night data\",\n", " search_index_parameters=SearchIndexKnowledgeSourceParameters(\n", " search_index_name=index_name,\n", - " source_data_fields=[SearchIndexFieldReference(name=\"id\"), SearchIndexFieldReference(name=\"page_number\")]\n", + " semantic_configuration_name=\"semantic_config\",\n", + " source_data_fields=[\n", + " SearchIndexFieldReference(name=\"id\"),\n", + " SearchIndexFieldReference(name=\"page_chunk\"),\n", + " SearchIndexFieldReference(name=\"page_number\")\n", + " ]\n", " ),\n", ")\n", "\n", - "index_client = SearchIndexClient(endpoint=endpoint, credential=credential)\n", + "index_client = SearchIndexClient(endpoint=endpoint, credential=search_credential)\n", "index_client.create_or_update_knowledge_source(knowledge_source=ks)\n", "print(f\"Knowledge source '{knowledge_source_name}' created or updated successfully.\")" ] @@ -258,11 +272,11 @@ " retrieval_reasoning_effort=KnowledgeRetrievalMinimalReasoningEffort()\n", ")\n", "\n", - "index_client = SearchIndexClient(endpoint=endpoint, credential=credential)\n", + "index_client = SearchIndexClient(endpoint=endpoint, credential=search_credential)\n", "index_client.create_or_update_knowledge_base(knowledge_base=knowledge_base)\n", "print(f\"Knowledge base '{base_name}' created or updated successfully\")\n", "\n", - "mcp_endpoint = f\"{endpoint}/knowledgebases/{base_name}/mcp?api-version=2025-11-01-Preview\"" + "mcp_endpoint = f\"{endpoint.rstrip('/')}/knowledgebases/{base_name}/mcp?api-version=2026-05-01-preview\"" ] }, { @@ -481,7 +495,7 @@ " Why do suburban belts display larger December brightening than urban cores even though absolute light levels are higher downtown?\n", " Why is the Phoenix nighttime street grid is so sharply visible from space, whereas large stretches of the interstate between midwestern cities remain comparatively dim?\n", " \"\"\",\n", - " extra_body={\"agent_reference\": {\"name\": agent.name, \"type\": \"agent_reference\"}},\n", + " extra_body={\"agent\": {\"name\": agent.name, \"type\": \"agent_reference\"}},\n", ")\n", "\n", "print(f\"Response: {response.output_text}\")" @@ -543,7 +557,7 @@ " description=\"SharePoint knowledge source\"\n", ")\n", "\n", - "index_client = SearchIndexClient(endpoint=endpoint, credential=credential)\n", + "index_client = SearchIndexClient(endpoint=endpoint, credential=search_credential)\n", "index_client.create_or_update_knowledge_source(knowledge_source=remote_sp_ks)\n", "print(f\"Knowledge source '{remote_sp_ks.name}' created or updated successfully.\")\n", "\n", @@ -689,7 +703,7 @@ } ], "source": [ - "index_client.delete_index(index)\n", + "index_client.delete_index(index_name)\n", "print(f\"Index '{index_name}' deleted successfully\")" ] } diff --git a/agentic-retrieval-pipeline-example/sample.env b/agentic-retrieval-pipeline-example/sample.env index 891a6cfa9..6ed6616bf 100644 --- a/agentic-retrieval-pipeline-example/sample.env +++ b/agentic-retrieval-pipeline-example/sample.env @@ -1,6 +1,8 @@ AZURE_SEARCH_ENDPOINT = https://your-search-service.search.windows.net +# AZURE_SEARCH_API_KEY = your-search-api-key # Optional: omit to use DefaultAzureCredential PROJECT_ENDPOINT = https://your-foundry-resource.services.ai.azure.com/api/projects/your-foundry-project PROJECT_RESOURCE_ID = /subscriptions/your-subscription-id/resourceGroups/your-resource-group/providers/Microsoft.CognitiveServices/accounts/your-account/projects/your-project AZURE_OPENAI_ENDPOINT = https://your-openai-service.openai.azure.com +# AZURE_OPENAI_API_KEY = your-openai-api-key # Optional: omit to use DefaultAzureCredential AZURE_OPENAI_EMBEDDING_DEPLOYMENT = text-embedding-3-large AGENT_MODEL = gpt-4.1-mini \ No newline at end of file