LLM Agents Academy
Module 10: Multi-Agent Systems

Agent Communication

Message passing, shared state, blackboard systems, and event-driven coordination

~12 min readIncludes code

Overview

In the previous two lessons, you explored why multi-agent systems exist and how to organize agents into topologies like supervisors, pipelines, and swarms. But topology only answers one question: who connects to whom. It does not answer the equally important question: how do agents actually talk to each other?

Communication is the nervous system of any multi-agent architecture. A supervisor cannot delegate if it cannot send a task description. A pipeline cannot flow if upstream agents cannot pass results downstream. A swarm cannot converge if agents cannot share discoveries. The communication mechanism you choose shapes everything -- how tightly agents are coupled, how easily you can add new agents, how the system handles failures, and how observable the interactions are.

This lesson covers the four fundamental communication patterns for multi-agent systems: direct message passing, shared state (the blackboard pattern), event-driven coordination, and communication protocols. You will implement a working message bus in Python and see how each pattern maps to the orchestration topologies from the previous lesson. By the end, you will know which pattern to reach for based on your system's coupling, scalability, and observability needs.

The Four Communication Patterns

Before diving into each pattern, here is the architectural landscape. These four patterns are not mutually exclusive -- production systems often combine two or more.

graph TD
  subgraph Direct["Direct Messaging"]
      A1["Agent A"] -->|request| A2["Agent B"]
      A2 -->|response| A1
  end

  subgraph Blackboard["Shared State / Blackboard"]
      B1["Agent A"] -->|write| BB["Blackboard"]
      B2["Agent B"] -->|read/write| BB
      B3["Agent C"] -->|read| BB
  end

  subgraph EventBus["Event Bus / Pub-Sub"]
      C1["Agent A"] -->|publish| BUS["Event Bus"]
      BUS -->|notify| C2["Agent B"]
      BUS -->|notify| C3["Agent C"]
  end

  subgraph Protocol["Communication Protocol"]
      D1["Agent A"] -->|structured envelope| D2["Agent B"]
      D2 -->|structured envelope| D1
      D3["Schema Registry"] -.->|validates| D1
      D3 -.->|validates| D2
  end

  style Direct fill:#ebf8ff,stroke:#3182ce
  style Blackboard fill:#f0fff4,stroke:#38a169
  style EventBus fill:#fefcbf,stroke:#d69e2e
  style Protocol fill:#fef0f0,stroke:#e53e3e

Each pattern trades off between coupling, complexity, and flexibility. Direct messaging is the simplest but creates tight coupling. A blackboard decouples timing but introduces shared mutable state. An event bus decouples both identity and timing but adds infrastructure. A formal protocol adds structure and interoperability at the cost of upfront design effort.

Pattern 1: Direct Message Passing

Direct message passing is the most intuitive approach: Agent A constructs a message and sends it to Agent B. Agent B processes the message and may send a response back. This is like a function call across agent boundaries.

sequenceDiagram
  participant Supervisor as Supervisor Agent
  participant Researcher as Researcher Agent
  participant Writer as Writer Agent

  Supervisor->>Researcher: {"type": "research_request", "topic": "LLM scaling laws", "depth": "detailed"}
  Note over Researcher: Searches sources,<br/>synthesizes findings

  Researcher-->>Supervisor: {"type": "research_result", "findings": [...], "sources": 12}

  Supervisor->>Writer: {"type": "write_request", "content": findings, "format": "blog_post"}
  Note over Writer: Drafts article from<br/>research findings

  Writer-->>Supervisor: {"type": "write_result", "draft": "...", "word_count": 1200}

  Supervisor->>Researcher: {"type": "fact_check", "claims": [...]}
  Note over Researcher: Verifies claims<br/>against sources

  Researcher-->>Supervisor: {"type": "fact_check_result", "verified": 8, "disputed": 1}

  Supervisor->>Writer: {"type": "revision_request", "feedback": "Fix disputed claim in paragraph 3"}
  Writer-->>Supervisor: {"type": "revision_result", "draft": "...", "changes": 1}

In this sequence, the supervisor orchestrates a research-and-writing workflow by sending structured messages to specialized agents. Each message has a type field that tells the receiver what kind of work is expected. The researcher and writer never communicate directly -- all coordination flows through the supervisor.

Strengths: Simple to implement and easy to trace. You can follow the message flow linearly. Works well for supervisor and pipeline topologies.

Weaknesses: The sender must know the receiver's identity and interface. Adding a new agent means modifying the sender's code to include it. If Agent B is unavailable, Agent A blocks or fails -- there is no built-in buffering.

Pattern 2: Shared State (The Blackboard Pattern)

The blackboard pattern comes from classical AI research. Instead of sending messages to each other, agents read from and write to a shared data structure -- the blackboard. Each agent monitors the blackboard for changes relevant to its expertise, contributes when it can, and steps back when it has nothing to add.

Think of it like a team of specialists gathered around a whiteboard in a conference room. The detective writes clues. The forensic analyst reads the clues, adds lab results. The profiler reads the lab results and clues, adds a suspect profile. Nobody sends messages to anyone directly. They all react to what appears on the board.

blackboard.py

The Blackboard class uses a lock for thread safety and a subscriber mechanism for reactive updates. When the ResearchAgent writes its findings, the AnalysisAgent is automatically notified through its subscription and runs its analysis without any direct communication between the two agents.

Strengths: Agents are fully decoupled -- they only know about the blackboard, not about each other. New agents can be added without modifying existing ones. Agents can work asynchronously and at different speeds. Natural fit for problems where partial results build on each other.

Weaknesses: The blackboard is shared mutable state, which introduces all the classic concurrency risks: race conditions, lost updates, and ordering ambiguity. Debugging is harder because there is no linear message trail -- you have to reconstruct the sequence of reads and writes. The blackboard can also become a bottleneck if many agents write frequently.

Design tip: Use versioned entries and copy-on-read (as shown above) to reduce the risk of one agent corrupting another's view of the data. For larger systems, consider partitioning the blackboard into namespaced sections so agents only see the keys relevant to their domain.

Pattern 3: Event-Driven Coordination

Event-driven coordination uses a message bus (or event bus) as an intermediary. Agents do not send messages to each other. Instead, they publish events to named topics, and other agents subscribe to the topics they care about. The bus handles routing. This is the publish-subscribe (pub/sub) pattern.

This is where the middleware concept from Module 6, Lesson 3 reappears at a new level. In that lesson, middleware intercepted tool calls within a single agent. Here, message middleware intercepts messages between agents. The same interception principle -- inspect, transform, or block a message as it passes through -- applies at the inter-agent boundary. You can add logging middleware to the bus that records every message, a validation middleware that rejects malformed events, or a rate-limiting middleware that throttles a noisy agent.

message_bus.py

Notice how the PlannerAgent and ResearcherAgent never reference each other. The planner publishes to task.assigned; the researcher subscribes to task.assigned. If you add a third agent that also listens for task assignments, the planner's code does not change. This is the decoupling advantage of pub/sub.

The MessageBus also keeps a complete history, which gives you a full audit trail of every interaction in the system. Combined with the LoggingMiddleware, you get observability without modifying any agent code.

Strengths: Maximum decoupling -- agents know only about topics, not about each other. Adding new agents is purely additive (subscribe to existing topics). The bus provides a natural point for cross-cutting concerns like logging, filtering, and rate limiting. Message history enables replay and debugging.

Weaknesses: Event-driven systems are harder to reason about than sequential message passing. The execution order depends on subscription order and timing, which can be surprising. Debugging requires tracing through event chains rather than following a call stack. You also need to handle the case where no agent subscribes to a topic (the message is silently dropped).

Pattern 4: Communication Protocols

The three patterns above describe mechanisms -- how messages travel. Communication protocols add structure -- what messages look like, what fields they must contain, and how agents negotiate capabilities. A protocol is an agreement between agents about the format and semantics of their communication.

Without a protocol, every pair of agents invents its own message format. Agent A sends {"task": "search", "q": "..."} while Agent B expects {"action": "search", "query": "..."}. This works in small systems where one person writes all the agents, but it breaks down as systems grow or when agents come from different teams or frameworks.

A well-designed protocol defines:

  • Message envelope -- standard fields every message must have (sender, recipient, timestamp, message type, correlation ID for request-response pairs)
  • Message types -- an enumeration of valid message types (request, response, broadcast, error, heartbeat)
  • Payload schemas -- the expected structure of the payload for each message type
  • Conversation patterns -- valid sequences of message types (a request must be followed by a response or an error, never by another request)
protocol.py

The ProtocolMessage enforces a standard envelope with sender, recipient, message type, and correlation IDs for request-response matching. The create_reply method ensures that responses are properly correlated with their originating requests. The ProtocolRouter validates that responses reference valid pending requests, catching protocol violations early.

This structured approach becomes essential when you move to cross-framework or cross-platform agent communication -- which is exactly what the A2A (Agent-to-Agent) protocol addresses in the next lesson.

Choosing the Right Pattern

There is no single best communication pattern. The right choice depends on your system's requirements.

| Concern | Direct Messaging | Blackboard | Event Bus | Protocol | |---------|------------------|------------|-----------|----------| | Coupling | Tight -- sender knows receiver | Loose -- agents know only the board | Loose -- agents know only topics | Medium -- agents know the schema | | Adding agents | Modify sender code | No changes needed | No changes needed | Register with schema | | Debugging | Easy -- follow the call chain | Hard -- reconstruct write order | Medium -- trace event chains | Easy -- structured audit trail | | Ordering | Explicit in code | Ambiguous | Subscription-order dependent | Protocol-defined sequences | | Best for | Supervisor, pipeline | Collaborative analysis | Swarm, reactive systems | Cross-team, cross-platform |

In practice, most production multi-agent systems combine patterns. A supervisor might use direct messaging to delegate tasks to workers while workers use an event bus to broadcast progress updates. A research team might use a blackboard for shared findings with a protocol envelope for message validation. The key is to pick the simplest pattern that meets your coupling and scalability requirements, and add structure only when you need it.

Summary

Agent communication is the mechanism that turns a collection of independent agents into a coordinated system. The four foundational patterns each offer different trade-offs.

  • Direct message passing is the simplest: Agent A sends a structured message to Agent B and receives a response. It maps naturally to supervisor and pipeline topologies but creates tight coupling between agents.
  • Shared state (blackboard) decouples agents by letting them read and write to a common data structure. Agents react to changes without knowing who made them. This pattern excels at collaborative problem-solving but introduces shared mutable state risks.
  • Event-driven coordination (pub/sub) uses a message bus to decouple senders from receivers completely. Agents publish events to topics and subscribe to the topics they care about. This is the most scalable pattern for growing systems but makes execution order harder to reason about.
  • Communication protocols add structure to any of the above mechanisms by defining message envelopes, types, and conversation rules. They are essential for cross-framework interoperability.
  • The middleware interception pattern from Module 6, Lesson 3 applies at the inter-agent level too -- a message bus supports the same logging, validation, and rate-limiting middleware, just applied to messages between agents instead of tool calls within a single agent.

In the next lesson, we move from general communication patterns to a specific, open standard for inter-agent communication: the Agent-to-Agent (A2A) protocol. A2A takes the protocol concepts from this lesson and defines a concrete, industry-backed specification for agents built on different frameworks to discover, authenticate, and collaborate with each other.

Check Your Understanding

Question 1 of 4

In a blackboard architecture, how do agents coordinate their work?