{"id":659762,"date":"2025-11-18T02:03:27","date_gmt":"2025-11-18T01:03:27","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=ai&#038;p=659762"},"modified":"2025-11-18T02:03:30","modified_gmt":"2025-11-18T01:03:30","slug":"koog-a2a-creacion-de-agentes-de-ia-conectados-en-kotlin","status":"publish","type":"ai","link":"https:\/\/blog.jetbrains.com\/es\/ai\/2025\/11\/koog-a2a-creacion-de-agentes-de-ia-conectados-en-kotlin\/","title":{"rendered":"Koog \u00d7 A2A: creaci\u00f3n de agentes de IA conectados en Kotlin"},"content":{"rendered":"<p>Si alguna vez ha intentado crear un sistema de varios agentes de IA, probablemente se habr\u00e1 encontrado con <em>este problema<\/em>. Empieza de forma bastante sencilla: tiene un agente escribiendo art\u00edculos de blog, otro corrigi\u00e9ndolas y quiz\u00e1 un tercero sugiriendo o generando im\u00e1genes. Por separado, son eficaces. Pero \u00bfy si quiere que trabajen juntos? Ah\u00ed es donde todo puede comenzar a torcerse.<\/p>\n<p>Cada agente habla su propio \u00abidioma\u00bb: uno utiliza una interfaz API diferente, otro tiene su propio formato de mensaje, y todos pueden tener requisitos de autenticaci\u00f3n espec\u00edficos. Hacer que se comuniquen significa escribir c\u00f3digo de integraci\u00f3n personalizado para cada conexi\u00f3n. En lugar de centrarse en hacer que sus agentes sean m\u00e1s inteligentes, m\u00e1s r\u00e1pidos o m\u00e1s \u00fatiles, usted se atasca construyendo puentes entre ellos.<\/p>\n<h2 class=\"wp-block-heading\">Qu\u00e9 hace A2A: forma la capa de comunicaci\u00f3n entre agentes<\/h2>\n<p><strong>Aqu\u00ed es donde entra en acci\u00f3n el <\/strong><a href=\"https:\/\/a2a-protocol.org\/latest\/\" target=\"_blank\" rel=\"noopener\"><strong>protocolo Agent2Agent (A2A)<\/a>.<\/strong><\/p>\n<p>Con A2A, sus agentes pueden comunicarse directamente a trav\u00e9s de un protocolo estandarizado, que funciona como un traductor universal para su ecosistema de IA. Su agente de redacci\u00f3n pasa sin problemas el contenido a su corrector, que activa su generador de im\u00e1genes, mientras que el corrector vuelve con correcciones y el generador de im\u00e1genes solicita aclaraciones de estilo. Todo ello, orquestado a trav\u00e9s de una \u00fanica capa de comunicaci\u00f3n unificada.<\/p>\n<p>En lugar de gestionar docenas de conexiones punto a punto, A2A le ofrece:<\/p>\n<ul>\n<li><strong>Conectividad plug-and-play<\/strong>: los agentes se descubren autom\u00e1ticamente y se conectan entre s\u00ed.<\/li>\n<li><strong>Mensajes estandarizados<\/strong>: formato unificado, protocolo claro y ning\u00fan problema de traducci\u00f3n.<\/li>\n<li><strong>Orquestaci\u00f3n integrada<\/strong>: defina los flujos de trabajo una vez y deje que A2A se encargue de la coordinaci\u00f3n.<\/li>\n<li><strong>Escalabilidad sin complejidad<\/strong>: a\u00f1ada o reutilice agentes sin reescribir las conexiones existentes.<\/li>\n<\/ul>\n<p>\u00bfEl resultado? Usted dedica tiempo a mejorar las capacidades de sus agentes, y no a depurar sus conversaciones. Y lo mejor: puede implementar sus agentes utilizando cualquier lenguaje o marco de trabajo que desee. Para los usuarios de JVM, Koog es una opci\u00f3n de primer orden y, a partir de la versi\u00f3n 0.5.0, se integra perfectamente con el ecosistema A2A.<\/p>\n<h2 class=\"wp-block-heading\">Qu\u00e9 hace Koog: el motor interno de orquestaci\u00f3n<\/h2>\n<p>Koog es un marco basado en Kotlin para crear agentes de IA orientados a JVM, Android, iOS, WebAssembly y aplicaciones dentro del navegador. Destaca en lo siguiente:<\/p>\n<ul>\n<li><strong>Gesti\u00f3n de flujos de trabajo complejos<\/strong>: dise\u00f1e estrategias basadas en grafos con compatibilidad con bucles, ramas, respaldos y ejecuci\u00f3n paralela de ramas.<\/li>\n<li><strong>Componentes listos para usar<\/strong>: saque partido a sus nodos integrados para invocar a LLM y herramientas externas, resumir el historial de mensajes y ejecutar estrategias completas.<\/li>\n<li><strong>Orquestaci\u00f3n de herramientas<\/strong>: convierta cualquier funci\u00f3n de su c\u00f3digo en una herramienta que su agente de IA pueda utilizar, ya sea de forma secuencial o incluso en paralelo.<\/li>\n<li><strong>Integraci\u00f3n MCP nativa<\/strong>: con\u00e9ctese con fluidez a cualquier servidor MCP utilizando el SDK de MCP de Kotlin.<\/li>\n<li><strong>Compatibilidad con memoria y almacenamiento<\/strong>: compatibilidad integrada con la memoria del agente y los flujos de trabajo RAG (generaci\u00f3n aumentada por recuperaci\u00f3n) con una gesti\u00f3n eficaz del contexto.<\/li>\n<li><strong>Tolerancia a fallos<\/strong>: reintentos integrados, puntos de control, mecanismos de recuperaci\u00f3n y persistencia del estado para garantizar una ejecuci\u00f3n fiable.<\/li>\n<li><strong>Observabilidad<\/strong>: manejo completo de eventos del agente, registro y compatibilidad con OpenTelemetry con integraciones incorporadas con Langfuse y W&amp;B Weave.<\/li>\n<\/ul>\n<p>En resumen, Koog es estupendo para crear agentes de IA fiables.<\/p>\n<h2 class=\"wp-block-heading\">Por qu\u00e9 combinar Koog con A2A<\/h2>\n<p>Koog y A2A cubren diferentes capas de la pila de agentes de IA. Cuando se utilizan juntos, se complementan y completan las lagunas.<\/p>\n<p><strong>Koog ya se encarga de las partes m\u00e1s dif\u00edciles<\/strong> de la orquestaci\u00f3n de la IA necesarias para el uso empresarial en el mundo real.<\/p>\n<p><strong>A2A a\u00f1ade la pieza que faltaba<\/strong>: permite a sus agentes Koog comunicarse con cualquier otro agente compatible con A2A de su ecosistema. En lugar de crear integraciones personalizadas para cada servicio externo, sus flujos de trabajo de IA de Koog pueden descubrir y utilizar autom\u00e1ticamente otros agentes.<\/p>\n<p><strong>El resultado es una combinaci\u00f3n perfecta<\/strong>: los flujos de trabajo avanzados de Koog se convierten en tareas A2A que cualquier agente puede solicitar, mientras que sus agentes Koog aprovechan toda la potencia del ecosistema A2A. Y puesto que Koog funciona en entornos backend, en el dispositivo y en el navegador, puede ofrecer IA interconectada de forma m\u00e1s extensa y eficaz que nunca.<\/p>\n<p>\u00bfC\u00f3mo es posible? \u00a1Ve\u00e1moslo!<\/p>\n<h2 class=\"wp-block-heading\">Protocolo A2A<\/h2>\n<p>El protocolo A2A define los elementos esenciales para la comunicaci\u00f3n entre agentes:<\/p>\n<ul>\n<li><strong>Descubrimiento de agentes<\/strong> a trav\u00e9s de tarjetas de agente estandarizadas (documentos JSON que describen las capacidades).<\/li>\n<li><strong>Formatos de mensajes<\/strong> para solicitudes y respuestas con esquemas coherentes.<\/li>\n<li><strong>Gesti\u00f3n del ciclo de vida de las tareas<\/strong> con estados claros: enviado \u2192 en funcionamiento \u2192 completado\/fallido.<\/li>\n<li><strong>Capas de transporte<\/strong> como JSON-RPC, gRPC y REST.<\/li>\n<li><strong>Esquemas de seguridad<\/strong> mediante el est\u00e1ndar OAuth2, claves API y tokens JWT.<\/li>\n<li><strong>Tratamiento de errores<\/strong> con c\u00f3digos de error normalizados.<\/li>\n<\/ul>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1008\" height=\"752\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image-50.png\" alt=\"\" class=\"wp-image-645498\" \/><\/figure>\n<h3 class=\"wp-block-heading\">Tarjetas de agente: tarjetas de visita digitales<\/h3>\n<p>Cada agente del ecosistema A2A publica sus capacidades a trav\u00e9s de una \u00abtarjeta de agente\u00bb: un archivo JSON estandarizado alojado en alguna URL, por ejemplo <em>\/.well-known\/agent-card.json<\/em>, en el dominio del agente. La tarjeta de agente act\u00faa como una tarjeta de visita digital que permite a otros agentes descubrir los servicios que ofrece.<\/p>\n<p>Una tarjeta de agente suele contener lo siguiente:<\/p>\n<ul>\n<li><strong>Informaci\u00f3n b\u00e1sica<\/strong>: como el nombre del agente, la descripci\u00f3n y la versi\u00f3n.<\/li>\n<li><strong>Habilidades<\/strong>: lo que el agente es capaz de hacer (por ejemplo, redactar borradores de documentos, corregir textos, analizar datos y generar im\u00e1genes).<\/li>\n<li><strong>Puntos de conexi\u00f3n<\/strong>: c\u00f3mo llegar al agente.\u00a0<\/li>\n<li><strong>Otra informaci\u00f3n opcional<\/strong>: capacidades habilitadas, autenticaci\u00f3n y m\u00e1s.<\/li>\n<\/ul>\n<p>Este mecanismo de descubrimiento elimina la necesidad del trabajo manual de integraci\u00f3n. Cuando un agente necesita una habilidad espec\u00edfica, simplemente comprueba la tarjeta de agente correspondiente para saber c\u00f3mo interactuar con ese servicio.<\/p>\n<p>En Koog, las tarjetas de agente se definen utilizando clases de datos Kotlin:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val agentCard = AgentCard(\n    name = \"Redactor de blogs\",\n    description = \"Agente de IA que crea art\u00edculos y publicaciones de alta calidad para blogs\",\n    url = \"https:\/\/api.blog-writer.com\/a2a\/v1\",\n    version = \"1.0.0\",\n    capabilities = AgentCapabilities(streaming = true),\n    defaultInputModes = listOf(\"text\/plain\"),\n    defaultOutputModes = listOf(\"text\/markdown\"),\n    skills = listOf(\n        AgentSkill(\n            id = \"write-post\",\n            name = \"Redacci\u00f3n de art\u00edculos de blog\",\n            description = \"Genere publicaciones de blog interesantes sobre cualquier tema\",\n            tags = listOf(\"writing\", \"content\", \"blog\"),\n            examples = listOf(\"Escriba una publicaci\u00f3n sobre tendencias de IA\")\n        )\n    )\n)<\/pre>\n<h3 class=\"wp-block-heading\">Mensajer\u00eda universal: un patr\u00f3n sencillo<\/h3>\n<p>A2A utiliza un formato de mensaje \u00fanico y estandarizado para todas las comunicaciones entre agentes. Esta simplicidad es potente: en lugar de aprender un sinf\u00edn de API diferentes, los agentes solo necesitan entender un patr\u00f3n de comunicaci\u00f3n.<\/p>\n<p>Todas las interacciones siguen el mismo flujo:<\/p>\n<ol>\n<li><strong>Enviar un mensaje<\/strong> con la solicitud de tarea y los par\u00e1metros.<\/li>\n<li><strong>Recibir<\/strong> resultados inmediatos o una tarea para su seguimiento.<\/li>\n<li><strong>Obtener actualizaciones<\/strong> a trav\u00e9s de canales en tiempo real para operaciones m\u00e1s prolongadas.<\/li>\n<\/ol>\n<p>Gracias a este enfoque universal, a\u00f1adir nuevas capacidades a los agentes no requiere cambiar los protocolos de comunicaci\u00f3n. Tanto si pide a un agente que resuma un texto como si debe generar un informe complejo, la estructura del mensaje sigue siendo coherente.<\/p>\n<p>En Koog, crear y enviar un mensaje es sencillo utilizando objetos y protocolos ya implementados:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val message = Message(\n    role = Role.User,\n    parts = listOf(\n        TextPart(\"Escriba una publicaci\u00f3n de blog sobre el futuro de los agente de IA\")\n    ),\n    contextId = \"blog-project-456\"\n)\n\nval request = Request(\n    data = MessageSendParams(\n        message = message,\n        configuration = MessageConfiguration(\n            blocking = false, \/\/ Obtener primera respuesta\n            historyLength = 5 \/\/ Incluir contexto\n        )\n    )\n)\n\nval response = client.sendMessage(request)<\/pre>\n<p>El formato de mensaje admite contenido enriquecido a trav\u00e9s de diferentes tipos <em>Part<\/em>, incluidos TextPart para contenido de texto sin formato, FilePart para archivos adjuntos y DataPart para datos JSON estructurados.<\/p>\n<p>Esta estructura unificada logra que sus agentes Koog puedan comunicarse sin problemas con cualquier agente compatible con A2A, ya sea para el procesamiento de textos, el an\u00e1lisis de archivos o las transformaciones complejas de datos.<\/p>\n<h3 class=\"wp-block-heading\">Ciclo de vida de las tareas: flujos de trabajo inteligentes<\/h3>\n<p>A2A gestiona de forma inteligente diferentes tipos de trabajo en funci\u00f3n de su complejidad y duraci\u00f3n:<\/p>\n<p><strong>Mensajes inmediatos<\/strong>: las operaciones sencillas como el formateo de texto o los c\u00e1lculos r\u00e1pidos muestran los resultados directamente en la respuesta de la IA. Sin esperas, sin necesidad de seguimiento.<\/p>\n<p><strong>Tareas de larga duraci\u00f3n<\/strong>: las operaciones complejas como el an\u00e1lisis de documentos o los flujos de trabajo de varios pasos se programan y devuelven una tarea. A continuaci\u00f3n, el agente solicitante puede supervisar el progreso y recuperar los resultados de la tarea una vez que est\u00e9n listos.<\/p>\n<p><strong>Actualizaciones en tiempo real<\/strong>: para las operaciones que requieren mucho tiempo, los eventos enviados por el servidor (SSE) presentan actualizaciones del progreso en tiempo real. Esto mantiene informados a los agentes sin necesidad de sondeos constantes.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class BlogWriterExecutor : AgentExecutor {\n    override suspend fun execute(\n        context: RequestContext,\n        eventProcessor: SessionEventProcessor\n    ) {\n        val task = Task(\n            contextId = context.contextId,\n            status = TaskStatus(\n                state = TaskState.Submitted,\n                message = Message(\n                    role = Role.Agent,\n                    parts = listOf(TextPart(\"Solicitud de redacci\u00f3n de blog recibida\")),\n                    contextId = context.contextId,\n    \t\t\ttaskId = context.taskId,\n                )\n            )\n        )\n\n        eventProcessor.sendTaskEvent(task)\n\t ...\n    }\n}\n<\/pre>\n<h3 class=\"wp-block-heading\">Seguridad integrada: solo est\u00e1ndares del sector<\/h3>\n<p>A2A no reinventa la seguridad. En su lugar, se basa en est\u00e1ndares demostrados y ampliamente adoptados como OAuth2, claves API y HTTPS est\u00e1ndar.<\/p>\n<p>Esto significa que los desarrolladores no tienen que aprender nuevos esquemas de autenticaci\u00f3n. Si entiende la seguridad de las API web modernas, ya entiende la seguridad A2A. El sistema hereda todas las herramientas, las mejores pr\u00e1cticas y las auditor\u00edas de seguridad que acompa\u00f1an a estas normas establecidas.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\"securitySchemes\": {\n   \"google\": {\n       \"openIdConnectUrl\": \"https:\/\/accounts.google.com\/.well-known\/openid-configuration\",\n       \"type\": \"openIdConnect\"\n   }\n}\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class AuthorizedA2AServer(\n    agentExecutor: AgentExecutor,\n    agentCard: AgentCard,\n    agentCardExtended: AgentCard? = null,\n    taskStorage: TaskStorage = InMemoryTaskStorage(),\n    messageStorage: MessageStorage = InMemoryMessageStorage(),\n    private val authService: AuthService, \/\/ Servicio responsable de la autenticaci\u00f3n\n) : A2AServer(\n    agentExecutor = agentExecutor,\n    agentCard = agentCard,\n    agentCardExtended = agentCardExtended,\n    taskStorage = taskStorage,\n    messageStorage = messageStorage,\n) {\n\n    private suspend fun authenticateAndAuthorize(\n        ctx: ServerCallContext,\n        requiredPermission: String\n    ): AuthenticatedUser {\n        val token = ctx.headers[\"Authorization\"]?.firstOrNull()\n            ?: throw A2AInvalidParamsException(\"Falta token de autorizaci\u00f3n\")\n\n        val user = authService.authenticate(token)\n            ?: throw A2AInvalidParamsException(\"Token de autorizaci\u00f3n no v\u00e1lido\")\n\n        if (requiredPermission !in user.permissions) {\n            throw A2AUnsupportedOperationException(\"Permisos insuficientes\")\n        }\n\n        return user\n    }\n\n   override suspend fun onSendMessage(\n        request: Request,\n        ctx: ServerCallContext\n    ): Response {\n        val user = authenticateAndAuthorize(ctx, requiredPermission = \"send_message\")\n\n        \/\/ Pasar datos de usuario al ejecutor del agente a trav\u00e9s del estado de contexto\n        val enrichedCtx = ctx.copy(\n            state = ctx.state + (AuthStateKeys.USER to user)\n        )\n\n        \/\/ Delegar a implementaci\u00f3n superior con contexto enriquecido\n        return super.onSendMessage(request, enrichedCtx)\n    }\n\n   \/\/ el resto de los m\u00e9todos incorporados de A2A \n   \/\/ ...\n}<\/pre>\n<h2 class=\"wp-block-heading\">C\u00f3mo integrar los agentes Koog con A2A<\/h2>\n<p>El marco Koog incluye tanto el cliente como el servidor A2A integrados. Esto significa que sus agentes Koog pueden comunicarse sin problema con otros agentes compatibles con A2A a la vez que se hacen visibles para el mundo exterior. He aqu\u00ed un sencillo ejemplo que demuestra c\u00f3mo puede ponerlo en pr\u00e1ctica.<\/p>\n<h3 class=\"wp-block-heading\">C\u00f3mo integrar agentes Koog en servidores A2A<\/h3>\n<p>En primer lugar, defina una estrategia para el agente. Koog ofrece pr\u00e1cticos conversores (<em>toKoogMessage<\/em>, <em>toA2AMessage<\/em>) para transformar sin problemas entre los formatos de mensajes Koog y A2A, lo que elimina la necesidad de la serializaci\u00f3n manual. Los nodos especializados como <em>nodeA2ASendMessage<\/em> se encargan del proceso de intercambio de mensajes, lo que hace que los flujos de trabajo de comunicaci\u00f3n sean sencillos de implementar:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fun blogpostWritingStrategy() = strategy(\"blogpost-writer-strategy\") {\n    val blogpostRequest by node { input -&gt;\n        val userMessage = input.toKoogMessage().content\n\n        llm.writeSession {\n            user {\n                +\"Escriba un art\u00edculo de blog basado en la solicitud del usuario\"\n                +xml {\n                    tag(\"user_request\") {\n                        +userMessage\n                    }\n                }\n            }\n\n            requestLLM().toA2AMessage()\n        }\n    }\n\n    val sendMessage by nodeA2ARespondMessage()\n\n    nodeStart then blogpostRequest then sendMessage then nodeFinish\n}<\/pre>\n<p>En segundo lugar, defina el propio agente. Una vez instalada la funcionalidad <em>A2AServer<\/em>, su agente pasa a ser detectable y accesible para otros en el ecosistema, lo que permite la creaci\u00f3n de redes sofisticadas en las que agentes especializados colaboran sin problemas.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fun createBlogpostWritingAgent(\n    requestContext: RequestContext,\n    eventProcessor: SessionEventProcessor\n): AIAgent {\n     \/\/ Obtener mensajes existentes para el contexto actual de la conversaci\u00f3n\ufeff\n     val messageHistory = requestContext.messageStorage.getAll().map { it.toKoogMessage() }\n\n     val agentConfig = AIAgentConfig(\n        prompt = prompt(\"blogpost\") {\n            system(\"Usted es un agente encargado de redactar art\u00edculos para blogs\")\n\n            messages(messageHistory)\n        },\n        model = GoogleModels.Gemini2_5Flash,\n        maxAgentIterations = 5\n    )\n\n    return agent = AIAgent(\n        promptExecutor = MultiLLMPromptExecutor(\n            LLMProvider.Google to GoogleLLMClient(System.getenv(\"GOOGLE_API_KEY\")),\n        ),\n        strategy = blogpostWritingStrategy(),\n        agentConfig = agentConfig\n    ) {\n        install(A2AAgentServer) {\n            this.context = requestContext\n            this.eventProcessor = eventProcessor\n        }\n\n        handleEvents {\n            onAgentFinished { ctx -&gt;\n                \/\/ Actualice el contexto de la conversaci\u00f3n actual con la respuesta del agente\ufeff\n                val resultMessge = ctx.result as A2AMessage\n                requestContext.messageStorage.save(resultMessge)\n            }\n        }\n    }\n}<\/pre>\n<p>En tercer lugar, tenemos que incorporar al agente en el ejecutor y luego definir un servidor.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class BlogpostAgentExecutor : AgentExecutor {\n    override suspend fun execute(\n        context: RequestContext,\n        eventProcessor: SessionEventProcessor\n    ) {\n        createBlogpostWritingAgent(context, eventProcessor)\n            .run(context.params.message)\n    }\n}\n\nval a2aServer = A2AServer(\n    agentExecutor = BlogpostAgentExecutor(),\n    agentCard = agentCard,\n)<\/pre>\n<p>El \u00faltimo paso consiste en definir un transporte de servidor y ejecutar el servidor.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val transport = HttpJSONRPCServerTransport(\n    requestHandler = a2aServer\n)\n\ntransport.start(\n    engineFactory = Netty,\n    port = 8080,\n    path = \"\/a2a\",\n    wait = true,\n    agentCard = agentCard,\n    agentCardPath = A2AConsts.AGENT_CARD_WELL_KNOWN_PATH\n)<\/pre>\n<p>\u00a1Su agente ya est\u00e1 listo para atender solicitudes!\u00a0<\/p>\n<h3 class=\"wp-block-heading\">C\u00f3mo llamar a otros agentes compatibles con A2A desde un agente Koog<\/h3>\n<p>En primer lugar, debe configurar un cliente A2A y conectarlo para obtener una tarjeta de agente.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val agentUrl = \"https:\/\/example.com\"\n\nval cardResolver = UrlAgentCardResolver(\n    baseUrl = agentUrl,\n    path = A2AConsts.AGENT_CARD_WELL_KNOWN_PATH,\n)\n\nval transport = HttpJSONRPCClientTransport(\n    url = agentUrl,\n)\n\nval a2aClient = A2AClient(\n    transport = transport,\n    agentCardResolver = cardResolver\n)\n\n\/\/ Inicialice el cliente y obtenga la tarjeta\na2aClient.connect()<\/pre>\n<p>A continuaci\u00f3n, puede utilizar <em>nodeA2ASendMessage<\/em> o <em>nodeA2ASendMessageStreaming<\/em> en su estrategia para llamar a estos clientes y recibir un mensaje<em> <\/em>o una respuesta de tarea.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val agentId = \"agent_id\"\nval agent = AIAgent(\n    promptExecutor = MultiLLMPromptExecutor(\n        LLMProvider.Google to GoogleLLMClient(System.getenv(\"GOOGLE_API_KEY\")),\n    ),\n    strategy = strategy(\"a2a\") {\n        val nodePrepareRequest by node&lt;String, A2AClientRequest&gt; { input -&gt;\n            A2AClientRequest(\n                agentId = agentId,\n                callContext = ClientCallContext.Default,\n                params = MessageSendParams(\n                    message = A2AMessage(\n                        messageId = Uuid.random().toString(),\n                        role = Role.User,\n                        parts = listOf(\n                            TextPart(input)\n                        )\n                    )\n                )\n            )\n        }\n        val nodeA2A by nodeA2AClientSendMessage(agentId)\n        \n        val nodeProcessResponse by node {\n            \/\/ Process event\n            when (it) {\n                is A2AMessage -&gt; it.parts\n                    .filterIsInstance()\n                    .joinToString(separator = \"n\") { it.text }\n                \n                is Task -&gt; it.artifacts\n                    .orEmpty()\n                    .flatMap { it.parts }\n                    .filterIsInstance()\n                    .joinToString(separator = \"n\") { it.text }\n            }\n        }\n\n        nodeStart then nodePrepareRequest then nodeA2A then nodeProcessResponse then nodeFinish\n\n    },\n    agentConfig = agentConfig\n) {\n   install(A2AAgentClient) {\n        this.a2aClients = mapOf(agentId to client)\n    }\n}\n\nagent.run(\"Escriba un art\u00edculo de blog sobre la integraci\u00f3n de A2A y Koog\")<\/pre>\n<h2 class=\"wp-block-heading\">Pr\u00f3ximos pasos<\/h2>\n<p>Para profundizar en Koog y A2A, consulte estos \u00fatiles materiales:<\/p>\n<p><a href=\"https:\/\/docs.koog.ai\/\" target=\"_blank\" rel=\"noopener\">Documentaci\u00f3n de Koog<\/a><\/p>\n<p><a href=\"https:\/\/a2a-protocol.org\/latest\/specification\/\" target=\"_blank\" rel=\"noopener\">Especificaci\u00f3n A2A<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/JetBrains\/koog\/tree\/develop\/examples\/simple-examples\/src\/main\/kotlin\/ai\/koog\/agents\/example\/a2a\" data-type=\"link\" data-id=\"https:\/\/github.com\/JetBrains\/koog\/tree\/develop\/examples\/simple-examples\/src\/main\/kotlin\/ai\/koog\/agents\/example\/a2a\" target=\"_blank\" rel=\"noopener\">Ejemplos de A2A con Koog<\/a><\/p>\n\n\n<p>A<em>rt\u00edculo original en ingl\u00e9s de:<\/em><\/p>\n\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                <div class=\"about-author__box-img\">\n                    <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/10\/T0288D531-UL11E3JG5-1870329d7bae-512.png\" width=\"200\" height=\"200\" alt=\"Andrey Bragin\" loading=\"lazy\"  class=\"avatar avatar-200 wp-user-avatar wp-user-avatar-200 photo avatar-default\">\n                <\/div>\n                <div class=\"about-author__box-text\">\n                                            <h4>Andrey Bragin<\/h4>\n                                                        <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n","protected":false},"author":1086,"featured_media":659777,"comment_status":"closed","ping_status":"closed","template":"","categories":[89,907],"tags":[6847,8724],"cross-post-tag":[6355],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/ai\/659762"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/ai"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/types\/ai"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/users\/1086"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/comments?post=659762"}],"version-history":[{"count":2,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/ai\/659762\/revisions"}],"predecessor-version":[{"id":659789,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/ai\/659762\/revisions\/659789"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media\/659777"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media?parent=659762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/categories?post=659762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/tags?post=659762"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/cross-post-tag?post=659762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}