{"id":2720,"date":"2025-03-29T07:02:21","date_gmt":"2025-03-29T07:02:21","guid":{"rendered":"https:\/\/mailitics.com\/index.php\/2025\/03\/29\/ai-agents-from-zero-to-hero-part-3\/"},"modified":"2025-03-29T07:02:21","modified_gmt":"2025-03-29T07:02:21","slug":"ai-agents-from-zero-to-hero-part-3","status":"publish","type":"post","link":"https:\/\/mailitics.com\/index.php\/2025\/03\/29\/ai-agents-from-zero-to-hero-part-3\/","title":{"rendered":"AI Agents from Zero to Hero \u2014 Part 3"},"content":{"rendered":"<p>    AI Agents from Zero to Hero \u2014 Part 3<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n    <!-- no image --><br \/>\n \t<BR><br \/>\n<BR><\/BR><\/p>\n<div>\n<h2 class=\"wp-block-heading\"><strong><mdspan datatext=\"el1743121445633\" class=\"mdspan-comment\">Intro<\/mdspan><\/strong><\/h2>\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-1\/\">Part 1<\/a> of this tutorial series, we introduced <strong>AI Agents<\/strong>, autonomous programs that perform tasks, make decisions, and communicate with others.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-2\/\" data-type=\"link\" data-id=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-2\/\">Part 2<\/a> of this tutorial series, we understood how to make the Agent try and retry until the task is completed through <strong>Iterations and Chains<\/strong>.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">A single Agent can usually operate effectively using a tool, but it can be less effective when using many tools simultaneously. One way to tackle complicated tasks is through a \u201cdivide-and-conquer\u201d approach: create a specialized Agent for each task and have them work together as a <strong>Multi-Agent System (MAS)<\/strong>.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">In a MAS, multiple agents collaborate to achieve common goals, often tackling challenges that are too difficult for a single Agent to handle alone. There are two main ways they can interact:\u00a0<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Sequential flow \u2013<\/strong> The Agents do their work in a specific order, one after the other. For example, Agent 1 finishes its task, and then Agent 2 uses the result to do its task. This is useful when tasks depend on each other and must be done step-by-step.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Hierarchical flow<\/strong> <strong>\u2013<\/strong> Usually, one higher-level Agent manages the whole process and gives instructions to lower level Agents which focus on specific tasks. This is useful when the final output requires some back-and-forth.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">In this tutorial, I\u2019m going to show how to <strong>build from scratch different types of Multi-Agent Systems<\/strong>, from simple to more advanced. I will present some useful Python code that can be easily applied in other similar cases (just copy, paste, run) and walk through every line of code with comments so that you can replicate this example (link to full code at the end of the article).<\/p>\n<h2 class=\"wp-block-heading\"><strong>Setup<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Please refer to <a href=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-1\/\">Part 1<\/a> for the setup of <a href=\"https:\/\/ollama.com\/\"><strong><em>Ollama<\/em><\/strong><\/a> and the main LLM.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import ollama\nllm = \"qwen2.5\"\u00a0<\/code><\/pre>\n<p class=\"wp-block-paragraph\">In this example, I will ask the model to process images, therefore I\u2019m also going to need a <strong>Vision LLM<\/strong>. It is a specialized version of a Large Language Model that, integrating NLP with CV, is designed to understand visual inputs, such as images and videos, in addition to text.<\/p>\n<p class=\"wp-block-paragraph\">Microsoft\u2019s <a href=\"https:\/\/github.com\/haotian-liu\/LLaVA\"><em>LLaVa<\/em><\/a> is an efficient choice as it can also run without a GPU.<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXes7Rt84FhxB9xOWjY3xwdieX4lBZQKIxq6otDFZzNA8fz7WDiZpRxuQZIdVMhvlH55B82ru8hmCbYKSI1jlpQO76NDCWT_7oBk17Qe7GgJwu1HzsZDhxsQpcp8GfxQwkPopOgpOw?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">After the download is completed, you can move on to Python and start writing code. Let\u2019s load an image so that we can try out the Vision LLM.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from matplotlib import image as pltimg, pyplot as plt\n\nimage_file = \"draghi.jpeg\"\n\nplt.imshow(pltimg.imread(image_file))\nplt.show()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">In order to test the Vision LLM, you can just pass the image as an input:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import ollama\n\nollama.generate(model=\"llava\",\n prompt=\"describe the image\",\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\n images=[image_file])[\"response\"]<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfRdfizjUj9SKOv67_SEEymnsjNoxXYltgyO6OkL1Z0h1wctbY23msJsh2rCzrlcOCLo-aVQKmYQMZyZGixf3GsW7jbFiaOIB5Qenan5kCmSroQAGnUFj0dusVTthbFzymnQgI7ug?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<h2 class=\"wp-block-heading\">\n<strong><strong>Sequential<\/strong><\/strong> <strong>Multi-Agent System<\/strong><br \/>\n<\/h2>\n<p class=\"wp-block-paragraph\">I shall build two Agents that will work in a <strong>sequential flow<\/strong>, one after the other, where the second takes the output of the first as an input, just like a Chain.<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXd8dpciEWSoK8UqWcqbI6S1fIdnv-UXSbWhgBVZ86vprrzEdsI38cn5vV00i7WwzGcDgZXJmwNPc5VK9F5l3X8qbjVgAuijh38EWNuwOjJLerl-HwuAQLd15qHai7uIBrAwF7zO-w?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>The first Agent <\/strong>must process an image provided by the user and return a verbal description of what it sees.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>The second Agent<\/strong> will search the internet and try to understand where and when the picture was taken, based on the description provided by the first Agent.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Both Agents shall use one <strong>Tool <\/strong>each. The first Agent will have the Vision LLM as a Tool. Please remember that with <em>Ollama<\/em>, in order to use a Tool, the function must be described in a dictionary.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def process_image(path: str) -&gt; str:\n\u00a0 \u00a0 return ollama.generate(model=\"llava\", prompt=\"describe the image\", images=[path])[\"response\"]\n\ntool_process_image = {'type':'function', 'function':{\n\u00a0 'name': 'process_image',\n\u00a0 'description': 'Load an image for a given path and describe what you see',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['path'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'path': {'type':'str', 'description':'the path of the image'},\n}}}}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The second Agent should have a web-searching Tool. In the previous articles of this tutorial series, I showed how to leverage the <em>DuckDuckGo<\/em> package for searching the web. So, this time, we can use a new Tool: <a href=\"https:\/\/pypi.org\/project\/wikipedia\/\"><em>Wikipedia<\/em><\/a> (<code>pip install wikipedia==1.4.0<\/code>). You can directly use the original library or import the <em>LangChain<\/em> wrapper.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from langchain_community.tools import WikipediaQueryRun\nfrom langchain_community.utilities import WikipediaAPIWrapper\n\ndef search_wikipedia(query:str) -&gt; str:\n\u00a0 \u00a0 return WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()).run(query)\n\ntool_search_wikipedia = {'type':'function', 'function':{\n\u00a0 'name': 'search_wikipedia',\n\u00a0 'description': 'Search on Wikipedia by passing some keywords',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['query'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'query': {'type':'str', 'description':'The input must be short keywords, not a long text'},\n}}}}\n## test\nsearch_wikipedia(query=\"draghi\")<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXczaDz_rFIwhtJDIX2NBpdZdYtMidtha_sK4RqzEhEB3jXbwmQJMH686i8P6E-AOo0tR_2_rSAKerni4vVtQbKVTv6A4Pk2t_dbvJzhBPr2cXtqJrXtsbb29nPkWKvb-CPBKQ1rSQ?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">First, you need to write a prompt to describe the task of each Agent (the more detailed, the better), and that will be the first message in the chat history with the LLM.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">prompt = '''\nYou are a photographer that analyzes and describes images in details.\n'''\nmessages_1 = [{\"role\":\"system\", \"content\":prompt}]<\/code><\/pre>\n<p class=\"wp-block-paragraph\">One important decision to make when building a MAS is whether the Agents should share the chat history or not. The <strong>management of chat history<\/strong> depends on the design and objectives of the system:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Shared chat history \u2013 <\/strong>Agents have access to a common conversation log, allowing them to see what other Agents have said or done in previous interactions. This can enhance the collaboration and the understanding of the overall context.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Separate chat history \u2013<\/strong> Agents only have access to their own interactions, focusing only on their own communication. This design is typically used when independent decision-making is important.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">I recommend keeping the chats separate unless it is necessary to do otherwise. LLMs might have a limited context window, so it\u2019s better to make the history as lite as possible.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">prompt = '''\nYou are a detective. You read the image description provided by the photographer, and you search Wikipedia to understand when and where the picture was taken.\n'''\n\nmessages_2 = [{\"role\":\"system\", \"content\":prompt}]<\/code><\/pre>\n<p class=\"wp-block-paragraph\">For convenience, I shall use the function defined in the previous articles to process the model\u2019s response.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def use_tool(agent_res:dict, dic_tools:dict) -&gt; dict:\n\u00a0 \u00a0 ## use tool\n\u00a0 \u00a0 if \"tool_calls\" in agent_res[\"message\"].keys():\n\u00a0 \u00a0 \u00a0 \u00a0 for tool in agent_res[\"message\"][\"tool_calls\"]:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 t_name, t_inputs = tool[\"function\"][\"name\"], tool[\"function\"][\"arguments\"]\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if f := dic_tools.get(t_name):\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ### calling tool\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print('<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f527.png?ssl=1\" alt=\"\ud83d\udd27\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;', f\"x1b[1;31m{t_name} -&gt; Inputs: {t_inputs}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ### tool output\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 t_output = f(**tool[\"function\"][\"arguments\"])\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(t_output)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ### final res\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 res = t_output\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 else:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print('<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f92c.png?ssl=1\" alt=\"\ud83e\udd2c\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;', f\"x1b[1;31m{t_name} -&gt; NotFoundx1b[0m\")\n\u00a0 \u00a0 ## don't use tool\n\u00a0 \u00a0 if agent_res['message']['content'] != '':\n\u00a0 \u00a0 \u00a0 \u00a0 res = agent_res[\"message\"][\"content\"]\n\u00a0 \u00a0 \u00a0 \u00a0 t_name, t_inputs = '', ''\n\u00a0 \u00a0 return {'res':res, 'tool_used':t_name, 'inputs_used':t_inputs}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">As we already did in previous tutorials, the interaction with the Agents can be started with a <em>while loop<\/em>. The user is requested to provide an image that the first Agent will process.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">dic_tools = {'process_image':process_image, \n 'search_wikipedia':search_wikipedia}\n\nwhile True:\n\u00a0 \u00a0 ## user input\n\u00a0 \u00a0 try:\n\u00a0 \u00a0 \u00a0 \u00a0 q = input('<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f4f7.png?ssl=1\" alt=\"\ud83d\udcf7\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt; give me the image to analyze:')\n\u00a0 \u00a0 except EOFError:\n\u00a0 \u00a0 \u00a0 \u00a0 break\n\u00a0 \u00a0 if q == \"quit\":\n\u00a0 \u00a0 \u00a0 \u00a0 break\n\u00a0 \u00a0 if q.strip() == \"\":\n\u00a0 \u00a0 \u00a0 \u00a0 continue\n\u00a0 \u00a0 messages_1.append( {\"role\":\"user\", \"content\":q} )\n\n\u00a0 \u00a0 plt.imshow(pltimg.imread(q))\n\u00a0 \u00a0 plt.show()\n\n\u00a0\u00a0\u00a0\u00a0## Agent 1\n\u00a0 \u00a0 agent_res = ollama.chat(model=llm,\n tools=[tool_process_image],\n messages=messages_1)\n\u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\u00a0\u00a0\u00a0\u00a0\n res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\n\n\u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f47d.png?ssl=1\" alt=\"\ud83d\udc7d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f4f7.png?ssl=1\" alt=\"\ud83d\udcf7\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;30m{res}x1b[0m\")\n\u00a0 \u00a0 messages_1.append( {\"role\":\"assistant\", \"content\":res} )<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"228\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/image-190-1024x228.png?resize=1024%2C228&#038;ssl=1\" alt=\"\" class=\"wp-image-600705\"><\/figure>\n<p class=\"wp-block-paragraph\">The first Agent used the Vision LLM Tool and recognized text within the image. Now, the description will be passed to the second Agent, which shall extract some keywords to search <em>Wikipedia<\/em>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 ## Agent 2\n\u00a0 \u00a0 messages_2.append( {\"role\":\"system\", \"content\":\"-Picture: \"+res} )\n\n\u00a0 \u00a0 agent_res = ollama.chat(model=llm,\n tools=[tool_search_wikipedia],\n messages=messages_2)\n\u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\u00a0\u00a0\u00a0\u00a0\n res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\u00a0\u00a0\u00a0<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdp2w5v0xwpafXsSQKSIKIYy02GqT7ks5wwGkId6F98OvMcaSxXPxRSX8xM4TDFXqC6oTvhmOK1lH-E36Wr5TVAJ8RWluEOE6oWtQvACc7a6gI95x3giyYIqu9wToGH1eY1PXTT5w?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">The second Agent used the Tool and extracted information from the web, based on the description provided by the first Agent. Now, it can process everything and give a final answer.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 if tool_used == \"search_wikipedia\":\n\u00a0 \u00a0 \u00a0 \u00a0 messages_2.append( {\"role\":\"system\", \"content\":\"-Wikipedia: \"+res} )\n\u00a0 \u00a0 \u00a0 \u00a0 agent_res = ollama.chat(model=llm, tools=[],\u00a0messages=messages_2)\n\u00a0 \u00a0 \u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\n res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\u00a0\n\u00a0 \u00a0 else:\n\u00a0 \u00a0 \u00a0 \u00a0 messages_2.append( {\"role\":\"assistant\", \"content\":res} )\n\u00a0 \u00a0\n\u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f47d.png?ssl=1\" alt=\"\ud83d\udc7d\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f4d6.png?ssl=1\" alt=\"\ud83d\udcd6\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;30m{res}x1b[0m\")<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdFifoZkhsXg8Tmxm1i8FBbUgm0Vzwz0iIBVO44codsPioIfTb956bYfV7vuOpBuSY0YNt07HmabJ7Uf0JN3VYf8MPLZSxKZXS0xEGa3jiHOjK3Fq-F8JTXd7O8LcEfRB4Y9_bxEA?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">This is literally perfect! Let\u2019s move on to the next example.<\/p>\n<h2 class=\"wp-block-heading\"><strong><strong>Hierarchical<\/strong> Multi-Agent System<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Imagine having a squad of Agents that operates with a <strong>hierarchical flow, <\/strong>just like a human team, with distinct roles to ensure smooth collaboration and efficient problem-solving. At the top, a manager oversees the overall strategy, talking to the customer (the user), making high-level decisions, and guiding the team toward the goal. Meanwhile, other team members handle operative tasks. Just like humans, Agents can work together and delegate tasks appropriately.<\/p>\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXc7xIeRBZrafcEe4x7F0SlwgLtQMS2L--SVHg59Ep65FybieP6KSHHQZm977pBBzJrYKEK12nS_K22Q8hlLx20L7gLkfLkp5SG0wgXqtgqgcCVDG9AivnaZwE-WKJHCR3q7y7gQBQ?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\" style=\"width:395px;height:auto\"><\/figure>\n<p class=\"wp-block-paragraph\">I shall build a tech team of 3 Agents with the objective of querying a SQL database per user\u2019s request. They must work in a hierarchical flow:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>The Lead Agent<\/strong> talks to the user and understands the request. Then, it decides which team member is the most appropriate for the task.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>The Junior Agent<\/strong> has the job of exploring the db and building SQL queries.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>The Senior Agent<\/strong> shall review the SQL code, correct it if necessary, and execute it.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">LLMs know how to code by being exposed to a large corpus of both code and natural language text, where they learn patterns, syntax, and semantics of programming languages. The model learns the relationships between different parts of the code by predicting the next token in a sequence. In short, LLMs can generate SQL code but can\u2019t execute it, Agents can.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">First of all, I am going to create a database and connect to it, then I shall prepare a series of <strong>Tools to<\/strong> <strong>execute SQL code<\/strong>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">## Read dataset\nimport pandas as pd\n\ndtf = pd.read_csv('http:\/\/bit.ly\/kaggletrain')\ndtf.head(3)\n\n## Create dbimport sqlite3\ndtf.to_sql(index=False,\u00a0name=\"titanic\",\n con=sqlite3.connect(\"database.db\"),\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\n if_exists=\"replace\")\n\n## Connect db\nfrom langchain_community.utilities.sql_database import SQLDatabase\n\ndb = SQLDatabase.from_uri(\"sqlite:\/\/\/database.db\")<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcfnLgz2ke5ZENoyIbDYWdbgMApVFQWdnK6c0ZvD4HoIppViKjbQ7b5vRJkDBxfRQ-60EqwyySvWQ2kZZXBm2LmW7115CFn2mee3GCiNoUC7ze8UNCn6ao3AeE8Q0DZZpTtP1Aq?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">Let\u2019s start with the <strong>Junior Agent<\/strong>. LLMs don\u2019t need Tools to generate SQL code, but the Agent doesn\u2019t know the table names and structure. Therefore, we need to provide Tools to investigate the database.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from langchain_community.tools.sql_database.tool import ListSQLDatabaseTool\n\ndef get_tables() -&gt; str:\n\u00a0 \u00a0 return ListSQLDatabaseTool(db=db).invoke(\"\")\n\ntool_get_tables = {'type':'function', 'function':{\n\u00a0 'name': 'get_tables',\n\u00a0 'description': 'Returns the name of the tables in the database.',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': [],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {}\n}}}\n\n## test\nget_tables()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">That will show the available tables in the db, and this will print the columns in a table.\u00a0<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from langchain_community.tools.sql_database.tool import InfoSQLDatabaseTool\n\ndef get_schema(tables: str) -&gt; str:\n\u00a0 \u00a0 tool = InfoSQLDatabaseTool(db=db)\n\u00a0 \u00a0 return tool.invoke(tables)\n\ntool_get_schema = {'type':'function', 'function':{\n\u00a0 'name': 'get_schema',\n\u00a0 'description': 'Returns the name of the columns in the table.',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['tables'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {'tables': {'type':'str', 'description':'table name. Example Input: table1, table2, table3'}}\n}}}\n\n## test\nget_schema(tables='titanic')<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Since this Agent must use more than one Tool which might fail, I\u2019ll write a solid prompt, following the structure of the previous article.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">prompt_junior = '''\n[GOAL] You are a data engineer who builds efficient SQL queries to get data from the database.\n\n[RETURN] You must return a final SQL query based on user's instructions.\n\n[WARNINGS] Use your tools only once.\n\n[CONTEXT] In order to generate the perfect SQL query, you need to know the name of the table and the schema.\nFirst ALWAYS use the tool 'get_tables' to find the name of the table.\nThen, you MUST use the tool 'get_schema' to get the columns in the table.\nFinally, based on the information you got, generate an SQL query to answer user question.\n'''<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Moving to the <strong>Senior Agent<\/strong>. Code checking doesn\u2019t require any particular trick, you can just use the LLM.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def sql_check(sql: str) -&gt; str:\n\u00a0 \u00a0 p = f'''Double check if the SQL query is correct: {sql}. You MUST just SQL code without comments'''\n\u00a0 \u00a0 res = ollama.generate(model=llm, prompt=p)[\"response\"]\n\u00a0 \u00a0 return res.replace('sql','').replace('```','').replace('n',' ').strip()\n\ntool_sql_check = {'type':'function', 'function':{\n\u00a0 'name': 'sql_check',\n\u00a0 'description': 'Before executing a query, always review the SQL query and correct the code if necessary',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['sql'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {'sql': {'type':'str', 'description':'SQL code'}}\n}}}\n\n## test\nsql_check(sql='SELECT * FROM titanic TOP 3')<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeFY3MuPjbiadqndJEJuj7NO_j8R_lmAG9z27osPmUi0GLEIWXklUolmbiJDsb6dZVFkrupJHLz4v1iI2kN7mB0NXYJetbJkA1L8n095zo4IXoCqXFWovUFHHl62nzbCyLVdl7VzA?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">Executing code on the database is a different story: LLMs can\u2019t do that alone.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool\n\ndef sql_exec(sql: str) -&gt; str:\n\u00a0 \u00a0 return QuerySQLDataBaseTool(db=db).invoke(sql)\n\u00a0 \u00a0\ntool_sql_exec = {'type':'function', 'function':{\n\u00a0 'name': 'sql_exec',\n\u00a0 'description': 'Execute a SQL query',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['sql'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {'sql': {'type':'str', 'description':'SQL code'}}\n}}}\n\n## test\nsql_exec(sql='SELECT * FROM titanic LIMIT 3')<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXf0n3gevKHeVfm-1enRBfOPeK4-LGcQ-4n5-sfY0falbPCnp66hRvNCcO_zNW8lXe4ggG98jGI2FEbjVeIW2t5zhCQsZ46F2J7pq9kciPnHvslYt0uFvw1OcjYoV1oJkuASPWEw?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">And of course, a good prompt.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">prompt_senior = '''[GOAL] You are a senior data engineer who reviews and execute the SQL queries written by others.\n\n[RETURN] You must return data from the database.\n\n[WARNINGS] Use your tools only once.\n\n[CONTEXT] ALWAYS check the SQL code before executing on the database.First ALWAYS use the tool 'sql_check' to review the query. The output of this tool is the correct SQL query.You MUST use ONLY the correct SQL query when you use the tool 'sql_exec'.'''<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Finally, we shall create the <strong>Lead Agent<\/strong>. It has the most important job: invoking other Agents and telling them what to do. There are many ways to achieve that, but I find creating a simple Tool the most accurate one.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def invoke_agent(agent:str, instructions:str) -&gt; str:\n\u00a0 \u00a0 return agent+\" - \"+instructions if agent in ['junior','senior'] else f\"Agent '{agent}' Not Found\"\n\u00a0 \u00a0\ntool_invoke_agent = {'type':'function', 'function':{\n\u00a0 'name': 'invoke_agent',\n\u00a0 'description': 'Invoke another Agent to work for you.',\n\u00a0 'parameters': {'type': 'object',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'required': ['agent', 'instructions'],\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'properties': {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'agent': {'type':'str', 'description':'the Agent name, one of \"junior\" or \"senior\".'},\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'instructions': {'type':'str', 'description':'detailed instructions for the Agent.'}\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n}}}\n\n## test\ninvoke_agent(agent=\"intern\", instructions=\"build a query\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Describe in the prompt what kind of behavior you\u2019re expecting. Try to be as detailed as possible, for hierarchical Multi-Agent Systems can get very confusing.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">prompt_lead = '''\n[GOAL] You are a tech lead.\nYou have a team with one junior data engineer called 'junior', and one senior data engineer called 'senior'.\n\n[RETURN] You must return data from the database based on user's requests.\n\n[WARNINGS] You are the only one that talks to the user and gets the requests from the user.\nThe 'junior' data engineer only builds queries.\nThe 'senior' data engineer checks the queries and execute them.\n\n[CONTEXT] First ALWAYS ask the users what they want.\nThen, you MUST use the tool 'invoke_agent' to pass the instructions to the 'junior' for building the query.\nFinally, you MUST use the tool 'invoke_agent' to pass the instructions to the 'senior' for retrieving the data from the database.\n'''<\/code><\/pre>\n<p class=\"wp-block-paragraph\">I shall keep chat history separate so each Agent will know only a specific part of the whole process.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">dic_tools = {'get_tables':get_tables,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'get_schema':get_schema,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'sql_exec':sql_exec,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'sql_check':sql_check,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'Invoke_agent':invoke_agent}\n\nmessages_junior = [{\"role\":\"system\", \"content\":prompt_junior}]\nmessages_senior = [{\"role\":\"system\", \"content\":prompt_senior}]\nmessages_lead \u00a0 = [{\"role\":\"system\", \"content\":prompt_lead}]<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Everything is ready to <strong>start the workflow<\/strong>. After the user begins the chat, the first to respond is the Leader, which is the only one that directly interacts with the human.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">while True:\n\u00a0 \u00a0 ## user input\n\u00a0 \u00a0 q = input('<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f642.png?ssl=1\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;')\n\u00a0 \u00a0 if q == \"quit\":\n\u00a0 \u00a0 \u00a0 \u00a0 break\n\u00a0 \u00a0 messages_lead.append( {\"role\":\"user\", \"content\":q} )\n\u00a0 \u00a0\n\u00a0 \u00a0 ## Lead Agent\n\u00a0 \u00a0 agent_res = ollama.chat(model=llm, messages=messages_lead, tools=[tool_invoke_agent])\n\u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\n\u00a0 \u00a0 res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\n\u00a0 \u00a0 agent_invoked = res.split(\"-\")[0].strip() if len(res.split(\"-\")) &gt; 1 else ''\n\u00a0 \u00a0 instructions = res.split(\"-\")[1].strip() if len(res.split(\"-\")) &gt; 1 else ''\n\n\u00a0\u00a0\u00a0\u00a0###--&gt;CODE TO INVOKE OTHER AGENTS HERE&lt;--###\n\n\u00a0\u00a0\u00a0\u00a0## Lead Agent final response\u00a0\u00a0\u00a0\u00a0print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f469-200d-1f4bc.png?ssl=1\" alt=\"\ud83d\udc69\u200d\ud83d\udcbc\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;30m{res}x1b[0m\")\u00a0\u00a0\u00a0\u00a0messages_lead.append( {\"role\":\"assistant\", \"content\":res} )<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcOIcLWD8HZVHePC7_odfzLuPBfNIhMEJ7Y_YsQXdSMOvuy06z4dFc5498K522-D_K-nrFggQgjykGcDt8zuo2SLwRmhzAqjelEpuKGJwmdA7-AHQq3gU7lKTEQJLxVXnwMuO_ZQg?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">The Lead Agent decided to invoke the Junior Agent giving it some instruction, based on the interaction with the user. Now the Junior Agent shall start working on the query.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 ## Invoke Junior Agent\n\u00a0 \u00a0 if agent_invoked == \"junior\":\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f60e.png?ssl=1\" alt=\"\ud83d\ude0e\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;32mReceived instructions: {instructions}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_junior.append( {\"role\":\"user\", \"content\":instructions} )\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 ### use the tools\n\u00a0 \u00a0 \u00a0 \u00a0 available_tools = {\"get_tables\":tool_get_tables, \"get_schema\":tool_get_schema}\n\u00a0 \u00a0 \u00a0 \u00a0 context = ''\n\u00a0 \u00a0 \u00a0 \u00a0 while available_tools:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 agent_res = ollama.chat(model=llm, messages=messages_junior,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 tools=[v for v in available_tools.values()])\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if tool_used:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 available_tools.pop(tool_used)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 context = context + f\"nTool used: {tool_used}. Output: {res}\" #-&gt;add tool usage context\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 messages_junior.append( {\"role\":\"user\", \"content\":context} )\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 ### response\n\u00a0 \u00a0 \u00a0 \u00a0 agent_res = ollama.chat(model=llm, messages=messages_junior)\n\u00a0 \u00a0 \u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\n\u00a0 \u00a0 \u00a0 \u00a0 res = dic_res[\"res\"]\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f60e.png?ssl=1\" alt=\"\ud83d\ude0e\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;32m{res}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_junior.append( {\"role\":\"assistant\", \"content\":res} )<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcn-jJKkv4UOp6zjBlwbH_hgz2fs5ev55TSKzg4m3VwjEWFPA8u4NJi16E1o1w-VDE12INfqmQAqBh2CZmwalzTPQ_F2hWRZ4fuK_YC5SuNqesdx2SKsIttOEIL6gC9z0pDiXxbbQ?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">The Junior Agent activated all its Tools to explore the database and collected the necessary information to generate some SQL code. Now, it must report back to the Lead.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 \u00a0 \u00a0 ## update Lead Agent\n\u00a0 \u00a0 \u00a0 \u00a0 context = \"Junior already wrote this query: \"+res+ \"nNow invoke the Senior to review and execute the code.\"\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f469-200d-1f4bc.png?ssl=1\" alt=\"\ud83d\udc69\u200d\ud83d\udcbc\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;30m{context}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_lead.append( {\"role\":\"user\", \"content\":context} )\n\u00a0 \u00a0 \u00a0 \u00a0 agent_res = ollama.chat(model=llm, messages=messages_lead, tools=[tool_invoke_agent])\n\u00a0 \u00a0 \u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\n\u00a0 \u00a0 \u00a0 \u00a0 res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0agent_invoked = res.split(\"-\")[0].strip() if len(res.split(\"-\")) &gt; 1 else ''\n\u00a0 \u00a0 \u00a0 \u00a0 instructions = res.split(\"-\")[1].strip() if len(res.split(\"-\")) &gt; 1 else ''<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfBYJ72Ff2mzXkPQjIuLKW0NbHHRlzj7RJRlkLsrmKHHbuqkqQlZYHTc12vC4ZoG_guqej48Wqcs3avhb3Kjag1W2xeTBtk9MTwWgJcaXSYxaDjqoTWj3G2vRtJ6XaNo_7HxauKvQ?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">The Lead Agent received the output from the Junior and asked the Senior Agent to review and execute the SQL query.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 ## Invoke Senior Agent\n\u00a0 \u00a0 if agent_invoked == \"senior\":\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f9d3.png?ssl=1\" alt=\"\ud83e\uddd3\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;34mReceived instructions: {instructions}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_senior.append( {\"role\":\"user\", \"content\":instructions} )\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 ### use the tools\n\u00a0 \u00a0 \u00a0 \u00a0 available_tools = {\"sql_check\":tool_sql_check, \"sql_exec\":tool_sql_exec}\n\u00a0 \u00a0 \u00a0 \u00a0 context = ''\n\u00a0 \u00a0 \u00a0 \u00a0 while available_tools:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 agent_res = ollama.chat(model=llm, messages=messages_senior,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 tools=[v for v in available_tools.values()])\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 dic_res = use_tool(agent_res, dic_tools)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 res, tool_used, inputs_used = dic_res[\"res\"], dic_res[\"tool_used\"], dic_res[\"inputs_used\"]\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if tool_used:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 available_tools.pop(tool_used)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 context = context + f\"nTool used: {tool_used}. Output: {res}\" #-&gt;add tool usage context\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 messages_senior.append( {\"role\":\"user\", \"content\":context} )\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 ### response\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f9d3.png?ssl=1\" alt=\"\ud83e\uddd3\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;34m{res}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_senior.append( {\"role\":\"assistant\", \"content\":res} )<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcgltGUkY5FnQqdAlfAfWW7K3tjIq_rDmPnIRIDF4vHIA2bOmnelahyjypmEYCDosoQQ9s9IRnQH9-f6ESEP36LriBZWYETmZ1Wioyj3w8dtYBIocfUhC4xGRy2KTTu2u2mM3g2?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"wp-block-paragraph\">The Senior Agent executed the query on the db and got an answer. Finally, it can report back to the Lead which will give the final answer to the user.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">\u00a0 \u00a0 \u00a0 \u00a0 ### update Lead Agent\n\u00a0 \u00a0 \u00a0 \u00a0 context = \"Senior agent returned this output: \"+res\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f469-200d-1f4bc.png?ssl=1\" alt=\"\ud83d\udc69\u200d\ud83d\udcbc\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> &gt;\", f\"x1b[1;30m{context}x1b[0m\")\n\u00a0 \u00a0 \u00a0 \u00a0 messages_lead.append( {\"role\":\"user\", \"content\":context} )<\/code><\/pre>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXecAg5t5t5Q-WIHZuk3Si8IKKoO5nAgobruVyJdSWNluNTIDmbOmKa8glusVvm8hOcqYvoQbA-eRDT7B8vdOUjGwnhsENMUrzuw-3WhmW-GsGWp1wKl7xbKImxC3fU_VHFhYnn2Eg?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">This article has covered the basic steps of creating Multi-Agent Systems from scratch using only <em>Ollama<\/em>. With these building blocks in place, you are already equipped to start developing your own MAS for different use cases.\u00a0<\/p>\n<p class=\"wp-block-paragraph\"><strong>Stay tuned for Part 4<\/strong>, where we will dive deeper into more advanced examples.<\/p>\n<p class=\"wp-block-paragraph\">Full code for this article: <a href=\"https:\/\/github.com\/mdipietro09\/GenerativeAI\/blob\/main\/Agents_ZeroToHero\/notebook.ipynb\"><strong>GitHub<\/strong><\/a><\/p>\n<p class=\"wp-block-paragraph\">I hope you enjoyed it! Feel free to contact me for questions and feedback or just to share your interesting projects.<\/p>\n<p class=\"has-text-align-center wp-block-paragraph\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f449.png?ssl=1\" alt=\"\ud83d\udc49\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\">\u00a0<a href=\"https:\/\/maurodp.carrd.co\/\"><strong>Let\u2019s Connect<\/strong><\/a>\u00a0<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f448.png?ssl=1\" alt=\"\ud83d\udc48\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"><\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcXVH8mSyqGhKP8BS4vRj0KoYw2vFPykNq-6EWnUx3hecIzDoMwDaPsMBb-IWEfrMnlOVkQSNmzIk3Dow1nsWnWIVW-eEX-e64XcJ4LkGngTTslRHtyDqPzLwOKNcDVIQFRzZjg9w?key=iX8bdX_lFj0k8Pt-EKQOYPag\" alt=\"\"><\/figure>\n<p class=\"has-text-align-center has-eyebrow-2-font-size wp-block-paragraph\">All images, unless otherwise noted, are by the author<\/p>\n<p>The post <a href=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-3\/\">AI Agents from Zero to Hero \u2014 Part 3<\/a> appeared first on <a href=\"https:\/\/towardsdatascience.com\/\">Towards Data Science<\/a>.<\/p>\n<\/div>\n<p> \t<BR><br \/>\n <BR><\/BR><br \/>\n    Mauro Di Pietro<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n<a href=\"https:\/\/towardsdatascience.com\/ai-agents-from-zero-to-hero-part-3\/\">Go to original source<\/a><br \/>\n \t<BR><br \/>\n <BR><\/BR><\/p>\n","protected":false},"excerpt":{"rendered":"<p>AI Agents from Zero to Hero \u2014 Part 3 Intro In Part 1 of this tutorial series, we introduced AI Agents, autonomous programs that perform tasks, make decisions, and communicate with others.\u00a0 In Part 2 of this tutorial series, we understood how to make the Agent try and retry until the task is completed through [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[678,799,62,69,166,1647,471],"tags":[448,1140,1740],"class_list":["post-2720","post","type-post","status-publish","format-standard","hentry","category-agentic-ai","category-ai-agent","category-aimldsaimlds","category-artificial-intelligence","category-hands-on-tutorials","category-multi-agent-systems","category-vision-language-model","tag-agent","tag-agents","tag-part"],"_links":{"self":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2720"}],"collection":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/comments?post=2720"}],"version-history":[{"count":0,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2720\/revisions"}],"wp:attachment":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/media?parent=2720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/categories?post=2720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/tags?post=2720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}