diff --git a/docker/Dockerfile b/docker/Dockerfile index f9b2a7b92..4c3b38c3b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.11-slim WORKDIR /app COPY . . -RUN pip install flask praisonai==2.1.4 gunicorn markdown +RUN pip install flask praisonai==2.1.5 gunicorn markdown EXPOSE 8080 CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"] diff --git a/docker/Dockerfile.chat b/docker/Dockerfile.chat index f6cd75898..e4f020605 100644 --- a/docker/Dockerfile.chat +++ b/docker/Dockerfile.chat @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.1.4" \ + "praisonai==2.1.5" \ "praisonai[chat]" \ "embedchain[github,youtube]" diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index f3b5840af..e10a3853e 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.1.4" \ + "praisonai==2.1.5" \ "praisonai[ui]" \ "praisonai[chat]" \ "praisonai[realtime]" \ diff --git a/docker/Dockerfile.ui b/docker/Dockerfile.ui index b233ba396..ad5ed48b7 100644 --- a/docker/Dockerfile.ui +++ b/docker/Dockerfile.ui @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.1.4" \ + "praisonai==2.1.5" \ "praisonai[ui]" \ "praisonai[crewai]" diff --git a/docs/api/praisonai/deploy.html b/docs/api/praisonai/deploy.html index 0e113b469..2d5e7d1e7 100644 --- a/docs/api/praisonai/deploy.html +++ b/docs/api/praisonai/deploy.html @@ -110,7 +110,7 @@

Raises

file.write("FROM python:3.11-slim\n") file.write("WORKDIR /app\n") file.write("COPY . .\n") - file.write("RUN pip install flask praisonai==2.1.4 gunicorn markdown\n") + file.write("RUN pip install flask praisonai==2.1.5 gunicorn markdown\n") file.write("EXPOSE 8080\n") file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n') diff --git a/docs/deploy/multi-agents-deploy.mdx b/docs/deploy/multi-agents-deploy.mdx new file mode 100644 index 000000000..deb386a11 --- /dev/null +++ b/docs/deploy/multi-agents-deploy.mdx @@ -0,0 +1,210 @@ +--- +title: "Deploying Multi-Agent Systems as APIs" +sidebarTitle: "Multi-Agent Deployment" +description: "Learn how to deploy PraisonAI multi-agent systems as RESTful APIs for production environments" +icon: "network-wired" +--- + +# Deploying Multi-Agent Systems as APIs + +PraisonAI allows you to deploy sophisticated multi-agent systems as RESTful APIs, enabling seamless integration with various applications and services. This guide covers different approaches to deploying multi-agent systems. + +## Quick Start + + + + Make sure you have the required packages installed: + ```bash + pip install "praisonaiagents[api]>=0.0.81" + ``` + + + ```bash + export OPENAI_API_KEY="your_api_key" + ``` + + + Create a file named `multi-agents-api.py` with the following code: + ```python + from praisonaiagents import Agent, Agents, Tools + + research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search]) + summarise_agent = Agent(name="Summarise", instructions="You are a summarize agent to summarise in points") + agents = Agents(agents=[research_agent, summarise_agent]) + agents.launch(path="/agents", port=3030) + ``` + + + ```bash + python multi-agents-api.py + ``` + + Your multi-agent API will be available at `http://localhost:3030/agents` + + + +## Making API Requests + +Once your multi-agent system is deployed, you can make POST requests to interact with it: + +```bash +curl -X POST http://localhost:3030/agents \ + -H "Content-Type: application/json" \ + -d '{"message": "What are the latest developments in AI in 2024?"}' +``` + +The response will include the collaborative output from both the research and summarization agents: + +```json +{ + "response": "# Latest AI Developments in 2024\n\n- Multimodal AI models have become mainstream, combining text, image, audio, and video understanding\n- Significant advancements in AI reasoning capabilities with models like GPT-4o and Claude 3\n- Increased focus on AI alignment and safety research\n- Emergence of specialized AI agents for specific domains\n- Growth in open-source AI models and frameworks\n- Regulatory frameworks for AI being established globally" +} +``` + +## Multiple Agent Groups + +You can deploy multiple agent groups on the same server, each with its own endpoint: + +```python +from praisonaiagents import Agent, Agents, Tools + +research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search]) +summarise_agent = Agent(name="Summarise", instructions="You are a summarize agent to summarise in points") +agents = Agents(agents=[research_agent, summarise_agent]) +agents2 = Agents(agents=[research_agent]) +agents.launch(path="/agents", port=3030) +agents2.launch(path="/agents2", port=3030) +``` + +With this setup, you can access: +- The full agent group at `http://localhost:3030/agents` +- Just the research agent at `http://localhost:3030/agents2` + +## Independent Multi-Agent Deployment + +You can also deploy multiple independent agents on the same server: + +```python +from praisonaiagents import Agent + +weather_agent = Agent( + instructions="""You are a weather agent that can provide weather information for a given city.""", + llm="gpt-4o-mini" +) + +stock_agent = Agent( + instructions="""You are a stock market agent that can provide information about stock prices and market trends.""", + llm="gpt-4o-mini" +) + +travel_agent = Agent( + instructions="""You are a travel agent that can provide recommendations for destinations, hotels, and activities.""", + llm="gpt-4o-mini" +) + +weather_agent.launch(path="/weather", port=3030) +stock_agent.launch(path="/stock", port=3030) +travel_agent.launch(path="/travel", port=3030) +``` + +## Production Deployment Options + +For production environments, consider the following deployment options: + +### Docker Deployment + + + + ```dockerfile + FROM python:3.11-slim + + WORKDIR /app + + COPY requirements.txt . + RUN pip install --no-cache-dir -r requirements.txt + + COPY . . + + EXPOSE 3030 + + CMD ["python", "multi-agents-api.py"] + ``` + + + ``` + praisonaiagents[api]>=0.0.81 + ``` + + + ```bash + docker build -t praisonai-multi-agent . + docker run -p 3030:3030 -e OPENAI_API_KEY=your_api_key praisonai-multi-agent + ``` + + + +### Cloud Deployment + +For detailed cloud deployment instructions, refer to: +- [AWS Deployment Guide](/deploy/aws) +- [Google Cloud Deployment Guide](/deploy/googlecloud) + +## Scaling Multi-Agent Systems + +When deploying multi-agent systems to production, consider these scaling strategies: + +1. **Horizontal Scaling**: Deploy multiple instances behind a load balancer +2. **Vertical Scaling**: Allocate more CPU and memory resources for complex agent interactions +3. **Caching**: Implement response caching for frequently asked questions +4. **Asynchronous Processing**: Use message queues for handling long-running agent tasks + +## API Configuration Options + +When launching your multi-agent system as an API, you can customize various parameters: + +```python +agents.launch( + path="/custom-endpoint", # API endpoint path + port=8080, # Port number + host="0.0.0.0", # Host address (0.0.0.0 for external access) + debug=True, # Enable debug mode + cors_origins=["*"], # CORS configuration + api_key="your-api-key" # Optional API key for authentication +) +``` + +## Securing Your Multi-Agent API + +For production deployments, consider implementing: + +1. **API Key Authentication**: Require API keys for all requests +2. **Rate Limiting**: Limit the number of requests per client +3. **HTTPS**: Use SSL/TLS certificates for encrypted communication +4. **Input Validation**: Validate all input data before processing +5. **Output Filtering**: Implement content filtering for agent responses + +## Monitoring and Logging + +For production environments, consider: + +1. **Centralized Logging**: Collect logs from all agents in a central location +2. **Performance Metrics**: Track response times and resource usage +3. **Error Tracking**: Monitor and alert on agent failures +4. **Usage Analytics**: Track which agents are used most frequently + +## Features + + + + Deploy agent systems that collaborate to solve complex problems. + + + Create dedicated endpoints for different agent groups or individual agents. + + + Deploy agents with specialized tools like web search capabilities. + + + Scale your multi-agent systems to handle production workloads. + + diff --git a/docs/developers/local-development.mdx b/docs/developers/local-development.mdx index 28b82e1a2..e9ab16c00 100644 --- a/docs/developers/local-development.mdx +++ b/docs/developers/local-development.mdx @@ -27,7 +27,7 @@ WORKDIR /app COPY . . -RUN pip install flask praisonai==2.1.4 watchdog +RUN pip install flask praisonai==2.1.5 watchdog EXPOSE 5555 diff --git a/docs/mint.json b/docs/mint.json index 5ddc4c31e..575d4d45d 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -376,6 +376,7 @@ "group": "Deploy", "pages": [ "deploy/deploy", + "deploy/multi-agents-deploy", "deploy/aws", "deploy/googlecloud" ] diff --git a/docs/ui/chat.mdx b/docs/ui/chat.mdx index a7eee75f0..02878517b 100644 --- a/docs/ui/chat.mdx +++ b/docs/ui/chat.mdx @@ -155,7 +155,7 @@ To facilitate local development with live reload, you can use Docker. Follow the COPY . . - RUN pip install flask praisonai==2.1.4 watchdog + RUN pip install flask praisonai==2.1.5 watchdog EXPOSE 5555 diff --git a/docs/ui/code.mdx b/docs/ui/code.mdx index 9337647af..5224cd58e 100644 --- a/docs/ui/code.mdx +++ b/docs/ui/code.mdx @@ -208,7 +208,7 @@ To facilitate local development with live reload, you can use Docker. Follow the COPY . . - RUN pip install flask praisonai==2.1.4 watchdog + RUN pip install flask praisonai==2.1.5 watchdog EXPOSE 5555 diff --git a/examples/api/multi-agents-api.py b/examples/api/multi-agents-api.py new file mode 100644 index 000000000..8f6ac2444 --- /dev/null +++ b/examples/api/multi-agents-api.py @@ -0,0 +1,6 @@ +from praisonaiagents import Agent, Agents, Tools + +research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search]) +summarise_agent = Agent(name="Summarise", instructions="You are a summarize agent to summarise in points") +agents = Agents(agents=[research_agent, summarise_agent]) +agents.launch(path="/agents", port=3030) \ No newline at end of file diff --git a/examples/api/multi-agents-group-api.py b/examples/api/multi-agents-group-api.py new file mode 100644 index 000000000..8888cb1cf --- /dev/null +++ b/examples/api/multi-agents-group-api.py @@ -0,0 +1,8 @@ +from praisonaiagents import Agent, Agents, Tools + +research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search]) +summarise_agent = Agent(name="Summarise", instructions="You are a summarize agent to summarise in points") +agents = Agents(agents=[research_agent, summarise_agent]) +agents2 = Agents(agents=[research_agent]) +agents.launch(path="/agents", port=3030) +agents2.launch(path="/agents2", port=3030) \ No newline at end of file diff --git a/praisonai/deploy.py b/praisonai/deploy.py index 5924cd4f5..d6069ab6f 100644 --- a/praisonai/deploy.py +++ b/praisonai/deploy.py @@ -56,7 +56,7 @@ def create_dockerfile(self): file.write("FROM python:3.11-slim\n") file.write("WORKDIR /app\n") file.write("COPY . .\n") - file.write("RUN pip install flask praisonai==2.1.4 gunicorn markdown\n") + file.write("RUN pip install flask praisonai==2.1.5 gunicorn markdown\n") file.write("EXPOSE 8080\n") file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n') diff --git a/pyproject.toml b/pyproject.toml index 7dffee1f7..29b14bff8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "PraisonAI" -version = "2.1.4" +version = "2.1.5" description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration." readme = "README.md" license = "" @@ -12,7 +12,7 @@ dependencies = [ "rich>=13.7", "markdown>=3.5", "pyparsing>=3.0.0", - "praisonaiagents>=0.0.79", + "praisonaiagents>=0.0.81", "python-dotenv>=0.19.0", "instructor>=1.3.3", "PyYAML>=6.0", @@ -89,7 +89,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"] [tool.poetry] name = "PraisonAI" -version = "2.1.4" +version = "2.1.5" description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration." authors = ["Mervin Praison"] license = "" @@ -107,7 +107,7 @@ python = ">=3.10,<3.13" rich = ">=13.7" markdown = ">=3.5" pyparsing = ">=3.0.0" -praisonaiagents = ">=0.0.79" +praisonaiagents = ">=0.0.81" python-dotenv = ">=0.19.0" instructor = ">=1.3.3" PyYAML = ">=6.0" diff --git a/src/praisonai-agents/praisonaiagents/agent/agent.py b/src/praisonai-agents/praisonaiagents/agent/agent.py index 1834e8f39..a3d0150d3 100644 --- a/src/praisonai-agents/praisonaiagents/agent/agent.py +++ b/src/praisonai-agents/praisonaiagents/agent/agent.py @@ -23,9 +23,9 @@ from dataclasses import dataclass # Global variables for API server -_server_started = False -_registered_agents = {} -_shared_app = None +_server_started = {} # Dict of port -> started boolean +_registered_agents = {} # Dict of port -> Dict of path -> agent_id +_shared_apps = {} # Dict of port -> FastAPI app # Don't import FastAPI dependencies here - use lazy loading instead @@ -1421,7 +1421,7 @@ def launch(self, path: str = '/', port: int = 8000, host: str = '0.0.0.0', debug Returns: None """ - global _server_started, _registered_agents, _shared_app + global _server_started, _registered_agents, _shared_apps # Try to import FastAPI dependencies - lazy loading try: @@ -1447,32 +1447,41 @@ class AgentQuery(BaseModel): print("pip install 'praisonaiagents[api]'") return None - # Initialize shared FastAPI app if not already created - if _shared_app is None: - _shared_app = FastAPI( - title="PraisonAI Agents API", + # Initialize port-specific collections if needed + if port not in _registered_agents: + _registered_agents[port] = {} + + # Initialize shared FastAPI app if not already created for this port + if _shared_apps.get(port) is None: + _shared_apps[port] = FastAPI( + title=f"PraisonAI Agents API (Port {port})", description="API for interacting with PraisonAI Agents" ) # Add a root endpoint with a welcome message - @_shared_app.get("/") + @_shared_apps[port].get("/") async def root(): - return {"message": "Welcome to PraisonAI Agents API. See /docs for usage."} + return { + "message": f"Welcome to PraisonAI Agents API on port {port}. See /docs for usage.", + "endpoints": list(_registered_agents[port].keys()) + } # Add healthcheck endpoint - @_shared_app.get("/health") + @_shared_apps[port].get("/health") async def healthcheck(): - return {"status": "ok", "agents": list(_registered_agents.keys())} + return { + "status": "ok", + "endpoints": list(_registered_agents[port].keys()) + } # Normalize path to ensure it starts with / if not path.startswith('/'): path = f'/{path}' - # Check if path is already registered by another agent - if path in _registered_agents and _registered_agents[path] != self.agent_id: - existing_agent = _registered_agents[path] - logging.warning(f"Path '{path}' is already registered by another agent. Please use a different path.") - print(f"⚠️ Warning: Path '{path}' is already registered by another agent.") + # Check if path is already registered for this port + if path in _registered_agents[port]: + logging.warning(f"Path '{path}' is already registered on port {port}. Please use a different path.") + print(f"⚠️ Warning: Path '{path}' is already registered on port {port}.") # Use a modified path to avoid conflicts original_path = path path = f"{path}_{self.agent_id[:6]}" @@ -1480,10 +1489,10 @@ async def healthcheck(): print(f"🔄 Using '{path}' instead") # Register the agent to this path - _registered_agents[path] = self.agent_id + _registered_agents[port][path] = self.agent_id # Define the endpoint handler - @_shared_app.post(path) + @_shared_apps[port].post(path) async def handle_agent_query(request: Request, query_data: Optional[AgentQuery] = None): # Handle both direct JSON with query field and form data if query_data is None: @@ -1521,17 +1530,18 @@ async def handle_agent_query(request: Request, query_data: Optional[AgentQuery] print(f"🚀 Agent '{self.name}' available at http://{host}:{port}{path}") - # Start the server if it's not already running - if not _server_started: - _server_started = True + # Start the server if it's not already running for this port + if not _server_started.get(port, False): + # Mark the server as started first to prevent duplicate starts + _server_started[port] = True # Start the server in a separate thread def run_server(): try: print(f"✅ FastAPI server started at http://{host}:{port}") print(f"📚 API documentation available at http://{host}:{port}/docs") - print(f"🔌 Available endpoints: {', '.join(list(_registered_agents.keys()))}") - uvicorn.run(_shared_app, host=host, port=port, log_level="debug" if debug else "info") + print(f"🔌 Available endpoints: {', '.join(list(_registered_agents[port].keys()))}") + uvicorn.run(_shared_apps[port], host=host, port=port, log_level="debug" if debug else "info") except Exception as e: logging.error(f"Error starting server: {str(e)}", exc_info=True) print(f"❌ Error starting server: {str(e)}") @@ -1545,7 +1555,7 @@ def run_server(): else: # If server is already running, wait a moment to make sure the endpoint is registered time.sleep(0.1) - print(f"🔌 Available endpoints: {', '.join(list(_registered_agents.keys()))}") + print(f"🔌 Available endpoints on port {port}: {', '.join(list(_registered_agents[port].keys()))}") # Get the stack frame to check if this is the last launch() call in the script import inspect @@ -1571,18 +1581,19 @@ def run_server(): # If this is the last launch call, block the main thread if not has_more_launches: try: - print("\nAll agents registered. Press Ctrl+C to stop the server.") + print("\nAll agents registered. Press Ctrl+C to stop the servers.") while True: time.sleep(1) except KeyboardInterrupt: - print("\nServer stopped") + print("\nServers stopped") except Exception as e: # If something goes wrong with detection, block anyway to be safe logging.error(f"Error in launch detection: {e}") try: + print("\nKeeping servers alive. Press Ctrl+C to stop.") while True: time.sleep(1) except KeyboardInterrupt: - print("\nServer stopped") + print("\nServers stopped") return None \ No newline at end of file diff --git a/src/praisonai-agents/pyproject.toml b/src/praisonai-agents/pyproject.toml index 0c2b1a110..182111113 100644 --- a/src/praisonai-agents/pyproject.toml +++ b/src/praisonai-agents/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "praisonaiagents" -version = "0.0.80" +version = "0.0.81" description = "Praison AI agents for completing complex tasks with Self Reflection Agents" authors = [ { name="Mervin Praison" } diff --git a/src/praisonai-agents/uv.lock b/src/praisonai-agents/uv.lock index 55b41153f..56f851752 100644 --- a/src/praisonai-agents/uv.lock +++ b/src/praisonai-agents/uv.lock @@ -1883,7 +1883,7 @@ wheels = [ [[package]] name = "praisonaiagents" -version = "0.0.80" +version = "0.0.81" source = { editable = "." } dependencies = [ { name = "mcp" }, diff --git a/uv.lock b/uv.lock index 0cb4bdf1d..aeeb5306c 100644 --- a/uv.lock +++ b/uv.lock @@ -3614,7 +3614,7 @@ wheels = [ [[package]] name = "praisonai" -version = "2.1.4" +version = "2.1.5" source = { editable = "." } dependencies = [ { name = "instructor" }, @@ -3756,7 +3756,7 @@ requires-dist = [ { name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" }, { name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.15" }, { name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.15" }, - { name = "praisonaiagents", specifier = ">=0.0.79" }, + { name = "praisonaiagents", specifier = ">=0.0.81" }, { name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" }, { name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" }, { name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" }, @@ -3813,7 +3813,7 @@ wheels = [ [[package]] name = "praisonaiagents" -version = "0.0.79" +version = "0.0.81" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mcp" }, @@ -3821,9 +3821,9 @@ dependencies = [ { name = "pydantic" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/c3/172035c72e559b5fb918eb98faedaeccdaad2c96eb8116c277406259541f/praisonaiagents-0.0.79.tar.gz", hash = "sha256:5ab55b2c1130961ffd7091193a819be3b7fe6675429ee19eb56d94dc073ed125", size = 118276 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/e8/5c254f6e097db086f6c72652a81edfbdd4426daa91d80f9eb020fc1d8e2d/praisonaiagents-0.0.81.tar.gz", hash = "sha256:daec5dc448bd9221f5b2ec1ea9af0a942eb0d0f19fb0e0e588842e3d0259bddd", size = 121033 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/65/e1e40a2c1219246c0fc775be02f2a414fe453f4f9bac5ab074a6e292c39f/praisonaiagents-0.0.79-py3-none-any.whl", hash = "sha256:24b2c2288cb7231b6a2a658141e3c97bb1a73389bb4a4ff1939cab106bd81099", size = 137869 }, + { url = "https://files.pythonhosted.org/packages/a5/4d/c49811749f579d11b84e683cc0c2685f81bcbda6ed7edec907863087d1cb/praisonaiagents-0.0.81-py3-none-any.whl", hash = "sha256:41252168220aa2326c77dbaff53918e09fcc62f059ff4ab9633fc95b6b8bc4f7", size = 140816 }, ] [[package]]