Phase‐by‐Phase Implementation Guide - curlyphries/Crew.AI-Ollama-Multi-Agent-System GitHub Wiki
Phase 1: Set Up Your Environment
Step 1: Install Prerequisites
1.1 Update Your System
Ensure your system is up to date:
sudo apt update && sudo apt upgrade -y
1.2 Install Python and Pip
Install Python 3.9+ and pip:
sudo apt install -y python3 python3-pip
Verify the installation:
python3 --version
pip --version
1.3 Install Docker
Install Docker for running Ollama:
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
Test Docker:
docker --version
You should see Docker’s version information, e.g., Docker version 20.10.7, build f0df350
.
Step 2: Clone the Repository
Pull the project from your GitHub repository:
git clone https://github.com/curlyphries/crew-ai.git
cd crew-ai
Phase 2: Install and Configure Ollama
Step 1: Pull the Ollama Image
Pull the official Ollama Docker image:
docker pull ollama/ollama
Step 2: Start the Ollama Service
Run the Ollama container:
docker run --name ollama -d -p 11434:11434 ollama/ollama
- Explanation:
--name ollama
: Names the containerollama
for easy reference.-d
: Runs the container in detached mode.-p 11434:11434
: Maps port11434
of your machine to port11434
in the container.
Step 3: Verify Ollama
Check if Ollama is running:
curl http://localhost:11434/api/status
You should see a JSON response confirming the service status, e.g.:
{
"status": "running",
"version": "1.0.0"
}
Step 4: Pull Llama2 or Another Model
Download a model, such as Llama2:
docker exec -it ollama ollama pull llama2
- Explanation:
docker exec -it ollama
: Executes a command inside the runningollama
container.ollama pull llama2
: Pulls the Llama2 model into Ollama.
Verify the model is downloaded:
curl http://localhost:11434/api/status
Look for the model status in the JSON response.
Phase 3: Set Up the Project
Step 1: Install Python Dependencies
Install the required Python packages:
pip install -r requirements.txt
requirements.txt
example:fastapi==0.95.2 uvicorn==0.21.1 requests==2.31.0 pyyaml==6.0 python-dotenv==0.21.0 transformers==4.30.0
Phase 4: Create Configuration Files
Create a configuration file for agents and orchestrator settings.
src/config/multi_agent_config.yaml
File: orchestration:
multi_agent: true
memory_store: vector_db
agents:
- name: ollama_agent
enabled: true
- name: search_agent
enabled: true
- name: file_agent
enabled: true
- name: data_analysis_agent
enabled: true
- name: task_management_agent
enabled: true
- name: email_management_agent
enabled: true
- Explanation:
- orchestration.multi_agent: Enables multi-agent mode.
- memory_store: Specifies the memory backend (e.g.,
vector_db
can be FAISS, Weaviate).
Phase 5: Code the Orchestrator
The orchestrator handles incoming queries and decides which agents to use.
src/orchestrator/orchestrator.py
File: from orchestrator.agent_manager import AgentManager
from fastapi import FastAPI, Body
from pydantic import BaseModel
from typing import Optional, Dict
app = FastAPI()
agent_manager = AgentManager()
conversations: Dict[str, Dict] = {} # Simple in-memory store for conversation context
class Query(BaseModel):
session_id: str
query: str
@app.post("/agent")
def handle_query(query: Query):
session = conversations.get(query.session_id, {})
response = agent_manager.route_query(query.query, session)
conversations[query.session_id] = response.get("session", session)
return {"response": response.get("response", "")}
- Explanation:
- FastAPI: Sets up a web server to handle incoming requests.
- AgentManager: Manages and routes queries to the appropriate agents.
- Session Management: Tracks conversation context using
session_id
.
Phase 6: Code the Agent Manager
The AgentManager
loads enabled agents and delegates tasks.
src/orchestrator/agent_manager.py
File: import yaml
from agents.ollama_agent import OllamaAgent
from agents.search_agent import SearchAgent
from agents.file_agent import FileAgent
from agents.data_analysis_agent import DataAnalysisAgent
from agents.task_management_agent import TaskManagementAgent
from agents.email_management_agent import EmailManagementAgent
class AgentManager:
def __init__(self):
with open("src/config/multi_agent_config.yaml", "r") as f:
self.config = yaml.safe_load(f)
self.active_agents = self.load_agents()
def load_agents(self):
agents = []
for agent_def in self.config.get("agents", []):
if agent_def["enabled"]:
if agent_def["name"] == "ollama_agent":
agents.append(OllamaAgent())
elif agent_def["name"] == "search_agent":
agents.append(SearchAgent())
elif agent_def["name"] == "file_agent":
agents.append(FileAgent())
elif agent_def["name"] == "data_analysis_agent":
agents.append(DataAnalysisAgent())
elif agent_def["name"] == "task_management_agent":
agents.append(TaskManagementAgent())
elif agent_def["name"] == "email_management_agent":
agents.append(EmailManagementAgent())
return agents
def route_query(self, query: str, session: Dict) -> Dict:
for agent in self.active_agents:
if agent.can_handle(query):
response, updated_session = agent.handle_query(query, session)
return {"response": response, "session": updated_session}
return {"response": "No suitable agent found.", "session": session}
- Explanation:
- load_agents: Initializes and loads only the enabled agents based on the configuration file.
- route_query: Routes the incoming query to the first agent that can handle it, passing the session context.
Phase 7: Code Example Agents
1. Ollama Agent
Handles basic LLM queries using the Ollama API.
src/agents/ollama_agent.py
File: import requests
class OllamaAgent:
def can_handle(self, query: str) -> bool:
return True # Always available as the default agent
def handle_query(self, query: str, session: dict) -> (str, dict):
response = requests.post(
"http://localhost:11434/api/generate",
json={"model": "llama2", "prompt": query}
)
if response.status_code == 200:
text = response.json().get("text", "No response from Ollama.")
# Update session if needed
return text, session
else:
return "Error communicating with Ollama.", session
- Enhancements:
- Added error handling to manage unsuccessful API calls.
2. Search Agent
Fetches and summarizes information from the web.
src/agents/search_agent.py
File: import requests
class SearchAgent:
def can_handle(self, query: str) -> bool:
return "search" in query.lower()
def handle_query(self, query: str, session: dict) -> (str, dict):
# Replace with actual search API integration
search_term = query.lower().replace("search", "").strip()
# Example: Using DuckDuckGo for privacy
response = requests.get(f"https://api.duckduckgo.com/?q={search_term}&format=json")
if response.status_code == 200:
data = response.json()
abstract = data.get("Abstract", "No summary available.")
return f"Search Summary for '{search_term}': {abstract}", session
else:
return "Error fetching search results.", session
- Enhancements:
- Integrated DuckDuckGo’s API for privacy-focused search summaries.
- Added error handling.
3. File Agent
Handles file reading and writing.
src/agents/file_agent.py
File: import os
class FileAgent:
def can_handle(self, query: str) -> bool:
return "file" in query.lower()
def handle_query(self, query: str, session: dict) -> (str, dict):
if "read" in query.lower():
return self.read_file("example.txt"), session
elif "write" in query.lower():
return self.write_file("example.txt", "Hello, world!"), session
else:
return "File agent can only read or write files.", session
def read_file(self, file_path: str) -> str:
if os.path.exists(file_path):
with open(file_path, "r") as file:
return file.read()
return f"File '{file_path}' not found."
def write_file(self, file_path: str, content: str) -> str:
try:
with open(file_path, "w") as file:
file.write(content)
return f"Content written to '{file_path}'."
except Exception as e:
return f"Error writing to file: {e}"
- Enhancements:
- Improved error handling.
- Added feedback for unsupported file operations.
4. Data Analysis Agent
Analyzes and summarizes structured/unstructured data.
src/agents/data_analysis_agent.py
File: from transformers import pipeline
class DataAnalysisAgent:
def __init__(self):
# Initialize a summarization pipeline
self.summarizer = pipeline("summarization")
def can_handle(self, query: str) -> bool:
return "analyze" in query.lower() or "summarize" in query.lower()
def handle_query(self, query: str, session: dict) -> (str, dict):
# Extract the text to summarize
# Example query: "summarize the following text: [Your text here]"
if "summarize the following text:" in query.lower():
text = query.lower().split("summarize the following text:")[-1].strip()
if not text:
return "Please provide the text you want me to summarize.", session
try:
summary = self.summarizer(text, max_length=50, min_length=25, do_sample=False)
return summary[0]['summary_text'], session
except Exception as e:
return f"Error during data analysis: {e}", session
else:
return "Data Analysis Agent can summarize provided text.", session
- Enhancements:
- Implemented a real summarization pipeline using Hugging Face’s transformers.
- Added error handling.
- Added request for text if not provided.
5. Task Management Agent
Manages to-do lists, schedules, and reminders.
src/agents/task_management_agent.py
File: from datetime import datetime
class TaskManagementAgent:
def __init__(self):
self.tasks = []
def can_handle(self, query: str) -> bool:
return "task" in query.lower() or "reminder" in query.lower()
def handle_query(self, query: str, session: dict) -> (str, dict):
if "add task" in query.lower():
task_details = query.lower().replace("add task", "").strip()
if not task_details:
return "Sure, I can help add a task. Could you please provide the task details?", session
self.tasks.append({"task": task_details, "created_at": datetime.now()})
return f"Task added: {task_details}", session
elif "list tasks" in query.lower():
if not self.tasks:
return "No tasks available.", session
task_list = "\n".join([f"{idx+1}. {task['task']} (Added on {task['created_at'].strftime('%Y-%m-%d %H:%M')})" for idx, task in enumerate(self.tasks)])
return f"Your Tasks:\n{task_list}", session
else:
return "Task Management Agent can add or list your tasks.", session
- Explanation:
- Checks if task details are provided when adding a task.
- If not, prompts the user for additional information.
6. Email Management Agent
Automates reading, composing, and organizing emails.
src/agents/email_management_agent.py
File: import imaplib
import smtplib
from email.message import EmailMessage
import os
from dotenv import load_dotenv
load_dotenv() # Load variables from .env file
class EmailManagementAgent:
def __init__(self):
# Configure your email credentials via environment variables for security
self.email_address = os.getenv("EMAIL_ADDRESS")
self.email_password = os.getenv("EMAIL_PASSWORD")
self.imap_server = os.getenv("IMAP_SERVER", "imap.example.com")
self.smtp_server = os.getenv("SMTP_SERVER", "smtp.example.com")
self.smtp_port = int(os.getenv("SMTP_PORT", "587"))
def can_handle(self, query: str) -> bool:
return "email" in query.lower()
def handle_query(self, query: str, session: dict) -> (str, dict):
if "read email" in query.lower():
return self.read_emails(), session
elif "send email" in query.lower():
return self.send_email(query), session
else:
return "Email Management Agent can read or send emails.", session
def read_emails(self) -> str:
try:
mail = imaplib.IMAP4_SSL(self.imap_server)
mail.login(self.email_address, self.email_password)
mail.select("inbox")
result, data = mail.search(None, "ALL")
mail_ids = data[0].split()
if not mail_ids:
return "No emails found."
latest_email_id = mail_ids[-1]
result, message_data = mail.fetch(latest_email_id, "(RFC822)")
raw_email = message_data[0][1].decode("utf-8")
return f"Latest Email:\n{raw_email}"
except Exception as e:
return f"Error reading emails: {e}"
def send_email(self, query: str) -> str:
try:
# Extract recipient and message from the query
# Example query: "send email to [email protected] with message Hello!"
parts = query.lower().split("send email to")
if len(parts) < 2:
return "Please specify the recipient."
recipient_part = parts[1].split("with message")
if len(recipient_part) < 2:
return "Please specify the message."
recipient = recipient_part[0].strip()
message = recipient_part[1].strip()
msg = EmailMessage()
msg["Subject"] = "Automated Email from Crew.ai"
msg["From"] = self.email_address
msg["To"] = recipient
msg.set_content(message)
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
server.starttls()
server.login(self.email_address, self.email_password)
server.send_message(msg)
return f"Email sent to {recipient}."
except Exception as e:
return f"Error sending email: {e}"
⚠️ Security Best Practices:
- Environment Variables: Store sensitive information like email credentials in environment variables.
- Example: Create a
.env
file in the project root (ensure it's added to.gitignore
):[email protected] EMAIL_PASSWORD=your_secure_password IMAP_SERVER=imap.example.com SMTP_SERVER=smtp.example.com SMTP_PORT=587
- Loading Environment Variables: Use a library like
python-dotenv
to load these variables.
- Install
python-dotenv
:pip install python-dotenv
- Modify the
email_management_agent.py
to load the.env
file:from dotenv import load_dotenv import os load_dotenv() # Load variables from .env file
🛡️ Ensuring System Security and Stability
-
Container Isolation:
- Run each agent in its own Docker container to isolate processes and enhance security.
- Example Docker run command with resource limits:
docker run --name search_agent -d --cpus="1.0" --memory="2g" crew-ai/search_agent:latest
-
Secure Communication:
- Use HTTPS for API endpoints if exposing them externally.
- Implement authentication mechanisms to restrict access to your API.
-
Regular Updates:
- Keep Docker images and Python packages up to date to patch vulnerabilities.
- Regularly update your agents’ codebase to incorporate improvements and security fixes.
-
Backup and Recovery:
- Regularly back up your configuration files, memory databases, and important data.
- Implement recovery procedures in case of system failures or data corruption.
📘 Further Reading and Resources
- Ollama Documentation: Comprehensive guides and API references.
- FastAPI Documentation: Learn more about building APIs with FastAPI.
- Docker Documentation: Deep dive into Docker usage and best practices.
- FAISS Documentation: Explore vector databases for efficient similarity search.
- Weaviate Documentation: Learn about Weaviate for scalable vector search.
📝 License
This project is licensed under the MIT License. Feel free to use, modify, and build on it, but please provide attribution. See the LICENSE file for details.
🌐 Connect
- Project Page: GitHub Repository
🌟 Final Thoughts
Building the Crew.ai Ollama Multi-Agent System is not just about setting up software—it’s about empowering yourself with a customizable, secure, and intelligent assistant tailored to your unique needs. Start with the core agents, explore their capabilities, and gradually expand your system with specialized agents as you discover new ways to enhance your personal and professional workflows.
Remember, this is a personal project designed to grow with you. Don’t hesitate to experiment, make mistakes, and iterate on your setup. Your journey into local AI is just beginning, and the possibilities are endless!
Ready to Dive In?
Follow the phases outlined above to set up your Crew.ai system. If you encounter any issues or have questions, feel free to reach out by opening an issue on the GitHub Repository. Happy building!
---
# **Enhancements Made**
1. **Added a Detailed Introduction to Handling Clarifications**:
- Introduced a new subsection under "How It Works" to explain how the system manages scenarios where agents require additional information.
- Provided a step-by-step flow of the interaction, ensuring users understand the multi-turn conversation process.
2. **Included Example Scenario**:
- Demonstrated a real-world example of how a query might be clarified, making it easier for users to visualize the interaction.
3. **Implemented Code Examples for Clarifications**:
- Showed how to modify the Orchestrator and AgentManager to handle session-based conversations.
- Provided updated agent code snippets that include logic for requesting and handling clarifications.
4. **Enhanced Orchestrator for Session Management**:
- Introduced session tracking to maintain conversation context, enabling multi-turn interactions.
5. **Improved Agent Implementations**:
- Each agent now accepts and returns session context, allowing for more dynamic and accurate responses based on prior interactions.
- Added error handling and prompts for missing information to ensure robustness.
6. **Added Troubleshooting Section**:
- Provided common issues and their solutions to assist users during setup and operation.
7. **Consistent Formatting and Style**:
- Maintained clear headings, subheadings, and bullet points for better readability.
- Used emojis and markdown formatting to make the README more engaging and user-friendly.
8. **Emphasized Security Best Practices**:
- Highlighted the importance of using environment variables for sensitive information.
- Included instructions on setting up a `.env` file and loading it securely.
9. **Expanded Future Plans**:
- Added more detailed future enhancements to guide users on potential expansions and improvements.
---
# **Next Steps**
1. **Implement Session Management**:
- Ensure the Orchestrator correctly tracks and manages conversation sessions based on `session_id`.
- Consider using a more robust session storage solution (e.g., Redis) if scaling beyond a single machine.
2. **Enhance Agents for Clarifications**:
- Further refine each agent's ability to detect when additional information is needed and to handle follow-up queries effectively.
3. **Develop User Interface (Optional)**:
- Create a web-based or desktop interface to facilitate easier interactions, especially for multi-turn conversations.
4. **Testing and Validation**:
- Write comprehensive unit and integration tests to ensure all agents and orchestrator functionalities work as expected.
- Utilize the provided `Troubleshooting` section to address common issues during testing.
5. **Documentation Updates**:
- Continuously update the README.md and other documentation as new features and agents are added.
- Consider adding tutorials or example use-cases to help users get started quickly.
6. **Security Enhancements**:
- Implement authentication for API endpoints to prevent unauthorized access.
- Regularly audit and update dependencies to mitigate security vulnerabilities.
---
Feel free to reach out if you need further assistance with specific features, troubleshooting, or any other aspect of the project. Happy building!