n4nAI

Running CrewAI locally with n4n.ai and Claude Sonnet 4.5

A step-by-step guide to running CrewAI locally with n4n.ai as the LLM gateway, using Claude Sonnet 4.5 for agent execution.

n4n Team4 min read792 words

Audio narration

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

Running CrewAI locally with n4n.ai and Claude Sonnet 4.5 gives you a reproducible multi-agent setup without managing multiple provider accounts or API keys. This tutorial walks through the complete flow: environment setup, gateway configuration, agent and task definition, execution, and verification. You’ll end up with a working crew that routes through a single OpenAI-compatible endpoint while n4n.ai handles provider fallback and usage metering behind the scenes.

Step 1: Prerequisites and environment setup

Start with a clean Python environment. CrewAI requires Python 3.10 or higher. Use venv or conda to isolate dependencies.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

Verify the Python version:

python --version
# Python 3.10.12 (or newer)

You’ll also need an n4n.ai account with an API key. Create one at the dashboard if you haven’t already. Keep the key handy — you’ll set it as an environment variable in the next step.

Step 2: Install CrewAI and dependencies

Install CrewAI with the tools extra for built-in utilities, plus the OpenAI client library (n4n.ai exposes an OpenAI-compatible interface).

pip install "crewai[tools]" openai python-dotenv

Confirm the install:

python -c "import crewai; print(crewai.__version__)"
# 0.80.0 (or newer)

Create a .env file in your project root to store credentials. Never commit this file.

cat > .env << 'EOF'
N4N_API_KEY=sk-your-n4n-key-here
N4N_BASE_URL=https://api.n4n.ai/v1
EOF

Step 3: Configure n4n.ai credentials and endpoint

CrewAI’s LLM abstraction accepts any OpenAI-compatible client. Point it at the n4n.ai base URL and pass your API key. This is where the crewai local n4n.ai claude sonnet 4.5 integration happens — the gateway handles model routing, so you reference the model by its n4n.ai identifier.

Create config.py to centralize the LLM factory:

# config.py
import os
from dotenv import load_dotenv
from crewai import LLM

load_dotenv()

def get_llm(model: str = "anthropic/claude-sonnet-4.5") -> LLM:
    """
    Return a CrewAI LLM instance configured for n4n.ai.
    The model string follows the n4n.ai catalog format: provider/model-name.
    """
    return LLM(
        model=model,
        base_url=os.getenv("N4N_BASE_URL"),
        api_key=os.getenv("N4N_API_KEY"),
        temperature=0.3,
        max_tokens=4096,
    )

Test the configuration in a REPL:

python -c "
from config import get_llm
llm = get_llm()
resp = llm.call('Reply with only the word: pong')
print(resp)
"
# Expected: pong (or similar brief response)

If you see a response, the gateway connection works. If you get a 401, double-check the API key. A 404 on the model name means the identifier doesn’t match the n4n.ai catalog — list available models at https://api.n4n.ai/v1/models with your key.

Step 4: Define agents and tasks for a sample crew

Build a minimal two-agent crew: a researcher who gathers facts and a writer who summarizes them. This demonstrates task delegation and context passing between agents.

Create crew.py:

# crew.py
from crewai import Agent, Task, Crew, Process
from config import get_llm

llm = get_llm()

researcher = Agent(
    role="Tech Researcher",
    goal="Find concrete, up-to-date details about a given technical topic",
    backstory=(
        "You specialize in extracting specific facts — version numbers, "
        "release dates, API changes — from documentation and changelogs. "
        "You never hallucinate; you cite sources or say you don't know."
    ),
    llm=llm,
    verbose=True,
    allow_delegation=False,
)

writer = Agent(
    role="Technical Writer",
    goal="Produce a concise, accurate summary for engineers",
    backstory=(
        "You turn raw research into a 150-word brief with clear headings. "
        "You preserve technical precision and avoid marketing fluff."
    ),
    llm=llm,
    verbose=True,
    allow_delegation=False,
)

research_task = Task(
    description=(
        "Research the key differences between CrewAI 0.70 and 0.80. "
        "Focus on: agent memory changes, task output handling, and any "
        "breaking API changes. List at least 3 specific changes with "
        "version references."
    ),
    expected_output="Bulleted list of 3+ specific changes with version context",
    agent=researcher,
)

write_task = Task(
    description=(
        "Using the researcher's output, write a 150-word engineering brief "
        "titled 'CrewAI 0.70 → 0.80 Migration Notes'. Include a one-line "
        "summary, then three sections: Memory, Task Output, Breaking Changes."
    ),
    expected_output="Formatted brief with title, summary, and three sections",
    agent=writer,
    context=[research_task],  # passes researcher output to writer
)

crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, write_task],
    process=Process.sequential,
    verbose=True,
)

Step 5: Run the crew and verify output

Execute the crew from a script entry point. Create main.py:

# main.py
from crew import crew

if __name__ == "__main__":
    result = crew.kickoff()
    print("\n=== FINAL OUTPUT ===\n")
    print(result.raw)

Run it:

python main.py

You should see verbose logs for each agent’s reasoning, tool use (if any), and final output. The run completes when the writer task finishes. Expected wall time: 15–40 seconds depending on gateway latency.

Verification checklist:

  • Both agents log Thought: / Action: / Observation: cycles in the terminal
  • Researcher output contains at least three version-specific bullets
  • Writer output matches the requested structure (title, summary, three sections)
  • No LLM call failed or Rate limit errors appear — n4n.ai retries across providers automatically
  • Total token usage prints at the end (CrewAI logs this when verbose=True)

Sample successful tail of output:

=== FINAL OUTPUT ===

# CrewAI 0.70 → 0.80 Migration Notes

**Summary:** CrewAI 0.80 introduces persistent agent memory, structured task outputs, and breaking changes to the `Crew` constructor signature.

## Memory
- 0.70: Stateless agents; memory required external vector stores.
- 0.80: Built-in `memory=True` flag enables short-term and long-term memory per agent.

## Task Output
- 0.70: Tasks returned raw strings; parsing was manual.
- 0.80: `TaskOutput` objects with `raw`, `json_dict`, and `pydantic` attributes.

## Breaking Changes
- `Crew(agents, tasks)` now requires `process=` keyword argument.
- `Agent(llm=...)` no longer accepts raw OpenAI client; must use `crewai.LLM` wrapper.
- `kickoff()` returns `CrewOutput` instead of raw string.

If the output is truncated or missing sections, increase max_tokens in config.py or refine the task expected_output to be more explicit.

Step 6: Observability and debugging tips

Token usage and cost tracking

n4n.ai returns standard OpenAI usage fields in each response. CrewAI aggregates these per run. To capture them programmatically:

# debug_usage.py
from crew import crew
from crewai.utilities.token_counter import TokenProcess

result = crew.kickoff()
print(f"Total tokens: {result.token_usage.total_tokens}")
print(f"Prompt tokens: {result.token_usage.prompt_tokens}")
print(f"Completion tokens: {result.token_usage.completion_tokens}")

Inspecting raw gateway responses

Enable HTTP debug logging to see the exact request/response between CrewAI and n4n.ai:

export OPENAI_LOG=debug
python main.py 2>&1 | head -100

This shows the model identifier sent (anthropic/claude-sonnet-4.5), the gateway’s provider routing decision, and any x-n4n-provider or x-n4n-fallback headers indicating automatic failover.

Handling rate limits and degradation

n4n.ai honors provider Retry-After headers and retries across healthy providers. If you hit a hard limit, the exception surfaces as openai.RateLimitError. Wrap kickoff() with tenacity for application-level retries:

# resilient_main.py
from tenacity import retry, stop_after_attempt, wait_exponential_jitter
from crew import crew

@retry(
    wait=wait_exponential_jitter(initial=2, max=30),
    stop=stop_after_attempt(3),
)
def run_with_retry():
    return crew.kickoff()

if __name__ == "__main__":
    result = run_with_retry()
    print(result.raw)

Switching models for cost/latency tradeoffs

The get_llm() factory accepts any n4n.ai catalog model. For faster iteration, swap to a smaller model during development:

# In config.py or at call site
llm = get_llm("openai/gpt-4o-mini")  # cheaper, faster for dev loops
# llm = get_llm("anthropic/claude-sonnet-4.5")  # production quality

No code changes elsewhere — agents and tasks remain identical.

Step 7: Persisting crew state for reproducibility

CrewAI 0.80+ supports memory=True on agents and output_file on tasks. Enable both to persist intermediate state across runs:

# crew_with_memory.py
from crewai import Agent, Task, Crew, Process
from config import get_llm

llm = get_llm()

researcher = Agent(
    role="Tech Researcher",
    goal="...",
    backstory="...",
    llm=llm,
    verbose=True,
    memory=True,  # enables persistent memory
)

research_task = Task(
    description="...",
    expected_output="...",
    agent=researcher,
    output_file="research_output.md",  # writes result to file
)

On subsequent runs, the researcher recalls prior findings. The output_file gives you a version-controlled artifact for CI/CD gates or documentation pipelines.

Troubleshooting common issues

Symptom Likely Cause Fix
AuthenticationError Invalid or missing N4N_API_KEY Verify key in .env; ensure no trailing whitespace
NotFoundError: model not found Model identifier mismatch Query GET /v1/models at n4n.ai base URL; use exact id field
TimeoutError on kickoff() Gateway latency spike Increase timeout in LLM() constructor; enable verbose=True to see which call hangs
Output cuts off mid-sentence max_tokens too low Raise max_tokens in get_llm(); Sonnet 4.5 supports 8192 output tokens
Agents repeat work memory=True but no persistent store CrewAI uses in-memory storage by default; configure memory_config with a vector DB for cross-process persistence

Next steps

You now have a working crewai local n4n.ai claude sonnet 4.5 pipeline. From here:

  • Add tools (web search, file I/O, code execution) via crewai_tools or custom @tool functions
  • Parallelize independent tasks with Process.hierarchical and a manager agent
  • Wire n4n.ai usage webhooks into your cost dashboard for per-crew accounting
  • Containerize the project with a Dockerfile that bakes the .env at runtime via secrets

The gateway abstraction means you can swap models, add fallback policies, or enforce org-wide rate limits without touching agent code. That’s the leverage.

Tagscrewain4n-aiclaude-sonnet-4-5local-setup

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 getting started with n4n.ai posts →