-: In the last video, we explored the Runnable protocol
in great detail.
In this video, we're gonna mix it up a little bit
and show you some more practical examples
now that you've got those strong foundations about Runnable
lambdas and Runnable parallels
and how those kind of interact with dictionaries as well.
So, we're gonna import a couple of things.
This Runnable PassThrough, Runnable Parallel,
and Runnable Lambda.
Now, one thing I wanna show you is how it's easily possible
to access previous values using something called
a Runnable PassThrough.
So if we set up a Runnable Parallel
and we have this origin, which is just the Runnable
PassThrough, and we have a modified, which is a Lambda,
which has X plus X one.
And if we invoke that,
what you'll see is we get back the original
and we also get back this parsed, right?
So let me just show you, if I was to print this one here,
(keyboard clacking)
you'll see we get the original and we also get the modified.
So we invoked it with one.
We get back the original key,
and also we get back a new key called modified,
which just takes the Lambda X and and pluses one to that.
Additionally, we can do things like take in an LLM response
and then we can do something to that.
So we have the original, which in this case is Hello,
which is the Runnable PassThrough.
And then we have a, the parsed, which is reversing the text.
So it's possible to use these Runnable PassThroughs
to get the original output from a Runnable,
and then to, we can also manipulate it or add extra keys
if we want as well.
So the Runnable pass through is a way for you to
get the original PassThrough of the previous output
without any changes to the keys.
You'll use this when you've got larger prompt chains.
Let's see how you can do this using a prompt
and a model though.
We first start by importing Chat OpenAI
and a Chat prompt template.
We then load up the model using the chat,
and we then use the from template
to tell me a joke about topic.
Notice here is where we're using that pipe operator.
This is the core foundation
of LangChain expression language.
We have the prompt on the left, pipe chat,
which creates a runnable chain.
The chain actually does have some things
that are quite interesting.
So we can do chain.first, chain.last,
and it'll tell us about what is actually first in the chain
and what's at last in the chain.
In terms of the interface
about how you can use these Runnable chains,
there are various ways you can do this.
One approach is to use the streaming.stream function
while we passing the topic
and then we can print the contents of the docs.
Another way is to basically say,
let's invoke the function using chain.invoke
and then get the content of that.
Or if we want to do multiple,
we can even use the chain.batch.
So let's see these in action.
You'll see that the streaming one comes in first,
followed by the invoke, follow the by the batch.
This is because streaming is always faster in terms
of latency, and then the invoke is only doing one LLM
request whilst the dot batch is actually doing three batches
on three separate jokes for bears.
Moving on, we can also do some things using retrieval
augmented generation inside of
LangChain expression language.
For example, we can install some relevant packages.
We will use the item.getter.
We'll add some extra things like the OpenAI embeddings
and a string output passer.
We set up our vector database with fast from text,
and then we insert some texts about James, where he works
and his age, and we are using the OpenAI embeddings
to do this.
We then set up our retriever,
and then we have a prompt template that says,
"Answer the question based only
"on the following context," with the question.
This then creates our prompts and we have our model.
Now we want to make sure that the model
receives the extra documents and does a query
against those documents in the retrieval
to answer that question based on the context
that you can see in this prompt template.
We say the context is the retriever,
and we say the question is a Runnable PassThrough.
Those are gonna get parsed into our prompt,
which will then get parsed into the model.
And then rather than having to do the dot content,
we're gonna use string output parser,
which is gonna basically get the output of that LLM
in a string form.
So now I can say something like, so let me just go
and run these cells.
So now I can say, what company does James Phoenix work at?
James Phoenix works at Just Understanding Data.
And what is James's age?
Well, James's age is 31 at the moment.
Let's also have a bit of time talking about the item getter
and how that works.
So if you've got a dictionary here
and you've got a key of data and you have a list,
when you do item getter test,
you'll see it gives you back an operator.
Now you can use that with, for example,
we can say item getter.
I want to get the data key on this thing, which is test.
And you'll then see we get back the Python list.
So the item getter is a way for us
to get previous outputs from chains
that we can use in further downstream prompt chains
inside of LCL.
Now let's have a look at this as an example.
So we've got this chat prompt template.
What is the profession of James Phoenix
and his profession is profession.
Now we have a first chain where we say, let's set the name
to James and his age at 31.
Now on the second chain, notice how we're using
this item getter, this function,
and we're parsing in the name key
because this is the first chain,
and we want to get those properties,
which will then be parsed to the prompt template.
We can also set extra properties by just using a lambda.
So you can see the first chain gets executed,
which will then get parsed into the second chain,
and we can get those things using the item getter,
so the name and the age.
These are then parsed into the prompt,
and then those are then parsed into the model.
So you'll now see that it says James Phoenix
is a data engineer.
Now, I could even take this one step further
and say, let's put a string output parser out the end.
So pipe string output parser,
and you'll see we don't even get an AI message anymore.
We get the string.
And this is the beautiful nature
of LangChain expression language is you can set up
these pipe operators to get relevant keys
from previous chains.
And also, as well as that, we can use things
like the string output parser to get strings out to then
parses in for downstream chains.
Now, I will highlight that the item getter
only works one layer deep.
So for example, if we had a third chain here,
the third chain would not have access
to the first chain keys.
That's a big gotcha, because a lot of you would,
it might assume that perhaps potentially the first chain
would always be accessible to the second chain,
and the first chain would always be accessible
to the third chain, and that's not necessarily true.
So it is good practice if you need to parse things down
further and further along, make sure that you still write
those same keys in your second chain or your third chain,
and use the item getter to parse those through.
That's one approach.
Just be aware that is a current limitation of LCL.
Cool.
So we've done a quick introduction into
how Runnable PassThrough works.
We also looked at how you can set up a chat model
using a prompt and a chat model,
and also using a string output parser to get that as well.
And then we've also had a look a little bit
at multiple chainings.
In the next video, we will explore multiple chains
and more complicated ones.
See you in the next one.