Articles de blog

Création d'une salle de presse avec agent LLM, protocole A2A et MCP dans Elasticsearch : Partie II

Découvrez comment construire une salle de presse hybride spécialisée pour les agents LLM en utilisant le protocole A2A pour la collaboration entre agents et MCP pour l'accès aux outils dans Elasticsearch.

A2A et MCP : le code en action

Cet article est le complément de l'article "Creating an LLM Agent newsroom with A2A protocol and MCP in Elasticsearch !", qui expliquait les avantages de la mise en œuvre des architectures A2A et MCP au sein du même agent afin de profiter pleinement des avantages uniques des deux frameworks. Un référentiel est disponible si vous souhaitez exécuter la démo par vous-même.

A2A & Flux de travail de l'agent de protocole MCP

Voyons comment les agents de notre salle de presse collaborent en utilisant à la fois A2A et MCP pour produire un article. Le référentiel d'accompagnement pour voir les agents en action est disponible ici.

Étape 1 : Attribution de l'histoire

Le chef de l'information (agissant en tant que client) attribue un sujet :

{
  "message_type": "task_request",
  "sender": "news_chief",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "story_renewable_energy_2024",
    "assignment": {
      "topic": "Renewable Energy Adoption in Europe",
      "angle": "Policy changes driving solar and wind expansion",
      "target_length": 1200,
      "deadline": "2025-09-30T18:00:00Z"
    }
  }
}

Étape 2 : Le journaliste demande des recherches

L'agent rapporteur reconnaît qu'il a besoin d'informations générales et délègue à l'agent chercheur par l'intermédiaire de l'A2A :

{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "researcher_agent",
  "payload": {
    "task_id": "research_eu_renewable_2024",
    "parent_task_id": "story_renewable_energy_2024",
    "capability": "fact_gathering",
    "parameters": {
      "queries": [
        "EU renewable energy capacity 2024",
        "Solar installations growth Europe",
        "Wind energy policy changes 2024"
      ],
      "depth": "comprehensive"
    }
  }
}

Étape 3 : Le rapporteur demande le contexte historique à l'agent d'archivage

L'agent rapporteur reconnaît que le contexte historique renforcerait l'histoire. Il délègue à l'agent d'archivage (alimenté par l'agent A2A d'Elastic), via A2A, le soin d'effectuer des recherches dans les archives d'articles de la salle de presse alimentées par Elasticsearch :

{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "archive_agent",
  "payload": {
    "task_id": "archive_search_renewable_2024",
    "parent_task_id": "story_renewable_energy_2024",
    "capability": "search_archive",
    "parameters": {
      "query": "European renewable energy policy changes and adoption trends over past 5 years",
      "focus_areas": ["solar", "wind", "policy", "Germany", "France"],
      "time_range": "2019-2024",
      "result_count": 10
    }
  }
}

Étape 4 : L'agent d'archivage utilise l'agent Elastic A2A avec MCP

L'agent d'archivage utilise l'agent A2A d'Elastic, qui à son tour utilise MCP pour accéder aux outils Elasticsearch. Ceci démontre l'architecture hybride où A2A permet la collaboration des agents tandis que MCP fournit l'accès aux outils :

# Archive Agent using Elastic A2A Agent
async def search_historical_articles(self, query_params):
    # The Archive Agent sends a request to Elastic's A2A Agent
    elastic_response = await self.a2a_client.send_request(
        agent="elastic_agent",
        capability="search_and_analyze",
        parameters={
            "natural_language_query": query_params["query"],
            "index_pattern": "newsroom-articles-*",
            "filters": {
                "topics": query_params["focus_areas"],
                "date_range": query_params["time_range"]
            },
            "analysis_type": "trend_analysis"
        }
    )
    
    # Elastic's A2A Agent internally uses MCP tools:
    # - platform.core.search (to find relevant articles)
    # - platform.core.generate_esql (to analyze trends)
    # - platform.core.index_explorer (to identify relevant indices)
    
    return elastic_response

L'agent d'archivage reçoit des données historiques complètes de l'agent A2A d'Elastic et les renvoie au rapporteur :

{
  "message_type": "task_response",
  "sender": "archive_agent",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "archive_search_renewable_2024",
    "status": "completed",
    "archive_data": {
      "historical_articles": [
        {
          "title": "Germany's Energiewende: Five Years of Solar Growth",
          "published": "2022-06-15",
          "key_points": [
            "Germany added 7 GW annually 2020-2022",
            "Policy subsidies drove 60% of growth"
          ],
          "relevance_score": 0.94
        },
        {
          "title": "France Balances Nuclear and Renewables",
          "published": "2023-03-20",
          "key_points": [
            "France increased renewable target to 40% by 2030",
            "Solar capacity doubled 2021-2023"
          ],
          "relevance_score": 0.89
        }
      ],
      "trend_analysis": {
        "coverage_frequency": "EU renewable stories increased 150% since 2019",
        "emerging_themes": ["policy incentives", "grid modernization", "battery storage"],
        "coverage_gaps": ["Small member states", "offshore wind permitting"]
      },
      "total_articles_found": 47,
      "search_confidence": 0.91
    }
  }
}

Cette étape montre comment l'agent A2A d'Elastic s'intègre dans le flux de travail de la salle de presse. L'Archive Agent (un agent spécifique à la salle de presse) se coordonne avec l'A2A Agent d'Elastic (un spécialiste tiers) pour exploiter les puissantes capacités de recherche et d'analyse d'Elasticsearch. L'agent Elastic utilise MCP en interne pour accéder aux outils Elasticsearch, ce qui montre la séparation nette entre la coordination de l'agent (A2A) et l'accès aux outils (MCP).

Étape 5 : Le chercheur utilise les serveurs MCP

L'agent chercheur accède à plusieurs serveurs MCP pour recueillir des informations :

# Researcher Agent using MCP to access tools
async def gather_facts(self, queries):
    results = []
    
    # Use News API MCP Server
    news_data = await self.mcp_client.invoke_tool(
        server="news_api_mcp",
        tool="search_articles",
        parameters={
            "query": queries[0],
            "date_range": "2024-01-01 to 2024-09-30",
            "sources": ["reuters", "bloomberg", "euractiv"]
        }
    )
    
    # Use Statistics MCP Server
    stats_data = await self.mcp_client.invoke_tool(
        server="eurostat_mcp",
        tool="get_energy_statistics",
        parameters={
            "metrics": ["solar_capacity_mw", "wind_capacity_mw"],
            "countries": ["EU27"],
            "year": 2024
        }
    )
    
    # Use Fact-Checking MCP Server
    verified_facts = await self.mcp_client.invoke_tool(
        server="factcheck_mcp",
        tool="verify_claims",
        parameters={
            "claims": [
                "EU solar capacity increased 40% in 2024",
                "Germany leads in wind installations"
            ]
        }
    )
    
    return self._synthesize_research(news_data, stats_data, verified_facts)

Étape 6 : Le chercheur renvoie les données au rapporteur

L'agent chargé de la recherche renvoie la recherche complète par l'intermédiaire de l'A2A :

{
  "message_type": "task_response",
  "sender": "researcher_agent",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "research_eu_renewable_2024",
    "status": "completed",
    "research_data": {
      "key_facts": [
        {
          "claim": "EU solar capacity reached 260 GW in 2024",
          "source": "Eurostat Q3 2024 Report",
          "confidence": 0.95,
          "verified": true
        },
        {
          "claim": "Germany installed 12 GW of wind capacity in 2024",
          "source": "German Federal Network Agency",
          "confidence": 0.92,
          "verified": true
        }
      ],
      "statistics": {
        "solar_growth_rate": "35%",
        "wind_growth_rate": "28%"
      },
      "sources_count": 15
    }
  }
}

Étape 7 : Le journaliste rédige un article

L'agent rapporteur utilise les données de recherche et ses propres capacités LLM pour rédiger l'article. Pendant la rédaction, le Reporter utilise les serveurs MCP pour le style et les modèles :

# Reporter Agent writing with MCP assistance
async def write_article(self, research_data, assignment):
    # Get style guidelines via MCP
    style_guide = await self.mcp_client.get_resource(
        server="newsroom_mcp",
        resource="style://editorial/ap_style_guide"
    )
    
    # Get article template via MCP
    template = await self.mcp_client.get_resource(
        server="newsroom_mcp",
        resource="template://articles/news_story"
    )
    
    # Generate article using LLM + research + style
    draft = await self.llm.generate(
        prompt=f"""
        Write a news article following these guidelines:
        {style_guide}
        
        Using this template:
        {template}
        
        Based on this research:
        {research_data}
        
        Assignment: {assignment}
        """
    )
    
    # Self-evaluate confidence in claims
    confidence_check = await self._evaluate_confidence(draft)
    
    return draft, confidence_check

Étape 8 : le manque de confiance déclenche une nouvelle recherche

L'agent déclarant évalue son projet et constate qu'une créance a un faible degré de confiance. Il envoie une autre demande à l'agent du chercheur :

{
  "message_type": "collaboration_request",
  "sender": "reporter_agent",
  "receiver": "researcher_agent",
  "payload": {
    "request_type": "fact_verification",
    "claims": [
      {
        "text": "France's nuclear phase-down contributed to 15% increase in renewable capacity",
        "context": "Discussing policy drivers for renewable growth",
        "current_confidence": 0.45,
        "required_confidence": 0.80
      }
    ],
    "urgency": "high"
  }
}

Le chercheur vérifie l'allégation à l'aide des serveurs MCP de vérification des faits et renvoie les informations mises à jour :

{
  "message_type": "collaboration_response",
  "sender": "researcher_agent",
  "receiver": "reporter_agent",
  "payload": {
    "verified_claims": [
      {
        "original_claim": "France's nuclear phase-down contributed to 15% increase...",
        "verified_claim": "France's renewable capacity increased 18% in 2024, partially offsetting reduced nuclear output",
        "confidence": 0.88,
        "corrections": "Percentage was 18%, not 15%; nuclear phase-down is gradual, not primary driver",
        "sources": ["RTE France", "French Energy Ministry Report 2024"]
      }
    ]
  }
}

Étape 9 : Le journaliste révise le texte et le soumet au rédacteur en chef

Le rapporteur incorpore les faits vérifiés et envoie le projet complet à l'agent rédacteur par l'intermédiaire de l'A2A :

{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "editor_agent",
  "payload": {
    "task_id": "edit_renewable_story",
    "parent_task_id": "story_renewable_energy_2024",
    "content": {
      "headline": "Europe's Renewable Revolution: Solar and Wind Surge 30% in 2024",
      "body": "[Full article text...]",
      "word_count": 1185,
      "sources": [/* array of sources */]
    },
    "editing_requirements": {
      "check_style": true,
      "check_facts": true,
      "check_seo": true
    }
  }
}

Étape 10 : Examens des éditeurs à l'aide des outils MCP

L'agent rédacteur utilise plusieurs serveurs MCP pour réviser l'article :

# Editor Agent using MCP for quality checks
async def review_article(self, content):
    # Grammar and style check
    grammar_issues = await self.mcp_client.invoke_tool(
        server="grammarly_mcp",
        tool="check_document",
        parameters={"text": content["body"]}
    )
    
    # SEO optimization check
    seo_analysis = await self.mcp_client.invoke_tool(
        server="seo_mcp",
        tool="analyze_content",
        parameters={
            "headline": content["headline"],
            "body": content["body"],
            "target_keywords": ["renewable energy", "Europe", "solar", "wind"]
        }
    )
    
    # Plagiarism check
    originality = await self.mcp_client.invoke_tool(
        server="plagiarism_mcp",
        tool="check_originality",
        parameters={"text": content["body"]}
    )
    
    # Generate editorial feedback
    feedback = await self._generate_feedback(
        grammar_issues, 
        seo_analysis, 
        originality
    )
    
    return feedback

Le rédacteur en chef approuve l'article et le transmet :

{
  "message_type": "task_response",
  "sender": "editor_agent",
  "receiver": "reporter_agent",
  "payload": {
    "status": "approved",
    "quality_score": 9.2,
    "minor_edits": [
      "Changed 'surge' to 'increased' in paragraph 3 for AP style consistency",
      "Added Oxford comma in list of countries"
    ],
    "approved_content": "[Final edited article]"
  }
}

Étape 11 : L'éditeur publie via CI/CD

Enfin, l'agent imprimeur publie l'article approuvé en utilisant les serveurs MCP pour le CMS et le pipeline CI/CD :

# Publisher Agent publishing via MCP
async def publish_article(self, content, metadata):
    # Upload to CMS via MCP
    cms_result = await self.mcp_client.invoke_tool(
        server="wordpress_mcp",
        tool="create_post",
        parameters={
            "title": content["headline"],
            "body": content["body"],
            "status": "draft",
            "categories": metadata["categories"],
            "tags": metadata["tags"],
            "featured_image_url": metadata["image_url"]
        }
    )
    
    post_id = cms_result["post_id"]
    
    # Trigger CI/CD deployment via MCP
    deploy_result = await self.mcp_client.invoke_tool(
        server="cicd_mcp",
        tool="trigger_deployment",
        parameters={
            "pipeline": "publish_article",
            "environment": "production",
            "post_id": post_id,
            "schedule": "immediate"
        }
    )
    
    # Track analytics
    await self.mcp_client.invoke_tool(
        server="analytics_mcp",
        tool="register_publication",
        parameters={
            "post_id": post_id,
            "publish_time": datetime.now().isoformat(),
            "story_id": metadata["story_id"]
        }
    )
    
    return {
        "status": "published",
        "post_id": post_id,
        "url": f"https://newsroom.example.com/articles/{post_id}",
        "deployment_id": deploy_result["deployment_id"]
    }

L'éditeur confirme la publication via A2A :

{
  "message_type": "task_complete",
  "sender": "printer_agent",
  "receiver": "news_chief",
  "payload": {
    "task_id": "story_renewable_energy_2024",
    "status": "published",
    "publication": {
      "url": "https://newsroom.example.com/articles/renewable-europe-2024",
      "published_at": "2025-09-30T17:45:00Z",
      "post_id": "12345"
    },
    "workflow_metrics": {
      "total_time_minutes": 45,
      "agents_involved": ["reporter", "researcher", "archive", "editor", "printer"],
      "iterations": 2,
      "mcp_calls": 12
    }
  }
}

Voici la séquence complète du flux de travail A2A dans le référentiel d'accompagnement en utilisant les mêmes agents que ceux décrits ci-dessus.

#

De

Pour

Action

Protocole

Description

1

Utilisateur

Chef de l'information

Attribuer l'histoire

HTTP POST

L'utilisateur soumet le sujet et l'angle de l'article

2

Chef de l'information

Interne

Créer une histoire

-

Création d'un enregistrement d'histoire avec un identifiant unique

3

Chef de l'information

Reporter

Affectation des délégués

A2A

Envoi de l'article via le protocole A2A

4

Reporter

Interne

Accepter l'affectation

-

Stockage interne de l'affectation

5

Reporter

Serveur MCP

Générer un plan

MCP/HTTP

Création d'un plan d'article et de questions de recherche

6a

Reporter

Chercheur

Demande de recherche

A2A

Envoie des questions (parallèle avec 6b)

6b

Reporter

Archiviste

Recherche dans les archives

A2A JSONRPC

Recherche d'articles historiques (parallèle avec 6a)

7

Chercheur

Serveur MCP

Questions de recherche

MCP/HTTP

Utilise l'Anthropique via le MCP pour répondre aux questions

8

Chercheur

Reporter

Recherche en matière de retour

A2A

Réponses à la recherche sur les retours

9

Archiviste

Elasticsearch

Index de recherche

API REST ES

Requêtes news_archive index

10

Archiviste

Reporter

Retour à l'archive

A2A JSONRPC

Renvoie les résultats de la recherche historique

11

Reporter

Serveur MCP

Générer un article

MCP/HTTP

Création d'un article dans un contexte de recherche ou d'archives

12

Reporter

Interne

Projet de magasin

-

Sauvegarde interne du projet

13

Reporter

Chef de l'information

Soumettre le projet

A2A

Soumission d'un projet achevé

14

Chef de l'information

Interne

Mise à jour de l'histoire

-

Stocke le projet, met à jour le statut à "draft_submitted"

15

Chef de l'information

Éditeur

Projet de révision

A2A

Routes automatiques vers l'éditeur pour révision

16

Éditeur

Serveur MCP

Article de synthèse

MCP/HTTP

Analyse du contenu à l'aide d'Anthropic via MCP

17

Éditeur

Chef de l'information

Retourner à l'examen

A2A

Envoi d'un retour d'information et de suggestions éditoriales

18

Chef de l'information

Interne

Revue des magasins

-

Stocke les commentaires des éditeurs

19

Chef de l'information

Reporter

Appliquer les modifications

A2A

Acheminement du retour d'information sur l'examen au rapporteur

20

Reporter

Serveur MCP

Appliquer les modifications

MCP/HTTP

Révision de l'article en fonction du retour d'information

21

Reporter

Interne

Projet de mise à jour

-

Mise à jour du projet avec des révisions

22

Reporter

Chef de l'information

Retour Révisé

A2A

Retourne l'article révisé

23

Chef de l'information

Interne

Mise à jour de l'histoire

-

Stocker le projet révisé, statut à "révisé"

24

Chef de l'information

Éditeur

Publier un article

A2A

Routes automatiques vers l'éditeur

25

Éditeur

Serveur MCP

Générer des étiquettes

MCP/HTTP

Création d'étiquettes et de catégories

26

Éditeur

Elasticsearch

Index Article

API REST ES

Indexe l'article dans l'index news_archive

27

Éditeur

Système de fichiers

Sauvegarder la démarque

Fichier E/S

Enregistre l'article au format .md fichier dans /articles

28

Éditeur

Chef de l'information

Confirmer la publication

A2A

Renvoie l'état de réussite

29

Chef de l'information

Interne

Mise à jour de l'histoire

-

Mise à jour du statut de l'article à "publié"

Conclusion

L'A2A et le MCP ont tous deux un rôle important à jouer dans le paradigme moderne de l'infrastructure augmentée-LLM. L'A2A offre une certaine souplesse pour les systèmes multi-agents complexes, mais potentiellement moins de portabilité et une plus grande complexité opérationnelle. MCP offre une approche standardisée pour l'intégration des outils, plus simple à mettre en œuvre et à maintenir, bien qu'il ne soit pas conçu pour gérer l'orchestration multi-agents.

Le choix n'est pas binaire. Comme le montre notre exemple de salle de presse, les systèmes les plus sophistiqués et les plus efficaces soutenus par le LLM combinent souvent les deux approches : les agents se coordonnent et se spécialisent par le biais de protocoles A2A tout en accédant à leurs outils et à leurs ressources par le biais de serveurs MCP. Cette architecture hybride offre les avantages organisationnels des systèmes multi-agents ainsi que les avantages de la normalisation et de l'écosystème du MCP. Cela suggère qu'il n'est peut-être pas nécessaire de faire un choix : il suffit d'utiliser les deux en tant qu'approche standard.

C'est à vous, en tant que développeur ou architecte, de tester et de déterminer le meilleur mélange de ces deux solutions pour obtenir le bon résultat pour votre cas d'utilisation spécifique. Comprendre les points forts, les limites et les applications appropriées de chaque approche vous permettra de construire des systèmes d'IA plus efficaces, plus faciles à maintenir et plus évolutifs.

Que vous construisiez une salle de presse numérique, une plateforme de service à la clientèle, un assistant de recherche ou toute autre application alimentée par le LLM, l'examen attentif de vos besoins de coordination (A2A) et des exigences d'accès aux outils (MCP) vous mettra sur la voie de la réussite.

Ressources supplémentaires

Pour aller plus loin

Agent Builder, bien plus qu’une interface de discussion : vers une infrastructure augmentée

Alexander Wert

Gestion de la mémoire agentique avec Elasticsearch.

Someshwaran Mohankumar

Utilisation de l'API d'inférence Elasticsearch avec les modèles Hugging Face

Jeffrey Rengifo

Construire un agent d'IA pour les RH avec Elastic Agent Builder et GPT-OSS

Tomás Murúa

Création d'un serveur Elasticsearch MCP avec TypeScript

Jeffrey Rengifo

Prêt à créer des expériences de recherche d'exception ?

Une recherche suffisamment avancée ne se fait pas avec les efforts d'une seule personne. Elasticsearch est alimenté par des data scientists, des ML ops, des ingénieurs et bien d'autres qui sont tout aussi passionnés par la recherche que vous. Mettons-nous en relation et travaillons ensemble pour construire l'expérience de recherche magique qui vous permettra d'obtenir les résultats que vous souhaitez.

Jugez-en par vous-même