In Lektion 2.4 haben Sie reise-helfer im Portal gebaut. Eine Anwendung soll ihn nun ansprechen. Dieselben vier NuGet-Pakete wie in Lektion 2.3 (Azure.AI.Projects, Azure.AI.Projects.Agents, Azure.AI.Extensions.OpenAI, Azure.Identity), dieselbe Anmeldung mit az login und DefaultAzureCredential, derselbe Projekt-Endpunkt. Nur der Client ist ein anderer. Der Code ist nicht gegen Azure ausgeführt; so zeigt es Microsoft Learn. Eine Antwort des Agenten ist deshalb nirgends abgedruckt. Zur Prüfung und zu Python gilt der Hinweis aus Lektion 2.3.
Teil 1: eine Agentenversion anlegen
Learn zeigt, wie man in C# eine Agentenversion im Code anlegt. Der Code ist Learns Beispiel „Create an agent“. Geändert sind nur der Projekt-Endpunkt, der Agentenname und der Deployment-Name von Nordlicht. Lange Zeilen sind umgebrochen, sonst ist nichts verändert.
using Azure.Identity;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
// Format: "https://resource_name.services.ai.azure.com/api/projects/project_name"
var foundryProjectEndpoint =
"https://foundry-nordlicht.services.ai.azure.com/api/projects/nordlicht-ki";
var foundryAgentName = "reise-helfer";
// Create project client to call Foundry API
AIProjectClient projectClient = new(
endpoint: new Uri(foundryProjectEndpoint),
tokenProvider: new DefaultAzureCredential());
// Create an agent with a model and instructions
ProjectsAgentDefinition agentDefinition =
new DeclarativeAgentDefinition("reise-chat") // supports all Foundry direct models
{
Instructions = "You are a helpful assistant that answers general questions",
};
ProjectsAgentVersion agent =
projectClient.AgentAdministrationClient.CreateAgentVersion(
foundryAgentName,
options: new(agentDefinition));
Console.WriteLine(
$"Agent created (id: {agent.Id}, name: {agent.Name}, version: {agent.Version})");
Zeile für Zeile
AIProjectClientmit Endpunkt undDefaultAzureCredential: wie in Lektion 2.3.DeclarativeAgentDefinition("reise-chat"): die Definition eines Prompt-Agenten. Der Parameter ist das Modell, hier der Deployment-Name.Instructions: die Anweisungen. Bei Learn steht dort ein allgemeiner englischer Satz.AgentAdministrationClient.CreateAgentVersion(…): legt eine neue Version des Agenten mit diesem Namen an. Gibt es den Agenten noch nicht, entsteht er mit der ersten Version, sonst kommt eine Version hinzu. Das sagt Learns Kommentar „Create the agent (or a new version, if it already exists)“.Console.WriteLine: schreibt laut Learn Kennung, Name und Versionsnummer in die Konsole.
Achtung bei Nordlicht: Wer das Beispiel unverändert startet, legt eine Version mit Learns allgemeiner Anweisung an. Standardmäßig bedient die Adresse des Agenten die neueste Version (Lektion 2.4): Dann gelten die Grenzen aus den Anweisungen des Piloten nicht mehr. Für Nordlicht gehören die Anweisungen aus Lektion 2.4 in diese Zeichenfolge. Und: Learns Beispiel legt bei jedem Start eine Version an.
Teil 2: eine Konversation führen
Der zweite Teil von Learns Beispiel steht in derselben Datei. Sie beginnt wie oben und hat zusätzlich using OpenAI.Responses; und die Zeile #pragma warning disable OPENAI001 (wie in Lektion 2.3). Nach dem Anlegen der Version folgt:
// Create a conversation for multi-turn chat
ProjectConversation conversation = projectClient.ProjectOpenAIClient
.GetProjectConversationsClient()
.CreateProjectConversation();
// Chat with the agent to answer questions
ProjectResponsesClient responsesClient =
projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(
defaultAgent: foundryAgentName,
defaultConversationId: conversation.Id);
ResponseResult response = responsesClient.CreateResponse(
"What is the size of France in square miles?");
Console.WriteLine(response.GetOutputText());
// Ask a follow-up question in the same conversation
response = responsesClient.CreateResponse("And what is the capital city?");
Console.WriteLine(response.GetOutputText());
Die Fragen zu Frankreich sind Learns Beispielfragen. Eigene, erfundene Fragen zu einem Hotel passen besser; die zweite sollte sich auf die erste beziehen.
CreateProjectConversation(): legt eine Konversation an, den Verlauf einer Unterhaltung.GetProjectResponsesClientForAgent(defaultAgent, defaultConversationId): ein Responses-Client, der an den Agenten und an diese Konversation gebunden ist. In Lektion 2.3 war er an ein Deployment gebunden.CreateResponse(…): stellt die Frage. Der Aufruf ist hier nichtasync; Learn zeigt in diesem Beispiel die einfache Form.- Die Nachfrage „And what is the capital city?“ nennt Frankreich nicht. Sie funktioniert, weil der Client dieselbe Konversation nutzt: Laut Learn bleibt der Verlauf über die Aufrufe hinweg erhalten, und die Antwort auf die Nachfrage zeigt das.
Was eine Konversation festhält
- Foundry hängt Fragen und Antworten an die Konversation an, wenn eine verwendet wird (Learn zu Prompt-Agenten). Der Dienst verwaltet Konversationen, Werkzeugaufrufe und den Lebenszyklus des Agenten.
- Der Verlauf liegt im Dienst. Wer eigene Ressourcen nutzen will, etwa Azure Cosmos DB für den Konversationszustand, kann das laut Learn („Use your own resources“) einrichten.
- Wie lange Konversationen aufbewahrt werden und wie groß ein Verlauf werden darf, ist offen: Learn nennt es auf diesen Seiten nicht.
Für Nordlicht heißt das: Eine Konversation kann Namen und Wünsche von Kundschaft enthalten. Wo sie liegt und wie lange, gehört zur Datenschutzprüfung vor dem Pilotbetrieb (Lektion 1.1), nicht ins Belieben der Entwickler.
Aufräumen und Wiederverwenden
Learns C#-Beispiel räumt nicht auf. Die TypeScript-Fassung derselben Seite löscht am Ende die Konversation und die Agentenversion; für die C#-Methoden dazu nennt die Seite nichts, das ist offen. Das Löschen wegen Test-Resten ist trotzdem sinnvoll: Learn weist darauf hin, dass frühere Versionen weiter aufrufbar bleiben, bis sie gelöscht sind, auch wenn die Adresse auf eine neuere zeigt. Wer unsichere Konfigurationen entfernen will, löscht die Versionen und prüft, dass sie weg sind.
Zum Wiederverwenden rät Learn (Lebenszyklus): Legen Sie einen Agenten einmal an, merken Sie sich Namen und Kennung und nutzen Sie sie in späteren Läufen. Legen Sie ihn nicht bei jedem Start neu an. Gibt eine Anfrage für einen früher angelegten Agenten „404 Not Found“ zurück, wurde er gelöscht. Dann legen Sie ihn neu an und versuchen nicht endlos dieselbe Kennung.
Ein Testprojekt, das Sie ganz entfernen wollen, löschen Sie über die Ressourcengruppe, wie in Lektion 2.1.
Ein Mensch prüft jede Antwort
Der Code zeigt: Die Antwort des Agenten steht als Text in einer Variablen. Was damit geschieht, entscheidet die Anwendung. Bei Nordlicht schreibt sie den Text nie direkt an Kunden, sondern legt ihn als Entwurf vor: Ein Mensch im Kundendienst prüft jede Antwort, bevor sie hinausgeht. Kein Modell entscheidet über Erstattungen, Kündigungen oder Vertragsfragen. Das ist die Grenze des Piloten aus Lektion 1.1, und kein Code in dieser Lektion hebt sie auf.
Merktabelle
| Aufgabe | Baustein |
|---|---|
| Agentenversion anlegen | AgentAdministrationClient.CreateAgentVersion |
| Verlauf anlegen | CreateProjectConversation |
| mit Agent und Verlauf sprechen | GetProjectResponsesClientForAgent |
| fragen | CreateResponse, Text mit GetOutputText |
| Anmeldung | DefaultAzureCredential nach az login |
Übung 1
Nordlicht startet das Programm aus Teil 1 und 2 jeden Morgen für einen Test. Nach einer Woche gibt es im Projekt viele Versionen von reise-helfer. Beantworten Sie:
- Warum entstehen sie?
- Welcher Satz im Beispielcode bewirkt es?
- Was ändert Nordlicht am Programm?
Lösung 1
- Jeder Aufruf von
CreateAgentVersionlegt eine neue Version an. Jede Änderung der Konfiguration erzeugt nach Learn eine neue, unveränderliche Version. - Der Aufruf
CreateAgentVersionam Anfang des Programms. Learns Kommentar sagt, er legt den Agenten an „oder eine neue Version, wenn er schon existiert“. - Das Anlegen wird vom Chatten getrennt: Der Agent wird einmal angelegt (oder im Portal gebaut), danach nutzt das Programm nur noch Konversation und Responses-Client. Alte Test-Versionen werden gelöscht. Wie genau man sie in C# löscht, ist offen: Die TypeScript-Fassung zeigt das Löschen, für C# nennt die Seite keinen Aufruf.