Cost-audit series, episode 3. This series began with an AI agent that burned 136M tokens overnight →.
CrewAI is one of the most-starred agent orchestration frameworks on GitHub. Its pitch is intuitive: define a crew of role-playing agents, assign tasks, watch them collaborate. What the README doesn't tell you is that the default context-passing model has a quadratic token cost curve. A 5-agent crew doesn't cost 5× a solo agent — on input tokens it costs closer to 6×, and once you stack memory, delegation, and verbose mode it climbs to 8–15×. The multiplier grows with every agent or task you add.
This audit shows you exactly where the tokens go, with line numbers.
CrewAI executes tasks sequentially (by default). Each task has an optional context
list — a list of other tasks whose outputs should be available to the executing agent. When you don't specify context
explicitly, CrewAI's default behavior is to make all previously completed tasks available to each subsequent agent. The output of Task 1 goes into Task 2's prompt. Task 1 + Task 2 outputs go into Task 3's prompt. And so on.
This is linear accumulation — and it produces a quadratic total token count.
** src/crewai/crew.py** — the
Crew._get_context
method (line 792 at tag 0.80.0):
def _get_context(self, task: Task, task_outputs: List[TaskOutput]):
context = (
aggregate_raw_outputs_from_tasks(task.context)
if task.context
else aggregate_raw_outputs_from_task_outputs(task_outputs)
)
return context
Source: src/crewai/crew.py#L792
The decisive branch is the else
: when a task sets no explicit context, CrewAI falls back to
aggregate_raw_outputs_from_task_outputs(task_outputs)
— the outputs of crewai/utilities
) serializes each prior task's full raw output into the string that gets injected into the current task's prompt. There is no summarization, no truncation, no deduplication. The string grows with every task.** src/crewai/crew.py** — the task execution loop lives in
Crew._execute_tasks
(defined at line 635 at tag 0.80.0; the context-injection call is at line 696). Simplified to the two lines that matter:
context = self._get_context(task, task_outputs) # task_outputs = every prior task's output
task_output = task.execute_sync(
agent=agent_to_use, context=context, tools=agent_to_use.tools
)
Source: src/crewai/crew.py (method
_execute_tasks
)task_outputs
is the running list of every prior task's output, so it grows as the crew progresses. Each call to execute_sync
constructs a full prompt that includes that accumulated context string, and it is sent with every LLM API request — not cached between tasks (CrewAI doesn't use prompt caching by default).
Assume:
Token count for Task k = T_system + (k-1) × T_task (accumulated context from all prior tasks)
| Task | Context tokens | System + task | Total input tokens |
|---|---|---|---|
| 1 | 0 | 800 | 800 |
| 2 | 500 | 800 | 1,300 |
| 3 | 1,000 | 800 | 1,800 |
| 4 | 1,500 | 800 | 2,300 |
| 5 | 2,000 | 800 | 2,800 |
| Total | |||
| 5,000 | |||
| 4,000 | |||
| 9,000 |
A naive model would predict 5 × 800 = 4,000 input tokens. The actual bill is 9,000 — 2.25× for just five tasks with modest outputs. Now scale up:
| Task | Context tokens | System + task | Total input tokens |
|---|---|---|---|
| 1 | 0 | 800 | 800 |
| 2 | 2,000 | 800 | 2,800 |
| 3 | 4,000 | 800 | 4,800 |
| 4 | 6,000 | 800 | 6,800 |
| 5 | 8,000 | 800 | 8,800 |
| Total | |||
| 20,000 | |||
| 4,000 | |||
| 24,000 |
Now you're at 6× the naive estimate — and that's input tokens only. Add output tokens from each task (another ~2,000 × 5 = 10,000) and the total API cost for one crew run is 34,000 tokens instead of the ~14,000 you'd expect.
With claude-sonnet-4-6 ($3/M input, $15/M output):
Now run 50 crew executions per day:
For a SaaS product with hundreds of daily crew runs, this gap becomes tens of thousands of dollars per month — and it gets worse as you add agents or as task outputs grow.
CrewAI's memory=True
flag (off by default, but heavily promoted) activates four memory systems:
class ShortTermMemory(Memory):
def search(self, query: str, score_threshold: float = 0.35):
return self.storage.search(query=query, score_threshold=score_threshold)
Source: src/crewai/memory/short_term/short_term_memory.py
Short-term memory retrieves every stored item scoring above a similarity threshold (default 0.35
) and appends them to the prompt — the count is unbounded, so a longer run history injects more retrieved context per task. Long-term memory hits an SQLite database. Entity memory maintains structured entity descriptions. Semantic memory uses ChromaDB embeddings — each retrieval costs an embedding API call plus the tokens from the retrieved chunks injected into the prompt.
With memory=True
on a 10-run crew history, expect +1,500–3,000 tokens per task in retrieval overhead.
verbose=True
(the default in most tutorials)
Most CrewAI tutorials set verbose=True
or verbose=2
. This surfaces the agent's intermediate reasoning — but the real cost driver isn't the logging, it's the ReAct loop underneath it. CrewAI runs its own CrewAgentExecutor
(not LangChain's), and each agent step accumulates the full "Thought / Action / Observation" trace back into the LLM prompt for the next iteration. Each tool call adds another round of Thought + Action + Observation tokens before the final answer. For an agent that calls 3 tools, this can add 800–2,000 tokens per task.
allow_delegation=True
) When an agent can delegate to another, it can route subtasks to specialist agents mid-task. This is CrewAI's "hierarchical" feature. The cost: each delegation creates a new complete LLM call with the delegating agent's accumulated context inherited into the delegatee's prompt. A single task can spawn 2–3 delegation chains, each carrying the full context blob from above.
Let's measure a concrete 3-agent research crew using @wartzar-bee/tokenscope
:
npx @wartzar-bee/tokenscope crew-session.jsonl
For a crew with:
The per-agent context accumulation (illustrative — tokenscope reports the session total you can check this against, not a per-agent split):
Per-agent context accumulation:
researcher → input: 1,100 output: 1,800 (system + task only)
analyst → input: 2,900 output: 1,200 (+1,800 context from researcher)
writer → input: 4,100 output: 2,000 (+1,800 + 1,200 context from prior two)
Total input: 8,100
Total output: 5,000
Session total: 13,100 tokens
Naive estimate (no context accumulation): 8,300 tokens
Actual multiplier: 1.58×
This is a modest crew. Bump to 5 agents with research-heavy outputs and the multiplier reaches 4–6×. Add memory and delegation: 8–15×.
CrewAI lets you control which tasks feed context to which. Use the context
parameter explicitly:
from crewai import Task
research_task = Task(
description="Find the top 3 cloud cost optimization techniques.",
agent=researcher,
)
analysis_task = Task(
description="Analyze the techniques and rank by ROI.",
agent=analyst,
context=[research_task], # only research output, not all prior tasks
)
writing_task = Task(
description="Write a 500-word summary of the #1 technique.",
agent=writer,
context=[analysis_task], # only the analysis — researcher output not needed here
)
Result: the writer agent sees only the analyst's output (~1,200 tokens), not the researcher's raw output + the analyst's output (3,000 tokens). Context tokens halved on the most expensive task.
For longer pipelines, consider a summary task: a cheap, short-output task that condenses prior results, and only its output flows forward. The cost of the summarization step is far less than sending raw outputs through N subsequent agents.
If you're running CrewAI in production, the default LLM logging doesn't surface how much of each call is re-sent accumulated context. Point tokenscope at a session transcript to see it:
npm install -g @wartzar-bee/tokenscope
Export your run as a session JSONL (a Claude Code session under ~/.claude/projects
, or any transcript in that format), then:
npx @wartzar-bee/tokenscope crew-session.jsonl
npx @wartzar-bee/tokenscope crew-session.jsonl --json
You'll see the session total, how much is new work versus re-sent accumulated context, and where the growth is steepest — the accumulation this whole post is about.
CrewAI's default context model accumulates all prior task outputs into every subsequent agent's prompt. This produces a quadratic total token count as N grows — not linear. The practical impact at modest scale (5 agents, 2,000-token outputs): 4–6× the token count you'd expect. Add memory layers, delegation, and verbose mode: 8–15×.
The fix is explicit context scoping: pass only the task outputs that each agent actually needs. It's a one-line change per task, and it can halve your API bill immediately.
Next in the series: we'll look at LangGraph's token footprint — the stateful graph model has a different cost shape, and it's worth understanding before you migrate from LangChain to LangGraph chasing efficiency gains.
wartzar-bee builds tools for operating cost-efficient autonomous agents. tokenscope is free and open-source. Follow on dev.to →