К основному содержанию
скилл CX Codex

check-crewai-api — скилл для Claude Code: актуальный API crewai 1.15.x

Скилл сверяет код crewai с версией 1.15.x вместо устаревшего 0.x, который помнят ассистенты. Пригодится, когда импорт или параметр молча не работают.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add crewAIInc/skills --skill check-crewai-api -a claude-code
Открыть на GitHub

Что делает check-crewai-api

Ассистенты уверенно пишут crewai по памяти — и память эта из 0.x. Скилл подгружает карту соответствий: какие импорты переехали, какие параметры Agent, Task и Crew реально существуют в 1.15.x, что стало значением по умолчанию. Например, Task.expected_output теперь обязателен, Agent.max_iter равен 25, а Process.consensual больше нет.

Внутри — таблицы по импортам, параметрам, вариантам kickoff, полям CrewOutput, строкам моделей LLM, структурированному выводу, guardrails, единой Memory, knowledge embedders, мастеру crewai create crew против --classic и флагам сброса памяти. Отдельно разобраны ошибки, которые чаще всего приносят в чат: cannot import name 'BaseTool' from 'crewai_tools', cannot import name 'persist', got an unexpected keyword argument 'response_format', result.pydantic is None.

Главная ловушка описана первым правилом: неизвестные именованные аргументы Agent, Task и Crew принимаются и молча отбрасываются. Task(response_format=Model) создастся без ошибки и не сделает ничего. Поэтому скилл советует проверять поля через model_fields и смотреть на установленный исходник, а не на документацию или AGENTS.md. Сверка шла против crewai 1.15.22 и 1.15.23; если crewai version показывает другую мажорную или минорную версию, строки просят перепроверить.

Какие задачи решает

  • переписать импорты crewai под 1.15.x после переезда с 0.x
  • найти параметр, который молча игнорируется вместо ошибки
  • разобрать ImportError на BaseTool или persist
  • проверить структурированный вывод, когда result.pydantic пустой
  • сверить сигнатуры установленной версии перед правкой кода

Примеры запросов агенту

  • Проверь мой код crewai по актуальному API 1.15.x, начни с импортов и параметров Agent и Task
  • У меня падает cannot import name 'BaseTool' from 'crewai_tools' — что заменить?
  • result.pydantic возвращает None, хотя запуск прошёл успешно. Где ошибка?

Как установить check-crewai-api

1Через Skills CLI (Vercel)

npx skills add crewAIInc/skills --skill check-crewai-api -a claude-code

2Вручную: положить файлы

~/.claude/skills/check-crewai-api/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/check-crewai-api/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора5

Похожие

crewai davila7 Помогает проектировать команды ИИ-агентов на CrewAI: роли, задачи, оркестрация и процессы. Пригодится, когда один агент уже не тянет. 141установок agents-crewai Orchestra Research Скилл для сборки команд автономных агентов с ролями, памятью и последовательным или иерархическим выполнением задач. 371установок gemini-api-dev официальный google-gemini Помогает писать код для Gemini API на Python и TypeScript по актуальным правилам SDK: от вызова моделей до миграции с устаревшего generateContent. CX Codex +1 25 100установок langchain4j-ai-services-patterns giuseppe-trisciuoglio Скилл показывает, как собирать декларативные AI Services на LangChain4j: интерфейсы, аннотации, память и вызов инструментов. CX Codex +1 3 700установок langchain4j-tool-function-calling-patterns giuseppe-trisciuoglio Скилл подсказывает агенту, как описывать Java-методы через @Tool, регистрировать их в AiServices и обрабатывать ошибки вызова. CX Codex +1 3 700установок multi-agent-orchestration qodex-ai Помогает проектировать совместную работу нескольких ИИ-агентов, распределять задачи между ними и объединять результаты. Пригодится при настройке сложных цепочек с разделением ролей. CX Codex +1 2 100установок

Рядом в теме «ИИ и ML»

Всё по теме «ИИ и ML» →

Вопросы о check-crewai-api

Как установить check-crewai-api в Claude?

Выполните npx skills add crewAIInc/skills --skill check-crewai-api -a claude-code. Файл скилла появится по пути ~/.claude/skills/check-crewai-api/SKILL.md.

Что делает check-crewai-api?

Сопоставляет то, что ассистент помнит про crewai, с тем, что принимает версия 1.15.x: импорты, параметры и значения по умолчанию, варианты kickoff, поля CrewOutput, структурированный вывод, guardrails, Memory и удалённые возможности.

Для каких версий crewai он актуален?

Сверка проводилась против crewai 1.15.22 и 1.15.23. Если crewai version даёт другую мажорную или минорную версию, строки просят перепроверить по установленному исходнику.

Исходный текст

SKILL.md · MIT
---
name: check-crewai-api
description: "Current crewai 1.15.x API versus the 0.x API that coding assistants remember: imports, Agent/Task/Crew parameters and defaults, kickoff variants, CrewOutput fields, LLM model strings and provider extras, structured output (output_pydantic, response_model, response_format), guardrails, unified Memory, knowledge embedders, the `crewai create crew` wizard vs --classic, reset-memories flags, and removed features. Use when writing, reviewing, or debugging any crewai code, before trusting remembered crewai syntax, or when a user pastes errors like `cannot import name 'BaseTool' from 'crewai_tools'`, `cannot import name 'persist'`, `ShortTermMemory`, `Anthropic native provider not available`, `LiteLLM fallback package is not installed`, `got an unexpected keyword argument 'response_format'`, `OPENAI_API_KEY is required`, `If return type is annotated, it must be Tuple[bool, Any]`, or `result.pydantic is None`."
---

# Check CrewAI API

Load this before writing or reviewing crewai code: it maps what you probably remember to what crewai 1.15.x actually accepts.

Verified against crewai 1.15.22 and 1.15.23 on 2026-10-01.
Live-tested with real LLMs on 2026-10-01.
Run `crewai version` first; if the major/minor differs from 1.15, re-verify version-sensitive rows with the `ask-docs` skill before trusting them.

---

## 1. Three rules before you write anything

1. **Unknown keyword arguments are silently ignored.** `Agent`, `Task` and `Crew` accept and drop parameters that do not exist. `Crew(memory_config={...})` and `Task(response_format=Model)` construct fine and do nothing. A stale parameter name never raises, so check it exists:

   ```python
   from crewai import Agent, Crew, Task

   assert "response_model" in Task.model_fields      # real field
   assert "response_format" not in Task.model_fields  # silently dropped if passed
   assert "memory_config" not in Crew.model_fields    # silently dropped if passed
   print(sorted(Agent.model_fields)[:5])
   ```

2. **The installed source wins over any doc, tutorial, or memory.** That includes the `AGENTS.md` that `crewai create` writes into new projects. When a row below matters, check the installed signature (see [verify-installed-api.md](references/verify-installed-api.md)).
3. **Assert on structured output at the boundary.** Several mistakes below fail quietly with `out.pydantic is None` while the run reports success.

---

## 2. Imports

| You probably wrote | Current 1.15.x form | What the wrong form does |
|---|---|---|
| `from crewai_tools import BaseTool, tool` | `from crewai.tools import BaseTool, tool` | `ImportError: cannot import name 'BaseTool' from 'crewai_tools'` |
| `from crewai.flow.flow import Flow, start, listen, persist` | `from crewai.flow import Flow, start, listen, router, or_, and_, persist` | `ImportError: cannot import name 'persist'` |
| `from crewai.task import ConditionalTask` | `from crewai.tasks.conditional_task import ConditionalTask` | `ImportError` |
| `from crewai.memory import ShortTermMemory, LongTermMemory, EntityMemory` | `from crewai import Memory` | `ImportError` (the classes are gone) |
| `from crewai.utilities.events import crewai_event_bus` | `from crewai.events import BaseEventListener, crewai_event_bus` | `ModuleNotFoundError: No module named 'crewai.utilities.events'` |
| `from crewai_tools import CodeInterpreterTool` | No replacement in crewai - use a sandbox tool or service | `ImportError` (removed) |

The current top-level and project imports:

```python
from crewai import Agent, BaseLLM, Crew, CrewOutput, Flow, LLM, Memory, Process, Task, TaskOutput
from crewai.project import CrewBase, after_kickoff, agent, before_kickoff, crew, llm, task, tool
from crewai.tools import BaseTool, tool
from crewai.flow import Flow, and_, listen, or_, persist, router, start
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
from crewai.mcp import MCPServerHTTP, MCPServerSSE, MCPServerStdio
from crewai.events import BaseEventListener, crewai_event_bus
```

---

## 3. Agent, Task, Crew parameters and defaults

| Parameter | Current value | Note |
|---|---|---|
| `Task.expected_output` | **required** | `Task(description=...)` alone raises `ValidationError ... expected_output Field required` |
| `Agent.max_iter` | `25` | Do not assume 15 or 20 |
| `Agent.llm` | `None` -> resolved at construction | From env `MODEL`, then `MODEL_NAME`, then `OPENAI_MODEL_NAME`, else `gpt-4.1-mini` |
| `Agent.cache` | `True` | Only *permits* caching; it does not turn it on |
| `Crew.cache` | `False` | Tool-result caching is opt-in: set `Crew(cache=True)` |
| `Crew.memory` | `False` | |
| `Crew.process` | `Process.sequential` | Only `sequential` and `hierarchical` exist |
| `Task.guardrail_max_retries` | `3` | `max_retries` is deprecated (DeprecationWarning) |

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `Process.consensual` | `Process.sequential` or `Process.hierarchical` | `AttributeError` |
| `Crew(process=Process.hierarchical, ...)` with no manager | add `manager_llm="openai/gpt-4.1-mini"` or `manager_agent=...` | `ValidationError: Attribute manager_llm or manager_agent is required` |
| `Crew(memory=True, memory_config={...})` | `Crew(memory=Memory(...))` | `memory_config` is silently ignored |
| `Agent(allow_code_execution=True)` / `code_execution_mode="unsafe"` | Remove; use a sandbox tool | Deprecated no-ops; `allow_code_execution=True` emits a `DeprecationWarning` |
| `Crew(function_calling_llm=...)` | Remove, or set `llm` per agent | Deprecated, `DeprecationWarning` |
| Two `async_execution=True` tasks with the same `agent` | One agent per concurrent async task | `RuntimeError: Executor is already running. Cannot invoke the same executor instance concurrently.` |

```python
from crewai import Agent, Crew, Process, Task

researcher = Agent(
    role="Researcher",
    goal="Find facts about {topic}",
    backstory="A careful researcher.",
    llm="openai/gpt-4.1-mini",
)
research = Task(
    description="List three facts about {topic}.",
    expected_output="Three bullet points.",
    agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[research], process=Process.sequential, cache=True)
out = crew.kickoff(inputs={"topic": "honey bees"})
print(out.raw)
```

---

## 4. Running a crew and reading the result

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `crew.kickoff("honey bees")` | `crew.kickoff(inputs={"topic": "honey bees"})` | `TypeError: inputs must be a dict or Mapping, got str` |
| `await crew.kickoff_async(...)` for native async | `await crew.akickoff(...)` | Works, but `kickoff_async` runs the sync `kickoff` in a thread (`asyncio.to_thread`) |
| `result.output` / `result.final_output` / `result.result` | `result.raw` | `AttributeError: 'CrewOutput' object has no attribute ...` |
| `crew.kickoff(...)` then `crew.kickoff_for_each(...)` on the same `Crew` | Build a fresh `Crew` for `kickoff_for_each` (or call it before any `kickoff`) | No error, but every run reuses the first kickoff's inputs: the per-run copies keep the already-interpolated task text |
| `Agent(mcps=["https://..."])` in a crew run with `await crew.akickoff()` | `mcps=[MCPServerHTTP(url="https://...")]` (from `crewai.mcp`) | No error, but the agent gets **zero** MCP tools: string refs resolve with `asyncio.run()`, which fails inside a running event loop (see connect-tools-and-mcp) |

`CrewOutput` fields: `raw`, `pydantic`, `json_dict`, `tasks_output` (a list of `TaskOutput`), `token_usage`. `out["field"]` reads from `pydantic`/`json_dict`. `kickoff_for_each(inputs=[...])` returns a list of `CrewOutput`.

`token_usage` is summed over each agent's `LLM` object for that object's whole lifetime, not per run. One `LLM(...)` instance shared by two agents counts every call twice, and one reused across crews carries the earlier crews' tokens (verified with `anthropic/claude-haiku-4-5`: a second one-call crew on the same `LLM` reported 148 tokens and 2 requests, a fresh `LLM` 73 and 1). For per-run cost, give each crew its own `LLM` objects, or count `LLMCallCompletedEvent`s (`event.usage`).

```python
import asyncio

from crewai import Agent, Crew, Task



def make_crew() -> Crew:
    writer = Agent(role="Writer", goal="Write", backstory="Writes short text.", llm="openai/gpt-4.1-mini")
    task = Task(description="One line on {topic}.", expected_output="One line.", agent=writer)
    return Crew(agents=[writer], tasks=[task])


out = make_crew().kickoff(inputs={"topic": "bees"})
print(out.raw, out.token_usage.total_tokens, [t.raw for t in out.tasks_output])

many = make_crew().kickoff_for_each(inputs=[{"topic": "bees"}, {"topic": "ants"}])
print([o.raw for o in many])


async def main():
    return await make_crew().akickoff(inputs={"topic": "wasps"})

print(asyncio.run(main()).raw)
```

---

## 5. LLMs, model strings, and provider extras

LiteLLM is no longer a dependency. `LLM(model=...)` is a factory that returns a native provider class; only the OpenAI SDK ships with core crewai.

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `llm="anthropic/claude-sonnet-4-5"` with plain `crewai` installed | `uv add "crewai[anthropic]"`, then the same string | `ImportError: Anthropic native provider not available, to install: uv add "crewai[anthropic]"` |
| `llm="gemini/gemini-2.5-flash"` with plain `crewai` | `uv add "crewai[google-genai]"` | `ImportError: Google Gen AI native provider not available` |
| `llm="groq/llama-3.3-70b-versatile"` (or `mistral/...`, any non-native provider) | `uv add "crewai[litellm]"` | `ImportError: Unable to initialize LLM with model '...'. The model did not match any supported native provider (...), and the LiteLLM fallback package is not installed.` |
| No `llm=` and assuming `gpt-4` | Default is `gpt-4.1-mini`; set `MODEL=...` or `llm=` | |
| `llm.call(messages, response_format=Model)` | `llm.call(messages, response_model=Model)` | `TypeError: ... unexpected keyword argument 'response_format'. Did you mean 'response_model'?` |
| Custom `BaseLLM.call(self, messages, tools=None, callbacks=None, available_functions=None)` | Also accept `from_task=None, from_agent=None, response_model=None` (or `**kwargs`) | `TypeError: call() got an unexpected keyword argument 'from_task'` at kickoff |

Native providers: openai, anthropic/claude, azure, google/gemini, bedrock/aws, openrouter, deepseek, ollama, hosted_vllm, cerebras, dashscope, snowflake. Extras: `crewai[anthropic]`, `crewai[google-genai]`, `crewai[bedrock]`, `crewai[azure-ai-inference]`, `crewai[litellm]`. Construction never checks the key; kickoff does (`ValueError: OPENAI_API_KEY is required`, or `ANTHROPIC_API_KEY is required`; a wrong key gets the provider's `AuthenticationError ... 401`). The `crewai create` scaffolds never add a provider extra, even with `--provider anthropic/...`: run `uv add "crewai[anthropic]"` yourself.

```python
from crewai import LLM

gpt = LLM(model="openai/gpt-4.1-mini", temperature=0.2)  # core install
local = LLM(model="ollama/llama3")                        # core install, OpenAI-compatible route
claude = LLM(model="anthropic/claude-sonnet-4-5")         # needs: uv add "crewai[anthropic]"
print(type(gpt).__name__, type(local).__name__, type(claude).__name__)
```

A custom LLM subclasses `BaseLLM` and implements `call` with the full signature. If `call` forwards `messages` to a provider SDK, send only each message's `role` and `content`: crewai adds a `cache_breakpoint: True` key to some messages, and the Anthropic API rejects it with `400 ... messages.0.cache_breakpoint: Extra inputs are not permitted`.

```python
from typing import Any

from crewai import Agent, BaseLLM, Crew, Task


class EchoLLM(BaseLLM):
    def call(self, messages, tools=None, callbacks=None, available_functions=None,
             from_task=None, from_agent=None, response_model=None, **kwargs: Any) -> str:
        return "echo: " + str(messages[-1]["content"])[:40]


agent = Agent(role="Echo", goal="Echo", backstory="Echoes.", llm=EchoLLM(model="echo"))
task = Task(description="Say hi", expected_output="Anything", agent=agent)
print(Crew(agents=[agent], tasks=[task]).kickoff().raw)
```

---

## 6. Structured output

| Where | Use | Result lands in |
|---|---|---|
| `Task(output_pydantic=Model)` | Parsed model on the task and crew output | `out.pydantic`, `out["field"]` |
| `Task(output_json=Model)` | Dict output | `out.json_dict` |
| `Task(response_model=Model)` | Native provider structured output only | `out.raw` (JSON text); `out.pydantic` stays `None` |
| `Agent.kickoff(messages, response_format=Model)` | Standalone agent | `LiteAgentOutput.pydantic` |
| `llm.call(messages, response_model=Model)` | Direct LLM call | the parsed model |
| `LLM(model=..., response_format=Model)` | Constructor-level default | |

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `Task(response_format=Model)` | `Task(output_pydantic=Model)` | Silently ignored |
| `Agent.kickoff(msg, response_model=Model)` | `Agent.kickoff(msg, response_format=Model)` | `TypeError: ... Did you mean 'response_format'?` |
| `Task(output_pydantic=M, output_json=M)` | Pick one | `ValidationError: Only one output type can be set` |
| `Task(output_pydantic=M, output_file="report.md")` expecting prose in the file | Drop `output_pydantic`, or render the model yourself | The file gets the model's JSON, whatever the extension |
| `output_file="/abs/path/report.md"` | A relative path (or `output_file="{out_dir}/report.md"` via inputs) | The leading `/` is stripped, so the file lands under the current directory |
| `output_pydantic: Report` in `tasks.yaml` | Set `output_pydantic=Report` in the `@task` method in Python | With no matching `@output_pydantic` class: `KeyError: 'Report'`. With one: silently dropped, `out.pydantic is None` |

```python
from pydantic import BaseModel

from crewai import Agent, Crew, Task


class Report(BaseModel):
    title: str
    points: list[str]


analyst = Agent(role="Analyst", goal="Summarise", backstory="Concise.", llm="openai/gpt-4.1-mini")
task = Task(description="Summarise {topic}.", expected_output="A title and points.",
            agent=analyst, output_pydantic=Report)
out = Crew(agents=[analyst], tasks=[task]).kickoff(inputs={"topic": "bees"})
assert out.pydantic is not None, "structured output was dropped"
print(out.pydantic.title, out["points"])

standalone = analyst.kickoff("Summarise bees.", response_format=Report)
print(standalone.pydantic)
```

In a `@CrewBase` project keep the model in Python even when the rest of the task is YAML:

```python
@task
def research_task(self) -> Task:
    return Task(config=self.tasks_config["research_task"], output_pydantic=Report)
```

---

## 7. Guardrails

A function guardrail takes one argument (`TaskOutput`) and returns a tuple `(bool, value)`. On `False` the value is fed back to the agent as the error and the task retries, up to `guardrail_max_retries` (default 3); then the task raises `Task failed guardrail validation after N retries`. A string guardrail is checked by an extra LLM call.

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `def g(out) -> bool: return True` | `def g(out: TaskOutput) -> tuple[bool, Any]` returning `(True, out.raw)` | Annotated: `ValidationError: If return type is annotated, it must be Tuple[bool, Any]` at `Task(...)`. Unannotated: `TypeError: cannot unpack non-iterable bool object` at kickoff |
| `-> tuple[bool, object]` | `-> tuple[bool, Any]` (or `str`, `TaskOutput`) | Same `ValidationError` at `Task(...)` |
| `Task(max_retries=2)` | `Task(guardrail_max_retries=2)` | `DeprecationWarning` |
| Relying on `HallucinationGuardrail` | Write a function guardrail | In open-source crewai it is a no-op that always passes |

```python
from typing import Any

from crewai import Agent, Crew, Task, TaskOutput


def under_50_words(output: TaskOutput) -> tuple[bool, Any]:
    if len(output.raw.split()) > 50:
        return (False, "Keep it under 50 words.")
    return (True, output.raw)


writer = Agent(role="Writer", goal="Write", backstory="Brief.", llm="openai/gpt-4.1-mini")
task = Task(description="Describe {topic}.", expected_output="A short paragraph.", agent=writer,
            guardrails=[under_50_words, "Must not mention prices"], guardrail_max_retries=2)
print(Crew(agents=[writer], tasks=[task]).kickoff(inputs={"topic": "bees"}).raw)
```

`guardrails=[...]` runs each guardrail in order; a successful string result replaces `out.raw` for the next one.

---

## 8. Memory and knowledge

Memory is one `Memory` class (LanceDB storage). Its defaults call OpenAI: `text-embedding-3-large` for embeddings and `gpt-5.4-mini` for analysis. `Crew(memory=True)` analyses with the first agent's `llm` instead, and knowledge with no `embedder` embeds with `text-embedding-3-small`. Live with an OpenAI key: a `memory=True` crew stored a codename in one process and a new crew recalled it in the next; crew and agent knowledge both answered from the source.

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `ShortTermMemory()`, `LongTermMemory()`, `EntityMemory()` | `Memory(...)` | `ImportError` |
| `Crew(memory=True)` with no (or an invalid) `OPENAI_API_KEY` | Set the key, or pass `Memory(llm=..., embedder=...)` | Crew **completes**; every save fails silently (only a `MemorySaveFailedEvent` is emitted) and nothing is stored |
| `memory.remember(...)` with no key | Same | `RuntimeError: Memory requires an embedder for vector search` (an invalid key: `AuthenticationError ... 401`) |
| `Agent(knowledge_sources=[...])` with no key or embedder, agent in a crew | Pass `embedder={...}` on the Agent or Crew | `ValueError: Invalid Knowledge Configuration: The OPENAI_API_KEY environment variable is not set.` at crew kickoff (an invalid key: `AuthenticationError ... 401`) |
| `agent.kickoff(...)` on an agent with `knowledge_sources` | Run the agent as a task in a `Crew`, or put the facts in the prompt | No error with or without a key: `Agent.kickoff()` never queries agent knowledge, so the answer ignores it |
| `Crew(knowledge_sources=[...])` with no key or embedder | Same | Logs `Failed to upsert documents`; crew runs with **no** knowledge |
| Changing the knowledge `embedder` after a run stored knowledge | `crewai reset-memories -kn` (or `crew.reset_memories(command_type="knowledge")`), then run | `Embedding function conflict: new: <x> vs persisted: openai`; the crew runs with no knowledge |
| Adding `embedder={"provider": "openai"}` after knowledge was stored with no `embedder` (or changing the OpenAI embedding model) | Same reset | `Failed to upsert documents: Collection expecting embedding with dimension of 1536, got 3072` (the explicit provider defaults to `text-embedding-3-large`); the crew answers without its knowledge |

The embedder config shape is `{"provider": <name>, "config": {...}}`; the OpenAI model key is `model_name`. `"model"` raises `TypeError: ... unexpected keyword argument 'model'` in `Memory`, and for knowledge it is silently ignored (the crew embeds with `text-embedding-3-large`). The `ollama` provider below also needs `uv add ollama` and a running Ollama server with the model pulled; without the package, crew knowledge is silently `None`. `{"provider": "onnx"}` is a local, key-free embedder that core crewai can already run (chromadb's `onnxruntime`; about 80 MB of model downloaded on first use) - the design-agent skill's memory-and-knowledge reference has working examples. For a deterministic embedder in tests, use a callable (`Memory`) or a custom class (knowledge) - see [verify-installed-api.md](references/verify-installed-api.md).

```python
from crewai import Agent, Crew, Memory, Task
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

embedder = {"provider": "ollama", "config": {"model_name": "nomic-embed-text"}}  # needs: uv add ollama
memory = Memory(llm="openai/gpt-4.1-mini", embedder=embedder)
facts = StringKnowledgeSource(content="acme was founded in 2020.")

agent = Agent(role="Analyst", goal="Answer", backstory="Uses knowledge.", llm="openai/gpt-4.1-mini")
task = Task(description="When was acme founded?", expected_output="A year.", agent=agent)
crew = Crew(agents=[agent], tasks=[task], memory=memory, knowledge_sources=[facts], embedder=embedder)
if crew.knowledge is None:
    print("knowledge failed to initialise - is the ollama package installed and the server running?")
```

Reset stored data from the project directory with `crewai reset-memories -m` (memory; errors with `Memory memory system is not initialized` if the crew has no memory), `-kn` (knowledge), `-akn` (agent knowledge), `-k` (latest kickoff outputs), `-a` (all). The old `-s`, `-l`, `-e` flags are hidden deprecated aliases that print a warning and reset the unified memory. Storage path and offline embedders: [verify-installed-api.md](references/verify-installed-api.md).

---

## 9. Project scaffold and CLI

| You probably wrote | Current form | What the wrong form does |
|---|---|---|
| `crewai create crew my_crew` expecting `crew.py` + YAML | `crewai create crew my_crew --classic` | Starts an interactive wizard that writes a JSON project (`crew.jsonc`, `agents/*.jsonc`); with no TTY it prints `Aborted!`. Scripts that only need a crew should use `--classic --skip-provider`. |
| `crewai run` on a JSON crew in CI or a script | For CI, create the crew with `crewai create crew <name> --classic` and run it with `uv run run_crew` | Opens a full-screen run view that waits for the user to quit, even with no TTY, so the command never exits. An environment variable, `CREWAI_DMN=1`, skipped the run view on crewai 1.15.x, but it is unsupported and undocumented; may change |
| Leaving `"memory": true` from the JSON scaffold with no `OPENAI_API_KEY` | Set the key, set `"memory": false`, or configure an embedder | The crew completes; memory recall and saves fail silently |
| `crewai run --inputs '{...}'` on a classic crew | Put inputs in `main.py` `run()` | `Error: --inputs is only supported for declarative flows and crews` |
| `crewai reset-memories -s -l -e` | `crewai reset-memories -m` | Deprecated aliases, warning printed |
| `return crew.kickoff(...)` from `main.run()` | Do not return the output | The `run_crew` script calls `sys.exit(<CrewOutput>)` and exits 1 after a successful run; `crewai run` prints `An error occurred while running the crew: ... non-zero exit status 1` |
| Trusting `crewai run`'s exit code in CI on a classic crew (`--classic`) or a Python flow | Run `uv run run_crew` (exit code propagates) or check the output | There `crewai run` exits 0 even when the crew or flow process failed; JSON (wizard) crews have no `run_crew` script, so create CI crews with `--classic` |

```bash
crewai version
crewai create crew research_crew --classic --skip-provider
cd research_crew && uv add "crewai[anthropic]"   # only if an agent uses an anthropic/ model
crewai install && crewai run
crewai reset-memories --help
```

The classic layout: `src/<name>/crew.py` (`@CrewBase` class), `src/<name>/config/agents.yaml` and `tasks.yaml` (keys match the `@agent`/`@task` method names), `main.py`, and `pyproject.toml` with `[tool.crewai] type = "crew"` and dependency `crewai[tools]`. In YAML, `llm: <name>` resolves to an `@llm` method of that name, otherwise it is used as a model string. `crewai create flow` also writes a `.env` with a placeholder `OPENAI_API_KEY` - replace it, never commit it.

---

## 10. Removed and deprecated

| Feature | Status in 1.15.22-1.15.23 | Do instead |
|---|---|---|
| `CodeInterpreterTool` | Removed from `crewai_tools` | Sandbox tool or service |
| `Agent(allow_code_execution=...)`, `code_execution_mode` | Deprecated no-ops | Same |
| `ShortTermMemory`, `LongTermMemory`, `EntityMemory`, `memory_config` | Removed / ignored | `Memory(...)` |
| `crewai.utilities.events` | Removed | `crewai.events` |
| `Crew(function_calling_llm=...)` | Deprecated | Per-agent `llm` |
| `Task(max_retries=...)` | Deprecated | `guardrail_max_retries` |
| `crewai.cli` module | Deprecation shim | `crewai_cli` (the CLI is its own package) |
| LiteLLM as a core dependency | Optional extra | `crewai[litellm]` only for non-native providers |

---

## 11. Common mistakes

| Symptom | Cause | Fix |
|---|---|---|
| A parameter has no effect and no error | Unknown kwargs are dropped by Agent/Task/Crew | Check `"name" in Task.model_fields` |
| `out.pydantic is None` | `output_pydantic` set in YAML, or `response_model` used instead of `output_pydantic` | Set `output_pydantic=Model` in Python; assert non-None |
| `ImportError: ... native provider not available` | Provider SDK extra missing | `uv add "crewai[anthropic]"` (or `[google-genai]`, `[bedrock]`, `[litellm]`) |
| `ValueError: OPENAI_API_KEY is required` at kickoff | No `llm=` set, so the default `gpt-4.1-mini` was used | Set `llm=` or `MODEL`, plus the provider key |
| Crew finishes but nothing was remembered | `memory=True` with no embedder key | Pass `Memory(embedder=...)` or set the key; listen for `MemorySaveFailedEvent` from `crewai.events` |
| Knowledge never appears in prompts | Crew-level knowledge failed to embed | Set `embedder=`; look for `Failed to upsert documents` |
| `TypeError: ... unexpected keyword argument 'from_task'` | Custom `BaseLLM.call` with the old signature | Accept `from_task`, `from_agent`, `response_model`, `**kwargs` |
| `Tuple[bool, Any]` ValidationError at `Task(...)` | Guardrail annotated `-> bool` or `tuple[bool, object]` | Annotate `-> tuple[bool, Any]` and return a tuple |
| `crewai create crew` hangs or prints `Aborted!` | It is an interactive JSON wizard now | Add `--classic` for the `@CrewBase` layout; use it for CI and scripts |
| `crewai run` never returns on a JSON crew | The run view waits for a keypress | For CI, use `crewai create crew <name> --classic` plus `uv run run_crew` |
| `kickoff_for_each` results all answer the first topic | The `Crew` was already kicked off | Build a fresh `Crew` per batch |
| `token_usage` larger than the run could have used | An `LLM` object shared by several agents or reused across crews | One `LLM` per agent per crew, or count `LLMCallCompletedEvent`s |
| Agent never uses its MCP tools under `akickoff()` | `https://` string in `mcps` inside a running event loop | `MCPServerHTTP(url=...)` |
| `Embedding function conflict ... persisted: openai` | Knowledge was stored with another embedder | `crewai reset-memories -kn` |
| `Collection expecting embedding with dimension of 1536, got 3072` | Knowledge was stored with another OpenAI embedding model | `crewai reset-memories -kn` |
| `crewai run` reports `non-zero exit status 1` after the crew succeeds | `run()` returns the `CrewOutput` | Do not return it |

---

## 12. Checklist

- [ ] `crewai version` checked; rows re-verified if not 1.15.x
- [ ] Every `Agent`/`Task`/`Crew` kwarg exists in `model_fields`
- [ ] Tools import from `crewai.tools`, flow decorators and `persist` from `crewai.flow`
- [ ] Every task has `expected_output`
- [ ] Every non-OpenAI model string has its extra in `pyproject.toml`
- [ ] Structured output set in Python with `output_pydantic`, and `out.pydantic` asserted non-None
- [ ] Guardrails return `(bool, value)` and are annotated `tuple[bool, Any]` or not at all
- [ ] Memory and knowledge have an explicit embedder or a provider key in the environment
- [ ] No `CodeInterpreterTool`, `allow_code_execution`, `ShortTermMemory`, `memory_config`
- [ ] Classic projects created with `crewai create crew <name> --classic`; provider extra added with `uv add`
- [ ] CI and scripts use classic crews (`crewai create crew <name> --classic`) run with `uv run run_crew`

---

## References

- [Verify the installed API](references/verify-installed-api.md) - one-liners to check fields, defaults and signatures in the installed crewai; storage paths; an offline embedder for memory and knowledge
- [Source receipts](references/source-receipts.md) - the crewai source file and line behind each row, so you can re-check after an upgrade
- Public docs: https://docs.crewai.com

For related skills:

- **ask-docs** - query the live CrewAI docs when a row may have changed
- **getting-started** - project scaffolding and choosing crews vs flows
- **design-agent** / **design-task** - tuning agents and tasks once the API is right
- **build-flow** - Flow state, routers, `@persist`, human feedback
- **connect-tools-and-mcp** - `BaseTool`, `@tool`, `mcps=[...]`
- **test-crewai-project** - offline stub LLM and deterministic tests
- **deploy-to-amp** / **call-deployed-crew** - shipping and calling a crew

© crewAIInc · MIT · crewAIInc/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой