Structuring Inputs and Outputs in Multi-agent systems Using CrewAI

Mounish V Last Updated : 20 Oct, 2024
10 min read

Looking to enhance the performance of your agent-based systems? One of the most effective strategies is to structure both the inputs and intermediate outputs shared between agents. In this article, we’ll explore how to organize inputs, manage placeholders for passing data, and structure outputs to ensure that each agent delivers the desired results. Let’s start optimizing these key elements to achieve more consistent and reliable outcomes from your agentic systems. Agentic systems use multiple agents working together, allowing for collaboration, communication, and problem-solving that exceed the capabilities of individual LLMs. We’ll work with CrewAI in this guide and use Pydantic models and json to structure the outputs (structuring inputs and outputs in multi-agent). 

CrewAI

Overview

  1. Structuring inputs and outputs is crucial for enhancing performance in agent-based systems.
  2. Using Pydantic models helps validate and organize data shared between agents.
  3. CrewAI integrates with agents to streamline task execution and manage input/output data.
  4. Well-structured data prevents issues like data loss and inconsistencies, ensuring smooth collaboration.
  5. Defining expected outputs using models or JSON formats improves precision and reliability.
  6. Effective data management between agents can optimize multi-agent systems for complex tasks.

The Pydantic Models

Pydantic models are Python objects offered by the Pydantic library, designed for data parsing and validation. With Pydantic, you can create Python classes (models) that automatically validate data when instantiated, ensuring input data aligns with expected types and constraints. This provides a reliable way to handle structured data.

Here are the features:

Features of PydanticDescription
Data validationVerifies that input data conforms to expected types (e.g., int, str, list) and can apply custom rules.
Automatic type conversionConverts compatible data types automatically, such as turning “2023-10-17” into a datetime.date.
Data serializationModels can serialize data into formats like JSON, simplifying interactions with APIs.
Default valuesFields can be optional or have default values, providing flexibility in handling inputs.

Example of Pydantic Models

Let’s make a UserModel that inherits from BaseModel from Pydantic and the instantiated class should have an “id” as int, name as “str” and email as “email” 

from pydantic import BaseModel
class UserModel(BaseModel):
   id: int
   name: str
   email: str
# Valid input
valid_user = UserModel(id=1, name="Vidhya", email="[email protected]")
print(valid_user)
id=1 name='Vidhya' email='[email protected]'
# Invalid input (raises a validation error)
try:
   invalid_user = UserModel(id="one", name="Vidhya", email="[email protected]")
except ValueError as e:
   print(f"Validation Error: {e}")
Validation Error: 1 validation error for UserModel
id
  Input should be a valid integer, unable to parse string as an integer
[type=int_parsing, input_value='one', input_type=str]
    For further information visit https://errors.pydantic.dev/2.9/v/int_parsing

We got a validation error when we tried passing a string in id and Pydantic also returns the link to documentation that helps us understand the error.

Now, let’s look at other features of Pydantic, such as optional, date, and default value. 

from pydantic import BaseModel
from typing import Optional
from datetime import date
class EventModel(BaseModel):
   event_name: Optional[str] = None  # It's Optional to provide a value
   event_loc: str = "India" # Default value
   event_date: date
# Automatic conversion of a string to a `date` object
event = EventModel(event_date="2024-10-17")
print(event)
event_name=None event_loc='India' event_date=datetime.date(2024, 10, 17)

We have passed only the event_date, yet it’s not throwing any error because we set event_name to Optional and event_loc to “India” by default. Also, notice that the date is being typecast from string to datetime. 

Installations

We will be using CrewAI throughout this guide, so make sure you install CrewAI.

!pip install crewai

Structuring Inputs in Agentic Systems

The inputs can be formatted while defining the Agent and Task using curly braces { } with a variable name inside. Setting the human_input=True will prompt the user for feedback for the output. Let’s define an agent and task to answer questions related to physics:

Note: I’ll be using the  ‘gpt-4o-mini-2024-07-18’ from openai throughout the guide. 

from crewai import Agent, Task, Crew
import os
os.environ['OPENAI_API_KEY']=''
llm_config={'model':'gpt-4o-mini-2024-07-18'}
teacher_agent = Agent(
 role="Physics Professor",
 goal="You have strong foundational knowledge on physics "
       "You give the best answer to your students",
 backstory=(
   "You work as a college professor"
   "You teach physics and clarify doubts {doubts}"
   "You answer the question only if it is related to physics"
   "You make sure that you provide the best answers!"
 ),
 allow_delegation=False,
 verbose=True)
doubt_clarification_task = Task(
   description=(
       "Address the physics doubts raised by the student {doubts}. "
       "You don't answer the question if the question is not related to physics"
       "Provide clear, detailed explanations, examples, and any necessary formulas to help the student understand the concepts."
   ),
   expected_output=(
       "A clear response to the student's doubts, "
       "including explanations and examples if needed. "
   ),
   agent=teacher_agent,
   human_input=True
)
crew = Crew(
 agents=[teacher_agent],
 tasks=[doubt_clarification_task],
 verbose=True,
 memory=False
)

The inputs can be passed to the “inputs “ parameter in crew.kickoff()

inputs = {
   "doubts": "What is thermodynamics",
}
result = crew.kickoff(inputs=inputs)

Output

# Agent: Physics Professor

## Task: Address the physics doubts raised by the student What is
thermodynamics. You don't answer the question if the question is not related
to physicsProvide clear, detailed explanations, examples, and any necessary
formulas to help the student understand the concepts.

# Agent: Physics Professor

## Final Answer: 

Thermodynamics is the branch of physics that deals with the relationships
between heat, work, temperature, and energy. It provides a framework for
understanding how energy is transferred and transformed in systems, whether
they are mechanical engines, refrigerators, or biological organisms.

The study of thermodynamics is based on four fundamental laws that describe
how energy moves and changes form:

1. **Zeroth Law of Thermodynamics**: This law establishes the concept of
temperature. It states that if two systems are in thermal equilibrium with a
third system, then they are also in thermal equilibrium with each other. For
example, if System A is in equilibrium with System C, and System B is also
in equilibrium with System C, then System A and System B are in equilibrium
with each other. This allows us to define temperature as a measurable entity.

2. **First Law of Thermodynamics**: Often stated as the law of energy
conservation, this law asserts that energy cannot be created or destroyed,
only transformed. Mathematically, it can be expressed as:

   \[

   \Delta U = Q - W

   \]

   where \( \Delta U \) is the change in internal energy of the system, \( Q
\) is the heat added to the system, and \( W \) is the work done by the
system. An example of the first law in practice is a steam engine, where heat
energy is converted into work.

3. **Second Law of Thermodynamics**: This law introduces the concept of
entropy, stating that in any energy transfer, the total entropy of an
isolated system can never decrease over time. It suggests that energy
transformations are not 100% efficient and that systems naturally progress
toward a state of disorder. A common example is the idea that heat flows
spontaneously from a hotter body to a colder body, not the reverse.

4. **Third Law of Thermodynamics**: This law states that as the temperature
of a system approaches absolute zero, the entropy of a perfect crystal
approaches zero. This implies that it is impossible to reach absolute zero
in a finite number of steps, a concept that underscores the fundamental
limits of thermodynamic processes.

In practical applications, thermodynamics is used in numerous fields such as
engineering (designing engines, refrigerators), chemistry (reaction
spontaneity), and environmental science (understanding climate systems). 

In summary, thermodynamics is essential for analyzing how energy is utilized
and transferred, providing insights into improving efficiency and
understanding natural processes in various physical systems.

 ## Final Result: Thermodynamics is the branch of physics that deals with the
relationships between heat, work, temperature, and energy. It provides a
framework for understanding how energy is transferred and transformed in
systems, whether they are mechanical engines, refrigerators, or biological
organisms.

The study of thermodynamics is based on four fundamental laws that describe
how energy moves and changes form:

1. **Zeroth Law of Thermodynamics**: This law establishes the concept of
temperature. It states that if two systems are in thermal equilibrium with a
third system, then they are also in thermal equilibrium with each other. For
example, if System A is in equilibrium with System C, and System B is also
in equilibrium with System C, then System A and System B are in equilibrium
with each other. This allows us to define temperature as a measurable
entity.

2. **First Law of Thermodynamics**: Often stated as the law of energy
conservation, this law asserts that energy cannot be created or destroyed,
only transformed. Mathematically, it can be expressed as:

   \[

   \Delta U = Q - W

   \]

   where \( \Delta U \) is the change in internal energy of the system, \( Q
\) is the heat added to the system, and \( W \) is the work done by the
system. An example of the first law in practice is a steam engine, where
heat energy is converted into work.

3. **Second Law of Thermodynamics**: This law introduces the concept of
entropy, stating that in any energy transfer, the total entropy of an
isolated system can never decrease over time. It suggests that energy
transformations are not 100% efficient and that systems naturally progress
toward a state of disorder. A common example is the idea that heat flows
spontaneously from a hotter body to a colder body, not the reverse.

4. **Third Law of Thermodynamics**: This law states that as the temperature
of a system approaches absolute zero, the entropy of a perfect crystal
approaches zero. This implies that it is impossible to reach absolute zero
in a finite number of steps, a concept that underscores the fundamental
limits of thermodynamic processes.

In practical applications, thermodynamics is used in numerous fields such as
engineering (designing engines, refrigerators), chemistry (reaction
spontaneity), and environmental science (understanding climate systems). 

In summary, thermodynamics is essential for analyzing how energy is utilized
and transferred, providing insights into improving efficiency and
understanding natural processes in various physical systems.

=====

## Please provide feedback on the Final Result and the Agent's actions:

Give the answer in 3 lines

# Agent: Physics Professor

## Final Answer: 

Thermodynamics is the branch of physics that deals with the relationships
between heat, work, temperature, and energy. It is governed by four
fundamental laws that describe how energy is transferred and converted in
physical systems. For example, the first law of thermodynamics states that
energy cannot be created or destroyed, only transformed, which is expressed
mathematically as ΔU = Q - W, where ΔU is the change in internal energy, Q
is the heat added to the system, and W is the work done by the system.

We passed a question in the input, “What is thermodynamics?” and with the help of a human input, we got the desired answer. 

Structuring Outputs in Agentic Systems

Let’s make agents who can help me fill out details like name, email, phone number, and job one by one. Structuring the outputs as Pydantic or json helps define what output we’re expecting and the format we expect so that the subsequent agents get structured data and context.

Note: In a case like mine, not structuring the outputs with expected fields might lead to a loss of information, and the subsequent agents might start hallucinating. 

from crewai import Agent, Task, Crew
import os
os.environ['OPENAI_API_KEY']=''
llm_config={'model':'gpt-4o-mini-2024-07-18'}

Let’s define the classes using pedantic with the fields I expect in the output. As explained in the Pydantic models’ section, you can use Optional or set a value by default if needed.

from pydantic import BaseModel
from typing import List
# Define the classes using Pydantic
class nameEmail(BaseModel):
   name: List[str]
   email: List[str]
class phoneNo(BaseModel):
   name: str
   email: str
   phone: int
class allDetails(BaseModel):
   name: str
   email: List[str]
   phone: int
   job: str

Let’s define the first agent and task that fills out the user’s name and email. Use the “output_pydantic” parameter in Task(). I passed the nameEmail class as I won’t be using name and email as output here. 

# Task 1: Agent for filling name and email using output_pydantic
name_email_agent = Agent(
   role="Data Entry Specialist",
   goal="Your task is to fill out the user's name and email on your own.",
   backstory=(
       "You specialize in filling out personal information like name and email."
       "You fill the name and email on your own"
       "You use rare names and use birth year in the email"
   ),
   allow_delegation=False,
   verbose=True
)
name_email_task = Task(
   description="Fill out the name and email of the user.",
   expected_output="Name and email.",
   agent=name_email_agent,
   output_pydantic=nameEmail,
   human_input=False
)

Let’s use the other way to structure the output by using the “output_json” parameter in Task() which gives the output in json format. 

# Task 2: Agent for filling phone number using output_json
phone_number_agent = Agent(
   role="Contact Information Manager",
   goal="Your task is to fill out a random 10 digit phone number on your own.",
   backstory=(
       "You are an expert in managing contact details, specifically phone numbers."
   ),
   allow_delegation=False,
   verbose=True
)
phone_number_task = Task(
   description="Fill out the user's phone number.",
   expected_output="A JSON format with the user's phone number.",
   agent=phone_number_agent,
   output_json=phoneNo,
   human_input=False
)

Here, the agent is designed to fill out the job details for the user. The final output will contain all the name, email, phone number, and job role information as pedantic and stored in output.txt using the “output_file” parameter. 

# Task 3: Agent for filling job description using output_file
job_description_agent = Agent(
   role="Job Decider",
   goal="Your task is to randomly decide a job for the user",
   backstory=(
       "You handle assigning job roles randomly."
   ),
   allow_delegation=False,
   verbose=True
)

job_description_task = Task(

   description="Fill out the user's job description.",

   expected_output="Display name, email, phone no and job description.",

   agent=job_description_agent,

   output_pydantic=allDetails,

   output_file="/content/output.txt",

   human_input=False

)
# Define the crew to run all tasks
crew = Crew(
   agents=[name_email_agent, phone_number_agent, job_description_agent],
   tasks=[name_email_task, phone_number_task, job_description_task],
   verbose=True,
   memory=False
)
result = crew.kickoff()
# Agent: Data Entry Specialist

## Task: Fill out the name and email of the user.

# Agent: Data Entry Specialist

## Final Answer: 

Name: Elowen Thorne  

Email: [email protected]

# Agent: Contact Information Manager

## Task: Fill out the user's phone number.

# Agent: Contact Information Manager

## Final Answer: 

{

  "name": "Elowen Thorne",

  "email": "[email protected]",

  "phone_number": "1234567890"

}

# Agent: Job Decider

## Task: Fill out the user's job role.

# Agent: Job Decider

## Final Answer: 

Name: Elowen Thorne  

Email: [email protected]  

Phone No: 1234567890  

Job Role: Data Analyst

This is the output file that was created :

Output

You can also look at each task’s output:

job_description_task.output
TaskOutput(description="Fill out the user's job role.", name=None,
expected_output='Display name, email, phone no and job role.', summary="Fill
out the user's job role....", raw='Name: Elowen Thorne  \nEmail:
[email protected]  \nPhone No: 1234567890  \nJob Role: Data
Analyst', pydantic=allDetails(name='Elowen Thorne', email=
['[email protected]'], phone=1234567890, job='Data Analyst'),
json_dict=None, agent='Job Decider', output_format=<OutputFormat.PYDANTIC:
'pydantic'>)

I got the expected output, and due to structuring the intermediate outputs, the details remained constant as each task progressed. 

Also, to understand the Agent AI better, explore: The Agentic AI Pioneer Program.

Conclusion

This article explored the importance of structuring inputs and outputs in multi-agent using tools like Pydantic models and CrewAI. By organizing data effectively and validating inputs, we can significantly enhance the performance and reliability of multi-agent systems. Structured outputs help maintain consistency and prevent errors such as data loss and hallucinations, ensuring that agents can collaborate efficiently. Implementing these strategies allows developers to create more robust agentic systems capable of handling complex tasks with greater precision and reliability.

Frequently Asked Questions

Q1. What are agent-based systems?

Ans. Agent-based systems involve multiple agents working together to solve problems, communicate, and collaborate, providing more robust solutions than single systems like LLMs.

Q2. What is CrewAI, and how does it integrate with agentic systems?

Ans. CrewAI is a framework that supports agentic systems, allowing agents to work together to solve tasks. In this article, we use CrewAI with pedantic models to structure outputs and ensure proper data management between agents.

Q3. How do you input an image in CrewAI?

Ans. One way to input an image in CrewAI is by assigning the URL of the image to a variable and then passing it to the inputs parameter in crew.kickoff(). 

Q4. What are Pydantic models, and how are they used in agentic systems?

Ans. Pydantic models are Python objects used for data validation and serialization. They help ensure that inputs and outputs between agents are properly structured, leading to more reliable outcomes in agent-based systems.

Q5. How do you structure outputs in agentic systems using Pydantic models?

Ans. Outputs are structured by defining the expected fields (like name, email, etc.) using Pydantic models, which ensures that the next agent receives valid and well-formatted data for processing.

I'm a tech enthusiast, graduated from Vellore Institute of Technology. I'm working as a Data Science Trainee right now. I am very much interested in Deep Learning and Generative AI.

Responses From Readers

Clear

We use cookies essential for this site to function well. Please click to help us improve its usefulness with additional cookies. Learn about our use of cookies in our Privacy Policy & Cookies Policy.

Show details