{"id":651486,"date":"2025-10-31T04:24:53","date_gmt":"2025-10-31T03:24:53","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=ai&#038;p=651486"},"modified":"2025-10-31T04:24:57","modified_gmt":"2025-10-31T03:24:57","slug":"koog-a2a-ki-agents-in-kotlin-vernetzen","status":"publish","type":"ai","link":"https:\/\/blog.jetbrains.com\/de\/ai\/2025\/10\/koog-a2a-ki-agents-in-kotlin-vernetzen\/","title":{"rendered":"Koog \u00d7 A2A: KI-Agents in Kotlin vernetzen"},"content":{"rendered":"<p>Wenn Sie jemals versucht haben, ein System mit mehreren KI-Agents aufzubauen, d\u00fcrften Sie <em>das Problem<\/em> bereits kennen. Der Anfang ist unkompliziert: Ein Agent schreibt Blogartikel, der n\u00e4chste liest Korrektur, und vielleicht gibt es noch einen dritten, der Bilder vorschl\u00e4gt oder generiert. Einzeln sind sie alle effektiv. Aber wie bringt man sie dazu, zusammenzuarbeiten? An dieser Stelle kommt das Projekt oft ins Schlingern.<\/p>\n<p>Jeder Agent spricht seine eigene \u201eSprache\u201c: Einer verwendet eine eigene API-Schnittstelle, der n\u00e4chste hat ein spezielles Nachrichtenformat, und mit etwas Pech haben alle unterschiedliche Authentifizierungsanforderungen. Damit sie miteinander kommunizieren k\u00f6nnen, ben\u00f6tigt jede einzelne Verbindung einen individuellen Integrationscode. So vergeuden Sie Ihre Zeit damit, Br\u00fccken zwischen Ihren Agents zu bauen, statt sie intelligenter, schneller und n\u00fctzlicher zu machen.<\/p>\n<h2 class=\"wp-block-heading\">Das bietet A2A: eine agenten\u00fcbergreifende Kommunikationsschicht<\/h2>\n<p><strong>An dieser Stelle kommt das <\/strong><a href=\"https:\/\/a2a-protocol.org\/latest\/\" target=\"_blank\" rel=\"noopener\"><strong>Agent2Agent-Protokoll (A2A)<\/strong><\/a><strong> ins Spiel.<\/strong><\/p>\n<p>Mit A2A k\u00f6nnen Ihre Agents direkt \u00fcber ein standardisiertes Protokoll kommunizieren, das als universeller \u00dcbersetzer f\u00fcr Ihr KI-\u00d6kosystem fungiert. Ihr Blogschreibe-Agent \u00fcbergibt die Inhalte den an den Korrektur-Agent, wodurch Ihr Bildgenerator aktiviert wird. Der Korrektor sendet Korrekturen zur\u00fcck, und der Bildgenerator fordert genauere Stilvorgaben an. All dies wird \u00fcber eine einzige einheitliche Kommunikationsschicht koordiniert.<\/p>\n<p>Damit Sie nicht mit Dutzenden Punkt-zu-Punkt-Verbindungen jonglieren m\u00fcssen, stellt A2A Folgendes bereit:<\/p>\n<ul>\n<li><strong>Plug-and-play-Konnektivit\u00e4t<\/strong>: Die Agents erkennen sich automatisch und stellen eine Verbindung zueinander her.<\/li>\n<li><strong>Standardisierte Nachrichten\u00fcbermittlung<\/strong>: Einheitliches Format, klares Protokoll und keine \u00dcbersetzungsprobleme.<\/li>\n<li><strong>Integrierte Orchestrierung:<\/strong> Workflows m\u00fcssen nur einmalig definiert werden \u2013 danach \u00fcbernimmt A2A die Koordination.<\/li>\n<li><strong>Skalierung ohne Komplexit\u00e4t<\/strong>: Sie k\u00f6nnen neue Agents hinzuf\u00fcgen oder bestehende Agents wiederverwenden, ohne vorhandene Verbindungen umzuschreiben.<\/li>\n<\/ul>\n<p>Das Ergebnis Sie investieren Ihre Zeit in die Verbesserung Ihrer Agents, nicht in das Debugging des Austauschs zwischen ihnen. Und das Beste daran: Sie k\u00f6nnen Ihre Agents in jeder beliebigen Sprache oder jedem beliebigen Framework implementieren. F\u00fcr JVM-Benutzer*innen ist Koog die erste Wahl, und seit Version 0.5.0 l\u00e4sst es sich problemlos in das A2A-\u00d6kosystem integrieren.<\/p>\n<h2 class=\"wp-block-heading\">Das bietet Koog: eine interne Orchestrierungs-Engine<\/h2>\n<p>Koog ist ein auf Kotlin basierendes Framework zur Entwicklung von KI-Agents f\u00fcr JVM-, Android-, iOS-, WebAssembly- und Browseranwendungen. Besondere St\u00e4rken:<\/p>\n<ul>\n<li><strong>Komplexes Workflow-Management<\/strong>: Entwerfen Sie graphbasierte Strategien mit Unterst\u00fctzung f\u00fcr Schleifen, Verzweigungen, Fallbacks und paralleler Ausf\u00fchrung von Zweigen.<\/li>\n<li><strong>Einsatzbereite Komponenten<\/strong>: Nutzen Sie die integrierten Knoten zum Aufrufen von LLMs und externen Tools, um Nachrichtenverl\u00e4ufe zusammenzufassen oder komplette Strategien auszuf\u00fchren.<\/li>\n<li><strong>Tool-Orchestrierung<\/strong>: Verwandeln Sie jede Funktion in Ihrem Code in ein Werkzeug, das Ihr KI-Agent sequenziell oder sogar parallel verwenden kann<\/li>\n<li><strong>Native MCP-Integration<\/strong>: Mit dem Kotlin-MCP-SDK k\u00f6nnen Sie m\u00fchelos eine Verbindung zu jedem MCP-Server herstellen.<\/li>\n<li><strong>Arbeits- und Festspeicherunterst\u00fctzung<\/strong>: Integrierte Unterst\u00fctzung f\u00fcr Agentenspeicher und RAG-Workflows (Retrieval-Augmented Generation) mit effizientem Kontextmanagement.<\/li>\n<li><strong>Fehlertoleranz<\/strong>: Eingebaute Wiederholfunktion, Verlaufspunkte, Wiederherstellungsm\u00f6glichkeiten und Zustandsspeicherung gew\u00e4hrleisten eine zuverl\u00e4ssige Ausf\u00fchrung.<\/li>\n<li><strong>Observability<\/strong>: Umfassende Agent-Ereignisbehandlung, Protokollierung und Unterst\u00fctzung f\u00fcr OpenTelemetry mit eingebauten Integrationen f\u00fcr Langfuse und W&amp;B Weave.<\/li>\n<\/ul>\n<p>Alles in allem eignet sich Koog hervorragend f\u00fcr die Entwicklung zuverl\u00e4ssiger KI-Agents.<\/p>\n<h2 class=\"wp-block-heading\">Wozu Koog mit A2A kombinieren?<\/h2>\n<p>Koog und A2A decken unterschiedliche Ebenen des KI-Agent-Stacks ab. Zusammen verwendet schlie\u00dfen sie die vorhandenen L\u00fccken und erg\u00e4nzen einander.<\/p>\n<p><strong>Koog \u00fcbernimmt bereits die schwierigsten Aspekte <\/strong>der im realen Unternehmenseinsatz erforderlichen KI-Orchestrierung.<\/p>\n<p><strong>A2A schlie\u00dft die verbleibende L\u00fccke: <\/strong>Es erm\u00f6glicht Ihren Koog-Agents, mit allen anderen A2A-kompatiblen Agents in Ihrem \u00d6kosystem zu kommunizieren. Anstatt f\u00fcr jeden externen Service individuelle Integrationen zu erstellen, k\u00f6nnen Ihre Koog-KI-Workflows andere Agents automatisch erkennen und nutzen.<\/p>\n<p><strong>Das Ergebnis ist eine perfekte Zusammenarbeit<\/strong>: Komplexe Koog-Workflows werden zu A2A-Aufgaben, die jeder Agent nutzen kann, w\u00e4hrend Ihre Koog-Agents die volle Leistungsf\u00e4higkeit des A2A-\u00d6kosystems nutzen k\u00f6nnen. Da Koog im Backend, auf Ger\u00e4ten und in Browser-Umgebungen ausgef\u00fchrt werden kann, k\u00f6nnen Sie vernetzte KI-Systeme umfassender und effektiver als je zuvor bereitstellen.<\/p>\n<p>Wie ist das m\u00f6glich? Sehen wir es uns an!<\/p>\n<h2 class=\"wp-block-heading\">A2A-Protokoll<\/h2>\n<p>Das A2A-Protokoll definiert die wesentlichen Bausteine f\u00fcr die Kommunikation zwischen Agents:<\/p>\n<ul>\n<li><strong>Agent-Erkennung<\/strong> \u00fcber standardisierte Agent-Karten (JSON-Dokumente, die F\u00e4higkeiten beschreiben).<\/li>\n<li><strong>Nachrichtenformate<\/strong> f\u00fcr Anfragen und Antworten mit konsistenten Schemata.<\/li>\n<li><strong>Aufgabenlebenszyklus<\/strong>-Verwaltung mit klaren Statuswerten: \u00fcbermittelt \u2192 in Bearbeitung \u2192 abgeschlossen\/fehlgeschlagen.<\/li>\n<li><strong>Transportschichten<\/strong> wie JSON-RPC, gRPC und REST.<\/li>\n<li><strong>Sicherheitskonzepte<\/strong> mittels Standard-OAuth2, API-Schl\u00fcsseln und JWT-Tokens.<\/li>\n<li><strong>Fehlerbehandlung<\/strong> mit standardisierten Fehlercodes.<\/li>\n<\/ul>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-645498\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image-50.png\" alt=\"\" width=\"1008\" height=\"752\" \/><\/figure>\n<h3 class=\"wp-block-heading\">Agent-Karten: digitale Visitenkarten<\/h3>\n<p>Jeder Agent im A2A-\u00d6kosystem ver\u00f6ffentlicht seine F\u00e4higkeiten \u00fcber eine \u201eAgent-Karte\u201c \u2013 eine standardisierte JSON-Datei, die unter einer bestimmten URL, z.\u00a0B. <em>\/.well-known\/agent-card.json<\/em>, auf der Domain des Agents gehostet wird. Die Agent-Karte fungiert als digitale Visitenkarte, die es anderen Agents erm\u00f6glicht, die bereitgestellten Services zu erkennen.<\/p>\n<p>Eine Agent-Karte enth\u00e4lt in der Regel:<\/p>\n<ul>\n<li><strong>Basisinformationen: <\/strong>Agentenname, Beschreibung, Version usw.<\/li>\n<li><strong>F\u00e4higkeiten<\/strong>: Was der Agent leisten kann (z.\u00a0B. Dokumente verfassen, Texte korrigieren, Daten analysieren oder Bilder generieren).<\/li>\n<li><strong>Endpunkte<\/strong>: Wie der Agent zu erreichen ist.<\/li>\n<li><strong>Weitere optionale Informationen: <\/strong>Aktivierte F\u00e4higkeiten, Authentifizierung und mehr.<\/li>\n<\/ul>\n<p>Dieser Erkennungsmechanismus erspart uns die manuelle Integration. Wenn ein Agent eine bestimmte F\u00e4higkeit ben\u00f6tigt, \u00fcberpr\u00fcft er einfach die entsprechende Agent-Karte, um zu verstehen, wie er mit dem Service interagieren muss.<\/p>\n<p>In Koog werden Agent-Karten mittels Kotlin-Datenklassen definiert:<\/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 = \"Blog-Autor\",\n    description = \"KI-Agent zum Erstellen hochwertiger Blogeintr\u00e4ge und Artikel\",\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 = \"Schreiben von Blogartikeln\",\n            description = \"Generierung interessanter Blogartikel zu jedem Thema\",\n            tags = listOf(\"writing\", \"content\", \"blog\"),\n            examples = listOf(\"Schreibe einen Beitrag \u00fcber KI-Trends\")\n        )\n    )\n)<\/pre>\n<h3 class=\"wp-block-heading\">Universelles Nachrichtensystem: ein einfaches Muster<\/h3>\n<p>A2A verwendet ein einheitliches, standardisiertes Nachrichtenformat f\u00fcr die gesamte Kommunikation zwischen Agents. In dieser Einfachheit liegt die Kraft \u2013 anstatt mit Dutzenden unterschiedlichen APIs zu hantieren, m\u00fcssen Agents lediglich ein einziges Kommunikationsmuster verstehen.<\/p>\n<p>Jede Interaktion folgt dem gleichen Ablauf:<\/p>\n<ol>\n<li><strong>Senden<\/strong> einer Nachricht mit der Aufgabenanfrage und den Parametern.<\/li>\n<li><strong>Empfangen<\/strong> entweder sofortiger Ergebnisse oder einer Aufgabe zur Statusverfolgung.<\/li>\n<li><strong>Updates<\/strong> \u00fcber Echtzeitkan\u00e4le f\u00fcr l\u00e4ngere Vorg\u00e4nge.<\/li>\n<\/ol>\n<p>Dank diesem universellen Ansatz k\u00f6nnen neue Agentenf\u00e4higkeiten hinzugef\u00fcgt werden, ohne die Kommunikationsprotokolle zu \u00e4ndern. Unabh\u00e4ngig davon, ob der Agent einen Text zusammenfassen oder einen komplexen Bericht generieren soll, bleibt die Nachrichtenstruktur gleich.<\/p>\n<p>In Koog k\u00f6nnen Sie Nachrichten ganz einfach mithilfe bereits implementierter Objekte und Protokolle erstellen und senden:<\/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(\"Schreibe einen Blogartikel \u00fcber die Zukunft von KI-Agents\")\n    ),\n    contextId = \"blog-project-456\"\n)\n\nval request = Request(\n    data = MessageSendParams(\n        message = message,\n        configuration = MessageConfiguration(\n            blocking = false, \/\/ Erste Antwort abrufen\n            historyLength = 5 \/\/ Kontext ber\u00fccksichtigen\n        )\n    )\n)\n\nval response = client.sendMessage(request)<\/pre>\n<p>Das Nachrichtenformat unterst\u00fctzt vielf\u00e4ltige Inhalte durch unterschiedliche <em>Part<\/em>-Typen, darunter TextPart f\u00fcr reine Textinhalte, FilePart f\u00fcr angeh\u00e4ngte Dateien und DataPart f\u00fcr strukturierte JSON-Daten.<\/p>\n<p>Dadurch k\u00f6nnen Ihre Koog-Agents m\u00fchelos mit jedem A2A-kompatiblen Agent kommunizieren, ganz gleich, ob es um Textverarbeitung, Dateianalyse oder komplexe Datentransformationen geht.<\/p>\n<h3 class=\"wp-block-heading\">Aufgabenlebenszyklus: intelligente Abl\u00e4ufe<\/h3>\n<p>A2A verwaltet unterschiedliche Arbeitstypen auf intelligente Weise, basierend auf Komplexit\u00e4t und Dauer:<\/p>\n<p><strong>Sofortnachrichten<\/strong>: Bei einfachen Vorg\u00e4ngen wie Textformatierung oder schnellen Berechnungen werden die Ergebnisse direkt in der Antwort der KI zur\u00fcckgegeben. Es ist kein Warten und keine Statusverfolgung erforderlich.<\/p>\n<p><strong>L\u00e4nger andauernde Aufgaben<\/strong>: Komplexe Vorg\u00e4nge wie Dokumentanalysen oder mehrstufige Workflows werden in die Warteschlange gestellt und geben eine Aufgabe zur\u00fcck. Der anfordernde Agent kann den Fortschritt \u00fcberwachen und die Ergebnisse der Aufgabe abrufen, sobald diese fertig sind.<\/p>\n<p><strong>Echtzeit-Updates<\/strong>: Bei zeitaufw\u00e4ndigen Vorg\u00e4ngen stellen serverseitige Events (Server-Sent Events, SSE) Live-Updates zum Fortschritt bereit. Dadurch bleiben die Agents auch ohne st\u00e4ndige Statusabfragen auf dem Laufenden.<\/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(\"Anfrage zum Schreiben eines Blogbeitrags erhalten\")),\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\">Eingebaute Sicherheit: nur Industriestandards<\/h3>\n<p>A2A will die Sicherheit nicht neu erfinden. Stattdessen werden bew\u00e4hrte und weit verbreitete Standards wie OAuth2, API-Schl\u00fcssel und Standard-HTTPS verwendet.<\/p>\n<p>Dies bedeutet auch, dass Sie als Entwickler*in keine neuen Authentifizierungskonzepte erlernen m\u00fcssen. Wenn Sie mit der Sicherheit moderner Web-APIs vertraut sind, kennen Sie sich bereits in der A2A-Sicherheit aus. Das System \u00fcbernimmt alle Tools, Best Practices und Sicherheitsaudits, die mit diesen etablierten Standards einhergehen.<\/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, \/\/ F\u00fcr die Authentifizierung zust\u00e4ndiger Service\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(\"Missing Authorization token\")\n\n        val user = authService.authenticate(token)\n            ?: throw A2AInvalidParamsException(\"Invalid Authorization token\")\n\n        if (requiredPermission !in user.permissions) {\n            throw A2AUnsupportedOperationException(\"Insufficient permissions\")\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        \/\/ Benutzerdaten \u00fcber Kontext-State an Agent-Executor \u00fcbergeben\n        val enrichedCtx = ctx.copy(\n            state = ctx.state + (AuthStateKeys.USER to user)\n        )\n\n        \/\/ Mit erweitertem Kontext an \u00fcbergeordnete Implementierung delegieren\n        return super.onSendMessage(request, enrichedCtx)\n    }\n\n   \/\/ die \u00fcbrigen gewrappten A2A-Methoden \n   \/\/ ...\n}<\/pre>\n<h2 class=\"wp-block-heading\">Koog-Agents in A2A integrieren<\/h2>\n<p>Das Koog-Framework bringt sowohl einen A2A-Client als auch einen A2A-Server mit. Dies bedeutet, dass Ihre Koog-Agents problemlos mit anderen A2A-f\u00e4higen Agents kommunizieren k\u00f6nnen und ihrerseits f\u00fcr die Au\u00dfenwelt sichtbar sind. Das folgende einfache Beispiel zeigt, wie Sie das implementieren k\u00f6nnen.<\/p>\n<h3 class=\"wp-block-heading\">Koog-Agents in A2A-Server einbinden<\/h3>\n<p>Definieren Sie als Erstes eine Strategie f\u00fcr den Agent. Koog stellt Konverter (<em>toKoogMessage<\/em>, <em>toA2AMessage<\/em>) bereit, um unkompliziert zwischen den Nachrichtenformaten von Koog und A2A zu wechseln \u2013 Sie sparen sich somit die manuelle Serialisierung. Spezielle Knoten wie <em>nodeA2ASendMessage<\/em> k\u00fcmmern sich um den Nachrichtenaustausch, sodass Kommunikationsabl\u00e4ufe einfach zu implementieren sind:<\/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                +\"Schreibe einen Blogbeitrag auf Grundlage der Benutzeranfrage\"\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>Definieren Sie als N\u00e4chstes den Agent selbst. Sobald Sie das Feature <em>A2AServer<\/em> installiert haben, wird Ihr Agent im \u00d6kosystem sichtbar und zug\u00e4nglich. Auf diese Weise k\u00f6nnen komplexe Netzwerke entstehen, in denen spezialisierte Agents reibungslos zusammenarbeiten.<\/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     \/\/ Vorhandene Nachrichten f\u00fcr den aktuellen Unterhaltungskontext abrufen\n     val messageHistory = requestContext.messageStorage.getAll().map { it.toKoogMessage() }\n\n     val agentConfig = AIAgentConfig(\n        prompt = prompt(\"blogpost\") {\n            system(\"Du bist ein Agent, der Blogbeitr\u00e4ge schreibt\")\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                \/\/ Antwort des Agents in den aktuellen Gespr\u00e4chskontext aufnehmen\n                val resultMessge = ctx.result as A2AMessage\n                requestContext.messageStorage.save(resultMessge)\n            }\n        }\n    }\n}<\/pre>\n<p>Drittens m\u00fcssen wir den Agent in den Executor einbinden und anschlie\u00dfend einen Server definieren.<\/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>Im letzten Schritt definieren wir einen Servertransport und f\u00fchren den Server aus.<\/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>Ihr Agent ist nun bereit, Anfragen zu bearbeiten!<\/p>\n<h3 class=\"wp-block-heading\">Andere A2A-Agents von einem Koog-Agent aus aufrufen<\/h3>\n<p>Zun\u00e4chst m\u00fcssen Sie einen A2A-Client konfigurieren und verbinden, um eine Agent-Karte abzurufen.<\/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\/\/ Client initialisieren und Karte abrufen\na2aClient.connect()<\/pre>\n<p>Anschlie\u00dfend k\u00f6nnen Sie in Ihrer Strategie <em>nodeA2ASendMessage <\/em>oder <em>nodeA2ASendMessageStreaming<\/em> verwenden, um diese Clients aufzurufen und eine Nachricht oder eine Aufgabe zu erhalten.<\/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            \/\/ Ereignis verarbeiten\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(\"Schreibe einen Blogartikel \u00fcber die Integration von A2A und Koog\")<\/pre>\n<h2 class=\"wp-block-heading\">N\u00e4chste Schritte<\/h2>\n<p>Wenn Sie sich detaillierter mit Koog und A2A besch\u00e4ftigen m\u00f6chten, empfehlen wir Ihnen die folgenden n\u00fctzlichen Ressourcen:<\/p>\n<p><a href=\"https:\/\/docs.koog.ai\/\" target=\"_blank\" rel=\"noopener\">Koog-Dokumentation<\/a><\/p>\n<p><a href=\"https:\/\/a2a-protocol.org\/latest\/specification\/\" target=\"_blank\" rel=\"noopener\">A2A-Spezifikation<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/JetBrains\/koog\/tree\/develop\/examples\/simple-examples\/src\/main\/kotlin\/ai\/koog\/agents\/example\/a2a\" target=\"_blank\" rel=\"noopener\" data-type=\"link\" data-id=\"https:\/\/github.com\/JetBrains\/koog\/tree\/develop\/examples\/simple-examples\/src\/main\/kotlin\/ai\/koog\/agents\/example\/a2a\">Beispiele f\u00fcr die Verwendung von Koog und A2A<\/a><\/p>\n<p><strong>Autor des urspr\u00fcnglichen Blogposts<\/strong><\/p>\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":964,"featured_media":654243,"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\/de\/wp-json\/wp\/v2\/ai\/651486"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/ai"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/types\/ai"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/users\/964"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/comments?post=651486"}],"version-history":[{"count":3,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/ai\/651486\/revisions"}],"predecessor-version":[{"id":654267,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/ai\/651486\/revisions\/654267"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media\/654243"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/media?parent=651486"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/categories?post=651486"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/tags?post=651486"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/de\/wp-json\/wp\/v2\/cross-post-tag?post=651486"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}