CrewAICrewAI 1.15 · Python 3.10 to 3.13
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
35 small wins to finish your pathNext lesson →

The agent prompt: what the model is sent

The agent prompt is the set of messages CrewAI builds from an agent's role, goal and backstory and its task; printing them shows what the model reads.

Last updated: 28 Sep, 2026 · CrewAI 1.15

Your first crew answered, but the messages were hidden inside it. A small subclass of ShopLLM can print every message it receives and then answer as before.

Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
shop_llm.py
import os
import re

from crewai import BaseLLM

os.environ["CREWAI_DISABLE_TELEMETRY"] = "true"
os.environ["CREWAI_TRACING_ENABLED"] = "false"
os.environ["CREWAI_DISABLE_VERSION_CHECK"] = "true"


class ShopLLM(BaseLLM):
    def call(self, messages, tools=None, **kwargs):
        if isinstance(messages, str):
            messages = [{"role": "user", "content": messages}]
        text = messages[-1]["content"]
        orders = re.findall(r"\b[A-Z]\d+\b", text)
        if orders:
            return f"I have no way to look up {orders[0]} yet."
        return "Hello. Which order is this about?"

A model that prints its messages

python
from shop_llm import ShopLLM


class Peek(ShopLLM):
    def call(self, messages, tools=None, **kwargs):
        for message in messages:
            print(f"--- {message['role']}")
            print(message["content"].strip())
        return super().call(messages, tools, **kwargs)

Peek changes nothing about the answer. It prints each message's role and text, then hands over to ShopLLM.call with super().

The crew as it stands

python
from crewai import Agent, Crew, Task
from shop_llm import ShopLLM

agent = Agent(
    role="Support agent",
    goal="Answer customers of a small online shop",
    backstory="You have worked the shop's support desk for years.",
    llm=ShopLLM(model="shop"),
)
task = Task(
    description="Answer the customer: Where is my order A17?",
    expected_output="One short, friendly sentence.",
    agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])

The crew as it stands, with its agent, its task and the model it runs on.

The two messages CrewAI sends

Example
agent.llm = Peek(model="shop")
crew.kickoff()

The system message is built from the agent: You are and the role, then the backstory, then the goal. The user message is built from the task: the description, then the expected output, then two instructions CrewAI adds to every task. A hosted model reads all of it, which is why the documentation's advice on crafting agents is mostly about writing a specific role and a concrete goal.

The model never learns it is part of a crew. Each agent's call is a fresh conversation, and anything it needs from another agent has to arrive in these messages; the sequential-tasks lesson shows how.

Changing the backstory changes the prompt

Example
agent.llm = Peek(model="shop")
agent.backstory = "You answer in one sentence and never guess an order status."
crew.kickoff()

Changing an attribute changes the prompt on the next run. The role, goal and backstory are only text the model reads.

Reading the printed prompt

  • The system message is the agent: You are the role, then the backstory, then the goal.
  • The user message is the task: the description, the expected output, and two instructions CrewAI adds to every task.
  • Editing an attribute edits the next prompt; role, goal and backstory are only text the model reads.

System vs user message

MessageBuilt fromContains
systemthe agentYou are <role>, the backstory, the goal
userthe taskthe description, the expected output, CrewAI's instructions

When printing the prompt helps

  • An answer comes back blank or off topic and you want to see what was sent.
  • You are tuning a role or a goal and want to confirm where it lands.
  • You are checking that inputs, from the inputs lesson, filled the placeholders you meant.
Watch out
Each agent call is a fresh conversation; the model never learns it is in a crew. Anything one agent needs from another has to arrive in these messages, which is what the inputs lesson and the sequential-tasks lesson arrange.
Try it yourself
  • Set agent.goal to something else and find where it lands in the system message.
  • Change expected_output to "A reply of at most ten words" and read the user message.
  • Add a second task for the same agent and count how many times Peek prints.

Every expert started right here.