This project implements a modular multi-agent system in Rust. It demonstrates how agents can communicate, interact, and execute behaviors in a simulated environment. The system is designed to be extensible, allowing developers to add new agent types, behaviors, and simulation logic with minimal changes to the core architecture.
Key features include:
- Message-passing communication: Agents exchange messages via a centralized message queue.
- Tick-based simulation: The environment processes agent actions and messages in discrete time steps.
- Extensible architecture: Add new agent types and behaviors without modifying existing code.
- Error handling: Built with robust error handling using the
anyhow
crate. - Scalable design: Modular components allow for easy testing, debugging, and extension.
- Features
- Project Structure
- Getting Started
- Adding New Agents
- Example Output
- Configuration
- Testing
- Contributing
- License
- Agent Types: Multiple agent types (
BasicAgent
,LearningAgent
) with distinct behaviors. - Message Queue: Centralized message routing for inter-agent communication.
- Simulation Loop: Tick-based execution loop for processing agent actions and messages.
- Extensibility: Easily add new agent behaviors or modify the environment.
- Error Handling: Graceful error reporting using
anyhow
. - Serialization Support: Optional support for saving/loading agent states (via Serde).
The system is designed with a modular architecture that separates concerns and promotes extensibility. The main components are:
- Environment: The core of the simulation, responsible for managing agents, processing messages, and executing ticks.
- Agents: Autonomous entities that can communicate, make decisions, and execute behaviors.
- Behaviors: The logic that defines how an agent acts and reacts to messages.
- Message Queue: A centralized queue for inter-agent communication.
- TUI: A terminal user interface for visualizing the simulation.
Here is a diagram of the architecture:
graph TD;
A[Environment] -->|Manages| B(Agents);
B -->|Executes| C(Behaviors);
C -->|Sends| D{Message Queue};
D -->|Delivers| B;
A -->|Updates| E[TUI];
The project is organized into modular components for clarity and maintainability:
ai-agents/
├── Cargo.toml # Project metadata and dependencies
├── README.md # This documentation
├── config.json # Configuration file for agents and providers
└── src/
├── main.rs # Entry point for the application
├── agents/ # Agent implementations
│ ├── mod.rs # Module declaration for agents
│ ├── agent.rs # Base agent implementation
│ ├── basic_agent.rs # Basic agent behavior
│ ├── learning_agent.rs # Learning agent behavior
│ ├── researcher_agent.rs # Researcher agent behavior
│ └── writer_agent.rs # Writer agent behavior
├── behaviors/ # Behavior traits and implementations
│ ├── mod.rs # Module declaration for behaviors
│ └── behavior_trait.rs # Core behavior trait
├── tools/ # Tools for agents
│ ├── mod.rs # Module declaration for tools
│ └── web_search.rs # Web search tool
├── environment.rs # Environment management and simulation loop
├── message.rs # Message struct and utilities
└── config.rs # Configuration system
- Rust: Ensure you have Rust installed. You can install it from rust-lang.org.
- Cargo: The Rust package manager (comes bundled with Rust).
-
Clone the repository:
git clone https://github.com/your-repo/ai-agents.git cd ai-agents
-
Build the project:
cargo build
Run the simulation with default settings:
cargo run
You can also specify the number of ticks for the simulation:
cargo run -- <number_of_ticks>
For example:
cargo run -- 10
To add a new agent type:
- Create a new file in
src/agents/
(e.g.,advanced_agent.rs
). - Implement the
AgentBehavior
trait for your new agent. - Register the new agent type in
src/agents/mod.rs
:pub mod advanced_agent;
- Add a new variant to the
AgentType
enum insrc/agents/agent.rs
:pub enum AgentType { Basic, Learning, Advanced, }
- Update the
Agent::new()
constructor to handle the new type:match agent_type { AgentType::Advanced => Box::new(advanced_agent::AdvancedAgent::default()), }
When running the simulation, you might see output like this:
[LearningAgent] Learning: Hello from BasicAgent #0
[BasicAgent] Received: Learned: Hello from BasicAgent #0
[LearningAgent] Learning: Hello from BasicAgent #3
[BasicAgent] Received: Learned: Hello from BasicAgent #3
Each line represents an agent receiving or processing a message.
The system supports runtime configuration via src/config.rs
. You can customize parameters such as:
message_limit
: Maximum number of messages processed per tick.learning_capacity
: Maximum knowledge size for learning agents.
To use custom configurations, pass a Config
instance when creating the environment:
let config = Config { message_limit: 50, learning_capacity: 500 };
let mut env = Environment::with_config(config);
The project includes tests for critical components. Run all tests with:
cargo test
To add new tests:
- Create a new file in
tests/
(e.g.,test_agents.rs
). - Write test cases using Rust's built-in testing framework.
We welcome contributions! Here are some ways you can help:
- Bug Reports: Open an issue if you find a bug.
- Feature Requests: Suggest new features or improvements.
- Code Contributions: Fork the repository, make changes, and submit a pull request.
- Documentation: Improve the README or add comments to the code.
Before contributing, please review the Code of Conduct.
This project is licensed under the MIT License. See the LICENSE file for details.
- Inspired by multi-agent systems in artificial intelligence research.
- Built with Rust's robust concurrency and safety features.