back to index

LLM Chains using GPT 3.5 and other LLMs — LangChain #3


Chapters

0:0 What are Langchain chains?
1:1 LLMChain
5:14 Utility chains walkthrough
10:25 All generic chains in langchain
14:7 Langchain hub
15:10 Other chains in langchain

Whisper Transcript | Transcript Only Page

00:00:00.000 | Today, we're going to take a look at chains
00:00:02.560 | in the Langchain library.
00:00:04.800 | As you might have guessed,
00:00:06.000 | chains are a pretty big component of Langchain.
00:00:10.160 | And naturally, being able to use chains
00:00:12.520 | is a essential skill for anyone
00:00:14.440 | wanting to use the Langchain library.
00:00:16.980 | Now, today is going to be a little bit different.
00:00:19.440 | We have Francisco, who is one of the contributors
00:00:23.020 | to the Langchain library.
00:00:24.720 | And later on, he's going to dive
00:00:26.280 | into some of the details behind chains
00:00:28.880 | and actually show you how to use them.
00:00:30.760 | So that'll be pretty interesting.
00:00:32.800 | But for now, let's just introduce chains.
00:00:35.000 | I'll give you a quick overview before handing it over.
00:00:37.680 | Now, we can think of chains as thin wrappers
00:00:40.520 | around different components in the Langchain library.
00:00:45.400 | And more specifically, primitives within the library.
00:00:49.040 | So primitives cover a few different things.
00:00:51.800 | They can be the prompts that we use,
00:00:54.520 | they can be large-language models,
00:00:57.000 | utilities within the library, and even other chains.
00:01:01.240 | Now, the simplest of these chains,
00:01:03.440 | you might have seen it before,
00:01:04.680 | is called the large-language model chain.
00:01:07.160 | And what it is, is actually very simple.
00:01:09.420 | So up here, we have our prompt template.
00:01:12.440 | Now, to actually build our prompt template,
00:01:13.880 | we'd actually use a prompt template object as well.
00:01:16.200 | Let's just pretend I've done that here.
00:01:17.680 | Now, what a user is going to input
00:01:19.560 | into this large-language model chain
00:01:21.640 | is going to be a query, okay?
00:01:24.280 | Now, the query we actually have here, right?
00:01:26.800 | So the first part of this chain
00:01:28.320 | is taking the input from the user
00:01:30.520 | and putting it into first primitive of the chain,
00:01:33.240 | which is this prompt template here.
00:01:36.080 | And then the next step is this prompt template
00:01:39.640 | with the query included inside it
00:01:42.880 | will now be passed across to our large-language model, okay?
00:01:47.400 | And the large-language model will, of course,
00:01:50.640 | output some generation based on our prompt.
00:01:54.680 | That is the LLM chain.
00:01:56.960 | And yeah, I mean, you've seen it, it's super simple.
00:01:59.840 | And naturally, it's very easy to create.
00:02:03.000 | We can actually see the code here.
00:02:04.440 | So we'll just run this.
00:02:06.520 | We would put in our OpenAI API key here.
00:02:10.480 | We'd initialize our large-language model,
00:02:12.400 | create our prompt template, as I just described,
00:02:15.280 | and then we just use this.
00:02:17.200 | So if we run that, we should be able to get an output.
00:02:20.240 | So we're going to run this here, llmchain.run,
00:02:24.640 | and we just ask a question.
00:02:26.480 | And it's going to return as a bullet point list
00:02:28.960 | because in this prompt template that we use here,
00:02:31.400 | we asked for a bullet point list.
00:02:33.080 | And there we get it.
00:02:36.320 | So despite only running this single function,
00:02:39.720 | we've actually created a chain of,
00:02:41.480 | in this case, two functions.
00:02:43.320 | Now, as I said, this is one of the simplest chains
00:02:45.840 | in line chain.
00:02:46.680 | They get far more complicated than this.
00:02:48.680 | And we can actually see that in the docs here.
00:02:50.800 | So if we go over to the left, we have chains,
00:02:53.680 | how-to guides, we can see that there's these
00:02:55.440 | three different types of chains.
00:02:57.520 | Generic chains, combined document chains,
00:03:00.760 | and utility chains.
00:03:02.640 | And we can describe each of these chains,
00:03:05.560 | starting with the generic chains,
00:03:07.240 | which is, as you might have guessed from the name,
00:03:09.840 | fairly generic.
00:03:10.960 | They are more or less used to build other chains
00:03:13.440 | in the library.
00:03:14.360 | You wouldn't necessarily use them by themselves
00:03:17.440 | because they're not built for any particular purpose.
00:03:20.040 | But nonetheless, you might find yourself using them
00:03:22.280 | as I just demonstrated with the Lodged Image Model chain.
00:03:25.600 | We use it just to generate some text.
00:03:28.920 | But typically, I'm using these as parts of other chains.
00:03:32.720 | We have the combined document chains,
00:03:34.640 | which is super useful when we are doing anything
00:03:38.480 | where we're working with other documents,
00:03:40.840 | like we might do in question answering,
00:03:42.840 | summarization, or any retrieval augmented use case.
00:03:47.640 | And then, the final one is utility chains.
00:03:50.520 | And these are more specific chains
00:03:53.720 | that consist of usually a Lodged Image Model chain
00:03:57.720 | alongside another specific line chain utility.
00:04:02.080 | Now, the combined document chains,
00:04:04.360 | they are very use case specific,
00:04:07.360 | and I feel need a bit more of a deep dive
00:04:10.600 | to understand how to use them properly.
00:04:12.880 | So we're actually just going to focus
00:04:14.200 | on two of the types of chains at the moment,
00:04:16.720 | which are the generic chains and the utility chains.
00:04:20.520 | Now, what I'm going to do is leave you there,
00:04:22.320 | and I'm going to let Francisco take you through these chains
00:04:26.680 | and take a look at one of the utility chains
00:04:30.320 | and how we'd use it,
00:04:31.880 | and also have a look at what the generic chains are
00:04:35.640 | and give a couple of cool examples on actually using them,
00:04:40.440 | which I think rarely gets across what they are useful for.
00:04:45.000 | So without any further ado, let me hand over to Francisco.
00:04:49.440 | - Hi there, my name is Francisco.
00:04:51.200 | As James said, I am a contributor to Lankchain.
00:04:53.680 | I think Lankchain is definitely
00:04:55.400 | one of the most powerful libraries out there.
00:04:57.960 | And to really leverage Lankchain fully,
00:05:01.120 | we need to understand
00:05:02.160 | what its fundamental building blocks are
00:05:04.120 | so we know how we can use them for our specific use case.
00:05:07.880 | So let's get right into the code for chains.
00:05:11.200 | We will be using the OpenAI LLM as the LLM in this notebook.
00:05:16.040 | So you will need to set your OpenAI API key right here.
00:05:19.920 | I have already set it up so I can initialize my LLM there.
00:05:23.800 | And we will be using this count tokens function,
00:05:27.080 | which will really let us know how many tokens we are using
00:05:30.960 | when we run our LLM.
00:05:33.040 | And this is important because OpenAI charges us
00:05:35.720 | by the number of tokens we use.
00:05:37.040 | So we really want to keep track of these tokens
00:05:40.360 | when we are making many experiments with Lankchain.
00:05:43.120 | So we will be diving into one example for the utility chains
00:05:47.840 | to really understand what a utility chain is under the hood.
00:05:51.160 | And the example chain we'll be using is the LLM math chain.
00:05:55.360 | The LLM math chain, as you can see here,
00:05:57.800 | will help us use LLMs to do complex math.
00:06:01.160 | So let's say that we want to know what 13
00:06:04.160 | is raised to the 0.3432 power.
00:06:07.600 | And if we run this, we will be running the LLM math chain
00:06:10.760 | with that query.
00:06:12.000 | And we will get an answer for that.
00:06:14.360 | And it will be the correct answer.
00:06:16.440 | This is not so easy to do with a vanilla LLM
00:06:20.560 | because the LLM doesn't know how to do complex math.
00:06:24.080 | So we need to help it to be able to return accurate results.
00:06:28.120 | So let's see what's going on here.
00:06:29.960 | The chain received a question
00:06:31.520 | and we are changing that question.
00:06:33.840 | We are computing that question through the LLM
00:06:36.480 | and we are getting some Python code in return.
00:06:39.560 | So now we need to ask ourselves,
00:06:40.960 | what is going on under the hood here?
00:06:42.760 | And we can see that Python code is being generated
00:06:45.800 | in an intermediate step.
00:06:47.120 | So why is this Python code being generated
00:06:49.960 | and who is generating this Python code?
00:06:52.480 | Here is where prompts come in.
00:06:54.080 | And prompts are really important for utility chains
00:06:56.640 | because utility chains serve a very specific purpose.
00:06:59.400 | And the prompt we use for the utility chain
00:07:02.560 | will tell the chain how exactly it needs to perform
00:07:06.680 | the utility purpose that we have for that chain.
00:07:09.880 | So we will be sending this prompt to the LLM
00:07:12.960 | and the LLM will know how to behave
00:07:15.640 | because this prompt will give it very precise instructions.
00:07:18.880 | And this is a concept that is repeated
00:07:21.120 | across all utility chains.
00:07:22.640 | So let's take a look.
00:07:23.840 | As we can see here, we can always print a chain's prompt
00:07:27.480 | by accessing the prompt attribute
00:07:29.240 | and then the template attribute from the prompt.
00:07:31.800 | So here we can see that we're telling the LLM
00:07:35.960 | that it can do basic math,
00:07:38.120 | but it should not try to do complex math.
00:07:40.080 | And if anyone asks it a complex question,
00:07:43.400 | it should just output Python code.
00:07:45.160 | So that's why we're getting Python code
00:07:47.480 | as an intermediate step.
00:07:48.520 | The LLM is returning Python code
00:07:50.800 | because it knows that it cannot do really complex math.
00:07:54.000 | And what if we try to send the LLM
00:07:57.600 | just a random complex query
00:08:00.040 | and see if it can perform,
00:08:02.600 | give us an accurate result on its own.
00:08:04.520 | If we do, as we have here,
00:08:06.160 | we will send it the same question,
00:08:08.320 | but without any context.
00:08:09.840 | We will not ask it to generate Python code,
00:08:12.360 | just give us an answer.
00:08:13.880 | So if we run this,
00:08:15.160 | we will see that the answer is 2.907,
00:08:18.600 | which is different and wrong from our right answer,
00:08:22.040 | which was 2.41.
00:08:24.320 | So if we don't have this prompt
00:08:26.880 | and we don't do this intermediate Python code,
00:08:29.680 | we wouldn't be getting a right answer.
00:08:31.720 | So here the chain is really enabling us
00:08:34.160 | to use LLMs to do math.
00:08:36.440 | Whereas if we didn't have this chain,
00:08:38.960 | the LLM would be doing the math wrongly.
00:08:41.600 | So here is an insight for utility chains.
00:08:44.440 | By using prompts intelligently,
00:08:46.320 | we can force the LLM to avoid common pitfalls.
00:08:49.200 | And this can be done by explicitly programming it
00:08:52.320 | to behave in a certain way.
00:08:54.080 | And this is really important
00:08:56.000 | because this is what is done again and again
00:08:58.440 | in different utility chains.
00:09:00.480 | So let's see the LLM math call method
00:09:03.160 | to see how this Python code is being used then.
00:09:05.800 | Once the Python code is generated,
00:09:08.040 | we can see here that if the LLM returned Python code,
00:09:13.040 | T here is the output of the LLM,
00:09:15.880 | we will be able to run that code
00:09:17.280 | and then give that code as an answer right here.
00:09:21.040 | And if not, we will just output that answer directly.
00:09:24.400 | So here it's interesting that we can handle both cases.
00:09:29.200 | We can receive Python code and run it,
00:09:32.080 | or we can just return the straight answer.
00:09:35.280 | And this is it for the LLM math chain.
00:09:38.400 | As we can see, there are several other chains
00:09:41.160 | that do very different things.
00:09:43.760 | There's the SQL chain, which computes SQL commands
00:09:47.560 | and can build SQL commands for natural language queries.
00:09:51.320 | There's also the API chain,
00:09:53.600 | which helps us make correct API calls to a specific API
00:09:58.240 | by giving the LLM the documentation for that API.
00:10:01.640 | And also there's the bash commands chain,
00:10:04.280 | which helps us create bash commands on the fly.
00:10:07.360 | But there's many more,
00:10:08.720 | and we really encourage you to check them out on your own
00:10:11.840 | and play with the example notebooks,
00:10:13.360 | which are in the documentation,
00:10:15.180 | which you can check out in this link.
00:10:17.400 | And with that documentation and those notebooks,
00:10:20.900 | you will be able to understand which utility chains
00:10:23.120 | you might need for your specific application.
00:10:25.360 | Awesome.
00:10:26.280 | So now we are ready to go deep into generic chains,
00:10:30.060 | and generic chains are a bit different than utility chains
00:10:33.160 | in that they're not thought of as chains
00:10:35.520 | that you will be using on their own,
00:10:37.000 | but more as building blocks for building other chains.
00:10:40.320 | And there are three types of generic chains,
00:10:42.240 | which we will cover,
00:10:43.200 | and we will cover them all in the same example.
00:10:46.480 | So we can really understand the power
00:10:48.960 | of combining these chains to build custom solutions
00:10:52.380 | for applications.
00:10:53.700 | So let's start by the first of these chains,
00:10:56.520 | which is the transform chain.
00:10:57.940 | And let's say we need to clean an input text
00:11:01.140 | from extra spaces,
00:11:02.620 | because extra spaces are being charged for us as tokens,
00:11:06.780 | and we don't want to spend extra with dirty text.
00:11:10.720 | And also it's just not really neat.
00:11:13.260 | So we have this function as we can see here,
00:11:16.140 | and we will initialize our chain
00:11:17.980 | by saying this is the input,
00:11:20.260 | and this is the output,
00:11:21.240 | and this is a transform function.
00:11:22.500 | So basically a transform chain just gets some inputs,
00:11:25.780 | applies a function to those inputs,
00:11:27.460 | and returns the outputs.
00:11:29.260 | It's very important here to notice
00:11:30.820 | that the transform chain does not have an LLM.
00:11:32.980 | So not all chains are LLM dependent.
00:11:36.300 | So we here, we will be building our clean extra spaces chain,
00:11:40.100 | and then we will run it.
00:11:41.300 | We don't need the count tokens here function,
00:11:43.420 | because we don't have any LLMs.
00:11:45.940 | So as we can see here the random text
00:11:48.740 | with a lot of irregular spacing will be cleaned,
00:11:52.380 | and we will have our clean text as an output.
00:11:55.360 | So let's say now that we want to use this chain
00:11:58.660 | to clean some text and then send it to an LLM.
00:12:01.260 | And we want to send it to an LLM
00:12:04.020 | that will change the style
00:12:06.660 | of what we have given as an input to another style.
00:12:10.560 | So say to write it in the style of a poet or a policeman.
00:12:14.620 | So to do that, we will need to build our prompt template
00:12:18.300 | for our LLM chain.
00:12:20.200 | And we will say paraphrase this text
00:12:22.260 | in the style of a specific style here.
00:12:24.700 | And this is our prompt.
00:12:27.060 | And here is our style paraphrase chain with this LLM chain,
00:12:31.100 | which is the second generic chain that we will be seeing.
00:12:34.100 | And the LLM chain is just a chain
00:12:37.260 | that computes an LLM call with a prompt template.
00:12:41.700 | James already covered this in detail.
00:12:44.100 | So as we can see here,
00:12:46.100 | we will have our style paraphrase chain.
00:12:49.220 | And now we want to combine these two.
00:12:51.540 | And here comes our third generic chain.
00:12:53.940 | So how can we combine two chains?
00:12:56.780 | Well, we can do that with a sequential chain.
00:12:58.720 | So the sequential chain just receives a few chains
00:13:00.940 | as an input.
00:13:02.260 | And we want to tell it which are the input variables
00:13:05.020 | we will give in the sequential chain,
00:13:06.780 | and now which output variables we are expecting.
00:13:09.420 | So we will initialize that.
00:13:11.100 | And now we can give our final chain an input,
00:13:15.060 | which will be cleaned from extra spacing,
00:13:17.460 | and then will be written in the style
00:13:19.700 | of some desired style we want.
00:13:22.940 | So let's say we have this definition of chains
00:13:26.420 | from the Lang chain documentation,
00:13:28.100 | which has, as you can see,
00:13:29.420 | lots of extra spacing that we don't really want.
00:13:32.460 | But we also want it to be written in the style of,
00:13:37.020 | let's say, a '90s rapper,
00:13:38.900 | just because we can try that.
00:13:40.660 | And if we just run it here,
00:13:43.620 | we will see that here we get our answer.
00:13:47.220 | Let's change, let us link up multiple pieces
00:13:50.460 | to make one dope app.
00:13:52.760 | Like we can take user input,
00:13:54.260 | style it up with a prompt template,
00:13:57.060 | then pass it to an LLM.
00:13:58.660 | We can get even more creative
00:13:59.940 | by combining multiple chains
00:14:01.180 | or mixing chains with our components.
00:14:02.860 | So that's quite creative and accurate
00:14:05.700 | in the style of a '90s rapper.
00:14:07.700 | So finally, just a small note on LangChainHub.
00:14:10.580 | LangChainHub is where chains, prompts,
00:14:13.220 | and agents are serialized,
00:14:14.620 | and we can load them from LangChainHub
00:14:17.180 | to use them for our own purposes.
00:14:19.420 | And it's going to be the place
00:14:20.980 | where these components will ultimately live.
00:14:24.580 | So it's really important
00:14:25.420 | that we learn how to use LangChainHub
00:14:27.380 | to load these components and then use them.
00:14:30.480 | So it's really, really easy
00:14:31.760 | to load chains from LangChainHub.
00:14:33.620 | You can just import the load chain function,
00:14:37.580 | set the path for the chain you want to import.
00:14:40.620 | This path, you can find it in the LangChainHub repository.
00:14:44.700 | You can find the appropriate path
00:14:46.340 | for the chain you want to load.
00:14:48.220 | And here you can overwrite any of the default parameters
00:14:52.500 | that you want to change.
00:14:53.460 | So for example, if you want to have the chain
00:14:56.940 | not be verbose when it's being run,
00:14:59.260 | you can just set it to false,
00:15:00.900 | and then you can see here that it's not verbose anymore.
00:15:04.480 | So it's really easy to change any parameters
00:15:07.200 | that you might want.
00:15:08.260 | So that's all for chains.
00:15:10.560 | - Okay, so that's it for the code portion.
00:15:13.220 | Again, massive thank you to Francisco
00:15:15.380 | for taking us through that
00:15:16.540 | and sharing some of his insights
00:15:18.540 | as one of the contributors of the library.
00:15:21.180 | If there's one thing that I'd like to point out,
00:15:22.980 | it's that just now we only saw a couple of chains.
00:15:26.340 | This really just acts as an introduction
00:15:29.620 | to chains in LangChain.
00:15:31.380 | But there are a huge number of these
00:15:34.540 | that we haven't even spoken about
00:15:37.060 | or even mentioned yet.
00:15:39.040 | And okay, we've covered generic chains relatively well.
00:15:42.840 | Combined documents chains, we haven't covered whatsoever.
00:15:45.820 | And utility chains, we've covered a little bit.
00:15:48.160 | But even within utility chains,
00:15:50.200 | we've had a look at LLM math,
00:15:52.960 | but we haven't had a look at any of the other ones.
00:15:54.960 | So there are a ton of these chains
00:15:56.960 | that we can use in the library.
00:15:58.720 | And we will make sure to go through
00:16:01.320 | at least a few of these in the future.
00:16:04.160 | But the point being that there is a lot more potential
00:16:07.980 | for building really cool tools here
00:16:10.500 | than what we've just shown you.
00:16:12.060 | So for now, we're going to leave it there.
00:16:14.860 | I hope this is all useful and interesting.
00:16:17.140 | So thank you very much for watching
00:16:19.300 | and I will see you again in the next one.
00:16:21.940 | (soft music)
00:16:24.360 | (soft music)
00:16:26.780 | (soft music)
00:16:29.200 | (soft music)
00:16:31.700 | (soft music)
00:16:34.120 | [BLANK_AUDIO]