> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CrewAI

> Trace CrewAI multi-agent crews with OpenInference and send spans to Arize AX for LLM observability.

[CrewAI](https://www.crewai.com/) is a Python framework for orchestrating role-playing autonomous agents — agents collaborate on tasks, hand off work, and call tools. Arize AX captures every CrewAI run — Crew / Agent / Task spans plus the underlying LLM calls — via the [`openinference-instrumentation-crewai`](https://github.com/Arize-ai/openinference/tree/main/python/instrumentation/openinference-instrumentation-crewai) package, paired with an LLM-level instrumentor matching the provider CrewAI routes to.

<CardGroup>
  <Card horizontal icon="https://storage.googleapis.com/arize-phoenix-assets/assets/images/phoenix-docs-images/gc.ico" href="http://colab.research.google.com/github/Arize-ai/tutorials/blob/main/python/llm/tracing/crewai/crewai-tracing.ipynb" title="CrewAI Tracing Tutorial (Google Colab)" />
</CardGroup>

## Prerequisites

* Python 3.10+
* An Arize AX account ([sign up](https://arize.com/sign-up/))
* An `OPENAI_API_KEY` from the [OpenAI Platform](https://platform.openai.com/api-keys)
* CrewAI 1.0+ (this guide uses the native-SDK routing model introduced in 1.0; for 0.x see [Troubleshooting](#troubleshooting))

## Launch Arize AX

1. Sign in to your [Arize AX account](https://app.arize.com/).
2. From **Space Settings**, copy your **Space ID** and **API Key**. You will set them as `ARIZE_SPACE_ID` and `ARIZE_API_KEY` below.

## Install

```bash theme={null}
pip install arize-otel \
  openinference-instrumentation-crewai \
  openinference-instrumentation-openai \
  crewai
```

<Note>
  CrewAI 1.0+ routes LLM calls based on the model-string prefix: `openai/...` and bare model names go to the native OpenAI SDK, `anthropic/...` goes to Anthropic, etc. The LLM-level instrumentor must match the provider CrewAI is actually calling. The example below uses `openai/gpt-5` so it pairs `openinference-instrumentation-crewai` with `openinference-instrumentation-openai`. Other prefixes need a different pairing — see [Which instrumentor do I need?](#which-instrumentor-do-i-need) below.
</Note>

## Which instrumentor do I need?

CrewAI 1.0+ routes LLM calls to different provider SDKs based on your model string. Match your LLM-level instrumentor to the provider CrewAI is actually calling:

| Model string                                                   | Provider SDK used  | Instrumentor package                      |
| -------------------------------------------------------------- | ------------------ | ----------------------------------------- |
| `openai/gpt-5`, `gpt-5`, or no prefix                          | OpenAI (native)    | `openinference-instrumentation-openai`    |
| `anthropic/claude-sonnet-4-6`                                  | Anthropic (native) | `openinference-instrumentation-anthropic` |
| Groq, Together, or other providers without a native CrewAI SDK | LiteLLM (fallback) | `openinference-instrumentation-litellm`   |

The **CrewAI instrumentor** (`openinference-instrumentation-crewai`) is always required regardless of provider — it captures Crew, Agent, and Task spans.

## Configure credentials

```bash theme={null}
export ARIZE_SPACE_ID="<your-space-id>"
export ARIZE_API_KEY="<your-api-key>"
export ARIZE_PROJECT_NAME="crewai-tracing-example"
export OPENAI_API_KEY="<your-openai-api-key>"
```

## Setup tracing

```python theme={null}
# instrumentation.py
import os

from arize.otel import register
from openinference.instrumentation.crewai import CrewAIInstrumentor
from openinference.instrumentation.openai import OpenAIInstrumentor

tracer_provider = register(
    space_id=os.environ["ARIZE_SPACE_ID"],
    api_key=os.environ["ARIZE_API_KEY"],
    project_name=os.environ["ARIZE_PROJECT_NAME"],
)

# Both instrumentors monkey-patch their target libraries — they must run
# before any `from crewai import ...` or any LLM client construction.
CrewAIInstrumentor().instrument(tracer_provider=tracer_provider)
OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
print("Arize AX tracing initialized for CrewAI.")
```

## Run CrewAI

```python theme={null}
# example.py

# Importing instrumentation first ensures both instrumentors run before
# CrewAI is imported. Out-of-order imports silently drop spans.
from instrumentation import tracer_provider

from crewai import Agent, Crew, LLM, Task

# `openai/gpt-5` tells CrewAI 1.0+ to use the native OpenAI SDK, which
# OpenAIInstrumentor patches. It reads OPENAI_API_KEY from the env.
llm = LLM(model="openai/gpt-5")

researcher = Agent(
    role="Ocean researcher",
    goal="Explain ocean facts to a general audience.",
    backstory="You are a marine scientist who values brevity.",
    llm=llm,
    allow_delegation=False,
    verbose=False,
)

writer = Agent(
    role="Science writer",
    goal="Turn researcher notes into a clean two-sentence summary.",
    backstory="You write clear, concise prose for a general audience.",
    llm=llm,
    allow_delegation=False,
    verbose=False,
)

research_task = Task(
    description=(
        "Explain why the ocean is salty. List the two primary mechanisms."
    ),
    expected_output="A short factual paragraph naming the two mechanisms.",
    agent=researcher,
)

writeup_task = Task(
    description=(
        "Using the researcher's notes, produce exactly two sentences "
        "for a general reader. No preamble."
    ),
    expected_output="Exactly two sentences, no headings.",
    agent=writer,
)

crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writeup_task],
    verbose=False,
)

result = crew.kickoff()
print(result)
```

### Expected output

```text wrap theme={null}
Arize AX tracing initialized for CrewAI.
The ocean is salty because rivers continuously dissolve mineral salts from rocks and soil and carry them to the sea, where they accumulate over millions of years. Water leaves the ocean through evaporation but the salts remain, steadily concentrating until reaching today's roughly 3.5% salinity.
```

## Verify in Arize AX

1. Open your Arize AX space and select project **`crewai-tracing-example`**.
2. You should see a new trace within \~30 seconds with this shape: a `Crew_<uuid>.kickoff` root span (CHAIN) wraps `Crew Created`, per-agent `<role>._execute_core` (AGENT), and per-task `Task Created` / `Task Execution` spans. Each task's `Task Execution` wraps a `ChatCompletion` LLM span (model `gpt-5-2025-08-07`, with prompt, response, and token usage attached).
3. If no traces appear, see [Troubleshooting](#troubleshooting).

## Troubleshooting

* **No traces in Arize AX.** Confirm `ARIZE_SPACE_ID` and `ARIZE_API_KEY` are set in the same shell that runs `example.py`. Enable OpenTelemetry debug logs with `export OTEL_LOG_LEVEL=debug` and re-run.
* **Crew / Agent / Task spans appear but no LLM spans.** The LLM-level instrumentor doesn't match the provider CrewAI is calling. CrewAI 1.0+ routes by model-string prefix:
  * `openai/<model>` (or no prefix) → install `openinference-instrumentation-openai`
  * `anthropic/<model>` → install `openinference-instrumentation-anthropic`
  * Groq / Together / providers without a native CrewAI SDK → install `openinference-instrumentation-litellm` (CrewAI falls back to LiteLLM for these)
* **All spans missing — no Crew, no LLM.** This is almost always import order. `CrewAIInstrumentor().instrument(...)` and the LLM-level instrumentor both monkey-patch class methods or module functions; if `crewai` (or the LLM library) is imported before `instrument()` runs, the patches land on stale references and never fire. Make sure `instrumentation.py` is the first import in your entry point — and watch for transitive imports (importing your own `crew.py` module that has `from crewai import ...` at the top has the same effect).
* **`401` from OpenAI.** Verify `OPENAI_API_KEY` is set and has access to `gpt-5`. Swap `openai/gpt-5` in `LLM(model=...)` for a model your key can call.
* **Version-check error from `CrewAIInstrumentor`.** If you're on a CrewAI release candidate that's outside the instrumentor's supported range, escape-hatch with `CrewAIInstrumentor().instrument(skip_dep_check=True, tracer_provider=tracer_provider)`.
* **You're on CrewAI 0.x.** 0.x routes every LLM call through LangChain or LiteLLM rather than provider-native SDKs. Pair the CrewAI instrumentor with both `openinference-instrumentation-langchain` and `openinference-instrumentation-litellm` instead of `openinference-instrumentation-openai`. The Setup tracing call list becomes `CrewAIInstrumentor().instrument(...)` + `LangChainInstrumentor().instrument(...)` + `LiteLLMInstrumentor().instrument(...)`. Upgrade to 1.0+ when you can — the [LiteLLM removal guide](https://docs.crewai.com/en/learn/litellm-removal-guide) covers the migration.

## Resources

<CardGroup>
  <Card icon="book-open" href="https://docs.crewai.com/" title="CrewAI Documentation" horizontal />

  <Card icon="book-open" href="https://docs.crewai.com/en/concepts/llms" title="CrewAI LLM Provider Routing" horizontal />

  <Card icon="terminal" href="https://github.com/Arize-ai/openinference/tree/main/python/instrumentation/openinference-instrumentation-crewai" title="OpenInference CrewAI Instrumentor" horizontal />

  <Card icon="github" href="https://github.com/crewAIInc/crewAI" title="CrewAI GitHub" horizontal />
</CardGroup>
