diff --git a/DOCS/DESIGN.md b/DOCS/DESIGN.md new file mode 100644 index 00000000..be92089a --- /dev/null +++ b/DOCS/DESIGN.md @@ -0,0 +1,146 @@ +# Swarm Architecture Design Document + +## Overview + +The goal of the Swarm Architecture is to provide a flexible and scalable system to build swarm intelligence models that can solve complex problems. This document details the proposed design to create a plug-and-play system, which makes it easy to create custom swarms, and provides pre-configured swarms with multi-modal agents. + +## Design Principles + +- **Modularity**: The system will be built in a modular fashion, allowing various components to be easily swapped or upgraded. +- **Interoperability**: Different swarm classes and components should be able to work together seamlessly. +- **Scalability**: The design should support the growth of the system by adding more components or swarms. +- **Ease of Use**: Users should be able to easily create their own swarms or use pre-configured ones with minimal configuration. + +## Design Components + +### AbstractSwarm + +The AbstractSwarm is an abstract base class which defines the basic structure of a swarm and the methods that need to be implemented. Any new swarm should inherit from this class and implement the required methods. + +### Swarm Classes + +Various Swarm classes can be implemented inheriting from the AbstractSwarm class. Each swarm class should implement the required methods for initializing the components, worker nodes, and boss node, and running the swarm. + +Pre-configured swarm classes with multi-modal agents can be provided for ease of use. These classes come with a default configuration of tools and agents, which can be used out of the box. + +### Tools and Agents + +Tools and agents are the components that provide the actual functionality to the swarms. They can be language models, AI assistants, vector stores, or any other components that can help in problem solving. + +To make the system plug-and-play, a standard interface should be defined for these components. Any new tool or agent should implement this interface, so that it can be easily plugged into the system. + +## Usage + +Users can either use pre-configured swarms or create their own custom swarms. + +To use a pre-configured swarm, they can simply instantiate the corresponding swarm class and call the run method with the required objective. + +To create a custom swarm, they need to: + +1. Define a new swarm class inheriting from AbstractSwarm. +2. Implement the required methods for the new swarm class. +3. Instantiate the swarm class and call the run method. + +### Example + +```python +# Using pre-configured swarm +swarm = PreConfiguredSwarm(openai_api_key) +swarm.run_swarms(objective) + +# Creating custom swarm +class CustomSwarm(AbstractSwarm): + # Implement required methods + +swarm = CustomSwarm(openai_api_key) +swarm.run_swarms(objective) +``` + +## Conclusion + +This Swarm Architecture design provides a scalable and flexible system for building swarm intelligence models. The plug-and-play design allows users to easily use pre-configured swarms or create their own custom swarms. + + +# Swarming Architectures +Sure, below are five different swarm architectures with their base requirements and an abstract class that processes these components: + +1. **Hierarchical Swarm**: This architecture is characterized by a boss/worker relationship. The boss node takes high-level decisions and delegates tasks to the worker nodes. The worker nodes perform tasks and report back to the boss node. + - Requirements: Boss node (can be a large language model), worker nodes (can be smaller language models), and a task queue for task management. + +2. **Homogeneous Swarm**: In this architecture, all nodes in the swarm are identical and contribute equally to problem-solving. Each node has the same capabilities. + - Requirements: Homogeneous nodes (can be language models of the same size), communication protocol for nodes to share information. + +3. **Heterogeneous Swarm**: This architecture contains different types of nodes, each with its specific capabilities. This diversity can lead to more robust problem-solving. + - Requirements: Different types of nodes (can be different types and sizes of language models), a communication protocol, and a mechanism to delegate tasks based on node capabilities. + +4. **Competitive Swarm**: In this architecture, nodes compete with each other to find the best solution. The system may use a selection process to choose the best solutions. + - Requirements: Nodes (can be language models), a scoring mechanism to evaluate node performance, a selection mechanism. + +5. **Cooperative Swarm**: In this architecture, nodes work together and share information to find solutions. The focus is on cooperation rather than competition. + - Requirements: Nodes (can be language models), a communication protocol, a consensus mechanism to agree on solutions. + + +6. **Grid-based Swarm**: This architecture positions agents on a grid, where they can only interact with their neighbors. This is useful for simulations, especially in fields like ecology or epidemiology. + - Requirements: Agents (can be language models), a grid structure, and a neighborhood definition (i.e., how to identify neighboring agents). + +7. **Particle Swarm Optimization (PSO) Swarm**: In this architecture, each agent represents a potential solution to an optimization problem. Agents move in the solution space based on their own and their neighbors' past performance. PSO is especially useful for continuous numerical optimization problems. + - Requirements: Agents (each representing a solution), a definition of the solution space, an evaluation function to rate the solutions, a mechanism to adjust agent positions based on performance. + +8. **Ant Colony Optimization (ACO) Swarm**: Inspired by ant behavior, this architecture has agents leave a pheromone trail that other agents follow, reinforcing the best paths. It's useful for problems like the traveling salesperson problem. + - Requirements: Agents (can be language models), a representation of the problem space, a pheromone updating mechanism. + +9. **Genetic Algorithm (GA) Swarm**: In this architecture, agents represent potential solutions to a problem. They can 'breed' to create new solutions and can undergo 'mutations'. GA swarms are good for search and optimization problems. + - Requirements: Agents (each representing a potential solution), a fitness function to evaluate solutions, a crossover mechanism to breed solutions, and a mutation mechanism. + +10. **Stigmergy-based Swarm**: In this architecture, agents communicate indirectly by modifying the environment, and other agents react to such modifications. It's a decentralized method of coordinating tasks. + - Requirements: Agents (can be language models), an environment that agents can modify, a mechanism for agents to perceive environment changes. + +These architectures all have unique features and requirements, but they share the need for agents (often implemented as language models) and a mechanism for agents to communicate or interact, whether it's directly through messages, indirectly through the environment, or implicitly through a shared solution space. Some also require specific data structures, like a grid or problem space, and specific algorithms, like for evaluating solutions or updating agent positions. + + + + + +Here is an abstract class that provides the basic structure to process these components: + +```python +from abc import ABC, abstractmethod + +class AbstractSwarm(ABC): + + def __init__(self, agents, vectorstore, tools): + self.agents = agents + self.vectorstore = vectorstore + self.tools = tools + + @abstractmethod + def initialize(self): + pass + + @abstractmethod + def communicate(self): + pass + + @abstractmethod + def process(self): + pass + + @abstractmethod + def solve(self): + pass +``` + +This abstract class requires four methods to be implemented: + +- `initialize`: This method is used to set up the initial state of the swarm, including setting up nodes and tools. +- `communicate`: This method is responsible for facilitating communication between nodes. +- `process`: This method handles the processing logic, which can be different based on the swarm architecture. +- `solve`: This method is called to start the problem-solving process. + +This abstract class can be inherited by specific swarm architecture classes to implement their specific behavior. + +# 3 Ingredients + +* The Individual Agent Configuration with a vectorstore and tools + +* The Orchestrator, => task assignment, task completion handling, communication layer \ No newline at end of file diff --git a/DOCS/DOCUMENTATION.md b/DOCS/DOCUMENTATION.md index 699483c8..da0db9c3 100644 --- a/DOCS/DOCUMENTATION.md +++ b/DOCS/DOCUMENTATION.md @@ -22,7 +22,7 @@ swarm = Swarms(api_key=api_key) objective = "Please make a web GUI for using HTTP API server..." # Run Swarms -result = swarm.run_swarms(objective) +result = swarm.run(objective) print(result) ``` @@ -37,7 +37,7 @@ def __init__(self, openai_api_key) ## Methods -### run_swarms(objective) +### run(objective) Runs the swarm with the given objective by initializing the worker and boss nodes. @@ -59,7 +59,7 @@ swarm = Swarms(api_key=api_key) objective = "Please make a web GUI for using HTTP API server..." # Run Swarms -result = swarm.run_swarms(objective) +result = swarm.run(objective) print(result) ``` diff --git a/README.md b/README.md index 0eec6337..044c9839 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ The ports you can use are 4500 and 6500. """ # Run Swarms -swarm.run_swarms(objective) +swarm.run(objective) ``` * Or just the worker no `BossNode`: @@ -159,7 +159,7 @@ Here are some agents in the swarm you can use! | Agent | Import Statement | Example Usage | |--------------|----------------------------------------------------|---------------------------------------------------------| | WorkerNode | `from swarms import worker_node` | ```python api_key = "sksdsds" node = worker_node(api_key) objective = "Please make a web GUI for using HTTP API server..." task = node.run(objective) print(task)``` | -| Swarms | `from swarms.swarms import Swarms` | ```python import os from swarms.swarms import Swarms api_key = os.getenv("OPENAI_API_KEY") swarm = Swarms(openai_api_key=api_key) objective = "Please make a web GUI for using HTTP API server..." task = swarm.run_swarms(objective) print(task)``` | +| Swarms | `from swarms.swarms import Swarms` | ```python import os from swarms.swarms import Swarms api_key = os.getenv("OPENAI_API_KEY") swarm = Swarms(openai_api_key=api_key) objective = "Please make a web GUI for using HTTP API server..." task = swarm.run(objective) print(task)``` | --- diff --git a/api/app.py b/api/app.py index c4afcf24..cac23332 100644 --- a/api/app.py +++ b/api/app.py @@ -22,7 +22,7 @@ async def startup(): @app.post("/chat", dependencies=[Depends(RateLimiter(times=2, minutes=1))]) @cache(expire=60) # Cache results for 1 minute -async def run_swarms(swarm_input: SwarmInput): +async def run(swarm_input: SwarmInput): try: results = swarm(swarm_input.api_key, swarm_input.objective) if not results: diff --git a/example.py b/example.py index 1f5e92e4..89b387d5 100644 --- a/example.py +++ b/example.py @@ -1,10 +1,10 @@ import os -from swarms.swarms import Swarms +from swarms.swarms import HierarchicalSwarm api_key = os.getenv("OPENAI_API_KEY") # Initialize Swarms with your API key -swarm = Swarms(openai_api_key=api_key) +swarm = HierarchicalSwarm(openai_api_key=api_key) # Define an objective objective = """ @@ -19,6 +19,6 @@ I want it to have neumorphism-style. Serve it on port 4500. """ # Run Swarms -task = swarm.run_swarms(objective) +task = swarm.run(objective) print(task) \ No newline at end of file diff --git a/misc/swarms.txt b/misc/swarms.txt index 19b9ade0..e818cf3b 100644 --- a/misc/swarms.txt +++ b/misc/swarms.txt @@ -92,7 +92,7 @@ # return BossNode(llm, vectorstore, agent_executor, max_iterations=5) -# def run_swarms(self, objective, run_as=None): +# def run(self, objective, run_as=None): # try: # # Run the swarm with the given objective # worker_tools = self.initialize_tools(OpenAI) @@ -109,7 +109,7 @@ # task = boss_node.create_task(objective) # return boss_node.execute_task(task) # except Exception as e: -# logging.error(f"An error occurred in run_swarms: {e}") +# logging.error(f"An error occurred in run: {e}") # raise @@ -218,7 +218,7 @@ # agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True) # return BossNode(self.openai_api_key, llm, vectorstore, agent_executor, verbose=True, max_iterations=5) -# def run_swarms(self, objective): +# def run(self, objective): # # Run the swarm with the given objective # llm = self.initialize_llm() # worker_tools = self.initialize_tools(llm) diff --git a/playground/analysis/task1.txt b/playground/analysis/task1.txt index 0045efde..224b7b4f 100644 --- a/playground/analysis/task1.txt +++ b/playground/analysis/task1.txt @@ -131,26 +131,26 @@ message='Request to OpenAI API' method=post path=https://api.openai.com/v1/engin api_version=None data='{"input": ["Create the JavaScript code to capture user input and deploy the web GUI on port 4500."], "encoding_format": "base64"}' message='Post details' https://api.openai.com:443 "POST /v1/engines/text-embedding-ada-002/embeddings HTTP/1.1" 200 None message='OpenAI API response' path=https://api.openai.com/v1/engines/text-embedding-ada-002/embeddings processing_ms=40 request_id=d5225adb1208b38e2639a23afcccf29d response_code=200 -An error occurred in run_swarms: Tried to add ids that already exist: {'result_1'} +An error occurred in run: Tried to add ids that already exist: {'result_1'} ╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮ │ /content/swarms/example.py:26 in │ │ │ │ 23 """ │ │ 24 │ │ 25 # Run Swarms │ -│ ❱ 26 task = swarm.run_swarms(objective) │ +│ ❱ 26 task = swarm.run(objective) │ │ 27 │ │ 28 print(task) │ │ 29 │ │ │ -│ /content/swarms/swarms/swarms.py:79 in run_swarms │ +│ /content/swarms/swarms/swarms.py:79 in run │ │ │ │ 76 │ │ │ boss_node = self.initialize_boss_node(vectorstore, worker_node) │ │ 77 │ │ │ │ │ 78 │ │ │ task = boss_node.create_task(objective) │ │ ❱ 79 │ │ │ return boss_node.execute_task(task) │ │ 80 │ │ except Exception as e: │ -│ 81 │ │ │ logging.error(f"An error occurred in run_swarms: {e}") │ +│ 81 │ │ │ logging.error(f"An error occurred in run: {e}") │ │ 82 │ │ │ raise │ │ │ │ /content/swarms/swarms/agents/boss/boss_agent.py:27 in execute_task │ diff --git a/playground/gui_app.py b/playground/gui_app.py index 70de7b80..18d66597 100644 --- a/playground/gui_app.py +++ b/playground/gui_app.py @@ -1,16 +1,16 @@ -from swarms import Swarms +from swarms import HierarchicalSwarm # Retrieve your API key from the environment or replace with your actual key api_key = "sksdsds" -# Initialize Swarms with your API key -swarm = Swarms(openai_api_key=api_key) +# Initialize HierarchicalSwarm with your API key +swarm = HierarchicalSwarm(openai_api_key=api_key) # Define an objective objective = """ Please make a web GUI for using HTTP API server. -The name of it is Swarms. +The name of it is HierarchicalSwarm. You can check the server code at ./main.py. The server is served on localhost:8000. Users should be able to write text input as 'query' and url array as 'files', and check the response. @@ -19,5 +19,5 @@ I want it to have neumorphism-style. Serve it on port 4500. """ -# Run Swarms -swarm.run_swarms(objective) \ No newline at end of file +# Run HierarchicalSwarm +swarm.run(objective) \ No newline at end of file diff --git a/playground/social_app.py b/playground/social_app.py index d3d02984..7e148e62 100644 --- a/playground/social_app.py +++ b/playground/social_app.py @@ -1,10 +1,10 @@ -from ..swarms import Swarms +from ..swarms import HierarchicalSwarm # Retrieve your API key from the environment or replace with your actual key api_key = "sksdsds" -# Initialize Swarms with your API key -swarm = Swarms(openai_api_key=api_key) +# Initialize HierarchicalSwarm with your API key +swarm = HierarchicalSwarm(openai_api_key=api_key) # Define an objective objective = """ @@ -15,5 +15,5 @@ I want it to have neumorphism-style. The ports you can use are 4500 and 6500. """ -# Run Swarms -swarm.run_swarms(objective) \ No newline at end of file +# Run HierarchicalSwarm +swarm.run(objective) \ No newline at end of file diff --git a/playground/swarms_example.py b/playground/swarms_example.py index f3a9c99a..e074cecc 100644 --- a/playground/swarms_example.py +++ b/playground/swarms_example.py @@ -1,14 +1,14 @@ -from swarms import Swarms +from swarms import HierarchicalSwarm import os # Retrieve your API key from the environment or replace with your actual key api_key = "" -# Initialize Swarms with your API key -swarm = Swarms(api_key) +# Initialize HierarchicalSwarm with your API key +swarm = HierarchicalSwarm(api_key) # Define an objective -objective = "Find 20 potential customers for a Swarms based AI Agent automation infrastructure" +objective = "Find 20 potential customers for a HierarchicalSwarm based AI Agent automation infrastructure" -# Run Swarms -swarm.run_swarms(objective) \ No newline at end of file +# Run HierarchicalSwarm +swarm.run(objective) \ No newline at end of file diff --git a/playground/todo_app.py b/playground/todo_app.py index 5162ce33..0f7fc8fd 100644 --- a/playground/todo_app.py +++ b/playground/todo_app.py @@ -1,11 +1,11 @@ -from swarms import Swarms +from swarms import HierarchicalSwarm # Retrieve your API key from the environment or replace with your actual key api_key = "sksdsds" -# Initialize Swarms with your API key -swarm = Swarms(openai_api_key=api_key) +# Initialize HierarchicalSwarm with your API key +swarm = HierarchicalSwarm(openai_api_key=api_key) # Define an objective objective = """ @@ -16,5 +16,5 @@ The ports you can use are 4500 and 6500. """ -# Run Swarms -swarm.run_swarms(objective) \ No newline at end of file +# Run HierarchicalSwarm +swarm.run(objective) \ No newline at end of file diff --git a/swarms/__init__.py b/swarms/__init__.py index 6f6b97c4..900cea32 100644 --- a/swarms/__init__.py +++ b/swarms/__init__.py @@ -1,5 +1,5 @@ # from swarms import Swarms, swarm -from swarms.swarms import Swarms, swarm +from swarms.swarms import HierarchicalSwarm, swarm from swarms.workers import worker_node from swarms.workers.worker_ultra_node import WorkerUltraNode, WorkerUltra from swarms.workers.worker_agent_ultra import worker_ultra_node diff --git a/swarms/agents/__init__.py b/swarms/agents/__init__.py index 9c51ea85..06d8b003 100644 --- a/swarms/agents/__init__.py +++ b/swarms/agents/__init__.py @@ -1,3 +1,11 @@ -"""Agents, workers and bosses""" -# from ..agents.workers import worker_node -# from .workers.worker_ultra_node import WorkerUltraNode \ No newline at end of file +"""Agent Infrastructure, models, memory, utils, tools""" + + +#models +from swarms.agents.models.llm import LLM +from swarms.agents.models.hf import HuggingFaceLLM + + + +# Vectorstore: +faiss \ No newline at end of file diff --git a/swarms/agents/memory/ocean.py b/swarms/agents/memory/ocean.py new file mode 100644 index 00000000..744300bc --- /dev/null +++ b/swarms/agents/memory/ocean.py @@ -0,0 +1,3 @@ +#init ocean +# TODO upload ocean to pip and config it to the abstract class + diff --git a/swarms/hivemind.py b/swarms/hivemind.py index cbe421c4..c0ee1e05 100644 --- a/swarms/hivemind.py +++ b/swarms/hivemind.py @@ -4,7 +4,7 @@ import concurrent.futures import logging -from swarms.swarms import Swarms +from swarms.swarms import HierarchicalSwarm #this needs to change, we need to specify exactly what needs to be imported from swarms.agents.tools.agent_tools import * @@ -17,7 +17,7 @@ class HiveMind: def __init__(self, openai_api_key="", num_swarms=1, max_workers=None): self.openai_api_key = openai_api_key self.num_swarms = num_swarms - self.swarms = [Swarms(openai_api_key) for _ in range(num_swarms)] + self.swarms = [HierarchicalSwarm(openai_api_key) for _ in range(num_swarms)] self.vectorstore = self.initialize_vectorstore() self.max_workers = max_workers if max_workers else min(32, num_swarms) @@ -33,11 +33,11 @@ class HiveMind: def run_swarm(self, swarm, objective): try: - return swarm.run_swarms(objective) + return swarm.run(objective) except Exception as e: - logging.error(f"An error occurred in run_swarms: {e}") + logging.error(f"An error occurred in run: {e}") - def run_swarms(self, objective, timeout=None): + def run(self, objective, timeout=None): with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor: futures = {executor.submit(self.run_swarm, swarm, objective) for swarm in self.swarms} results = [] @@ -49,7 +49,7 @@ class HiveMind: return results def add_swarm(self): - self.swarms.append(Swarms(self.openai_api_key)) + self.swarms.append(HierarchicalSwarm(self.openai_api_key)) def remove_swarm(self, index): try: @@ -69,4 +69,4 @@ class HiveMind: def queue_tasks(self, tasks): for task in tasks: - self.run_swarms(task) + self.run(task) diff --git a/swarms/orchestrate.py b/swarms/orchestrate.py new file mode 100644 index 00000000..bedf1ce5 --- /dev/null +++ b/swarms/orchestrate.py @@ -0,0 +1,31 @@ +from abc import ABC, abstractmethod +import celery +from typing import List, Dict, Any +import numpy as np + +class Orchestrator(ABC): + def __init__(self, agent_list: List[Any], task_queue: celery.Celery, vector_db: np.ndarray): + self.agents = agent_list + self.task_queue = task_queue + self.vector_db = vector_db + self.current_tasks = {} + + @abstractmethod + def assign_task(self, agent_id: int, task: Dict[str, Any]) -> None: + """Assign a task to a specific agent""" + pass + + @abstractmethod + def retrieve_results(self, agent_id: int) -> Any: + """Retrieve results from a specific agent""" + pass + + @abstractmethod + def update_vector_db(self, data: np.ndarray) -> None: + """Update the vector database""" + pass + + @abstractmethod + def get_vector_db(self) -> np.ndarray: + """Retrieve the vector database""" + pass diff --git a/swarms/swarms.py b/swarms/swarms.py index 49bd5966..38698c05 100644 --- a/swarms/swarms.py +++ b/swarms/swarms.py @@ -7,19 +7,20 @@ from swarms.workers.WorkerNode import WorkerNodeInitializer, worker_node from swarms.boss.boss_node import BossNodeInitializer as BossNode from swarms.workers.worker_ultra_node import WorkerUltra -from langchain import LLMMathChain +from swarms.utils.task import Task +from swarms.agents.models.hf import HuggingFaceLLM +# from langchain import LLMMathChain logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') -from swarms.utils.task import Task - # TODO: Pass in abstract LLM class that can utilize Hf or Anthropic models, Move away from OPENAI # TODO: ADD Universal Communication Layer, a ocean vectorstore instance # TODO: BE MORE EXPLICIT ON TOOL USE, TASK DECOMPOSITION AND TASK COMPLETETION AND ALLOCATION # TODO: Add RLHF Data collection, ask user how the swarm is performing -class Swarms: + +class HierarchicalSwarm: def __init__(self, openai_api_key="", use_vectorstore=True, use_async=True, human_in_the_loop=True): #openai_api_key: the openai key. Default is empty if not openai_api_key: @@ -41,7 +42,10 @@ class Swarms: """ try: # Initialize language model - return llm_class(openai_api_key=self.openai_api_key, temperature=temperature) + if self.llm_class == OpenAI: + return llm_class(openai_api_key=self.openai_api_key, temperature=temperature) + else: + return self.llm_class(model_id="gpt-2", temperature=temperature) except Exception as e: logging.error(f"Failed to initialize language model: {e}") @@ -164,7 +168,7 @@ class Swarms: - def run_swarms(self, objective): + def run(self, objective): """ Run the swarm with the given objective @@ -191,7 +195,7 @@ class Swarms: logging.info(f"Completed tasks: {task}") return result except Exception as e: - logging.error(f"An error occurred in run_swarms: {e}") + logging.error(f"An error occurred in run: {e}") return None # usage-# usage- @@ -214,8 +218,8 @@ def swarm(api_key="", objective=""): logging.error("Invalid objective") raise ValueError("A valid objective is required") try: - swarms = Swarms(api_key, use_async=False) # Turn off async - result = swarms.run_swarms(objective) + swarms = HierarchicalSwarm(api_key, use_async=False) # Turn off async + result = swarms.run(objective) if result is None: logging.error("Failed to run swarms") else: diff --git a/tests/swarms.py b/tests/swarms.py index fa3b2ec6..90d12202 100644 --- a/tests/swarms.py +++ b/tests/swarms.py @@ -19,9 +19,9 @@ class TestSwarms(unittest.TestCase): vectorstore = self.swarm.initialize_vectorstore() self.assertIsNotNone(vectorstore) - def test_run_swarms(self): + def test_run(self): objective = "Do a web search for 'OpenAI'" - result = self.swarm.run_swarms(objective) + result = self.swarm.run(objective) self.assertIsNotNone(result)