WEBVTT

00:00.050 --> 00:02.220
-: In the last video, we explored the Runnable protocol

00:02.220 --> 00:03.150
in great detail.

00:03.150 --> 00:04.890
In this video, we're gonna mix it up a little bit

00:04.890 --> 00:06.990
and show you some more practical examples

00:06.990 --> 00:09.720
now that you've got those strong foundations about Runnable

00:09.720 --> 00:11.280
lambdas and Runnable parallels

00:11.280 --> 00:14.190
and how those kind of interact with dictionaries as well.

00:14.190 --> 00:15.810
So, we're gonna import a couple of things.

00:15.810 --> 00:18.360
This Runnable PassThrough, Runnable Parallel,

00:18.360 --> 00:19.800
and Runnable Lambda.

00:19.800 --> 00:23.130
Now, one thing I wanna show you is how it's easily possible

00:23.130 --> 00:25.830
to access previous values using something called

00:25.830 --> 00:27.300
a Runnable PassThrough.

00:27.300 --> 00:29.220
So if we set up a Runnable Parallel

00:29.220 --> 00:32.457
and we have this origin, which is just the Runnable

00:32.457 --> 00:36.090
PassThrough, and we have a modified, which is a Lambda,

00:36.090 --> 00:38.070
which has X plus X one.

00:38.070 --> 00:39.245
And if we invoke that,

00:39.245 --> 00:42.147
what you'll see is we get back the original

00:42.147 --> 00:45.840
and we also get back this parsed, right?

00:45.840 --> 00:48.878
So let me just show you, if I was to print this one here,

00:48.878 --> 00:50.250
(keyboard clacking)

00:50.250 --> 00:53.940
you'll see we get the original and we also get the modified.

00:53.940 --> 00:55.800
So we invoked it with one.

00:55.800 --> 00:57.930
We get back the original key,

00:57.930 --> 01:00.960
and also we get back a new key called modified,

01:00.960 --> 01:04.530
which just takes the Lambda X and and pluses one to that.

01:04.530 --> 01:08.267
Additionally, we can do things like take in an LLM response

01:08.267 --> 01:10.200
and then we can do something to that.

01:10.200 --> 01:13.710
So we have the original, which in this case is Hello,

01:13.710 --> 01:15.480
which is the Runnable PassThrough.

01:15.480 --> 01:20.100
And then we have a, the parsed, which is reversing the text.

01:20.100 --> 01:23.610
So it's possible to use these Runnable PassThroughs

01:23.610 --> 01:27.480
to get the original output from a Runnable,

01:27.480 --> 01:30.660
and then to, we can also manipulate it or add extra keys

01:30.660 --> 01:31.560
if we want as well.

01:31.560 --> 01:33.831
So the Runnable pass through is a way for you to

01:33.831 --> 01:37.320
get the original PassThrough of the previous output

01:37.320 --> 01:39.330
without any changes to the keys.

01:39.330 --> 01:42.270
You'll use this when you've got larger prompt chains.

01:42.270 --> 01:44.250
Let's see how you can do this using a prompt

01:44.250 --> 01:45.720
and a model though.

01:45.720 --> 01:48.630
We first start by importing Chat OpenAI

01:48.630 --> 01:50.340
and a Chat prompt template.

01:50.340 --> 01:52.410
We then load up the model using the chat,

01:52.410 --> 01:54.000
and we then use the from template

01:54.000 --> 01:56.550
to tell me a joke about topic.

01:56.550 --> 01:59.820
Notice here is where we're using that pipe operator.

01:59.820 --> 02:01.500
This is the core foundation

02:01.500 --> 02:03.414
of LangChain expression language.

02:03.414 --> 02:07.560
We have the prompt on the left, pipe chat,

02:07.560 --> 02:09.693
which creates a runnable chain.

02:10.530 --> 02:12.300
The chain actually does have some things

02:12.300 --> 02:13.230
that are quite interesting.

02:13.230 --> 02:15.870
So we can do chain.first, chain.last,

02:15.870 --> 02:19.170
and it'll tell us about what is actually first in the chain

02:19.170 --> 02:20.770
and what's at last in the chain.

02:21.870 --> 02:23.070
In terms of the interface

02:23.070 --> 02:25.269
about how you can use these Runnable chains,

02:25.269 --> 02:27.840
there are various ways you can do this.

02:27.840 --> 02:30.987
One approach is to use the streaming.stream function

02:30.987 --> 02:33.030
while we passing the topic

02:33.030 --> 02:36.393
and then we can print the contents of the docs.

02:37.770 --> 02:40.020
Another way is to basically say,

02:40.020 --> 02:42.911
let's invoke the function using chain.invoke

02:42.911 --> 02:45.330
and then get the content of that.

02:45.330 --> 02:46.650
Or if we want to do multiple,

02:46.650 --> 02:48.870
we can even use the chain.batch.

02:48.870 --> 02:50.640
So let's see these in action.

02:50.640 --> 02:52.678
You'll see that the streaming one comes in first,

02:52.678 --> 02:55.740
followed by the invoke, follow the by the batch.

02:55.740 --> 02:58.380
This is because streaming is always faster in terms

02:58.380 --> 03:02.130
of latency, and then the invoke is only doing one LLM

03:02.130 --> 03:05.499
request whilst the dot batch is actually doing three batches

03:05.499 --> 03:08.733
on three separate jokes for bears.

03:10.380 --> 03:13.560
Moving on, we can also do some things using retrieval

03:13.560 --> 03:15.210
augmented generation inside of

03:15.210 --> 03:16.980
LangChain expression language.

03:16.980 --> 03:19.620
For example, we can install some relevant packages.

03:19.620 --> 03:21.540
We will use the item.getter.

03:21.540 --> 03:24.390
We'll add some extra things like the OpenAI embeddings

03:24.390 --> 03:26.730
and a string output passer.

03:26.730 --> 03:30.401
We set up our vector database with fast from text,

03:30.401 --> 03:33.810
and then we insert some texts about James, where he works

03:33.810 --> 03:36.380
and his age, and we are using the OpenAI embeddings

03:36.380 --> 03:37.680
to do this.

03:37.680 --> 03:39.450
We then set up our retriever,

03:39.450 --> 03:41.497
and then we have a prompt template that says,

03:41.497 --> 03:43.057
"Answer the question based only

03:43.057 --> 03:46.110
"on the following context," with the question.

03:46.110 --> 03:49.020
This then creates our prompts and we have our model.

03:49.020 --> 03:51.360
Now we want to make sure that the model

03:51.360 --> 03:54.960
receives the extra documents and does a query

03:54.960 --> 03:57.450
against those documents in the retrieval

03:57.450 --> 04:00.240
to answer that question based on the context

04:00.240 --> 04:02.850
that you can see in this prompt template.

04:02.850 --> 04:05.225
We say the context is the retriever,

04:05.225 --> 04:09.300
and we say the question is a Runnable PassThrough.

04:09.300 --> 04:12.150
Those are gonna get parsed into our prompt,

04:12.150 --> 04:14.160
which will then get parsed into the model.

04:14.160 --> 04:16.860
And then rather than having to do the dot content,

04:16.860 --> 04:19.530
we're gonna use string output parser,

04:19.530 --> 04:23.370
which is gonna basically get the output of that LLM

04:23.370 --> 04:24.810
in a string form.

04:24.810 --> 04:27.120
So now I can say something like, so let me just go

04:27.120 --> 04:28.623
and run these cells.

04:31.650 --> 04:35.010
So now I can say, what company does James Phoenix work at?

04:35.010 --> 04:37.560
James Phoenix works at Just Understanding Data.

04:37.560 --> 04:38.940
And what is James's age?

04:38.940 --> 04:41.313
Well, James's age is 31 at the moment.

04:42.750 --> 04:45.900
Let's also have a bit of time talking about the item getter

04:45.900 --> 04:47.100
and how that works.

04:47.100 --> 04:48.390
So if you've got a dictionary here

04:48.390 --> 04:51.450
and you've got a key of data and you have a list,

04:51.450 --> 04:53.068
when you do item getter test,

04:53.068 --> 04:56.040
you'll see it gives you back an operator.

04:56.040 --> 04:58.320
Now you can use that with, for example,

04:58.320 --> 05:00.120
we can say item getter.

05:00.120 --> 05:04.047
I want to get the data key on this thing, which is test.

05:04.047 --> 05:06.120
And you'll then see we get back the Python list.

05:06.120 --> 05:08.880
So the item getter is a way for us

05:08.880 --> 05:11.610
to get previous outputs from chains

05:11.610 --> 05:15.390
that we can use in further downstream prompt chains

05:15.390 --> 05:17.160
inside of LCL.

05:17.160 --> 05:19.590
Now let's have a look at this as an example.

05:19.590 --> 05:21.630
So we've got this chat prompt template.

05:21.630 --> 05:23.520
What is the profession of James Phoenix

05:23.520 --> 05:25.541
and his profession is profession.

05:25.541 --> 05:28.676
Now we have a first chain where we say, let's set the name

05:28.676 --> 05:31.980
to James and his age at 31.

05:31.980 --> 05:34.260
Now on the second chain, notice how we're using

05:34.260 --> 05:36.810
this item getter, this function,

05:36.810 --> 05:38.190
and we're parsing in the name key

05:38.190 --> 05:39.920
because this is the first chain,

05:39.920 --> 05:41.859
and we want to get those properties,

05:41.859 --> 05:44.940
which will then be parsed to the prompt template.

05:44.940 --> 05:48.750
We can also set extra properties by just using a lambda.

05:48.750 --> 05:51.089
So you can see the first chain gets executed,

05:51.089 --> 05:54.063
which will then get parsed into the second chain,

05:54.930 --> 05:57.230
and we can get those things using the item getter,

05:57.230 --> 05:58.740
so the name and the age.

05:58.740 --> 06:00.690
These are then parsed into the prompt,

06:00.690 --> 06:02.990
and then those are then parsed into the model.

06:04.170 --> 06:06.660
So you'll now see that it says James Phoenix

06:06.660 --> 06:08.460
is a data engineer.

06:08.460 --> 06:10.260
Now, I could even take this one step further

06:10.260 --> 06:13.380
and say, let's put a string output parser out the end.

06:13.380 --> 06:16.387
So pipe string output parser,

06:16.387 --> 06:17.970
and you'll see we don't even get an AI message anymore.

06:17.970 --> 06:19.080
We get the string.

06:19.080 --> 06:21.090
And this is the beautiful nature

06:21.090 --> 06:23.640
of LangChain expression language is you can set up

06:23.640 --> 06:27.270
these pipe operators to get relevant keys

06:27.270 --> 06:29.370
from previous chains.

06:29.370 --> 06:31.380
And also, as well as that, we can use things

06:31.380 --> 06:33.690
like the string output parser to get strings out to then

06:33.690 --> 06:35.520
parses in for downstream chains.

06:35.520 --> 06:37.795
Now, I will highlight that the item getter

06:37.795 --> 06:40.230
only works one layer deep.

06:40.230 --> 06:42.873
So for example, if we had a third chain here,

06:44.610 --> 06:46.800
the third chain would not have access

06:46.800 --> 06:49.110
to the first chain keys.

06:49.110 --> 06:52.110
That's a big gotcha, because a lot of you would,

06:52.110 --> 06:55.890
it might assume that perhaps potentially the first chain

06:55.890 --> 06:57.990
would always be accessible to the second chain,

06:57.990 --> 06:59.400
and the first chain would always be accessible

06:59.400 --> 07:02.100
to the third chain, and that's not necessarily true.

07:02.100 --> 07:05.100
So it is good practice if you need to parse things down

07:05.100 --> 07:08.220
further and further along, make sure that you still write

07:08.220 --> 07:11.820
those same keys in your second chain or your third chain,

07:11.820 --> 07:15.420
and use the item getter to parse those through.

07:15.420 --> 07:16.920
That's one approach.

07:16.920 --> 07:20.460
Just be aware that is a current limitation of LCL.

07:20.460 --> 07:21.567
Cool.

07:21.567 --> 07:23.400
So we've done a quick introduction into

07:23.400 --> 07:25.260
how Runnable PassThrough works.

07:25.260 --> 07:28.620
We also looked at how you can set up a chat model

07:28.620 --> 07:30.900
using a prompt and a chat model,

07:30.900 --> 07:34.500
and also using a string output parser to get that as well.

07:34.500 --> 07:36.300
And then we've also had a look a little bit

07:36.300 --> 07:37.133
at multiple chainings.

07:37.133 --> 07:40.200
In the next video, we will explore multiple chains

07:40.200 --> 07:41.790
and more complicated ones.

07:41.790 --> 07:42.990
See you in the next one.
