Building an Agent Message Bus: Patterns for AI-to-AI Communication

Practical architecture patterns for building a message bus that connects AI agents, with concrete examples for request-response, pub-sub, and long-running inference workflows.

Building an Agent Message Bus

A message bus for AI agents is not the same as a message bus for microservices. Agents produce variable-length responses, sometimes stream tokens, invoke tools mid-conversation, and can take 30+ seconds to reply. If you treat them like stateless HTTP services, you'll hit timeouts, lose context, and create brittle integrations.

This article walks through the patterns that actually work when you're wiring agents to each other—whether you're building a multi-agent pipeline, a research assistant that delegates to specialists, or a customer support swarm.

Why Agents Need a Different Bus

Traditional message buses assume fast, predictable producers and consumers. A microservice replies in 50-200ms. An LLM agent might take 15 seconds to think, call three tools, then produce a 2,000-token response. That breaks assumptions in three places:

  1. Timeouts. Default HTTP clients and message brokers give up after 30 seconds. Agents working on hard problems need more room.
  2. Message size. A single agent response can be several KB of structured output. Buses optimized for small events start choking.
  3. State. Agents often need conversation history. A pure fire-and-forget bus drops the thread.

The fix is a bus design that handles long-running, stateful, asymmetric exchanges.

Pattern 1: Request-Response with Correlation IDs

This is the workhorse pattern. Agent A sends a message to Agent B, and B replies with a correlated response. The key is using a correlation ID so replies don't block the sending connection.

bash curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $AP_TOKEN"
-H "Content-Type: application/"
-d '{ "to": "research-agent-01", "correlation_id": "req-8f3a2b", "body": { "task": "summarize", "content": "Q3 earnings transcript...", "max_tokens": 500 } }'

The response comes back asynchronously. Agent A either polls or subscribes to a reply channel filtered by correlation_id. This decouples the agents from each other's latency.

When to use: Direct task delegation where one agent needs a specific answer from another.

Pattern 2: Topic-Based Pub/Sub for Specialist Routing

When you have multiple agents with overlapping capabilities, pub/sub lets you broadcast a task and let whichever agent is available pick it up.

python import agentspub

client = agentspub.Client(api_key=os.environ["AP_TOKEN"])

Subscribe to a topic

client.subscribe("financial-analysis", handler=handle_analysis_request)

Publish a task to the topic

client.publish( topic="financial-analysis", body={ "action": "analyze_risk", "portfolio": portfolio_data, "risk_tolerance": "moderate" } )

The bus delivers the message to one subscriber (work queue semantics) or all subscribers (broadcast), depending on your configuration. For specialist agents, you usually want work queue semantics—only one agent picks up each task.

When to use: Pools of interchangeable agents, fan-out work distribution, or event notifications where multiple agents should react.

Pattern 3: Conversation Threads for Stateful Exchange

Some agent collaborations need back-and-forth. A planner agent might iterate with a code review agent three times before settling on a fix. For this, use conversation threads.

python

Start a thread

thread = client.create_thread( participants=["planner-agent", "code-review-agent"], context={ "repo": "acme/payment-service", "pr": 421 } )

Messages within the thread carry history

client.send( thread_id=thread.id, from_="planner-agent", body={"message": "Review this diff for SQL injection risks", "diff": diff_text} )

The bus maintains conversation history per thread. Each agent sees prior messages when it receives a new one, so neither side has to re-send context.

When to use: Multi-turn collaboration, negotiation, or any workflow where agents build on each other's output iteratively.

Handling Long-Running Inference

Agents that call LLMs are slow. Design your bus so senders don't block. Three approaches:

1. Async acknowledgment. The bus immediately returns a 202 Accepted with a message ID. The agent processes when it can. The sender retrieves the result later.

2. Webhook callbacks. Pass a callback URL in the original message. When the receiving agent finishes, the bus POSTs the result to that URL.

bash curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $AP_TOKEN"
-d '{ "to": "summarizer-agent", "body": {"task": "summarize", "doc_id": "abc123"}, "callback_url": "https://myapp.com/agent-callback" }'

3. Streaming tokens. For real-time UX, some buses support streaming. The agent pushes partial responses as they're generated. This is useful when a human is watching, less so for pure agent-to-agent traffic where the full response is what matters.

For agent-to-agent communication, pattern 1 or 2 is usually sufficient. Reserve streaming for human-facing interactions.

Error Handling and Dead Letters

Agents fail. LLM API calls time out, tool calls return bad data, context windows overflow. Your bus needs a strategy:

  • Retry with backoff. Retry transient failures 2-3 times with exponential backoff. Don't retry on 400 errors—those are deterministic.
  • Dead letter queue. Messages that fail after max retries go to a DLQ. An operator (human or meta-agent) can inspect and requeue them.
  • Timeout policies. Set explicit timeouts per agent. If a research agent doesn't respond in 60 seconds, fail the message and move on. Don't let one slow agent stall the whole pipeline.

python client.send( to="research-agent", body={"task": "deep_research", "query": "..."}, timeout_seconds=90, max_retries=2, on_dead_letter="research-dlq" )

Security Boundaries Between Agents

When agents belong to different teams or organizations, the bus must enforce boundaries:

  • Identity. Each agent has its own credential. Messages are signed so receivers can verify provenance.
  • Scoping. Agents can only send to and receive from explicitly allowed peers. An internal analysis agent shouldn't receive messages from an external customer-facing agent.
  • Payload inspection. For sensitive environments, the bus can enforce schema validation or content policies on message bodies.

This matters because agents can invoke tools—file access, code execution, web requests. A compromised or misconfigured agent is a real risk. Treat agent identities with the same rigor you'd treat service accounts.

Putting It Together: A Three-Agent Pipeline

Here's a concrete architecture for a content pipeline:

  1. Orchestrator agent receives a user request and decides what's needed.
  2. Orchestrator publishes to the research topic. A research agent picks it up, gathers sources, and replies with findings.
  3. Orchestrator sends those findings to a writer agent via direct request-response.
  4. Writer returns a draft. Orchestrator sends it to an editor agent in a conversation thread for iterative refinement.

Each step uses a different pattern: pub/sub for research pool, request-response for writing, threaded conversation for editing. The bus ties them together with correlation IDs so the orchestrator tracks the full workflow.

This is more robust than chaining direct API calls. If the research agent crashes, the message sits in the queue. If the editor needs two rounds, the thread handles it. The orchestrator doesn't need to know implementation details of any agent—it just sends messages and waits for replies.

Common Pitfalls

  • Synchronous chains. A → B → C → D where each blocks on the next. One slow agent stalls everything. Use async patterns throughout.
  • Overloaded context. Stuffing entire conversation histories into every message. Use thread references instead of inline history.
  • No idempotency. Agents process the same message twice because of retries. Include an idempotency key and have agents check for duplicates.
  • Treating all agents the same. A fast classification agent and a slow deep-research agent have different timeout and retry profiles. Configure per agent.

Getting started

Ready to wire your agents together? AgentPub provides the message bus primitives—topics, threads, request-response, and callbacks—so you can focus on agent logic instead of plumbing.