WEBVTT

1
00:00:00.870 --> 00:00:01.703
<v Eden>Hey, there.</v>

2
00:00:01.703 --> 00:00:03.930
Eden here, and quick update before we dive in.

3
00:00:03.930 --> 00:00:06.360
So you might notice in this video that I'm going

4
00:00:06.360 --> 00:00:09.600
to be using PyCharm, and you'll see a peep file

5
00:00:09.600 --> 00:00:12.030
and peep file.log in the project.

6
00:00:12.030 --> 00:00:15.510
And that's because in this particular video was recorded

7
00:00:15.510 --> 00:00:17.880
in earlier versions of the course.

8
00:00:17.880 --> 00:00:19.080
Now, I've gone through

9
00:00:19.080 --> 00:00:21.750
and rerecorded almost every single video

10
00:00:21.750 --> 00:00:24.540
to keep everything up to date with the latest versions

11
00:00:24.540 --> 00:00:26.910
of LangChains and the other libraries

12
00:00:26.910 --> 00:00:28.230
we're going to be using.

13
00:00:28.230 --> 00:00:30.390
However, in this specific lesson,

14
00:00:30.390 --> 00:00:32.160
the code is exactly the same.

15
00:00:32.160 --> 00:00:33.540
It hasn't changed at all.

16
00:00:33.540 --> 00:00:37.080
So rather than rerecord something that's identical,

17
00:00:37.080 --> 00:00:39.180
I kept this one as is.

18
00:00:39.180 --> 00:00:41.850
Now, that being said, if this really bothers you,

19
00:00:41.850 --> 00:00:44.880
just let me know and drop a comment or send me a message.

20
00:00:44.880 --> 00:00:47.460
This video is on my list to rerecord,

21
00:00:47.460 --> 00:00:49.590
but I've got a lot of other updates

22
00:00:49.590 --> 00:00:53.010
and new content I'm working on, so I'm prioritizing things

23
00:00:53.010 --> 00:00:54.810
that actually affect your learning.

24
00:00:54.810 --> 00:00:57.090
All right, so now that is out of the way.

25
00:00:57.090 --> 00:00:58.863
Let's get into it.

26
00:00:59.760 --> 00:01:02.760
Let's review the file that we're going to ingest.

27
00:01:02.760 --> 00:01:04.890
So this is the medium block.

28
00:01:04.890 --> 00:01:07.380
Now, let's initialize the text loader.

29
00:01:07.380 --> 00:01:09.960
So I'm going to create a text loader object

30
00:01:09.960 --> 00:01:12.390
and I'm going to give it the path of the file we want

31
00:01:12.390 --> 00:01:16.110
to load, and you need to change this path to match the path

32
00:01:16.110 --> 00:01:18.930
where it's saved in your file system.

33
00:01:18.930 --> 00:01:20.160
And then all we need

34
00:01:20.160 --> 00:01:24.900
to do is simply use the method loader.load.

35
00:01:24.900 --> 00:01:28.740
Now, this would load the file into a LangChain document.

36
00:01:28.740 --> 00:01:31.590
Now, the beautiful thing about this abstraction

37
00:01:31.590 --> 00:01:34.410
is that if we were to use WhatsApp

38
00:01:34.410 --> 00:01:38.430
for loading WhatsApp messages or Notion for Notion Notebooks

39
00:01:38.430 --> 00:01:42.540
or Google Drive files, then the interface would be the same.

40
00:01:42.540 --> 00:01:45.600
Would need to create the document loader specifically

41
00:01:45.600 --> 00:01:47.010
for that third party

42
00:01:47.010 --> 00:01:51.030
and we would need to use the load method.

43
00:01:51.030 --> 00:01:54.750
I just want to show you how rich this ecosystem is.

44
00:01:54.750 --> 00:01:57.300
If we'll head up to the LangChain documentation

45
00:01:57.300 --> 00:02:00.330
into the document loader section, we can see

46
00:02:00.330 --> 00:02:02.700
that on the left side we have some document loaders

47
00:02:02.700 --> 00:02:04.200
that LangChain implemented.

48
00:02:04.200 --> 00:02:07.830
So those are for generic file types like CSV,

49
00:02:07.830 --> 00:02:10.410
HTML, JSON, PDF.

50
00:02:10.410 --> 00:02:12.240
But if we go to integration,

51
00:02:12.240 --> 00:02:14.580
and this is a part of LangChain community

52
00:02:14.580 --> 00:02:17.430
because everyone from the community can upload

53
00:02:17.430 --> 00:02:22.320
a third party loader, then we'll see that we have tons

54
00:02:22.320 --> 00:02:23.763
of document loaders.

55
00:02:26.340 --> 00:02:30.780
Now, let's take an example, and let's say that we want

56
00:02:30.780 --> 00:02:33.873
to load some YouTube transcripts.

57
00:02:36.270 --> 00:02:39.210
So the interface is going to be the same

58
00:02:39.210 --> 00:02:44.210
to simply use the loader.load.

59
00:02:47.190 --> 00:02:49.950
If we wanted to load Slack messages,

60
00:02:49.950 --> 00:02:51.723
we can use the Slack loader,

61
00:02:53.340 --> 00:02:55.950
and use the loader.load.

62
00:02:55.950 --> 00:02:59.280
So this is a very nice abstraction in my opinion,

63
00:02:59.280 --> 00:03:01.710
and you can really see the power of the community

64
00:03:01.710 --> 00:03:04.380
with the amount of loaders that we have.

65
00:03:04.380 --> 00:03:05.490
Cool.

66
00:03:05.490 --> 00:03:07.020
Co we've loaded the document,

67
00:03:07.020 --> 00:03:09.660
so now it's time to split it into chunks.

68
00:03:09.660 --> 00:03:12.540
But before that, let's just run everything in debug

69
00:03:12.540 --> 00:03:15.360
and let's examine all the objects.

70
00:03:15.360 --> 00:03:18.660
But before we begin, I just want to note that some of you,

71
00:03:18.660 --> 00:03:20.100
depending where you live

72
00:03:20.100 --> 00:03:24.480
and what kind of encoder your operating system uses,

73
00:03:24.480 --> 00:03:26.160
you might get an error.

74
00:03:26.160 --> 00:03:28.590
So this error is going to be looking like this.

75
00:03:28.590 --> 00:03:30.540
So it's going to have the string

76
00:03:30.540 --> 00:03:35.160
of unicode error in codec can't decode bytes.

77
00:03:35.160 --> 00:03:37.830
Here is another example of this error.

78
00:03:37.830 --> 00:03:41.340
And luckily for us, fixing it is very, very easy.

79
00:03:41.340 --> 00:03:43.830
You need to add the flag of encoding

80
00:03:43.830 --> 00:03:47.730
equals to the string of UTF-8.

81
00:03:47.730 --> 00:03:51.060
And if that doesn't work for you, you can use the flag

82
00:03:51.060 --> 00:03:54.780
of auto detect encoding equals true.

83
00:03:54.780 --> 00:03:58.290
So one of these flags should definitely fix your issue.

84
00:03:58.290 --> 00:03:59.550
However, for most people,

85
00:03:59.550 --> 00:04:02.130
everything should be fine even without those flags

86
00:04:02.130 --> 00:04:04.440
like for me in the video.

87
00:04:04.440 --> 00:04:08.010
So we can examine the text loader object

88
00:04:08.010 --> 00:04:10.680
and we can have a look in all the metadata

89
00:04:10.680 --> 00:04:13.980
we initialize this object with, like the file path,

90
00:04:13.980 --> 00:04:17.280
and we can use different encoding systems if you want to.

91
00:04:17.280 --> 00:04:20.520
After we invoke the loader.load method,

92
00:04:20.520 --> 00:04:24.030
then we get back a list of LangChain documents.

93
00:04:24.030 --> 00:04:26.160
So let's examine the document variable,

94
00:04:26.160 --> 00:04:29.910
and we can see it contains a list of only one document.

95
00:04:29.910 --> 00:04:32.250
And all the elements

96
00:04:32.250 --> 00:04:35.280
of that list are documents of LangChain.

97
00:04:35.280 --> 00:04:38.250
Now, every document has a couple of key attributes.

98
00:04:38.250 --> 00:04:40.470
So one of them is page contact.

99
00:04:40.470 --> 00:04:43.536
So it's all the content that we loaded.

100
00:04:43.536 --> 00:04:46.200
We also have the metadata field,

101
00:04:46.200 --> 00:04:50.190
and this field is going to hold by default the source

102
00:04:50.190 --> 00:04:51.420
of this document.

103
00:04:51.420 --> 00:04:54.360
So we can see now the sources the file path.

104
00:04:54.360 --> 00:04:58.500
And this is used when we use reg to say

105
00:04:58.500 --> 00:05:00.450
where we got that information for,

106
00:05:00.450 --> 00:05:04.230
and where did we ground the LMS answer with.

107
00:05:04.230 --> 00:05:06.270
So it is super important.

108
00:05:06.270 --> 00:05:10.380
And we can add to this metadata field any key

109
00:05:10.380 --> 00:05:11.850
and value that we want.

110
00:05:11.850 --> 00:05:14.610
And this could be used for filtering later

111
00:05:14.610 --> 00:05:17.130
or for segregation of data.

112
00:05:17.130 --> 00:05:20.790
And this is very useful when we deploy things to production

113
00:05:20.790 --> 00:05:24.333
and we implement more advanced reg systems.

114
00:05:25.350 --> 00:05:26.183
All righty.

115
00:05:26.183 --> 00:05:28.080
Let's go and split some text,

116
00:05:28.080 --> 00:05:32.190
and we're going to create a character text splitter object.

117
00:05:32.190 --> 00:05:35.010
And the character text splitter object is something

118
00:05:35.010 --> 00:05:36.660
which can be very complex.

119
00:05:36.660 --> 00:05:39.390
It can use regular expressions,

120
00:05:39.390 --> 00:05:44.070
it can use a different length function to count the number

121
00:05:44.070 --> 00:05:46.470
of tokens that we're splitting it for,

122
00:05:46.470 --> 00:05:48.540
and it has a lot of customizations.

123
00:05:48.540 --> 00:05:50.850
But in this example, we just want

124
00:05:50.850 --> 00:05:53.370
to show you the principle of how it works.

125
00:05:53.370 --> 00:05:55.980
So we're just going to populate two arguments.

126
00:05:55.980 --> 00:05:58.680
Chunk size, we're going to set for 1,000.

127
00:05:58.680 --> 00:06:02.700
So this will limit our chunk size

128
00:06:02.700 --> 00:06:04.740
to 1,000 characters.

129
00:06:04.740 --> 00:06:08.280
And why did I choose 1,000 for the chunk size?

130
00:06:08.280 --> 00:06:10.140
So this is a heuristic.

131
00:06:10.140 --> 00:06:12.840
And a rule thumb when chunking

132
00:06:12.840 --> 00:06:15.630
is to keep the chunk size small enough

133
00:06:15.630 --> 00:06:18.060
so it would fit in the context window.

134
00:06:18.060 --> 00:06:20.310
And the context window usually is going

135
00:06:20.310 --> 00:06:22.620
to be holding a couple of chunks

136
00:06:22.620 --> 00:06:24.240
because we're going to retrieve a couple

137
00:06:24.240 --> 00:06:28.680
of chunks from the documents, and it should be big enough.

138
00:06:28.680 --> 00:06:33.420
So if we would read it as human beings, we would know

139
00:06:33.420 --> 00:06:36.870
what these chunk means, and it has a value

140
00:06:36.870 --> 00:06:38.520
and semantic meaning.

141
00:06:38.520 --> 00:06:40.710
So if the chunk size would be too small,

142
00:06:40.710 --> 00:06:43.470
we simply won't understand anything from it

143
00:06:43.470 --> 00:06:47.280
and it won't help the LLM give us the answer that we want.

144
00:06:47.280 --> 00:06:49.470
So this is a rule of thumb.

145
00:06:49.470 --> 00:06:53.760
And here in this example I've used 1,000.

146
00:06:53.760 --> 00:06:56.160
And splitting text to chunks

147
00:06:56.160 --> 00:06:59.040
and document to chunks is still super important,

148
00:06:59.040 --> 00:07:01.650
even when we have models like Gemini,

149
00:07:01.650 --> 00:07:04.740
which can ingest 1 million tokens,

150
00:07:04.740 --> 00:07:09.330
because in LLMs there is a very nice another rule of thumb,

151
00:07:09.330 --> 00:07:12.060
which means garbage in, garbage out.

152
00:07:12.060 --> 00:07:15.060
So if we send the LLMA lot of information,

153
00:07:15.060 --> 00:07:17.820
which is not relevant, so first thing it's going

154
00:07:17.820 --> 00:07:20.970
to cost us money because the more tokens we send,

155
00:07:20.970 --> 00:07:24.510
the more tokens the LLM digest, then it costs us more money.

156
00:07:24.510 --> 00:07:28.410
And second, it's proven that we'll get worse results.

157
00:07:28.410 --> 00:07:31.260
So if we just use the relevant context

158
00:07:31.260 --> 00:07:33.840
and the relevant chunks,

159
00:07:33.840 --> 00:07:37.020
then we will get better results from the LLM.

160
00:07:37.020 --> 00:07:41.430
Now, let's talk about trunk overlap, and I've put here zero.

161
00:07:41.430 --> 00:07:45.060
Now, this means that all of my chunks are not going

162
00:07:45.060 --> 00:07:46.920
to have overlapping data.

163
00:07:46.920 --> 00:07:49.380
So when is overlapping data useful?

164
00:07:49.380 --> 00:07:53.160
So it's when we don't want to use context between chunks.

165
00:07:53.160 --> 00:07:55.380
So sometimes that will help as well.

166
00:07:55.380 --> 00:07:57.630
But again, this is a simple example.

167
00:07:57.630 --> 00:08:00.210
So we just want to keep things simple

168
00:08:00.210 --> 00:08:02.370
and to give those values.

169
00:08:02.370 --> 00:08:05.820
Let's create the chunks from our medium blog.

170
00:08:05.820 --> 00:08:07.710
So we want to invoke the function,

171
00:08:07.710 --> 00:08:09.630
the method split documents,

172
00:08:09.630 --> 00:08:12.030
which receives a list of documents.

173
00:08:12.030 --> 00:08:15.420
So the variable document is actually holding a list

174
00:08:15.420 --> 00:08:17.050
of LangChain documents

175
00:08:18.150 --> 00:08:20.040
with one document.

176
00:08:20.040 --> 00:08:23.973
Let's debug and examine all the LangChain objects.

177
00:08:26.820 --> 00:08:30.660
So we'll first start by examining the text splitter,

178
00:08:30.660 --> 00:08:34.290
and we can see all the fields that it has,

179
00:08:34.290 --> 00:08:37.290
and it has the chunk size, chunk overlap,

180
00:08:37.290 --> 00:08:39.330
and it also has a separator.

181
00:08:39.330 --> 00:08:41.550
So on what it's going to split the text.

182
00:08:41.550 --> 00:08:43.893
So here is Backslash and Backslash.

183
00:08:45.000 --> 00:08:47.940
And now let's go and examine texts.

184
00:08:47.940 --> 00:08:49.830
So those are the chunks.

185
00:08:49.830 --> 00:08:52.620
Now notice, chunks are still documents.

186
00:08:52.620 --> 00:08:54.510
So those are documents,

187
00:08:54.510 --> 00:08:57.690
but if we'll take a look, for example, about the value

188
00:08:57.690 --> 00:09:00.570
of the of those documents, we can see it's limited here.

189
00:09:00.570 --> 00:09:04.410
So it's much smaller, and here is for 1,000 characters.

190
00:09:04.410 --> 00:09:07.950
And we can also have the metadata of the document.

191
00:09:07.950 --> 00:09:10.800
So what is the source that it came from?

192
00:09:10.800 --> 00:09:12.240
Now, remember the rule of thumb

193
00:09:12.240 --> 00:09:15.030
is that you should read the content of the chunks

194
00:09:15.030 --> 00:09:18.303
and it should make sense and has a semantic value.

195
00:09:25.860 --> 00:09:29.220
And we got a system message from LangChain indicating

196
00:09:29.220 --> 00:09:30.630
that some of those chunks

197
00:09:30.630 --> 00:09:33.930
are having more than 1,000 characters,

198
00:09:33.930 --> 00:09:35.670
more than the token limit.

199
00:09:35.670 --> 00:09:39.240
So this is because we were splitting on Backslash + N

200
00:09:39.240 --> 00:09:41.700
and it's not exact science,

201
00:09:41.700 --> 00:09:45.180
so we might get bigger chunks.

202
00:09:45.180 --> 00:09:47.610
But again, those numbers are pretty small,

203
00:09:47.610 --> 00:09:50.950
and in today's context windows of LLMs

204
00:09:50.950 --> 00:09:54.120
of 32K, 100K, 1 million tokens,

205
00:09:54.120 --> 00:09:57.300
then this is not as much as important

206
00:09:57.300 --> 00:09:59.430
as it used to be in the past.

207
00:09:59.430 --> 00:10:03.300
And at the end we can see we created 20 chunks.

208
00:10:03.300 --> 00:10:04.133
All right.

209
00:10:04.133 --> 00:10:06.363
So now it's time to ingest everything.

210
00:10:07.650 --> 00:10:11.100
We'll initialize an OpenAI embeddings object

211
00:10:11.100 --> 00:10:13.410
and give it the open API key

212
00:10:13.410 --> 00:10:16.320
that we get from our environment variable.

213
00:10:16.320 --> 00:10:19.290
And this will give us the embeddings object.

214
00:10:19.290 --> 00:10:22.950
Now, which embeddings we're going to be using of OpenAI?

215
00:10:22.950 --> 00:10:26.040
So the default one is ada-002,

216
00:10:26.040 --> 00:10:28.500
and we can change it if we want, for example,

217
00:10:28.500 --> 00:10:31.890
multimodal embeddings or if we want other embeddings.

218
00:10:31.890 --> 00:10:34.200
And this object will under the hood

219
00:10:34.200 --> 00:10:36.720
will create an OpenAI client

220
00:10:36.720 --> 00:10:39.600
and it's going to use the OpenAI's API

221
00:10:39.600 --> 00:10:42.753
in order to embed our documents.

222
00:10:43.740 --> 00:10:46.530
Let's add a print that we're going to ingest all

223
00:10:46.530 --> 00:10:48.270
of those chunks,

224
00:10:48.270 --> 00:10:50.610
and now let's ingest them.

225
00:10:50.610 --> 00:10:55.050
And the Pinecone Vector stores has a from documents method.

226
00:10:55.050 --> 00:10:56.670
And not only the Pinecone Vector stores,

227
00:10:56.670 --> 00:10:58.680
but any LangChain vector store.

228
00:10:58.680 --> 00:11:01.590
And it's going to receive text, which is a list

229
00:11:01.590 --> 00:11:03.870
of documents, the embeddings object,

230
00:11:03.870 --> 00:11:05.100
which have all the information

231
00:11:05.100 --> 00:11:07.320
of the embeddings model do we want to use,

232
00:11:07.320 --> 00:11:08.430
and the index name

233
00:11:08.430 --> 00:11:12.000
that we have available in our environment variable.

234
00:11:12.000 --> 00:11:15.330
And what LangChain is going to do, it's going to iterate

235
00:11:15.330 --> 00:11:18.450
through all of the documents, all of the chunks, it's going

236
00:11:18.450 --> 00:11:21.420
to embed each and every one of them,

237
00:11:21.420 --> 00:11:25.290
and then it's going to store it in the vector store.

238
00:11:25.290 --> 00:11:28.320
Now, can we write it ourselves this logic?

239
00:11:28.320 --> 00:11:29.700
It's not that complicated.

240
00:11:29.700 --> 00:11:31.890
So the answer is yes, we can.

241
00:11:31.890 --> 00:11:34.200
But what if later we need to switch

242
00:11:34.200 --> 00:11:35.880
between embeddings models

243
00:11:35.880 --> 00:11:38.673
and maybe even to switch a vector store?

244
00:11:39.540 --> 00:11:43.470
Line Chain offers one single interface that is going

245
00:11:43.470 --> 00:11:45.030
to help us with this task

246
00:11:45.030 --> 00:11:48.603
of ingesting documents into vector stores.

247
00:11:49.440 --> 00:11:54.440
So it give us a lot of flexibility of moving between models

248
00:11:54.540 --> 00:11:57.033
and finding the best one for us to use.

249
00:11:59.250 --> 00:12:02.460
Another reason is that LangChain also implements

250
00:12:02.460 --> 00:12:06.420
using threading, using a Async I/O

251
00:12:06.420 --> 00:12:08.490
in order to run things concurrently

252
00:12:08.490 --> 00:12:12.000
and to handle rate limits in case we get one of them.

253
00:12:12.000 --> 00:12:14.250
So it has a lot of boilerplate support

254
00:12:14.250 --> 00:12:16.203
for a production usage.

255
00:12:17.580 --> 00:12:20.190
And this is the LangChains implementation,

256
00:12:20.190 --> 00:12:22.470
in case you were wondering.

257
00:12:22.470 --> 00:12:24.393
Let's go to add texts.

258
00:12:25.320 --> 00:12:29.640
And we can see over here the logic that we simply iterate

259
00:12:29.640 --> 00:12:31.800
through the text, create the embeddings,

260
00:12:31.800 --> 00:12:35.160
and then we insert them into the vector store.

261
00:12:35.160 --> 00:12:36.930
So we can do this in batches,

262
00:12:36.930 --> 00:12:39.690
we can run this asynchronously.

263
00:12:39.690 --> 00:12:41.850
And this is pretty much it.

264
00:12:41.850 --> 00:12:44.010
It's pretty straightforward.

265
00:12:44.010 --> 00:12:44.843
A lot of code

266
00:12:44.843 --> 00:12:47.571
that we would've needed to write ourselves.

267
00:12:47.571 --> 00:12:51.033
And this is also supported by all vector stores.

268
00:12:52.020 --> 00:12:52.853
Cool.

269
00:12:52.853 --> 00:12:54.060
We're almost finished.

270
00:12:54.060 --> 00:12:56.190
We just need to add another print line

271
00:12:56.190 --> 00:12:58.890
that we finished ingesting the documents.

272
00:12:58.890 --> 00:13:01.380
And now let's run everything.

273
00:13:01.380 --> 00:13:05.340
So I just want to show you that my index is empty,

274
00:13:05.340 --> 00:13:06.840
so we can see medium blogs,

275
00:13:06.840 --> 00:13:10.689
embeddings index is empty at the moment.

276
00:13:10.689 --> 00:13:13.473
And let's run our ingestion file.

277
00:13:17.580 --> 00:13:19.080
Boom, we're done.

278
00:13:19.080 --> 00:13:20.640
Let's go to Pinecone.

279
00:13:20.640 --> 00:13:23.760
Let's refresh the user interface.

280
00:13:23.760 --> 00:13:26.940
And we can see at the right side over here

281
00:13:26.940 --> 00:13:31.020
that we have ingested 20 vectors.

282
00:13:31.020 --> 00:13:33.660
Let's have a look on the data structure

283
00:13:33.660 --> 00:13:35.700
that is stored in Pinecone.

284
00:13:35.700 --> 00:13:38.700
So it has the field of text, which is going

285
00:13:38.700 --> 00:13:41.940
to be our page content of our LangChain document.

286
00:13:41.940 --> 00:13:45.090
And this is the chunk content.

287
00:13:45.090 --> 00:13:47.460
It also has the sources,

288
00:13:47.460 --> 00:13:51.390
and this is going to be our path of our chunk,

289
00:13:51.390 --> 00:13:53.550
and this is to give us proof

290
00:13:53.550 --> 00:13:56.220
of where did our grounding came from?

291
00:13:56.220 --> 00:13:58.950
And of course we have the vector,

292
00:13:58.950 --> 00:14:01.140
which is a list of numbers.

293
00:14:01.140 --> 00:14:04.890
And to summarize this video, we use LangChain

294
00:14:04.890 --> 00:14:07.920
to load our documents with the text loaders.

295
00:14:07.920 --> 00:14:11.670
We split them with the tech splitter into smaller chunks.

296
00:14:11.670 --> 00:14:14.580
We then took the embeddings model

297
00:14:14.580 --> 00:14:17.400
and LangChain help us embed all of those chunks

298
00:14:17.400 --> 00:14:19.890
and store them into the vector store.

299
00:14:19.890 --> 00:14:22.260
So this was the ingestion part

300
00:14:22.260 --> 00:14:24.690
to populate our vector database,

301
00:14:24.690 --> 00:14:27.030
and this is the first part of Reg.

302
00:14:27.030 --> 00:14:30.060
And the second part is the retrieval.

303
00:14:30.060 --> 00:14:34.110
So it's taking the user's question, embedding it,

304
00:14:34.110 --> 00:14:37.470
turning it into a vector, then using the vector store

305
00:14:37.470 --> 00:14:39.420
to find those relevant vectors,

306
00:14:39.420 --> 00:14:41.100
which are the relevant documents,

307
00:14:41.100 --> 00:14:43.590
and this is the relevant context.

308
00:14:43.590 --> 00:14:48.180
Then taking the original question, augmenting it

309
00:14:48.180 --> 00:14:51.990
with the chunks, and then sending everything to the LLM

310
00:14:51.990 --> 00:14:55.170
to get back the answer we want when it's grounded

311
00:14:55.170 --> 00:14:56.883
with relevant context.

