Oharra
Baimena behar duzu orria atzitzeko. Direktorioetan saioa has dezakezu edo haiek alda ditzakezu.
Baimena behar duzu orria atzitzeko. Direktorioak alda ditzakezu.
En este tutorial se muestra cómo agregar herramientas de función de front-end a los clientes de AG-UI. Las herramientas de front-end son funciones que se ejecutan en el lado cliente, lo que permite que el agente de IA interactúe con el entorno local del usuario, acceda a datos específicos del cliente o realice operaciones de interfaz de usuario. El servidor organiza cuándo llamar a estas herramientas, pero la ejecución se produce completamente en el cliente.
Prerrequisitos
Antes de comenzar, asegúrese de que ha completado el tutorial de introducción y que tiene:
- .NET 8.0 o posterior
-
Microsoft.Agents.AI.AGUIpaquete instalado -
Microsoft.Agents.AIpaquete instalado - Conocimientos básicos de la configuración del cliente de AG-UI
¿Qué son las herramientas de front-end?
Las herramientas de front-end son herramientas de función que:
- Se definen y registran en el cliente
- Ejecutar en el entorno del cliente (no en el servidor)
- Permitir que el agente de IA interactúe con recursos específicos del cliente
- Proporcionar los resultados al servidor para que el agente los incorpore en las respuestas.
- Habilitación de experiencias personalizadas y compatibles con el contexto
Casos de uso comunes:
- Lectura de datos del sensor local (GPS, temperatura, etc.)
- Acceso al almacenamiento o preferencias del lado cliente
- Realizar operaciones de interfaz de usuario (cambiar temas, mostrar notificaciones)
- Interacción con características específicas del dispositivo (cámara, micrófono)
Registro de herramientas de front-end en el cliente
La diferencia clave del tutorial de introducción es registrar herramientas con el agente del cliente. Estos son los cambios:
// Define a frontend function tool
[Description("Get the user's current location from GPS.")]
static string GetUserLocation()
{
// Access client-side GPS
return "Amsterdam, Netherlands (52.37°N, 4.90°E)";
}
// Create frontend tools
AITool[] frontendTools = [AIFunctionFactory.Create(GetUserLocation)];
// Pass tools when creating the agent
AIAgent agent = chatClient.AsAIAgent(
name: "agui-client",
description: "AG-UI Client Agent",
tools: frontendTools);
El resto del código de cliente sigue siendo el mismo que se muestra en el tutorial Introducción.
Cómo se envían las herramientas al servidor
Al registrar herramientas con AsAIAgent(), AGUIChatClient automáticamente:
- Captura las definiciones de herramientas (nombres, descripciones, esquemas de parámetros)
- Envía las herramientas con cada solicitud al agente de servidor que los asigna a
ChatAgentRunOptions.ChatOptions.Tools
El servidor recibe las declaraciones de la herramienta cliente y el modelo de IA puede decidir cuándo llamarlas.
Inspección y modificación de herramientas con middleware
Puede usar el middleware del agente para inspeccionar o modificar la ejecución del agente, incluido el acceso a las herramientas:
// Create agent with middleware that inspects tools
AIAgent inspectableAgent = baseAgent
.AsBuilder()
.Use(runFunc: null, runStreamingFunc: InspectToolsMiddleware)
.Build();
static async IAsyncEnumerable<AgentResponseUpdate> InspectToolsMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
// Access the tools from ChatClientAgentRunOptions
if (options is ChatClientAgentRunOptions chatOptions)
{
IList<AITool>? tools = chatOptions.ChatOptions?.Tools;
if (tools != null)
{
Console.WriteLine($"Tools available for this run: {tools.Count}");
foreach (AITool tool in tools)
{
if (tool is AIFunction function)
{
Console.WriteLine($" - {function.Metadata.Name}: {function.Metadata.Description}");
}
}
}
}
await foreach (AgentResponseUpdate update in innerAgent.RunStreamingAsync(messages, session, options, cancellationToken))
{
yield return update;
}
}
Este patrón de middleware le permite:
- Validación de definiciones de herramientas antes de la ejecución
Conceptos clave
A continuación se muestran nuevos conceptos para las herramientas de front-end:
-
Registro del lado cliente: las herramientas se registran en el cliente mediante
AIFunctionFactory.Create()y se pasan aAsAIAgent() -
Captura automática: las herramientas se capturan y envían automáticamente a través de
ChatAgentRunOptions.ChatOptions.Tools
Cómo funcionan las herramientas de front-end
flujo del lado del servidor
El servidor no conoce los detalles de implementación de las herramientas de front-end. Solo sabe lo siguiente:
- Nombres y descripciones de herramientas (desde el registro de cliente)
- Esquemas de parámetros
- Cuándo solicitar la ejecución de la herramienta
Cuando el agente de IA decide llamar a una herramienta de front-end:
- El servidor envía una solicitud de llamada de herramienta al cliente a través de SSE
- El servidor espera a que el cliente ejecute la herramienta y devuelva resultados
- El servidor incorpora los resultados en el contexto del agente
- El agente continúa procesando los resultados de la herramienta
Flujo del lado del cliente
El cliente controla la ejecución de la herramienta de front-end:
- Recibe
FunctionCallContentdesde el servidor que indica una solicitud para llamar a la herramienta - Corresponde el nombre de la herramienta a una función registrada localmente.
- Deserializa los parámetros de la petición.
- Ejecuta la función localmente.
- Serializa el resultado
- Devuelve
FunctionResultContental servidor. - Continúa recibiendo respuestas del agente
Salida esperada con herramientas de front-end
Cuando el agente llame a las herramientas de front-end, verá la llamada a la herramienta y dará como resultado la salida de streaming:
User (:q or quit to exit): Where am I located?
[Client Tool Call - Name: GetUserLocation]
[Client Tool Result: Amsterdam, Netherlands (52.37°N, 4.90°E)]
You are currently in Amsterdam, Netherlands, at coordinates 52.37°N, 4.90°E.
Configuración del servidor para las herramientas de front-end
El servidor no necesita una configuración especial para admitir herramientas de front-end. Utiliza el servidor AG-UI estándar del tutorial Guía de inicio: este se configura automáticamente.
- Recibe declaraciones de herramientas de front-end durante la conexión de cliente.
- Solicita la ejecución de la herramienta cuando el agente de IA los necesita.
- Espera los resultados del cliente
- Incorpora resultados en la toma de decisiones del agente
Pasos siguientes
Ahora que comprende las herramientas de front-end, puede hacer lo siguiente:
- Combínalo con herramientas de backend: utiliza herramientas de frontend y backend conjuntamente.
Recursos adicionales
En este tutorial se muestra cómo agregar herramientas de función de front-end a los clientes de AG-UI. Las herramientas de front-end son funciones que se ejecutan en el lado cliente, lo que permite que el agente de IA interactúe con el entorno local del usuario, acceda a datos específicos del cliente o realice operaciones de interfaz de usuario.
Prerrequisitos
Antes de comenzar, asegúrese de que ha completado el tutorial de introducción y que tiene:
- Python 3.10 o posterior
-
httpxinstalado para la funcionalidad del cliente HTTP - Conocimientos básicos de la configuración del cliente de AG-UI
- Servicio OpenAI de Azure configurado
¿Qué son las herramientas de front-end?
Las herramientas de front-end son herramientas de función que:
- Se definen y registran en el cliente
- Ejecutar en el entorno del cliente (no en el servidor)
- Permitir que el agente de IA interactúe con recursos específicos del cliente
- Proporcionar los resultados al servidor para que el agente los incorpore en las respuestas.
Casos de uso comunes:
- Lectura de datos del sensor local
- Acceso al almacenamiento o preferencias del lado cliente
- Realización de operaciones de interfaz de usuario
- Interacción con características específicas del dispositivo
Creación de herramientas de front-end
Las herramientas de front-end de Python se definen de forma similar a las herramientas de back-end, pero se registran con el cliente:
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}"
Creación de un cliente de AG-UI con herramientas de front-end
Esta es una implementación de cliente completa con herramientas de 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)
# Handle tool call requests from server
if event.get("type") == "TOOL_CALL_REQUEST":
await self._handle_tool_call(event, client)
else:
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")
# Send result back to server
await client.post(
f"{self.server_url}/tool_result",
json={
"tool_call_id": tool_call_id,
"result": result,
},
)
except Exception as e:
print(f"\033[91m[Tool Error: {e}]\033[0m")
# Send error back to server
await client.post(
f"{self.server_url}/tool_result",
json={
"tool_call_id": tool_call_id,
"error": str(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())
Cómo funcionan las herramientas de front-end
Flujo de protocolo
- Registro de cliente: el cliente envía declaraciones de herramientas (nombres, descripciones, parámetros) al servidor
- Orquestación del servidor: el agente de IA decide cuándo llamar a las herramientas de front-end en función de la solicitud de usuario
-
Solicitud de llamada de herramienta: el servidor envía
TOOL_CALL_REQUESTevento al cliente a través de SSE - Ejecución del cliente: el cliente ejecuta la herramienta localmente.
- Envío de resultados: el cliente devuelve el resultado al servidor a través de la solicitud POST.
- Procesamiento del agente: el servidor incorpora el resultado y continúa la respuesta
Eventos clave
-
TOOL_CALL_REQUEST: El servidor solicita la ejecución de la herramienta frontend -
TOOL_CALL_RESULT: el cliente envía el resultado de la ejecución (a través de HTTP POST)
Salida esperada
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]
Configuración del servidor
El servidor AG-UI estándar del tutorial de introducción admite automáticamente las herramientas de frontend. No se necesitan cambios en el lado servidor: controla automáticamente la orquestación de herramientas.
Procedimientos recomendados
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"
Tratamiento de errores
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)}"
Operaciones asincrónicas
async def capture_photo() -> str:
"""Capture a photo from device camera."""
# Simulate camera access
await asyncio.sleep(1)
return "photo_12345.jpg"
Solución de problemas
Herramientas a las que no se llama
- Asegurarse de que las declaraciones de herramientas se envían al servidor
- Verificar que las descripciones de la herramienta indiquen claramente el propósito
- Comprobación de los registros del servidor para el registro de herramientas
Errores de ejecución
- Incluir una gestión de errores completa.
- Validación de parámetros antes del procesamiento
- Devolver mensajes de error fáciles de entender
- Registro de errores para la depuración
Problemas de tipo
- Uso de modelos Pydantic para tipos complejos
- Conversión de modelos en dicts antes de la serialización
- Maneje las conversiones de tipo explícitamente
Pasos siguientes
- Representación de herramientas de back-end: combinación con herramientas del lado servidor