Ricerca di intelligenza artificiale di Azure

Azure AI Search basa gli agenti di Agent Framework sui contenuti di un indice di ricerca. In Python, AzureAISearchContextProvider supporta il recupero semantico e agentico. In .NET, connetti un client Azure AI Search a TextSearchProvider.

Questa integrazione usa il modello RAG: recupera il contenuto esterno pertinente prima della chiamata al modello senza considerare tale contenuto come memoria conversazionale.

Connettere Azure AI Search a TextSearchProvider

Crea un SearchClient, mappa i risultati della ricerca in TextSearchProvider.TextSearchResult e collega il provider tramite AIContextProviders.

string projectEndpoint = System.Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
    ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = FirstNonBlank(
    System.Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME"),
    System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL"),
    "gpt-4o")!;

string searchEndpoint = FirstNonBlank(System.Environment.GetEnvironmentVariable("AZURE_SEARCH_ENDPOINT"))
    ?? throw new InvalidOperationException("AZURE_SEARCH_ENDPOINT is not set.");
string searchIndexName = FirstNonBlank(System.Environment.GetEnvironmentVariable("AZURE_SEARCH_INDEX_NAME"))
    ?? throw new InvalidOperationException("AZURE_SEARCH_INDEX_NAME is not set.");

// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
// Use a chained credential. Try a temporary dev token first (for local Docker debugging),
// then fall back to DefaultAzureCredential (for local dev via dotnet run / managed identity in
// production). The dev credential is scope aware so a single instance serves both Foundry and
// Azure AI Search clients (each Azure SDK client requests a token for its own audience).
var credential = new DefaultAzureCredential();

// Connect to the pre-provisioned search index. The caller is expected to have created the
// index and populated it with documents matching the schema (id / content / sourceName /
// sourceLink) before running this sample. See README.md for an example provisioning script.
var searchClient = new SearchClient(new Uri(searchEndpoint), searchIndexName, credential);

TextSearchProviderOptions textSearchOptions = new()
{
    SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke,
    RecentMessageMemoryLimit = 6,
};

AIAgent agent = new AIProjectClient(new Uri(projectEndpoint), credential)
    .AsAIAgent(new ChatClientAgentOptions
    {
        Name = System.Environment.GetEnvironmentVariable("AGENT_NAME") ?? "hosted-azure-search-rag",
        ChatOptions = new ChatOptions
        {
            ModelId = deploymentName,
            Instructions = "You are a helpful support specialist for Contoso Outdoors. " +
                           "Answer questions using the provided context and cite the source document when available.",
        },
        AIContextProviders = [new TextSearchProvider(CreateSearchAdapter(searchClient), textSearchOptions)]
    });

// Host the agent as a Foundry Hosted Agent using the Responses API.
// the provider will inject into the model context.

static Func<string, CancellationToken, Task<IEnumerable<TextSearchProvider.TextSearchResult>>>
    CreateSearchAdapter(SearchClient client, int top = 3) =>
    async (query, cancellationToken) =>
    {
        var options = new SearchOptions { Size = top };
        Response<SearchResults<SearchDocument>> response =
            await client.SearchAsync<SearchDocument>(query, options, cancellationToken).ConfigureAwait(false);

        var results = new List<TextSearchProvider.TextSearchResult>();
        await foreach (SearchResult<SearchDocument> hit in response.Value.GetResultsAsync().WithCancellation(cancellationToken).ConfigureAwait(false))
        {
            results.Add(new TextSearchProvider.TextSearchResult
            {
                SourceName = hit.Document.TryGetValue("sourceName", out var name) ? name?.ToString() ?? string.Empty : string.Empty,
                SourceLink = hit.Document.TryGetValue("sourceLink", out var link) ? link?.ToString() ?? string.Empty : string.Empty,
                Text = hit.Document.TryGetValue("content", out var content) ? content?.ToString() ?? string.Empty : string.Empty,
                RawRepresentation = hit
            });
        }

        return results;
    };

L'esempio ospita l'agente risultante in Foundry, ma l'adattatore di ricerca funziona con un normale ChatClientAgent.

Installare i pacchetti

pip install agent-framework-azure-ai-search agent-framework-foundry --pre

Usare il recupero semantico

La modalità semantica esegue la ricerca su un indice esistente e può combinare la parola chiave e il recupero vettoriale.

credential = AzureCliCredential()

# Get configuration from environment
search_endpoint = os.environ["AZURE_SEARCH_ENDPOINT"]
search_key = os.environ.get("AZURE_SEARCH_API_KEY")
index_name = os.environ["AZURE_SEARCH_INDEX_NAME"]
project_endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
model_deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o")
openai_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
embedding_deployment = os.environ.get("AZURE_OPENAI_EMBEDDING_MODEL")

embedding_client = None
if openai_endpoint and embedding_deployment:
    embedding_client = OpenAIEmbeddingClient(
        azure_endpoint=openai_endpoint,
        model=embedding_deployment,
        credential=credential,
    )

# Create Azure AI Search context provider with semantic mode (recommended, fast)
print("Using SEMANTIC mode (hybrid search + semantic ranking, fast)\n")
search_provider = AzureAISearchContextProvider(
    source_id="search_provider",
    endpoint=search_endpoint,
    index_name=index_name,
    api_key=search_key,  # Use api_key for API key auth, or credential for managed identity
    credential=credential if not search_key else None,
    mode="semantic",  # Default mode
    top_k=3,  # Retrieve top 3 most relevant documents
    embedding_function=embedding_client,  # Provide embedding function for hybrid search
    vector_field_name="DescriptionVector"
    if embedding_client
    else None,  # Set vector field for hybrid search if using embeddings
)

# Create agent with search context provider
async with (
    search_provider,
    Agent(
        client=FoundryChatClient(
            project_endpoint=project_endpoint,
            model=model_deployment,
            credential=credential,
        ),
        name="SearchAgent",
        instructions=(
            "You are a helpful assistant. Use the provided context from the "
            "knowledge base to answer questions accurately."
        ),
        context_providers=[search_provider],
    ) as agent,
):
    print("=== Azure AI Agent with Search Context (Semantic Mode) ===\n")

    for user_input in USER_INPUTS:
        print(f"User: {user_input}")
        print("Agent: ", end="", flush=True)

        # Stream response
        async for chunk in agent.run(user_input, stream=True):
            if chunk.text:
                print(chunk.text, end="", flush=True)

        print("\n")

Utilizzare il recupero agentico

La modalità agentica usa una Knowledge Base di Azure AI Search per la pianificazione delle query e il recupero di più hop.

# Agentic mode requires exactly ONE of: knowledge_base_name OR index_name
# Option 1: Use existing Knowledge Base (recommended)
knowledge_base_name = os.environ.get("AZURE_SEARCH_KNOWLEDGE_BASE_NAME")
# Option 2: Auto-create KB from index (requires azure_openai_resource_url)
index_name = os.environ.get("AZURE_SEARCH_INDEX_NAME")
azure_openai_resource_url = os.environ.get("AZURE_OPENAI_RESOURCE_URL")

# Create Azure AI Search context provider with agentic mode (recommended for accuracy)
print("Using AGENTIC mode (Knowledge Bases with query planning, recommended)\n")
print("This mode is slightly slower but provides more accurate results.\n")

# Configure based on whether using existing KB or auto-creating from index
if knowledge_base_name:
    # Use existing Knowledge Base - simplest approach
    search_provider = AzureAISearchContextProvider(
        source_id="search_provider",
        endpoint=search_endpoint,
        api_key=search_key,
        credential=AzureCliCredential() if not search_key else None,
        mode="agentic",
        knowledge_base_name=knowledge_base_name,
        # Optional: Configure retrieval behavior. "answer_synthesis" output mode and
        # "medium"/"low" reasoning effort require the preview build of azure-search-documents
        # (`pip install --pre azure-search-documents`); the provider auto-detects the build.
        knowledge_base_output_mode="extractive_data",  # or "answer_synthesis" (preview build only)
        retrieval_reasoning_effort="minimal",  # or "medium", "low" (preview build only)
    )
else:
    # Auto-create Knowledge Base from index
    if not index_name:
        raise ValueError("Set AZURE_SEARCH_KNOWLEDGE_BASE_NAME or AZURE_SEARCH_INDEX_NAME")
    if not azure_openai_resource_url:
        raise ValueError("AZURE_OPENAI_RESOURCE_URL required when using index_name")
    search_provider = AzureAISearchContextProvider(
        source_id="search_provider",
        endpoint=search_endpoint,
        index_name=index_name,
        api_key=search_key,
        credential=AzureCliCredential() if not search_key else None,
        mode="agentic",
        azure_openai_resource_url=azure_openai_resource_url,
        model=model_deployment,
        # Optional: Configure retrieval behavior. "answer_synthesis" output mode and
        # "medium"/"low" reasoning effort require the preview build of azure-search-documents
        # (`pip install --pre azure-search-documents`); the provider auto-detects the build.
        knowledge_base_output_mode="extractive_data",  # or "answer_synthesis" (preview build only)
        retrieval_reasoning_effort="minimal",  # or "medium", "low" (preview build only)
        top_k=3,
    )

# Create agent with search context provider
async with (
    search_provider,
    Agent(
        client=FoundryChatClient(
            project_endpoint=project_endpoint,
            model=model_deployment,
            credential=AzureCliCredential(),
        ),
        name="SearchAgent",
        instructions=(
            "You are a helpful assistant with advanced reasoning capabilities. "
            "Use the provided context from the knowledge base to answer complex "
            "questions that may require synthesizing information from multiple sources."
        ),
        context_providers=[search_provider],
    ) as agent,
):
    print("=== Azure AI Agent with Search Context (Agentic Mode) ===\n")

    for user_input in USER_INPUTS:
        print(f"User: {user_input}")
        print("Agent: ", end="", flush=True)

        # Stream response
        async for chunk in agent.run(user_input, stream=True):
            if chunk.text:
                print(chunk.text, end="", flush=True)
            for content in chunk.contents:
                if content.annotations:
                    print(f"\n[Sources: {content.annotations}]", end="", flush=True)

        print("\n")

Alcune opzioni di output e ragionamento agentico richiedono il pacchetto di anteprima azure-search-documents .

Inoltrare l'identità del chiamante per il recupero basato sulle autorizzazioni

Impostare query_source_credential=caller_credential quando un'origine dati di conoscenza usa autorizzazioni a livello di documento e i risultati del recupero devono essere filtrati in base alle autorizzazioni di sicurezza per ogni utente che effettua la richiesta. Invia le credenziali del token Azure (sincrono o asincrono) dell'utente che ha effettuato l'accesso separatamente dalle credenziali dell'applicazione che si connette ad Azure AI Search.

Per ogni recupero agentico, il provider richiede un token per https://search.azure.com/.default. Inoltra l'identità Microsoft Entra del chiamante nell'intestazione x-ms-query-source-authorization in modo che Azure AI Search possa far rispettare le autorizzazioni indicizzate.

Questa opzione richiede una build di anteprima azure-search-documents, versione 12.1.0b1 o successiva nell'intervallo 12.x supportato:

pip install --pre "azure-search-documents>=12.1.0b1,<13"

Agent Framework restituisce un errore di chiusura se l'SDK installato non supporta l'autorizzazione tramite query-source. Genera un oggetto ValueError prima di inviare una richiesta di recupero. Gli errori nell'acquisizione dei token bloccano anche il recupero; il provider non ritenta senza l'identità del chiamante.

Annotazioni

Azure AI Search attualmente non dispone di un'integrazione dedicata di Agent Framework Go. Implementa il recupero dati come strumento personalizzato o fornitore di contesto, oppure consulta il repository di Agent Framework Go per gli aggiornamenti più recenti.

Considerazioni sulla produzione

  • Preferire l'autenticazione di Microsoft Entra o l'identità gestita anziché le chiavi di ricerca.
  • Applicare filtri tenant-aware e l'isolamento degli indici.
  • Considerare il contenuto recuperato come input non attendibile e mitigare la prompt injection indiretta.
  • Mantenere i metadati di origine quando l'agente deve citare documenti.

Passaggi successivi