Este documento contiene ejemplos prácticos de cómo usar el framework.
- Crear Tools Simples
- Trabajar con Schemas Complejos
- Validación y Error Handling
- Extensiones Avanzadas
- Integración con OpenAI (Conceptual)
public class SystemTools
{
[Tool(Description = "Obtiene la fecha y hora actual del sistema")]
public DateTimeResponse GetCurrentDateTime()
{
return new DateTimeResponse
{
DateTime = DateTime.Now,
TimeZone = TimeZoneInfo.Local.DisplayName
};
}
}
[JsonSchema(Description = "Información de fecha y hora")]
public class DateTimeResponse
{
[JsonSchemaProperty(Description = "Fecha y hora actual", Type = "string", Format = "date-time")]
public DateTime DateTime { get; set; }
[JsonSchemaProperty(Description = "Zona horaria")]
public required string TimeZone { get; set; }
}public class StringTools
{
[Tool(Description = "Convierte texto a mayúsculas o minúsculas")]
public TextResponse ConvertCase(
[ToolParam(Description = "Texto a convertir")]
string text,
[ToolParam(Description = "Modo: 'upper' o 'lower'", Required = false)]
string mode = "upper")
{
return new TextResponse
{
Original = text,
Converted = mode.ToLower() == "lower" ? text.ToLower() : text.ToUpper(),
Mode = mode
};
}
}public class FileTools
{
[Tool(Description = "Busca archivos por nombre y extensión")]
public FileSearchResponse SearchFiles(
[ToolParam(Description = "Directorio donde buscar")]
string directory,
[ToolParam(Description = "Patrón de búsqueda (ej: *.txt)")]
string pattern,
[ToolParam(Description = "Incluir subdirectorios", Required = false)]
bool recursive = false,
[ToolParam(Description = "Límite de resultados", Required = false)]
int maxResults = 100)
{
// Implementación mock...
return new FileSearchResponse
{
Directory = directory,
Pattern = pattern,
FilesFound = Random.Shared.Next(0, maxResults),
Recursive = recursive
};
}
}[JsonSchema(Description = "Respuesta con lista de usuarios")]
public class UserListResponse
{
[JsonSchemaProperty(Description = "Lista de usuarios encontrados", Required = true)]
public required List<User> Users { get; set; }
[JsonSchemaProperty(Description = "Total de usuarios", Type = "integer")]
public int TotalCount { get; set; }
}
public class User
{
[JsonSchemaProperty(Description = "ID del usuario", Type = "integer")]
public int Id { get; set; }
[JsonSchemaProperty(Description = "Nombre completo")]
public required string Name { get; set; }
[JsonSchemaProperty(Description = "Email", Format = "email")]
public required string Email { get; set; }
}[JsonSchema(Description = "Información completa del pedido")]
public class OrderResponse
{
[JsonSchemaProperty(Description = "ID del pedido")]
public required string OrderId { get; set; }
[JsonSchemaProperty(Description = "Información del cliente")]
public required CustomerInfo Customer { get; set; }
[JsonSchemaProperty(Description = "Items del pedido")]
public required List<OrderItem> Items { get; set; }
[JsonSchemaProperty(Description = "Total del pedido", Type = "number")]
public decimal Total { get; set; }
}
public class CustomerInfo
{
[JsonSchemaProperty(Description = "Nombre del cliente")]
public required string Name { get; set; }
[JsonSchemaProperty(Description = "Email de contacto", Format = "email")]
public required string Email { get; set; }
}
public class OrderItem
{
[JsonSchemaProperty(Description = "Nombre del producto")]
public required string ProductName { get; set; }
[JsonSchemaProperty(Description = "Cantidad", Type = "integer")]
public int Quantity { get; set; }
[JsonSchemaProperty(Description = "Precio unitario", Type = "number")]
public decimal Price { get; set; }
}var registry = new ToolRegistry();
// Validar antes de registrar
var validation = ToolValidator.ValidateToolClass(typeof(MyTools));
if (!validation.IsValid)
{
Console.WriteLine("? Errores encontrados:");
foreach (var error in validation.Errors)
{
Console.WriteLine($" - {error}");
}
return;
}
if (validation.HasWarnings)
{
Console.WriteLine("?? Advertencias:");
foreach (var warning in validation.Warnings)
{
Console.WriteLine($" - {warning}");
}
}
// Registrar si la validación pasó
registry.AddToolsFrom<MyTools>();var registry = new ToolRegistry();
registry.AddToolsFrom<MathTools>();
try
{
var result = registry.InvokeTool("Divide", 10.0, 0.0);
Console.WriteLine($"Resultado: {result}");
}
catch (TargetInvocationException ex)
{
// La excepción real está en InnerException
Console.WriteLine($"Error en la tool: {ex.InnerException?.Message}");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Tool no encontrada: {ex.Message}");
}var result = registry.TryInvokeTool("Divide", 10.0, 0.0);
if (result == null)
{
Console.WriteLine("? La invocación falló");
}
else
{
Console.WriteLine($"? Resultado: {result}");
}var registry = new ToolRegistry();
registry.AddToolsFrom<WeatherTools>();
registry.AddToolsFrom<MathTools>();
registry.AddToolsFrom<DatabaseTools>();
// Buscar todas las tools relacionadas con "weather"
var weatherTools = registry.FindTools("weather");
Console.WriteLine($"Tools encontradas: {weatherTools.Count()}");
foreach (var tool in weatherTools)
{
Console.WriteLine($" • {tool.Key}: {tool.Value.Description}");
}
// Buscar tools relacionadas con "user"
var userTools = registry.FindTools("user");
// ...var registry = new ToolRegistry();
registry.AddToolsFrom<WeatherTools>();
registry.AddToolsFrom<MathTools>();
registry.AddToolsFrom<DatabaseTools>();
var stats = registry.GetStats();
Console.WriteLine($"?? Estadísticas:");
Console.WriteLine($" Total de tools: {stats.TotalTools}");
Console.WriteLine($" Total de parámetros: {stats.TotalParameters}");
Console.WriteLine($" Tools con return type: {stats.ToolsWithReturnType}");
Console.WriteLine($" Promedio de parámetros: {stats.AverageParametersPerTool:F2}");var registry = new ToolRegistry();
registry.AddToolsFrom<WeatherTools>();
registry.AddToolsFrom<MathTools>();
// Exportar con formato
var json = registry.ExportToolsToJson(indented: true);
Console.WriteLine(json);
// Guardar en archivo
File.WriteAllText("tools-definition.json", json);if (registry.HasTool("GetCurrentWeather"))
{
var result = registry.InvokeTool("GetCurrentWeather", "Madrid", "celsius");
}
else
{
Console.WriteLine("Tool no disponible");
}Este es un ejemplo conceptual de cómo se integraría con OpenAI API.
var registry = new ToolRegistry();
registry.AddToolsFrom<WeatherTools>();
registry.AddToolsFrom<MathTools>();// Pseudo-código: convertir tools a formato OpenAI
var openAITools = registry.GetAllTools().Select(kvp => new
{
type = "function",
function = new
{
name = kvp.Key,
description = kvp.Value.Description,
parameters = new
{
type = "object",
properties = kvp.Value.Parameters.ToDictionary(
p => p.Name,
p => new
{
type = MapTypeToJsonType(p.Type),
description = p.Description
}
),
required = kvp.Value.Parameters
.Where(p => p.Required)
.Select(p => p.Name)
.ToArray()
}
}
}).ToList();// Pseudo-código: llamada a OpenAI
var response = await openAIClient.CreateChatCompletionAsync(new
{
model = "gpt-4",
messages = new[]
{
new { role = "user", content = "¿Qué temperatura hay en Madrid?" }
},
tools = openAITools
});// Si OpenAI quiere llamar una function
if (response.Choices[0].FinishReason == "tool_calls")
{
var toolCall = response.Choices[0].Message.ToolCalls[0];
var toolName = toolCall.Function.Name;
var arguments = JsonSerializer.Deserialize<Dictionary<string, object>>(
toolCall.Function.Arguments
);
// Invocar la tool usando nuestro registry
var result = registry.InvokeTool(
toolName,
arguments.Values.ToArray()
);
// Serializar resultado
var resultJson = JsonSerializer.Serialize(result);
// Enviar resultado de vuelta a OpenAI
var followUpResponse = await openAIClient.CreateChatCompletionAsync(new
{
model = "gpt-4",
messages = new[]
{
// ...mensajes anteriores...
new { role = "tool", tool_call_id = toolCall.Id, content = resultJson }
}
});
}public class AIOrchestrator
{
private readonly ToolRegistry _registry;
private readonly OpenAIClient _openAI; // Pseudo
public AIOrchestrator()
{
_registry = new ToolRegistry();
_registry.AddToolsFrom<WeatherTools>();
_registry.AddToolsFrom<MathTools>();
// _openAI = new OpenAIClient(...);
}
public async Task<string> ProcessUserQuery(string query)
{
// 1. Enviar query a OpenAI con tools disponibles
var response = await SendToOpenAI(query);
// 2. Si OpenAI quiere usar una tool
if (response.WantsToCallTool)
{
// 3. Ejecutar la tool
var toolResult = _registry.InvokeTool(
response.ToolName,
response.ToolArguments
);
// 4. Enviar resultado a OpenAI
var finalResponse = await SendToolResultToOpenAI(
toolResult,
response.ToolCallId
);
return finalResponse.Answer;
}
return response.Answer;
}
}// ? BUENO
[Tool(Description = "Busca información de vuelos por número de vuelo y fecha")]
public FlightInfo SearchFlight(
[ToolParam(Description = "Número de vuelo (ej: AA123)")]
string flightNumber,
[ToolParam(Description = "Fecha del vuelo en formato YYYY-MM-DD")]
string date)
{
// ...
}
// ? MALO
[Tool(Description = "Busca vuelo")]
public FlightInfo SearchFlight(string fn, string dt)
{
// ...
}[Tool(Description = "Divide dos números")]
public CalculationResponse Divide(
[ToolParam(Description = "Dividendo")]
double dividend,
[ToolParam(Description = "Divisor (no puede ser cero)")]
double divisor)
{
if (divisor == 0)
{
throw new ArgumentException("El divisor no puede ser cero", nameof(divisor));
}
return new CalculationResponse
{
Operation = "division",
Operand1 = dividend,
Operand2 = divisor,
Result = dividend / divisor
};
}// ? BUENO - Tipo específico
[JsonSchema]
public class ProductSearchResponse
{
[JsonSchemaProperty(Description = "Productos encontrados")]
public required List<Product> Products { get; set; }
[JsonSchemaProperty(Description = "Total de resultados")]
public int TotalResults { get; set; }
}
// ? MALO - Tipo genérico
public object SearchProducts(string query)
{
return new { products = new List<object>(), total = 0 };
}// Separar tools por funcionalidad
public class WeatherTools { /* ... */ }
public class FinanceTools { /* ... */ }
public class UserManagementTools { /* ... */ }
public class NotificationTools { /* ... */ }
// Registrar de forma organizada
registry.AddToolsFrom<WeatherTools>();
registry.AddToolsFrom<FinanceTools>();
registry.AddToolsFrom<UserManagementTools>();
registry.AddToolsFrom<NotificationTools>();- Todos los ejemplos son conceptuales y requieren implementación real para producción
- Los ejemplos de integración con OpenAI son pseudo-código ilustrativo
- Para casos reales, considera async/await, validaciones robustas y error handling
Para más información, consulta:
- README.md - Guía de inicio rápido
- ARCHITECTURE.md - Diseño y arquitectura detallada