Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Narzędzia frontonu są deklarowane i wykonywane przez klienta AG-UI. Serwer otrzymuje schematy, aby model mógł je zażądać, ale nie otrzymuje implementacji.
Rejestrowanie narzędzia frontonu
Utwórz narzędzie i przekaż je do agenta wspieranego przez AGUIChatClientusługę :
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 obsługuje przepływ kontynuacji:
- Wysyła deklarację narzędzia frontonu z żądaniem uruchomienia.
- Odbiera wywołanie narzędzia modelu z serwera.
- Wykonuje zgodną funkcję lokalnie.
- Wysyła wynik z powrotem do serwera.
- Kontynuuje przebieg i przesyła strumieniowo ostateczną odpowiedź.
Wskazówka
Zobacz przykładowe narzędzia frontonu .NET, aby zapoznać się z kompletnym klientem i serwerem.
Warning
Deklaracje narzędzi i wyniki dostarczane przez niezaufanego klienta są danymi wejściowymi niezaufanych. Autoryzuj narzędzia klienckie, które mogą mieć wpływ na wykonywanie agenta po stronie serwera, i zweryfikuj wyniki przed ich użyciem w przypadku operacji uprzywilejowanych.
Aby uzyskać ogólne wskazówki dotyczące tworzenia narzędzi, zobacz Używanie narzędzi funkcji z agentem.
Następne kroki
W tym samouczku pokazano, jak dodać narzędzia funkcji frontonu do klientów AG-UI. Narzędzia frontonu to funkcje wykonywane po stronie klienta, które umożliwiają agentowi sztucznej inteligencji interakcję ze środowiskiem lokalnym użytkownika, uzyskiwanie dostępu do danych specyficznych dla klienta lub wykonywanie operacji interfejsu użytkownika.
Wymagania wstępne
Przed rozpoczęciem upewnij się, że ukończyłeś samouczek Wprowadzenie i posiadasz:
- Python 3.10 lub nowszy
-
httpxzainstalowane na potrzeby funkcji klienta HTTP - Podstawowa wiedza na temat konfiguracji klienta AG-UI
- Skonfigurowano usługę Azure OpenAI
Co to są narzędzia frontonu?
Narzędzia frontonu to narzędzia funkcji, które:
- Są definiowane i rejestrowane na kliencie
- Wykonywanie w środowisku klienta (nie na serwerze)
- Zezwalanie agentowi sztucznej inteligencji na interakcję z zasobami specyficznymi dla klienta
- Podaj wyniki z powrotem do serwera agenta, aby uwzględnić je w odpowiedziach
Typowe przypadki użycia:
- Odczytywanie danych z czujników lokalnych
- Uzyskiwanie dostępu do magazynu lub preferencji po stronie klienta
- Wykonywanie operacji interfejsu użytkownika
- Interakcja z funkcjami specyficznymi dla urządzenia
Tworzenie narzędzi frontonu
Narzędzia frontonu w języku Python są definiowane podobnie do narzędzi zaplecza, ale są zarejestrowane w kliencie:
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}"
Tworzenie klienta AG-UI za pomocą narzędzi frontonu
Oto kompletna implementacja klienta z narzędziami frontonu:
"""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())
Jak działają narzędzia frontonu
Przepływ protokołu
- Rejestracja klienta: klient wysyła deklaracje narzędzi (nazwy, opisy, parametry) do serwera
- Orkiestracja serwera: agent sztucznej inteligencji decyduje, kiedy wywołać narzędzia frontonu na podstawie żądania użytkownika
-
Zdarzenia wywołania narzędzia: Serwer przesyła strumieniowo zdarzenia
TOOL_CALL_START,TOOL_CALL_ARGSiTOOL_CALL_ENDdo klienta - Wykonywanie klienta: klient wykonuje narzędzie lokalnie
-
Zdarzenia wynikowe: wyniki narzędzia są przedstawiane w strumieniu jako zdarzenia
TOOL_CALL_RESULT - Przetwarzanie agenta: serwer integruje wynik i kontynuuje przetwarzanie odpowiedzi
Kluczowe zdarzenia
-
TOOL_CALL_START/TOOL_CALL_ARGS/TOOL_CALL_END: Serwer żąda i strumieniuje szczegóły wywołań narzędzi -
TOOL_CALL_RESULT: Zdarzenie wyniku działania narzędzia
Oczekiwane dane wyjściowe
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]
Konfiguracja serwera
Standardowy serwer AG-UI z samouczka 'Pierwsze Kroki' automatycznie obsługuje narzędzia frontendowe. Po stronie serwera nie są wymagane żadne zmiany — automatycznie obsługuje orkiestrację narzędzi.
Najlepsze praktyki
Zabezpieczenia
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"
Obsługa błędów
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)}"
Operacje asynchroniczne
async def capture_photo() -> str:
"""Capture a photo from device camera."""
# Simulate camera access
await asyncio.sleep(1)
return "photo_12345.jpg"
Troubleshooting
Narzędzia, które nie są wywoływane
- Upewnij się, że deklaracje narzędzi są wysyłane do serwera
- Sprawdź, czy opisy narzędzi wyraźnie wskazują cel
- Sprawdzanie dzienników serwera pod kątem rejestracji narzędzi
Błędy wykonawcze
- Dodawanie kompleksowej obsługi błędów
- Weryfikowanie parametrów przed przetworzeniem
- Zwracanie przyjaznych dla użytkownika komunikatów o błędach
- Rejestrowanie błędów na potrzeby debugowania
Problemy typowe
- Używanie modeli Pydantic dla typów złożonych
- Konwertowanie modeli na dykty przed serializacji
- Jawnie przeprowadzaj konwersje typów
Dalsze kroki
- Renderowanie narzędzi zaplecza: łączenie z narzędziami po stronie serwera
Dodatkowe zasoby
Serwery AG-UI w Go mogą pozostawiać wywołania narzędzi po stronie frontendu, wyłączając automatyczne wywoływanie funkcji w hostowanym agencie.
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{}))
Wskazówka
Zobacz przykład narzędzi frontendowych AG-UI, aby zobaczyć kompletny działający przykład.