Skip to main content
Version: Next

CrewAI

Integrate CrewAI's role-based agent framework with Agent Kernel.

Installation​

pip install agentkernel[crewai]

Basic Usage​

from crewai import Agent as CrewAgent
from agentkernel.cli import CLI
from agentkernel.crewai import CrewAIModule

agent = CrewAgent(
role="assistant",
goal="Help users with their questions",
backstory="You are a helpful AI assistant",
verbose=False,
)

CrewAIModule([agent])

if __name__ == "__main__":
CLI.main()

Multi-Agent Crew​

from crewai import Agent as CrewAgent, Task, Crew
from agentkernel.crewai import CrewAIModule

researcher = CrewAgent(
role="researcher",
goal="Research topics thoroughly",
backstory="You are an expert researcher",
verbose=False,
)

writer = CrewAgent(
role="writer",
goal="Write clear content",
backstory="You are a skilled writer",
verbose=False,
)

CrewAIModule([researcher, writer])

Configuration​

export OPENAI_API_KEY=sk-... # CrewAI uses OpenAI by default

Tool Binding​

Use CrewAIToolBuilder to bind plain Python functions as tools to your CrewAI agents:

from crewai import Agent as CrewAgent
from agentkernel.crewai import CrewAIModule, CrewAIToolBuilder

def get_weather(city: str) -> str:
"""Returns the weather for a given city."""
return f"Weather in {city}: sunny, 25°C"

agent = CrewAgent(
role="weather",
goal="You provide weather information",
backstory="Use the get_weather tool for weather-related questions.",
tools=CrewAIToolBuilder.bind([get_weather]),
)

CrewAIModule([agent])

See Tools for the full guide on writing and binding tools.

Structured Output​

CrewAI configures structured output on the Task (output_pydantic / output_json), not on the agent, and Agent Kernel builds the task internally per run. Pass the model class to the module constructor, keyed by agent role; the runner forwards it into the task it creates:

from crewai import Agent as CrewAgent
from pydantic import BaseModel
from agentkernel.crewai import CrewAIModule

class ResearchReport(BaseModel):
topic: str
score: int

agent = CrewAgent(
role="Researcher",
goal="Research topics and score their relevance",
backstory="You are a meticulous researcher",
verbose=False,
)

CrewAIModule([agent], output_pydantic={"Researcher": ResearchReport})
# or: CrewAIModule([agent], output_json={"Researcher": ResearchReport})

To change the schema after the module is loaded, set it on the wrapped agent instead: module.get_agent("Researcher").output_pydantic = ResearchReport.

With output_pydantic, the CrewOutput.pydantic result is converted via model_dump(); with output_json, CrewOutput.json_dict is used directly. Plain-text crews continue to return AgentReplyText from CrewOutput.raw. str(reply) on an AgentReplyAny returns the JSON-serialized content, so text-based consumers work unchanged. See Reply Types for how structured replies are surfaced, and Execution Hooks for how hooks receive them.

Streaming limitation

Structured output applies to non-streaming execution only. Agent Kernel's CrewAI adapter does not implement Runner.stream() yet (CrewAI itself supports streaming).

Per-run context/state​

CrewAI does not support per-run caller context/state. Its kickoff(inputs=...) are .format() template-interpolation variables, not a state object, so there is no safe slot for a caller dict. If the reserved framework_context session key is set to a non-empty value, the CrewAI runner logs a single warning and ignores it (no injection, no write-back); the stored key is left untouched. A tool that still needs the dict can reach it directly via ToolContext.get().session.

Native run options​

The Crew(...) constructor's own arguments (step_callback, task_callback, max_rpm, planning, ...) are declared per agent with Module.run_options. Agent Kernel builds one Crew per run and writes the keys it owns (agents, tasks, memory) last; verbose=False is a default you may override. CrewAI agents are registered by role, so that is what resolves the agent:

CrewAIModule([agent]).run_options(
agent,
step_callback=record_step,
max_rpm=30,
)

Reserved (raise ValueError at declaration): agents, tasks, memory. Task-level options stay on the module constructor (output_pydantic, output_json).

Human in the loop​

This adapter cannot pause, and reports it rather than pretending: its runner leaves supports_pause at False, and resume() raises if called directly. A request that tries to resume a run on this framework is refused by Runtime with a message naming the runner.

The framework's own human-in-the-loop facility does not intersect what Agent Kernel wraps — see Human in the Loop for the five adapters that do pause.

Features​

  • ✅ Role-based agents
  • ✅ Task delegation
  • ✅ Sequential execution
  • ✅ Hierarchical teams
  • ✅ Framework-agnostic tool binding
  • ✅ Structured output (output_pydantic / output_json → AgentReplyAny)

Example​

See examples/cli/crewai for complete examples.

For per-agent native run options, see examples/cli/crewai-run-options (a Crew step_callback and max_rpm, with a deterministic Run stats: line on every reply).

Ready to Ship Your
First Agent?

Free, open-source, Apache 2.0. No licensing costs, no vendor lock-in. Join hundreds of developers building production AI agents with Agent Kernel.

Agent Kernel
Ask Agent Kernel