-: Alright, so in the last video we covered looking
at chat message history and also memory.
In this video what we're gonna have a look at is
how we can branch out using conditional logic
by using something called the RunnableBranch.
As well as that we will explore a concept called,
sort of, branching and merging.
So let's start with the first one
and we're just gonna do a couple of imports
and then we we'll have a look at this,
which is basically branching with conditional logic.
So I've done a really simple example
so that you can see how this works.
So we've got our RunnableBranch.
You do have to have a generic catch-all case
in case none of the conditionals match, right?
So if we remove the sort of standard one that would run,
you see that basically it has to have one
without kind of like a
you can call this like a default,
you know, condition, right?
If none of the conditions above are checked, right,
so in this case we're checking to see does X equal hello
or is X a type of string,
but if it doesn't equal any of those
when we need a standard kind of default catch all
that will basically stop the RunnableBranch
throwing an error.
Now if I invoke this with hello
(sneezing)
Now if I invoke this with hello
what's gonna happen is
firstly we check to see does X equal hello.
Oh, well it does
and therefore we just return hello, right?
And you can see that here.
Now we also say, okay,
if we invoke with none
then we're not gonna match any against these cases.
And you'll see this then triggers the default case.
Now you could use the RunnableBranch just for doing,
you know, different types of outputs,
but you could also use the RunnableBranch if you wanted
to run different types of chains based
on the outputs from previous chains.
So just have a think
about how you would like to implement that as well.
The next one we're gonna have a look at is
something called branching and merging,
which is where you want to take a input,
do something separately
in separate branches of workflow,
and then combine those branches into a final result.
Let's have a look at an example of this
where we have a planner,
which is saying generate an argument about input
that then gets associated and piped
with the ChatOpenAI,
piped into a string output parser
and then piped into a Python dictionary,
which takes the output of the string output parser,
which is from the runnable pass through.
And then associates that
with the base response key in the dictionary.
We also have two prompt chains,
which are separate chains for generating a arguments against
and an arguments for.
We then have a final responder,
which says the AI,
which is using the original response, the human,
which provides the pros, results one and results two,
for the pros and cons,
and then has a system message that says,
generate a final response given the critique,
which pipes it into a ChatOpenAI
and a string output parser.
So you can kind of think of the final responder
as the one that takes these,
and that would be the equivalent of the combined step
taking the outputs of branch one and branch two
and combining that.
So then it works like this.
You have the planner,
which then pipes into a dictionary
and creates results one and results two,
using the arguments for and arguments against chains.
We then also add on the original response
because remember the final responder chain
is also going to need to know
about the original response and, therefore,
it's important that we also grab it
from the planner chain so that we can pass that down
and get that in the final responder.
So then we have a results one,
which gets associated with the pros,
and a results two,
which gets associated with the cons.
We then have the original response,
which is the AI's original response,
and then that will then allow us to do something like this
where we do chain.invoke, input, and then scrum,
and then it has a little bit on scrum
for the advantages and disadvantages.
Now if you have a look here,
it's taken around 35 seconds to generate that content.
And the reason for this is we've got
a little bit of synchronous API calls happening here
where we have the input
and we then synchronously wait
for both branch one and branch two to finish
before then taking the outputs of branch one and branch two
and doing another LLM API request.
So branching and merging,
a little bit like sequential chains,
can allow you to separate out logic and,
but it also does come at the cost of increased time.
And so, you know, it might not necessarily
be the best responses for users
that need to get a response very quickly,
but it can be very useful
for breaking the chain down into more complicated bits
to solve more complicated problems.
Let's also just reinforce that
with having a look at a different example.
So we've got this joke
and then we've got a prompt template telling me a joke.
We then get the joke and assign that,
and we also get the topic
from the runnable pass through as well.
Now we then get the explain jokes.
We ask it to explain the joke.
We also say list all the benefits of the joke.
And then we've got the final responder,
which is, you know, you're responsible
for doing a small analysis.
The topic will be topic,
and getting the joke, the benefits,
the explanation of the joke,
generate a small analysis of the joke.
And then, so what we do is we get the topic,
we pass that through as a runnable pass through,
which gets added into the joke chain.
From there, then notice how we're also reattaching the joke
and the topic keys
because we need those to get passed to the final responder.
And this is the common thing
when you're doing these sort of sequential chains,
or branching or merging chains,
where you have to remember to get the keys
from previous chains so that they can get passed down
to the final chains as well.
So that's a big lesson that, you know,
it can take you a bit of time to figure that out.
And also notice how the explanation key
and the benefits keys,
these two keys are coming from the outputs of prompt chains.
And the reason why this works is
'cause we are using this string output parser,
which then means that the explanation
and the benefits of the joke are actually strings,
which can get piped into the chat prompt template
for the final responder.
So then again, this one's slightly faster,
about 15 seconds, 14.8 seconds,
and we're doing it on the topic of bears.
So it gives us a joke,
and it also talks about some of the analysis
behind that joke.
So this was a brief introduction into conditional branching
and also having a look at how we do merging and branching
across multiple prompt chains.