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