CrewAI / Hierarchical Manager: Build Reflection Enabled Agentic
Essentially, CrewAI uses a supervisor pattern to control subordinate agents. Here, I directly used the graph from the langgraph supervisor.
Assuming the reader has used CrewAI before and knows the general context of CrewAI, I will now slowly delve into our topic.
Agent
We define abstract agents, which are PlanAgent, RegressionAgent, CriticAgent, and ReportAgent, respectively.
plan_agent = Agent(
role="PlanAgent",
goal="Creating comprehensive working plan.",
backstory="""You've got some topics required by the user, create comprehensive plan so that we can do regression analysis for those topics.""",
llm=plan_model, .......)
regression_agent = Agent(
role="RegressionAgent",
goal="Conducting comprehensive regression analysis.",
backstory="""You've got a working plan to complete the regression analysis for some topics. You must follow the plan and complete the analysis.""",
llm=regression_model, ......)
)
critic_agent = Agent(
role="CriticAgent",
goal="You are the critic, do reflection, and provide constructive feedback on the AI responses.",
backstory=.......
)
report_agent = Agent(
role="ReportAgent",
goal="You are the ReportAgent, creating comprehensive, well-structured reports based on research findings.",
backstory=......
)
This is not much different from other frameworks. We can specify what the agent should do in the agent itself. Note that in CrewAI, you don’t have to explicitly define hand-offs, meaning the destination of the agent’s output. In CrewAI, hand-offs can be accomplished jointly by the manager and the task (the agent’s specific carrier).
Manager
It’s just a supervisor, the name is different, that’s all. He’s a regular agent, but his allow_delegation is true, after all, he needs to control his subordinate agents.
research_supervisor_agent = Agent(
role="ResearchSupervisorAgent",
goal="Managing and orchestrating a team of specialized AI agents. Your ONLY role is to manage the workflow by activating the appropriate agent at the appropriate time. You are NOT responsible for evaluating the quality or content of any agent's work.",
backstory="""You are the ResearchSupervisor, an AI coordinator responsible for orchestrating a team of specialized AI agents. Your ONLY role is to manage the workflow by activating the appropriate agent at the appropriate time. You are NOT responsible for evaluating the quality or content of any agent's work.
## WORKFLOW COORDINATION RESPONSIBILITIES
1. **Start with PlanAgent as coworker**:
- Always begin the workflow by activating the PlanAgent
- The PlanAgent will create a regression plan based on the user's request
- After the PlanAgent completes its plan, activate the RegressionAgent
2. **Activate RegressionAgent as coworker**:
- After the PlanAgent has finished, activate the RegressionAgent
- Provide the RegressionAgent with the plan created by the PlanAgent
- The RegressionAgent will gather comprehensive information on the assigned topics
- After the RegressionAgent completes its research, activate the CriticAgent
3. **Activate CriticAgent as coworker**:
- After the RegressionAgent has finished its research, activate the CriticAgent
- The CriticAgent will evaluate the regression findings
- Based on the CriticAgent's decision:
* If the CriticAgent requests revisions, activate the RegressionAgent again
* If the CriticAgent approves the revision, activate the ReportAgent
4. **Activate ReportAgent as coworker**:
- After the CriticAgent has approved the revision from the RegressionAgent
- The ReportAgent will create the final report based on the revision findings from the RegressionAgent
- IMPORTANT: Once the ReportAgent submits its report, the workflow is COMPLETE
- Do NOT activate any other agents after the ReportAgent has submitted its report
- The entire process ends when the ReportAgent delivers its final report
""",
allow_delegation=True, # must be True
.......)
In CrewAI, there’s a concept called “coworker” (as seen in my prompt, although “as coworker” isn’t strictly necessary, it doesn’t hurt). You can understand this as the agent to which an agent can hand-off, similar to the agent_name referred to in create_handoff_tool() in langchain-swarm. This completes one half of the hand-off setup.
💥Pay attention to the prompt, we have actually defined the logic of hand-off at this level, read carefully!
Task
For our task, generally speaking, we assign an agent to a specific carrier task. The task is responsible for the format of the agent’s output, the input of the context, and the execution method: parallel or not, etc.
My habit is that the prompt for a task is a description of specific business logic information, the more specific the better, avoiding abstraction.
Specifically, we show that we have defined revision_task, which is another carrier of RegressionAgent.
Based on the logic of the above diagram, the result of the CriticAgent (Evaluator)’s task needs to be reinterpreted by the RegressionAgent. In CrewAI, tasks inject information from other tasks through the context attribute. Referring to the code below, the critic_task’s context is the output of the regression_task.
However, technically, the regression_task cannot inject the output of the critic_task. We would get the following error:
Value error, Task 'Critic the regression result, provide the reflection and suggestions for the regression result.' has a context dependency on a future task 'Regression the information regarding the topics based on the plan:
plan_task = Task(
description="""Create a comprehensive regression plan based on user requests and required topics:
Topics:
{topics}""",
expected_output="""A good markdown format plan.
IMPORTANT: DO NOT USE ANY MARKDOWN CODE BLOCK SYNTAX (```). The content should be pure markdown without being wrapped in code blocks.
If you find yourself wanting to wrap the content in ```markdown ... ```, DO NOT DO IT. The content should be directly written in markdown format.""",
agent=plan_agent,
async_execution=False,
)
regression_task = Task(
description="""Regression the information regarding the topics based on the plan:
Topics:
{topics}""",
expected_output="""A good markdown format regression result.
IMPORTANT: DO NOT USE ANY MARKDOWN CODE BLOCK SYNTAX (```). The content should be pure markdown without being wrapped in code blocks.
If you find yourself wanting to wrap the content in ```markdown ... ```, DO NOT DO IT. The content should be directly written in markdown format.""",
agent=regression_agent,
async_execution=False,
context=[plan_task],
)
critic_task = Task(
description="""Critic the regression result, provide the reflection and suggestions for the regression result.""",
expected_output="""A good markdown format critic result.
IMPORTANT: DO NOT USE ANY MARKDOWN CODE BLOCK SYNTAX (```). The content should be pure markdown without being wrapped in code blocks.
If you find yourself wanting to wrap the content in ```markdown ... ```, DO NOT DO IT. The content should be directly written in markdown format.""",
agent=critic_agent,
async_execution=False,
context=[regression_task],
)
# assign RegressionAgent to the revision task again.
revision_task = Task(
description="""Revision the regression based on the critic result, review the plan and old regression result.
Rework the regression by using those information.
""",
expected_output="""A good markdown format revision result.
IMPORTANT: DO NOT USE ANY MARKDOWN CODE BLOCK SYNTAX (```). The content should be pure markdown without being wrapped in code blocks.
If you find yourself wanting to wrap the content in ```markdown ... ```, DO NOT DO IT. The content should be directly written in markdown format.""",
agent=regression_agent,
async_execution=False,
context=[plan_task, regression_task, critic_task],
)
report_task = Task(
description="""Produce a final report based on the reorganized key points and main ideas, render it in a clear and organized format with new presentation-layout and structure.""",
expected_output="""A good markdown format report.
IMPORTANT: DO NOT USE ANY MARKDOWN CODE BLOCK SYNTAX (```). The content should be pure markdown without being wrapped in code blocks.
If you find yourself wanting to wrap the content in ```markdown ... ```, DO NOT DO IT. The content should be directly written in markdown format.""",
agent=report_agent,
async_execution=False,
context=[revision_task],
output_file="output/crewai_BI_agent.md",
)
The solution is that we define a revision_task, another carrier for the RegressionAgent. This task accepts the output of the critic_task and the output of the regression_task, and so on…, so that the RegressionAgent can rework. The kind of logic we have already written this in the manager agent👆👆👆.
The report_task will accept the revision_task’s output as context.
💡💡💡 Combining the manipulation of the context attribute, adding tasks to the same agent carrier, and the “as coworker” portion in the initial prompt together weaves the logic of hand-off.
💥Defining a hand-off at the Agent level is very meaningful, refer to research_supervisor_agent.
This is the same as other frameworks, the difference is that we don’t need to write hand-offs in individual agents, this responsibility is taken over by the task context.
This diagram is at the task level, but remember, when prompting in the manager agent, use the underlying agent, which in this case refers to RegressionAgent. It works same in other frameworks 💥
.......
3. **Activate CriticAgent as coworker**:
.......
- Based on the CriticAgent's decision:
* If the CriticAgent requests revisions, activate the RegressionAgent again
* If the CriticAgent approves the revision, activate the ReportAgent
4. **Activate ReportAgent as coworker**:
- After the CriticAgent has approved the revision from the RegressionAgent
- The ReportAgent will create the final report based on the revision findings from the RegressionAgent
.......
.......
Crew
The chaining of Crew is not much different; here are two points to note: we need to point the manager to an instance of a manager agent, and process=Process.hierarchical.
Conventionally, open memory, use planning, although we have also defined PlanAgent, it doesn’t matter.
crew = Crew(
agents=[
plan_agent,
regression_agent,
critic_agent,
report_agent,
],
tasks=[
plan_task,
regression_task,
critic_task,
revision_task,
report_task,
],
planning=True,
planning_llm=plan_model,
memory=True,
manager_agent=research_supervisor_agent, # An instance of mananger agent
process=Process.hierarchical,
verbose=VERBOSE,
)
Code
Ref.
•Agents: https://ppc.land/content/files/2025/01/Newwhitepaper_Agents2.pdf
•Building Effective Agents: https://www.anthropic.com/research/building-effective-agents
•AGENTIC RETRIEVAL-AUGMENTED GENERATION: A SURVEY ON AGENTIC RAG https://arxiv.org/pdf/2501.09136