Multi-Agent Architecture
AuroraSOC employs 16 specialized AI agents organized in a hub-and-spoke topology. This page explains the architectural decisions behind this design and how agents collaborate.
Why Multiple Specialized Agents?
A single general-purpose agent struggles with the breadth of security operations. Consider:
- A malware analyst needs deep knowledge of reverse engineering, YARA rules, and sandbox behavior
- A compliance analyst needs knowledge of NIST, ISO 27001, HIPAA, PCI-DSS frameworks
- A CPS security specialist needs understanding of industrial protocols (Modbus, DNP3, OPC UA)
No single LLM prompt can effectively cover all these domains. Specialization allows:
- Focused system prompts — Each agent has a tailored persona with domain expertise
- Relevant tool sets — Each agent only sees tools relevant to its domain
- Optimized memory — Memory presets tuned per agent type
- Independent scaling — Scale hot agents without scaling cold ones
The Hub-and-Spoke Topology
The Orchestrator
The Orchestrator is the only agent that can directly communicate with all other agents. It:
- Receives tasks from users or the event pipeline
- Analyzes the task to determine which specialists are needed
- Dispatches work using HandoffTools (one per specialist agent)
- Aggregates results from multiple specialists
- Synthesizes a final response
The Orchestrator does NOT do the actual security analysis — it's a coordinator.
HandoffTools
Each specialist agent is exposed to the Orchestrator as a HandoffTool:
# From aurorasoc/agents/orchestrator/server.py
handoff_tools = []
for agent_type in AgentType:
if agent_type != AgentType.ORCHESTRATOR:
tool = HandoffTool(
agent=agent_type.value,
description=f"Delegate to {agent_type.value} specialist"
)
handoff_tools.append(tool)
This means the Orchestrator's LLM sees tools like:
handoff_security_analyst— "Delegate to security_analyst specialist"handoff_threat_hunter— "Delegate to threat_hunter specialist"handoff_malware_analyst— "Delegate to malware_analyst specialist"- ... (15 total)
Agent Communication: A2A Protocol
Agents communicate over HTTP using the Agent-to-Agent (A2A) protocol:
Why A2A over Direct Function Calls?
| Approach | Pros | Cons |
|---|---|---|
| Direct function calls | Fast, simple | Tight coupling, single process, no scaling |
| Message queue | Decoupled, scalable | Complex, async, harder to debug |
| A2A Protocol | Decoupled yet synchronous, standard protocol, independently deployable | HTTP overhead (minimal) |
A2A was chosen because:
- Each agent runs as an independent HTTP service (separate container)
- Agents can be deployed on different machines for scaling
- The protocol is standardized — any A2A-compatible agent can join
- Health checks and circuit breakers work naturally with HTTP
Parallel Dispatch
For complex investigations, the Orchestrator dispatches to multiple agents simultaneously:
The dispatch_parallel() function in the dispatch module sends requests concurrently using asyncio.gather(), dramatically reducing investigation time.
Agent Factory Pattern
All agents are created by the AuroraAgentFactory:
Every agent receives:
- A specialized system prompt from
prompts.py - ThinkTool as the first tool (forced at step 1 for reasoning)
- Domain-specific MCP tools relevant to its role
- TieredAgentMemory with a preset matching its memory needs
Why a single factory instead of each agent constructing itself? Because:
- Consistency — All agents follow the same construction pattern
- Configuration — Central place to modify agent creation
- Testing — Easy to mock factory for unit tests
- Inventory — Single source of truth for all agent types