---
title: "Add Caveman to AgentOps: compress a CrewAI crew"
description: "This guide adds Caveman Middleware to a CrewAI crew that AgentOps already records. AgentOps keeps doing what it does: same agentops.init(), same dashboard, same session replays. You wrap one agent, ru"
canonical: https://caveman.ac/switch/agentops
last-updated: 2026-10-04
---

# Add Caveman to AgentOps: compress a CrewAI crew

This guide adds Caveman Middleware to a CrewAI crew that AgentOps already records. AgentOps keeps doing what it does: same `agentops.init()`, same dashboard, same session replays. You wrap one agent, run the crew twice with tagged traces, and compare. For the background, read [Caveman vs AgentOps](/compare/agentops).

CrewAI is the example because AgentOps instruments it out of the box. The same steps work with Caveman's AutoGen, LangChain, Agno and LiteLLM adapters. Entry points and version ranges are on the [frameworks page](https://docs.caveman.so/docs/sdk/middleware/frameworks).

## What do you need before you start?

You need a crew AgentOps already records, and one agent whose tools return a lot of text: search results, logs, file reads, API payloads. Open a recent AgentOps replay and pick the agent whose calls carry the biggest tool results. That is the one to wrap first.

Check versions. `caveman-middleware` needs Python 3.13 or newer, and the CrewAI adapter accepts `crewai >=1.15 <2`. Outside that range it declines and passes calls through untouched.

## Step 1: Start the Caveman runtime

The middleware sends candidates to a local runtime that compresses them and keeps the originals on disk:

```bash
npm install -g @caveman-ai/cli && caveman setup --install
CAVEMAN_MODE=compress caveman start
```

Plain `caveman start` runs in `record` mode, which measures and changes nothing. Set `compress` on the runtime and switch the baseline on the client side instead, so the two runs differ in one setting.

## Step 2: Wrap one agent, keep AgentOps as it is

```bash
pip install caveman-sdk "caveman-middleware[crewai]==0.1.0a1"
```

`with_caveman_agent` takes the keyword arguments you already pass to CrewAI's `Agent` and returns new ones. Role, goal and backstory pass through untouched. It wraps the `llm` and adds the `caveman_retrieve` tool:

```python
import os, uuid
import agentops
from crewai import Agent, LLM
from caveman_cloud.middleware import MiddlewareRuntime, Scope
from caveman_middleware.crewai import with_caveman_agent

agentops.init(auto_start_session=False)  # reads AGENTOPS_API_KEY

mode = os.environ.get("CAVEMAN_CLIENT_MODE", "compress")
runtime = MiddlewareRuntime(mode=mode)
if mode != "off":
    runtime.ready()  # raises if the runtime is unreachable
run_id = str(uuid.uuid4())

analyst = Agent(**with_caveman_agent({
    "role": "Log analyst",
    "goal": "Find the root cause in the service logs",
    "backstory": "You read logs and recover original evidence when needed.",
    "llm": LLM(model="gpt-4.1-mini"),
    "tools": [read_logs],  # your existing tools
}, runtime=runtime, scope=Scope("triage", f"{run_id}-analyst", "main", "0")))
```

Give each agent context its own `Scope`. The four parts key the stored originals, so a handle only resolves under the scope that created it.

The rest of the crew, tasks and process stay the same.

## Step 3: Record two tagged sessions

Wrap the crew run in an AgentOps trace tagged with the mode:

```python
trace = agentops.start_trace("triage", tags=[f"caveman-{mode}"])
result = crew.kickoff(inputs={"service": "checkout"})
agentops.end_trace(trace, end_state="Success")
```

```bash
CAVEMAN_CLIENT_MODE=record python triage.py
CAVEMAN_CLIENT_MODE=compress python triage.py
```

Same inputs, same model, same tools. The `record` run is your baseline: the runtime measures each call and sends the original bytes.

## How do you check it worked?

Open the two sessions in AgentOps side by side and work through this list.

1. **The analyst's model calls.** Search the `compress` replay for `caveman: shortened`. AgentOps hooks CrewAI's LiteLLM-backed `LLM.call`; CrewAI 1.x routes `gpt-4.1-mini` to a native OpenAI class, so if the replay shows no model spans, pass `is_litellm=True` to `LLM(...)` (needs `litellm` installed) or read the Caveman reports below instead. The tool span keeps the full original.
2. **Recovery calls.** Count `caveman_retrieve` tool calls. Each carries the original back and costs tokens.
3. **Extra turns.** Compare iterations, retries and delegations across every agent. If the writer asks the analyst twice, that cost belongs in the total.
4. **Tokens.** Compare provider-reported input tokens for the whole session, every agent included. Where AgentOps records the model call, it takes usage from the provider response, so it reflects what was actually sent.
5. **The deliverable.** Judge both final outputs with the acceptance check you already trust. AgentOps shows how the runs differed; your check decides whether the result is still correct.

For a per-call decision, pass `on_report=print` to `MiddlewareRuntime`. `applied` or `reused` means a tool result was shortened. `skipped` comes with a reason, such as `no_candidate` when the call had no eligible tool result.

## What if the agents run on different machines?

A handle resolves only against the runtime that stored the original. If the analyst and the writer run in separate containers and both may call `caveman_retrieve`, point them at one shared runtime. That needs a token, TLS and explicit consent to send content off the machine, all covered in the [deployment docs](https://docs.caveman.so/docs/sdk/middleware/deployment#a-runtime-on-another-host). Until that's set up, wrap only agents that share a host with the runtime.

## How do you roll back?

Build the agent from the original dict again: `Agent(role=..., llm=LLM(...), tools=[read_logs])`. `with_caveman_agent` returns new options and mutates nothing. To switch off without a code change, set `CAVEMAN_CLIENT_MODE=off`. AgentOps was never modified, so both tagged sessions stay in the dashboard for reference.

Keep the runtime running until in-flight crews finish, because a handle the model already holds needs the stored original. Grants last 24 hours from their last use.

## Where to go next

- [Caveman vs AgentOps](/compare/agentops) for which span shows which copy
- [Python middleware docs](https://docs.caveman.so/docs/sdk/middleware/python) for the AutoGen, LangChain and Agno adapters
- [AgentOps docs](https://docs.agentops.ai/v2/introduction) for traces and tags
- [Measure agent cost](/guides/measure-agent-cost) for a fair two-arm comparison
