n4nAI

CrewAI example: a crew that drafts and reviews code

Build a CrewAI code review crew example that drafts and critiques Python functions. Step-by-step setup, runnable code, and verification tips.

n4n Team3 min read731 words

Audio narration

Coming soon — every post will get a voice note here.

A practical crewai code review crew example shows how to split responsibilities between a drafter and a critic without hand-rolling orchestration. This guide builds a two-agent crew that writes a Python function and then subjects it to line-by-line review, using CrewAI’s declarative primitives.

Step 1: Install and pin dependencies

pip install "crewai>=0.28.0" langchain-openai pydantic

CrewAI moves fast; pin a version in production. The drafter and reviewer will both call an OpenAI-compatible chat model, so we also need langchain-openai for the LangChain bridge.

Step 2: Point CrewAI at an LLM gateway

CrewAI accepts any LangChain chat model. If you want automatic fallback when a provider is rate-limited, route through a single OpenAI-compatible endpoint like n4n.ai, which fronts 240+ models and honors client routing directives. Set the base URL and key:

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.2,
    api_key=os.environ["N4N_API_KEY"],
    base_url="https://api.n4n.ai/v1",
)

Using a gateway keeps your crew resilient: if the primary model degrades, the gateway shifts traffic without code changes. For local experiments, swap in standard OpenAI credentials directly. Either way, keep temperature low for the drafter to avoid syntactic surprises.

Step 3: Define the agents

Agents are just role, goal, backstory, and constraints. The drafter stays narrow; the reviewer is adversarial but constructive.

from crewai import Agent

drafter = Agent(
    role="Senior Python Implementer",
    goal="Write correct, typed, and documented Python code for the given spec",
    backstory="You have 10 years building production libraries. You favor readability over cleverness.",
    llm=llm,
    verbose=True,
    allow_delegation=False,
)

reviewer = Agent(
    role="Strict Code Reviewer",
    goal="Find bugs, missing edge cases, and style violations in the drafted code",
    backstory="You block merges on missing docstrings, untyped signatures, and O(n^2) surprises.",
    llm=llm,
    verbose=True,
    allow_delegation=False,
)

Keep allow_delegation=False for a linear crew. Delegation adds nondeterminism that obscures which agent produced a defect. In a code review context, you want a clear audit trail.

Step 4: Define tasks with explicit outputs

Tasks bind an agent to a description and an output contract. We force the drafter to emit a Pydantic model so the reviewer gets structured input instead of a markdown blob.

from crewai import Task
from pydantic import BaseModel, Field

class CodeArtifact(BaseModel):
    filename: str = Field(description="module name, e.g. fib.py")
    code: str = Field(description="full python source")
    rationale: str = Field(description="why this design")

draft_task = Task(
    description=(
        "Write a Python function `memo_fib(n: int) -> int` that returns the nth Fibonacci number. "
        "Use functools.lru_cache. Include type hints, a docstring, and a guard for negative input."
    ),
    expected_output="A CodeArtifact with filename, code, and rationale",
    output_pydantic=CodeArtifact,
    agent=drafter,
)

review_task = Task(
    description=(
        "Review the drafted code for: negative input handling, recursion limit, cache thread-safety, "
        "and docstring completeness. Return a verdict and a list of issues."
    ),
    expected_output="JSON with keys: approved (bool), issues (list[str])",
    output_json={"approved": bool, "issues": list},
    agent=reviewer,
    context=[draft_task],
)

The context=[draft_task] line wires the reviewer to the drafter’s output. CrewAI resolves the Pydantic object to text automatically before injecting it into the reviewer prompt.

Step 5: Assemble and kick off the crew

Use Process.sequential so the reviewer never starts before the draft exists.

from crewai import Crew, Process

crew = Crew(
    agents=[drafter, reviewer],
    tasks=[draft_task, review_task],
    process=Process.sequential,
    verbose=True,
)

result = crew.kickoff()
print(result)

kickoff() blocks until both tasks finish. The returned result is the last task’s output (the review JSON). To inspect the draft, read draft_task.output.pydantic.

Step 6: Verify the crew did its job

Success means three things: the drafter produced parseable code, the code imports, and the reviewer’s verdict matches a manual glance. Write a small harness:

import ast, tempfile, os, json

# 1. Draft is valid Python
artifact = draft_task.output.pydantic
src = artifact.code
ast.parse(src)  # raises if syntax invalid

# 2. Executable behavior matches spec
with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as f:
    f.write(src)
    mod_path = f.name
try:
    import importlib.util
    spec = importlib.util.spec_from_file_location("mod", mod_path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    assert mod.memo_fib(10) == 55
    assert mod.memo_fib(0) == 0
    try:
        mod.memo_fib(-1)
        raise AssertionError("negative input not guarded")
    except ValueError:
        pass
finally:
    os.unlink(mod_path)

# 3. Review structure
review = json.loads(review_task.output.raw)
assert "approved" in review and "issues" in review
print("CREW VERIFIED:", review["approved"])

If ast.parse fails, lower the drafter temperature or add a linting tool. If the reviewer approves obviously broken code, tighten its backstory with concrete checklists.

Step 7: Operational notes for real code review crews

A crewai code review crew example is only useful if it runs inside your CI, not just a notebook. Wrap the crew in a CLI that takes a spec file and emits the review JSON to stdout. Cache the drafter’s output with provider cache-control hints if your gateway forwards them—n4n.ai does—so repeated reviews of the same diff cost fewer tokens.

Give the reviewer a read-only file tool instead of pasting code into the prompt. CrewAI’s CodeInterpreterTool or a custom FileReadTool reduces truncation risk on long modules.

Finally, treat the reviewer’s approved: false as a required gate. In GitHub Actions, exit non-zero when issues are non-empty. The drafter should never mark its own work approved; that separation is the entire point of the crew.

Step 8: Troubleshooting common failures

Pydantic export error. CrewAI serializes output_pydantic via model_dump_json(). If you use Pydantic v1, the signature differs. Pin pydantic>=2.5.

Reviewer ignores context. If review_task output lacks issues, confirm context=[draft_task] is set. Without it, the reviewer agent receives only its own description and hallucinates a draft.

Rate limits. Sequential crews still fire two completions back-to-back. With a shared gateway, per-token metering shows the spike; set max_rpm on the Crew to throttle.

Non-deterministic imports. The verification harness uses importlib on a temp file. If the drafted code uses relative imports or __main__ guards, adjust the harness to wrap in a package.

Why two agents beat one

A single prompt asking “write and review code” produces polite self-congratulation. Splitting the roles forces the reviewer to attend to a foreign artifact. In practice, the crewai code review crew example above catches missing ValueError guards roughly every time once the reviewer backstory lists them.

Keep the drafter’s temperature low (0.1–0.3) for deterministic output. The reviewer can run hotter to propose varied suggestions, but cap max tokens to avoid novel rewrite temptations.

Extending the pattern

Swap the drafter for a squad that generates tests first, then code. Add a third agent that runs pytest via a shell tool and feeds failures back. The same context wiring scales linearly. The crewai code review crew example is a leaf in a larger tree of specialized agents—start here because the feedback loop is tight and the success criteria are mechanical.

Tagscrewaireal-world-examplescode-reviewuse-case

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All crewai real-world crew examples posts →