Procedura per cercare documenti per significato invece che per parole. Un modello trasforma ogni testo in una serie di numeri, Azure AI Search li conserva e trova i più vicini alla domanda. Tutto da un'applicazione console .NET, senza chiavi nel codice.
Occorre: un account Azure con una sottoscrizione attiva, .NET 10 e l'interfaccia a riga di comando di Azure sul computer, un browser. Durata: circa trenta minuti. Costo: il servizio di ricerca nel piano Free non si paga: il portale indica 0,00 USD al mese. Gli embedding si pagano a consumo sui token, e la prova ne usa pochi.
Il portale delle schermate è in inglese: i nomi dei comandi sono riportati come appaiono a schermo.
Preparare le risorse
1. Crea il servizio di ricerca
Su portal.azure.com, cerca AI Search e premi + Create. Sotto Resource group premi Create new e scrivi il nome: il gruppo si crea qui, non prima. Poi premi Change Pricing Tier e scegli Free.
| Campo | Valore |
|---|---|
| Resource group | rg-guide-ais-01 (nuovo) |
| Service name | ais-guide-01 |
| Location | (Europe) West Europe |
| Pricing tier | Free |
Il piano Free dà 3 indici, 50 MB di spazio e 25 MB per i vettori: ce n'è d'avanzo per una prova, ed è uno solo per sottoscrizione. Premi Review + create e poi Create.

Le regioni compaiono e spariscono da quell'elenco quando la domanda è alta. Se West Europe non c'è, scegline un'altra e tienila uguale per tutte le risorse della guida.
2. Togli le chiavi
Nel servizio appena creato apri Security + networking → Keys e scegli Role-based access control, poi conferma. Da qui in avanti il servizio accetta solo identità, non più le chiavi di amministrazione, che infatti spariscono dalla pagina.

3. Crea la risorsa dei modelli
Serve un modello che trasformi i testi in vettori. Si crea da riga di comando:
az cognitiveservices account create \
--name foundry-guide-ais-01 \
--resource-group rg-guide-ais-01 \
--kind AIServices --sku S0 --location westeurope \
--custom-domain foundry-guide-ais-01 --yes--custom-domain non è facoltativo: senza, la risorsa riceve solo l'indirizzo comune della regione, l'indirizzo foundry-guide-ais-01.openai.azure.com non esiste e l'applicazione si ferma con No such host is known. Il nome del dominio deve essere unico in tutta Azure.
4. Distribuisci il modello
az cognitiveservices account deployment create \
--name foundry-guide-ais-01 \
--resource-group rg-guide-ais-01 \
--deployment-name text-embedding-3-small \
--model-name text-embedding-3-small \
--model-version 1 --model-format OpenAI \
--sku-capacity 1 --sku-name GlobalStandardtext-embedding-3-small restituisce 1536 numeri per ogni testo: è il numero da ripetere nella definizione dell'indice.
5. Assegna i ruoli
Senza chiavi, il permesso è un ruolo sulla risorsa. Ne servono tre:
az login
ID=$(az ad signed-in-user show --query id -o tsv)
SUB=$(az account show --query id -o tsv)
BASE="/subscriptions/$SUB/resourceGroups/rg-guide-ais-01/providers"
RICERCA="$BASE/Microsoft.Search/searchServices/ais-guide-01"
MODELLI="$BASE/Microsoft.CognitiveServices/accounts/foundry-guide-ais-01"
az role assignment create --assignee-object-id $ID --assignee-principal-type User \
--role "Search Service Contributor" --scope $RICERCA
az role assignment create --assignee-object-id $ID --assignee-principal-type User \
--role "Search Index Data Contributor" --scope $RICERCA
az role assignment create --assignee-object-id $ID --assignee-principal-type User \
--role "Cognitive Services OpenAI User" --scope $MODELLIIl primo ruolo serve a creare l'indice, il secondo a caricare e leggere i documenti, il terzo a chiamare il modello.
Scrivere l'applicazione
6. Crea il progetto
dotnet new console -n ricerca-demo
cd ricerca-demo
dotnet add package Azure.Identity --version 1.21.0
dotnet add package Azure.Search.Documents --version 12.0.0
dotnet add package OpenAI --version 2.14.07. Scrivi il codice
Sostituisce Program.cs. Fa tre cose: definisce l'indice, carica cinque frasi con il loro vettore, poi cerca i tre documenti più vicini a una domanda.
using Azure.Identity;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
using OpenAI;
using OpenAI.Embeddings;
using System.ClientModel.Primitives;
#pragma warning disable OPENAI001
const string ricerca = "https://ais-guide-01.search.windows.net";
const string modelli = "https://foundry-guide-ais-01.openai.azure.com/openai/v1";
const string modello = "text-embedding-3-small";
const string indice = "documenti";
DefaultAzureCredential credenziale = new();
BearerTokenPolicy tokenPolicy = new(
credenziale,
"https://cognitiveservices.azure.com/.default");
EmbeddingClient embedder = new(
modello,
tokenPolicy,
new OpenAIClientOptions { Endpoint = new Uri(modelli) });
string[] testi =
[
"Il gruppo di risorse raccoglie le risorse di una soluzione e si elimina in un colpo solo.",
"Azure Container Apps esegue contenitori senza gestire macchine o Kubernetes.",
"Azure AI Search indicizza documenti e li cerca per parole o per somiglianza.",
"Azure Bastion apre il desktop di una macchina virtuale dentro il browser.",
"Il registro container conserva le immagini da cui partono i contenitori.",
];
// 1. L'indice, con un campo vettoriale da 1536 numeri.
SearchIndexClient clientIndici = new(new Uri(ricerca), credenziale);
SearchIndex definizione = new(indice)
{
Fields =
{
new SimpleField("id", SearchFieldDataType.String) { IsKey = true },
new SearchableField("testo"),
new SearchField("vettore", SearchFieldDataType.Collection(SearchFieldDataType.Single))
{
IsSearchable = true,
VectorSearchDimensions = 1536,
VectorSearchProfileName = "profilo",
},
},
VectorSearch = new VectorSearch
{
Algorithms = { new HnswAlgorithmConfiguration("hnsw") },
Profiles = { new VectorSearchProfile("profilo", "hnsw") },
},
};
await clientIndici.CreateOrUpdateIndexAsync(definizione);
Console.WriteLine($"Indice '{indice}' pronto.");
// 2. Un vettore per ogni testo, poi il caricamento.
SearchClient clientRicerca = new(new Uri(ricerca), indice, credenziale);
List<SearchDocument> documenti = [];
for (int i = 0; i < testi.Length; i++)
{
var vettore = await embedder.GenerateEmbeddingAsync(testi[i]);
documenti.Add(new SearchDocument
{
["id"] = (i + 1).ToString(),
["testo"] = testi[i],
["vettore"] = vettore.Value.ToFloats().ToArray(),
});
}
await clientRicerca.UploadDocumentsAsync(documenti);
Console.WriteLine($"Caricati {documenti.Count} documenti.");
await Task.Delay(TimeSpan.FromSeconds(3));
// 3. La domanda diventa un vettore e si cercano i tre più vicini.
const string domanda = "come faccio a cancellare tutto insieme?";
var vettoreDomanda = await embedder.GenerateEmbeddingAsync(domanda);
SearchOptions opzioni = new() { Size = 3 };
opzioni.Select.Add("testo");
opzioni.VectorSearch = new VectorSearchOptions
{
Queries =
{
new VectorizedQuery(vettoreDomanda.Value.ToFloats())
{
KNearestNeighborsCount = 3,
Fields = { "vettore" },
},
},
};
Console.WriteLine($"\nDomanda: {domanda}\n");
var risultati = await clientRicerca.SearchAsync<SearchDocument>(searchText: null, opzioni);
await foreach (var r in risultati.Value.GetResultsAsync())
{
Console.WriteLine($"{r.Score:F4} {r.Document["testo"]}");
}#pragma warning disable OPENAI001 serve perché il costruttore del client con l'identità è marcato sperimentale: senza, la compilazione si ferma. L'attesa di tre secondi dopo il caricamento serve perché l'indice impiega un attimo a rendere ricercabili i documenti appena arrivati.
8. Esegui
dotnet runIndice 'documenti' pronto.
Caricati 5 documenti.
Domanda: come faccio a cancellare tutto insieme?
0,6509 Il gruppo di risorse raccoglie le risorse di una soluzione e si elimina in un colpo solo.
0,5926 Il registro container conserva le immagini da cui partono i contenitori.
0,5630 Azure Bastion apre il desktop di una macchina virtuale dentro il browser.La frase giusta arriva prima pur non avendo nessuna parola in comune con la domanda: né «cancellare» né «insieme» compaiono nel testo trovato. È questa la differenza con la ricerca per parole.
Guardare il risultato dal portale
9. L'indice
Nel servizio di ricerca apri Search management → Indexes: c'è documenti con 5 documenti.

I contatori dello spazio si aggiornano con qualche minuto di ritardo: subito dopo il caricamento segnano ancora zero.
Aprendolo, la scheda Fields mostra i tre campi: la chiave, il testo e il campo vettoriale con la sua dimensione, 1536.

10. La ricerca per parole, per confronto
Nella scheda Search explorer scrivi contenitori e premi Search: tornano due documenti, quelli che contengono la parola. La ricerca per parole trova le parole, quella per vettori trova il significato.

Eliminare le risorse
11. Elimina il gruppo di risorse
Apri rg-guide-ais-01: contiene il servizio di ricerca e la risorsa dei modelli.

Premi Delete resource group, riscrivi il nome del gruppo e premi Delete.

Conferma nella finestra che compare.

Eliminato il gruppo, la risorsa dei modelli resta in cancellazione soft e il suo nome non è riutilizzabile. Per liberarlo subito:
az cognitiveservices account purge \
--name foundry-guide-ais-01 \
--location westeurope \
--resource-group rg-guide-ais-01Nomi dei comandi e schermate rilevati sul portale di Azure il 4 novembre 2026, regione West Europe, con .NET 10.0.401 e l'interfaccia a riga di comando di Azure 2.91.0.