From e38f48d3cc052b0b34c90ed9c748ec61b36bb930 Mon Sep 17 00:00:00 2001 From: Kye Date: Wed, 6 Mar 2024 17:53:07 -0800 Subject: [PATCH] [BUFG][Majority Voting] --- README.md | 48 ++++++++ majority_voting.py | 42 +++++++ playground/structs/majority_voting.py | 21 ---- .../structs/message_pool.py | 0 .../sequential_workflow_with_agents.py | 0 pyproject.toml | 2 +- swarms/__init__.py | 1 + swarms/models/gemini.py | 3 +- swarms/structs/majority_voting.py | 113 ++++++------------ 9 files changed, 131 insertions(+), 99 deletions(-) create mode 100644 majority_voting.py delete mode 100644 playground/structs/majority_voting.py rename message_pool.py => playground/structs/message_pool.py (100%) rename sequential_workflow_with_agents.py => playground/structs/sequential_workflow_with_agents.py (100%) diff --git a/README.md b/README.md index c53b81fa..1ea16710 100644 --- a/README.md +++ b/README.md @@ -599,6 +599,54 @@ print(inference) ``` +## Majority Voting +Multiple-agents will evaluate an idea based off of an parsing or evaluation function. From papers like "[More agents is all you need](https://arxiv.org/pdf/2402.05120.pdf) + +```python +from swarms import Agent, MajorityVoting, ChromaDB, Anthropic + +# Initialize the llm +llm = Anthropic() + +# Agents +agent1 = Agent( + llm = llm, + system_prompt="You are the leader of the Progressive Party. What is your stance on healthcare?", + agent_name="Progressive Leader", + agent_description="Leader of the Progressive Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +agent2 = Agent( + llm=llm, + agent_name="Conservative Leader", + agent_description="Leader of the Conservative Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +agent3 = Agent( + llm=llm, + agent_name="Libertarian Leader", + agent_description="Leader of the Libertarian Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +# Initialize the majority voting +mv = MajorityVoting( + agents=[agent1, agent2, agent3], + output_parser=llm.majority_voting, + autosave=False, + verbose=True, +) + + +# Start the majority voting +mv.run("What is your stance on healthcare?") +``` + ## Real-World Deployment ### Multi-Agent Swarm for Logistics diff --git a/majority_voting.py b/majority_voting.py new file mode 100644 index 00000000..1ab56476 --- /dev/null +++ b/majority_voting.py @@ -0,0 +1,42 @@ +from swarms import Agent, MajorityVoting, ChromaDB, Anthropic + +# Initialize the llm +llm = Anthropic() + +# Agents +agent1 = Agent( + llm = llm, + system_prompt="You are the leader of the Progressive Party. What is your stance on healthcare?", + agent_name="Progressive Leader", + agent_description="Leader of the Progressive Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +agent2 = Agent( + llm=llm, + agent_name="Conservative Leader", + agent_description="Leader of the Conservative Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +agent3 = Agent( + llm=llm, + agent_name="Libertarian Leader", + agent_description="Leader of the Libertarian Party", + long_term_memory=ChromaDB(), + max_steps=1, +) + +# Initialize the majority voting +mv = MajorityVoting( + agents=[agent1, agent2, agent3], + output_parser=llm.majority_voting, + autosave=False, + verbose=True, +) + + +# Start the majority voting +mv.run("What is your stance on healthcare?") \ No newline at end of file diff --git a/playground/structs/majority_voting.py b/playground/structs/majority_voting.py deleted file mode 100644 index 149fd587..00000000 --- a/playground/structs/majority_voting.py +++ /dev/null @@ -1,21 +0,0 @@ -from swarms import Agent, MajorityVoting, OpenAIChat - -# Initialize the llm -llm = OpenAIChat() - -# Initialize the agents -agent1 = Agent(agent_name="worker-1", llm=llm, max_loops=1) -agent2 = Agent(agent_name="worker-2", llm=llm, max_loops=1) -agent3 = Agent(agent_name="worker3", llm=llm, max_loops=1) - - -# Initialize the majority voting -mv = MajorityVoting( - agents=[agent1, agent2, agent3], - concurrent=True, - multithreaded=True, -) - - -# Start the majority voting -mv.run("What is the capital of France?") diff --git a/message_pool.py b/playground/structs/message_pool.py similarity index 100% rename from message_pool.py rename to playground/structs/message_pool.py diff --git a/sequential_workflow_with_agents.py b/playground/structs/sequential_workflow_with_agents.py similarity index 100% rename from sequential_workflow_with_agents.py rename to playground/structs/sequential_workflow_with_agents.py diff --git a/pyproject.toml b/pyproject.toml index 7c291405..3a932719 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "swarms" -version = "4.2.7" +version = "4.2.8" description = "Swarms - Pytorch" license = "MIT" authors = ["Kye Gomez "] diff --git a/swarms/__init__.py b/swarms/__init__.py index 1177bf6e..66bbbaa4 100644 --- a/swarms/__init__.py +++ b/swarms/__init__.py @@ -17,3 +17,4 @@ from swarms.telemetry import * # noqa: E402, F403 from swarms.tokenizers import * # noqa: E402, F403 from swarms.tools import * # noqa: E402, F403 from swarms.utils import * # noqa: E402, F403 +from swarms.memory import * # noqa: E402, F403 \ No newline at end of file diff --git a/swarms/models/gemini.py b/swarms/models/gemini.py index 249e9c53..cf739418 100644 --- a/swarms/models/gemini.py +++ b/swarms/models/gemini.py @@ -33,7 +33,8 @@ def get_gemini_api_key_env(): key = os.getenv("GEMINI_API_KEY") if key is None: raise ValueError("Please provide a Gemini API key") - return key + return str(key) + # Main class diff --git a/swarms/structs/majority_voting.py b/swarms/structs/majority_voting.py index a2b414ba..513f20be 100644 --- a/swarms/structs/majority_voting.py +++ b/swarms/structs/majority_voting.py @@ -1,15 +1,14 @@ -import asyncio import concurrent.futures import re import sys from collections import Counter -from multiprocessing import Pool -from typing import Any, List +from typing import Any, Callable, List, Optional from loguru import logger from swarms.structs.agent import Agent from swarms.structs.conversation import Conversation +from swarms.utils.file_processing import create_file # Configure loguru logger with advanced settings logger.remove() @@ -96,7 +95,6 @@ def most_frequent( for i in clist: current_frequency = sum(cmp_func(i, item) for item in clist) - print(current_frequency) if current_frequency > counter: counter = current_frequency num = i @@ -104,7 +102,7 @@ def most_frequent( return num, counter -def majority_voting(answers: list): +def majority_voting(answers: List[str]): """ Performs majority voting on a list of answers and returns the most common answer. @@ -115,7 +113,12 @@ def majority_voting(answers: list): The most common answer in the list. """ counter = Counter(answers) - answer = counter.most_common(1)[0][0] + if counter: + + answer = counter.most_common(1)[0][0] + else: + answer = "I don't know" + return answer @@ -124,13 +127,11 @@ class MajorityVoting: Class representing a majority voting system for agents. Args: - agents (List[Agent]): A list of agents to use in the majority voting system. - concurrent (bool, optional): Whether to run the agents concurrently. Defaults to False. - multithreaded (bool, optional): Whether to run the agents using multithreading. Defaults to False. - multiprocess (bool, optional): Whether to run the agents using multiprocessing. Defaults to False. - asynchronous (bool, optional): Whether to run the agents asynchronously. Defaults to False. - output_parser (callable, optional): A callable function to parse the output of the majority voting system. Defaults to None. - + agents (list): A list of agents to be used in the majority voting system. + output_parser (function, optional): A function used to parse the output of the agents. + If not provided, the default majority voting function is used. + autosave (bool, optional): A boolean indicating whether to autosave the conversation to a file. + verbose (bool, optional): A boolean indicating whether to enable verbose logging. Examples: >>> from swarms.structs.agent import Agent >>> from swarms.structs.majority_voting import MajorityVoting @@ -148,21 +149,13 @@ class MajorityVoting: def __init__( self, agents: List[Agent], - concurrent: bool = False, - multithreaded: bool = False, - multiprocess: bool = False, - asynchronous: bool = False, - output_parser: callable = None, + output_parser: Optional[Callable] = majority_voting, autosave: bool = False, verbose: bool = False, *args, **kwargs, ): self.agents = agents - self.concurrent = concurrent - self.multithreaded = multithreaded - self.multiprocess = multiprocess - self.asynchronous = asynchronous self.output_parser = output_parser self.autosave = autosave self.verbose = verbose @@ -173,7 +166,7 @@ class MajorityVoting: # If autosave is enabled, save the conversation to a file if self.autosave: - self.conversation.save() + create_file(str(self.conversation), "majority_voting.json") # Log the agents logger.info("Initializing majority voting system") @@ -198,69 +191,37 @@ class MajorityVoting: """ # Route to each agent - if self.concurrent: - with concurrent.futures.ThreadPoolExecutor() as executor: - # Log the agents - logger.info("Running agents concurrently") - futures = [ - executor.submit(agent.run, task, *args) - for agent in self.agents - ] - results = [ - future.result() - for future in concurrent.futures.as_completed( - futures - ) - ] - elif self.multithreaded: - logger.info("Running agents using multithreading") - with concurrent.futures.ThreadPoolExecutor() as executor: - results = [ - executor.submit(agent.run, task, *args) - for agent in self.agents - ] - results = [future.result() for future in results] - elif self.multiprocess: - logger.info("Running agents using multiprocessing") - with Pool() as pool: - results = pool.starmap( - Agent.run, - [(agent, task, *args) for agent in self.agents], - ) - elif self.asynchronous: - loop = asyncio.get_event_loop() - tasks = [ - loop.run_in_executor(None, agent.run, task, *args) + with concurrent.futures.ThreadPoolExecutor() as executor: + logger.info("Running agents concurrently") + + futures = [ + executor.submit(agent.run, task, *args) for agent in self.agents ] - results = loop.run_until_complete(asyncio.gather(*tasks)) - loop.close() - else: results = [ - agent.run(task, *args) for agent in self.agents + future.result() + for future in concurrent.futures.as_completed(futures) ] # Add responses to conversation and log them for agent, response in zip(self.agents, results): - logger.info(f"[{agent.agent_id}][{response}]") - - response = ( - response if isinstance(response, list) else [response] - ) + response = response if isinstance(response, list) else [response] self.conversation.add(agent.agent_name, response) - logger.info(f"[{agent.agent_id}][{response}]") + logger.info(f"[Agent][Name: {agent.agent_name}][Response: {response}]") # Perform majority voting on the conversation - majority_vote = majority_voting(self.conversation.responses) - - # Log the majority vote - logger.info(f"Majority vote: {majority_vote}") - - # If an output parser is provided, parse the output - if self.output_parser: - majority_vote = self.output_parser( - majority_vote, *args, **kwargs - ) + responses = [ + message["content"] + for message in self.conversation.conversation_history + if message["role"] == "agent" + ] + + # If an output parser is provided, parse the responses + if self.output_parser is not None: + majority_vote = self.output_parser(responses, *args, **kwargs) + else: + majority_vote = majority_voting(responses) + # Return the majority vote return majority_vote