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.
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])from pydantic import BaseModel
class Reply(BaseModel):
order_id: str
status: str
email: strA 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.
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
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.
- Add a field
refund: bool = FalsetoReplyand run the first example. - Script a reply whose
statusis a number and read the error. - Use
output_json=Replyinstead and printresult.json_dict.
Every expert started right here.