Package Your Crew as a Service
Wrap the crew behind a thin API layer (FastAPI is the typical choice). Inputs in, structured output out.
FastAPI wrapper
from fastapi import FastAPI
from pydantic import BaseModel
from my_crew import build_crew # your factory function
app = FastAPI()
class RunRequest(BaseModel):
topic: str
@app.post("/run")
def run(req: RunRequest):
crew = build_crew()
result = crew.kickoff(inputs={"topic": req.topic})
return {"output": str(result)}
Async Execution & Queuing
Crews can take 30s–10min. Synchronous HTTP is the wrong shape — use a job queue.
Celery worker
from celery import Celery
from my_crew import build_crew
app = Celery("crews", broker="redis://localhost:6379/0")
@app.task(bind=True, max_retries=3)
def run_crew_async(self, topic: str):
try:
crew = build_crew()
result = crew.kickoff(inputs={"topic": topic})
return str(result)
except Exception as e:
raise self.retry(exc=e, countdown=30)
Dockerizing
For the full Docker command reference — images, volumes, networking, multi-stage builds — see the Docker cheatsheet.
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Secrets Management
Never bake API keys into images. Inject at runtime.
Runtime secrets
docker run -e OPENAI_API_KEY=$OPENAI_API_KEY \
-e SERPER_API_KEY=$SERPER_API_KEY \
-p 8000:8000 my-crew:latest
In production: AWS Secrets Manager, GCP Secret Manager, or Kubernetes secrets.
Scaling Patterns
Horizontal worker pool
Each crew run is independent — spin up N workers behind a queue. Scale on queue depth.
LLM rate-limit handling
Catch RateLimitError at the worker level, exponential backoff, requeue. Don't let one crew's retry block the pool.
Caching
Cache deterministic tool calls (web scrapes of stable URLs, DB lookups). Cuts cost dramatically on retries.
YAML Config (Recommended)
For non-trivial crews, define agents and tasks in YAML — easier to review, version, and let non-engineers edit. Map rows to executable @task methods on a CrewBase class as shown below.
The CrewBase class decorator wires those YAML files to @agent, @task, and @crew methods in the pattern below.
agents.yaml
researcher:
role: Senior Research Analyst
goal: Find current information on {topic}
backstory: >
You are a meticulous analyst with a decade of experience.
You cite sources and never speculate.
writer:
role: Tech Writer
goal: Turn research notes into a 200-word brief
backstory: >
You write punchy, jargon-light explainers for engineering managers.
Loading YAML in Python
Project crews typically combine @CrewBase with @before_kickoff for input checks, then factory methods marked @agent, @task, and a single @crew assembler.
from crewai.project import CrewBase, agent, task, crew, before_kickoff
@CrewBase
class ResearchCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def researcher(self): return Agent(config=self.agents_config["researcher"])
@task
def research_task(self): return Task(config=self.tasks_config["research_task"])
@crew
def crew(self): return Crew(agents=self.agents, tasks=self.tasks, process=Process.sequential)
Notes
LLM workers are memory-heavy
Concurrency limits should account for model client buffers, not only CPU. Set worker autoscaling on queue latency and GPU or RAM pressure, not just request count.
Graceful shutdown must drain queues
Killing pods mid-kickoff creates zombie external actions. Stop accepting new jobs, wait for in-flight crews with budgets, and mark partial results explicitly.
Secrets belong in vaults, not repo config
Docker images should mount runtime secrets. Baking keys into layers is a common regression when moving from laptops to Kubernetes.
Health checks should validate model reachability
HTTP 200 on your API does not prove OpenAI or Anthropic is healthy. Lightweight provider probes prevent routing traffic into guaranteed failures.
CrewAI production FAQ
How should I expose CrewAI over HTTP?
Put a thin API layer in front that authenticates callers, validates inputs, enqueues work, and streams results or webhooks instead of blocking workers.
What queueing pattern fits CrewAI workloads?
Use a durable queue with retries and dead-letter handling because LLM calls are slow and may fail transiently. Never run unbounded synchronous crews inside web request threads.
How do I package CrewAI in Docker?
Bake dependencies, pin versions, inject secrets at runtime, and ship non-root users with read-only root filesystems where possible.
What health checks matter for CrewAI services?
Check dependency connectivity to model providers, queue depth, worker liveness, and periodic smoke kickoffs that validate credentials.
How do I roll out CrewAI changes safely?
Use feature flags, shadow traffic, and golden eval suites so prompt or model updates do not silently regress customer-facing automation.
See also: DevShelfHub's CrewAI tool review for a product-level comparison, pricing notes, and links back into this tutorial series.