Azure.AI.Agents.Persistent (.NET)
Low-Level-SDK für die Erstellung und Verwaltung persistenter KI-Agenten mit Threads, Nachrichten, Ausführungen und Tools.
Installation
dotnet add package Azure.AI.Agents.Persistent --prerelease
dotnet add package Azure.Identity
Aktuelle Versionen: Stabil v1.1.0, Vorschau v1.2.0-beta.8
Umgebungsvariablen
PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>
MODEL_DEPLOYMENT_NAME=gpt-4o-mini
AZURE_BING_CONNECTION_ID=<bing-connection-resource-id>
AZURE_AI_SEARCH_CONNECTION_ID=<search-connection-resource-id>
AZURE_TOKEN_CREDENTIALS=prod
Authentifizierung
using Azure.AI.Agents.Persistent;
using Azure.Identity;
var projectEndpoint = Environment.GetEnvironmentVariable("PROJECT_ENDPOINT");
var credential = new DefaultAzureCredential(
DefaultAzureCredential.DefaultEnvironmentVariableName
);
PersistentAgentsClient client = new(projectEndpoint, credential);
Client-Hierarchie
PersistentAgentsClient
├── Administration → Agent-CRUD-Operationen
├── Threads → Thread-Verwaltung
├── Messages → Nachrichtenoperationen
├── Runs → Ausführung und Streaming
├── Files → Datei-Upload/Download
└── VectorStores → Vektor-Store-Verwaltung
Kernablauf
1. Agent erstellen
var modelDeploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME");
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Mathe-Tutor",
instructions: "Du bist ein persönlicher Mathe-Tutor. Schreibe und führe Code aus, um Mathefragen zu beantworten.",
tools: [new CodeInterpreterToolDefinition()]
);
2. Thread und Nachricht erstellen
PersistentAgentThread thread = await client.Threads.CreateThreadAsync();
await client.Messages.CreateMessageAsync(
thread.Id,
MessageRole.User,
"Ich muss die Gleichung `3x + 11 = 14` lösen. Kannst du mir helfen?"
);
3. Agent ausführen (Polling)
ThreadRun run = await client.Runs.CreateRunAsync(
thread.Id,
agent.Id,
additionalInstructions: "Bitte spreche den Benutzer als Max Mustermann an."
);
await Task.Delay(TimeSpan.FromMilliseconds(500));
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress)
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
}
await foreach (PersistentThreadMessage message in client.Messages.GetMessagesAsync(
threadId: thread.Id,
order: ListSortOrder.Ascending))
{
Console.Write($"{message.Role}: ");
foreach (MessageContent content in message.ContentItems)
{
if (content is MessageTextContent textContent)
Console.WriteLine(textContent.Text);
}
}
4. Streaming-Antwort
AsyncCollectionResult<StreamingUpdate> stream = client.Runs.CreateRunStreamingAsync(
thread.Id,
agent.Id
);
await foreach (StreamingUpdate update in stream)
{
if (update.UpdateKind == StreamingUpdateReason.RunCreated)
{
Console.WriteLine("--- Ausführung gestartet! ---");
}
else if (update is MessageContentUpdate contentUpdate)
{
Console.Write(contentUpdate.Text);
}
else if (update.UpdateKind == StreamingUpdateReason.RunCompleted)
{
Console.WriteLine("\n--- Ausführung abgeschlossen! ---");
}
}
5. Funktionsaufrufe
FunctionToolDefinition weatherTool = new(
name: "getCurrentWeather",
description: "Ermittelt das aktuelle Wetter an einem Ort.",
parameters: BinaryData.FromObjectAsJson(new
{
Type = "object",
Properties = new
{
Location = new { Type = "string", Description = "Stadt und Bundesland, z.B. Berlin, Deutschland" },
Unit = new { Type = "string", Enum = new[] { "c", "f" } }
},
Required = new[] { "location" }
}, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Wetter-Bot",
instructions: "Du bist ein Wetter-Bot.",
tools: [weatherTool]
);
do
{
await Task.Delay(500);
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
if (run.Status == RunStatus.RequiresAction
&& run.RequiredAction is SubmitToolOutputsAction submitAction)
{
List<ToolOutput> outputs = [];
foreach (RequiredToolCall toolCall in submitAction.ToolCalls)
{
if (toolCall is RequiredFunctionToolCall funcCall)
{
string result = ExecuteFunction(funcCall.Name, funcCall.Arguments);
outputs.Add(new ToolOutput(toolCall, result));
}
}
run = await client.Runs.SubmitToolOutputsToRunAsync(run, outputs, toolApprovals: null);
}
}
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress);
6. Dateisuche mit Vektor-Store
PersistentAgentFileInfo file = await client.Files.UploadFileAsync(
filePath: "document.txt",
purpose: PersistentAgentFilePurpose.Agents
);
PersistentAgentsVectorStore vectorStore = await client.VectorStores.CreateVectorStoreAsync(
fileIds: [file.Id],
name: "mein_vektor_store"
);
FileSearchToolResource fileSearchResource = new();
fileSearchResource.VectorStoreIds.Add(vectorStore.Id);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Dokumenten-Assistent",
instructions: "Du hilfst Benutzern, Informationen in Dokumenten zu finden.",
tools: [new FileSearchToolDefinition()],
toolResources: new ToolResources { FileSearch = fileSearchResource }
);
7. Bing Grounding
var bingConnectionId = Environment.GetEnvironmentVariable("AZURE_BING_CONNECTION_ID");
BingGroundingToolDefinition bingTool = new(
new BingGroundingSearchToolParameters(
[new BingGroundingSearchConfiguration(bingConnectionId)]
)
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Such-Agent",
instructions: "Verwende Bing, um Fragen zu aktuellen Ereignissen zu beantworten.",
tools: [bingTool]
);
8. Azure AI Search
AzureAISearchToolResource searchResource = new(
connectionId: searchConnectionId,
indexName: "mein_index",
topK: 5,
filter: "category eq 'documentation'",
queryType: AzureAISearchQueryType.Simple
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Such-Agent",
instructions: "Durchsuche den Dokumentationsindex, um Fragen zu beantworten.",
tools: [new AzureAISearchToolDefinition()],
toolResources: new ToolResources { AzureAISearch = searchResource }
);
9. Bereinigung
await client.Threads.DeleteThreadAsync(thread.Id);
await client.Administration.DeleteAgentAsync(agent.Id);
await client.VectorStores.DeleteVectorStoreAsync(vectorStore.Id);
await client.Files.DeleteFileAsync(file.Id);
Verfügbare Werkzeuge
| Werkzeug | Klasse | Zweck |
|---|
| Code-Interpreter | CodeInterpreterToolDefinition | Python-Code ausführen, Visualisierungen erstellen |
| Dateisuche | FileSearchToolDefinition | Hochgeladene Dateien über Vektor-Stores durchsuchen |
| Funktionsaufrufe | FunctionToolDefinition | Benutzerdefinierte Funktionen aufrufen |
| Bing Grounding | BingGroundingToolDefinition | Websuche über Bing |
| Azure AI Search | AzureAISearchToolDefinition | Azure AI Search-Indizes durchsuchen |
| OpenAPI | OpenApiToolDefinition | Externe APIs über OpenAPI-Spezifikation aufrufen |
| Azure Functions | AzureFunctionToolDefinition | Azure Functions aufrufen |
| MCP | MCPToolDefinition | Model Context Protocol-Werkzeuge |
| SharePoint | SharepointToolDefinition | Auf SharePoint-Inhalte zugreifen |
| Microsoft Fabric | MicrosoftFabricToolDefinition | Auf Fabric-Daten zugreifen |
Arten von Streaming-Updates
| Update-Typ | Beschreibung |
|---|
StreamingUpdateReason.RunCreated | Ausführung gestartet |
StreamingUpdateReason.RunInProgress | Ausführung läuft |
StreamingUpdateReason.RunCompleted | Ausführung abgeschlossen |
StreamingUpdateReason.RunFailed | Ausführung fehlgeschlagen |
MessageContentUpdate | Textinhalt-Abschnitt |
RunStepUpdate | Statusänderung des Schritts |
Referenz wichtiger Typen
| Typ | Zweck |
|---|
PersistentAgentsClient | Haupteinstiegspunkt |
PersistentAgent | Agent mit Modell, Anweisungen, Werkzeugen |
PersistentAgentThread | Unterhaltungsthread |
PersistentThreadMessage | Nachricht in einem Thread |
ThreadRun | Ausführung eines Agenten gegen einen Thread |
RunStatus | InWarteschlange, InBearbeitung, ErfordertAktion, Abgeschlossen, Fehlgeschlagen |
ToolResources | Kombinierte Werkzeugressourcen |
ToolOutput | Antwort eines Funktionsaufrufs |
Best Practices
- Clients immer entsorgen —
using-Anweisungen oder explizite Entsorgung verwenden
- Mit angemessenen Verzögerungen abfragen — 500ms zwischen Statusabfragen empfohlen
- Ressourcen bereinigen — Threads und Agenten nach der Verwendung löschen
- Alle Ausführungsstatus behandeln — Auf
RequiresAction, Failed, Cancelled prüfen
- Streaming für Echtzeit-Benutzererlebnis verwenden — Bessere Benutzererfahrung als Polling
- IDs, nicht Objekte speichern — Agenten/Threads über ID referenzieren
- Asynchrone Methoden verwenden — Alle Operationen sollten asynchron sein
Fehlerbehandlung
using Azure;
try
{
var agent = await client.Administration.CreateAgentAsync(...);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
Console.WriteLine("Ressource nicht gefunden");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Fehler: {ex.Status} - {ex.ErrorCode}: {ex.Message}");
}
Verwandte SDKs
| SDK | Zweck | Installationsbefehl |
|---|
Azure.AI.Agents.Persistent | Low-Level-Agenten (dieses SDK) | dotnet add package Azure.AI.Agents.Persistent |
Azure.AI.Projects | High-Level-Projektclient | dotnet add package Azure.AI.Projects |
Referenzlinks