YouTube2Text

LangChain Full Crash Course - AI Agents in Python — Transcript

by NeuralNine · 10,535 words · 1,463 segments · language en · Watch on YouTube

Full transcript

  1. 0:00Today we're going to do a crash course
  2. 0:01on Langchain, the Python framework for
  3. 0:03working with and building AI agents. It
  4. 0:06makes it super simple to interact with
  5. 0:08standalone models, build complex agents,
  6. 0:10and integrate all sorts of other
  7. 0:11components like embedding models or
  8. 0:13vector stores. And all of this without
  9. 0:15caring about specific differences in API
  10. 0:18definitions of the various providers.
  11. 0:20The goal of this video today is to cover
  12. 0:21as much as possible in a short amount of
  13. 0:23time. We're going to start by talking
  14. 0:25about Langchain and its ecosystem. Then
  15. 0:27we're going to take a look at a couple
  16. 0:28of simple examples for building agents
  17. 0:31and working with standalone models.
  18. 0:32We'll learn how to work with message
  19. 0:34histories, stream responses, use tools,
  20. 0:36generate structured output, handle
  21. 0:38multimodal input, pass context, and keep
  22. 0:40track of memory. After that, we'll also
  23. 0:42build a simple rag example. And finally,
  24. 0:44we're going to take a look at
  25. 0:45Langchain's powerful middleware, as well
  26. 0:48as some interesting use cases for it.
  27. 0:49That's quite a few things to cover, and
  28. 0:51I think you can learn a lot today,
  29. 0:52especially since we're going to work
  30. 0:54with the latest version of Langchain
  31. 0:551.0. If you like this video, let me know
  32. 0:57by hitting the like button and
  33. 0:59subscribing. But now, let us get right
  34. 1:00into it.
  35. 1:06[music]
  36. 1:10>> All right. So, we're going to cover
  37. 1:11quite a lot today, which is why I'm
  38. 1:12going to try to speed this up to cover
  39. 1:14as much as possible in a concise way so
  40. 1:16we don't waste too much time here. I
  41. 1:18want to start by just briefly talking
  42. 1:20one or two minutes about Langchain, the
  43. 1:22Langchain ecosystem, and also its
  44. 1:24development history. Now, langchain
  45. 1:26itself as I mentioned is a Python
  46. 1:28framework for building and working with
  47. 1:29AI agents. The main use case or the main
  48. 1:32benefit of using Langchain is that we
  49. 1:35can use all these models and related
  50. 1:37tools in an abstract way. So, regardless
  51. 1:39of the provider, regardless of whether
  52. 1:40you're using OpenAI or Enthropic or
  53. 1:43Google, you basically have the same
  54. 1:45classes and methods everywhere. And if
  55. 1:47you have a system built on langchain
  56. 1:49that uses vector stores, embedding
  57. 1:50models, uh AI models, agents, whatever,
  58. 1:53you can easily just swap out the
  59. 1:55underlying technology and you can keep
  60. 1:57the code the same for the most part. So
  61. 1:59that's what I would consider the main
  62. 2:00selling point of Langchain that you have
  63. 2:02this abstract highlevel way of working
  64. 2:05with agents and related tooling. Now in
  65. 2:07addition to lang, we also have lang
  66. 2:09graph which is more low-level. We have
  67. 2:10more granular control. We can build
  68. 2:12complex graph-based event-driven agents
  69. 2:15or agentic systems. We're not going to
  70. 2:17cover Langraph in this video today. I do
  71. 2:19have videos on this channel where we use
  72. 2:21Langraph, but it's not going to be the
  73. 2:23topic of this crash course. And finally,
  74. 2:24we also have Lang Smith, which is like a
  75. 2:26collection of tools for observing,
  76. 2:28evaluating, monitoring, and deploying
  77. 2:30models. We're not going to cover that
  78. 2:32either. We're going to focus fully on
  79. 2:34Langchain today. Speaking of which,
  80. 2:35Langchain is now on version 1.0. So,
  81. 2:38some of you guys watching this might
  82. 2:39have already worked with Langchain in
  83. 2:41the past. Maybe you're already familiar
  84. 2:43with the package to some degree. But if
  85. 2:45you take a look at 1.0, you will notice
  86. 2:47that some things have changed. So, when
  87. 2:49I first used Langchain, the structure
  88. 2:51was a little bit different. We had
  89. 2:52Langchain, then we had Langchain core,
  90. 2:54and langchain community. And then you
  91. 2:56also had langai, langchain anthropic as
  92. 3:00separate import packages. So you would
  93. 3:01do something like from langchain core
  94. 3:04import something from langchain openai
  95. 3:07import something. Now with 1.0 it seems
  96. 3:10like if you look in the documentation
  97. 3:12everything is going through the main
  98. 3:14langchain package. So from langchain do
  99. 3:17something we import stuff. The second
  100. 3:19thing you will notice is that langchain
  101. 3:20is now much more focused on being a
  102. 3:22library for agents. Not just for
  103. 3:24integrating tools not just for using
  104. 3:26models and vector stores and all that
  105. 3:28but actually for building agents. Which
  106. 3:30means that we now have here langchain
  107. 3:32agents with create agent and in the past
  108. 3:35in my opinion it was more like langchain
  109. 3:37is this general toolkit for working with
  110. 3:39these tools and lang graph was more
  111. 3:41about the agent side. So we can still
  112. 3:43use the packages like langchain core and
  113. 3:45langchain community but for the most
  114. 3:46part it's enough to just go with the
  115. 3:48main lang package that is the modern way
  116. 3:50of working with this framework. Cool. So
  117. 3:52now that we covered that let us go ahead
  118. 3:54and set up our environment. In my case
  119. 3:56I'm going to use uv which is a rustbased
  120. 3:58python package manager. Of course, feel
  121. 4:00free to use pip or pip 3 install. Feel
  122. 4:02free to use virtual environments with
  123. 4:04virtual env or ven, whatever you want to
  124. 4:06choose. In my case, I'm going to go to
  125. 4:08my tutorial directory, say UV init, and
  126. 4:11then I'm also going to say UV at
  127. 4:13langchain. Now, one thing that's
  128. 4:14important is if you want to use lang
  129. 4:17chain together with some AI provider,
  130. 4:19which you usually want to do, you need
  131. 4:21to also provide it in square brackets.
  132. 4:23So for example, if I want to install
  133. 4:24lang chain with the openai dependencies,
  134. 4:27what I will do is I will say open AI in
  135. 4:30square brackets here. So in my case, UV
  136. 4:32add langchain openai. If you use pip,
  137. 4:34you do pip or pip 3 install langchain
  138. 4:37openai. And this will also install
  139. 4:39packages like of course openai. And you
  140. 4:42have to do that basically for all the
  141. 4:44providers that you want to use. So you
  142. 4:45want to do that for enthropic, you want
  143. 4:47to do that for mistral AI. I'm going to
  144. 4:50actually just do it now to show you how
  145. 4:52this works. Mistral AI and you also want
  146. 4:54to do this for Google genai if you plan
  147. 4:56to use all these models. Now what we're
  148. 4:58also going to need is API keys. If you
  149. 5:00want to use models from providers of
  150. 5:02course you have to authenticate
  151. 5:03yourself. So we're going to create a
  152. 5:05file called and this file will contain
  153. 5:08our keys. So these keys will be the
  154. 5:10open_appi_key.
  155. 5:12It's going to also be the Mistral API
  156. 5:15key, the Anthropic
  157. 5:18API key, and I'm not sure what the
  158. 5:20correct name is for the Google one, but
  159. 5:22I'm just going to say Google API key,
  160. 5:24even though that's probably not the
  161. 5:25correct one. So, what you want to do is
  162. 5:26you want to go to the providers if you
  163. 5:28have accounts there if you have API keys
  164. 5:30and you want to paste them here. So, I'm
  165. 5:32going to go to OpenAI console to Mistral
  166. 5:34Console, Enthropic Console, and to my
  167. 5:36Google Cloud Platform. There I'm going
  168. 5:38to take the API keys, copy paste them
  169. 5:40here. I'm not going to show how to
  170. 5:42obtain them or maybe I'm going to show
  171. 5:43them for one of them. So yeah, here for
  172. 5:45example, we go to
  173. 5:45platform.openai.com/api
  174. 5:48keys or you just go to API keys here on
  175. 5:50the left and here you can create a new
  176. 5:52secret key or API key. You do that for
  177. 5:54the various providers. Then you just
  178. 5:55copy paste the keys here like this or
  179. 5:57you use quotation marks if you want to
  180. 5:59and that is our end file. So in my case
  181. 6:01I already did this and now I'm going to
  182. 6:03install an additional package called
  183. 6:06python-.end.
  184. 6:08This is going to allow us to load these
  185. 6:10API keys into our Python script. Now, to
  186. 6:13get autocomp completion, I'm also going
  187. 6:14to activate this environment here. This
  188. 6:16is something I just have to do for Neoim
  189. 6:18to get autocomp completion. So, you can
  190. 6:19ignore that if you're not coding in the
  191. 6:21terminal. And then we're going to go
  192. 6:23into our main py file and get started
  193. 6:25with a first simple example. So, instead
  194. 6:27of just covering the concepts one by
  195. 6:29one, I'm going to show you how to build
  196. 6:30a simple agent. And we're going to cover
  197. 6:32a couple of concepts while we're doing
  198. 6:33that. So, we're going to start with the
  199. 6:35import. Let's import requests. Then also
  200. 6:38as I said from we're going to import
  201. 6:40load.n this is for loading the API keys
  202. 6:43into the environment. And then from
  203. 6:45langchain
  204. 6:47agents as we saw already in the docs
  205. 6:49we're going to import the create agent
  206. 6:51function. This is like the central
  207. 6:53function that is going to create agents
  208. 6:55that we then use to do stuff. And in
  209. 6:57this function we can do a lot of things.
  210. 6:59So we can provide middleware, we can
  211. 7:01provide tools, we can do a lot of things
  212. 7:03in that function or with that function.
  213. 7:04In addition to that, I'm also going to
  214. 7:06say now from langchain.tools
  215. 7:08import tool. This is a decorator that we
  216. 7:11can use to annotate a function to
  217. 7:13basically make that function a tool. We
  218. 7:15can also provide some uh information
  219. 7:16like a description or the name of the
  220. 7:18function. So for example, we can say add
  221. 7:20tool and I want to define a tool that is
  222. 7:23called get weather. This is going to
  223. 7:25obviously get the weather and I can
  224. 7:27provide a description here for the agent
  225. 7:29to know what this function is about or
  226. 7:31what this tool can do. In my case, I'm
  227. 7:33going to say here return weather
  228. 7:35information for a given city.
  229. 7:38Theoretically, you can also say return
  230. 7:40direct is equal to true if you want to
  231. 7:42have just the output of that tool
  232. 7:43immediately returned to the user. In
  233. 7:45this case, set this to true. We can also
  234. 7:47explicitly set it to false. I think it's
  235. 7:49the default, but just so we know it
  236. 7:51exists, we're going to set it to false.
  237. 7:53And then we're going to say now the
  238. 7:55function is get weather. It's going to
  239. 7:56get a city, which is going to be a
  240. 7:58string as input. And we're going to make
  241. 8:00it very simple here. Here I don't want
  242. 8:02to use a mock function. So I'm actually
  243. 8:03going to ping a weather API. But this
  244. 8:06one is actually open source and free to
  245. 8:08use or maybe not open source, but you
  246. 8:09don't need an account to use it. So
  247. 8:11we're going to say here response is
  248. 8:12equal to requests.get.
  249. 8:14And we're going to use https/wtr.in/
  250. 8:22city question mark format equals j1. And
  251. 8:25of course this needs to be an fstring
  252. 8:27otherwise we cannot parse or we cannot
  253. 8:30format the city into the string here.
  254. 8:31But this basically gives us a JSON
  255. 8:33object with temperature and the weather
  256. 8:35information for a given city. And all we
  257. 8:37want to do here is we want to return the
  258. 8:39JSON object that we get here. So return
  259. 8:42response.json and then the model the
  260. 8:44agent can do whatever it wants with that
  261. 8:46information or whatever it thinks is the
  262. 8:48most reasonable thing to do. So to keep
  263. 8:49it simple we're going to have just this
  264. 8:50one tool. And now we're going to say
  265. 8:52agent is equal to create agent. And the
  266. 8:54first thing we want to do here is we
  267. 8:56want to provide the model. Now the model
  268. 8:57can just be a string. For example, I can
  269. 8:59say GPT-40.
  270. 9:01Now 40 doesn't support tool use. So
  271. 9:03we're not going to use that. But I can
  272. 9:05go with 4.1 mini. For example, this
  273. 9:08would be open AI. It is automatically
  274. 9:11recognized as OpenAI. So if I don't have
  275. 9:13Langchain OpenAI installed, it's not
  276. 9:15going to work. So for this, a couple of
  277. 9:17things need to be present. One is an
  278. 9:19OpenAI API key in the environment. And
  279. 9:22the other thing is langchain open AAI
  280. 9:24needs to be installed. So these two
  281. 9:26things need to be given so that we can
  282. 9:28actually use this model. After that I
  283. 9:30can just say give me a list of tools and
  284. 9:32this list will contain just get weather
  285. 9:34as an entity. So we're not calling the
  286. 9:36function we're passing it. And then we
  287. 9:38can provide a system prompt like you are
  288. 9:41a helpful weather assistant who always
  289. 9:45cracks jokes and is humorous while
  290. 9:49remaining
  291. 9:51helpful. So just to give you an example
  292. 9:53so that you can see that the system
  293. 9:54prompt actually affects the agent and
  294. 9:56then in order to get something from this
  295. 9:58agent in order to send something to the
  296. 10:01agent I should say we can just invoke
  297. 10:02it. So I can say agent.invoke invoke and
  298. 10:05here what we do is we pass a dictionary
  299. 10:08that contains a field messages and this
  300. 10:12messages has to point so this key
  301. 10:15messages has to point to the value which
  302. 10:17is a list and this list will contain all
  303. 10:19the messages as dictionaries with ro and
  304. 10:22content as we know it from the typical
  305. 10:25API. So ro is going to be user and
  306. 10:28content is going to be whatever we want
  307. 10:29to ask for. For example, what is the
  308. 10:32weather like in Vienna? Question mark.
  309. 10:36So I need to then save this as a
  310. 10:39response. And down here I can then print
  311. 10:41the entire response. So print response
  312. 10:45or I can say if I want to get just the
  313. 10:47message, I can get from response the
  314. 10:49messages. Maybe let me do that here with
  315. 10:52square brackets and a string. And then I
  316. 10:55want to have the last message. So
  317. 10:56negative one. And then from this
  318. 10:58message, I'm interested in the content.
  319. 11:00So I can run this now. And I get a
  320. 11:02problem because because I'm of course
  321. 11:04not loading the environment variables.
  322. 11:07So I need to import load. But I also
  323. 11:10need to call it to load the data from
  324. 11:12the end file. So let's go ahead and say
  325. 11:14uvun main py. I'm doing it outside here
  326. 11:16so I can see all the output. And what
  327. 11:19you see up here is the raw response
  328. 11:22object which contains the entire message
  329. 11:24history also with all the data that was
  330. 11:26provided by the API. And as a result
  331. 11:29down here I get the actual message. The
  332. 11:32weather in Vienna right now is partly
  333. 11:33cloudy with a comfortable temperature of
  334. 11:36about 15° C and then some information
  335. 11:38about the wind speed and humidity and so
  336. 11:40on. So actually quite comprehensive.
  337. 11:42We're going to build on top of this
  338. 11:43example and extend it later on. But
  339. 11:45before we go deeper into agents, let me
  340. 11:47remove all of this. I want to show you
  341. 11:48how to use standalone models. So maybe
  342. 11:50you don't want to have an agent. You
  343. 11:52just want to interact with a simple
  344. 11:54model and that's it. And you want to do
  345. 11:56that in a more abstract way. So you can
  346. 11:58replace the models that you're using.
  347. 11:59For this you can also use lang chain but
  348. 12:01not agents. You want to use lang chain
  349. 12:03chat models. And you want to import the
  350. 12:05function init chat model. And for this
  351. 12:07we're also not going to use tools. We're
  352. 12:09just going to do it like this. And it's
  353. 12:11actually quite simple and
  354. 12:12straightforward. I just say model is
  355. 12:14equal to init chat model. Then I can
  356. 12:16provide basic parameters like again the
  357. 12:18model identifier which is going to be
  358. 12:214.1 mini again. And theoretically if I
  359. 12:24want to I can do stuff like temperature
  360. 12:270.1 for example. And once I'm done with
  361. 12:29all this I can just say response is
  362. 12:31equal to model.invoke and here I just
  363. 12:34provide a prompt now like hello what is
  364. 12:38python question mark and then I can
  365. 12:40print the entire response object or I
  366. 12:43can just print the response content. So
  367. 12:45in this case, response.content since we
  368. 12:47didn't pass a message history or
  369. 12:49conversation history. And of course, one
  370. 12:52more time, I forgot the load. So we're
  371. 12:54going to add this and run this again.
  372. 12:56And there you go. We get an answer that
  373. 12:58tells us what Python is, a highle
  374. 13:00interpreted programming language. And we
  375. 13:02also have again this entire response
  376. 13:04object if we want to access different
  377. 13:06fields like the total amount of tokens
  378. 13:08and stuff like this. But you can see how
  379. 13:10easily this is done in lenchain. And we
  380. 13:12can also just swap the model if we want
  381. 13:13to use a different one. So instead of
  382. 13:15using GPT I can say I want to use
  383. 13:16Mistral medium. I just have to provide
  384. 13:18the proper string from the website and
  385. 13:21then I can run this and everything else
  386. 13:23in the application stays the same. I'm
  387. 13:25now just using Mistral uh medium instead
  388. 13:27of GPT4.1 mini and I'm going to get the
  389. 13:30response and everything's going to work
  390. 13:31in the same way. There you go. It's a
  391. 13:33quite comprehensive response but we get
  392. 13:36the answer here from Mistl. Let me now
  393. 13:38switch back to 4.1 mini. Now if we want
  394. 13:41to pass a conversation history and not
  395. 13:43just a single prompt, we can do that as
  396. 13:45well with this list and dictionary sort
  397. 13:47of notation that we used before. But we
  398. 13:49can also import specific classes for
  399. 13:51that. I can also say from langchain dot
  400. 13:54messages import human message AI message
  401. 13:58and system message. This makes it then
  402. 14:00super simple to work with. I can just
  403. 14:02say conversation is equal to a list and
  404. 14:05in here I can say I first have a system
  405. 14:07message. For example, you are a helpful
  406. 14:10assistant for questions regarding
  407. 14:14programming. Then the second message
  408. 14:16could be something that a human asks.
  409. 14:18Like for example, what is Python?
  410. 14:22Maybe let's stay consistent here with a
  411. 14:24quotation marks. Let's use single
  412. 14:26quotations everywhere. And then we're
  413. 14:27going to say an AI already answered
  414. 14:29that. We're going to say that it told us
  415. 14:32Python is an interpreted
  416. 14:35programming language. not question mark
  417. 14:38but period and then we're going to say
  418. 14:40the human has a follow-up question which
  419. 14:42relates to the previous messages and
  420. 14:45this is when was it released question
  421. 14:48mark. So now instead of invoking on a
  422. 14:50string I can also invoke on a
  423. 14:52conversation and actually I'm missing a
  424. 14:55t here and here as well and now the rest
  425. 14:58stays the same and we have a
  426. 14:59conversation. So Python was first
  427. 15:01released in 1991 by gofo fun rosesome.
  428. 15:04Now, we saw with Mistl that responses
  429. 15:06can be quite long and we need to wait
  430. 15:08for them to be finished before we can
  431. 15:09start reading them. If we don't want
  432. 15:11that, if we want to read them in real
  433. 15:12time as they're generated, we can also
  434. 15:14stream the response. So, let us maybe go
  435. 15:16back here to the prompt and let us also
  436. 15:19change the model back to mistrol. So,
  437. 15:21here I'm going to say mistrol medium 258
  438. 15:26and we're going to ask the same
  439. 15:27question, but instead of just getting
  440. 15:28the response here, we're going to stream
  441. 15:30it. So we're not going to invoke. We're
  442. 15:31going to say model stream and we're
  443. 15:34going to iterate over this generator
  444. 15:35here to generate the chunks. So I'm
  445. 15:37going to say for chunk in model stream
  446. 15:40I'm going to print the chunk.ext.
  447. 15:43I'm going to have no line breaks after
  448. 15:45each print and I'm going to say flush is
  449. 15:48equal true equal to true so I can see
  450. 15:50the output in real time. And we're going
  451. 15:53to delete that and run this. And now you
  452. 15:56can see how this is generated in real
  453. 15:58time and I can read while it's still
  454. 16:00generating. So let us now come back to
  455. 16:01our initial example with the agent here
  456. 16:04and the weather function. We're now
  457. 16:05going to extend it to incorporate more
  458. 16:07concepts. So on the one hand I want to
  459. 16:09have structured output. I want to have
  460. 16:11the output message or summary and I also
  461. 16:13want to have some key information like
  462. 16:15the temperature or the humidity. Also I
  463. 16:18want the agent to be able to realize
  464. 16:20what location I'm asking this question
  465. 16:22from. So I don't have to specify the
  466. 16:24city. So I just want to say what's the
  467. 16:26weather like? And the agent should
  468. 16:27realize that I'm asking from a specific
  469. 16:30city based on mock database entries that
  470. 16:32we're going to provide here. And with
  471. 16:34this context, it's going to then
  472. 16:36retrieve the proper information. And
  473. 16:38finally, I would also like to add memory
  474. 16:39to this agent so it can remember that we
  475. 16:42had a conversation and we're now
  476. 16:43continuing that conversation. So we're
  477. 16:45going to add some imports for all of
  478. 16:46this. First of all, from core Python,
  479. 16:48we're going to add here from data
  480. 16:50classes the data class. And for
  481. 16:53langchain here, we're going to say from
  482. 16:54langchain.models
  483. 16:57or chat models importit
  484. 17:00chat model. In addition to tool, we're
  485. 17:02also going to import tool runtime. And
  486. 17:05finally here from lang graph. Now I said
  487. 17:08we're not going to do lang graph. We're
  488. 17:10not going to cover the langraph
  489. 17:12framework, but we're going to use uh one
  490. 17:14specific class from there. It's from
  491. 17:16checkpoint memory the inmemory saver
  492. 17:19which is going to be important for
  493. 17:21remembering the message history. Cool.
  494. 17:23So now let us create two data classes.
  495. 17:25One is going to be for the context.
  496. 17:26We're going to keep track of the user ID
  497. 17:28that the model is communicating with so
  498. 17:30that we can actually look up the
  499. 17:32location of that user from our database
  500. 17:35which we're going to just model as a
  501. 17:37match case statement in a function. And
  502. 17:39then we're also going to have a data
  503. 17:40class for the response format. So we're
  504. 17:42going to say here at data class and then
  505. 17:45it's going to be a class called context.
  506. 17:47Quite simple and it's just going to have
  507. 17:49a user ID which is a string. And then
  508. 17:50for the response format we're going to
  509. 17:52say data class response format. And here
  510. 17:56I want to have a summary which is going
  511. 17:58to be a string. I want to have a
  512. 18:00temperature in Celsius which is going to
  513. 18:03be a float. I want to have the same in
  514. 18:05Fahrenheit. And I also want to have a
  515. 18:07humidity whatever the unit is here.
  516. 18:10Cool. So now what we're going to do is
  517. 18:12we're going to add an additional tool
  518. 18:14and this tool is going to be locate
  519. 18:16user. So the name is going to be locate
  520. 18:18user and it's going to have the
  521. 18:20following description. Look up a user's
  522. 18:24now I have to use double quotations
  523. 18:26here. Look up a user's city based on the
  524. 18:31context. Now the interesting thing is
  525. 18:33we're not going to pass the user ID as a
  526. 18:35parameter. We're going to have a tool
  527. 18:38runtime which contains context. So the
  528. 18:41context is going to contain the user ID
  529. 18:42and we're going to get it from this
  530. 18:44context. How do we do that? We say
  531. 18:46deflocate user and here we have a
  532. 18:49runtime. This runtime is going to be a
  533. 18:51tool runtime and we're going to pass
  534. 18:54here in square brackets the context
  535. 18:56class the data class we just created.
  536. 18:59And here what we're going to do is we're
  537. 19:00going to get the user ID from
  538. 19:02runtime.context.
  539. 19:03And I'm going to use a match statement.
  540. 19:05So match runtime dot context dot user
  541. 19:09ID. And depending on the value, we're
  542. 19:11going to return a different city. So
  543. 19:13let's make up some cases here. If the
  544. 19:14user ID is ABC123,
  545. 19:17I'm just going to return Vienna. Another
  546. 19:19case could be if the user ID is XYZ456,
  547. 19:24then I'm going to say that we're in
  548. 19:26London. Then another case could be HJKL
  549. 19:30for Vim and then 111. That would return
  550. 19:33Paris. And if it's none of these, if
  551. 19:36it's unknown, we're going to say case
  552. 19:38default is just going to return unknown.
  553. 19:41Now, you can define unknown behavior in
  554. 19:44multiple ways. You can provide it in the
  555. 19:46description. You can even provide it in
  556. 19:47the return value itself. You can provide
  557. 19:49it in the system prompt. You can also
  558. 19:51add some custom logic. But basically, we
  559. 19:53need to somehow instruct the model that
  560. 19:55if it's unknown, just say it's unknown.
  561. 19:57Maybe it can do it automatically as
  562. 19:58well. Uh, wherever you want to put that,
  563. 20:00put that somewhere how you want to
  564. 20:02handle unknown values. But we're going
  565. 20:03to look up based on the user ID in the
  566. 20:06context. So remember the connection here
  567. 20:08we have the runtime the tool runtime
  568. 20:10passed to this tool which is based on
  569. 20:12the data class context which we defined
  570. 20:14up here which contains the user ID. So
  571. 20:17now we're going to go down here create
  572. 20:19the model to show you that we can also
  573. 20:21pass a model instance. So model is going
  574. 20:23to be init chat model GPT-4.1-
  575. 20:27mini and the temperature not this sort
  576. 20:30of temperature but the model temperature
  577. 20:33is going to be 0.3 for example and then
  578. 20:37we're going to create a checkpointer
  579. 20:39which is going to be an in-memory saver.
  580. 20:41As I said this is for remembering
  581. 20:42conversations. We're going to add to the
  582. 20:45agent invocations a thread ID and this
  583. 20:48is going to determine the conversation
  584. 20:51that we're focusing on. So we can keep
  585. 20:53asking questions about the same
  586. 20:54conversation. And now we can combine all
  587. 20:56of this into the create agent function.
  588. 20:59So we're going to say agent is equal to
  589. 21:00create agent. Model is equal to model.
  590. 21:04Tools is equal to get weather and locate
  591. 21:06user. System prompt can stay the same.
  592. 21:09Now new stuff here is context schema.
  593. 21:12This is going to be the class the data
  594. 21:13class of our context. So just context.
  595. 21:17Then also response format. I think it's
  596. 21:19not surprising that this will be our
  597. 21:20class response format. And finally,
  598. 21:23checkpointer also not surprising is
  599. 21:26going to be the checkpoint. So what our
  600. 21:28agent now does is it has access to a
  601. 21:30model GPT4.1 mini. It has access to two
  602. 21:34tools. One for getting weather
  603. 21:35information about the city, one for
  604. 21:37locating the user, so getting the city
  605. 21:39of the user based on the user ID. We
  606. 21:41have a system prompt here. We now also
  607. 21:43have the ability to pass context. So for
  608. 21:46this we use the data class context which
  609. 21:48again contains the user ID. Then we have
  610. 21:50a response format which means that our
  611. 21:51model is forced now to answer in a
  612. 21:54specific format. This format is going to
  613. 21:56be a summary string and then three
  614. 21:58floats for temperature and humidity. And
  615. 22:00finally we add memory to the model so it
  616. 22:03can keep track of conversations based on
  617. 22:05a thread ID. So now when we invoke
  618. 22:07something we also need to pass context
  619. 22:10and thread ID. For this we're going to
  620. 22:12start by saying config is equal to
  621. 22:14dictionary which is going to have a key
  622. 22:17called configurable. And this
  623. 22:19configurable is going to point to
  624. 22:20another dictionary which contains thread
  625. 22:22ID which itself points to one for
  626. 22:25example. And now for the invocation I'm
  627. 22:27going to say what is the weather like
  628. 22:28without specifying a city but I'm going
  629. 22:31to specify context and I'm going to pass
  630. 22:33the configuration. So for the
  631. 22:35configuration just config equals config
  632. 22:38and for the context we're going to say
  633. 22:39context is equal to context an instance
  634. 22:42of the data class where we set the user
  635. 22:45ID to be equal to ABC123.
  636. 22:48So that would result in Vienna again. We
  637. 22:50should get the same response. And since
  638. 22:52we're now working with this response
  639. 22:54format, since we're forcing structured
  640. 22:56output, we're going to not access just
  641. 22:58messages negative1 content. We're going
  642. 23:00to print the entire response object if
  643. 23:02we want to. Actually, I don't want to do
  644. 23:03that. I just want to get the structured
  645. 23:05output itself. And for that, I'm going
  646. 23:07to say here response structured
  647. 23:10response. And this will give us the
  648. 23:12entire response object. If I'm
  649. 23:13interested in specific parts of that, I
  650. 23:15can just say dot summary or dot
  651. 23:19temperature Celsius for example. So now
  652. 23:21I can run this and we have a problem
  653. 23:24because we're not closing this curly
  654. 23:28bracket early enough. So of course it
  655. 23:30belongs to this message history. But
  656. 23:32these are now just keyword arguments. So
  657. 23:35let me run this again. And we can see
  658. 23:37the current weather in Vienna is partly
  659. 23:39cloudy. And then I also get 15.0 zero
  660. 23:42for the Celsius temperature. Now, if I
  661. 23:45change my user ID to something else like
  662. 23:47XYZ, what was it? 456, then I should get
  663. 23:51the weather for London. There you go.
  664. 23:52The weather in London is currently sunny
  665. 23:55with a temperature of 12. Then, if I try
  666. 23:57something completely different like
  667. 23:58this, something it doesn't recognize,
  668. 24:00probably it's going to tell me unknown
  669. 24:02or it's going to do something else. I
  670. 24:05couldn't find your location, so I can't
  671. 24:06tell the weather, but hey, if you tell
  672. 24:08me your city, I'll fetch the weather.
  673. 24:10and zero is the default value for
  674. 24:12temperature. And to show you that this
  675. 24:14actually works with a follow-up, if I
  676. 24:16provide here again a valid user ID like
  677. 24:19this for Vienna here, I can also follow
  678. 24:22up with the same config to keep track of
  679. 24:24this conversation. So I can just copy
  680. 24:25this here, paste it down here and I can
  681. 24:29say and is this usual question mark. So
  682. 24:33when I run this now and of course maybe
  683. 24:35before running this I should also print
  684. 24:37the result. So just copy this from up
  685. 24:39here. print structured response summary
  686. 24:42and now it should keep track of the
  687. 24:44information. So we have this inmemory
  688. 24:46saver. So we have still the information
  689. 24:48that uh the weather in Vienna is what it
  690. 24:50is and then yes the weather in Vienna
  691. 24:52being partly cloudy with mild
  692. 24:53temperatures around 15° C and so on is
  693. 24:57usual for this time of the year.
  694. 24:59However, you will notice that if I take
  695. 25:00this and I change this before I do that.
  696. 25:03So if I say now the thread ID is two,
  697. 25:06it's no longer going to be related to
  698. 25:08that thread. So, it doesn't know what
  699. 25:09I'm talking about. So, here I get the
  700. 25:11information about Vienna. And now I
  701. 25:13would need to know the specific weather
  702. 25:14conditions or location you're referring
  703. 25:16to in order to determine if it's usual
  704. 25:18or not. So, since we're in a different
  705. 25:20threat, it doesn't know what we talked
  706. 25:22about up until this point. If I may for
  707. 25:24a second, I would like to plug myself in
  708. 25:26as the sponsor of my own video. If you
  709. 25:28go to my website, neural9.com, you will
  710. 25:30find a tab services and a tab tutoring.
  711. 25:33Here you can hire me for all sorts of
  712. 25:35stuff like data science, machine
  713. 25:36learning, web development. If you need
  714. 25:38help with something in a project here,
  715. 25:40you can book me for one-on-one tutoring.
  716. 25:41If you want me to teach you personally
  717. 25:43something that you don't understand, if
  718. 25:45you like my teaching style on both pages
  719. 25:47at the bottom, you can contact me via
  720. 25:49mail and also via LinkedIn. Just wanted
  721. 25:52to let you know about this. Next, I want
  722. 25:53to show you how we can work with
  723. 25:54multimodal input. So, how can we pass to
  724. 25:57a model not just text, but for example,
  725. 25:59image data. For this, I'm going to say
  726. 26:01here model is equal to in a chat model.
  727. 26:03I'm going to use again GPT-4.1-
  728. 26:08mini. And we're now going to create a
  729. 26:11message in the dictionary format. Again,
  730. 26:13I'm going to show you a different way in
  731. 26:14a second as well. The role for this
  732. 26:17message is going to be user. And the
  733. 26:19content field now is going to have
  734. 26:20multiple values. So, we're going to say
  735. 26:22content is pointing to a list. And this
  736. 26:25list will contain multiple pieces of
  737. 26:27content. For example, the first one will
  738. 26:29be of type text and we're going to say
  739. 26:32that the actual text content. So again
  740. 26:34text here as a key not as a value will
  741. 26:37be describe the contents of this image.
  742. 26:42Now we can copy that and we can say type
  743. 26:45image and now we have two ways to
  744. 26:47provide image content. One is by using
  745. 26:50URL. So this basically points to an
  746. 26:52image somewhere on the web or we can
  747. 26:54also pass base 64 encoded image bytes.
  748. 26:58Now we're going to do both but I'm going
  749. 26:59to start with a URL and for that I have
  750. 27:02here a link from my website. So just
  751. 27:04neural9.com and the logo on my website.
  752. 27:07I'm going to pass this here as image
  753. 27:08content. And what I'm going to do then
  754. 27:11is I'm going to say model.invoke.
  755. 27:14I'm going to pass a list of messages and
  756. 27:16just my one message in here. That's
  757. 27:18going to be the response. And then I can
  758. 27:20just say print response.content.
  759. 27:23So if I run this, this will take a look
  760. 27:25at my image and tell me that this is a
  761. 27:29logo that reads neural 9 and orange text
  762. 27:31on a black background. The text is
  763. 27:33stylized with a number one. I think this
  764. 27:35is just a mistake in the font. And it
  765. 27:38explains what my logo looks like
  766. 27:39essentially. So this is what we want.
  767. 27:41And we can do the same thing with an
  768. 27:43image from disk. So if I open the
  769. 27:46sidebar here, you can see I have the
  770. 27:48logo.png. png. We can also load this and
  771. 27:51encode it with b 64. So in this case
  772. 27:54here just b 64 as the field as the key
  773. 27:58here and I'm also going to say from b 64
  774. 28:02import b 64 encode. So the idea is we
  775. 28:06load the bytes we encode them with b 64
  776. 28:08and then we decode it into a string. So
  777. 28:11we're going to say here b64 encode. What
  778. 28:13are we encoding? We're opening a file
  779. 28:16from disk called logo.png
  780. 28:19in reading bytes mode. Then we're
  781. 28:21reading the content of that file. We're
  782. 28:23encoding it with B 64 and then we're
  783. 28:25decoding it into a string. So we can
  784. 28:27actually pass it here to the model. Now
  785. 28:28what we also need to pass here if we use
  786. 28:30B 64 is a mime type. So let's actually
  787. 28:34format it like this. And the mime type
  788. 28:36is going to be image / PNG. And actually
  789. 28:41I think we need to use underscore not
  790. 28:43dash. So now when I run this you can see
  791. 28:44the image shows a logo with a text
  792. 28:46neural 9 written in orange and basically
  793. 28:49the same thing as before. Now we can
  794. 28:50also do it with the message classes but
  795. 28:52we have to do it basically in the same
  796. 28:54way. So I can say langchain do messages
  797. 28:57import human message and the only thing
  798. 28:59I would change is I would get rid of the
  799. 29:01role but I would still keep the content
  800. 29:03as it is. So I would say here the
  801. 29:05message is equal to human message and
  802. 29:08then I would say content is equal to the
  803. 29:10list. So that is the small difference
  804. 29:13here. So context would be equal to the
  805. 29:16list of these two things and then we
  806. 29:18would close that with an ordinary
  807. 29:21bracket but basically the rest stays the
  808. 29:23same. So when I run this we should get
  809. 29:24the same response. It's just a different
  810. 29:26way to write it. Now for the next
  811. 29:28example we're going to build a simple
  812. 29:29rack use case. So retrieval augmented
  813. 29:31generation. Basically we're going to use
  814. 29:34a vector store and an embedding model to
  815. 29:36find the most similar pieces of content.
  816. 29:38In our case, simple messages or simple
  817. 29:41statements, let's say. And for this,
  818. 29:43we're going to use lang chain in the old
  819. 29:45school way. So, we're actually going to
  820. 29:46say up here from langchain openai import
  821. 29:51openai embeddings. This is for the
  822. 29:52embeddings model. And then we're also
  823. 29:54going to use a vector store. So, a
  824. 29:56vector database in my case face. And for
  825. 29:58this, we're going to say from langchain
  826. 30:01community
  827. 30:02import. And we're going to import uh
  828. 30:05face. But actually not from community
  829. 30:06directly but from community.
  830. 30:09Vector stores and since I'm not getting
  831. 30:11autocomp completion I assume I have to
  832. 30:13install this separately. So I'm going to
  833. 30:15say here now uv at and then
  834. 30:18langchain-ash
  835. 30:20community. So this installs now
  836. 30:22additional packages langchain community
  837. 30:24langchain classic langchain textlitter.
  838. 30:26So if I now go back into the code
  839. 30:29hopefully if I type dot something here
  840. 30:32there you go. We can see all the modules
  841. 30:34here. So, langin community vector stores
  842. 30:36import face. Now, I think actually for
  843. 30:38face, we also need to install the face
  844. 30:40package. So, let me leave this and let's
  845. 30:42say UV add face. And I'm just going to
  846. 30:45go save here with the CPU. So, I don't
  847. 30:46have to care too much about GPU stuff.
  848. 30:49This is just face CPU. And now, if I go
  849. 30:52back into the code, we should be able to
  850. 30:53use them. So, the basic idea is I'm
  851. 30:55going to have a list of statements.
  852. 30:57These statements will be stuff like I
  853. 30:59love apples or I like oranges or I like
  854. 31:01pears and then something about computers
  855. 31:04also related to Apple but semantically
  856. 31:06different because Apple is a company.
  857. 31:07Apple is also a fruit. So we're going to
  858. 31:10see if the embeddings can distinguish
  859. 31:11the concepts and we're going to retrieve
  860. 31:14the most similar statements from the
  861. 31:16vector store. So let us start by saying
  862. 31:18embeddings is going to be equal to
  863. 31:20openAI embeddings and we're going to
  864. 31:21provide the embedding model text-
  865. 31:24embedding-large
  866. 31:27three. I think this was the identifier
  867. 31:28and we're going to say of course that
  868. 31:30this is the model. So model is equal to
  869. 31:32text embedding three large. Yeah. So
  870. 31:35actually three large not large three.
  871. 31:37Then I'm going to copy paste some very
  872. 31:39very simple statements. Nothing too
  873. 31:41fancy. Apple makes very good computers.
  874. 31:44Whether that's true or not, I'm just
  875. 31:45stating it here. I believe Apple is
  876. 31:48innovative. I love apples. I'm a fan of
  877. 31:50MacBooks. I enjoy oranges. I like Lenovo
  878. 31:53ThinkPads. I think pairs taste very
  879. 31:55good. So, theoretically, this message
  880. 31:58here, I like Lenovo ThinkPads, should be
  881. 32:00closer to I'm a fan of MacBooks. And
  882. 32:03even to stuff like Apple makes very good
  883. 32:05computers. uh it should be closer and
  884. 32:08more related than I love apples because
  885. 32:10that has nothing to do with apple only
  886. 32:12syntactically only in terms of like the
  887. 32:14name it has to do something with apple
  888. 32:16but it's a different concept. So we're
  889. 32:18going to create a vector store from
  890. 32:20these texts. I'm going to say vector
  891. 32:23store is going to be equal to face dot
  892. 32:26from texts and we're going to pass the
  893. 32:29list of texts here. Now in order for
  894. 32:31this to actually work we need to pass an
  895. 32:33embedding model as well. So embedding is
  896. 32:35going to be equal to embeddings. And
  897. 32:37this is going to basically take all
  898. 32:38these texts, embed them into vector
  899. 32:40space and then store them in the vector
  900. 32:42store. So to see how this works, we can
  901. 32:44say print vector store dot similarity
  902. 32:47search and then I can add something new
  903. 32:49like apples
  904. 32:51are my favorite
  905. 32:54food. K equals 7 to get all of them uh
  906. 32:58just in a specific ranking. And then I'm
  907. 33:00going to do the same thing with Linux is
  908. 33:04a great operating system. Of course,
  909. 33:07Linux is just a kernel, but you get the
  910. 33:09idea. So, I'm going to comment this out
  911. 33:11and run the first one alone to see what
  912. 33:14are the most similar statements in the
  913. 33:17vector store. So, you can see here the
  914. 33:18most similar was I love apples. Then the
  915. 33:20second one was I think pears taste very
  916. 33:22good. So, even though the word apple
  917. 33:24occurred, we or actually there you go. I
  918. 33:27enjoy oranges was before that then I
  919. 33:29think pears taste very good and then
  920. 33:31only it gives us Apple makes very good
  921. 33:33computers. I know this is not the best
  922. 33:34view. Uh but we have these individual
  923. 33:36documents the most similar the second
  924. 33:38most similar the third most similar and
  925. 33:41you can see that everything related to
  926. 33:42fruits was ranked as more important and
  927. 33:44more relevant than apple. Even though
  928. 33:47that apple here and apple here is the
  929. 33:50same string it recognizes that the
  930. 33:52concepts are different. So let's see
  931. 33:54what we get for Linux. We get I like
  932. 33:56Lenovo ThinkPads. I'm a fan of MacBooks.
  933. 34:00And then we get I love apples. For
  934. 34:03whatever reason, the company Apple is
  935. 34:05ranked lower. Whatever. So that is how
  936. 34:08you can use the vector store as a
  937. 34:09separate component. So just interact
  938. 34:11with embeddings and vector stores. But
  939. 34:12now what we want to do is we want to
  940. 34:14make this part of agents with lang. So
  941. 34:17we want to take this capability of using
  942. 34:19this rack feature of doing a similarity
  943. 34:22search. We want to take this and build
  944. 34:24it into our agent. For this, I want to
  945. 34:26use a slightly different example. So,
  946. 34:28the code is the same. We still have the
  947. 34:30same structure here of embeddings,
  948. 34:32texts, and then from text similarity
  949. 34:33search, but we have different content.
  950. 34:35We have I love apples. I enjoy oranges.
  951. 34:37I think pears taste very good. I hate
  952. 34:39bananas. I dislike raspberries. I
  953. 34:41despise mangoes. I love Linux. I hate
  954. 34:43Windows. And then we have here again the
  955. 34:46vector store. And here we look for what
  956. 34:48fruits does the person like and what
  957. 34:49fruits does the person hate. So if I run
  958. 34:52this, you can see that these two lookups
  959. 34:55give us the information that we want. I
  960. 34:57enjoy oranges. I love apples. I think
  961. 34:59pears taste very good. Then I despise
  962. 35:01mangoes. I hate bananas. I dislike
  963. 35:04raspberries. So we have the information
  964. 35:05by using the similarity search. What we
  965. 35:07can do now with this vector store is we
  966. 35:09can turn it into a retriever for our
  967. 35:12agent. So I can say down here retriever
  968. 35:14is equal to vector store as retriever.
  969. 35:18And we're just going to pass the search
  970. 35:20keyword arguments. So search_quarks
  971. 35:23is going to be equal to a dictionary
  972. 35:25where K is going to be equal to three.
  973. 35:28So this basically tells us just give me
  974. 35:30the top three answers. We're hard coding
  975. 35:32this to keep it simple here. But
  976. 35:34basically this now is a retriever that
  977. 35:36we can use in our agent. But in order to
  978. 35:38actually use this retriever in our
  979. 35:40agent, we need to turn it into a tool.
  980. 35:42So what we're going to do is another old
  981. 35:44school import up here from
  982. 35:46langchain_core.
  983. 35:48tools. We're going to import the create
  984. 35:51retriever tool. So the idea is we pass a
  985. 35:53retriever and we turn it into a tool
  986. 35:56that the agent can use. So quite simple,
  987. 35:58the retriever
  988. 36:00tool is going to be equal to create
  989. 36:01retriever tool. We pass the retriever
  990. 36:04and then we pass the name which is going
  991. 36:06to be our fruit search I guess or
  992. 36:09actually let's call it knowledgebased
  993. 36:10search. So KB search and then the
  994. 36:12description is search the small
  995. 36:16product/fruit
  996. 36:18database for information. Let me call
  997. 36:22this knowledge base and then we can
  998. 36:24close that. And now the cool thing is
  999. 36:26this is now just another tool. We can
  1000. 36:28just add it to the list of tools when we
  1001. 36:29create an agent. So for this we need to
  1002. 36:32import again from langchain. This is now
  1003. 36:34the modern way of doing things from
  1004. 36:36langchain.agents agents import create
  1005. 36:39agent and now I can just say as we did
  1006. 36:43before agent is equal to create agent
  1007. 36:45the model is going to be GPT4.1 mini
  1008. 36:47again then we can say tools is equal to
  1009. 36:50retriever tool then I'm going to copy
  1010. 36:52paste the system prompt nothing too
  1011. 36:54fancy here just explaining again your
  1012. 36:56helpful assistant and if there's any
  1013. 36:58questions about Macs apples laptops
  1014. 37:00whatever use the tool that you have
  1015. 37:02first the retriever tool basically
  1016. 37:04retrieve the context answer in a concise
  1017. 37:06way and the hint that maybe you have to
  1018. 37:08use this tool multiple times because if
  1019. 37:11I'm asking a question that needs to
  1020. 37:12combine information, you might have to
  1021. 37:14do it multiple times, which the agent
  1022. 37:16can do since it's not just a prompt.
  1023. 37:18It's an agent that can use tools, then
  1024. 37:20think, then use tools again, and so on.
  1025. 37:22So then we do what we already did
  1026. 37:24before. We pass a prompt. I'm just going
  1027. 37:26to say here, agent invoke, what three
  1028. 37:29fruits does the person like and what
  1029. 37:31three fruits does the person dislike?
  1030. 37:33And then we get the answer. So, I'm
  1031. 37:34asking two things in a single prompt.
  1032. 37:37And up here, we use two different
  1033. 37:39similarity searches for that. Let's see
  1034. 37:41if the agent can handle that. I'm going
  1035. 37:42to run this. And it says here, the
  1036. 37:44person likes oranges, apples, and pears.
  1037. 37:46The person dislikes mangoes,
  1038. 37:48raspberries, and bananas. You can see
  1039. 37:49also the retrieval um or actually cannot
  1040. 37:52see it up here. You can see the
  1041. 37:54retrieval that was done one. And then a
  1042. 37:58second call to the tool was done down
  1043. 38:00here. And this gave us the information
  1044. 38:02for this final response. Now we get to a
  1045. 38:05very powerful concept in lang chain. The
  1046. 38:06middleware. Middleware basically meaning
  1047. 38:08it sits between request and response.
  1048. 38:11And middleware allows us to do a lot of
  1049. 38:13different things to enhance the
  1050. 38:14capabilities of our agents. For example,
  1051. 38:16we can choose different system prompts
  1052. 38:18depending on the context. We can choose
  1053. 38:20different models based on certain
  1054. 38:21criteria. We can summarize stuff. We can
  1055. 38:24have rate limits. All sorts of things
  1056. 38:26can be done in between this window of
  1057. 38:28getting a request and sending a
  1058. 38:30response. We can do a lot of stuff
  1059. 38:31behind the scenes. And instead of
  1060. 38:32talking about this too long in a
  1061. 38:34theoretical way, what I want to do here
  1062. 38:35is I just want to show you a couple of
  1063. 38:36examples of custom middleware of already
  1064. 38:39existing middleware of different use
  1065. 38:41cases and then you can just go and
  1066. 38:43explore it yourself. So I want to get
  1067. 38:44started with a simple example right
  1068. 38:46away. I want to show you how we can swap
  1069. 38:47the system prompt based on the level of
  1070. 38:49expertise that the user has. So for this
  1071. 38:51we're going to use context again and I'm
  1072. 38:53going to start by importing from
  1073. 38:55langchain.agents.m
  1074. 38:57middleware the following things. model
  1075. 39:00request, model response and in this case
  1076. 39:04now the decorator called dynamic prompt.
  1077. 39:06So this is middleware that is already
  1078. 39:08implemented. So we don't have to build
  1079. 39:10it and define it ourselves. But what we
  1080. 39:13can do now is we can say that if the
  1081. 39:16user has a certain role like he's an
  1082. 39:18expert or he's a beginner or maybe even
  1083. 39:20he's a child, we're going to say adjust
  1084. 39:23your answer, adjust your style based on
  1085. 39:25that. So we're going to create a data
  1086. 39:26class again called context. And actually
  1087. 39:29we need to again import here from data
  1088. 39:32classes import data class. And this
  1089. 39:35context this time will not contain the
  1090. 39:36ID but the user role. So I'm going to
  1091. 39:38say here data class user ro is going to
  1092. 39:42be a string. And now we're going to
  1093. 39:43write a function that takes in the
  1094. 39:45context from the model request and
  1095. 39:46returns a system prompt dynamically
  1096. 39:49based on the user role. So I'm going to
  1097. 39:50use here the decorator dynamic prompt.
  1098. 39:53And we're going to call this function
  1099. 39:54user ro prompt. For example, it will get
  1100. 39:57a request as input which is a model
  1101. 40:00request and then we return the string.
  1102. 40:04So that is the structure and now we can
  1103. 40:06take the context from the request. So I
  1104. 40:08can say here the user role is going to
  1105. 40:10be request runtime context do user role
  1106. 40:16and we can do the same thing as before
  1107. 40:17with the user ID just a match case
  1108. 40:19statement. So match user role and then
  1109. 40:22we can have different cases. For
  1110. 40:24example, the user can be an expert. And
  1111. 40:26in this case, we will return a different
  1112. 40:28system prompt. Now, what I want to do
  1113. 40:29here is I want to define a base prompt.
  1114. 40:32So, we're going to have just a base
  1115. 40:33prompt. You are a helpful and very
  1116. 40:37concise assistant. And now, if it's an
  1117. 40:39expert, we're going to say here, give me
  1118. 40:42the base prompt. And then just add to
  1119. 40:44it, provide detail
  1120. 40:48technical responses. On the other hand,
  1121. 40:51if we have a beginner, we're going to
  1122. 40:53say keep your explanations
  1123. 40:57simple and basic. And finally, to see
  1124. 41:00the biggest difference, we're going to
  1125. 41:01say case child. And it's going to
  1126. 41:03basically be explain everything
  1127. 41:07as if you were literally
  1128. 41:11talking to a 5year-old. And then the
  1129. 41:14default case would just be okay. If it's
  1130. 41:16none of that, then we're just going to
  1131. 41:18return the base prompt. Cool. So now
  1132. 41:20basically we do the same thing as
  1133. 41:21before, but this time we don't pass it
  1134. 41:23as context. We don't pass it as a tool.
  1135. 41:25We pass it as middleware. So I say here
  1136. 41:27create agent. The model is going to be
  1137. 41:29the same as before. GBT4.1
  1138. 41:32mini. And now I'm going to say here
  1139. 41:33middleware is equal to and that's going
  1140. 41:36to be a list and it's going to contain
  1141. 41:38the user role prompt function. But of
  1142. 41:41course I still have to pass the context
  1143. 41:42otherwise it of course doesn't work. So
  1144. 41:45context schema still has to be this data
  1145. 41:48class. So then I can say response is
  1146. 41:50equal to agent.invoke.
  1147. 41:52I'm going to have to provide the
  1148. 41:53dictionary again here with messages role
  1149. 41:57is user and content is explain PCA. And
  1150. 42:01here now I pass the context. The context
  1151. 42:03is going to be that the user role let's
  1152. 42:06say in the beginning is going to be
  1153. 42:08beginner. So user role is equal to
  1154. 42:12beginner. Print response. And we can see
  1155. 42:14here content PCA principal component
  1156. 42:16analysis is the technique used to reduce
  1157. 42:18the number of variables in data while
  1158. 42:20keeping the most important information.
  1159. 42:21It transforms the original data into new
  1160. 42:23variables and so on. So quite simple but
  1161. 42:26still not something a 5-year-old would
  1162. 42:28understand. So let's go and see what the
  1163. 42:30export explanation would be. And there
  1164. 42:32we can see principal component analysis
  1165. 42:34is a dimensionality reduction technique
  1166. 42:36used to transform a large set of
  1167. 42:37correlated variables into a smaller set
  1168. 42:39of uncorrelated variables called
  1169. 42:41principal components. Yeah. Then we get
  1170. 42:43here projection and component selection.
  1171. 42:45Still not I mean I can decomposition.
  1172. 42:47Okay, it's a little bit more technical.
  1173. 42:49But if I go now to the lowest level here
  1174. 42:51which is the child then I should get
  1175. 42:53something really really simple. So here
  1176. 42:55okay imagine you have a big box of
  1177. 42:57crayons with lots of colors. Sometimes
  1178. 43:00you want to choose just a few crayons
  1179. 43:02that can still help you color many
  1180. 43:04pictures nicely. PCA is like a magic
  1181. 43:06helper. Yeah, you get the idea. So this
  1182. 43:08is something we can do with middleware
  1183. 43:10here. In between the request and
  1184. 43:11response, we can have this dynamic
  1185. 43:13prompt choice based on the user role,
  1186. 43:15based on the context. We can say uh that
  1187. 43:17we want to do different things. We want
  1188. 43:19to instruct the model to do different
  1189. 43:20things. Now, another thing that we can
  1190. 43:22do is we can not only select a prompt
  1191. 43:24dynamically, we can also select a model
  1192. 43:26dynamically. For this here, I'm also
  1193. 43:27going to import from langchain.hat
  1194. 43:30models our trusted init chat model
  1195. 43:33function. I'm going to get rid of
  1196. 43:34dynamic prompt and I'm going to import
  1197. 43:38wrap model call. This basically means it
  1198. 43:40happens around the model call whenever
  1199. 43:42we want to call the model that is part
  1200. 43:45of the agent. We're going to run our
  1201. 43:47middleware in that moment or I should
  1202. 43:49say in between the model request and the
  1203. 43:51model response. So the idea here would
  1204. 43:53be I want to have a basic model that
  1205. 43:55would be in it chat model and then I can
  1206. 43:57say for example model is equal to GPT4
  1207. 44:01mini and then I would also have an
  1208. 44:02advanced model which could be 4.1 mini.
  1209. 44:05The idea now is I define a function
  1210. 44:07called dynamic model selection. This
  1211. 44:10function takes in a request returns a
  1212. 44:12response. So I take in a model request
  1213. 44:16and the output of that function is a
  1214. 44:18model response. In addition to that we
  1215. 44:20also get a handler as parameter here and
  1216. 44:24I have to annotate this now with wrap
  1217. 44:26model call. So this actually happens
  1218. 44:29when the model is called. In case you're
  1219. 44:31interested in that, you can also go to
  1220. 44:32the langchain documentation. And there
  1221. 44:33you can see how this basically works.
  1222. 44:35Request comes in. Then we have before
  1223. 44:37agent, before model, wrap tool call,
  1224. 44:39wrap model call, after model, after
  1225. 44:42agent, result. And we're now doing this
  1226. 44:44here, wrapping the model call with our
  1227. 44:46middleware. So what kind of logic you
  1228. 44:48want to apply here is up to you. In my
  1229. 44:49case, I'm going to keep it simple. If I
  1230. 44:51have more than three messages, I'm going
  1231. 44:52to use the stronger model. Otherwise,
  1232. 44:54I'm going to use the basic model. Not
  1233. 44:56the most intelligent choice here, but
  1234. 44:57we're going to do it like this. So
  1235. 44:59message count is going to be equal to
  1236. 45:02length of request state and then
  1237. 45:05messages and then just if the message
  1238. 45:08count is greater than three the model is
  1239. 45:12going to be equal to basic model
  1240. 45:14otherwise we're going to say it's going
  1241. 45:17to be the advanced model and then we say
  1242. 45:19request domodel is equal to model and we
  1243. 45:22return a handler for that request. So
  1244. 45:26basically we're just taking the request
  1245. 45:27and setting the model to something else
  1246. 45:29depending on some criteria. This could
  1247. 45:31be something more intelligent and then
  1248. 45:33we just handle the request with this
  1249. 45:36change. So that's super easy to
  1250. 45:37integrate. Again agent is going to be
  1251. 45:39equal to create agent. Model is going to
  1252. 45:42be basic model by default. And then the
  1253. 45:44middleware is going to be our dynamic
  1254. 45:46model selection. Now to keep things a
  1255. 45:48little bit more beautiful here, I'm
  1256. 45:50going to import again from langchain
  1257. 45:53messages the system message, the human
  1258. 45:56message, and the AI message. And then
  1259. 45:58down here, I'm going to say response is
  1260. 46:00equal to agent invoke. I'm going to
  1261. 46:02invoke here on the following dictionary.
  1262. 46:05Messages is going to point to a list of
  1263. 46:08messages. I'm going to start with a
  1264. 46:10system message. You are a helpful
  1265. 46:12assistant. Human message. What is
  1266. 46:15oneplus 1? Keeping it very basic here
  1267. 46:18and essentially we can take a look at
  1268. 46:20two things. Uh on the one hand you can
  1269. 46:22get the idea if you look at the quality
  1270. 46:24of the output. I mean oneplus 1 is
  1271. 46:26something that every model should be
  1272. 46:27able to do. But you can say here again
  1273. 46:29print response messages
  1274. 46:32-1.content
  1275. 46:34to just get the answer but then you can
  1276. 46:37also take a look at the actual model
  1277. 46:39that was used to produce this response.
  1278. 46:40So instead of saying content you can say
  1279. 46:42response metadata and you can target the
  1280. 46:45field called model name. And if we run
  1281. 46:47this now we can see that we use the
  1282. 46:51wrong model. Why is that? Because we're
  1283. 46:54we have to swap this. Of course if we
  1284. 46:56have more messages we're using the
  1285. 46:57advanced model otherwise the basic
  1286. 46:59model. But in theory it works. So if I
  1287. 47:02run this now I should see that we're
  1288. 47:03using 40 mini. And if I add more
  1289. 47:06messages. So, for example, let's just
  1290. 47:08add the same message a couple of times
  1291. 47:10here. This is going to trigger the
  1292. 47:12change and now we're using 4.1 mini.
  1293. 47:14Now, in general, I want to show you how
  1294. 47:15you can define your own custom
  1295. 47:17middleware by using these hooks. So,
  1296. 47:18we're going to do that with a class
  1297. 47:20here. For this, I'm going to create a
  1298. 47:21class called hooks. Let's call it hooks
  1299. 47:24demo. It's going to inherit from a class
  1300. 47:26that we need to import called agent
  1301. 47:28middleware. So, we're now defining our
  1302. 47:30own agent middleware as a class here.
  1303. 47:33And we can just override these methods
  1304. 47:35that are representing the hooks. So in
  1305. 47:37order to do that, let me get rid of all
  1306. 47:39of this. We're also going to need
  1307. 47:40something called the agent state. And
  1308. 47:42basically the constructor is going to be
  1309. 47:44the init method taking self as a
  1310. 47:47parameter here calling the constructor
  1311. 47:50of the parent class. So super init. And
  1312. 47:52what we're going to do is we're going to
  1313. 47:54set a start time equal to 0.0. So this
  1314. 47:56is not going to be an actually useful
  1315. 47:58example. I'm just going to show you how
  1316. 47:59we can trigger when the different parts
  1317. 48:01are triggered. And now we can just
  1318. 48:02overwrite before agent. For example,
  1319. 48:05before agent is obviously before we get
  1320. 48:07to the agent, before the request comes
  1321. 48:09to the agent, we're going to be running
  1322. 48:11this. It takes self and an agent state.
  1323. 48:14So state, which is agent state, and also
  1324. 48:16the runtime. And in my case, what I want
  1325. 48:18to do here now is I want to say self dot
  1326. 48:21start time is going to be equal to and
  1327. 48:23now I need to import from core python
  1328. 48:25here time. I'm just going to say time.
  1329. 48:27So we're importing core python package
  1330. 48:29time. self.start time is equal to time.
  1331. 48:32And then just so we know it happened.
  1332. 48:34I'm going to say here before agent
  1333. 48:36triggered. Now I'm going to copy paste
  1334. 48:38it here. For the other ones, it's just
  1335. 48:40before model, after model, and after
  1336. 48:42agent. Here we're going to do something
  1337. 48:43else. So I didn't copy it. But basically
  1338. 48:46here we're just printing before model,
  1339. 48:47after model. Whatever you want to do
  1340. 48:49with that. It's basically also you have
  1341. 48:51wrap and so wrap tool call, wrap model
  1342. 48:53call. We saw that already. We're just
  1343. 48:55going to keep doing it with these four.
  1344. 48:57And what I'm going to do here is I'm now
  1345. 48:59going to calculate the time difference.
  1346. 49:01And I'm going to print the result. So
  1347. 49:02I'm going to say here print
  1348. 49:05after agent and then colon time. So the
  1349. 49:09current time minus self start time. And
  1350. 49:12now we can go and say agent is equal to
  1351. 49:14create agent GPT4.1 mini. And then we
  1352. 49:19can say middleware is equal to and now
  1353. 49:21we're going to pass hooks demo as an
  1354. 49:24instance here. So we're creating
  1355. 49:25instance of this class. This is another
  1356. 49:27way to use middleware. And then I can
  1357. 49:29just do the usual stuff from before just
  1358. 49:31agent invoke some question. And now when
  1359. 49:34I run this we get a problem of course
  1360. 49:36because I cannot just call the module
  1361. 49:38time. Of course I need to say time or
  1362. 49:40time perf counter whatever you want to
  1363. 49:42use here but that shouldn't be too much
  1364. 49:44of an issue. So now we get before agent
  1365. 49:46triggered before model. I forgot to add
  1366. 49:50trigger here. But then we should get at
  1367. 49:52some point after model and then we
  1368. 49:53should get after agent and the
  1369. 49:55difference here in time. And since PCA
  1370. 49:57is probably quite complicated uh for a
  1371. 49:59model to put into words. It takes some
  1372. 50:02time but you can see 14 seconds is what
  1373. 50:04we measured here. This is essentially
  1374. 50:05what you can do with these hooks in um
  1375. 50:08lang chain when it comes to middleware.
  1376. 50:10You can customize what happens at what
  1377. 50:12point in the workflow in the cycle. So
  1378. 50:14now, last but not least, I would just
  1379. 50:15like to show you a couple of examples of
  1380. 50:17already existing middleware. We're not
  1381. 50:19going to go too deep into this. I'm
  1382. 50:20going to just copy paste one of these
  1383. 50:22examples here into this uh file, which
  1384. 50:26is going to be summarizing conversation.
  1385. 50:28We're not going to actually use this.
  1386. 50:29I'm just showing you how to use this.
  1387. 50:31Basically, you go from langchain agents
  1388. 50:33middleware summarization middleware. One
  1389. 50:36of the many choices that you have. What
  1390. 50:38this basically does is you have a couple
  1391. 50:39of parameters here. You can specify the
  1392. 50:42model for the summarization, which is
  1393. 50:44not necessarily the same as the model
  1394. 50:45that the agent uses. The idea is that
  1395. 50:48after a certain number of tokens, you
  1396. 50:51summarize the conversation. You keep the
  1397. 50:53last 20 messages after 4,000 tokens and
  1398. 50:57GPT40 mini in this case summarizes the
  1399. 51:00important key points of the conversation
  1400. 51:02up until this point. And then you just
  1401. 51:03continue the conversation. That is one
  1402. 51:05middleware that we can use. And then on
  1403. 51:07the middleware page in the
  1404. 51:08documentation, you can also find some
  1405. 51:10examples. For example, here human in the
  1406. 51:12loop middleware. This basically means on
  1407. 51:14certain events on certain tool users, we
  1408. 51:17get an interrupt and then the user has
  1409. 51:19to manually say okay continue, edit,
  1410. 51:21approve, reject, whatever. This is of
  1411. 51:23course important in key steps. If you
  1412. 51:25have to do some payment, if you have to
  1413. 51:26send an email or something, it makes
  1414. 51:28sense to have this human in the loop
  1415. 51:29middleware. Then we also have model call
  1416. 51:31limit. So basically saying we cannot
  1417. 51:34call the model too often per run or per
  1418. 51:36threat. Same thing exists for tool
  1419. 51:38calls. Basically just a limiter for how
  1420. 51:40often you can call a tool in a run or in
  1421. 51:42a limit. Same thing also exists for tool
  1422. 51:45calls. Basically how often can you call
  1423. 51:47a tool in a specific thread or run. Then
  1424. 51:49also some interesting stuff here like
  1425. 51:51model fallback. If something doesn't
  1426. 51:52work, if you cannot use a model, fall
  1427. 51:54back to a different one. This can be
  1428. 51:56quite useful here. Also PII detection.
  1429. 51:58Basically personally identifiable
  1430. 52:00information. You can make it redact
  1431. 52:02certain key pieces of information for
  1432. 52:05compliance reasons for example and much
  1433. 52:07more other stuff like retrying tools or
  1434. 52:10having a to-do list. So basically a
  1435. 52:12planning middleware. You can take a look
  1436. 52:14at these examples but basically
  1437. 52:15middleware allows you to extend the
  1438. 52:18capabilities of your model or of your
  1439. 52:19agent I should say because you can tell
  1440. 52:21it what to do in certain scenarios make
  1441. 52:23it more dynamic make it more reactive so
  1442. 52:26to say which is very useful. So that's
  1443. 52:28it for this video today. I hope you
  1444. 52:30enjoyed it and hope you learned
  1445. 52:31something. If so, let me know by hitting
  1446. 52:32a like button and leaving a comment in
  1447. 52:34the comment section down below. Also, if
  1448. 52:36you're interested on my website, you
  1449. 52:37will find a tutoring tab and also a
  1450. 52:39services tab. There you can hire me
  1451. 52:41basically for one-on-one tutoring, for
  1452. 52:43one-on-one teaching you something or
  1453. 52:45also for services, machine learning,
  1454. 52:47backend development, consulting,
  1455. 52:49freelancing, whatever. If you're
  1456. 52:50interested in that, check it out. You
  1457. 52:52can contact me via mail or LinkedIn. And
  1458. 52:54besides that, don't forget to subscribe
  1459. 52:56to this channel and hit the notification
  1460. 52:57bell to not miss a single future video
  1461. 52:59for free. Other than that, thank you
  1462. 53:00much for watching. See you in the next
  1463. 53:02video and bye.

About this transcript

This page contains the full transcript of LangChain Full Crash Course - AI Agents in Python by NeuralNine, generated from the public captions YouTube serves with the video. The transcript has 10,535 words across 1,463 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.

What you can do with it

Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to choose a caption track available on the video.

Free YouTube transcript tool

YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, caption language selection, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.