Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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