This guide covers deploying AInTandem Agent MCP Scheduler to production environments.
- Environment Requirements
- Local Development Setup
- Production Deployment
- Docker Deployment
- Cloud Deployment
- Monitoring & Logging
- Security Best Practices
- Troubleshooting
- Python: 3.10 or higher
- Memory: 512MB RAM (1GB+ recommended)
- Disk: 500MB free space
- Network: For API calls and MCP servers
- CPU: 2+ cores
- Memory: 2GB+ RAM
- Disk: 5GB+ SSD storage
- Network: Stable internet connection
# Clone repository
git clone <your-repo-url>
cd agent-infra
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Configure environment
cp .env.example .env
# Edit .env with your API keys
# Run tests
python tests/test_integration.py
# Start application
python main.py# Enable debug logging
export LOG_LEVEL=DEBUG
# Start with auto-reload
uvicorn api.openapi_server:app --reload --host 0.0.0.0 --port 8000
# Start GUI separately
python -m gui.appCreate /etc/systemd/qwen-agent.service:
[Unit]
Description=AInTandem Agent MCP Scheduler
After=network.target
[Service]
Type=simple
User=agent
WorkingDirectory=/opt/qwen-agent
Environment="PATH=/opt/qwen-agent/venv/bin"
ExecStart=/opt/qwen-agent/venv/bin/python main.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable qwen-agent
sudo systemctl start qwen-agent
sudo systemctl status qwen-agentCreate /etc/supervisor/conf.d/qwen-agent.conf:
[program:qwen-agent]
command=/opt/qwen-agent/venv/bin/python main.py
directory=/opt/qwen-agent
user=agent
autostart=true
autorestart=true
stderr_logfile=/var/log/qwen-agent.err.log
stdout_logfile=/var/log/qwen-agent.out.logStart:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start qwen-agentInstall gunicorn:
pip install gunicorn uvicorn[standard]Create gunicorn_config.py:
import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"
timeout = 120
keepalive = 5
max_requests = 1000
max_requests_jitter = 50
preload_app = TrueRun:
gunicorn -c gunicorn_config.py api.openapi_server:appCreate Dockerfile:
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Create storage directory
RUN mkdir -p /app/storage/tasks /app/storage/logs
# Expose ports
EXPOSE 8000 7860
# Set environment variables
ENV PYTHONUNBUFFERED=1
ENV LOG_LEVEL=INFO
# Run application
CMD ["python", "main.py"]Create docker-compose.yml:
version: '3.8'
services:
qwen-agent:
build: .
container_name: qwen-agent
ports:
- "8000:8000" # API
- "7860:7860" # GUI
environment:
- LOG_LEVEL=INFO
- OPENAI_API_KEY=${OPENAI_API_KEY}
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
volumes:
- ./config:/app/config:ro
- ./storage:/app/storage
- ./logs:/app/storage/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3# Build image
docker-compose build
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down- Push Docker image to ECR
- Create ECS task definition
- Configure security groups (ports 8000, 7860)
- Set environment variables
- Deploy service
Task Definition Example:
{
"family": "qwen-agent",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "qwen-agent",
"image": "<your-ecr-repo>/qwen-agent:latest",
"portMappings": [
{"containerPort": 8000, "protocol": "tcp"},
{"containerPort": 7860, "protocol": "tcp"}
],
"environment": [
{"name": "LOG_LEVEL", "value": "INFO"},
{"name": "OPENAI_API_KEY", "value": "<your-key>"}
],
"mountPoints": [
{
"sourceVolume": "storage",
"containerPath": "/app/storage"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/qwen-agent",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"volumes": [
{
"name": "storage",
"efsVolumeConfiguration": {
"fileSystemId": "<your-efs-id>",
"rootDirectory": "/"
}
}
]
}# Build and push image
gcloud builds submit --tag gcr.io/<project-id>/qwen-agent
# Deploy to Cloud Run
gcloud run deploy qwen-agent \
--image gcr.io/<project-id>/qwen-agent \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars LOG_LEVEL=INFO \
--set-env-vars OPENAI_API_KEY=$OPENAI_API_KEY \
--port 8000# Create resource group
az group create --name qwen-agent-rg --location eastus
# Create container
az container create \
--resource-group qwen-agent-rg \
--name qwen-agent \
--image <your-registry>/qwen-agent:latest \
--cpu 1 \
--memory 2 \
--ports 8000 7860 \
--environment-variables LOG_LEVEL=INFO \
--secure-environment-variables OPENAI_API_KEY=$OPENAI_API_KEY \
--restart-policy AlwaysLogs are stored in storage/logs/:
storage/logs/
├── app.log # Application logs
├── error.log # Error logs
└── scheduler.log # Scheduler logs
Configure in config/app.yaml:
logging:
level: INFO
format: "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}"
rotation: "100 MB"
retention: "30 days"
compression: zip# Check API health
curl http://localhost:8000/health
# Check scheduler status
curl http://localhost:8000/v1/tasks
# Monitor system resources
python -c "from core.resource_limiter import SystemResourceMonitor; import json; print(json.dumps(SystemResourceMonitor.get_system_stats(), indent=2))"Use Prometheus + Grafana:
# Add to main.py
from prometheus_client import start_http_server, Counter, Histogram
# Define metrics
request_counter = Counter('api_requests_total', 'Total API requests')
task_counter = Counter('tasks_executed_total', 'Total tasks executed')
# Start metrics server
start_http_server(9090)- Never commit
.envfiles - Use different API keys for dev/prod
- Rotate keys regularly
- Use secret management services:
# AWS Secrets Manager
aws secretsmanager get-secret-value --secret-id qwen-agent/keys
# HashiCorp Vault
vault kv get -field=api_key secret/qwen-agent- Use HTTPS in production
- Configure CORS properly
- Use firewall rules:
- Only expose ports 8000, 7860
- Limit IP access if possible
- Use reverse proxy (nginx):
server {
listen 443 ssl;
server_name agent.example.com;
ssl_certificate /etc/ssl/certs/agent.crt;
ssl_certificate_key /etc/ssl/private/agent.key;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}For production, use strict security:
from core.security import create_strict_policy
# In config/app.yaml
sandbox:
enabled: true
max_memory_mb: 512
max_cpu_time: 30
network_access: false
allow_command_execution: false1. Agent Initialization Failed
ERROR: Failed to create agent: Invalid model cfg
Solution: Check LLM configuration in config/llm.yaml and verify API keys.
2. MCP Server Connection Timeout
WARNING: Failed to connect to MCP server: timeout
Solution:
- Verify MCP server is running
- Check command and arguments in
config/mcp_servers.yaml - Ensure required environment variables are set
3. Task Not Executing
Error running job: Agent 'researcher' not found
Solution:
- Verify agent exists and is enabled
- Check agent configuration
- Review scheduler logs
4. High Memory Usage
Resource violation: Memory usage 600MB exceeds 512MB
Solution:
- Adjust
max_memory_mbin sandbox config - Check for memory leaks in agent code
- Monitor with
psutil
Enable debug logging:
export LOG_LEVEL=DEBUG
python main.pyEnable verbose output:
import logging
logging.basicConfig(level=logging.DEBUG)Restore from backup:
# Stop services
sudo systemctl stop qwen-agent
# Restore storage
cp -r /backup/storage/* /opt/qwen-agent/storage/
# Restart services
sudo systemctl start qwen-agentClear task persistence:
# Backup first
cp storage/tasks/tasks.json storage/tasks/tasks.json.backup
# Clear tasks
echo '{"tasks": [], "updated_at": null}' > storage/tasks/tasks.json
# Restart
sudo systemctl restart qwen-agent# Add connection pooling
from sqlalchemy.pool import QueuePool
engine = create_async_engine(
DATABASE_URL,
poolclass=QueuePool,
pool_size=10,
max_overflow=20,
)# Add Redis caching
import redis
from functools import lru_cache
redis_client = redis.Redis(host='localhost', port=6379)
@lru_cache(maxsize=1000)
def get_agent_config(agent_name: str):
return config_manager.get_agent(agent_name)Use nginx as load balancer:
upstream qwen_agent_backend {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
listen 80;
location / {
proxy_pass http://qwen_agent_backend;
}
}