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

Answers with a fixed shape

output_pydantic makes a task's answer a Pydantic object instead of free text, so the next piece of code can read fields rather than parse a sentence.

Lesson 14's writer returns an email as text. The shop's ticket system needs the order id and status as separate fields.

Examplecrew.py, from lesson 14
from crewai import Agent, Crew, Task
from shop_llm import ShopLLM
from tools import lookup_order

clerk = Agent(role="Order clerk", goal="Find the status of customers' orders",
              backstory="You can look up any order in the shop's system.",
              llm=ShopLLM(model="shop"), tools=[lookup_order])
writer = Agent(role="Reply writer", goal="Write replies to customers",
               backstory="You write short, friendly emails.",
               llm=ShopLLM(model="shop"))

look = Task(description="Find the order in this message: {question}",
            expected_output="The order's status.", agent=clerk)
reply = Task(description="Write the customer a reply.",
             expected_output="A short, friendly email.", agent=writer)
crew = Crew(agents=[clerk, writer], tasks=[look, reply])
Examplereply.py
from pydantic import BaseModel


class Reply(BaseModel):
    order_id: str
    status: str
    email: str

A Pydantic model lists the fields and their types. Setting it as the task's output_pydantic tells CrewAI to ask for that shape and check the answer against it.

Example
reply.output_pydantic = Reply
writer.llm.script = ['{"order_id": "A17", "status": "shipped", "email": "Dear customer, A17 shipped on 3 March."}']

result = crew.kickoff(inputs={"question": "Where is my order A17?"})
print(repr(result.pydantic))
print(result["status"])

The writer's model is scripted to answer in JSON, since writing JSON for any schema is beyond a few lines of Python. CrewAI appended the schema to the task's prompt, parsed the reply and validated it. result.pydantic is a Reply, and indexing the result with a field name reads from it.

A reply that does not fit

Example
reply.output_pydantic = Reply
writer.llm.script = ["A17 shipped on 3 March."]

try:
    crew.kickoff(inputs={"question": "Where is my order A17?"})
except Exception as error:
    print(type(error).__name__)
    print(error)

Plain text cannot become a Reply, and the run stops with ConverterError. The message in 1.15.22 talks about a missing agent although the task has one; the cause is the text. A hosted model given the schema usually gets it right, and lesson 16 shows how to send a wrong answer back for another try.

Try it yourself
  • Add a field refund: bool = False to Reply and run the first example.
  • Script a reply whose status is a number and read the error.
  • Use output_json=Reply instead and print result.json_dict.

Every expert started right here.