MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1
Demo420 — Safe Telemetry
Observer des spans sûrs et distinguer mode déterministe et requêtes réelles.
Objectifs
- Observer Demo420 et ses variantes ; relier le résultat aux concepts du chapitre.
Préparer un essai isolé
Depuis la racine BaseTechnique ou du dépôt extrait, compiler la solution Release. Le projet App appelle ObservabilityDemo dans Maf.Observability ; Demo420 et Demo430 partagent cette implémentation. Le mode documenté --deterministic ne charge aucun modèle, embedding ou collecteur. Une base neuve permet de distinguer les actions de cet essai.
dotnet build BaseTechnique.slnx -m:1 -c ReleaseLancer sans modèle
$journal = Join-Path $env:TEMP ("maf-lot012-" + [guid]::NewGuid().ToString("N") + ".db")dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --deterministic --db $journalNoter ExecutionId, TraceId et Database. Attendre le workflow accepté puis ActionCommitted et ExecutionSucceeded. Les Trace: sont des JSON SafeSpan ; les Workflow event: sont des événements de progression. Dans ce mode, aucune consommation modèle n’est mesurée. Les identifiants et durées changent à chaque exécution.
public static SafeSpan Project(Activity activity) => new(
activity.Source.Name == Source.Name ? "host" : activity.Source.Name.StartsWith("System.Net.Http", StringComparison.Ordinal)
? "http" : activity.Source.Name.StartsWith("Microsoft.Agents.AI.Workflows", StringComparison.Ordinal)
? "maf.workflow" : activity.Source.Name.StartsWith("Microsoft.Extensions.AI", StringComparison.Ordinal)
? "maf.model" : "maf.agent",
activity.Source.Name == Source.Name && activity.OperationName is "execution" or "tool" or "workflow" or "model"
? activity.OperationName : "operation",
activity.TraceId.ToString(), activity.SpanId.ToString(), activity.ParentSpanId.ToString(),
activity.Duration.TotalMilliseconds, activity.Status.ToString());
Injecter une panne et relire
dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --deterministic --fail --db $journalCette nouvelle exécution a un autre GUID. --fail interrompt immédiatement avant CommitReview : sortie 1, Intention puis ExecutionFailed, aucun ActionCommitted pour ce GUID. Les actions antérieures restent présentes. --read attend un GUID existant ; remplacer la valeur de saisie par celle de l’exécution à examiner.
$executionId = Read-Host 'ExecutionId to inspect'dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --db $journal --read $executionIdSans --deterministic, le programme charge la connexion commune et appelle un vrai agent avec get_review_policy puis un reviewer natif. L’appel outil obligatoire est vérifié ; une panne ne déclenche aucune décision générée de secours. Exécuter uniquement avec le fournisseur configuré disponible ; les compteurs par requête peuvent rester null.
dotnet run --project demos/Demo420_SafeTelemetry/Demo420.App.csproj -c Release --no-build -- --db $journalVérifier la preuve, pas seulement la sortie
Dans un nouveau processus, relire le succès et vérifier ActionId avec HasAction. Relire aussi l’échec : son code de lecture peut être 0 malgré l’absence d’action, car toutes les actions présentes ont été vérifiées et il n’y en a aucune. Lire Kind et ActionId. Les tests contrôlent reprise, rejeu du même GUID, corrélation native, secrets exclus et usage manquant.
dotnet test tests/Maf.Observability.Tests/Maf.Observability.Tests.csproj -m:1 -c Release --no-build --no-restorevar input = usage?.InputTokenCount;
var output = usage?.OutputTokenCount;
long? derived = input.HasValue && output.HasValue ? checked(input.Value + output.Value) : null;
decimal? cost = rate is not null && input.HasValue && output.HasValue
? (input.Value * rate.InputPerMillion + output.Value * rate.OutputPerMillion) / 1_000_000m : null;
return new(input, output, usage?.TotalTokenCount, derived,
contextCharacters.HasValue ? ((long)contextCharacters.Value + 3) / 4 : null,
cost, rate?.Currency, rate?.Version);
Préserver la portée locale
Le commit local porte ReviewRequested ; il ne supprime, rembourse ou crée aucun effet distant. --erase supprime seulement les métadonnées de l’exécution choisie et n’est pas une annulation métier. Le journal n’est pas immuable. Une redirection de console est sous la responsabilité de son propriétaire ; aucun fichier brut n’est publié sur le site.
Suivre le code partagé
public static TracerProvider CreateProvider(Action<SafeSpan> write) => Sdk.CreateTracerProviderBuilder()
.AddSource("Maf.Renovation", "Maf.NativeAgent", "Microsoft.Agents.AI*", "Microsoft.Extensions.AI*")
.AddHttpClientInstrumentation()
.AddProcessor(new SimpleActivityExportProcessor(new SafeExporter(write))).Build();
/// <summary>Adds the native MAF decorator with sensitive data explicitly disabled.</summary>
public static AIAgent Instrument(AIAgent agent) => agent.AsBuilder()
.UseOpenTelemetry(sourceName: "Maf.NativeAgent", configure: options => options.EnableSensitiveData = false).Build();
