WEBVTT

00:00.180 --> 00:02.610
-: Alright, so in the last video we covered looking

00:02.610 --> 00:05.550
at chat message history and also memory.

00:05.550 --> 00:07.410
In this video what we're gonna have a look at is

00:07.410 --> 00:10.020
how we can branch out using conditional logic

00:10.020 --> 00:12.360
by using something called the RunnableBranch.

00:12.360 --> 00:15.600
As well as that we will explore a concept called,

00:15.600 --> 00:17.940
sort of, branching and merging.

00:17.940 --> 00:19.560
So let's start with the first one

00:19.560 --> 00:22.110
and we're just gonna do a couple of imports

00:22.110 --> 00:24.090
and then we we'll have a look at this,

00:24.090 --> 00:28.350
which is basically branching with conditional logic.

00:28.350 --> 00:29.820
So I've done a really simple example

00:29.820 --> 00:31.770
so that you can see how this works.

00:31.770 --> 00:33.630
So we've got our RunnableBranch.

00:33.630 --> 00:37.350
You do have to have a generic catch-all case

00:37.350 --> 00:40.140
in case none of the conditionals match, right?

00:40.140 --> 00:43.050
So if we remove the sort of standard one that would run,

00:43.050 --> 00:45.210
you see that basically it has to have one

00:45.210 --> 00:46.290
without kind of like a

00:46.290 --> 00:48.660
you can call this like a default,

00:48.660 --> 00:49.710
you know, condition, right?

00:49.710 --> 00:52.980
If none of the conditions above are checked, right,

00:52.980 --> 00:56.040
so in this case we're checking to see does X equal hello

00:56.040 --> 00:58.170
or is X a type of string,

00:58.170 --> 00:59.670
but if it doesn't equal any of those

00:59.670 --> 01:03.540
when we need a standard kind of default catch all

01:03.540 --> 01:05.790
that will basically stop the RunnableBranch

01:05.790 --> 01:07.260
throwing an error.

01:07.260 --> 01:10.432
Now if I invoke this with hello

01:10.432 --> 01:12.682
(sneezing)

01:21.750 --> 01:23.700
Now if I invoke this with hello

01:23.700 --> 01:25.470
what's gonna happen is

01:25.470 --> 01:28.110
firstly we check to see does X equal hello.

01:28.110 --> 01:29.100
Oh, well it does

01:29.100 --> 01:32.010
and therefore we just return hello, right?

01:32.010 --> 01:33.420
And you can see that here.

01:33.420 --> 01:35.040
Now we also say, okay,

01:35.040 --> 01:36.690
if we invoke with none

01:36.690 --> 01:39.390
then we're not gonna match any against these cases.

01:39.390 --> 01:42.450
And you'll see this then triggers the default case.

01:42.450 --> 01:45.630
Now you could use the RunnableBranch just for doing,

01:45.630 --> 01:47.700
you know, different types of outputs,

01:47.700 --> 01:50.370
but you could also use the RunnableBranch if you wanted

01:50.370 --> 01:52.650
to run different types of chains based

01:52.650 --> 01:55.050
on the outputs from previous chains.

01:55.050 --> 01:55.883
So just have a think

01:55.883 --> 01:58.410
about how you would like to implement that as well.

01:59.880 --> 02:01.290
The next one we're gonna have a look at is

02:01.290 --> 02:03.060
something called branching and merging,

02:03.060 --> 02:05.250
which is where you want to take a input,

02:05.250 --> 02:06.930
do something separately

02:06.930 --> 02:09.210
in separate branches of workflow,

02:09.210 --> 02:13.020
and then combine those branches into a final result.

02:13.020 --> 02:14.970
Let's have a look at an example of this

02:14.970 --> 02:16.440
where we have a planner,

02:16.440 --> 02:19.440
which is saying generate an argument about input

02:19.440 --> 02:21.240
that then gets associated and piped

02:21.240 --> 02:22.800
with the ChatOpenAI,

02:22.800 --> 02:24.780
piped into a string output parser

02:24.780 --> 02:26.850
and then piped into a Python dictionary,

02:26.850 --> 02:29.700
which takes the output of the string output parser,

02:29.700 --> 02:31.590
which is from the runnable pass through.

02:31.590 --> 02:32.520
And then associates that

02:32.520 --> 02:35.520
with the base response key in the dictionary.

02:35.520 --> 02:37.560
We also have two prompt chains,

02:37.560 --> 02:42.480
which are separate chains for generating a arguments against

02:42.480 --> 02:43.833
and an arguments for.

02:45.540 --> 02:47.550
We then have a final responder,

02:47.550 --> 02:49.380
which says the AI,

02:49.380 --> 02:52.320
which is using the original response, the human,

02:52.320 --> 02:55.350
which provides the pros, results one and results two,

02:55.350 --> 02:57.000
for the pros and cons,

02:57.000 --> 02:58.950
and then has a system message that says,

02:58.950 --> 03:01.530
generate a final response given the critique,

03:01.530 --> 03:03.160
which pipes it into a ChatOpenAI

03:03.160 --> 03:04.550
and a string output parser.

03:04.550 --> 03:06.870
So you can kind of think of the final responder

03:06.870 --> 03:09.090
as the one that takes these,

03:09.090 --> 03:11.490
and that would be the equivalent of the combined step

03:11.490 --> 03:14.130
taking the outputs of branch one and branch two

03:14.130 --> 03:15.570
and combining that.

03:15.570 --> 03:16.650
So then it works like this.

03:16.650 --> 03:17.760
You have the planner,

03:17.760 --> 03:19.920
which then pipes into a dictionary

03:19.920 --> 03:22.710
and creates results one and results two,

03:22.710 --> 03:25.920
using the arguments for and arguments against chains.

03:25.920 --> 03:28.290
We then also add on the original response

03:28.290 --> 03:30.870
because remember the final responder chain

03:30.870 --> 03:32.880
is also going to need to know

03:32.880 --> 03:35.010
about the original response and, therefore,

03:35.010 --> 03:37.110
it's important that we also grab it

03:37.110 --> 03:40.980
from the planner chain so that we can pass that down

03:40.980 --> 03:43.770
and get that in the final responder.

03:43.770 --> 03:45.990
So then we have a results one,

03:45.990 --> 03:48.150
which gets associated with the pros,

03:48.150 --> 03:49.590
and a results two,

03:49.590 --> 03:52.020
which gets associated with the cons.

03:52.020 --> 03:53.670
We then have the original response,

03:53.670 --> 03:55.890
which is the AI's original response,

03:55.890 --> 03:58.980
and then that will then allow us to do something like this

03:58.980 --> 04:02.100
where we do chain.invoke, input, and then scrum,

04:02.100 --> 04:04.230
and then it has a little bit on scrum

04:04.230 --> 04:06.720
for the advantages and disadvantages.

04:06.720 --> 04:07.800
Now if you have a look here,

04:07.800 --> 04:11.760
it's taken around 35 seconds to generate that content.

04:11.760 --> 04:13.530
And the reason for this is we've got

04:13.530 --> 04:16.590
a little bit of synchronous API calls happening here

04:16.590 --> 04:18.180
where we have the input

04:18.180 --> 04:19.860
and we then synchronously wait

04:19.860 --> 04:22.410
for both branch one and branch two to finish

04:22.410 --> 04:25.590
before then taking the outputs of branch one and branch two

04:25.590 --> 04:28.440
and doing another LLM API request.

04:28.440 --> 04:30.600
So branching and merging,

04:30.600 --> 04:32.820
a little bit like sequential chains,

04:32.820 --> 04:36.690
can allow you to separate out logic and,

04:36.690 --> 04:39.750
but it also does come at the cost of increased time.

04:39.750 --> 04:41.700
And so, you know, it might not necessarily

04:41.700 --> 04:43.890
be the best responses for users

04:43.890 --> 04:46.080
that need to get a response very quickly,

04:46.080 --> 04:47.220
but it can be very useful

04:47.220 --> 04:49.980
for breaking the chain down into more complicated bits

04:49.980 --> 04:53.220
to solve more complicated problems.

04:53.220 --> 04:55.320
Let's also just reinforce that

04:55.320 --> 04:57.210
with having a look at a different example.

04:57.210 --> 04:59.070
So we've got this joke

04:59.070 --> 05:02.880
and then we've got a prompt template telling me a joke.

05:02.880 --> 05:05.040
We then get the joke and assign that,

05:05.040 --> 05:06.600
and we also get the topic

05:06.600 --> 05:08.730
from the runnable pass through as well.

05:08.730 --> 05:10.830
Now we then get the explain jokes.

05:10.830 --> 05:12.570
We ask it to explain the joke.

05:12.570 --> 05:15.210
We also say list all the benefits of the joke.

05:15.210 --> 05:16.800
And then we've got the final responder,

05:16.800 --> 05:18.570
which is, you know, you're responsible

05:18.570 --> 05:20.040
for doing a small analysis.

05:20.040 --> 05:21.660
The topic will be topic,

05:21.660 --> 05:23.700
and getting the joke, the benefits,

05:23.700 --> 05:25.350
the explanation of the joke,

05:25.350 --> 05:28.170
generate a small analysis of the joke.

05:28.170 --> 05:30.210
And then, so what we do is we get the topic,

05:30.210 --> 05:32.820
we pass that through as a runnable pass through,

05:32.820 --> 05:35.160
which gets added into the joke chain.

05:35.160 --> 05:39.570
From there, then notice how we're also reattaching the joke

05:39.570 --> 05:41.670
and the topic keys

05:41.670 --> 05:44.520
because we need those to get passed to the final responder.

05:44.520 --> 05:45.660
And this is the common thing

05:45.660 --> 05:47.820
when you're doing these sort of sequential chains,

05:47.820 --> 05:49.440
or branching or merging chains,

05:49.440 --> 05:51.600
where you have to remember to get the keys

05:51.600 --> 05:54.300
from previous chains so that they can get passed down

05:54.300 --> 05:55.980
to the final chains as well.

05:55.980 --> 05:57.510
So that's a big lesson that, you know,

05:57.510 --> 05:59.850
it can take you a bit of time to figure that out.

05:59.850 --> 06:03.090
And also notice how the explanation key

06:03.090 --> 06:04.920
and the benefits keys,

06:04.920 --> 06:08.040
these two keys are coming from the outputs of prompt chains.

06:08.040 --> 06:09.360
And the reason why this works is

06:09.360 --> 06:12.510
'cause we are using this string output parser,

06:12.510 --> 06:14.610
which then means that the explanation

06:14.610 --> 06:17.460
and the benefits of the joke are actually strings,

06:17.460 --> 06:20.550
which can get piped into the chat prompt template

06:20.550 --> 06:21.840
for the final responder.

06:21.840 --> 06:24.030
So then again, this one's slightly faster,

06:24.030 --> 06:26.910
about 15 seconds, 14.8 seconds,

06:26.910 --> 06:28.890
and we're doing it on the topic of bears.

06:28.890 --> 06:30.270
So it gives us a joke,

06:30.270 --> 06:32.940
and it also talks about some of the analysis

06:32.940 --> 06:34.080
behind that joke.

06:34.080 --> 06:37.650
So this was a brief introduction into conditional branching

06:37.650 --> 06:40.500
and also having a look at how we do merging and branching

06:40.500 --> 06:42.333
across multiple prompt chains.
