Defining Agent Roles, Goals, and Backstories
Every CrewAI agent is steered by three strings: role, goal, and backstory.
Together they act as a job description the model cannot ignore as easily as a vague system prompt.
Summary
Write role as a crisp title, goal as a measurable outcome, and backstory as constraints plus taste - then pair them with least-privilege tools and tight task expected_output so behavior stays testable.
Recipe
- Name the job, not the personality brand ("Research Analyst", not "GeniusBot").
- Write a goal as a single outcome the agent optimizes ("produce citable notes", not "be helpful").
- Add a backstory with domain, quality bar, and hard refusals (what it will not invent).
- Align tools with that role only.
- Mirror the goal in the task's
expected_outputso acceptance criteria match the job. - Use
{placeholders}for run-specific topics; keep evergreen constraints in goal/backstory. - Review a verbose run and rewrite any line that did not change behavior.
Working Example
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="{topic} Research Analyst",
goal=(
"Deliver accurate, source-aware notes an engineer can trust. "
"Prefer precision over coverage when time is limited."
),
backstory=(
"You spent years fact-checking technical claims. "
"You never invent URLs or statistics. "
"When evidence is thin, you say so in one line and move on."
),
allow_delegation=False,
max_iter=10,
verbose=True,
)
writer = Agent(
role="Staff Technical Writer",
goal=(
"Turn research notes into a scannable brief for senior engineers. "
"Preserve caveats; do not add new facts."
),
backstory=(
"You write for people who skim. "
"Short paragraphs, concrete nouns, no marketing language. "
"If notes conflict, you surface the conflict instead of picking a side."
),
allow_delegation=False,
verbose=True,
)
research = Task(
description="Research {topic}. Capture 5 facts with confidence labels.",
expected_output="Markdown bullets: fact | why it matters | confidence (high/med/low).",
agent=researcher,
)
draft = Task(
description="Write a 3-paragraph brief on {topic} using only the research notes.",
expected_output="Markdown with three paragraphs and a 'Caveats' section.",
agent=writer,
context=[research],
)
crew = Crew(
agents=[researcher, writer],
tasks=[research, draft],
process=Process.sequential,
verbose=True,
)
print(crew.kickoff(inputs={"topic": "agent evaluation harnesses"}).raw)Deep Dive
What each field is for
| Field | Optimize for | Anti-pattern |
|---|---|---|
role | Instant identity in logs and prompts | Long essays, joke names, multi-jobs |
goal | Decision policy under ambiguity | Generic "help the user" |
backstory | Style, domain priors, refusals | Novel-length lore with no constraints |
The model uses these fields as standing orders.
Tasks are the ticket for this run.
If goal and expected_output disagree, expect thrash.
Patterns that work
Specialist split. One role owns discovery; another owns packaging. Different tools, different success metrics.
Quality bar in the goal. Phrases like "prefer precision over coverage" change tool use and length more than adjectives in the backstory.
Refusal clauses in the backstory. "Never invent URLs" and "do not add facts not in notes" reduce confident hallucination at handoff boundaries.
Parameterized role titles. role="{topic} Research Analyst" keeps identity relevant without rewriting the agent class.
What to put in the task instead
Do not stuff one-off formatting rules only into the backstory if they apply to a single ticket.
Put run-specific instructions in description and expected_output.
Keep role text stable so you can reuse the agent across crews.
Hierarchy note
In hierarchical crews, workers still need sharp roles. The manager routes work; it does not magically fix overlapping goals. If two workers both "own the full report," the manager will bounce work or duplicate effort.
Gotchas
- Role salad. "Researcher-writer-reviewer" is three agents wearing one coat. Split them.
- Goals that describe activities, not outcomes. "Search the web a lot" is not a goal; "produce five verified facts" is.
- Backstory cosplay without constraints. Flavor text that never mentions quality or refusals rarely changes traces.
- Tools that contradict the role. A writer with broad web search will re-research instead of drafting.
- Ignoring
allow_delegation. Accidental true turns a specialist into a middle manager. - Copy-pasting the same three fields on every agent. If strings are identical, you paid for multi-agent theater.
- Never re-reading verbose traces. Role text is a prompt product - iterate with evidence.
Alternatives
| Approach | When it wins | When it loses |
|---|---|---|
| Role + goal + backstory (CrewAI default) | Multi-specialist crews | Tiny single-step bots |
| Single system prompt, no roles | Prototypes | Tool and handoff complexity |
| Hierarchical manager + thin workers | Dynamic assignment | Cost-sensitive batch jobs |
| Skills / knowledge packs | Domain docs over persona | Replacing a clear goal |
FAQs
How long should a backstory be?
A short paragraph is enough. If a sentence does not change tools, tone, or refusals, cut it.
Should the goal mention the model or tools?
Mention tools only when the policy depends on them ("use search before asserting currency"). Prefer outcome language over stack trivia.
Can I change role text per kickoff?
Yes via {placeholders} and kickoff(inputs=...). Keep stable constraints outside placeholders.
Do roles replace system templates?
They are the default persona channel. Advanced system_template overrides exist for model-specific formatting - verify at build if you need them.
How do I test a role definition?
Run the same task with A/B role text, compare tool calls, length, and factual errors. Keep the winner in version control.
Where does max_iter fit relative to goals?
Goals describe quality; max_iter is a host safety rail. Use both.
Should managers have different role styles?
Yes. Manager goals should emphasize assignment, review, and stopping criteria, not deep specialist craft.
What if two roles need the same tool?
Share the tool class, not the entire tool list blindly. Still keep role goals distinct so usage differs.
How do knowledge sources interact with backstory?
Knowledge grounds facts; backstory still sets caution and style. Do not assume knowledge removes the need for refusal language.
Is YAML/JSONC better for roles?
Config files help non-Python editors and reviews. The writing craft is identical in code or JSONC.
Related
Related: The CrewAI Mental Model: Roles, Tasks, and Crews
Related: CrewAI Basics
Related: Sequential vs Hierarchical Crew Processes
Related: CrewAI Best Practices
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.