Chi arriva a Microsoft Foundry dopo aver lavorato con Azure Machine Learning cerca istintivamente l’equivalente del workspace, e lo trova solo a metà. In Foundry non esiste una singola risorsa che contiene tutto: esiste una risorsa Foundry, che è il confine di governance dove vivono rete, sicurezza e model deployment, e esistono i progetti, che sono confini di sviluppo dentro quella risorsa. Per un MLOps engineer la distinzione non è accademica: decide che cosa finisce nel template gestito dalla piattaforma e che cosa un team può creare da solo senza riaprire un ticket.
Risorsa, progetto e asset: che cosa si crea davvero
Sotto il portale ci sono due tipi ARM. La risorsa Foundry è Microsoft.CognitiveServices/accounts con kind uguale a AIServices; il progetto è Microsoft.CognitiveServices/accounts/projects, cioè una sottorisorsa dell’account. Vivono nello stesso resource provider di Azure OpenAI, Speech, Language e Vision, e questo ha una conseguenza pratica che vale la pena ricordare: le API di management, le azioni RBAC e gli alias per Azure Policy sono allineati, quindi le policy custom e le assegnazioni di ruolo scritte per Azure OpenAI continuano a valere quando si passa a Foundry.
La ripartizione delle responsabilità segue la gerarchia. A livello di risorsa si configurano networking, sicurezza, deployment dei modelli e connessioni condivise. A livello di progetto vivono gli asset di progetto (file, agenti, valutazioni, dataset) e un confine di access control proprio. Le risorse connesse — Azure Storage, Azure Key Vault, Azure AI Search, Azure Cosmos DB — restano risorse Azure a sé stanti, con un confine di governance separato: rete, policy di accesso e compliance si gestiscono lì, non dentro Foundry.
La stessa separazione si ritrova nel control plane e nel data plane. Creare la risorsa, creare un progetto, creare un capability host, distribuire un modello e creare una connessione sono azioni di control plane; costruire agenti, eseguire valutazioni, fare tracing e fine-tuning sono azioni di data plane. RBAC lo riflette letteralmente: actions per il primo, dataActions per il secondo. Attenzione infine a un dettaglio asimmetrico: la maggior parte delle API nuove è a scope di progetto, ma alcune capacità ereditate restano solo a livello di risorsa (l’API Translator, per esempio) e non hanno un equivalente di progetto.
Il progetto default non è un progetto come gli altri
Il primo progetto creato su una risorsa è il progetto default: lo riconosci dal tag “default” nelle interfacce e dalla proprietà is_default quando lavori da codice. Non è un’etichetta cosmetica. Inferenza, playground, agenti, valutazioni, tracing, dataset, indici e connessioni funzionano su tutti i progetti; ma OpenAI Batch, fine-tuning e stored completions sono disponibili solo sul progetto default, e sui progetti non default l’OpenAI SDK copre Responses, Files e Conversations.
Per chi automatizza, questo è un fallimento che non assomiglia a un problema di permessi: una pipeline di fine-tuning puntata su un progetto secondario non fallisce con un 403, fallisce perché quella capacità lì non c’è. C’è anche un secondo effetto da conoscere: se elimini il progetto default, il prossimo progetto creato diventa il default. Lo stato di default non è quindi un attributo stabile su cui costruire l’automazione — se conta per il tuo flusso, va verificato a runtime, non assunto.
Da Azure CLI, l’ordine dei passi è vincolante
Qui sta l’errore tipico. L’istinto suggerisce di creare l’account e poi aggiungere quello che serve, ma due proprietà si impostano solo alla creazione. La risorsa va creata con la gestione dei progetti abilitata e con una managed identity assegnata; senza la prima non potrai attivarla dopo, senza la seconda la creazione del progetto fallisce con un errore che chiede una managed identity abilitata sulla risorsa. Serve la CLI in versione 2.80.0 o superiore e il ruolo Contributor o Owner sul resource group.
az group create --name my-foundry-rg --location eastus
az cognitiveservices account create \
--name my-foundry-resource \
--resource-group my-foundry-rg \
--kind AIServices \
--sku S0 \
--location eastus \
--custom-domain my-foundry-resource \
--assign-identity \
--allow-project-management true
az cognitiveservices account project create \
--name my-foundry-resource \
--resource-group my-foundry-rg \
--project-name my-foundry-project \
--location eastus
Il parametro --custom-domain deve essere globalmente unico (altrimenti il comando restituisce CustomDomainInUse) ed è anche il prerequisito dell’autenticazione a token con Microsoft Entra ID: non è un vezzo estetico. Chiudi sempre con una verifica esplicita di properties.provisioningState sull’account e sul progetto, perché è il controllo che una pipeline può leggere senza interpretare output umani.
Lo stesso ambiente in Bicep, promosso fra ambienti
Bicep è dichiarativo e idempotente, non richiede uno state file da custodire e risolve da solo l’ordine delle dipendenze: è la forma giusta per un ambiente che deve esistere identico in dev, test e produzione. Account e progetto stanno nello stesso template, e il deploy è un comando solo.
az deployment group create \
--resource-group exampleRG \
--template-file main.bicep \
--parameters aiFoundryName=myai aiProjectName=myai-proj
Un template, un file di parametri per ambiente. Poiché il nome della risorsa deve essere globalmente unico, il suffisso d’ambiente va parametrizzato, non scritto a mano. Se parti da una risorsa già creata nel portale puoi esportarla come Bicep, ma il file esportato contiene ID di sottoscrizione, resource group e resource ID cablati: vanno sostituiti con parametri prima di riusarlo. Prima di promuovere in produzione, l’operazione what-if ti mostra le modifiche previste senza applicarle.
Una trappola concreta: se il template include anche un model deployment che punta a una versione ritirata, l’intero deploy fallisce con ServiceModelDeprecating. È un buon motivo per tenere nome e versione del modello come parametri e non come costanti nel template.
Da ricordare per l esame
- La risorsa Foundry è
Microsoft.CognitiveServices/accountsconkindAIServices; il progetto è la sottorisorsaaccounts/projects. Governance e model deployment stanno sulla risorsa, gli asset e l’access control di sviluppo stanno sul progetto. - Le risorse connesse (Storage, Key Vault, Azure AI Search, Cosmos DB) hanno un confine di governance separato: rete e accessi si configurano su di loro.
- Da Azure CLI la risorsa va creata con
--assign-identitye--allow-project-management true: la seconda non è modificabile dopo la creazione e senza la prima la creazione del progetto fallisce. - Il progetto default abilita OpenAI Batch, fine-tuning e stored completions; gli altri progetti no. Se elimini il default, il prossimo progetto creato prende quel ruolo.
- Bicep più
az deployment group createè il pattern IaC richiesto: un template, un file di parametri per ambiente,what-ifprima di promuovere, versione del modello parametrizzata.