En el mundo del desarrollo moderno, los agentes inteligentes están ganando terreno como una forma poderosa de automatizar tareas, integrar servicios y construir flujos conversacionales más humanos. En esta entrada quiero compartir mi experiencia explorando Agent Framework, una herramienta que permite crear agentes modulares, extensibles y altamente personalizables, y cómo he comenzado a experimentar con ella en mi propio repositorio: Demo Agent Framework
¿Qué es Agent Framework?
Agent Framework es una arquitectura que facilita la creación de agentes inteligentes capaces de interactuar con múltiples herramientas, razonar sobre tareas complejas y adaptarse a distintos contextos. Su diseño modular permite definir:
- Memoria: para que el agente recuerde información relevante.
- Herramientas: como buscadores, generadores de imágenes o analizadores de datos.
- Orquestadores: que deciden qué acción tomar en cada momento.
- Prompting inteligente: para guiar la conversación y mantener coherencia.
Este enfoque se alinea con la tendencia actual de construir agentes que no solo respondan, sino que actúen.
Demo: Hola Mundo en Modo Stream
using Azure.AI.OpenAI; using demo_agent_framework.Config; using Microsoft.Agents.AI; using OpenAI; using System; using System.ClientModel; using System.Threading.Tasks; namespace demo_agent_framework.Demos { public static class ModoStream { public static async Task RunAsync() { Console.WriteLine(); Console.WriteLine("=== Demo 2: Hola Mundo con Azure OpenAI y Stream ==="); // Los valores esperados son: // - AZURE_OPENAI_ENDPOINT: URL del endpoint de Azure OpenAI (por ejemplo https://tuservidor.openai.azure.com/) // - AZURE_OPENAI_KEY: clave API para autenticar peticiones al servicio // - AZURE_OPENAI_MODEL: nombre del despliegue del modelo a usar (deployment name) var endpoint = Credentials.Endpoint; var apiKey = Credentials.ApiKey; var model = Credentials.Model; var prompt = "¿Qué es el modo stream en los LLMs y para qué sirve?"; // Crear cliente y agente usando las librerías de Azure/Microsoft. // AzureOpenAIClient: cliente de alto nivel que encapsula la comunicación con el servicio Azure OpenAI. // ApiKeyCredential: credencial simple que envía la API key en las cabeceras de la petición. // GetChatClient(model).CreateAIAgent(): obtiene un cliente de chat para el despliegue especificado // y crea una instancia de AIAgent que proporciona métodos para ejecutar prompts y flujos de agente. AzureOpenAIClient client = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey)); AIAgent agent = client.GetChatClient(model).CreateAIAgent(); //NUEVO: Ejecutar una petición al agente en modo streaming. await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt)) { Console.Write(update); } Console.WriteLine(); Console.WriteLine("Demostración finalizada. Pulsa Enter para volver al menú principal."); Console.ReadLine(); } } }
Demo con Ollama
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; using OllamaSharp; namespace demo_agent_framework.Demos { public static class Ollama { public static async Task RunAsync() { Console.WriteLine(); Console.WriteLine("=== Demo 4 - Ollama ==="); var model = "llama3.1:8b"; var prompt = "Que son los modelos locales con Ollama"; var endpoint = "http://localhost:11434"; try { IChatClient client = new OllamaApiClient(endpoint, model); AIAgent agent = new ChatClientAgent(client); await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt)) { Console.Write(update); } } catch(Exception ex) { Console.WriteLine("Debe tener instalado Ollama y modelos locales"); Console.WriteLine($"Error: {ex.Message}"); } Console.WriteLine("Demostración finalizada. Pulsa Enter para volver al menú principal."); Console.ReadLine(); } } }
Demo con Foundry
using System; using System.Threading.Tasks; using System.IO; using Azure.Core; using Azure; using Azure.AI.Agents.Persistent; using Azure.Identity; using Microsoft.Agents.AI; using demo_agent_framework.Config; namespace demo_agent_framework.Demos { public static class AiFoundryAgent { public static async Task RunAsync() { // Encabezado de la demo Console.WriteLine(); Console.WriteLine("=== Demo 3 - AI Foundry Agent ==="); // -------------------------------------------------- // Configuración básica de la demo // -------------------------------------------------- // Endpoint del servicio de Persistent Agents (puedes cambiar por tu endpoint o leerlo desde .env) const string endpoint = "https://bri-ai-openai.services.ai.azure.com/api/projects/AIBRI"; // El modelo se lee desde las credenciales centralizadas (Config/Credentials.cs) var model = Credentials.Model; // Prompt de ejemplo para ejecutar en el agente var prompt = "Ayudarme a crear un agente para mi tienda de informática"; // Metadatos del agente que queremos crear (nombre, descripción, system prompt) var aiFoundryAgentName = "AgenteBri"; var aiFoundryAgentDescription = "Agente de prueba para la tienda de informática de Bri"; var aiFoundryAgentSystemPrompt = "Eres un agente experto en tiendas de informática y ayudas a los clientes a encontrar productos y resolver dudas técnicas."; // -------------------------------------------------- // Selección de credencial para autenticación con Azure // -------------------------------------------------- // Preferimos credenciales de Service Principal (ClientSecretCredential) si están definidas en .env // Si no, hacemos fallback a AzureCliCredential (requiere `az login`). TokenCredential credential; var clientId = Credentials.ClientId; var tenantId = Credentials.TenantId; var clientSecret = Credentials.ClientSecret; if (!string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(tenantId) && !string.IsNullOrEmpty(clientSecret)) { // Usar credenciales de aplicación (Service Principal) Console.WriteLine("Usando ClientSecretCredential con credenciales de aplicación."); credential = new ClientSecretCredential(tenantId, clientId, clientSecret); } else { // Fallback a credenciales del CLI de Azure (usuario debe haber hecho `az login`) Console.WriteLine("Usando AzureCliCredential. Asegúrate de haber hecho 'az login' previamente."); credential = new AzureCliCredential(); } // -------------------------------------------------- // Crear cliente de Persistent Agents con la credencial seleccionada // -------------------------------------------------- PersistentAgentsClient client = new PersistentAgentsClient(endpoint, credential); try { // -------------------------------------------------- // Almacenamiento local simple para evitar crear agentes duplicados // - Guardamos el Id del agente en .agents/{name}.id la primera vez que lo creamos // - En ejecuciones posteriores, leemos ese fichero para recuperar el Id y usar el agente existente // -------------------------------------------------- var repoRoot = Directory.GetCurrentDirectory(); var agentsDir = Path.Combine(repoRoot, ".agents"); Directory.CreateDirectory(agentsDir); var agentIdFile = Path.Combine(agentsDir, aiFoundryAgentName + ".id"); AIAgent agent = null; // 1) Intentar usar Id guardado si existe if (File.Exists(agentIdFile)) { var existingId = File.ReadAllText(agentIdFile).Trim(); if (!string.IsNullOrEmpty(existingId)) { try { // Obtener AIAgent por Id guardado agent = await client.GetAIAgentAsync(existingId); Console.WriteLine($"Agente con nombre '{aiFoundryAgentName}' ya existe (id guardado). Id: {existingId}"); } catch { // Si no se puede obtener por id (p. ej. borrado o id inválido), continuamos para crear uno nuevo Console.WriteLine("Id de agente guardado no válido o agente no encontrado. Se intentará crear uno nuevo."); agent = null; } } } // 2) Si no encontramos un agente por id guardado, intentar buscar por nombre (opcional) // NOTA: el SDK puede no exponer una lista directa; si tu servicio lo permite puedes implementar // una búsqueda por nombre aquí. Para simplicidad usamos el fichero local + creación si no existe. // 3) Si todavía no tenemos un AIAgent, crear uno nuevo if (agent == null) { // Crear el agente persistente en el servicio de administración var createResponse = await client.Administration.CreateAgentAsync( model, aiFoundryAgentName, aiFoundryAgentDescription, aiFoundryAgentSystemPrompt ); var createdMeta = createResponse.Value; Console.WriteLine($"Agente creado. Id: {createdMeta.Id}"); // Guardar id localmente para próximas ejecuciones try { File.WriteAllText(agentIdFile, createdMeta.Id); } catch { // Ignorar errores al escribir el fichero, no es crítico para la demo } // Obtener AIAgent a partir del Id creado agent = await client.GetAIAgentAsync(createdMeta.Id); } // -------------------------------------------------- // Ejecutar la interacción con el agente (usando AIAgent obtenido o creado) // -------------------------------------------------- if (agent is not null) { // Ejecutar en modo streaming para recibir actualizaciones parciales await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt)) { // Cada 'update' puede contener texto parcial o eventos; lo mostramos en consola Console.Write(update); } } else { Console.WriteLine("No se pudo obtener ni crear el agente. Revisa permisos y configuración."); } } catch (Exception ex) { // Manejo de errores genérico: mostrar detalle para depuración Console.WriteLine("Error en la operación de agentes persistentes:"); Console.WriteLine(ex.ToString()); } // Fin de la demo: esperar que el usuario pulse Enter para volver al menú Console.WriteLine(); Console.WriteLine("Demostración finalizada. Pulsa Enter para volver al menú principal."); Console.ReadLine(); } } }
Demo con Tools
using Azure.AI.OpenAI; using demo_agent_framework.Config; using Microsoft.Extensions.AI; using OpenAI; using System; using System.ClientModel; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo_agent_framework.Demos { public static class AgentTools { public static async Task RunAsync() { Console.WriteLine("=== Demo 6: Herramientas funcionales con Agent Tools ==="); var endpoint = Credentials.Endpoint; var apiKey = Credentials.ApiKey; var model = Credentials.Model; var prompt = "Eres un asistente útil que puede consultar el clima y recomendar platos típicos."; var client = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey)); // Tool 1: Clima [Description("Obtiene el clima para una ciudad dada.")] static string ObtenerClima([Description("La ciudad para consultar el clima.")] string ciudad) => $"El clima en {ciudad} es nublado con una máxima de 15°C."; // Tool 2: Plato típico [Description("Recomienda un plato típico según la ciudad.")] static string RecomendarPlato([Description("Ciudad para recomendar comida.")] string ciudad) => ciudad.ToLower() switch { "madrid" => "Cocido madrileño", "lisboa" => "Bacalhau à Brás", "parís" => "Coq au vin", _ => $"No tengo datos sobre platos típicos en {ciudad}." }; // Crear agente con ambas herramientas var agent = client.GetChatClient(model).CreateAIAgent( instructions: prompt, tools: [ AIFunctionFactory.Create(ObtenerClima), AIFunctionFactory.Create(RecomendarPlato) ] ); // Leer pregunta desde consola Console.Write("\nEscribe tu pregunta: "); var pregunta = Console.ReadLine(); // Ejecutar en modo streaming Console.WriteLine("\nRespuesta del agente:\n"); await foreach (var update in agent.RunStreamingAsync(pregunta)) Console.Write(update); Console.WriteLine("\n\nPulsa Enter para continuar."); Console.ReadLine(); } } }
Continuaré probando el producto y creando nuevas pruebas de conceptos para más información consulte el repositorio oficial: https://github.com/microsoft/agent-framework