Erste Schritte mit AG-UI

In diesem Lernprogramm wird das Erstellen von Server- und Clientanwendungen mithilfe des AG-UI-Protokolls mit Agent Framework veranschaulicht. Sie erfahren, wie Sie einen Agent hinter einem AG-UI Endpunkt hosten und einen Client für interaktive Unterhaltungen verbinden.

Was Sie erstellen werden

Am Ende dieses Lernprogramms haben Sie Folgendes:

  • Ein AG-UI Server, auf den ein KI-Agent gehostet wird, auf den über HTTP zugegriffen werden kann
  • Eine Clientanwendung, die eine Verbindung mit dem Server herstellt und Antworten streamt
  • Grundlegendes zur Funktionsweise des AG-UI-Protokolls mit Agent Framework

Voraussetzungen

  • .NET 8 oder höher
  • Ein ASP.NET Core Projekt
  • Ein konfiguriertes MAF AIAgent

Im Beispiel wird Azure OpenAI verwendet, funktioniert jedoch MapAGUIServer mit jedem MAF-Agent.

Erstellen eines AG-UI Servers

Installieren Sie das Hostingpaket:

dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCore --prerelease

Registrieren Sie das AG-UI-Hosting und ordnen Sie Ihren Agenten zu:

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddAGUIServer();

AIAgent agent = CreateAgent();

WebApplication app = builder.Build();
app.MapAGUIServer("/", agent);
await app.RunAsync();

MapAGUIServer akzeptiert AG-UI RunAgentInput Anfragen und überträgt die Antwort des Agenten als AG-UI-Ereignisse über Server-Sent Events (SSE).

Führen Sie den Server auf der url aus, die vom Clientbeispiel verwendet wird:

dotnet run --urls http://localhost:8888

Tip

Sehen Sie sich das .NET Beispiel für erste Schritte für einen vollständigen Server- und Konsolenclient an.

Herstellen einer Verbindung mit einem .NET-Client

Das AG-UI .NET SDK bietet AGUIChatClient, das implementiert IChatClient und an einen MAF-Agent angepasst werden kann:

dotnet add package AGUI.Client --prerelease
dotnet add package Microsoft.Agents.AI --prerelease
using AGUI.Abstractions;
using AGUI.Client;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

using HttpClient httpClient = new() { BaseAddress = new Uri("http://localhost:8888") };
AGUIChatClient chatClient = new(new AGUIChatClientOptions(httpClient, "/"));
AIAgent remoteAgent = chatClient.AsAIAgent();
AgentSession session = await remoteAgent.CreateSessionAsync();

List<AgentResponseUpdate> firstTurnUpdates = [];
await foreach (AgentResponseUpdate update in
    remoteAgent.RunStreamingAsync("Hello", session))
{
    firstTurnUpdates.Add(update);

    foreach (TextContent text in update.Contents.OfType<TextContent>())
    {
        Console.Write(text.Text);
    }
}

Sie können auch eine Verbindung mit jedem Client herstellen, der das AG-UI-Protokoll implementiert.

Konversationskontinuität

AG-UI verwendet threadId und parentRunId zur Identifizierung von Fortsetzungsanfragen. Diese Bezeichner sind Protokolldaten, keine Autorisierungsanmeldeinformationen.

AGUIChatClient ist zustandslos. Um eine serverseitige Konversation fortzusetzen, rufen Sie die Bezeichner aus dem RunStartedEvent der ersten Nachricht ab und geben Sie dann in der nächsten Anfrage dieselbe threadId und die vorherige runId als parentRunId mit:

RunStartedEvent started = firstTurnUpdates
    .Select(update => update.AsChatResponseUpdate().RawRepresentation)
    .OfType<RunStartedEvent>()
    .FirstOrDefault()
    ?? throw new InvalidOperationException("The server didn't return a run-started event.");

ChatMessage nextMessage = new(ChatRole.User, "What did I just say?");
ChatClientAgentRunOptions continuationOptions = new()
{
    ChatOptions = new ChatOptions
    {
        RawRepresentationFactory = _ => new RunAgentInput
        {
            ThreadId = started.ThreadId,
            ParentRunId = started.RunId,
            Messages = new[] { nextMessage }.AsAGUIMessages().ToList(),
        },
    },
};

await foreach (AgentResponseUpdate update in
    remoteAgent.RunStreamingAsync([nextMessage], session, continuationOptions))
{
    // Process the continued response.
}

Senden Sie nur die neuen Nachrichten in einer Fortsetzungsanforderung. MapAGUIServer verwendet threadId, um die gehostete Agent-Sitzung auszuwählen, und parentRunId, um den fortgesetzten Lauf zu identifizieren. Ohne gehostete Sitzungspersistenz empfängt jede Anforderung eine neue Serversitzung; der Client kann stattdessen den Unterhaltungsverlauf erneut senden.

Um den servereigenen AgentSession Zustand über Anforderungen hinweg beizubehalten, konfigurieren Sie die Persistenz und Isolation der gehosteten Sitzung, und ordnen Sie dann den benannten gehosteten Agent zu MapAGUIServer. Informationen zur AG-UI-spezifischen Vertrauensgrenze finden Sie unter Produktions- und Sicherheitsaspekte.

Nächste Schritte

Voraussetzungen

Bevor Sie beginnen, sollten Sie sicherstellen, dass Folgendes vorhanden ist:

Note

In diesen Beispielen werden Azure OpenAI-Modelle verwendet. Weitere Informationen finden Sie in der Bereitstellung von Azure OpenAI-Modellen mit Foundry.

Note

In diesen Beispielen wird DefaultAzureCredential zur Authentifizierung verwendet. Stellen Sie sicher, dass Sie bei Azure authentifiziert sind (z. B. über az login). Weitere Informationen finden Sie in der Azure Identity-Dokumentation.

Warning

Das AG-UI Protokoll befindet sich noch in der Entwicklung und kann geändert werden. Wir werden diese Beispiele aktualisieren, während sich das Protokoll weiterentwickelt.

Schritt 1: Erstellen eines AG-UI Servers

Der AG-UI-Server hostet Ihren KI-Agent und macht ihn über HTTP-Endpunkte mit FastAPI verfügbar.

Erforderliche Pakete installieren

Installieren Sie die erforderlichen Pakete für den Server:

pip install agent-framework-ag-ui --pre

Oder uv verwenden:

uv pip install agent-framework-ag-ui --prerelease=allow

Dadurch werden agent-framework-core, fastapi, uvicorn und sse-starlette automatisch als Abhängigkeiten installiert.

Servercode

Erstellen einer Datei mit dem Namen server.py:

"""AG-UI server example."""

import os

from agent_framework import Agent
from agent_framework.openai import OpenAIChatCompletionClient
from agent_framework_ag_ui import add_agent_framework_fastapi_endpoint
from azure.identity import AzureCliCredential
from fastapi import FastAPI

# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_CHAT_COMPLETION_MODEL")

if not endpoint:
    raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
    raise ValueError("AZURE_OPENAI_CHAT_COMPLETION_MODEL environment variable is required")

chat_client = OpenAIChatCompletionClient(
    model=deployment_name,
    azure_endpoint=endpoint,
    api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
    credential=AzureCliCredential(),
)

# Create the AI agent
agent = Agent(
    name="AGUIAssistant",
    instructions="You are a helpful assistant.",
    client=chat_client,
)

# Create FastAPI app
app = FastAPI(title="AG-UI Server")

# Register the AG-UI endpoint
add_agent_framework_fastapi_endpoint(app, agent, "/")

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8888)

Wichtige Konzepte

  • add_agent_framework_fastapi_endpoint: Registriert den AG-UI Endpunkt mit automatischer Anforderungs-/Antwortbehandlung und SSE-Streaming
  • Agent: Der Agent Framework-Agent, der eingehende Anforderungen verarbeitet
  • FastAPI-Integration: Verwendet die systemeigene asynchrone Unterstützung von FastAPI für Streamingantworten
  • Anweisungen: Der Agent wird mit Standardanweisungen erstellt, die von Clientnachrichten überschrieben werden können.
  • Konfiguration: OpenAIChatCompletionClient akzeptiert explizite Azure-Routingeingaben wie model, azure_endpoint, api_version, und credential, und kann auch aus Umgebungsvariablen lesen

Konfigurieren und Ausführen des Servers

Legen Sie die erforderlichen Umgebungsvariablen fest:

export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_CHAT_COMPLETION_MODEL="gpt-4o-mini"

Führen Sie den Server aus:

python server.py

Oder verwenden Sie uvicorn direkt:

uvicorn server:app --host 127.0.0.1 --port 8888

Der Server beginnt auf http://127.0.0.1:8888 zu lauschen.

Schritt 2: Erstellen eines AG-UI-Clients

Der AG-UI-Client verbindet sich mit dem Remoteserver und zeigt Streaming-Antworten an.

Erforderliche Pakete installieren

Das AG-UI-Paket ist bereits installiert, einschließlich: AGUIChatClient

# Already installed with agent-framework-ag-ui
pip install agent-framework-ag-ui --pre

Kundencode

Erstellen einer Datei mit dem Namen client.py:

"""AG-UI client example."""

import asyncio
import os

from agent_framework import Agent
from agent_framework_ag_ui import AGUIChatClient


async def main():
    """Main client loop."""
    # Get server URL from environment or use default
    server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
    print(f"Connecting to AG-UI server at: {server_url}\n")

    # Create AG-UI chat client
    chat_client = AGUIChatClient(endpoint=server_url)

    # Create agent with the chat client
    agent = Agent(
        name="ClientAgent",
        client=chat_client,
        instructions="You are a helpful assistant.",
    )

    # Get a thread for conversation continuity
    thread = agent.create_session()

    try:
        while True:
            # Get user input
            message = input("\nUser (:q or quit to exit): ")
            if not message.strip():
                print("Request cannot be empty.")
                continue

            if message.lower() in (":q", "quit"):
                break

            # Stream the agent response
            print("\nAssistant: ", end="", flush=True)
            async for update in agent.run(message, session=thread, stream=True):
                # Print text content as it streams
                if update.text:
                    print(f"\033[96m{update.text}\033[0m", end="", flush=True)

            print("\n")

    except KeyboardInterrupt:
        print("\n\nExiting...")
    except Exception as e:
        print(f"\n\033[91mAn error occurred: {e}\033[0m")


if __name__ == "__main__":
    asyncio.run(main())

Wichtige Konzepte

  • Server-Sent Events (SSE):Das Protokoll verwendet das SSE-Format (data: {json}\n\n)
  • Ereignistypen: Verschiedene Ereignisse stellen Metadaten und Inhalte bereit (UPPERCASE mit Unterstrichen):
    • RUN_STARTED: Agent hat mit der Verarbeitung begonnen
    • TEXT_MESSAGE_START: Beginn einer Textnachricht vom Agent
    • TEXT_MESSAGE_CONTENT: Inkrementeller Text, der vom Agent gestreamt wurde (mit delta Feld)
    • TEXT_MESSAGE_END: Ende einer Textnachricht
    • RUN_FINISHED: Erfolgreicher Abschluss
    • RUN_ERROR: Fehlerinformationen
  • Feldbenennung: Ereignisfelder verwenden camelCase (z. B. threadId, , runId) messageId
  • Threadverwaltung: Das threadId verwaltet den Gesprächskontext über Anfragen hinweg.
  • Client-Side Anweisungen: Vom Client gesendete Systemnachrichten

Konfigurieren und Ausführen des Clients

Optional eine benutzerdefinierte Server-URL festlegen:

export AGUI_SERVER_URL="http://127.0.0.1:8888/"

Führen Sie den Client aus (in einem separaten Terminal):

python client.py

Schritt 3: Testen des vollständigen Systems

Wenn sowohl der Server als auch der Client ausgeführt wird, können Sie jetzt das vollständige System testen.

Erwartete Ausgabe

$ python client.py
Connecting to AG-UI server at: http://127.0.0.1:8888/

User (:q or quit to exit): What is 2 + 2?

[Run Started - Thread: abc123, Run: xyz789]
2 + 2 equals 4.
[Run Finished - Thread: abc123, Run: xyz789]

User (:q or quit to exit): Tell me a fun fact about space

[Run Started - Thread: abc123, Run: def456]
Here's a fun fact: A day on Venus is longer than its year! Venus takes
about 243 Earth days to rotate once on its axis, but only about 225 Earth
days to orbit the Sun.
[Run Finished - Thread: abc123, Run: def456]

User (:q or quit to exit): :q

Farbkodierte Ausgabe

Der Client zeigt verschiedene Inhaltstypen mit unterschiedlichen Farben an:

  • Gelb: Gestartete Benachrichtigungen ausführen
  • Cyan: Agent-Textantworten (in Echtzeit gestreamt)
  • Grün: Ausführen von Abschlussbenachrichtigungen
  • Rot: Fehlermeldungen

Testen mit curl (optional)

Bevor Sie den Client ausführen, können Sie den Server manuell mit curl testen:

curl -N http://127.0.0.1:8888/ \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "messages": [
      {"role": "user", "content": "What is 2 + 2?"}
    ]
  }'

Sie sollten das Streaming von Server-Sent-Events wieder sehen.

data: {"type":"RUN_STARTED","threadId":"...","runId":"..."}

data: {"type":"TEXT_MESSAGE_START","messageId":"...","role":"assistant"}

data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":"The"}

data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":" answer"}

...

data: {"type":"TEXT_MESSAGE_END","messageId":"..."}

data: {"type":"RUN_FINISHED","threadId":"...","runId":"..."}

Bei einem inaktiven Datenstrom kann curl auch : keepaliveKommentarzeilen anzeigen. Hierbei handelt es sich um SSE-Transportkommentare, nicht AG-UI Ereignisse.

Funktionsweise

Server-Side Ablauf

  1. Client sendet HTTP POST-Anforderung mit Nachrichten
  2. Der FastAPI-Endpunkt empfängt die Anforderung.
  3. AgentFrameworkAgent Wrapper orchestriert die Ausführung
  4. Agent verarbeitet die Nachrichten mithilfe von Agent Framework
  5. AgentFrameworkEventBridge konvertiert Agentupdates in AG-UI Ereignisse
  6. Antworten werden als Server-Sent Events (SSE) zurückübertragen.
  7. Die Verbindung schließt, wenn der Lauf abgeschlossen ist.

Client-seitiger Ablauf

  1. Client sendet HTTP POST-Anforderung an den Serverendpunkt
  2. Server antwortet mit SSE-Stream
  3. Client analysiert eingehende data: Zeilen als JSON-Ereignisse
  4. Jedes Ereignis wird basierend auf seinem Typ angezeigt.
  5. threadId wird zur Wahrung der Gesprächskontinuität erfasst.
  6. Der Stream wird abgeschlossen, wenn das RUN_FINISHED Ereignis eintrifft.

Protokolldetails

Das AG-UI Protokoll verwendet:

  • HTTP POST zum Senden von Anforderungen
  • Server-Sent Events (SSE) für Streamingantworten
  • JSON für die Ereignis serialisierung
  • Thread-IDs zur Aufrechterhaltung des Gesprächskontexts
  • Ausführen von IDs zum Nachverfolgen einzelner Ausführungen
  • Benennung des Ereignistyps: GROßBUCHSTABEN mit Unterstrichen (z. B. RUN_STARTED, TEXT_MESSAGE_CONTENT)
  • Feldbenennung: camelCase (z. B., threadId, runId, messageId)
  • SSE-Keepalive-Kommentare alle 15 Sekunden senden, wenn ein Stream inaktiv ist. Clients, die nur data: Zeilen verarbeiten, ignorieren diese Kommentare automatisch.

Allgemeine Muster

Benutzerdefinierte Serverkonfiguration

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# Add CORS for web clients
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

add_agent_framework_fastapi_endpoint(
    app,
    agent,
    "/agent",
    keepalive_seconds=30,  # Defaults to 15; set to None to disable
)

keepalive_seconds muss eine positive Zahl oder None sein.

Mehrere Agenten

app = FastAPI()

weather_agent = Agent(name="weather", ...)
finance_agent = Agent(name="finance", ...)

add_agent_framework_fastapi_endpoint(app, weather_agent, "/weather")
add_agent_framework_fastapi_endpoint(app, finance_agent, "/finance")

Fehlerbehandlung

try:
    async for event in client.send_message(message):
        if event.get("type") == "RUN_ERROR":
            error_msg = event.get("message", "Unknown error")
            print(f"Error: {error_msg}")
            # Handle error appropriately
except httpx.HTTPError as e:
    print(f"HTTP error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Troubleshooting

Verbindung verweigert

Stellen Sie sicher, dass der Server ausgeführt wird, bevor Sie den Client starten:

# Terminal 1
python server.py

# Terminal 2 (after server starts)
python client.py

Authentifizierungsfehler

Stellen Sie sicher, dass Sie bei Azure authentifiziert sind:

az login

Stellen Sie sicher, dass Sie über die richtige Rollenzuweisung für die Azure OpenAI-Ressource verfügen.

Streaming funktioniert nicht

Überprüfen Sie, ob Ihr Client-Timeout angemessen ist:

httpx.AsyncClient(timeout=60.0)  # 60 seconds should be enough

Erhöhen Sie bei lang laufenden Agenten das Timeout entsprechend.

Inaktive Streams senden standardmäßig alle 15 Sekunden einen SSE-Keepalive-Kommentar. Wenn ein Proxy Leerlaufverbindungen schneller schließt, konfigurieren Sie beim Registrieren des Endpunkts einen kleineren positiven keepalive_seconds Wert.

Threadkontext verloren

Der Client verwaltet automatisch die Threadkontinuität. Wenn der Kontext verloren geht:

  1. Überprüfen, ob threadId aus RUN_STARTED Ereignissen erfasst wird
  2. Stellen Sie sicher, dass dieselbe Clientinstanz über alle Nachrichten hinweg verwendet wird
  3. Überprüfen Sie, ob der Server das thread_id bei den nachfolgenden Anfragen empfängt.

Nächste Schritte

Nachdem Sie nun die Grundlagen der AG-UI verstanden haben, können Sie:

Zusätzliche Ressourcen

Go unterstützt AG-UI über provider/aguiprovider sowohl für Server als auch für Clients.

import "github.com/microsoft/agent-framework-go/provider/aguiprovider"

mux := http.NewServeMux()
mux.Handle("/", aguiprovider.NewJSONHTTPHandler(myAgent, aguiprovider.HandlerConfig{}))

if err := http.ListenAndServe(":8888", mux); err != nil {
    log.Fatal(err)
}

Verwenden Sie aguiprovider.NewAgent, wenn Ihre Go-App einen AG-UI-Server als Agent aufrufen muss:

import aguiSSEClient "github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/client/sse"

a := aguiprovider.NewAgent(
    aguiSSEClient.NewClient(aguiSSEClient.Config{Endpoint: serverURL}),
    aguiprovider.AgentConfig{},
)

Tip

Siehe die AG-UI-Beispiele für den Einstieg mit dem Server und dem Client für vollständige ausführbare Beispiele.