{"id":146,"date":"2025-10-23T07:44:46","date_gmt":"2025-10-23T07:44:46","guid":{"rendered":"https:\/\/elbrinner.com\/?p=146"},"modified":"2025-10-23T07:44:46","modified_gmt":"2025-10-23T07:44:46","slug":"agent-framework","status":"publish","type":"post","link":"https:\/\/elbrinner.com\/index.php\/2025\/10\/23\/agent-framework\/","title":{"rendered":"Agent Framework"},"content":{"rendered":"<p>En el mundo del desarrollo moderno, los agentes inteligentes est\u00e1n ganando terreno como una forma poderosa de automatizar tareas, integrar servicios y construir flujos conversacionales m\u00e1s humanos. En esta entrada quiero compartir mi experiencia explorando <strong>Agent Framework<\/strong>, una herramienta que permite crear agentes modulares, extensibles y altamente personalizables, y c\u00f3mo he comenzado a experimentar con ella en mi propio repositorio: <a href=\"https:\/\/github.com\/elbrinner\/demo-agent-framework\/tree\/main\" target=\"_blank\" rel=\"noopener\">Demo Agent Framework<\/a><\/p>\n<h2>\u00bfQu\u00e9 es Agent Framework?<\/h2>\n<p>Agent Framework es una arquitectura que facilita la creaci\u00f3n de agentes inteligentes capaces de interactuar con m\u00faltiples herramientas, razonar sobre tareas complejas y adaptarse a distintos contextos. Su dise\u00f1o modular permite definir:<\/p>\n<ul>\n<li><strong>Memoria<\/strong>: para que el agente recuerde informaci\u00f3n relevante.<\/li>\n<li><strong>Herramientas<\/strong>: como buscadores, generadores de im\u00e1genes o analizadores de datos.<\/li>\n<li><strong>Orquestadores<\/strong>: que deciden qu\u00e9 acci\u00f3n tomar en cada momento.<\/li>\n<li><strong>Prompting inteligente<\/strong>: para guiar la conversaci\u00f3n y mantener coherencia.<\/li>\n<\/ul>\n<p>Este enfoque se alinea con la tendencia actual de construir agentes que no solo respondan, sino que <em>act\u00faen<\/em>.<\/p>\n<h3>Demo: Hola Mundo en Modo Stream<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using Azure.AI.OpenAI;\r\nusing demo_agent_framework.Config;\r\nusing Microsoft.Agents.AI;\r\nusing OpenAI;\r\nusing System;\r\nusing System.ClientModel;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace demo_agent_framework.Demos\r\n{\r\n    public static class ModoStream\r\n    {\r\n        public static async Task RunAsync()\r\n        {\r\n            Console.WriteLine();\r\n            Console.WriteLine(\"=== Demo 2: Hola Mundo con Azure OpenAI y Stream ===\");\r\n\r\n            \/\/ Los valores esperados son:\r\n            \/\/ - AZURE_OPENAI_ENDPOINT: URL del endpoint de Azure OpenAI (por ejemplo https:\/\/tuservidor.openai.azure.com\/)\r\n            \/\/ - AZURE_OPENAI_KEY: clave API para autenticar peticiones al servicio\r\n            \/\/ - AZURE_OPENAI_MODEL: nombre del despliegue del modelo a usar (deployment name)\r\n            var endpoint = Credentials.Endpoint;\r\n            var apiKey = Credentials.ApiKey;\r\n            var model = Credentials.Model;\r\n            var prompt = \"\u00bfQu\u00e9 es el modo stream en los LLMs y para qu\u00e9 sirve?\";\r\n            \/\/ Crear cliente y agente usando las librer\u00edas de Azure\/Microsoft.\r\n            \/\/ AzureOpenAIClient: cliente de alto nivel que encapsula la comunicaci\u00f3n con el servicio Azure OpenAI.\r\n            \/\/ ApiKeyCredential: credencial simple que env\u00eda la API key en las cabeceras de la petici\u00f3n.\r\n            \/\/ GetChatClient(model).CreateAIAgent(): obtiene un cliente de chat para el despliegue especificado\r\n            \/\/ y crea una instancia de AIAgent que proporciona m\u00e9todos para ejecutar prompts y flujos de agente.\r\n            AzureOpenAIClient client = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey));\r\n            AIAgent agent = client.GetChatClient(model).CreateAIAgent();\r\n\r\n            \/\/NUEVO: Ejecutar una petici\u00f3n al agente en modo streaming.\r\n            await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt))\r\n            {\r\n                Console.Write(update);\r\n            }\r\n\r\n            Console.WriteLine();\r\n            Console.WriteLine(\"Demostraci\u00f3n finalizada. Pulsa Enter para volver al men\u00fa principal.\");\r\n            Console.ReadLine();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h3>Demo con Ollama<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing Microsoft.Agents.AI;\r\nusing Microsoft.Extensions.AI;\r\nusing OllamaSharp;\r\n\r\nnamespace demo_agent_framework.Demos\r\n{\r\n    public static class Ollama\r\n    {\r\n        public static async Task RunAsync()\r\n        {\r\n            Console.WriteLine();\r\n            Console.WriteLine(\"=== Demo 4 - Ollama ===\");\r\n\r\n            var model = \"llama3.1:8b\";\r\n            var prompt = \"Que son los modelos locales con Ollama\";\r\n            var endpoint = \"http:\/\/localhost:11434\";\r\n            try\r\n            {\r\n                IChatClient client = new OllamaApiClient(endpoint, model);\r\n                AIAgent agent = new ChatClientAgent(client);\r\n\r\n                await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt))\r\n                {\r\n                    Console.Write(update);\r\n                }\r\n            }\r\n            catch(Exception ex)\r\n            {\r\n                Console.WriteLine(\"Debe tener instalado Ollama y modelos locales\");\r\n                Console.WriteLine($\"Error: {ex.Message}\");\r\n            }\r\n\r\n            Console.WriteLine(\"Demostraci\u00f3n finalizada. Pulsa Enter para volver al men\u00fa principal.\");\r\n            Console.ReadLine();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h3>Demo con Foundry<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">using System;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Azure.Core;\r\nusing Azure;\r\nusing Azure.AI.Agents.Persistent;\r\nusing Azure.Identity;\r\nusing Microsoft.Agents.AI;\r\nusing demo_agent_framework.Config;\r\n\r\nnamespace demo_agent_framework.Demos\r\n{\r\n    public static class AiFoundryAgent\r\n    {\r\n        public static async Task RunAsync()\r\n        {\r\n            \/\/ Encabezado de la demo\r\n            Console.WriteLine();\r\n            Console.WriteLine(\"=== Demo 3 - AI Foundry Agent ===\");\r\n\r\n            \/\/ --------------------------------------------------\r\n            \/\/ Configuraci\u00f3n b\u00e1sica de la demo\r\n            \/\/ --------------------------------------------------\r\n            \/\/ Endpoint del servicio de Persistent Agents (puedes cambiar por tu endpoint o leerlo desde .env)\r\n            const string endpoint = \"https:\/\/bri-ai-openai.services.ai.azure.com\/api\/projects\/AIBRI\";\r\n            \/\/ El modelo se lee desde las credenciales centralizadas (Config\/Credentials.cs)\r\n            var model = Credentials.Model;\r\n\r\n            \/\/ Prompt de ejemplo para ejecutar en el agente\r\n            var prompt = \"Ayudarme a crear un agente para mi tienda de inform\u00e1tica\";\r\n\r\n            \/\/ Metadatos del agente que queremos crear (nombre, descripci\u00f3n, system prompt)\r\n            var aiFoundryAgentName = \"AgenteBri\";\r\n            var aiFoundryAgentDescription = \"Agente de prueba para la tienda de inform\u00e1tica de Bri\";\r\n            var aiFoundryAgentSystemPrompt = \"Eres un agente experto en tiendas de inform\u00e1tica y ayudas a los clientes a encontrar productos y resolver dudas t\u00e9cnicas.\";\r\n\r\n            \/\/ --------------------------------------------------\r\n            \/\/ Selecci\u00f3n de credencial para autenticaci\u00f3n con Azure\r\n            \/\/ --------------------------------------------------\r\n            \/\/ Preferimos credenciales de Service Principal (ClientSecretCredential) si est\u00e1n definidas en .env\r\n            \/\/ Si no, hacemos fallback a AzureCliCredential (requiere `az login`).\r\n            TokenCredential credential;\r\n            var clientId = Credentials.ClientId;\r\n            var tenantId = Credentials.TenantId;\r\n            var clientSecret = Credentials.ClientSecret;\r\n\r\n            if (!string.IsNullOrEmpty(clientId) &amp;&amp; !string.IsNullOrEmpty(tenantId) &amp;&amp; !string.IsNullOrEmpty(clientSecret))\r\n            {\r\n                \/\/ Usar credenciales de aplicaci\u00f3n (Service Principal)\r\n                Console.WriteLine(\"Usando ClientSecretCredential con credenciales de aplicaci\u00f3n.\");\r\n                credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\r\n            }\r\n            else\r\n            {\r\n                \/\/ Fallback a credenciales del CLI de Azure (usuario debe haber hecho `az login`)\r\n                Console.WriteLine(\"Usando AzureCliCredential. Aseg\u00farate de haber hecho 'az login' previamente.\");\r\n                credential = new AzureCliCredential();\r\n            }\r\n\r\n            \/\/ --------------------------------------------------\r\n            \/\/ Crear cliente de Persistent Agents con la credencial seleccionada\r\n            \/\/ --------------------------------------------------\r\n            PersistentAgentsClient client = new PersistentAgentsClient(endpoint, credential);\r\n\r\n            try\r\n            {\r\n                \/\/ --------------------------------------------------\r\n                \/\/ Almacenamiento local simple para evitar crear agentes duplicados\r\n                \/\/ - Guardamos el Id del agente en .agents\/{name}.id la primera vez que lo creamos\r\n                \/\/ - En ejecuciones posteriores, leemos ese fichero para recuperar el Id y usar el agente existente\r\n                \/\/ --------------------------------------------------\r\n                var repoRoot = Directory.GetCurrentDirectory();\r\n                var agentsDir = Path.Combine(repoRoot, \".agents\");\r\n                Directory.CreateDirectory(agentsDir);\r\n                var agentIdFile = Path.Combine(agentsDir, aiFoundryAgentName + \".id\");\r\n\r\n                AIAgent agent = null;\r\n\r\n                \/\/ 1) Intentar usar Id guardado si existe\r\n                if (File.Exists(agentIdFile))\r\n                {\r\n                    var existingId = File.ReadAllText(agentIdFile).Trim();\r\n                    if (!string.IsNullOrEmpty(existingId))\r\n                    {\r\n                        try\r\n                        {\r\n                            \/\/ Obtener AIAgent por Id guardado\r\n                            agent = await client.GetAIAgentAsync(existingId);\r\n                            Console.WriteLine($\"Agente con nombre '{aiFoundryAgentName}' ya existe (id guardado). Id: {existingId}\");\r\n                        }\r\n                        catch\r\n                        {\r\n                            \/\/ Si no se puede obtener por id (p. ej. borrado o id inv\u00e1lido), continuamos para crear uno nuevo\r\n                            Console.WriteLine(\"Id de agente guardado no v\u00e1lido o agente no encontrado. Se intentar\u00e1 crear uno nuevo.\");\r\n                            agent = null;\r\n                        }\r\n                    }\r\n                }\r\n\r\n                \/\/ 2) Si no encontramos un agente por id guardado, intentar buscar por nombre (opcional)\r\n                \/\/    NOTA: el SDK puede no exponer una lista directa; si tu servicio lo permite puedes implementar\r\n                \/\/    una b\u00fasqueda por nombre aqu\u00ed. Para simplicidad usamos el fichero local + creaci\u00f3n si no existe.\r\n\r\n                \/\/ 3) Si todav\u00eda no tenemos un AIAgent, crear uno nuevo\r\n                if (agent == null)\r\n                {\r\n                    \/\/ Crear el agente persistente en el servicio de administraci\u00f3n\r\n                    var createResponse = await client.Administration.CreateAgentAsync(\r\n                        model,\r\n                        aiFoundryAgentName,\r\n                        aiFoundryAgentDescription,\r\n                        aiFoundryAgentSystemPrompt\r\n                    );\r\n\r\n                    var createdMeta = createResponse.Value;\r\n                    Console.WriteLine($\"Agente creado. Id: {createdMeta.Id}\");\r\n\r\n                    \/\/ Guardar id localmente para pr\u00f3ximas ejecuciones\r\n                    try\r\n                    {\r\n                        File.WriteAllText(agentIdFile, createdMeta.Id);\r\n                    }\r\n                    catch\r\n                    {\r\n                        \/\/ Ignorar errores al escribir el fichero, no es cr\u00edtico para la demo\r\n                    }\r\n\r\n                    \/\/ Obtener AIAgent a partir del Id creado\r\n                    agent = await client.GetAIAgentAsync(createdMeta.Id);\r\n                }\r\n\r\n                \/\/ --------------------------------------------------\r\n                \/\/ Ejecutar la interacci\u00f3n con el agente (usando AIAgent obtenido o creado)\r\n                \/\/ --------------------------------------------------\r\n                if (agent is not null)\r\n                {\r\n           \r\n\r\n                    \/\/ Ejecutar en modo streaming para recibir actualizaciones parciales\r\n                    await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(prompt))\r\n                    {\r\n                        \/\/ Cada 'update' puede contener texto parcial o eventos; lo mostramos en consola\r\n                        Console.Write(update);\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    Console.WriteLine(\"No se pudo obtener ni crear el agente. Revisa permisos y configuraci\u00f3n.\");\r\n                }\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                \/\/ Manejo de errores gen\u00e9rico: mostrar detalle para depuraci\u00f3n\r\n                Console.WriteLine(\"Error en la operaci\u00f3n de agentes persistentes:\");\r\n                Console.WriteLine(ex.ToString());\r\n            }\r\n\r\n            \/\/ Fin de la demo: esperar que el usuario pulse Enter para volver al men\u00fa\r\n            Console.WriteLine();\r\n            Console.WriteLine(\"Demostraci\u00f3n finalizada. Pulsa Enter para volver al men\u00fa principal.\");\r\n            Console.ReadLine();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h3>Demo con Tools<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">using Azure.AI.OpenAI;\r\nusing demo_agent_framework.Config;\r\nusing Microsoft.Extensions.AI;\r\nusing OpenAI;\r\nusing System;\r\nusing System.ClientModel;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace demo_agent_framework.Demos\r\n{\r\n    public static class AgentTools\r\n    {\r\n        public static async Task RunAsync()\r\n        {\r\n            Console.WriteLine(\"=== Demo 6: Herramientas funcionales con Agent Tools ===\");\r\n\r\n            var endpoint = Credentials.Endpoint;\r\n            var apiKey = Credentials.ApiKey;\r\n            var model = Credentials.Model;\r\n            var prompt = \"Eres un asistente \u00fatil que puede consultar el clima y recomendar platos t\u00edpicos.\";    \r\n\r\n            var client = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey));\r\n\r\n            \/\/ Tool 1: Clima\r\n            [Description(\"Obtiene el clima para una ciudad dada.\")]\r\n            static string ObtenerClima([Description(\"La ciudad para consultar el clima.\")] string ciudad)\r\n                =&gt; $\"El clima en {ciudad} es nublado con una m\u00e1xima de 15\u00b0C.\";\r\n\r\n            \/\/ Tool 2: Plato t\u00edpico\r\n            [Description(\"Recomienda un plato t\u00edpico seg\u00fan la ciudad.\")]\r\n            static string RecomendarPlato([Description(\"Ciudad para recomendar comida.\")] string ciudad)\r\n                =&gt; ciudad.ToLower() switch\r\n                {\r\n                    \"madrid\" =&gt; \"Cocido madrile\u00f1o\",\r\n                    \"lisboa\" =&gt; \"Bacalhau \u00e0 Br\u00e1s\",\r\n                    \"par\u00eds\" =&gt; \"Coq au vin\",\r\n                    _ =&gt; $\"No tengo datos sobre platos t\u00edpicos en {ciudad}.\"\r\n                };\r\n\r\n            \/\/ Crear agente con ambas herramientas\r\n            var agent = client.GetChatClient(model).CreateAIAgent(\r\n                instructions: prompt,\r\n                tools: [\r\n                    AIFunctionFactory.Create(ObtenerClima),\r\n            AIFunctionFactory.Create(RecomendarPlato)\r\n                ]\r\n            );\r\n\r\n            \/\/ Leer pregunta desde consola\r\n            Console.Write(\"\\nEscribe tu pregunta: \");\r\n            var pregunta = Console.ReadLine();\r\n\r\n            \/\/ Ejecutar en modo streaming\r\n            Console.WriteLine(\"\\nRespuesta del agente:\\n\");\r\n            await foreach (var update in agent.RunStreamingAsync(pregunta))\r\n                Console.Write(update);\r\n\r\n            Console.WriteLine(\"\\n\\nPulsa Enter para continuar.\");\r\n            Console.ReadLine();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Continuar\u00e9 probando el producto y creando nuevas pruebas de conceptos para m\u00e1s informaci\u00f3n consulte el repositorio oficial:\u00a0 <a href=\"https:\/\/github.com\/microsoft\/agent-framework\">https:\/\/github.com\/microsoft\/agent-framework<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En el mundo del desarrollo moderno, los agentes inteligentes est\u00e1n ganando terreno como una forma poderosa de automatizar tareas, integrar servicios y construir flujos conversacionales m\u00e1s humanos. En esta entrada quiero compartir mi experiencia explorando Agent Framework, una herramienta que permite crear agentes modulares, extensibles y altamente personalizables, y c\u00f3mo he comenzado a experimentar con &#8230; <a title=\"Agent Framework\" class=\"read-more\" href=\"https:\/\/elbrinner.com\/index.php\/2025\/10\/23\/agent-framework\/\" aria-label=\"Leer m\u00e1s sobre Agent Framework\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[72],"tags":[15,60,62],"class_list":["post-146","post","type-post","status-publish","format-standard","hentry","category-agent-framework","tag-net","tag-codigo","tag-mcp"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/comments?post=146"}],"version-history":[{"count":1,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/146\/revisions"}],"predecessor-version":[{"id":147,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/146\/revisions\/147"}],"wp:attachment":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/media?parent=146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/categories?post=146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/tags?post=146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}