AI
Microsoft Foundry Toolbox : valider une version avant de la promouvoir aux agents
Un runbook de production pour tester une version de Toolbox, ses outils MCP, identités, approbations et traces avant promotion, puis revenir à la version précédente sans redéployer les agents.
Une équipe centralise dans Microsoft Foundry Toolbox un accès à Azure AI Search, un serveur MCP interne et une API OpenAPI. Plusieurs agents consomment le même endpoint. Une nouvelle version ajoute une opération, modifie un schéma d’entrée et durcit l’authentification. La promouvoir comme version par défaut paraît moins risqué qu’un redéploiement applicatif, mais le changement peut atteindre tous les agents qui suivent cette version sans modifier leur code.
Le cas d’usage est un agent d’exploitation qui recherche un runbook, lit l’état d’un service et prépare une action soumise à approbation. L’objectif n’est pas seulement de vérifier que les outils apparaissent dans tools/list. Il faut prouver le contrat, l’identité effective, la frontière d’approbation, les traces et le comportement d’échec avant de déplacer le pointeur partagé. Le rollback consiste à restaurer la version par défaut précédente, pas à improviser une nouvelle configuration pendant l’incident.
Identifier qui suit la version par défaut
Une Toolbox est un bundle nommé et versionné de configurations d’outils, exposé par un endpoint compatible MCP. Cette centralisation réduit la duplication, mais transforme la promotion en changement de plateforme. Commencez par inventorier les consommateurs et leur mode de résolution.
toolbox:
name: ops-toolbox
current_default: v17
candidate: v18
rollback_target: v17
consumers:
- agent: incident-triage
resolution: default-version
runtime_identity: mi-agent-triage-prod
sensitive_tools: [restart_job]
- agent: runbook-search
resolution: pinned-v17
runtime_identity: mi-agent-search-prod
sensitive_tools: []
- client: vscode-operations
resolution: default-version
user_identity_passthrough: true
change_scope:
added_tool: get_change_window
changed_schema: restart_job
changed_connection: operations-api
forbidden_drift: [search_index, approval_policy] Un consommateur épinglé ne reçoit pas le changement au même moment qu’un consommateur branché sur la version par défaut. L’inventaire doit aussi distinguer l’identité développeur qui administre la Toolbox, l’identité managée de l’agent qui appelle les outils et, pour un flux OAuth, l’identité utilisateur éventuellement transmise.
Geler le contrat candidat
Créez une version candidate sans la promouvoir. Le dossier de changement conserve la définition, les connexions, les stratégies de garde-fou et un digest du contrat visible par les clients. N’utilisez jamais latest comme preuve.
{
"toolbox": "ops-toolbox",
"version": "v18",
"previousDefault": "v17",
"endpointMode": "version-pinned",
"toolContractDigest": "<sha256>",
"connections": [
{"name": "runbook-search", "auth": "managed-identity"},
{"name": "operations-api", "auth": "oauth-or-managed-identity"}
],
"approvalPolicy": "approvals-v6",
"guardrailPolicy": "toolbox-rai-v4",
"owner": "platform-ai",
"expiresIfNotPromoted": "2026-08-26T18:00:00Z"
} Le digest doit être calculé sur une représentation normalisée des noms, descriptions, schémas d’entrée et métadonnées de contrôle. Il ne contient ni secret ni jeton. Si une connexion ou une policy change entre le test et la promotion, invalidez la preuve et recommencez la qualification.
Tester l’endpoint versionné comme un client MCP
Récupérez l’endpoint candidat et connectez un client isolé. La séquence minimale est initialize, puis tools/list. Vérifiez que la liste n’est pas vide, que chaque outil expose un nom, une description et un inputSchema exploitable, et que les noms restent stables et correctement préfixés.
Initialisation
HTTP 200 et session MCP initialisee
endpoint explicitement lie a v18
aucune redirection implicite vers la version par defaut
tools/list
liste non vide
noms uniques et stables
description suffisamment precise pour le choix de l'outil
inputSchema.properties present
champs requis, types et enums compatibles avec v17
outil supprime absent uniquement si la rupture est approuvee
Controles negatifs
argument inconnu refuse
scope hors production refuse par le serveur
identite sans role refusee
appel sensible sans approbation non execute
timeout et indisponibilite retournes comme erreurs Comparez v17 et v18 sous forme structurée. Un changement de description peut modifier la sélection du modèle même si le JSON Schema reste identique. Un enum élargi, un champ devenu optionnel ou une valeur par défaut côté serveur peuvent élargir l’action réelle sans casser le client.
Prouver les identités et l’approbation
Testez avec les identités qui existeront en production, mais contre des ressources bornées. Une réussite avec l’identité d’un administrateur ne valide pas l’identité managée de l’agent. Une erreur 403 doit rester visible comme un refus d’autorisation, pas être transformée en réponse vide exploitable par le modèle.
La métadonnée require_approval publiée avec un outil indique au runtime qu’une confirmation est nécessaire. Elle ne constitue pas, seule, une barrière serveur : le runtime consommateur doit présenter l’action, attendre la décision et empêcher l’appel tant que l’approbation n’est pas accordée. Pour une opération sensible, ajoutez aussi un contrôle serveur indépendant : rôle limité, périmètre de ressource, idempotency key et validation des paramètres.
tool: operations.restart_job
require_approval: always
runtime_enforcement:
show: [environment, job_id, reason, correlation_id]
approver_role: production-operator
approval_ttl_seconds: 300
server_enforcement:
allowed_environments: [preprod, production]
production_scope: [job-billing-nightly]
require_idempotency_key: true
reject_unknown_arguments: true
max_execution_seconds: 30
evidence:
log_arguments: redacted
log_result: status-only
retain_approval_id: true Testez explicitement refus, expiration et réutilisation d’une approbation. Une UI qui affiche une confirmation sans lier la décision aux arguments exacts permet qu’un appel différent profite d’une approbation ancienne.
Évaluer des scénarios, pas seulement la connectivité
Un ping réussi ne dit pas si l’agent choisit le bon outil. Rejouez un jeu borné de demandes représentatives et adversariales avec la version candidate : recherche documentaire, lecture d’état, action autorisée, action hors scope, argument ambigu, dépendance lente et réponse d’outil malformée.
blocking:
- forbidden_tool_selected
- approval_bypassed
- broader_resource_scope
- secret_or_token_in_trace
- tool_error_reported_as_success
- write_retried_without_idempotency
measured:
- tool_call_accuracy
- task_adherence
- correct_refusal
- argument_schema_validity
- p95_tool_latency
- trace_completeness
decision:
blocking_failures_allowed: 0
sensitive_cases_require_human_review: true
aggregate_score_cannot_override_blocking_failure: true Conservez la même version de prompt, de modèle et de jeu de données pendant la comparaison. Sinon, une amélioration ou une régression ne peut plus être attribuée à la Toolbox.
Vérifier les traces sans exposer les arguments
Les traces doivent relier l’exécution de l’agent, le nom et la version de Toolbox, l’outil sélectionné, la décision d’approbation, la latence et le statut final. Les arguments et résultats peuvent contenir des données sensibles : redigez-les avant ingestion et conservez seulement les champs nécessaires à l’enquête.
AgentToolInvocations
| where TimeGenerated > ago(2h)
| where ToolboxName == "ops-toolbox" and ToolboxVersion == "v18"
| summarize
Calls = count(),
Failures = countif(Status != "success"),
ApprovalBypass = countif(RequiresApproval and ApprovalDecision != "approved" and Executed),
MissingTrace = countif(isempty(AgentTraceId) or isempty(ToolCallId)),
P95LatencyMs = percentile(DurationMs, 95)
by ToolName, RuntimeIdentity
| order by ApprovalBypass desc, Failures desc AgentToolInvocations représente une table normalisée à adapter au schéma réel d’Application Insights ou de votre pipeline OpenTelemetry. Vérifiez aussi la télémétrie du runtime : une Toolbox saine avec des traces absentes reste inexploitable en production.
Promouvoir par étapes et garder le retour prêt
La promotion devient autorisée quand le contrat est figé, les contrôles négatifs passent, les identités minimales fonctionnent, aucune approbation n’est contournée, les évaluations bloquantes sont à zéro et les traces sont complètes. Commencez avec un agent de validation lié à v18, puis un canary de consommateurs explicites avant de déplacer la version par défaut.
Au moment du changement, consignez l’ancienne et la nouvelle version, l’heure UTC, le digest validé et les consommateurs attendus. Surveillez les sélections d’outil, 401/403, erreurs de schéma, délais, demandes d’approbation et effets métiers. Une baisse du nombre d’appels peut signaler que les outils ne sont plus découverts ; elle n’est pas automatiquement une amélioration.
Rollbackez vers v17 si un outil disparaît, si la portée s’élargit, si une identité échoue, si l’approbation n’est plus liée aux arguments ou si les traces deviennent incomplètes. Restaurez le pointeur de version par défaut précédent, vérifiez son digest, puis rejouez les contrôles critiques. Les agents épinglés à v18 doivent être traités séparément : changer la valeur par défaut ne les ramène pas en arrière.
Conclusion
Une Toolbox mutualise les outils, les connexions et les contrôles, mais elle mutualise aussi le risque de changement. La bonne unité de mise en production n’est donc pas un endpoint qui répond : c’est une version immuable avec un contrat, des identités, des approbations, des évaluations et des traces prouvées.
La décision finale reste simple : promouvoir v18 avec un canary et un retour testé, maintenir v17 si la preuve est incomplète, ou rollbacker immédiatement si un invariant sensible casse. Cette discipline permet de faire évoluer l’outillage des agents sans transformer une promotion centrale en changement silencieux de production.