Condividi tramite


Introduzione alle AG-UI

Questa esercitazione illustra come compilare applicazioni server e client usando il protocollo AG-UI con .NET o Python e Agent Framework. Si apprenderà come creare un server AG-UI che ospita un agente di intelligenza artificiale e un client che si connette a tale server per conversazioni interattive.

Cosa costruirai

Al termine di questa esercitazione, si avranno le seguenti informazioni:

  • Un server AG-UI che ospita un agente di intelligenza artificiale accessibile tramite HTTP
  • Applicazione client che si connette al server e trasmette le risposte
  • Informazioni sul funzionamento del protocollo AG-UI con Agent Framework

Prerequisiti

Prima di iniziare, assicurarsi di disporre degli elementi seguenti:

Annotazioni

Questi esempi usano modelli OpenAI di Azure. Per altre informazioni, vedere come distribuire modelli OpenAI di Azure con Azure AI Foundry.

Annotazioni

Questi esempi usano DefaultAzureCredential per l'autenticazione. Assicurarsi di essere autenticati con Azure (ad esempio, tramite az login). Per altre informazioni, vedere la documentazione sull'identità di Azure.

Avvertimento

Il protocollo AG-UI è ancora in fase di sviluppo e soggetto a modifiche. Questi esempi verranno aggiornati man mano che il protocollo si evolve.

Passaggio 1: Creazione di un server AG-UI

Il server AG-UI ospita l'agente di intelligenza artificiale ed esegue l'esposizione tramite endpoint HTTP usando ASP.NET Core.

Annotazioni

Il progetto server richiede l'SDK Microsoft.NET.Sdk.Web . Se si sta creando un nuovo progetto da zero, usare dotnet new web o assicurarsi che il .csproj file usi <Project Sdk="Microsoft.NET.Sdk.Web"> invece di Microsoft.NET.Sdk.

Installare i pacchetti necessari

Installare i pacchetti necessari per il server:

dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCore --prerelease
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease

Annotazioni

Il pacchetto Microsoft.Extensions.AI.OpenAI è necessario per il metodo di estensione AsIChatClient() che converte il ChatClient di OpenAI nell'interfaccia IChatClient prevista da Agent Framework.

Codice server

Creare un file denominato Program.cs:

// Copyright (c) Microsoft. All rights reserved.

using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Extensions.AI;
using OpenAI.Chat;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddAGUI();

WebApplication app = builder.Build();

string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
    ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
    ?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");

// Create the AI agent
ChatClient chatClient = new AzureOpenAIClient(
        new Uri(endpoint),
        new DefaultAzureCredential())
    .GetChatClient(deploymentName);

AIAgent agent = chatClient.AsIChatClient().AsAIAgent(
    name: "AGUIAssistant",
    instructions: "You are a helpful assistant.");

// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);

await app.RunAsync();

Concetti chiave

  • AddAGUI: registra i servizi AG-UI con il contenitore di iniezione delle dipendenze
  • MapAGUI: metodo di estensione che registra l'endpoint AG-UI con la gestione automatica delle richieste/risposte e il flusso SSE
  • ChatClient e AsIChatClient(): AzureOpenAIClient.GetChatClient() restituisce il tipo di ChatClient OpenAI. Il AsIChatClient() metodo di estensione (da Microsoft.Extensions.AI.OpenAI) lo converte nell'interfaccia IChatClient richiesta da Agent Framework
  • AsAIAgent: crea un agente di Agent Framework da un oggetto IChatClient
  • integrazione principale di ASP.NET: usa il supporto asincrono nativo di ASP.NET Core per le risposte di streaming
  • Istruzioni: l'agente viene creato con istruzioni predefinite, che possono essere sostituite dai messaggi client
  • Configurazione: AzureOpenAIClient con DefaultAzureCredential fornisce l'autenticazione sicura

Configurare ed eseguire il server

Impostare le variabili di ambiente necessarie:

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

Esegui il server

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

Il server inizierà ad essere in ascolto su http://localhost:8888.

Annotazioni

Mantenere il server in esecuzione durante la configurazione e l'esecuzione del client nel passaggio 2. Sia il server che il client devono essere eseguiti simultaneamente per il funzionamento del sistema completo.

Passaggio 2: Creazione di un client AG-UI

Il client AG-UI si connette al server remoto e visualizza le risposte in streaming.

Importante

Prima di eseguire il client, verificare che il server AG-UI dal passaggio 1 sia in esecuzione in http://localhost:8888.

Installare i pacchetti necessari

Installare la libreria client AG-UI:

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

Annotazioni

Il Microsoft.Agents.AI pacchetto fornisce il AsAIAgent() metodo di estensione.

Codice client

Creare un file denominato Program.cs:

// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AGUI;
using Microsoft.Extensions.AI;

string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888";

Console.WriteLine($"Connecting to AG-UI server at: {serverUrl}\n");

// Create the AG-UI client agent
using HttpClient httpClient = new()
{
    Timeout = TimeSpan.FromSeconds(60)
};

AGUIChatClient chatClient = new(httpClient, serverUrl);

AIAgent agent = chatClient.AsAIAgent(
    name: "agui-client",
    description: "AG-UI Client Agent");

AgentSession session = await agent.CreateSessionAsync();
List<ChatMessage> messages =
[
    new(ChatRole.System, "You are a helpful assistant.")
];

try
{
    while (true)
    {
        // Get user input
        Console.Write("\nUser (:q or quit to exit): ");
        string? message = Console.ReadLine();

        if (string.IsNullOrWhiteSpace(message))
        {
            Console.WriteLine("Request cannot be empty.");
            continue;
        }

        if (message is ":q" or "quit")
        {
            break;
        }

        messages.Add(new ChatMessage(ChatRole.User, message));

        // Stream the response
        bool isFirstUpdate = true;
        string? threadId = null;

        await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, session))
        {
            ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate();

            // First update indicates run started
            if (isFirstUpdate)
            {
                threadId = chatUpdate.ConversationId;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine($"\n[Run Started - Thread: {chatUpdate.ConversationId}, Run: {chatUpdate.ResponseId}]");
                Console.ResetColor();
                isFirstUpdate = false;
            }

            // Display streaming text content
            foreach (AIContent content in update.Contents)
            {
                if (content is TextContent textContent)
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.Write(textContent.Text);
                    Console.ResetColor();
                }
                else if (content is ErrorContent errorContent)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"\n[Error: {errorContent.Message}]");
                    Console.ResetColor();
                }
            }
        }

        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine($"\n[Run Finished - Thread: {threadId}]");
        Console.ResetColor();
    }
}
catch (Exception ex)
{
    Console.WriteLine($"\nAn error occurred: {ex.Message}");
}

Concetti chiave

  • Server-Sent Events (SSE): il protocollo utilizza SSE per trasmettere risposte in streaming.
  • AGUIChatClient: classe client che si connette ai server AG-UI e implementa IChatClient
  • AsAIAgent: metodo di estensione su AGUIChatClient per creare un agente dal client
  • RunStreamingAsync: trasmette le risposte come AgentResponseUpdate oggetti
  • AsChatResponseUpdate: metodo di estensione per accedere a proprietà specifiche della chat come ConversationId e ResponseId
  • Gestione delle sessioni: Il AgentSession mantiene il contesto della conversazione attraverso le richieste
  • Tipi di contenuto: le risposte includono TextContent per i messaggi e ErrorContent per gli errori

Configurare ed eseguire il client

Facoltativamente, impostare un URL del server personalizzato:

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

Eseguire il client in un terminale separato (verificare che il server del passaggio 1 sia in esecuzione):

dotnet run

Passaggio 3: Test del sistema completo

Con il server e il client in esecuzione, è ora possibile testare il sistema completo.

Output previsto

$ dotnet run
Connecting to AG-UI server at: http://localhost:8888

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

[Run Started - Thread: thread_abc123, Run: run_xyz789]
2 + 2 equals 4.
[Run Finished - Thread: thread_abc123]

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

[Run Started - Thread: thread_abc123, Run: 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: thread_abc123]

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

output codificato a colori

Il client visualizza diversi tipi di contenuto con colori distinti:

  • Giallo: Notifiche di avvio eseguito
  • Ciano: Risposte di testo dell'agente (trasmesse in tempo reale)
  • Verde: Eseguire le notifiche di completamento
  • Rosso: messaggi di errore

Funzionamento

Flusso lato server

  1. Il client invia una richiesta HTTP POST con messaggi
  2. ASP.NET endpoint Core riceve la richiesta tramite MapAGUI
  3. Agent elabora i messaggi usando Agent Framework
  4. Le risposte vengono convertite in eventi AG-UI
  5. Gli eventi vengono trasmessi come eventi inviati dal server (SSE)
  6. La connessione viene chiusa al termine dell'esecuzione

flusso lato client

  1. AGUIChatClient invia una richiesta HTTP POST all'endpoint server
  2. Il server risponde con il flusso SSE
  3. Il client analizza gli eventi in ingresso in AgentResponseUpdate oggetti
  4. Ogni aggiornamento viene visualizzato in base al tipo di contenuto
  5. ConversationId viene acquisito per la continuità della conversazione
  6. Lo streaming completa quando l'esecuzione termina.

Dettagli del protocollo

Il protocollo AG-UI usa:

  • HTTP POST per l'invio di richieste
  • Eventi Server-Sent (SSE) per le risposte in streaming
  • JSON per la serializzazione di eventi
  • ID thread (come ConversationId) per il mantenimento del contesto di conversazione
  • ID di esecuzione (come ResponseId) per tenere traccia delle singole esecuzioni

Passaggi successivi

Dopo aver compreso le nozioni di base di AG-UI, è possibile:

Risorse aggiuntive

Prerequisiti

Prima di iniziare, assicurarsi di disporre degli elementi seguenti:

Annotazioni

Questi esempi usano modelli OpenAI di Azure. Per altre informazioni, vedere come distribuire modelli OpenAI di Azure con Azure AI Foundry.

Annotazioni

Questi esempi usano DefaultAzureCredential per l'autenticazione. Assicurarsi di essere autenticati con Azure (ad esempio, tramite az login). Per altre informazioni, vedere la documentazione sull'identità di Azure.

Avvertimento

Il protocollo AG-UI è ancora in fase di sviluppo e soggetto a modifiche. Questi esempi verranno aggiornati man mano che il protocollo si evolve.

Passaggio 1: Creazione di un server AG-UI

Il server AG-UI ospita l'agente di intelligenza artificiale e lo espone tramite endpoint HTTP utilizzando FastAPI.

Installare i pacchetti necessari

Installare i pacchetti necessari per il server:

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

Oppure usando uv:

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

Verranno installati automaticamente agent-framework-core, fastapi e uvicorn come dipendenze.

Codice server

Creare un file denominato server.py:

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

import os

from agent_framework import Agent
from agent_framework.azure import AzureOpenAIChatClient
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_DEPLOYMENT_NAME")

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

chat_client = AzureOpenAIChatClient(
    credential=AzureCliCredential(),
    endpoint=endpoint,
    deployment_name=deployment_name,
)

# Create the AI agent
agent = Agent(
    name="AGUIAssistant",
    instructions="You are a helpful assistant.",
    chat_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)

Concetti chiave

  • add_agent_framework_fastapi_endpoint: registra l'endpoint AG-UI con la gestione automatica delle richieste/risposte e lo streaming SSE
  • Agent: agente di Agent Framework che gestirà le richieste in ingresso
  • Integrazione FastAPI: usa il supporto asincrono nativo di FastAPI per le risposte di streaming
  • Istruzioni: l'agente viene creato con istruzioni predefinite, che possono essere sostituite dai messaggi client
  • Configurazione: AzureOpenAIChatClient legge da variabili di ambiente o accetta direttamente i parametri

Configurare ed eseguire il server

Impostare le variabili di ambiente necessarie:

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

Esegui il server

python server.py

Oppure usando direttamente uvicorn:

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

Il server inizierà ad essere in ascolto su http://127.0.0.1:8888.

Passaggio 2: Creazione di un client AG-UI

Il client AG-UI si connette al server remoto e visualizza le risposte in streaming.

Installare i pacchetti necessari

Il pacchetto AG-UI è già installato, che include :AGUIChatClient

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

Codice client

Creare un file denominato 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(server_url=server_url)

    # Create agent with the chat client
    agent = Agent(
        name="ClientAgent",
        chat_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())

Concetti chiave

  • Server-Sent Events (SSE): il protocollo usa il formato SSE (data: {json}\n\n)
  • Tipi di evento: eventi diversi forniscono metadati e contenuto (MAIUSCOLA con caratteri di sottolineatura):
    • RUN_STARTED: l'agente ha avviato l'elaborazione
    • TEXT_MESSAGE_START: inizio di un messaggio di testo dall'agente
    • TEXT_MESSAGE_CONTENT: testo incrementale trasmesso dall'agente (con delta campo)
    • TEXT_MESSAGE_END: fine di un sms
    • RUN_FINISHED: Completamento riuscito
    • RUN_ERROR: informazioni sull'errore
  • Denominazione dei campi: i campi evento usano camelCase (ad esempio, threadId, runId, messageId)
  • Gestione thread: threadId mantiene il contesto della conversazione tra le richieste
  • Istruzioni lato client: i messaggi di sistema vengono inviati dal client

Configurare ed eseguire il client

Facoltativamente, impostare un URL del server personalizzato:

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

Eseguire il client (in un terminale separato):

python client.py

Passaggio 3: Test del sistema completo

Con il server e il client in esecuzione, è ora possibile testare il sistema completo.

Output previsto

$ 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

output codificato a colori

Il client visualizza diversi tipi di contenuto con colori distinti:

  • Giallo: Notifiche di avvio eseguito
  • Ciano: Risposte di testo dell'agente (trasmesse in tempo reale)
  • Verde: Eseguire le notifiche di completamento
  • Rosso: messaggi di errore

Testare con curl (facoltativo)

Prima di eseguire il client, è possibile testare manualmente il server usando curl:

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?"}
    ]
  }'

Dovresti vedere eventi inviati dal server in streaming.

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":"..."}

Funzionamento

Flusso lato server

  1. Il client invia una richiesta HTTP POST con messaggi
  2. L'endpoint FastAPI riceve la richiesta
  3. AgentFrameworkAgent Wrapper orchestra l'esecuzione
  4. Agent elabora i messaggi usando Agent Framework
  5. AgentFrameworkEventBridge converte gli aggiornamenti dell'agente in AG-UI eventi
  6. Le risposte vengono trasmesse come Eventi Inviati dal Server (SSE)
  7. La connessione viene chiusa al termine dell'esecuzione

flusso lato client

  1. Il client invia una richiesta HTTP POST all'endpoint server
  2. Il server risponde con il flusso SSE
  3. Il client analizza le righe in ingresso data: come eventi JSON
  4. Ogni evento viene visualizzato in base al tipo
  5. threadId viene acquisito per la continuità della conversazione
  6. Lo stream si completa quando arriva l'evento RUN_FINISHED

Dettagli del protocollo

Il protocollo AG-UI usa:

  • HTTP POST per l'invio di richieste
  • Eventi Server-Sent (SSE) per le risposte in streaming
  • JSON per la serializzazione di eventi
  • ID thread per la gestione del contesto di conversazione
  • Identificatori di esecuzione per tenere traccia delle singole esecuzioni
  • Denominazione del tipo di evento: MAIUSCOLA con caratteri di sottolineatura (ad esempio, RUN_STARTED, TEXT_MESSAGE_CONTENT)
  • Denominazione dei campi: camelCase (ad esempio, threadId, runId, messageId)

Modelli comuni

Configurazione del server personalizzato

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")

Agenti multipli

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")

Gestione degli errori

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}")

Risoluzione dei problemi

Connessione rifiutata

Verificare che il server sia in esecuzione prima di avviare il client:

# Terminal 1
python server.py

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

Errori di autenticazione

Assicurarsi di essere autenticati con Azure:

az login

Verificare di avere l'assegnazione di ruolo corretta nella risorsa OpenAI di Azure.

Streaming non funzionante

Verificare che il timeout del client sia sufficiente:

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

Per gli agenti a esecuzione prolungata, aumentare il timeout di conseguenza.

Contesto thread perso

Il client gestisce automaticamente la continuità dei thread. Se il contesto viene perso:

  1. Verificare che threadId venga acquisito da eventi di RUN_STARTED
  2. Verificare che la stessa istanza client venga usata tra i messaggi
  3. Verificare che il server riceva thread_id nelle richieste successive

Passaggi successivi

Dopo aver compreso le nozioni di base di AG-UI, è possibile:

Risorse aggiuntive