azure-search-documents-py
Azure AI Search SDK for Python. Use for vector search, hybrid search, semantic ranking, indexing, and skillsets. Triggers: "azure-search-documents", "SearchClient", "SearchIndexClient", "vector search", "hybrid search", "semantic search".
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install microsoft-skills-azure-search-documents-py
Repository
Skill path: .github/plugins/azure-sdk-python/skills/azure-search-documents-py
Azure AI Search SDK for Python. Use for vector search, hybrid search, semantic ranking, indexing, and skillsets. Triggers: "azure-search-documents", "SearchClient", "SearchIndexClient", "vector search", "hybrid search", "semantic search".
Open repositoryBest for
Primary workflow: Analyze Data & AI.
Technical facets: Full Stack, Data / AI.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: microsoft.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install azure-search-documents-py into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/microsoft/skills before adding azure-search-documents-py to shared team environments
- Use azure-search-documents-py for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: azure-search-documents-py
description: |
Azure AI Search SDK for Python. Use for vector search, hybrid search, semantic ranking, indexing, and skillsets.
Triggers: "azure-search-documents", "SearchClient", "SearchIndexClient", "vector search", "hybrid search", "semantic search".
package: azure-search-documents
---
# Azure AI Search SDK for Python
Full-text, vector, and hybrid search with AI enrichment capabilities.
## Installation
```bash
pip install azure-search-documents
```
## Environment Variables
```bash
AZURE_SEARCH_ENDPOINT=https://<service-name>.search.windows.net
AZURE_SEARCH_API_KEY=<your-api-key>
AZURE_SEARCH_INDEX_NAME=<your-index-name>
```
## Authentication
### API Key
```python
from azure.search.documents import SearchClient
from azure.core.credentials import AzureKeyCredential
client = SearchClient(
endpoint=os.environ["AZURE_SEARCH_ENDPOINT"],
index_name=os.environ["AZURE_SEARCH_INDEX_NAME"],
credential=AzureKeyCredential(os.environ["AZURE_SEARCH_API_KEY"])
)
```
### Entra ID (Recommended)
```python
from azure.search.documents import SearchClient
from azure.identity import DefaultAzureCredential
client = SearchClient(
endpoint=os.environ["AZURE_SEARCH_ENDPOINT"],
index_name=os.environ["AZURE_SEARCH_INDEX_NAME"],
credential=DefaultAzureCredential()
)
```
## Client Types
| Client | Purpose |
|--------|---------|
| `SearchClient` | Search and document operations |
| `SearchIndexClient` | Index management, synonym maps |
| `SearchIndexerClient` | Indexers, data sources, skillsets |
## Create Index with Vector Field
```python
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
SearchIndex,
SearchField,
SearchFieldDataType,
VectorSearch,
HnswAlgorithmConfiguration,
VectorSearchProfile,
SearchableField,
SimpleField
)
index_client = SearchIndexClient(endpoint, AzureKeyCredential(key))
fields = [
SimpleField(name="id", type=SearchFieldDataType.String, key=True),
SearchableField(name="title", type=SearchFieldDataType.String),
SearchableField(name="content", type=SearchFieldDataType.String),
SearchField(
name="content_vector",
type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
searchable=True,
vector_search_dimensions=1536,
vector_search_profile_name="my-vector-profile"
)
]
vector_search = VectorSearch(
algorithms=[
HnswAlgorithmConfiguration(name="my-hnsw")
],
profiles=[
VectorSearchProfile(
name="my-vector-profile",
algorithm_configuration_name="my-hnsw"
)
]
)
index = SearchIndex(
name="my-index",
fields=fields,
vector_search=vector_search
)
index_client.create_or_update_index(index)
```
## Upload Documents
```python
from azure.search.documents import SearchClient
client = SearchClient(endpoint, "my-index", AzureKeyCredential(key))
documents = [
{
"id": "1",
"title": "Azure AI Search",
"content": "Full-text and vector search service",
"content_vector": [0.1, 0.2, ...] # 1536 dimensions
}
]
result = client.upload_documents(documents)
print(f"Uploaded {len(result)} documents")
```
## Keyword Search
```python
results = client.search(
search_text="azure search",
select=["id", "title", "content"],
top=10
)
for result in results:
print(f"{result['title']}: {result['@search.score']}")
```
## Vector Search
```python
from azure.search.documents.models import VectorizedQuery
# Your query embedding (1536 dimensions)
query_vector = get_embedding("semantic search capabilities")
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
results = client.search(
vector_queries=[vector_query],
select=["id", "title", "content"]
)
for result in results:
print(f"{result['title']}: {result['@search.score']}")
```
## Hybrid Search (Vector + Keyword)
```python
from azure.search.documents.models import VectorizedQuery
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
results = client.search(
search_text="azure search",
vector_queries=[vector_query],
select=["id", "title", "content"],
top=10
)
```
## Semantic Ranking
```python
from azure.search.documents.models import QueryType
results = client.search(
search_text="what is azure search",
query_type=QueryType.SEMANTIC,
semantic_configuration_name="my-semantic-config",
select=["id", "title", "content"],
top=10
)
for result in results:
print(f"{result['title']}")
if result.get("@search.captions"):
print(f" Caption: {result['@search.captions'][0].text}")
```
## Filters
```python
results = client.search(
search_text="*",
filter="category eq 'Technology' and rating gt 4",
order_by=["rating desc"],
select=["id", "title", "category", "rating"]
)
```
## Facets
```python
results = client.search(
search_text="*",
facets=["category,count:10", "rating"],
top=0 # Only get facets, no documents
)
for facet_name, facet_values in results.get_facets().items():
print(f"{facet_name}:")
for facet in facet_values:
print(f" {facet['value']}: {facet['count']}")
```
## Autocomplete & Suggest
```python
# Autocomplete
results = client.autocomplete(
search_text="sea",
suggester_name="my-suggester",
mode="twoTerms"
)
# Suggest
results = client.suggest(
search_text="sea",
suggester_name="my-suggester",
select=["title"]
)
```
## Indexer with Skillset
```python
from azure.search.documents.indexes import SearchIndexerClient
from azure.search.documents.indexes.models import (
SearchIndexer,
SearchIndexerDataSourceConnection,
SearchIndexerSkillset,
EntityRecognitionSkill,
InputFieldMappingEntry,
OutputFieldMappingEntry
)
indexer_client = SearchIndexerClient(endpoint, AzureKeyCredential(key))
# Create data source
data_source = SearchIndexerDataSourceConnection(
name="my-datasource",
type="azureblob",
connection_string=connection_string,
container={"name": "documents"}
)
indexer_client.create_or_update_data_source_connection(data_source)
# Create skillset
skillset = SearchIndexerSkillset(
name="my-skillset",
skills=[
EntityRecognitionSkill(
inputs=[InputFieldMappingEntry(name="text", source="/document/content")],
outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]
)
]
)
indexer_client.create_or_update_skillset(skillset)
# Create indexer
indexer = SearchIndexer(
name="my-indexer",
data_source_name="my-datasource",
target_index_name="my-index",
skillset_name="my-skillset"
)
indexer_client.create_or_update_indexer(indexer)
```
## Best Practices
1. **Use hybrid search** for best relevance combining vector and keyword
2. **Enable semantic ranking** for natural language queries
3. **Index in batches** of 100-1000 documents for efficiency
4. **Use filters** to narrow results before ranking
5. **Configure vector dimensions** to match your embedding model
6. **Use HNSW algorithm** for large-scale vector search
7. **Create suggesters** at index creation time (cannot add later)
## Reference Files
| File | Contents |
|------|----------|
| [references/vector-search.md](references/vector-search.md) | HNSW configuration, integrated vectorization, multi-vector queries |
| [references/semantic-ranking.md](references/semantic-ranking.md) | Semantic configuration, captions, answers, hybrid patterns |
| [scripts/setup_vector_index.py](scripts/setup_vector_index.py) | CLI script to create vector-enabled search index |
---
## Additional Azure AI Search Patterns
# Azure AI Search Python SDK
Write clean, idiomatic Python code for Azure AI Search using `azure-search-documents`.
## Installation
```bash
pip install azure-search-documents azure-identity
```
## Environment Variables
```bash
AZURE_SEARCH_ENDPOINT=https://<search-service>.search.windows.net
AZURE_SEARCH_INDEX_NAME=<index-name>
# For API key auth (not recommended for production)
AZURE_SEARCH_API_KEY=<api-key>
```
## Authentication
**DefaultAzureCredential (preferred)**:
```python
from azure.identity import DefaultAzureCredential
from azure.search.documents import SearchClient
credential = DefaultAzureCredential()
client = SearchClient(endpoint, index_name, credential)
```
**API Key**:
```python
from azure.core.credentials import AzureKeyCredential
from azure.search.documents import SearchClient
client = SearchClient(endpoint, index_name, AzureKeyCredential(api_key))
```
## Client Selection
| Client | Purpose |
|--------|---------|
| `SearchClient` | Query indexes, upload/update/delete documents |
| `SearchIndexClient` | Create/manage indexes, knowledge sources, knowledge bases |
| `SearchIndexerClient` | Manage indexers, skillsets, data sources |
| `KnowledgeBaseRetrievalClient` | Agentic retrieval with LLM-powered Q&A |
## Index Creation Pattern
```python
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
SearchIndex, SearchField, VectorSearch, VectorSearchProfile,
HnswAlgorithmConfiguration, AzureOpenAIVectorizer,
AzureOpenAIVectorizerParameters, SemanticSearch,
SemanticConfiguration, SemanticPrioritizedFields, SemanticField
)
index = SearchIndex(
name=index_name,
fields=[
SearchField(name="id", type="Edm.String", key=True),
SearchField(name="content", type="Edm.String", searchable=True),
SearchField(name="embedding", type="Collection(Edm.Single)",
vector_search_dimensions=3072,
vector_search_profile_name="vector-profile"),
],
vector_search=VectorSearch(
profiles=[VectorSearchProfile(
name="vector-profile",
algorithm_configuration_name="hnsw-algo",
vectorizer_name="openai-vectorizer"
)],
algorithms=[HnswAlgorithmConfiguration(name="hnsw-algo")],
vectorizers=[AzureOpenAIVectorizer(
vectorizer_name="openai-vectorizer",
parameters=AzureOpenAIVectorizerParameters(
resource_url=aoai_endpoint,
deployment_name=embedding_deployment,
model_name=embedding_model
)
)]
),
semantic_search=SemanticSearch(
default_configuration_name="semantic-config",
configurations=[SemanticConfiguration(
name="semantic-config",
prioritized_fields=SemanticPrioritizedFields(
content_fields=[SemanticField(field_name="content")]
)
)]
)
)
index_client = SearchIndexClient(endpoint, credential)
index_client.create_or_update_index(index)
```
## Document Operations
```python
from azure.search.documents import SearchIndexingBufferedSender
# Batch upload with automatic batching
with SearchIndexingBufferedSender(endpoint, index_name, credential) as sender:
sender.upload_documents(documents)
# Direct operations via SearchClient
search_client = SearchClient(endpoint, index_name, credential)
search_client.upload_documents(documents) # Add new
search_client.merge_documents(documents) # Update existing
search_client.merge_or_upload_documents(documents) # Upsert
search_client.delete_documents(documents) # Remove
```
## Search Patterns
```python
# Basic search
results = search_client.search(search_text="query")
# Vector search
from azure.search.documents.models import VectorizedQuery
results = search_client.search(
search_text=None,
vector_queries=[VectorizedQuery(
vector=embedding,
k_nearest_neighbors=5,
fields="embedding"
)]
)
# Hybrid search (vector + keyword)
results = search_client.search(
search_text="query",
vector_queries=[VectorizedQuery(vector=embedding, k_nearest_neighbors=5, fields="embedding")],
query_type="semantic",
semantic_configuration_name="semantic-config"
)
# With filters
results = search_client.search(
search_text="query",
filter="category eq 'technology'",
select=["id", "title", "content"],
top=10
)
```
## Agentic Retrieval (Knowledge Bases)
For LLM-powered Q&A with answer synthesis, see [references/agentic-retrieval.md](references/agentic-retrieval.md).
Key concepts:
- **Knowledge Source**: Points to a search index
- **Knowledge Base**: Wraps knowledge sources + LLM for query planning and synthesis
- **Output modes**: `EXTRACTIVE_DATA` (raw chunks) or `ANSWER_SYNTHESIS` (LLM-generated answers)
## Async Pattern
```python
from azure.search.documents.aio import SearchClient
async with SearchClient(endpoint, index_name, credential) as client:
results = await client.search(search_text="query")
async for result in results:
print(result["title"])
```
## Best Practices
1. **Use environment variables** for endpoints, keys, and deployment names
2. **Prefer `DefaultAzureCredential`** over API keys for production
3. **Use `SearchIndexingBufferedSender`** for batch uploads (handles batching/retries)
4. **Always define semantic configuration** for agentic retrieval indexes
5. **Use `create_or_update_index`** for idempotent index creation
6. **Close clients** with context managers or explicit `close()`
## Field Types Reference
| EDM Type | Python | Notes |
|----------|--------|-------|
| `Edm.String` | str | Searchable text |
| `Edm.Int32` | int | Integer |
| `Edm.Int64` | int | Long integer |
| `Edm.Double` | float | Floating point |
| `Edm.Boolean` | bool | True/False |
| `Edm.DateTimeOffset` | datetime | ISO 8601 |
| `Collection(Edm.Single)` | List[float] | Vector embeddings |
| `Collection(Edm.String)` | List[str] | String arrays |
## Error Handling
```python
from azure.core.exceptions import (
HttpResponseError,
ResourceNotFoundError,
ResourceExistsError
)
try:
result = search_client.get_document(key="123")
except ResourceNotFoundError:
print("Document not found")
except HttpResponseError as e:
print(f"Search error: {e.message}")
```
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/vector-search.md
```markdown
# Vector Search Patterns
Detailed patterns for vector search with Azure AI Search.
## Vector Search Configuration
### HNSW Algorithm Configuration
HNSW (Hierarchical Navigable Small World) is the recommended algorithm for large-scale vector search.
```python
from azure.search.documents.indexes.models import (
VectorSearch,
HnswAlgorithmConfiguration,
VectorSearchProfile,
HnswParameters,
)
vector_search = VectorSearch(
algorithms=[
HnswAlgorithmConfiguration(
name="hnsw-config",
parameters=HnswParameters(
m=4, # Bi-directional links per node (default: 4)
ef_construction=400, # Size of dynamic candidate list during indexing
ef_search=500, # Size of dynamic candidate list during search
metric="cosine" # Distance metric: cosine, euclidean, dotProduct
)
)
],
profiles=[
VectorSearchProfile(
name="vector-profile",
algorithm_configuration_name="hnsw-config"
)
]
)
```
### Parameter Tuning Guide
| Parameter | Range | Trade-off |
|-----------|-------|-----------|
| `m` | 4-16 | Higher = better recall, more memory |
| `ef_construction` | 100-1000 | Higher = better index quality, slower indexing |
| `ef_search` | 100-1000 | Higher = better recall, slower queries |
## Integrated Vectorization
Let Azure AI Search generate embeddings automatically using Azure OpenAI.
### Vectorizer Configuration
```python
from azure.search.documents.indexes.models import (
AzureOpenAIVectorizer,
AzureOpenAIVectorizerParameters,
)
vectorizer = AzureOpenAIVectorizer(
vectorizer_name="openai-vectorizer",
parameters=AzureOpenAIVectorizerParameters(
resource_url="https://<resource>.openai.azure.com",
deployment_name="text-embedding-3-large",
model_name="text-embedding-3-large"
)
)
```
### Vector Field with Integrated Vectorization
```python
from azure.search.documents.indexes.models import (
SearchField,
SearchFieldDataType,
)
vector_field = SearchField(
name="content_vector",
type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
searchable=True,
stored=False, # Don't store vectors to save space
vector_search_dimensions=3072, # text-embedding-3-large
vector_search_profile_name="vector-profile"
)
```
## Vector Query Patterns
### Basic Vector Query
```python
from azure.search.documents.models import VectorizedQuery
def vector_search(client, query_vector: list[float], k: int = 10):
"""Execute a pure vector search."""
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=k,
fields="content_vector"
)
results = client.search(
search_text=None,
vector_queries=[vector_query],
select=["id", "title", "content"]
)
return list(results)
```
### Multi-Vector Query
Search across multiple vector fields simultaneously.
```python
from azure.search.documents.models import VectorizedQuery
def multi_vector_search(client, title_vector: list[float], content_vector: list[float]):
"""Search across title and content vectors."""
results = client.search(
search_text=None,
vector_queries=[
VectorizedQuery(
vector=title_vector,
k_nearest_neighbors=10,
fields="title_vector"
),
VectorizedQuery(
vector=content_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
],
select=["id", "title", "content"]
)
return list(results)
```
### Vector Search with Filters
Pre-filter documents before vector search for better performance.
```python
def filtered_vector_search(
client,
query_vector: list[float],
category: str,
min_rating: float = 4.0
):
"""Vector search with pre-filtering."""
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
results = client.search(
search_text=None,
vector_queries=[vector_query],
filter=f"category eq '{category}' and rating ge {min_rating}",
select=["id", "title", "content", "category", "rating"]
)
return list(results)
```
## Exhaustive KNN Search
For exact nearest neighbor search (smaller indexes or when precision is critical).
```python
from azure.search.documents.indexes.models import (
VectorSearch,
ExhaustiveKnnAlgorithmConfiguration,
ExhaustiveKnnParameters,
VectorSearchProfile,
)
vector_search = VectorSearch(
algorithms=[
ExhaustiveKnnAlgorithmConfiguration(
name="exhaustive-knn",
parameters=ExhaustiveKnnParameters(
metric="cosine"
)
)
],
profiles=[
VectorSearchProfile(
name="exhaustive-profile",
algorithm_configuration_name="exhaustive-knn"
)
]
)
```
## Scalar Quantization (Preview)
Reduce vector storage size with minimal quality loss.
```python
from azure.search.documents.indexes.models import (
VectorSearch,
VectorSearchProfile,
ScalarQuantizationCompression,
ScalarQuantizationParameters,
)
vector_search = VectorSearch(
profiles=[
VectorSearchProfile(
name="quantized-profile",
algorithm_configuration_name="hnsw-config",
compression_name="scalar-quantization"
)
],
compressions=[
ScalarQuantizationCompression(
compression_name="scalar-quantization",
parameters=ScalarQuantizationParameters(
quantized_data_type="int8"
)
)
]
)
```
## Async Vector Search
```python
from azure.search.documents.aio import SearchClient
from azure.search.documents.models import VectorizedQuery
async def async_vector_search(client: SearchClient, query_vector: list[float]):
"""Async vector search."""
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="content_vector"
)
results = client.search(
search_text=None,
vector_queries=[vector_query],
select=["id", "title", "content"]
)
docs = []
async for result in results:
docs.append(result)
return docs
```
## Best Practices
1. **Dimensions**: Match your embedding model (text-embedding-3-large = 3072, ada-002 = 1536)
2. **Stored vectors**: Set `stored=False` to save storage if you don't need to retrieve vectors
3. **Pre-filtering**: Use filters to narrow search space before vector comparison
4. **Hybrid search**: Combine with keyword search for best relevance (see hybrid-search.md)
5. **Compression**: Use scalar quantization for large indexes to reduce costs
```
### references/semantic-ranking.md
```markdown
# Semantic Ranking Patterns
Semantic ranking uses machine learning to re-rank search results for better relevance.
## Semantic Configuration
### Basic Semantic Configuration
```python
from azure.search.documents.indexes.models import (
SemanticSearch,
SemanticConfiguration,
SemanticPrioritizedFields,
SemanticField,
)
semantic_search = SemanticSearch(
default_configuration_name="my-semantic-config",
configurations=[
SemanticConfiguration(
name="my-semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="title"),
content_fields=[
SemanticField(field_name="content"),
SemanticField(field_name="summary")
],
keywords_fields=[
SemanticField(field_name="tags")
]
)
)
]
)
```
### Field Priority Rules
| Field Type | Max Fields | Purpose |
|------------|------------|---------|
| `title_field` | 1 | Most important for ranking |
| `content_fields` | 10 | Main content, ordered by priority |
| `keywords_fields` | 10 | Keywords/tags for matching |
## Semantic Queries
### Basic Semantic Query
```python
from azure.search.documents.models import QueryType
def semantic_search(client, query: str):
"""Execute a semantic search query."""
results = client.search(
search_text=query,
query_type=QueryType.SEMANTIC,
semantic_configuration_name="my-semantic-config",
select=["id", "title", "content"]
)
return list(results)
```
### Semantic Search with Captions
Captions provide extractive summaries highlighting relevant passages.
```python
from azure.search.documents.models import QueryType, QueryCaptionType
def semantic_search_with_captions(client, query: str):
"""Semantic search with extractive captions."""
results = client.search(
search_text=query,
query_type=QueryType.SEMANTIC,
semantic_configuration_name="my-semantic-config",
query_caption=QueryCaptionType.EXTRACTIVE,
select=["id", "title", "content"]
)
for result in results:
print(f"Title: {result['title']}")
print(f"Score: {result['@search.score']}")
print(f"Reranker Score: {result.get('@search.reranker_score', 'N/A')}")
# Extract captions
captions = result.get("@search.captions", [])
for caption in captions:
print(f"Caption: {caption.text}")
print(f"Highlights: {caption.highlights}")
```
### Semantic Search with Answers
Answers extract specific text that directly answers the query.
```python
from azure.search.documents.models import QueryType, QueryCaptionType, QueryAnswerType
def semantic_search_with_answers(client, query: str):
"""Semantic search with extractive answers."""
results = client.search(
search_text=query,
query_type=QueryType.SEMANTIC,
semantic_configuration_name="my-semantic-config",
query_caption=QueryCaptionType.EXTRACTIVE,
query_answer=QueryAnswerType.EXTRACTIVE,
query_answer_count=3, # Request up to 3 answers
select=["id", "title", "content"]
)
# Get semantic answers (top-level, not per-document)
answers = results.get_answers()
if answers:
for answer in answers:
print(f"Answer: {answer.text}")
print(f"Highlights: {answer.highlights}")
print(f"Score: {answer.score}")
print(f"Key: {answer.key}")
# Process documents
for result in results:
print(f"Document: {result['title']}")
```
## Hybrid Search with Semantic Ranking
Combine keyword, vector, and semantic ranking for best results.
```python
from azure.search.documents.models import (
VectorizedQuery,
QueryType,
QueryCaptionType,
)
def hybrid_semantic_search(
client,
query: str,
query_vector: list[float],
top: int = 10
):
"""Hybrid search with semantic re-ranking."""
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=50, # Over-fetch for re-ranking
fields="content_vector"
)
results = client.search(
search_text=query,
vector_queries=[vector_query],
query_type=QueryType.SEMANTIC,
semantic_configuration_name="my-semantic-config",
query_caption=QueryCaptionType.EXTRACTIVE,
top=top,
select=["id", "title", "content"]
)
return list(results)
```
## Semantic Configuration for Different Content Types
### Document Search
```python
doc_semantic_config = SemanticConfiguration(
name="document-semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="document_title"),
content_fields=[
SemanticField(field_name="body_text"),
SemanticField(field_name="abstract")
],
keywords_fields=[
SemanticField(field_name="categories"),
SemanticField(field_name="authors")
]
)
)
```
### Product Search
```python
product_semantic_config = SemanticConfiguration(
name="product-semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="product_name"),
content_fields=[
SemanticField(field_name="description"),
SemanticField(field_name="features")
],
keywords_fields=[
SemanticField(field_name="brand"),
SemanticField(field_name="category")
]
)
)
```
### FAQ Search
```python
faq_semantic_config = SemanticConfiguration(
name="faq-semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="question"),
content_fields=[
SemanticField(field_name="answer")
],
keywords_fields=[
SemanticField(field_name="topic")
]
)
)
```
## Multiple Semantic Configurations
Define different configurations for different query patterns.
```python
semantic_search = SemanticSearch(
default_configuration_name="general-config",
configurations=[
SemanticConfiguration(
name="general-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="title"),
content_fields=[SemanticField(field_name="content")]
)
),
SemanticConfiguration(
name="qa-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="question"),
content_fields=[SemanticField(field_name="answer")]
)
)
]
)
# Use specific config at query time
results = client.search(
search_text=query,
query_type=QueryType.SEMANTIC,
semantic_configuration_name="qa-config" # Override default
)
```
## Best Practices
1. **Title field**: Always specify a title field for best ranking
2. **Content field order**: List most important content fields first
3. **Over-fetch**: Request more results than needed, let semantic re-ranking select the best
4. **Captions for UI**: Use captions to show relevant snippets in search results
5. **Answers for Q&A**: Use answers for question-answering scenarios
6. **Combine with hybrid**: Semantic ranking works best with hybrid (keyword + vector) search
```
### scripts/setup_vector_index.py
```python
#!/usr/bin/env python3
"""
Create an Azure AI Search index with vector search capabilities.
Usage:
python setup_vector_index.py --index-name <name> [options]
Environment variables required:
AZURE_SEARCH_ENDPOINT: Azure AI Search endpoint
AZURE_OPENAI_ENDPOINT: Azure OpenAI endpoint (for integrated vectorization)
AZURE_OPENAI_EMBEDDING_DEPLOYMENT: Embedding model deployment name
"""
import argparse
import os
from azure.identity import DefaultAzureCredential
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
SearchIndex,
SearchField,
SearchFieldDataType,
VectorSearch,
VectorSearchProfile,
HnswAlgorithmConfiguration,
HnswParameters,
AzureOpenAIVectorizer,
AzureOpenAIVectorizerParameters,
SemanticSearch,
SemanticConfiguration,
SemanticPrioritizedFields,
SemanticField,
SearchableField,
SimpleField,
)
def create_vector_index(
client: SearchIndexClient,
index_name: str,
aoai_endpoint: str | None = None,
embedding_deployment: str | None = None,
dimensions: int = 1536,
enable_semantic: bool = True,
) -> SearchIndex:
"""Create a search index with vector and optional semantic search."""
# Define fields
fields = [
SimpleField(
name="id",
type=SearchFieldDataType.String,
key=True,
filterable=True,
sortable=True,
),
SearchableField(
name="title",
type=SearchFieldDataType.String,
filterable=True,
sortable=True,
),
SearchableField(
name="content",
type=SearchFieldDataType.String,
),
SimpleField(
name="category",
type=SearchFieldDataType.String,
filterable=True,
facetable=True,
),
SearchField(
name="content_vector",
type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
searchable=True,
stored=False,
vector_search_dimensions=dimensions,
vector_search_profile_name="vector-profile",
),
]
# Configure vector search
vectorizers = []
if aoai_endpoint and embedding_deployment:
vectorizers.append(
AzureOpenAIVectorizer(
vectorizer_name="openai-vectorizer",
parameters=AzureOpenAIVectorizerParameters(
resource_url=aoai_endpoint,
deployment_name=embedding_deployment,
model_name=embedding_deployment,
),
)
)
vector_search = VectorSearch(
algorithms=[
HnswAlgorithmConfiguration(
name="hnsw-algo",
parameters=HnswParameters(
m=4,
ef_construction=400,
ef_search=500,
metric="cosine",
),
)
],
profiles=[
VectorSearchProfile(
name="vector-profile",
algorithm_configuration_name="hnsw-algo",
vectorizer_name="openai-vectorizer" if vectorizers else None,
)
],
vectorizers=vectorizers if vectorizers else None,
)
# Configure semantic search
semantic_search = None
if enable_semantic:
semantic_search = SemanticSearch(
default_configuration_name="semantic-config",
configurations=[
SemanticConfiguration(
name="semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="title"),
content_fields=[SemanticField(field_name="content")],
keywords_fields=[SemanticField(field_name="category")],
),
)
],
)
# Create index
index = SearchIndex(
name=index_name,
fields=fields,
vector_search=vector_search,
semantic_search=semantic_search,
)
return client.create_or_update_index(index)
def main():
parser = argparse.ArgumentParser(
description="Create an Azure AI Search index with vector search"
)
parser.add_argument("--index-name", required=True, help="Search index name")
parser.add_argument(
"--dimensions",
type=int,
default=1536,
help="Vector dimensions (default: 1536 for ada-002, use 3072 for text-embedding-3-large)",
)
parser.add_argument(
"--no-semantic",
action="store_true",
help="Disable semantic search configuration",
)
parser.add_argument(
"--no-vectorizer",
action="store_true",
help="Skip integrated vectorization (provide vectors manually)",
)
args = parser.parse_args()
# Load environment
search_endpoint = os.environ["AZURE_SEARCH_ENDPOINT"]
aoai_endpoint = (
os.environ.get("AZURE_OPENAI_ENDPOINT") if not args.no_vectorizer else None
)
embedding_deployment = (
os.environ.get("AZURE_OPENAI_EMBEDDING_DEPLOYMENT")
if not args.no_vectorizer
else None
)
credential = DefaultAzureCredential()
client = SearchIndexClient(endpoint=search_endpoint, credential=credential)
print(f"Creating index '{args.index_name}'...")
index = create_vector_index(
client=client,
index_name=args.index_name,
aoai_endpoint=aoai_endpoint,
embedding_deployment=embedding_deployment,
dimensions=args.dimensions,
enable_semantic=not args.no_semantic,
)
print(f" Index created: {index.name}")
print(f" Fields: {[f.name for f in index.fields]}")
print(f" Vector dimensions: {args.dimensions}")
print(f" Semantic search: {'enabled' if not args.no_semantic else 'disabled'}")
print(f" Integrated vectorization: {'enabled' if aoai_endpoint else 'disabled'}")
if __name__ == "__main__":
main()
```
### references/agentic-retrieval.md
```markdown
# Agentic Retrieval with Knowledge Bases
Agentic retrieval integrates an LLM to process queries, retrieve content, and generate grounded answers.
## Architecture
```
Knowledge Base (wraps LLM + sources)
├── Knowledge Source 1 → Search Index A
├── Knowledge Source 2 → Search Index B
└── Azure OpenAI Model (query planning + answer synthesis)
```
## Setup Workflow
### 1. Create Index with Semantic Configuration
```python
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
SearchIndex, SearchField, VectorSearch, VectorSearchProfile,
HnswAlgorithmConfiguration, AzureOpenAIVectorizer,
AzureOpenAIVectorizerParameters, SemanticSearch,
SemanticConfiguration, SemanticPrioritizedFields, SemanticField
)
index = SearchIndex(
name="my-index",
fields=[
SearchField(name="id", type="Edm.String", key=True, filterable=True),
SearchField(name="content", type="Edm.String", filterable=False),
SearchField(name="embedding", type="Collection(Edm.Single)",
stored=False, vector_search_dimensions=3072,
vector_search_profile_name="hnsw-profile"),
SearchField(name="category", type="Edm.String", filterable=True, facetable=True)
],
vector_search=VectorSearch(
profiles=[VectorSearchProfile(
name="hnsw-profile",
algorithm_configuration_name="hnsw-algo",
vectorizer_name="aoai-vectorizer"
)],
algorithms=[HnswAlgorithmConfiguration(name="hnsw-algo")],
vectorizers=[AzureOpenAIVectorizer(
vectorizer_name="aoai-vectorizer",
parameters=AzureOpenAIVectorizerParameters(
resource_url=aoai_endpoint,
deployment_name="text-embedding-3-large",
model_name="text-embedding-3-large"
)
)]
),
# REQUIRED for agentic retrieval
semantic_search=SemanticSearch(
default_configuration_name="semantic-config",
configurations=[SemanticConfiguration(
name="semantic-config",
prioritized_fields=SemanticPrioritizedFields(
content_fields=[SemanticField(field_name="content")]
)
)]
)
)
index_client = SearchIndexClient(endpoint, credential)
index_client.create_or_update_index(index)
```
### 2. Create Knowledge Source
```python
from azure.search.documents.indexes.models import (
SearchIndexKnowledgeSource,
SearchIndexKnowledgeSourceParameters,
SearchIndexFieldReference
)
knowledge_source = SearchIndexKnowledgeSource(
name="my-knowledge-source",
description="Knowledge source for document retrieval",
search_index_parameters=SearchIndexKnowledgeSourceParameters(
search_index_name="my-index",
source_data_fields=[
SearchIndexFieldReference(name="id"),
SearchIndexFieldReference(name="category")
]
)
)
index_client.create_or_update_knowledge_source(knowledge_source)
```
### 3. Create Knowledge Base
```python
from azure.search.documents.indexes.models import (
KnowledgeBase, KnowledgeBaseAzureOpenAIModel,
KnowledgeSourceReference, AzureOpenAIVectorizerParameters,
KnowledgeRetrievalOutputMode
)
knowledge_base = KnowledgeBase(
name="my-knowledge-base",
models=[KnowledgeBaseAzureOpenAIModel(
azure_open_ai_parameters=AzureOpenAIVectorizerParameters(
resource_url=aoai_endpoint,
deployment_name="gpt-4o-mini",
model_name="gpt-4o-mini"
)
)],
knowledge_sources=[KnowledgeSourceReference(name="my-knowledge-source")],
output_mode=KnowledgeRetrievalOutputMode.ANSWER_SYNTHESIS,
answer_instructions="Provide concise, well-cited answers based on retrieved documents."
)
index_client.create_or_update_knowledge_base(knowledge_base)
```
## Querying the Knowledge Base
```python
from azure.search.documents.knowledgebases import KnowledgeBaseRetrievalClient
from azure.search.documents.knowledgebases.models import (
KnowledgeBaseRetrievalRequest,
KnowledgeRetrievalSemanticIntent,
KnowledgeRetrievalMinimalReasoningEffort,
)
client = KnowledgeBaseRetrievalClient(
endpoint=endpoint,
credential=credential,
)
# Build retrieval request with semantic intents
request = KnowledgeBaseRetrievalRequest(
intents=[KnowledgeRetrievalSemanticIntent(search="What is vector search?")]
)
result = client.retrieve(
knowledge_base_name="my-knowledge-base",
retrieval_request=request,
)
```
## Processing Results
```python
import json
# Extract response content
response_parts = []
for resp in result.response or []:
for content in resp.content or []:
if hasattr(content, "text"):
response_parts.append(content.text)
if response_parts:
response_content = "\n\n".join(response_parts)
print(response_content)
# Extract references (source documents)
if result.references:
for ref in result.references:
print(f"Reference ID: {ref.id}")
if hasattr(ref, 'reranker_score'):
print(f" Score: {ref.reranker_score}")
if ref.source_data:
print(f" Content: {ref.source_data.get('content', '')[:200]}")
```
## Multi-turn Conversations
```python
from azure.search.documents.knowledgebases.models import (
KnowledgeBaseRetrievalRequest,
KnowledgeRetrievalSemanticIntent,
)
def ask(question: str) -> str:
"""Ask a question against the knowledge base."""
request = KnowledgeBaseRetrievalRequest(
intents=[KnowledgeRetrievalSemanticIntent(search=question)]
)
result = client.retrieve(
knowledge_base_name="my-knowledge-base",
retrieval_request=request,
)
# Extract response
response_text = "\n\n".join(
content.text
for resp in (result.response or [])
for content in (resp.content or [])
if hasattr(content, "text")
)
return response_text
```
## Output Modes
| Mode | Description |
|------|-------------|
| `EXTRACTIVE_DATA` | Return raw chunks from knowledge sources |
| `ANSWER_SYNTHESIS` | LLM generates answers citing retrieved content |
## Reasoning Effort Levels
| Level | Class |
|-------|-------|
| `KnowledgeRetrievalMinimalReasoningEffort` | No query planning or iterative search |
| `KnowledgeRetrievalLowReasoningEffort` | Basic query decomposition |
| `KnowledgeRetrievalMediumReasoningEffort` | More sophisticated reasoning |
**Usage:**
```python
from azure.search.documents.knowledgebases.models import KnowledgeRetrievalMinimalReasoningEffort
knowledge_base = KnowledgeBase(
name="my-knowledge-base",
knowledge_sources=[KnowledgeSourceReference(name="my-knowledge-source")],
retrieval_reasoning_effort=KnowledgeRetrievalMinimalReasoningEffort(),
)
```
## Async Pattern
```python
from azure.search.documents.knowledgebases.aio import KnowledgeBaseRetrievalClient
async with KnowledgeBaseRetrievalClient(endpoint, credential=credential) as client:
result = await client.retrieve(
knowledge_base_name="my-knowledge-base",
retrieval_request=request,
)
```
## Clean Up
```python
# Delete in reverse order of creation
index_client.delete_knowledge_base("my-knowledge-base")
index_client.delete_knowledge_source("my-knowledge-source")
index_client.delete_index("my-index")
```
```