Let me now create a new file and I'm going to call it schemas dot p y.
And this file is going to hold the pydantic classes that we want to get structured output of.
And by the way when we installed Linkchain we implicitly installed Pydantic because Linkchain uses Pydantic
a lot in our implementation.
So just to give you a quick overview.
Pydantic is a Python library for data validation using Python typings.
So it automatically validates the data, converts types when possible, and provides clear error messages
when the data doesn't match our descriptions.
And it turns out using Pydantic objects to describe structured output for Llms is very, very effective.
And we're going to see that.
And we're going to discuss at the end of this video why this is happening and why this is working so
well together.
All right.
Let me start with the imports.
So let me first import the type annotation of list.
And I also want to import from pedantic.
The base model and field and base model is the core pedantic class that we're going to inherit from
in order to create our own data models and data objects.
And when we create the class that is going to inherit from base model, we get automatic validations,
realization from JSON and ID auto complete.
And this is very useful.
Now field is a function that lets us add extra validation and metadata to our model attributes.
And we can set constraints like minimum maximum maybe descriptions and default values.
And this is very very useful when we want to create those data objects.
All right let's go and see this in action.
So let's create now a new class which will inherit from base model.
And let's call this class source.
Now source is going to have one attribute, which is going to be a URL, and its type is going to be
string.
Now I'm using now the field function to add a description to mention that this is the URL of the source.
Now notice here I also wrote a short description that this is the schema for a source used by the agent.
So you can imagine that we are going to propagate all of this information eventually to an LLM.
So this is what is going to help us get structured output.
All right.
Let's now create our second class which is going to be our agent response class.
So it's also going to inherit from the base model.
And here the description is going to be that this is the schema for the agent response with answer and
sources.
Right.
So we want now the agent to return us two fields.
One is going to be the field answer which is going to be a string.
And here you can see we added the description of this is the agent's answer to the query.
And if we'll take our example from before, where we asked for job postings for AI engineers in Lake
Chain in the Bay area.
So the answer of the agent should be here in this field.
So it's going to be here the list of three job openings that we looked for.
So the second thing is it's going to have an attribute of sources.
Now notice here the type hinting.
This is going to be a list of the source class that we created before.
And here in the description is going to be the list of sources used to generate the answer.
And the default factory list tells pedantic to call the list function to create a new empty list for
each instance where no value is provided.
So this is going to ensure that all of the instances get their own independent lists.
Cool.
So I also wanted to add to this example a nested class.
So notice the agent response holds within it the class of source.
So we have here two pedantic objects, which we compose one on another.
And LM these days can easily handle this kind of composition and to output those kinds of nested objects.
And a fun fact, this wasn't always the case.
So in the past LMS, even top tier LMS struggled with this task.
However, this is not the case today.
We can easily do those kinds of things.
All right so let's go now and format the code.
Let me write here black.
And I sort all right.
So all of this information here on the answers that we expect to do, they need somehow to be plugged
into the prompt that we send the large language model.
So somewhere somebody needs to plug this information in.
So this is what we're going to do now.
So let's go and create a new file and let's call it prompt py.
And here we're going to write our own special prompt.
I'm going to call it the react prompt with format instructions.
And this prompt is going to be the react prompt that we already saw from before.
But we're going to transform it a bit and add here our format instructions.
So the information that we want to give the LLM for us to get a structured response.
So let me go to the prompt in the prompt tab and let me copy it and paste it.
All right.
So this is the exact prompt that we used before.
And now we want to do a bit of prompt engineering.
And here in this final answer clause here.
So I'm going to edit this prompt a bit.
And here I want to tell the LLM to use the format instructions that I'm going to plug it in in the final
answer.
And let me now read this line, the final answer to the original input question formatted according
to the format Instructions and then the placeholder format instructions.
And you can probably guess that we're going to plug in some dynamic value of the objects that we want
our LM to structure.
Alrighty.
So let's go now to the main file.
And we want to use now this prompt in our reasoning chain.
So we want to get rid of this prompt here.
And here we want to put our new and revised prompt that we just wrote here.
Cool.
So let me go now and let me import some classes that we'll be needing here.
So let's go to the top of the file.
And I'm going to paste in those couple of imports here I want to import the pedantic output parser.
And let's have a sneak peek on the implementation here.
And this class is a link chain output parser.
And it's going to take the response that we get from the LM.
And it's going to parse that response into a Pydantic model object.
Now, we're not going to dive into the implementation here.
It's really some ugly parsing here.
And really nobody wants to see this.
And the assumption here is that the response which the LM is going to return is going to be a JSON response,
which is going to be in the Pydantic object format.
So this class shouldn't have any hard time doing it, because we're leaving all of the output and structuring
the data to the LM.
So the LM is going to do all of the heavy lifting.
And this class is simply going to take the response.
And it's going to format it nicely as a Pydantic object.
Alrighty.
So let's go back to the imports.
And we also imported prompt template which we know from previous lessons.
And we imported a class which is called Runnable Lambda.
Now this is a part of the link chain expression language.
And we'll be seeing and learning it very, very soon.
So I don't want to talk about it right now.
And let's go and import the prompt that we wrote and the agent response class from our schema.py file.
Let me just see that the imports are referring to the right code.
So let me go here and let me click here.
And yeah so this seems to be right.
Imports.
All right.
So let me go now and paste this line over here.
And this is going to be the output parser that we're going to create.
It's going to be an object of the pedantic output parser.
And it's going to receive as an input the agent response object.
So we want the output parser to parse objects of the type agent response.
And now I want to create the react prompt with format instructions.
So it's going to be an object of the prompt template.
And the template is going to be what we wrote in the prompt.py file.
So it's going to be the value of the react prompt with format instructions.
So this is now the new template we're going to be using.
So it's going to have the same input variables like before.
So it's going to have a tool names.
It's going to have the input the agent scratchpad.
And by the way notice here I forgot actually to write the tools input variable.
And funny enough this is still going to work.
And I've debugged it for a bit.
And it turns out that in the prompt template logic the login object, they go through the prompt and
they extract everything between those curly brackets and they implicitly add them as input variables.
So this is why the missing tools input variable, which is missing here, is still going to be populated
over here.
And I highly suggest you do those kinds of exercises where if something doesn't add up, simply take
a look at the implementation.
You will have all the answers there anyways.
So up until now we did everything that we know.
We populated the prompt template, but there is something else we need to do here.
So we need to provide those format instructions here.
So we're going to do that with the partial method which is going to allow us to partially format a form
template by pre-filling some of its variables to create a new prompt template that only requires the
remaining variables to be provided later.
And this is useful when we have some variables available early, but others later in the workflow.
So I want to partially populate first the format instructions placeholder, and the value I'm going
to give it is I'm going to give it the output parser.
It has a function or a method which is called get format instructions.
And it's going to get us the format instructions where we want to plug in.
And we're reviewing those format instructions A very very soon.
And anyways, last thing I want to do is to switch the prompt when creating the reasoning chain with
the prompt with format instructions.
And let me run this in debug, because I want to show you the get format instructions here.
So once it's going to get to this breakpoints, let me go and let me copy this expression over here.
Let's paste it here in the debug console.
And here we can see those are the formatting instructions.
The output should be formatted as a JSON instance that conforms to the JSON schema below.
And in example blah blah blah blah.
And at the bottom here we're going to have all the metadata of our Pydantic objects that we wrote.
So eventually this is going to be propagated to the LLM.
And the LLM is going to return us a JSON response that is adhering here to those fields and to those
requirements.
We write it over here.
So this is actually very smart.
And LMS now are very good at doing those things.
So the output parser later is going to have a very easy time taking that JSON and turning that JSON
into a Pydantic object.
All right.
So now let me run everything before we even go and parse it.
And I want to show you the response that we eventually get from the agent here.
So let's go and click run.
And let me fast forward everything here.
All right.
So we got here a response.
Now notice here that in the output field here we can see that we actually have here a JSON which has
the answer key.
And it also has the sources key with the URLs.
So the LLM did what it was supposed to do.
So let me go.
And now put a breakpoint here and run it in debug and let me go and fast forward it again.
So we got the result.
And here is the output key.
And this is here a JSON string.
So let me go and even prove it to you.
And let's go to the debug console.
And let's go and check the types.
So the type of a result is going to be a dictionary.
And the type of result in the key of output is going to be a string.
And this is the JSON string.
And it has all of the properties of the Pydantic object that we want.
So now let me show you how simple it is to create this Pydantic object.
So I'm going to use the output parser of Linkchain.
And it has a method which is called parse.
And I'm going to give it this result here in the output key.
And this is going to parse it into the answer agent object that we want to.
And we can see now the result is of type agent response where we have the answer as the first attribute.
And we also have the sources attribute which is going to be a list of sources.
So this is a very cool.
And now we actually have an object that we can work with programmatically.
So if we want we can downstream it into an application maybe to a front end or expose it via API to
serialize it.
So we have lots of flexibility of what we can do here.
And we can build really robust software leveraging Llms with these kinds of functionality.
So this is a very important part of Linkchain.
And let me show you what I mean.
So let's go and take the parsed object and let's go for example in access the answer here.
So this is the string answer.
Let's go now and check out the sources.
And this is here a list of sources where each source has a URL attribute.
So we can check it for example like this.
This is the URL of one source and we can continue to iterate through the URLs.
Let me just open it and we can see that it opens a valid LinkedIn page.
Hey there.
Ethan here popping out.
And yeah, in case you're wondering, those are new glasses.
Turns out I need glasses in order to review the screen.
You can see much better now, I can tell you that.
And anyways, by now, I hope you have a better understanding of what is output parsing.
Why do we need it?
How does it work?
It all boils down to a prompt.
We send the LM.
The LM structures the output according to our instructions, and then Linkchain simply takes it and
simply formats it nicely to our Pydantic object.
Right?
So in the next video, I want to use the chain expression language to take the output of our agent and
to format it nicely.