Tutorial 4: Production Systems
⏱️ Time: 60 minutes | 🎯 Goal: Build a scalable, production-ready system
Time to build something serious! In this tutorial, you’ll create a comprehensive research system with multiple specialized agents, persistent memory, and production-ready features. This is where AgentX really shines.
What You’ll Learn
- Advanced multi-agent architectures
- Memory systems for long-term context
- Error handling and resilience
- File operations and deliverable generation
- Production deployment patterns
- Monitoring and observability
Prerequisites
- Completed all previous tutorials
- Understanding of multi-agent systems and tools
- DeepSeek API key
- Python 3.8+
Step 1: Project Architecture
Create a sophisticated project structure for your research system:
mkdir research-system
cd research-system
mkdir -p config/{prompts,memory}
mkdir -p workspace/{research,reports,temp}
mkdir -p tools
mkdir logs
Your production structure:
research-system/
├── config/
│ ├── team.yaml # Team configuration
│ ├── prompts/ # Agent prompts
│ │ ├── coordinator.md
│ │ ├── researcher.md
│ │ ├── analyst.md
│ │ └── writer.md
│ └── memory/ # Memory configuration
├── tools/
│ ├── __init__.py
│ ├── research_tools.py # Custom research tools
│ └── file_tools.py # File operation tools
├── workspace/
│ ├── research/ # Research data
│ ├── reports/ # Final reports
│ └── temp/ # Temporary files
├── logs/ # Application logs
├── main.py # Main application
└── requirements.txt # Dependencies
Step 2: Production Team Configuration
Create config/team.yaml
with a sophisticated multi-agent setup:
name: "research_system"
description: "Production research system with specialized agents"
# Four specialized agents for different research phases
agents:
- name: "coordinator"
description: "Research coordinator and project manager"
prompt_template: "prompts/coordinator.md"
tools: ["handoff", "memory", "file_ops"]
llm_config:
provider: "deepseek"
model: "deepseek-chat"
temperature: 0.3 # Focused for coordination
max_tokens: 4000
- name: "researcher"
description: "Information gathering specialist"
prompt_template: "prompts/researcher.md"
tools: ["handoff", "memory", "web_search", "file_ops"]
llm_config:
provider: "deepseek"
model: "deepseek-chat"
temperature: 0.5 # Balanced for research
max_tokens: 4000
- name: "analyst"
description: "Data analysis and synthesis expert"
prompt_template: "prompts/analyst.md"
tools: ["handoff", "memory", "file_ops"]
llm_config:
provider: "deepseek"
model: "deepseek-chat"
temperature: 0.4 # Analytical focus
max_tokens: 4000
- name: "writer"
description: "Report writing and documentation specialist"
prompt_template: "prompts/writer.md"
tools: ["handoff", "memory", "file_ops"]
llm_config:
provider: "deepseek"
model: "deepseek-chat"
temperature: 0.7 # Creative for writing
max_tokens: 4000
# Production-grade tool configuration
tools:
- name: "handoff"
type: "builtin"
- name: "memory"
type: "builtin"
- name: "web_search"
type: "custom"
module: "tools.research_tools"
class: "WebSearchTool"
- name: "file_ops"
type: "custom"
module: "tools.file_tools"
class: "FileOperationsTool"
# Production execution configuration
execution:
mode: "autonomous"
initial_agent: "coordinator"
max_rounds: 20 # Allow for complex workflows
timeout_seconds: 1800 # 30 minutes
# Enable orchestrator with production settings
orchestrator:
max_rounds: 20
timeout: 1800
brain_config:
model: "deepseek/deepseek-chat"
temperature: 0.0
max_tokens: 200
# Production memory configuration
memory:
enabled: true
backend: "mem0"
config:
vector_store:
provider: "qdrant"
config:
collection_name: "research_memory"
embedding_model: "sentence-transformers/all-MiniLM-L6-v2"
llm:
provider: "deepseek"
model: "deepseek-chat"
temperature: 0.1
# Workspace configuration
workspace:
base_path: "workspace"
auto_cleanup: false # Keep files for production
max_file_size: "10MB"
Step 3: Specialized Agent Prompts
Coordinator Agent
Create config/prompts/coordinator.md
:
# Research Coordinator
You are the research coordinator responsible for managing complex research projects from start to finish.
## Your Role
- Break down research requests into manageable phases
- Coordinate between specialist agents
- Track project progress and deliverables
- Ensure quality and completeness of research
- Manage timelines and resources
## Research Process
1. **Planning Phase**: Analyze request, create research plan
2. **Research Phase**: Direct researcher to gather information
3. **Analysis Phase**: Have analyst synthesize findings
4. **Writing Phase**: Direct writer to create final report
5. **Review Phase**: Quality check and finalization
## Handoff Strategy
- **To Researcher**: When information gathering is needed
- **To Analyst**: When data synthesis is required
- **To Writer**: When report creation is needed
- **Back to yourself**: To coordinate next steps
## Memory Usage
- Store project plans and progress updates
- Track key findings and decisions
- Remember stakeholder requirements
- Maintain research methodology notes
## File Operations
- Create project folders and organize workspace
- Save research plans and progress reports
- Track deliverables and versions
## Example Workflow
1. Receive research request
2. Create detailed research plan
3. Set up project workspace
4. Hand off to researcher for data gathering
5. Coordinate analysis and synthesis
6. Oversee report writing
7. Final quality review and delivery
Always maintain professional project management standards.
Researcher Agent
Create config/prompts/researcher.md
:
# Research Specialist
You are an expert researcher skilled in gathering, evaluating, and organizing information from multiple sources.
## Your Role
- Conduct thorough information gathering
- Evaluate source credibility and relevance
- Organize findings systematically
- Identify research gaps and opportunities
- Provide comprehensive data for analysis
## Research Methodology
1. **Scope Definition**: Understand research parameters
2. **Source Identification**: Find relevant information sources
3. **Data Collection**: Gather comprehensive information
4. **Source Evaluation**: Assess credibility and relevance
5. **Data Organization**: Structure findings logically
## Tools Usage
- **Web Search**: Find current information and data
- **Memory**: Store and recall research findings
- **File Operations**: Save research data and sources
## Research Standards
- Always verify information from multiple sources
- Document sources and methodology
- Identify potential biases or limitations
- Organize findings by themes or categories
- Highlight key insights and patterns
## Handoff Criteria
Hand back to coordinator when:
- Initial research phase is complete
- Sufficient data has been gathered
- Research gaps have been identified
- Ready for analysis phase
## Output Format
Structure research findings with:
- Executive summary of key findings
- Detailed information by category/theme
- Source documentation and credibility assessment
- Identified gaps or areas for further research
- Recommendations for analysis focus
Always maintain academic research standards and cite sources properly.
Analyst Agent
Create config/prompts/analyst.md
:
# Data Analyst
You are a skilled analyst who synthesizes complex information into actionable insights and recommendations.
## Your Role
- Analyze research data for patterns and trends
- Synthesize information from multiple sources
- Identify key insights and implications
- Develop evidence-based recommendations
- Create structured analysis frameworks
## Analysis Process
1. **Data Review**: Examine all research findings
2. **Pattern Recognition**: Identify trends and relationships
3. **Synthesis**: Combine information into coherent insights
4. **Validation**: Cross-check findings and conclusions
5. **Recommendation Development**: Create actionable advice
## Analytical Frameworks
- SWOT analysis for strategic insights
- Trend analysis for market intelligence
- Comparative analysis for benchmarking
- Risk assessment for decision-making
- Impact analysis for recommendations
## Memory Usage
- Store analytical frameworks and methodologies
- Remember key insights and patterns
- Track analysis progress and decisions
- Maintain analytical standards and criteria
## File Operations
- Save analysis reports and frameworks
- Create data visualizations and summaries
- Organize findings by analytical dimensions
## Handoff Criteria
Hand to writer when:
- Analysis is complete and validated
- Key insights are clearly identified
- Recommendations are evidence-based
- Analysis framework is documented
## Output Standards
- Clear methodology and assumptions
- Evidence-based conclusions
- Quantified impacts where possible
- Risk assessments and limitations
- Actionable recommendations
Always maintain analytical rigor and objectivity.
Writer Agent
Create config/prompts/writer.md
:
# Report Writer
You are a professional writer who creates clear, comprehensive reports and documentation.
## Your Role
- Transform analysis into readable reports
- Create executive summaries and detailed findings
- Ensure clear communication of complex information
- Maintain professional writing standards
- Produce publication-ready documents
## Writing Process
1. **Content Planning**: Organize information structure
2. **Executive Summary**: Create high-level overview
3. **Detailed Sections**: Develop comprehensive content
4. **Review and Edit**: Ensure clarity and accuracy
5. **Formatting**: Apply professional presentation standards
## Report Structure
- **Executive Summary**: Key findings and recommendations
- **Introduction**: Background and methodology
- **Findings**: Detailed research results
- **Analysis**: Insights and implications
- **Recommendations**: Actionable next steps
- **Appendices**: Supporting data and sources
## Writing Standards
- Clear, professional tone
- Logical flow and structure
- Evidence-based statements
- Proper citations and references
- Executive-ready presentation
## File Operations
- Create professional report documents
- Save multiple versions and drafts
- Generate executive summaries
- Organize supporting materials
## Handoff Criteria
Hand back to coordinator when:
- Report is complete and professionally formatted
- All sections are comprehensive and accurate
- Executive summary captures key points
- Ready for final review and delivery
## Quality Checklist
- Clear executive summary
- Logical document structure
- Evidence-based content
- Professional formatting
- Proper citations
- Actionable recommendations
Always maintain professional writing and presentation standards.
Step 4: Custom Production Tools
Research Tools
Create tools/__init__.py
:
# Empty file to make tools a package
Create tools/research_tools.py
:
import aiohttp
import asyncio
from typing import List, Dict, Any
from agentx.tool.base import Tool
class WebSearchTool(Tool):
"""Production web search tool with rate limiting and error handling."""
def __init__(self):
super().__init__()
self.search_results_cache = {}
self.rate_limit_delay = 1.0 # Seconds between requests
self.last_request_time = 0
async def search_web(self, query: str, max_results: int = 10) -> str:
"""
Search the web for information.
Args:
query: Search query string
max_results: Maximum number of results to return
Returns:
Formatted search results
"""
try:
# Check cache first
cache_key = f"{query}_{max_results}"
if cache_key in self.search_results_cache:
return self.search_results_cache[cache_key]
# Rate limiting
current_time = asyncio.get_event_loop().time()
if current_time - self.last_request_time < self.rate_limit_delay:
await asyncio.sleep(self.rate_limit_delay)
# Simulate web search (in production, use real search API)
results = await self._simulate_search(query, max_results)
if not results:
return f"No search results found for: {query}"
formatted_results = self._format_search_results(query, results)
# Cache results
self.search_results_cache[cache_key] = formatted_results
self.last_request_time = asyncio.get_event_loop().time()
return formatted_results
except Exception as e:
return f"Error searching for '{query}': {str(e)}"
async def _simulate_search(self, query: str, max_results: int) -> List[Dict[str, Any]]:
"""Simulate search results for demonstration."""
# In production, replace with real search API
await asyncio.sleep(0.5) # Simulate network delay
return [
{
"title": f"Research Article: {query}",
"url": f"https://example.com/research/{query.replace(' ', '-')}",
"snippet": f"Comprehensive research on {query} with detailed analysis and findings...",
"source": "Academic Journal"
},
{
"title": f"Industry Report: {query}",
"url": f"https://industry.com/reports/{query.replace(' ', '-')}",
"snippet": f"Latest industry insights on {query} including market trends and forecasts...",
"source": "Industry Publication"
},
{
"title": f"News Article: {query}",
"url": f"https://news.com/articles/{query.replace(' ', '-')}",
"snippet": f"Recent developments in {query} with expert opinions and analysis...",
"source": "News Outlet"
}
][:max_results]
def _format_search_results(self, query: str, results: List[Dict[str, Any]]) -> str:
"""Format search results for agent consumption."""
formatted = f"🔍 Search Results for: {query}\n\n"
for i, result in enumerate(results, 1):
formatted += f"**Result {i}:**\n"
formatted += f"Title: {result['title']}\n"
formatted += f"Source: {result['source']}\n"
formatted += f"URL: {result['url']}\n"
formatted += f"Summary: {result['snippet']}\n\n"
formatted += f"Found {len(results)} results for analysis.\n"
return formatted
File Operations Tool
Create tools/file_tools.py
:
import os
import json
import aiofiles
from pathlib import Path
from typing import Dict, Any, Optional
from agentx.tool.base import Tool
class FileOperationsTool(Tool):
"""Production file operations with error handling and security."""
def __init__(self):
super().__init__()
self.workspace_path = Path("workspace")
self.allowed_extensions = {'.txt', '.md', '.json', '.csv', '.html'}
self.max_file_size = 10 * 1024 * 1024 # 10MB
async def save_file(self, filename: str, content: str, folder: str = "temp") -> str:
"""
Save content to a file in the workspace.
Args:
filename: Name of the file to save
content: Content to write to the file
folder: Subfolder within workspace (temp, research, reports)
Returns:
Success message with file path
"""
try:
# Validate inputs
if not self._is_safe_filename(filename):
return f"Error: Invalid filename '{filename}'. Use only alphanumeric characters, hyphens, and underscores."
if not self._is_allowed_extension(filename):
return f"Error: File extension not allowed. Allowed: {', '.join(self.allowed_extensions)}"
if len(content.encode('utf-8')) > self.max_file_size:
return f"Error: File size exceeds maximum allowed size of {self.max_file_size // (1024*1024)}MB."
# Create directory structure
folder_path = self.workspace_path / folder
folder_path.mkdir(parents=True, exist_ok=True)
# Save file
file_path = folder_path / filename
async with aiofiles.open(file_path, 'w', encoding='utf-8') as f:
await f.write(content)
return f"✅ File saved successfully: {file_path}"
except Exception as e:
return f"❌ Error saving file '{filename}': {str(e)}"
async def read_file(self, filename: str, folder: str = "temp") -> str:
"""
Read content from a file in the workspace.
Args:
filename: Name of the file to read
folder: Subfolder within workspace
Returns:
File content or error message
"""
try:
file_path = self.workspace_path / folder / filename
if not file_path.exists():
return f"❌ File not found: {file_path}"
if file_path.stat().st_size > self.max_file_size:
return f"❌ File too large to read: {filename}"
async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
content = await f.read()
return f"📄 Content of {filename}:\n\n{content}"
except Exception as e:
return f"❌ Error reading file '{filename}': {str(e)}"
async def list_files(self, folder: str = "temp") -> str:
"""
List files in a workspace folder.
Args:
folder: Subfolder to list
Returns:
Formatted list of files
"""
try:
folder_path = self.workspace_path / folder
if not folder_path.exists():
return f"📁 Folder '{folder}' does not exist or is empty."
files = []
for file_path in folder_path.iterdir():
if file_path.is_file():
size = file_path.stat().st_size
files.append({
'name': file_path.name,
'size': f"{size:,} bytes",
'modified': file_path.stat().st_mtime
})
if not files:
return f"📁 Folder '{folder}' is empty."
# Sort by modification time (newest first)
files.sort(key=lambda x: x['modified'], reverse=True)
result = f"📁 Files in '{folder}' folder:\n\n"
for file_info in files:
result += f"• {file_info['name']} ({file_info['size']})\n"
return result
except Exception as e:
return f"❌ Error listing files in '{folder}': {str(e)}"
def _is_safe_filename(self, filename: str) -> bool:
"""Check if filename is safe (no path traversal, etc.)."""
if not filename or '..' in filename or '/' in filename or '\\' in filename:
return False
return True
def _is_allowed_extension(self, filename: str) -> bool:
"""Check if file extension is allowed."""
return Path(filename).suffix.lower() in self.allowed_extensions
Step 5: Production Main Application
Create main.py
:
#!/usr/bin/env python3
import asyncio
import logging
import sys
from pathlib import Path
from datetime import datetime
# Add tools to path
sys.path.insert(0, str(Path(__file__).parent))
from agentx.core.task import TaskExecutor
# Configure production logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/research_system.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
class ResearchSystem:
"""Production research system with comprehensive features."""
def __init__(self):
self.config_path = Path(__file__).parent / "config" / "team.yaml"
self.task_executor = None
self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
async def initialize(self):
"""Initialize the research system."""
try:
logger.info("Initializing Research System...")
self.task_executor = TaskExecutor(str(self.config_path))
logger.info("Research System initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize Research System: {e}")
raise
async def conduct_research(self, research_request: str) -> str:
"""Conduct comprehensive research on a topic."""
logger.info(f"Starting research session: {self.session_id}")
logger.info(f"Research request: {research_request}")
try:
# Enhanced prompt for production research
enhanced_prompt = f"""
RESEARCH REQUEST: {research_request}
SESSION ID: {self.session_id}
TIMESTAMP: {datetime.now().isoformat()}
INSTRUCTIONS:
1. Create a comprehensive research plan
2. Conduct thorough information gathering
3. Perform detailed analysis and synthesis
4. Generate a professional research report
5. Save all work products to appropriate workspace folders
DELIVERABLES REQUIRED:
- Research plan document
- Comprehensive findings report
- Executive summary
- Recommendations document
Begin the research process now.
"""
# Track research progress
progress_log = []
handoff_count = 0
current_agent = "coordinator"
print(f"🔬 Research System - Session {self.session_id}")
print(f"📋 Request: {research_request}")
print("=" * 60)
async for update in self.task_executor.execute_task(enhanced_prompt, stream=True):
update_type = update.get("type")
if update_type == "content":
content = update.get("content", "")
print(content, end="", flush=True)
elif update_type == "handoff":
handoff_count += 1
from_agent = update["from_agent"]
to_agent = update["to_agent"]
current_agent = to_agent
progress_entry = {
"timestamp": datetime.now().isoformat(),
"handoff": handoff_count,
"from": from_agent,
"to": to_agent
}
progress_log.append(progress_entry)
print(f"\n\n🔄 HANDOFF #{handoff_count}: {from_agent} → {to_agent}")
print("─" * 40)
logger.info(f"Agent handoff: {from_agent} → {to_agent}")
elif update_type == "tool_call":
tool_name = update.get("tool_name", "unknown")
print(f"\n🛠️ Using tool: {tool_name}")
logger.info(f"Tool call: {tool_name}")
elif update_type == "routing_decision":
if update["action"] == "complete":
print(f"\n\n🎉 Research Complete!")
print(f"📊 Session: {self.session_id}")
print(f"🔄 Total handoffs: {handoff_count}")
print(f"🎯 Final agent: {current_agent}")
logger.info(f"Research session completed: {self.session_id}")
break
# Save session log
await self._save_session_log(progress_log, research_request)
return f"Research session {self.session_id} completed successfully."
except Exception as e:
logger.error(f"Research session failed: {e}")
print(f"\n❌ Research failed: {e}")
return f"Research session failed: {e}"
async def _save_session_log(self, progress_log: list, research_request: str):
"""Save session progress log."""
try:
log_data = {
"session_id": self.session_id,
"timestamp": datetime.now().isoformat(),
"research_request": research_request,
"progress_log": progress_log,
"summary": {
"total_handoffs": len(progress_log),
"agents_involved": list(set([entry["from"] for entry in progress_log] + [entry["to"] for entry in progress_log]))
}
}
log_file = Path("logs") / f"session_{self.session_id}.json"
log_file.parent.mkdir(exist_ok=True)
with open(log_file, 'w') as f:
import json
json.dump(log_data, f, indent=2)
logger.info(f"Session log saved: {log_file}")
except Exception as e:
logger.error(f"Failed to save session log: {e}")
async def main():
"""Main application entry point."""
print("🏭 AgentX Production Research System")
print("Advanced multi-agent research with memory and file operations")
print()
# Initialize system
research_system = ResearchSystem()
await research_system.initialize()
# Interactive mode
while True:
print("\n" + "="*60)
research_request = input("Enter research topic (or 'quit' to exit): ").strip()
if research_request.lower() in ['quit', 'q', 'exit']:
print("Goodbye! 👋")
break
if not research_request:
print("Please enter a research topic.")
continue
# Conduct research
result = await research_system.conduct_research(research_request)
print(f"\n✅ {result}")
# Show workspace contents
workspace_path = Path("workspace")
if workspace_path.exists():
print(f"\n📁 Check the workspace folder for research deliverables:")
for folder in ["research", "reports", "temp"]:
folder_path = workspace_path / folder
if folder_path.exists() and any(folder_path.iterdir()):
print(f" • {folder}/ - {len(list(folder_path.iterdir()))} files")
if __name__ == "__main__":
asyncio.run(main())
Step 6: Production Dependencies
Create requirements.txt
:
agentx-py>=0.1.0
aiofiles>=23.2.1
aiohttp>=3.9.0
mem0ai>=0.1.0
qdrant-client>=1.7.0
sentence-transformers>=2.2.2
Step 7: Run the Production System
# Install dependencies
pip install -r requirements.txt
# Set environment variables
export DEEPSEEK_API_KEY="your-api-key-here"
# Run the system
python main.py
Step 8: Test Production Features
Try these comprehensive research requests:
Market Research
Enter research topic: AI market trends and opportunities 2024
Competitive Analysis
Enter research topic: Competitive landscape analysis for electric vehicles
Technology Assessment
Enter research topic: Blockchain technology adoption in healthcare
🎉 Congratulations!
You’ve completed the comprehensive AgentX tutorial series! You now have the knowledge and skills to build production-ready multi-agent systems.
What You’ve Mastered
✅ Single Agent Systems - Basic agent configuration and interaction
✅ Multi-Agent Collaboration - Agent handoffs and team coordination
✅ Custom Tools - Extending agent capabilities with external integrations
✅ Production Concepts - Scalable, maintainable agent architectures
Real-World Applications
With your AgentX skills, you can now build:
- Research Systems - Automated research with multiple specialist agents
- Content Creation - Writer-reviewer teams for high-quality content
- Customer Service - Multi-agent support systems with specialized roles
- Data Analysis - Research, analysis, and reporting pipelines
- Workflow Automation - Complex business process automation
Next Steps
- Explore the Examples - Check out the example projects
- Read the API Docs - Dive deeper with the API Reference
- Join the Community - Connect with other developers on GitHub Discussions
- Build Something Amazing - Apply your skills to solve real problems
🚀 Ready to build the future with AgentX? The possibilities are endless!