n4nAI

CrewAI agent roles tutorial: goal, backstory, and tools

Hands-on CrewAI tutorial: define agent roles, goals, backstories, and tools step by step to build a working multi-agent crew with runnable Python code.

n4n Team3 min read732 words

Audio narration

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

When you build multi-agent systems in CrewAI, the crewai agent role goal backstory tools tuple defines everything about how an agent behaves. This tutorial walks through constructing a working crew from scratch, showing how each parameter changes the generated prompts and the final output.

Prerequisites

  • Python 3.10 or newer
  • crewai and crewai-tools installed (pip install crewai crewai-tools)
  • An OpenAI API key (or any OpenAI-compatible endpoint) exported as OPENAI_API_KEY
  • Familiarity with basic Python and function decorators

If you plan to run the code, set the key first:

export OPENAI_API_KEY="sk-your-key-here"

Step 1: Scaffold the imports

Create a file crew_demo.py and start with the minimal imports. CrewAI wraps LangChain agents but exposes a cleaner API.

from crewai import Agent, Task, Crew, Process
from crewai.tools import tool

Step 2: Define a tool

Tools are callables the agent can invoke. The @tool decorator requires a docstring—that docstring is sent to the LLM as the tool description. Keep it precise.

We’ll use a fake search to avoid external dependencies:

@tool("Fake Web Search")
def fake_search(query: str) -> str:
    """Return simulated search results for a query string."""
    return f"Result for '{query}': CrewAI is a framework for orchestrating role-playing agents."

The crewai agent role goal backstory tools design expects tools to be explicit about input and output. The type hint and docstring are not optional. CrewAI uses the function signature to build the JSON schema the LLM sees. If you need two arguments, define them explicitly:

@tool("Sectioned Search")
def sectioned_search(query: str, section: str) -> str:
    """Search a specific section of docs. section must be 'api' or 'guide'."""
    return f"[{section}] {query}: dummy result"

The LLM will be prompted to fill both. Missing docstring details cause the model to guess which parameters matter.

Step 3: Create agents with role, goal, backstory, tools

An Agent needs at least role, goal, and backstory. tools is a list; omit it if the agent should reason only.

researcher = Agent(
    role="Senior Research Analyst",
    goal="Uncover actionable insights about {topic}",
    backstory=(
        "You have 15 years of experience distilling complex technical "
        "subjects into bullet-point briefs for executives."
    ),
    tools=[fake_search],
    verbose=True,
)

writer = Agent(
    role="Tech Content Writer",
    goal="Turn research findings into a tight 100-word summary",
    backstory="You are a former newspaper editor who hates jargon.",
    tools=[],
    verbose=True,
)

The goal field accepts curly-brace templating that CrewAI fills from task inputs. The backstory is prepended to the system prompt to set persona. Neither should contradict the role. Setting verbose=True streams the agent’s thoughts and tool calls to stdout, which is indispensable when debugging prompt quality.

Step 4: Assign tasks and run the crew

Tasks bind an agent to a description and an expected_output format. The crew runs sequentially by default, but you can also use a hierarchical process where a manager agent delegates.

research_task = Task(
    description="Investigate {topic} using the provided search tool.",
    expected_output="Three bullet points of key findings.",
    agent=researcher,
)

write_task = Task(
    description="Read the research and write the summary.",
    expected_output="A 100-word paragraph.",
    agent=writer,
)

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

result = crew.kickoff(inputs={"topic": "multi-agent LLM frameworks"})
print(result)

Expected output (truncated for brevity):

[Research Analyst] Task output: 
- CrewAI orchestrates multiple agents with defined roles.
- Role-playing improves task focus versus a single monolithic prompt.
- Tools must have clear docstrings for reliable invocation.

[Writer] Task output:
Multi-agent frameworks like CrewAI assign each agent a role, goal, and backstory...

The exact text varies by model, but the structure follows the expected_output contracts. If you omit inputs={"topic": ...} while the goal contains {topic}, CrewAI raises a missing-key error before any LLM call.

Step 5: How goal and backstory shape prompts

CrewAI compiles the agent into a system prompt roughly like:

You are a Senior Research Analyst.
Your goal is: Uncover actionable insights about multi-agent LLM frameworks.
Backstory: You have 15 years of experience...

You have access to these tools: Fake Web Search.

If you change goal to something vague like “do good work”, the agent loses direction and the task output degrades. The crewai agent role goal backstory tools pattern works because the LLM gets a constrained identity. The backstory should reinforce the role, not describe a different job. A researcher with a writer’s backstory produces confused tool usage.

Step 6: Add delegation with a third agent

For larger flows, set allow_delegation=True so an agent can hand subtasks to others.

editor = Agent(
    role="Managing Editor",
    goal="Ensure the writer's output is publishable",
    backstory="You enforce style guides ruthlessly.",
    tools=[],
    allow_delegation=True,
    verbose=True,
)

edit_task = Task(
    description="Review the summary and fix any errors.",
    expected_output="Final polished paragraph.",
    agent=editor,
)

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

Delegation adds tokens and latency. Use it only when a clear hierarchy exists; otherwise a sequential crew is cheaper and more predictable.

Step 7: Point CrewAI at a different LLM endpoint

CrewAI accepts any LangChain chat model. If you want a single OpenAI-compatible endpoint that fronts 240+ models with automatic fallback when a provider is rate-limited, you can pass a ChatOpenAI instance configured for n4n.ai:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="anthropic/claude-3.5-sonnet",
    base_url="https://api.n4n.ai/v1",
    api_key="sk-your-n4n-key",
)

researcher = Agent(
    role="Senior Research Analyst",
    goal="Uncover actionable insights about {topic}",
    backstory="Veteran analyst.",
    tools=[fake_search],
    llm=llm,
    verbose=True,
)

The same crewai agent role goal backstory tools definitions work unchanged; only the underlying inference call differs. Per-token metering and provider cache-control hints are handled at the gateway layer, so your agent code stays identical.

Best practices

  • Goal: Write it as a measurable outcome, not a verb phrase. “Summarize X into 3 bullets” beats “understand X”.
  • Backstory: One or two sentences of relevant persona. Long backstories eat context without improving output.
  • Tools: Every tool needs a docstring that states when to use it. The LLM selects tools based on that text, not the function name alone.
  • Roles: Use job titles a human would recognize. “SQL Debugger” is clearer than “Agent1”.
  • Verbose: Keep it on during development. The small log noise pays back in debug speed.

Common pitfalls

  • Forgetting inputs= in kickoff when the goal or task description has {topic} templates throws a key error.
  • Tool functions that mutate global state cause non-deterministic crews.
  • Setting verbose=False during development hides the exact prompt sent to the LLM, making debugging slower.
  • Passing a tool without a docstring results in an empty description; the agent will either ignore it or call it incorrectly.
  • Overusing allow_delegation creates loops where agents bounce tasks without producing output.

Building with the crewai agent role goal backstory tools primitives is straightforward once you treat each agent as a constrained worker with a job description. The code above runs as-is with a valid key.

Tagscrewaiagent-rolestask-designtutorial

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 →