Building Multi-Agent Systems That Work Together
The Problem: Single AI agents are limited. They can only focus on one task at a time, lack specialized knowledge, and struggle with complex, multi-step workflows. We need a way to combine multiple agents into cohesive systems.
The Solution: Agent swarms—coordinated groups of specialized AI agents working together toward common goals. This article covers the architecture, communication patterns, and coordination strategies for building effective multi-agent systems.
// Swarm Coordinator
class SwarmCoordinator {
constructor(config) {
this.agents = new Map();
this.sharedMemory = new Map();
this.taskQueue = [];
this.results = [];
this.config = config;
}
// Register an agent
registerAgent(agent) {
this.agents.set(agent.id, agent);
agent.setCoordinator(this);
}
// Execute task with swarm
async execute(task) {
const context = {
task,
sharedMemory: this.sharedMemory,
results: []
};
// Route task to appropriate agents
const selectedAgents = this.selectAgents(task);
// Execute in parallel or sequence based on task type
if (task.parallel) {
return await this.executeParallel(selectedAgents, context);
} else {
return await this.executeSequence(selectedAgents, context);
}
}
// Select agents for task
selectAgents(task) {
return Array.from(this.agents.values()).filter(agent =>
agent.capabilities.some(cap => task.requiredCapabilities?.includes(cap))
);
}
// Parallel execution
async executeParallel(agents, context) {
const results = await Promise.all(
agents.map(agent => agent.execute(context))
);
return this.aggregateResults(results);
}
// Sequential execution
async executeSequence(agents, context) {
let result = context;
for (const agent of agents) {
result = await agent.execute(result);
this.updateSharedMemory(result);
}
return result;
}
// Aggregate results from multiple agents
aggregateResults(results) {
return {
final: results[results.length - 1],
all: results,
consensus: this.buildConsensus(results)
};
}
// Build consensus from conflicting results
buildConsensus(results) {
// Vote on best result
const votes = results.map(r => ({
result: r,
confidence: r.confidence || 0.5
}));
return votes.sort((a, b) => b.confidence - a.confidence)[0].result;
}
// Update shared memory
updateSharedMemory(data) {
for (const [key, value] of Object.entries(data)) {
this.sharedMemory.set(key, value);
}
}
}
// Base Agent Class
class Agent {
constructor(config) {
this.id = config.id;
this.role = config.role;
this.capabilities = config.capabilities || [];
this.coordinator = null;
this.memory = new Map();
}
setCoordinator(coordinator) {
this.coordinator = coordinator;
}
async execute(context) {
throw new Error('Execute must be implemented by subclass');
}
// Communicate with other agents
async sendMessage(targetAgent, message) {
if (!this.coordinator) {
throw new Error('Agent has no coordinator');
}
const agent = this.coordinator.agents.get(targetAgent);
if (!agent) {
throw new Error(`Agent ${targetAgent} not found`);
}
return await agent.receiveMessage(this.id, message);
}
async receiveMessage(from, message) {
this.memory.set(Date.now(), { from, message });
return await this.processMessage(message);
}
async processMessage(message) {
// Override in subclass
return { received: true };
}
// Access shared memory
getShared(key) {
return this.coordinator?.sharedMemory.get(key);
}
setShared(key, value) {
this.coordinator?.updateSharedMemory({ [key]: value });
}
}
// Research Agent
class ResearchAgent extends Agent {
constructor(config) {
super({
...config,
id: 'researcher',
role: 'researcher',
capabilities: ['web_search', 'data_analysis', 'fact_checking']
});
}
async execute(context) {
const { task } = context;
// Gather information
const research = await this.performResearch(task.query);
// Store in shared memory
this.setShared('research_data', research);
return {
type: 'research',
data: research,
confidence: this.calculateConfidence(research)
};
}
async performResearch(query) {
// Implement research logic
return { query, results: [], sources: [] };
}
calculateConfidence(research) {
// Calculate based on source quality, result count, etc.
return 0.7;
}
}
// Writer Agent
class WriterAgent extends Agent {
constructor(config) {
super({
...config,
id: 'writer',
role: 'writer',
capabilities: ['content_generation', 'copywriting', 'editing']
});
}
async execute(context) {
const research = this.getShared('research_data');
const { task } = context;
if (!research) {
throw new Error('No research data available');
}
// Generate content based on research
const content = await this.generateContent(task, research);
// Request critique from critic agent
const critique = await this.sendMessage('critic', {
type: 'critique_request',
content
});
// Refine based on critique
const refined = await this.refineContent(content, critique);
return {
type: 'content',
content: refined,
critique: critique,
confidence: this.calculateConfidence(refined)
};
}
async generateContent(task, research) {
// Implement content generation
return '';
}
async refineContent(content, critique) {
// Implement refinement logic
return content;
}
calculateConfidence(content) {
return 0.8;
}
}
// Critic Agent
class CriticAgent extends Agent {
constructor(config) {
super({
...config,
id: 'critic',
role: 'critic',
capabilities: ['content_review', 'quality_assessment', 'feedback']
});
}
async processMessage(message) {
if (message.type === 'critique_request') {
return await this.critique(message.content);
}
return { received: true };
}
async critique(content) {
// Implement critique logic
return {
score: 0.8,
feedback: [],
suggestions: []
};
}
}
// Broadcast to all agents
async function broadcast(swarm, message) {
const agents = Array.from(swarm.agents.values());
return await Promise.all(
agents.map(agent => agent.receiveMessage('system', message))
);
}
// Usage
await broadcast(coordinator, {
type: 'task_update',
status: 'in_progress',
progress: 0.5
});
// Direct agent-to-agent communication
const writer = coordinator.agents.get('writer');
await writer.sendMessage('critic', {
type: 'critique_request',
content: 'Draft content here'
});
// Orchestrate complex workflow
async function orchestrateContentCreation(coordinator, topic) {
// Phase 1: Research
const researchResult = await coordinator.execute({
type: 'research',
query: topic,
parallel: false,
requiredCapabilities: ['web_search']
});
// Phase 2: Content Generation
const contentResult = await coordinator.execute({
type: 'write',
topic: topic,
research: researchResult,
parallel: false,
requiredCapabilities: ['content_generation']
});
// Phase 3: Review
const reviewResult = await coordinator.execute({
type: 'review',
content: contentResult,
parallel: true,
requiredCapabilities: ['content_review', 'seo_analysis']
});
// Phase 4: Final Polish
const finalResult = await coordinator.execute({
type: 'edit',
content: contentResult,
feedback: reviewResult,
parallel: false,
requiredCapabilities: ['editing']
});
return finalResult;
}
Agents organized in layers, with higher-level agents managing lower-level ones.
All agents communicate directly with each other, coordinated through shared memory.
Mix of hierarchical and flat—teams of agents with team leads.
// Content production swarm
const contentSwarm = new SwarmCoordinator({
name: 'ContentProduction'
});
// Register agents
contentSwarm.registerAgent(new ResearchAgent());
contentSwarm.registerAgent(new WriterAgent());
contentSwarm.registerAgent(new CriticAgent());
contentSwarm.registerAgent(new EditorAgent());
contentSwarm.registerAgent(new SEOAgent());
// Execute content production
async function produceArticle(topic) {
return await orchestrateContentCreation(contentSwarm, topic);
}
// Usage
const article = await produceArticle('The Future of AI');
console.log(article);
After implementing agent swarms in production:
Problem: Communication between agents adds latency.
Solution: Batch messages, use shared memory, minimize synchronous communication.
Problem: Agents may produce conflicting outputs.
Solution: Implement voting systems, confidence scoring, conflict resolution protocols.
Problem: Hard to trace issues across multiple agents.
Solution: Comprehensive logging, request tracing, visualization tools.
Agent swarms unlock capabilities impossible for single agents. By combining specialized agents with effective coordination, we can build AI systems that are more capable, more reliable, and more scalable.
The key is specialization and communication. Each agent should be an expert in their domain, and the swarm should provide robust mechanisms for them to work together.
The future of AI isn't bigger models—it's smarter coordination.