AI applications are increasingly moving from a single agent to multiple agents that work together.
One agent may handle customer questions, another may search internal documentation, and another may perform an action in a business system. Once these agents start communicating with each other, the application needs a reliable way to exchange messages, maintain state, and coordinate work.
This is where an agent mesh can be useful.
A Redis-based agent mesh provides an infrastructure layer through which multiple AI agents can communicate without being tightly coupled to each other. Redis can help with message delivery, shared state, task coordination, and short-lived agent information.
The important idea is that agents should not need to know the internal implementation of every other agent. They can communicate through well-defined messages and routing rules.
What Is an Agent Mesh?
An agent mesh is a communication layer connecting multiple AI agents.
Consider a customer-support application with these agents:
User
|
v
Orchestrator Agent
|
+----> Knowledge Agent
|
+----> Order Agent
|
+----> Billing Agent
|
+----> Notification AgentThe orchestrator does not need to implement every capability itself.
Instead, it determines which agent should handle each task.
For example:
Customer asks about an order
|
v
Orchestrator Agent
|
v
Order Agent
|
v
Order ServiceThe response can then return through the same communication layer.
Redis can act as part of this communication infrastructure.
Why Use Redis for Agent Communication?
AI agents often need communication that is faster and more dynamic than traditional request-response APIs.
Redis is useful for this type of workload because applications can use it for:
- Message queues
- Pub/Sub communication
- Shared state
- Task coordination
- Temporary context
- Event notifications
- Rate limiting
- Agent status
- Session information
The exact Redis feature used should depend on the communication pattern.
For example, Pub/Sub is useful when multiple consumers need to receive an event, while a queue-oriented design is better when a task should be processed by a worker.
A Simple Agent Mesh Architecture
A basic architecture can look like this:
+----------------+
| API / Client |
+-------+--------+
|
v
+-------------------+
| Orchestrator Agent|
+---------+---------+
|
+---------v---------+
| Redis Agent |
| Communication |
+----+----+----+----+
| | |
v v v
Agent Agent Agent
A B CEach agent can have its own responsibility.
For example:
Agent A → Customer Support
Agent B → Order Processing
Agent C → Knowledge Search
Agent D → NotificationThe agents do not need direct connections to every other agent.
This reduces the number of dependencies between services.
Defining Agent Messages
The first step in building an agent mesh is defining the message format.
A message should contain enough information for the receiving agent to understand the request.
For example:
{
"messageId": "msg-1024",
"sourceAgent": "support-agent",
"targetAgent": "order-agent",
"task": "get-order-status",
"conversationId": "conv-501",
"payload": {
"orderId": "ORD-10045"
}
}The message contains several important fields.
The messageId helps identify a particular message.
The sourceAgent identifies the sender.
The targetAgent identifies the intended receiver.
The task describes the requested operation.
The conversationId allows related messages to be associated with the same interaction.
The payload contains task-specific information.
A consistent message contract becomes especially important when the number of agents increases.
Sending Agent Tasks Through Redis
A simplified Node.js example can use Redis to publish an agent message.
const message = {
messageId: crypto.randomUUID(),
sourceAgent: "support-agent",
targetAgent: "order-agent",
task: "get-order-status",
conversationId: "conv-501",
payload: {
orderId: "ORD-10045"
}
};
await redis.publish(
"agent:order",
JSON.stringify(message)
);The support agent does not need to know how the order agent retrieves the order.
It only needs to know the communication contract.
The order agent can subscribe to its communication channel and process incoming messages.
Receiving Messages in an Agent
A receiving agent can subscribe to its designated channel.
For example:
await subscriber.subscribe("agent:order");
await subscriber.on("message", async (channel, rawMessage) => {
const message = JSON.parse(rawMessage);
if (message.targetAgent !== "order-agent") {
return;
}
await processOrderTask(message);
});The processOrderTask function can then perform the actual business operation.
A simplified implementation might look like this:
async function processOrderTask(message) {
if (message.task === "get-order-status") {
const order = await getOrder(message.payload.orderId);
await redis.publish(
"agent:responses",
JSON.stringify({
messageId: crypto.randomUUID(),
sourceAgent: "order-agent",
targetAgent: message.sourceAgent,
conversationId: message.conversationId,
task: "order-status-result",
payload: order
})
);
}
}This creates a simple request-and-response flow between agents.
Pub/Sub Is Not the Same as a Task Queue
One common design mistake is treating every Redis communication pattern as a queue.
Pub/Sub works well for broadcasting events.
For example:
Order Updated
|
+----> Support Agent
+----> Analytics Agent
+----> Notification AgentEach subscriber can receive the event.
However, a task-processing system may require a different pattern.
For example:
Generate Report
|
v
Task Queue
|
+----> Worker AgentThe goal here is to have a worker process the task rather than broadcast it to every subscriber.
The communication mechanism should therefore match the required delivery behavior.
Adding an Orchestrator Agent
A multi-agent system usually benefits from an orchestrator.
The orchestrator determines which agent should handle a task.
For example:
User Request
|
v
Orchestrator
|
+---- Customer question → Support Agent
|
+---- Order question → Order Agent
|
+---- Documentation → Knowledge AgentThe routing decision can be based on application rules, an AI model, or a combination of both.
For predictable operations, deterministic rules are often easier to maintain.
For example:
function selectAgent(task) {
switch (task.type) {
case "order":
return "order-agent";
case "knowledge":
return "knowledge-agent";
case "support":
return "support-agent";
default:
return "support-agent";
}
}An AI model can then be used where the classification requires natural-language understanding.
Sharing Conversation Identity
Agents often need to understand that multiple messages belong to the same user interaction.
A conversationId can provide this connection.
For example:
conversationId = conv-501
Message 1 → Support Agent
Message 2 → Order Agent
Message 3 → Notification Agent
Message 4 → Support AgentEach agent can attach the same conversation identifier to messages related to the interaction.
This makes it easier to trace the flow across the mesh.
It also helps applications separate one user's workflow from another.
Handling Agent Failures
Distributed agent systems must assume that an agent can fail.
For example:
Orchestrator
|
v
Order Agent
X
FailedThe orchestrator should not wait indefinitely.
A production design should consider:
- Timeouts
- Retry policies
- Maximum retry counts
- Failure messages
- Dead-letter handling
- Agent health status
- Correlation IDs
- Logging and tracing
A retry should also be designed carefully.
If an operation creates an external side effect, blindly retrying it can create duplicate actions.
For example, retrying a read operation is usually easier than retrying a payment operation.
Making Agent Tasks Idempotent
An agent may receive the same message more than once depending on the delivery architecture.
The application should therefore consider idempotency.
For example:
messageId = msg-1024Before processing the message, the agent can check whether that message has already been handled.
A simplified approach could be:
const processed = await redis.get(
`processed:${message.messageId}`
);
if (processed) {
return;
}
await processTask(message);
await redis.set(
`processed:${message.messageId}`,
"1",
{ EX: 3600 }
);The expiration prevents processed-message records from remaining indefinitely.
The exact retention period should depend on the application's retry and processing model.
Controlling Agent Access
Not every agent should be allowed to communicate with every other agent.
For example:
Support Agent
|
+----> Order Agent
|
+----> Knowledge Agent
Billing Agent
|
+----> Payment ServiceThe application should define which communication paths are allowed.
This prevents accidental coupling and reduces the impact of a compromised or incorrectly configured agent.
Message validation should also be performed by the receiving agent.
Never assume that because a message arrived on a Redis channel, its contents are automatically trustworthy.
Monitoring an Agent Mesh
As the number of agents grows, debugging becomes more difficult.
A request might travel through several agents:
User
|
v
Orchestrator
|
v
Knowledge Agent
|
v
Tool Agent
|
v
DatabaseWithout tracing information, finding a slow or failed step can become difficult.
Useful fields include:
messageId
conversationId
sourceAgent
targetAgent
task
createdAt
completedAt
statusLogging these identifiers consistently allows developers to reconstruct the workflow.
Metrics can also track:
- Messages processed
- Failed tasks
- Retry counts
- Processing duration
- Queue depth
- Agent availability
- Timeout frequency
Common Mistakes
Creating Direct Connections Between Every Agent
If every agent communicates directly with every other agent, the architecture becomes difficult to maintain.
A communication layer provides a cleaner boundary.
Using One Redis Channel for Everything
A single communication channel can become difficult to manage.
Use clear naming and routing conventions.
For example:
agent:order
agent:knowledge
agent:support
agent:notificationsSending Large Agent Context Through Messages
Do not place an entire conversation history into every message.
Large context increases network traffic and processing requirements.
Store suitable shared state separately and pass references when appropriate.
Ignoring Duplicate Messages
Distributed systems can encounter retries and duplicate delivery.
Message handling should account for this possibility.
Giving Every Agent Full Access
Agents should only have access to the communication paths and resources they actually require.
Best Practices
- Define a consistent message contract before connecting multiple agents.
- Give every message a unique message ID.
- Use a conversation or correlation ID to connect related operations.
- Keep agent responsibilities clearly separated.
- Use Pub/Sub for broadcast-style events and queue-oriented mechanisms for task processing.
- Make important agent operations idempotent.
- Set reasonable timeouts and retry limits.
- Validate every incoming message.
- Avoid sending unnecessarily large context between agents.
- Monitor message latency, failures, retries, and agent health.
- Restrict which agents can communicate with each other.
- Keep business logic inside the appropriate agent rather than inside the communication layer.
Advantages and Disadvantages
| Area | Advantages | Disadvantages |
|---|---|---|
| Agent communication | Reduces direct dependencies | Adds another infrastructure component |
| Shared state | Agents can coordinate through shared data | Poorly designed state can create coupling |
| Scaling | Agents can scale independently | Distributed scaling is more complex |
| Fault handling | Retries and routing can be centralized | Duplicate processing must be handled |
| Development | Agents can remain focused on specific tasks | Message contracts require careful design |
| Observability | Central communication provides useful tracing points | Debugging still requires distributed tracing |
When an Agent Mesh Makes Sense
An agent mesh is useful when an application has multiple specialized agents that need to collaborate.
It may be unnecessary for a small application where one agent handles the entire workflow.
For example:
Simple Application
User → Single Agent → Databasedoes not necessarily need an agent mesh.
A more complex system may benefit from:
User
|
v
Orchestrator
|
+----> Support Agent
+----> Order Agent
+----> Knowledge Agent
+----> Notification AgentThe architecture should therefore grow with the application's requirements rather than introducing distributed infrastructure too early.
Summary
Redis can provide useful building blocks for connecting multiple AI agents into a coordinated system.
An agent mesh separates agent responsibilities from agent communication. The orchestrator can route tasks, specialized agents can perform focused operations, and Redis can provide communication and shared infrastructure between them.
A reliable design requires more than simply publishing messages. Message contracts, correlation IDs, retries, idempotency, access control, stable routing, and monitoring should all be considered as the system grows.
The most important design principle is to keep agents loosely coupled. Each agent should know what task it is responsible for and how to communicate with the rest of the system without needing to understand every internal implementation detail.


Join the conversation! Your thoughts help the community grow.