n4nAI

CrewAI agent roles: tools, memory, and delegation settings

Hands-on guide to CrewAI agent roles: configure tools, memory, and delegation settings with Python examples, plus pitfalls and a sane default setup.

n4n Team4 min read961 words

Audio narration

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

When you scaffold a multi-agent workflow in CrewAI, the crewai agent role tools memory delegation configuration is what separates a system that ships from one that hangs in a loop of vague Slack-like messages. Get the role definitions right, give each agent only the tools it needs, decide explicitly whether it should remember past steps, and lock down delegation—or your crew will spend tokens arguing about who does what instead of producing output.

1. Define the role before the toolset

In CrewAI, an Agent is instantiated with role, goal, and backstory. These strings are not flavor text; they are injected into the system prompt and heavily influence tool selection, tone, and delegation targeting. The role string is also used as a key when another agent delegates by name, so it must be unique and stable across runs.

A vague role like “Assistant” causes the agent to grab whatever tool is available and interpret goals loosely. A precise role like “PostgreSQL Analyst” bounds its behavior.

from crewai import Agent

sql_analyst = Agent(
    role="PostgreSQL Analyst",
    goal="Write correct PostgreSQL queries to answer business questions from the data team",
    backstory="Senior data engineer who prefers explicit joins and always checks nulls.",
    verbose=True,
    llm="gpt-4o-mini",
)

The goal should be measurable. If you cannot tell from logs whether the goal was met, the agent cannot either. The backstory steers style: a “former journalist” writer produces tighter prose than a “generic AI”. Tune these before touching tools.

2. Tools: give the minimum, wrap the risky ones

Tools are passed as a list of callable objects—usually subclasses of Tool or functions decorated with @tool. The most common mistake is attaching every tool to every agent “just in case”. Each tool adds its schema to the prompt and increases the chance of the agent calling the wrong one or bloating context.

from crewai_tools import SerperDevTool, WebsiteScraperTool

search = SerperDevTool()
scrape = WebsiteScraperTool()

researcher = Agent(
    role="Web Researcher",
    goal="Find recent pricing for competitor LLM APIs",
    backstory="Competitive intelligence analyst",
    tools=[search],  # deliberately omit scrape; another agent handles extraction
)

If a tool performs a side effect (POST, delete, send email), wrap it with a confirmation gate or restrict it to a single role. CrewAI does not enforce isolation; your code must.

Define narrow tools instead of generic ones:

from crewai.tools import tool

@tool("fetch_pricing_page")
def fetch_pricing_page(url: str) -> str:
    """Fetch a pricing page and return first 2000 chars."""
    import requests
    try:
        return requests.get(url, timeout=5).text[:2000]
    except Exception as e:
        return f"ERROR: {e}"

Pitfall: tools that return huge payloads blow up context. Cap responses in the tool implementation. Another pitfall is mismatched schemas—if your tool argument is a dict but the agent passes a string, the call fails silently and the agent retries. Test each tool in isolation with tool.run() before wiring it into a crew.

3. Memory: opt-in per role, not globally

CrewAI supports memory=True on an agent, enabling short-term memory (previous steps in the current crew execution) and, with an embedder configured, long-term memory across runs. The default is False. Turning it on for every agent multiplies embedding calls and vector store reads.

from crewai import Agent

writer = Agent(
    role="Report Writer",
    goal="Synthesize research into a 500-word brief",
    backstory="Former journalist",
    memory=True,
    embedder={
        "provider": "openai",
        "config": {"model": "text-embedding-3-small"}
    },
)

Short-term memory is usually safe: it lets the writer see what the researcher produced. Long-term memory persists to a local SQLite store by default and can be swapped for a managed vector DB. The tradeoff is leakage—if you reuse a memory-enabled agent across unrelated crews, it may treat old context as fact. For stateless pipelines, keep memory=False and pass context explicitly via Task.description.

Pitfall: shared vector collections between roles mean agents can read each other’s notes. Use per-crew collection names or disable long-term persistence in production unless you have a retention policy.

4. Delegation settings: explicit allowlists beat blanket True

Delegation lets an agent hand a subtask to another role. In CrewAI this is controlled by allow_delegation. The naive setting is allow_delegation=True, which permits delegating to any agent in the crew. That creates non-deterministic graphs and latency spikes.

researcher = Agent(
    role="Web Researcher",
    goal="...",
    backstory="...",
    allow_delegation=False,  # leaf node, never delegates
)

editor = Agent(
    role="Editor",
    goal="Coordinate research and writing",
    backstory="...",
    allow_delegation=["Web Researcher", "Report Writer"],  # only these
)

Under the hood, delegation is a special tool call. The agent emits a delegate action with a target role and a task string. If the target is not in the allowlist, the call is rejected.

For hierarchical control, set process="hierarchical" on the Crew and provide a manager agent. The manager delegates automatically; individual allow_delegation flags still constrain it.

from crewai import Crew, Process

crew = Crew(
    agents=[researcher, writer, editor],
    tasks=[...],
    process=Process.hierarchical,
    manager_agent=editor,
)

Pitfall: with allow_delegation=True on all agents and a hierarchical process, you get loops where A delegates to B, B delegates back to A. Use allowlists and a hard timeout around crew.kickoff(). Another pitfall is assuming delegation works in process="sequential"—it does not trigger automatically; only the manager in hierarchical mode initiates it.

5. Point the LLM at a resilient endpoint

CrewAI accepts any LangChain-compatible LLM or a model string with a custom base URL. If you point the agent’s LLM at an OpenAI-compatible gateway like n4n.ai, you get automatic fallback when a provider is rate-limited or degraded, without rewriting agent logic. This matters when your crew runs long jobs and a single provider outage shouldn’t kill the run.

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini",
    base_url="https://api.n4n.ai/v1",
    api_key="YOUR_KEY",
)

analyst = Agent(
    role="PostgreSQL Analyst",
    goal="...",
    backstory="...",
    llm=llm,
)

The gateway forwards provider cache-control hints and meters per token, so you can attribute cost to specific agent roles from the usage logs. When a crew has five roles, that attribution is the only way to know which agent is burning the budget.

When tuning crewai agent role tools memory delegation, start from this skeleton:

  • One role per concern (research, transform, write).
  • Tools attached only to the role that owns that action; leaf roles get zero delegation.
  • memory=False unless cross-task state is required; then use per-crew embedder collections and a retention script.
  • allow_delegation=False on leaf roles; explicit role list on coordinators.
  • Hierarchical process only when you need dynamic task routing; otherwise sequential with fixed tasks.

Common failures we see in production:

  1. Tool overload: 8 tools on a researcher leads to a measurable wrong-call rate. Trim to 2–3 high-precision tools.
  2. Memory leakage: reusing a memory-enabled agent across unrelated crews surfaces old context as “facts”. Instantiate fresh agents per crew.
  3. Delegation storms: allow_delegation=True on all agents with a manager causes ping-pong loops. Set allowlists and log delegate calls.
  4. No timeouts: a delegated subtask can spin. Wrap crew.kickoff() in a worker with a hard timeout (e.g., 120s per agent turn).
  5. Uncapped tool output: a scrape tool returning 50k tokens blows the context window. Cap at the tool boundary.

CrewAI gives you the primitives; discipline gives you a system that runs at 2am without paging you. The crewai agent role tools memory delegation decisions you make upfront are the difference between a demo and a deployable service.

Tagscrewaiagent-rolestoolsdelegation

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 agent roles & task design posts →