Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Gli strumenti front-end vengono dichiarati ed eseguiti dal client AG-UI. Il server riceve gli schemi in modo che il modello possa richiederli, ma non riceve le implementazioni.
Registrare uno strumento front-end
Creare lo strumento e passarlo all'agente supportato da AGUIChatClient:
using System.ComponentModel;
using AGUI.Client;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Get the user's current location from the client device.")]
static string GetUserLocation() => "Amsterdam, Netherlands";
AITool locationTool = AIFunctionFactory.Create(
GetUserLocation,
name: "get_user_location");
using HttpClient httpClient = new() { BaseAddress = new Uri("http://localhost:8888") };
AGUIChatClient chatClient = new(new AGUIChatClientOptions(httpClient, "/"));
AIAgent agent = chatClient.AsAIAgent(tools: [locationTool]);
AGUIChatClient gestisce il flusso di continuazione:
- Invia la dichiarazione dello strumento front-end con la richiesta di esecuzione.
- Riceve la chiamata dello strumento del modello dal server.
- Esegue la funzione corrispondente in locale.
- Invia di nuovo il risultato al server.
- Continua l'esecuzione e invia in streaming la risposta finale.
Suggerimento
Vedere l'esempio di .NET front-end-tools per un client e un server completi.
Avvertimento
Le dichiarazioni e i risultati degli strumenti forniti da un client non attendibile sono input non attendibili. Autorizzare gli strumenti client che possono influenzare l'esecuzione dell'agente sul lato server e convalidare i risultati prima di usarli per le operazioni con privilegi.
Per indicazioni generali sulla creazione di strumenti, vedere Usare gli strumenti per le funzioni con un agente.
Passaggi successivi
Questa esercitazione illustra come aggiungere strumenti di funzione front-end ai client AG-UI. Gli strumenti front-end sono funzioni eseguite sul lato client, consentendo all'agente di intelligenza artificiale di interagire con l'ambiente locale dell'utente, accedere ai dati specifici del client o eseguire operazioni dell'interfaccia utente.
Prerequisiti
Prima di iniziare, assicurarsi di aver completato l'esercitazione introduttiva e di avere:
- Python 3.10 o versione successiva
-
httpxinstallato per la funzionalità client HTTP - Conoscenza di base della configurazione del client di AG-UI
- Servizio OpenAI di Azure configurato
Che cosa sono gli strumenti front-end?
Gli strumenti front-end sono strumenti per le funzioni che:
- Vengono definiti e registrati nel client
- Eseguire nell'ambiente del client (non nel server)
- Consentire all'agente di intelligenza artificiale di interagire con risorse specifiche del client
- Fornire i risultati al server affinché l'agente possa incorporarli nelle risposte
Casi d'uso comuni:
- Lettura dei dati dei sensori locali
- Accesso all'archiviazione sul lato client o alle preferenze
- Esecuzione di operazioni dell'interfaccia utente
- Interazione con funzionalità specifiche del dispositivo
Creazione di strumenti front-end
Gli strumenti front-end in Python sono definiti in modo analogo agli strumenti back-end, ma vengono registrati con il client:
from typing import Annotated
from pydantic import BaseModel, Field
class SensorReading(BaseModel):
"""Sensor reading from client device."""
temperature: float
humidity: float
air_quality_index: int
def read_climate_sensors(
include_temperature: Annotated[bool, Field(description="Include temperature reading")] = True,
include_humidity: Annotated[bool, Field(description="Include humidity reading")] = True,
) -> SensorReading:
"""Read climate sensor data from the client device."""
# Simulate reading from local sensors
return SensorReading(
temperature=22.5 if include_temperature else 0.0,
humidity=45.0 if include_humidity else 0.0,
air_quality_index=75,
)
def change_background_color(color: Annotated[str, Field(description="Color name")] = "blue") -> str:
"""Change the console background color."""
# Simulate UI change
print(f"\n🎨 Background color changed to {color}")
return f"Background changed to {color}"
Creazione di un client AG-UI con gli strumenti front-end
Ecco un'implementazione client completa con gli strumenti front-end:
"""AG-UI client with frontend tools."""
import asyncio
import json
import os
from typing import Annotated, AsyncIterator
import httpx
from pydantic import BaseModel, Field
class SensorReading(BaseModel):
"""Sensor reading from client device."""
temperature: float
humidity: float
air_quality_index: int
# Define frontend tools
def read_climate_sensors(
include_temperature: Annotated[bool, Field(description="Include temperature")] = True,
include_humidity: Annotated[bool, Field(description="Include humidity")] = True,
) -> SensorReading:
"""Read climate sensor data from the client device."""
return SensorReading(
temperature=22.5 if include_temperature else 0.0,
humidity=45.0 if include_humidity else 0.0,
air_quality_index=75,
)
def get_user_location() -> dict:
"""Get the user's current GPS location."""
# Simulate GPS reading
return {
"latitude": 52.3676,
"longitude": 4.9041,
"accuracy": 10.0,
"city": "Amsterdam",
}
# Tool registry maps tool names to functions
FRONTEND_TOOLS = {
"read_climate_sensors": read_climate_sensors,
"get_user_location": get_user_location,
}
class AGUIClientWithTools:
"""AG-UI client with frontend tool support."""
def __init__(self, server_url: str, tools: dict):
self.server_url = server_url
self.tools = tools
self.thread_id: str | None = None
async def send_message(self, message: str) -> AsyncIterator[dict]:
"""Send a message and handle streaming response with tool execution."""
# Prepare tool declarations for the server
tool_declarations = []
for name, func in self.tools.items():
tool_declarations.append({
"name": name,
"description": func.__doc__ or "",
# Add parameter schema from function signature
})
request_data = {
"messages": [
{"role": "system", "content": "You are a helpful assistant with access to client tools."},
{"role": "user", "content": message},
],
"tools": tool_declarations, # Send tool declarations to server
}
if self.thread_id:
request_data["thread_id"] = self.thread_id
async with httpx.AsyncClient(timeout=60.0) as client:
async with client.stream(
"POST",
self.server_url,
json=request_data,
headers={"Accept": "text/event-stream"},
) as response:
response.raise_for_status()
async for line in response.aiter_lines():
if line.startswith("data: "):
data = line[6:]
try:
event = json.loads(data)
# Tool calls arrive as TOOL_CALL_START/ARGS/END events
# and results are streamed back as TOOL_CALL_RESULT events.
yield event
# Capture thread_id
if event.get("type") == "RUN_STARTED" and not self.thread_id:
self.thread_id = event.get("threadId")
except json.JSONDecodeError:
continue
async def _handle_tool_call(self, event: dict, client: httpx.AsyncClient):
"""Execute frontend tool and send result back to server."""
tool_name = event.get("toolName")
tool_call_id = event.get("toolCallId")
arguments = event.get("arguments", {})
print(f"\n\033[95m[Client Tool Call: {tool_name}]\033[0m")
print(f" Arguments: {arguments}")
try:
# Execute the tool
tool_func = self.tools.get(tool_name)
if not tool_func:
raise ValueError(f"Unknown tool: {tool_name}")
result = tool_func(**arguments)
# Convert Pydantic models to dict
if hasattr(result, "model_dump"):
result = result.model_dump()
print(f"\033[94m[Client Tool Result: {result}]\033[0m")
# In current Python AG-UI, frontend tool declarations are sent with
# the run request. Tool-call lifecycle events are streamed back over SSE.
print(f"Tool result for {tool_call_id}: {result}")
except Exception as e:
print(f"\033[91m[Tool Error: {e}]\033[0m")
print(f"Tool error for {tool_call_id}: {e}")
async def main():
"""Main client loop with frontend tools."""
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")
client = AGUIClientWithTools(server_url, FRONTEND_TOOLS)
try:
while True:
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
continue
if message.lower() in (":q", "quit"):
break
print()
async for event in client.send_message(message):
event_type = event.get("type", "")
if event_type == "RUN_STARTED":
print(f"\033[93m[Run Started]\033[0m")
elif event_type == "TEXT_MESSAGE_CONTENT":
print(f"\033[96m{event.get('delta', '')}\033[0m", end="", flush=True)
elif event_type == "RUN_FINISHED":
print(f"\n\033[92m[Run Finished]\033[0m")
elif event_type == "RUN_ERROR":
error_msg = event.get("message", "Unknown error")
print(f"\n\033[91m[Error: {error_msg}]\033[0m")
print()
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mError: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())
Funzionamento degli strumenti front-end
Flusso del protocollo
- Registrazione del client: il client invia dichiarazioni degli strumenti (nomi, descrizioni, parametri) al server
- Orchestrazione server: l'agente di intelligenza artificiale decide quando chiamare gli strumenti front-end in base alla richiesta dell'utente
-
Eventi di invocazione di strumenti: il server trasmette al client gli eventi
TOOL_CALL_START,TOOL_CALL_ARGSeTOOL_CALL_END - Esecuzione client: il client esegue lo strumento in locale
-
Eventi risultato: i risultati degli strumenti vengono rappresentati come
TOOL_CALL_RESULTeventi nel flusso - Elaborazione agente: il server incorpora il risultato e continua la risposta
Eventi chiave
-
TOOL_CALL_START/TOOL_CALL_ARGS/TOOL_CALL_END: Il server richiede e trasmette in streaming i dettagli delle chiamate agli strumenti -
TOOL_CALL_RESULT: evento del risultato dell'esecuzione dello strumento
Output previsto
User (:q or quit to exit): What's the temperature reading from my sensors?
[Run Started]
[Client Tool Call: read_climate_sensors]
Arguments: {'include_temperature': True, 'include_humidity': True}
[Client Tool Result: {'temperature': 22.5, 'humidity': 45.0, 'air_quality_index': 75}]
Based on your sensor readings, the current temperature is 22.5°C and the
humidity is at 45%. These are comfortable conditions!
[Run Finished]
Installazione del server
Il server AG-UI standard dell'esercitazione introduttiva supporta automaticamente gli strumenti front-end. Nessuna modifica necessaria sul lato server: gestisce automaticamente l'orchestrazione degli strumenti.
Migliori pratiche
Security
def access_sensitive_data() -> str:
"""Access user's sensitive data."""
# Always check permissions first
if not has_permission():
return "Error: Permission denied"
try:
# Access data
return "Data retrieved"
except Exception as e:
# Don't expose internal errors
return "Unable to access data"
Gestione degli errori
def read_file(path: str) -> str:
"""Read a local file."""
try:
with open(path, "r") as f:
return f.read()
except FileNotFoundError:
return f"Error: File not found: {path}"
except PermissionError:
return f"Error: Permission denied: {path}"
except Exception as e:
return f"Error reading file: {str(e)}"
Operazioni asincrone
async def capture_photo() -> str:
"""Capture a photo from device camera."""
# Simulate camera access
await asyncio.sleep(1)
return "photo_12345.jpg"
Troubleshooting
Strumenti non chiamati
- Verificare che le dichiarazioni degli strumenti vengano inviate al server
- Verificare che le descrizioni degli strumenti indichino chiaramente il scopo
- Controllare i log del server per la registrazione dello strumento
Errori di esecuzione
- Aggiungere una gestione completa degli errori
- Convalidare i parametri prima dell'elaborazione
- Restituire messaggi di errore intuitivi
- Errori di log per il debug
Problemi di tipo
- Usare modelli Pydantic per tipi complessi
- Convertire i modelli in dict prima della serializzazione
- Gestire le conversioni dei tipi in modo esplicito
Operazioni successive
- Rendering degli strumenti del backend: combinare con gli strumenti a lato server
Risorse aggiuntive
I server Go AG-UI possono lasciare le chiamate agli strumenti al frontend disabilitando la chiamata automatica delle funzioni sull'agente ospitato.
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You are a helpful assistant.",
Config: agent.Config{
Name: "AGUIAssistant",
DisableFuncAutoCall: true,
},
})
mux := http.NewServeMux()
mux.Handle("/", aguiprovider.NewJSONHTTPHandler(a, aguiprovider.HandlerConfig{}))
Suggerimento
Consulta l'esempio degli strumenti frontend di AG-UI per un esempio completo e funzionante.