{"id":287,"date":"2026-11-03T14:01:57","date_gmt":"2026-11-03T14:01:57","guid":{"rendered":"https:\/\/devdojo.co.in\/?p=287"},"modified":"2026-11-03T14:01:58","modified_gmt":"2026-11-03T14:01:58","slug":"agentic-ai-series-part-3-tool-calling","status":"publish","type":"post","link":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/","title":{"rendered":"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions"},"content":{"rendered":"\n<div class=\"dd-post\">\n<style>\n.single article:has(.dd-hero) .entry-media{display:none}\n.dd-post{--navy:#0b1020;--blue:#3178c6;--violet:#7c5cff;--ink:#1f2433;--muted:#5b6275;--line:#e3e6ef;font-size:17px;line-height:1.75;color:var(--ink)}\n.dd-post h2{margin:2.2em 0 .6em;font-size:1.6em;line-height:1.3;scroll-margin-top:90px}\n.dd-post h3{margin:1.6em 0 .5em;font-size:1.22em;scroll-margin-top:90px}\n.dd-post a{color:var(--blue);text-decoration:underline;text-underline-offset:3px}\n.dd-post pre{background:#0f1430;color:#e6e9f5;padding:18px 20px;border-radius:12px;overflow-x:auto;line-height:1.6;border:1px solid #232a52;margin:1.2em 0;font-size:14.5px !important}\n.dd-post pre code{font-size:1em !important;background:none;color:inherit;padding:0;font-family:\"JetBrains Mono\",\"Fira Code\",Consolas,Menlo,monospace;white-space:pre}\n.dd-post :not(pre)>code{background:#eef1fb;color:#2b3a8f;padding:2px 6px;border-radius:5px;font-size:.9em}\n.dd-post .dd-file{display:inline-block;background:#151b3b;color:#c9d1ff;font:600 13px\/1 \"JetBrains Mono\",Consolas,monospace;padding:7px 12px;border-radius:8px 8px 0 0;margin:1em 0 -1.2em;position:relative}\n.dd-post .dd-hero{margin:0 0 1.6em;border-radius:16px;overflow:hidden;box-shadow:0 10px 30px rgba(11,16,32,.25)}\n.dd-post .dd-hero svg{display:block;width:100%;height:auto}\n.dd-post .dd-hero .node{transition:transform .25s,filter .25s;transform-box:fill-box;transform-origin:center;cursor:pointer}\n.dd-post .dd-hero .node:hover{transform:scale(1.08);filter:drop-shadow(0 0 10px #7c5cff)}\n.dd-post .dd-series{display:inline-flex;align-items:center;gap:8px;background:#151b3b;color:#dfe3ff;border-radius:999px;padding:6px 14px;font-size:.88em;font-weight:600;margin:0 0 .8em}\n.dd-post .dd-series span{background:var(--violet);color:#fff;border-radius:999px;padding:2px 10px}\n.dd-post .dd-prereq{font-size:.96em;color:var(--muted);border-left:3px solid var(--line);padding-left:12px;margin:.6em 0 1.2em}\n.dd-post .dd-summary{background:linear-gradient(135deg,#eef3ff,#f4efff);border:1px solid #d6dcf5;border-left:5px solid var(--violet);border-radius:12px;padding:18px 22px;margin:1.4em 0}\n.dd-post .dd-summary strong.lbl{display:block;font-size:1.05em;margin-bottom:6px;color:#3a2fa0}\n.dd-post .dd-summary ul{margin:.3em 0 0 1.1em}\n.dd-post .dd-toc{background:#f8f9fc;border:1px solid var(--line);border-radius:12px;padding:16px 22px;margin:1.4em 0}\n.dd-post .dd-toc ol{margin:.4em 0 0 1.2em;columns:2;column-gap:28px}\n.dd-post .dd-toc li{break-inside:avoid;margin:.15em 0}\n@media(max-width:640px){.dd-post .dd-toc ol{columns:1}}\n.dd-post .dd-tip,.dd-post .dd-note,.dd-post .dd-warn{border-radius:10px;padding:14px 18px;margin:1.3em 0}\n.dd-post .dd-tip{background:#ecfbf3;border-left:4px solid #1f9d61}\n.dd-post .dd-note{background:#eef4ff;border-left:4px solid var(--blue)}\n.dd-post .dd-warn{background:#fff6e8;border-left:4px solid #e08a00}\n.dd-post .dd-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px;margin:1.3em 0}\n.dd-post .dd-card{border:1px solid var(--line);border-radius:12px;padding:14px 16px;background:#fff;box-shadow:0 2px 8px rgba(20,30,70,.05)}\n.dd-post .dd-card b{display:block;color:#3a2fa0;margin-bottom:4px}\n.dd-post table{width:100%;border-collapse:collapse;margin:1.3em 0;font-size:.95em}\n.dd-post th,.dd-post td{border:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:top}\n.dd-post th{background:#151b3b;color:#fff}\n.dd-post tr:nth-child(even) td{background:#f8f9fc}\n.dd-post .dd-tablewrap{overflow-x:auto}\n.dd-post figure{margin:1.6em 0;text-align:center}\n.dd-post figure svg{width:100%;height:auto;border-radius:12px}\n.dd-post figcaption{font-size:.9em;color:var(--muted);margin-top:8px}\n.dd-post details{border:1px solid var(--line);border-radius:10px;padding:12px 16px;margin:.7em 0;background:#fff}\n.dd-post details summary{cursor:pointer;font-weight:600}\n.dd-post details[open] summary{margin-bottom:8px;color:#3a2fa0}\n.dd-post .dd-roadmap{border:2px solid #d6dcf5;background:#fbfbff}\n.dd-post .dd-roadmap h4{margin:1em 0 .3em;color:#151b3b;font-size:1em;text-transform:uppercase;letter-spacing:.04em}\n.dd-post .dd-roadmap ol{margin:.2em 0 .6em 1.4em;padding:0}\n.dd-post .dd-roadmap li{margin:.2em 0}\n.dd-post .dd-roadmap .here{background:var(--violet);color:#fff;border-radius:999px;padding:1px 9px;font-size:.8em;font-weight:700;margin-left:6px}\n.dd-post .dd-roadmap .soon{color:#8a90a6;font-size:.82em;margin-left:6px}\n.dd-post .dd-tabs{border:1px solid var(--line);border-radius:12px;padding:6px 16px 16px;margin:1.4em 0;background:#fbfbfe}\n.dd-post .dd-tabs>input{position:absolute;opacity:0;pointer-events:none}\n.dd-post .dd-tabs .labels label{display:inline-block;padding:8px 16px;margin:10px 6px 0 0;border-radius:999px;border:1px solid #cfd5ea;cursor:pointer;font-weight:600;font-size:.95em;background:#fff;transition:background .2s}\n.dd-post .dd-tabs .labels label:hover{border-color:var(--violet)}\n.dd-post .dd-tabs .panel{display:none;margin-top:12px}\n.dd-post .dd-tabs #ti1:checked~.labels label[for=ti1],.dd-post .dd-tabs #ti2:checked~.labels label[for=ti2],.dd-post .dd-tabs #ti3:checked~.labels label[for=ti3],.dd-post .dd-tabs #ti4:checked~.labels label[for=ti4]{background:var(--violet);color:#fff;border-color:var(--violet)}\n.dd-post .dd-tabs #ti1:checked~.p1,.dd-post .dd-tabs #ti2:checked~.p2,.dd-post .dd-tabs #ti3:checked~.p3,.dd-post .dd-tabs #ti4:checked~.p4{display:block}\n.dd-post .dd-tabs #ti1:focus-visible~.labels label[for=ti1],.dd-post .dd-tabs #ti2:focus-visible~.labels label[for=ti2],.dd-post .dd-tabs #ti3:focus-visible~.labels label[for=ti3],.dd-post .dd-tabs #ti4:focus-visible~.labels label[for=ti4]{outline:2px solid var(--blue);outline-offset:2px}\n.dd-post .dd-cta{background:linear-gradient(135deg,#0b1020,#151b3b);color:#e8ebff;border-radius:16px;padding:24px 26px;margin:2em 0;text-align:center}\n.dd-post .dd-cta h3{color:#fff;margin-top:0}\n.dd-post .dd-cta a{color:#a99bff}\n.dd-post .dd-vsc{position:relative;margin:1.5em 0;border-radius:12px;overflow:hidden;background:#1e1e1e;border:1px solid #2b2b2b;box-shadow:0 14px 34px rgba(0,0,0,.28);font-family:\"Segoe UI\",system-ui,sans-serif}\n.dd-post .dd-vsc>input{position:absolute;opacity:0;pointer-events:none}\n.dd-post .dd-vsc-bar{display:flex;align-items:center;gap:12px;background:#323233;color:#cccccc;font-size:12.5px;padding:8px 12px}\n.dd-post .dd-dots{display:inline-flex;gap:7px}.dd-post .dd-dots i{width:12px;height:12px;border-radius:50%;background:#ff5f57;display:block}.dd-post .dd-dots i:nth-child(2){background:#febc2e}.dd-post .dd-dots i:nth-child(3){background:#28c840}\n.dd-post .dd-vsc-title{flex:1;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:50px;opacity:.85}\n.dd-post .dd-vsc-tabs{display:flex;align-items:stretch;background:#252526;border-bottom:1px solid #1e1e1e;overflow-x:auto}\n.dd-post .dd-vsc-tabs label{display:flex;align-items:center;gap:7px;padding:9px 16px;color:#969696;font-size:13px;cursor:pointer;background:#2d2d2d;border-right:1px solid #252526;border-top:1px solid transparent;white-space:nowrap;margin:0;transition:color .15s}\n.dd-post .dd-vsc-tabs label:hover{color:#e0e0e0}\n.dd-post .dd-vsc-tabs .ic{font:700 9.5px\/1 Consolas,monospace;padding:3px 4px;border-radius:3px;color:#1e1e1e}\n.dd-post .ic.py{background:#ffd43b}.dd-post .ic.js{background:#f1e05a}.dd-post .ic.sh{background:#89e051}\n.dd-post .dd-vsc-tabs label.run{margin-left:auto;background:transparent;border:0;color:#89d185;font-weight:600;display:none}\n.dd-post .dd-vsc-tabs label.run:hover{color:#b5f0b0;background:#2a2d2e}\n.dd-post .dd-vsc-pane{display:none}\n.dd-post .dd-vsc>.f1:checked~.dd-vsc-tabs .t1,.dd-post .dd-vsc>.f2:checked~.dd-vsc-tabs .t2,.dd-post .dd-vsc>.f3:checked~.dd-vsc-tabs .t3{background:#1e1e1e;color:#ffffff;border-top-color:#3178c6}\n.dd-post .dd-vsc>.f1:checked~.p1,.dd-post .dd-vsc>.f2:checked~.p2,.dd-post .dd-vsc>.f3:checked~.p3{display:block}\n.dd-post .dd-vsc>.f1:checked~.dd-vsc-tabs .run1,.dd-post .dd-vsc>.f2:checked~.dd-vsc-tabs .run2,.dd-post .dd-vsc>.f3:checked~.dd-vsc-tabs .run3{display:flex}\n.dd-post .dd-vsc>.f1:focus-visible~.dd-vsc-tabs .t1,.dd-post .dd-vsc>.f2:focus-visible~.dd-vsc-tabs .t2,.dd-post .dd-vsc>.f3:focus-visible~.dd-vsc-tabs .t3,.dd-post .dd-vsc>input[type=checkbox]:focus-visible~.dd-vsc-tabs .run{outline:2px solid #3178c6;outline-offset:-2px}\n.dd-post .dd-vsc-crumbs{background:#1e1e1e;color:#a9a9a9;font-size:12px;padding:5px 16px 2px}\n.dd-post .dd-vsc pre.dd-vsc-code{background:#1e1e1e;color:#d4d4d4;border:0;border-radius:0;margin:0;padding:8px 0 14px;counter-reset:ln;line-height:1.62;overflow-x:auto}\n.dd-post .dd-vsc pre code{font-family:Consolas,\"JetBrains Mono\",\"Fira Code\",Menlo,monospace;color:inherit;background:none;white-space:pre}\n.dd-post .dd-vsc .l{display:inline-block;min-width:100%;padding-right:18px;box-sizing:border-box}\n.dd-post .dd-vsc .l::before{counter-increment:ln;content:counter(ln);display:inline-block;width:3.2em;padding-right:1.4em;text-align:right;color:#6e7681;user-select:none;-webkit-user-select:none}\n.dd-post .dd-vsc .l:hover{background:#2a2d2e}.dd-post .dd-vsc .l:hover::before{color:#c6c6c6}\n.dd-post .dd-vsc .k,.dd-post .dd-vsc .kn{color:#c586c0}.dd-post .dd-vsc .kc{color:#569cd6}.dd-post .dd-vsc .s{color:#ce9178}.dd-post .dd-vsc .c{color:#6a9955}.dd-post .dd-vsc .m{color:#b5cea8}.dd-post .dd-vsc .nf{color:#dcdcaa}.dd-post .dd-vsc .nc{color:#4ec9b0}.dd-post .dd-vsc .nb{color:#4ec9b0}.dd-post .dd-vsc .nd{color:#dcdcaa}.dd-post .dd-vsc .n{color:#9cdcfe}.dd-post .dd-vsc .o{color:#d4d4d4}.dd-post .dd-vsc .gp{color:#89d185;user-select:none;-webkit-user-select:none}\n.dd-post .dd-vsc-term{display:none;border-top:1px solid #3c3c3c;background:#181818}\n.dd-post .dd-vsc>.r1:checked~.p1 .dd-vsc-term,.dd-post .dd-vsc>.r2:checked~.p2 .dd-vsc-term,.dd-post .dd-vsc>.r3:checked~.p3 .dd-vsc-term{display:block;animation:ddterm .35s ease-out}\n@keyframes ddterm{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}\n.dd-post .dd-term-head{display:flex;gap:18px;align-items:center;font-size:11px;letter-spacing:.06em;color:#8b8b8b;padding:7px 16px 0}\n.dd-post .dd-term-head span:first-child{color:#e7e7e7;border-bottom:1px solid #e7e7e7;padding-bottom:4px}\n.dd-post .dd-term-head .dd-term-note{margin-left:auto;letter-spacing:0;text-transform:none;color:#d7ba7d;border:0;font-size:11.5px}\n.dd-post .dd-vsc-term pre{background:#181818;color:#cccccc;border:0;margin:0;padding:10px 16px 14px;border-radius:0}\n.dd-post .dd-vsc-status{display:flex;flex-wrap:wrap;gap:4px 14px;background:#007acc;color:#fff;font-size:11.5px;padding:4px 12px}\n.dd-post .dd-vsc-status .sp{flex:1}\n.dd-post .dd-vsc-termonly pre.dd-vsc-code{background:#181818;padding:12px 16px}\n@media(max-width:640px){.dd-post .dd-vsc-title{padding-right:0;text-align:left}.dd-post .dd-vsc-status span:nth-child(n+4){display:none}.dd-post .dd-vsc .l::before{width:2.2em;padding-right:1em}}\n.dd-post .dd-vsc-hint{font-size:.93em;color:var(--muted);margin-top:-.6em}\n.dd-post .dd-next{border:1px dashed var(--violet);border-radius:12px;padding:16px 20px;margin:1.6em 0;background:#f7f4ff}\n<\/style>\n\n<div class=\"dd-hero\">\n<svg viewBox=\"0 0 1200 520\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"Agentic AI series Part 3 banner: an LLM sends a tool call to your code, your function runs, and the result flows back to the model\">\n<defs>\n<linearGradient id=\"ddbg\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"#0b1020\"\/><stop offset=\"1\" stop-color=\"#151b3b\"\/><\/linearGradient>\n<linearGradient id=\"ddac\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#3178c6\"\/><stop offset=\"1\" stop-color=\"#7c5cff\"\/><\/linearGradient>\n<radialGradient id=\"ddglow\" cx=\".5\" cy=\".5\" r=\".5\"><stop offset=\"0\" stop-color=\"#7c5cff\" stop-opacity=\".45\"\/><stop offset=\"1\" stop-color=\"#7c5cff\" stop-opacity=\"0\"\/><\/radialGradient>\n<\/defs>\n<rect x=\"0\" y=\"-60\" width=\"1200\" height=\"640\" fill=\"url(#ddbg)\"\/>\n<circle cx=\"900\" cy=\"290\" r=\"270\" fill=\"url(#ddglow)\"\/>\n<g opacity=\".12\" stroke=\"#9fb2ff\"><path d=\"M0 100H1200M0 200H1200M0 300H1200M0 400H1200M200 0V520M400 0V520M600 0V520M800 0V520M1000 0V520\"\/><\/g>\n<rect x=\"60\" y=\"46\" width=\"128\" height=\"38\" rx=\"19\" fill=\"url(#ddac)\"\/>\n<text x=\"124\" y=\"71\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"18\" font-weight=\"700\" fill=\"#fff\">PART 3<\/text>\n<text x=\"204\" y=\"71\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"18\" fill=\"#aab4e8\">Agentic AI Series \u00b7 DevDojo<\/text>\n<text x=\"60\" y=\"150\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"54\" font-weight=\"800\" fill=\"#ffffff\">Tool Calling<\/text>\n<text x=\"60\" y=\"212\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"54\" font-weight=\"800\" fill=\"url(#ddac)\">for AI Agents<\/text>\n<text x=\"60\" y=\"260\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"24\" fill=\"#c9d1ff\">Let an LLM use your functions safely,<\/text>\n<text x=\"60\" y=\"292\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"24\" fill=\"#c9d1ff\">step by step, with runnable code<\/text>\n<g fill=\"none\" stroke=\"url(#ddac)\" stroke-width=\"3\" stroke-dasharray=\"8 8\" opacity=\".75\">\n<path id=\"ddp1\" d=\"M840 150 C 960 150, 1000 180, 1000 228\"\/>\n<path id=\"ddp2\" d=\"M1000 352 C 1000 400, 960 430, 840 430\"\/>\n<path id=\"ddp3\" d=\"M740 400 L740 180\"\/>\n<\/g>\n<g class=\"node\"><rect x=\"660\" y=\"118\" width=\"180\" height=\"62\" rx=\"14\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"750\" y=\"146\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"21\" font-weight=\"800\" fill=\"#fff\">LLM<\/text><text x=\"750\" y=\"168\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">decides which tool<\/text><\/g>\n<g class=\"node\"><rect x=\"920\" y=\"228\" width=\"200\" height=\"124\" rx=\"16\" fill=\"#0b1020\" stroke=\"url(#ddac)\" stroke-width=\"3\"\/><text x=\"1020\" y=\"270\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"21\" font-weight=\"800\" fill=\"#fff\">Your code<\/text><text x=\"1020\" y=\"296\" text-anchor=\"middle\" font-family=\"Consolas,monospace\" font-size=\"15\" fill=\"#61dafb\">get_weather()<\/text><text x=\"1020\" y=\"320\" text-anchor=\"middle\" font-family=\"Consolas,monospace\" font-size=\"15\" fill=\"#61dafb\">convert_inr()<\/text><\/g>\n<g class=\"node\"><rect x=\"660\" y=\"400\" width=\"180\" height=\"62\" rx=\"14\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"750\" y=\"428\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"21\" font-weight=\"800\" fill=\"#fff\">Result<\/text><text x=\"750\" y=\"450\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">back to the model<\/text><\/g>\n<text x=\"930\" y=\"140\" font-family=\"Consolas,monospace\" font-size=\"14\" fill=\"#aab4e8\">function_call<\/text>\n<text x=\"880\" y=\"460\" font-family=\"Consolas,monospace\" font-size=\"14\" fill=\"#aab4e8\">function_call_output<\/text>\n<circle r=\"7\" fill=\"#7c5cff\"><animateMotion dur=\"2.4s\" repeatCount=\"indefinite\"><mpath href=\"#ddp1\"\/><\/animateMotion><\/circle>\n<circle r=\"7\" fill=\"#61dafb\"><animateMotion dur=\"2.4s\" begin=\".8s\" repeatCount=\"indefinite\"><mpath href=\"#ddp2\"\/><\/animateMotion><\/circle>\n<circle r=\"7\" fill=\"#ffffff\"><animateMotion dur=\"2.4s\" begin=\"1.6s\" repeatCount=\"indefinite\"><mpath href=\"#ddp3\"\/><\/animateMotion><\/circle>\n<g font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">\n<rect x=\"60\" y=\"350\" width=\"150\" height=\"36\" rx=\"18\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"135\" y=\"374\" text-anchor=\"middle\">Python<\/text>\n<rect x=\"222\" y=\"350\" width=\"150\" height=\"36\" rx=\"18\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"297\" y=\"374\" text-anchor=\"middle\">Node.js<\/text>\n<rect x=\"384\" y=\"350\" width=\"190\" height=\"36\" rx=\"18\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"479\" y=\"374\" text-anchor=\"middle\">OpenAI + Claude<\/text>\n<\/g>\n<text x=\"60\" y=\"505\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" fill=\"#7f89b5\">devdojo.co.in \u00b7 Beginner friendly \u00b7 Runs offline, no API key needed<\/text>\n<\/svg>\n<\/div>\n\n<div class=\"dd-series\">Series: Agentic AI <span>Part 3 of 30<\/span><\/div>\n<p class=\"dd-prereq\"><strong>What you should know first:<\/strong> read <a href=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/27\/agentic-ai-series-part-2-anatomy-of-an-ai-agent\/\">Agentic AI Part 2: Anatomy of an AI Agent<\/a> (the four parts of an agent) and <a href=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/20\/agentic-ai-series-part-1-what-is-agentic-ai\/\">Part 1: What Is Agentic AI?<\/a>. Basic Python or JavaScript is enough.<\/p>\n\n<p>In Part 2 we called tools the &#8220;hands&#8221; of an AI agent. Today we look closely at how those hands actually work. <strong>Tool calling<\/strong> (also called <em>function calling<\/em>) is the feature that lets a large language model (LLM) ask your program to run a real function, such as checking the weather, reading a database or sending an email, and then use the result in its answer. Without tool calling, an LLM can only talk. With it, an LLM can <em>do things<\/em>. That is the single biggest step from a chatbot to an agent.<\/p>\n<p>You will learn the full tool-calling round trip, how to describe tools with JSON Schema, how parallel tool calls work, how to handle errors safely, and how the same idea looks in the OpenAI and Anthropic (Claude) APIs. Every main example runs offline with a small fake model, so you can try it without an API key.<\/p>\n\n<div class=\"dd-summary\">\n<strong class=\"lbl\">Quick Summary<\/strong>\n<ul>\n<li><strong>Tool calling<\/strong> lets an LLM ask <em>your code<\/em> to run a function. The model never runs the function itself.<\/li>\n<li>You describe each tool with a <strong>name<\/strong>, a <strong>description<\/strong> and a <strong>JSON Schema<\/strong> for its arguments.<\/li>\n<li>The round trip: send tools \u2192 model returns a tool call \u2192 you run it \u2192 send the result back \u2192 model answers.<\/li>\n<li>Models can ask for <strong>several tools at once<\/strong> (parallel tool calls). Match each result with its <code>call_id<\/code>.<\/li>\n<li>Never crash on a bad call: <strong>validate arguments<\/strong> and return errors as text so the model can recover.<\/li>\n<\/ul>\n<\/div>\n\n<nav class=\"dd-toc\" aria-label=\"Table of contents\">\n<strong>In this post<\/strong>\n<ol>\n<li><a href=\"#what\">What is tool calling?<\/a><\/li>\n<li><a href=\"#roundtrip\">The tool-calling round trip<\/a><\/li>\n<li><a href=\"#schema\">Describing tools with JSON Schema<\/a><\/li>\n<li><a href=\"#loop\">Build a tool-calling loop<\/a><\/li>\n<li><a href=\"#parallel\">Parallel tool calls<\/a><\/li>\n<li><a href=\"#errors\">Handling tool errors safely<\/a><\/li>\n<li><a href=\"#real\">Tool calling with OpenAI and Claude<\/a><\/li>\n<li><a href=\"#choice\">Controlling when tools are used<\/a><\/li>\n<li><a href=\"#fixes\">Common errors and fixes<\/a><\/li>\n<li><a href=\"#best\">Best practices<\/a><\/li>\n<li><a href=\"#practice\">Practice task<\/a><\/li>\n<li><a href=\"#faq\">FAQ<\/a><\/li>\n<\/ol>\n<\/nav>\n\n<h2 id=\"what\">What is tool calling in AI agents?<\/h2>\n<p>An LLM is trained on text. It does not know today&#8217;s weather, your order status or the files on your laptop. Tool calling fixes this. You give the model a list of tools (functions) it is allowed to use. When the model decides one would help, it does <em>not<\/em> answer with normal text. Instead, it replies with a small, structured request like this:<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: tool_call.js\">\n<input type=\"radio\" name=\"v0\" id=\"v0f1\" class=\"f1\" checked>\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">tool_call.js \u2014 agentic-ai-part3 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v0f1\" class=\"t1\"><b class=\"ic js\">JS<\/b>tool_call.js<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a tool_call.js<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\">\/\/ What the model sends back instead of text (OpenAI Responses API shape)<\/span><\/span>\n<span class=\"l\"><span class=\"k\">const<\/span> <span class=\"n\">toolCall<\/span> = {<\/span>\n<span class=\"l\">  <span class=\"n\">type<\/span>: <span class=\"s\">\"function_call\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"n\">call_id<\/span>: <span class=\"s\">\"call_1\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"n\">name<\/span>: <span class=\"s\">\"get_weather\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"nb\">arguments<\/span>: <span class=\"s\">'{\"city\": \"Pune\", \"unit\": \"celsius\"}'<\/span>,<\/span>\n<span class=\"l\">};<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 7, Col 1<\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>JavaScript<\/span><\/div>\n<\/div>\n<\/div>\n<p>Your program reads that request, runs the matching function, and sends the result back. The model then writes the final answer using real data. Think of the model as a manager who can only write notes, and your code as the assistant who actually does the work.<\/p>\n\n<div class=\"dd-cards\">\n<div class=\"dd-card\"><b>The model decides<\/b>Which tool to call and with which arguments, based on the user&#8217;s question and the tool descriptions.<\/div>\n<div class=\"dd-card\"><b>Your code executes<\/b>It runs the real function. You stay in control of what is allowed, logged and checked.<\/div>\n<div class=\"dd-card\"><b>The model explains<\/b>It reads the tool result and turns it into a helpful answer for the user.<\/div>\n<\/div>\n\n<div class=\"dd-note\"><strong>Function calling vs tool calling:<\/strong> they mean the same thing. OpenAI first called it &#8220;function calling&#8221;; today most providers say &#8220;tool calling&#8221; or &#8220;tool use&#8221; because a tool can also be a built-in service like web search.<\/div>\n\n<h2 id=\"roundtrip\">The tool-calling round trip, step by step<\/h2>\n<p>Every tool call follows the same five steps, no matter which provider you use. Click through the steps below to see what the data looks like at each point.<\/p>\n\n<figure>\n<svg viewBox=\"0 0 900 360\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"Sequence diagram of tool calling between the user, your app, the LLM and your function\">\n<rect width=\"900\" height=\"360\" fill=\"#0f1430\"\/>\n<g font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\" text-anchor=\"middle\">\n<rect x=\"40\" y=\"20\" width=\"150\" height=\"44\" rx=\"10\" fill=\"#1b2250\" stroke=\"#3178c6\"\/><text x=\"115\" y=\"48\">User<\/text>\n<rect x=\"260\" y=\"20\" width=\"150\" height=\"44\" rx=\"10\" fill=\"#1b2250\" stroke=\"#3178c6\"\/><text x=\"335\" y=\"48\">Your app<\/text>\n<rect x=\"480\" y=\"20\" width=\"150\" height=\"44\" rx=\"10\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"555\" y=\"48\">LLM<\/text>\n<rect x=\"700\" y=\"20\" width=\"160\" height=\"44\" rx=\"10\" fill=\"#1b2250\" stroke=\"#61dafb\"\/><text x=\"780\" y=\"48\">Your function<\/text>\n<\/g>\n<g stroke=\"#3a4380\" stroke-dasharray=\"4 6\"><path d=\"M115 64V345M335 64V345M555 64V345M780 64V345\"\/><\/g>\n<g font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#c9d1ff\">\n<path d=\"M115 95H330\" stroke=\"#9fb2ff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"125\" y=\"88\">1. question<\/text>\n<path d=\"M335 135H550\" stroke=\"#9fb2ff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"345\" y=\"128\">2. question + tool list<\/text>\n<path d=\"M555 175H340\" stroke=\"#a99bff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"370\" y=\"168\">3. tool call (name + args)<\/text>\n<path d=\"M335 215H775\" stroke=\"#61dafb\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"560\" y=\"208\">4a. run function<\/text>\n<path d=\"M780 245H340\" stroke=\"#61dafb\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"560\" y=\"238\">4b. result<\/text>\n<path d=\"M335 285H550\" stroke=\"#9fb2ff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"345\" y=\"278\">5. result + history<\/text>\n<path d=\"M555 315H340\" stroke=\"#a99bff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"380\" y=\"308\">final answer<\/text>\n<path d=\"M335 335H120\" stroke=\"#9fb2ff\" stroke-width=\"2\" marker-end=\"url(#ar)\"\/><text x=\"150\" y=\"328\">reply<\/text>\n<\/g>\n<defs><marker id=\"ar\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto\"><path d=\"M0 0L10 5L0 10z\" fill=\"#c9d1ff\"\/><\/marker><\/defs>\n<\/svg>\n<figcaption>The tool-calling round trip: the model only <em>asks<\/em> for a tool; your app runs it and sends the result back.<\/figcaption>\n<\/figure>\n\n<div class=\"dd-tabs\" role=\"group\" aria-label=\"Tool calling step explorer\">\n<input type=\"radio\" name=\"ddsteps\" id=\"ti1\" checked>\n<input type=\"radio\" name=\"ddsteps\" id=\"ti2\">\n<input type=\"radio\" name=\"ddsteps\" id=\"ti3\">\n<input type=\"radio\" name=\"ddsteps\" id=\"ti4\">\n<div class=\"labels\"><label for=\"ti1\">1. Send tools<\/label><label for=\"ti2\">2. Model asks<\/label><label for=\"ti3\">3. You run it<\/label><label for=\"ti4\">4. Model answers<\/label><\/div>\n<div class=\"panel p1\"><p>You send the user&#8217;s message <strong>and<\/strong> the list of tools. Each tool has a name, a plain-English description and a JSON Schema for its arguments. The description is how the model knows <em>when<\/em> to use the tool.<\/p><\/div>\n<div class=\"panel p2\"><p>The model returns a <code>function_call<\/code> item instead of text: <code>name: \"get_weather\"<\/code>, <code>arguments: \"{\\\"city\\\": \\\"Pune\\\", \\\"unit\\\": \\\"celsius\\\"}\"<\/code> and a unique <code>call_id<\/code>. Note that <code>arguments<\/code> is a <strong>JSON string<\/strong>, so you must parse it.<\/p><\/div>\n<div class=\"panel p3\"><p>Your code looks up the function by name, parses the arguments, runs it and turns the result into a string (usually JSON). You append the original tool call <strong>and<\/strong> a <code>function_call_output<\/code> with the same <code>call_id<\/code> to the conversation.<\/p><\/div>\n<div class=\"panel p4\"><p>You call the model again with the updated history. Now it can see the real data and writes a final answer, or asks for another tool. Keep looping until there are no more tool calls, with a maximum number of turns as a safety limit.<\/p><\/div>\n<\/div>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"schema\">Describing tools with JSON Schema<\/h2>\n<p>A tool definition is just data. The model never sees your Python or JavaScript code; it only sees the <strong>name<\/strong>, the <strong>description<\/strong> and the <strong>parameters<\/strong> schema. So write them for the model like you would write docs for a new teammate. Here are two tools and the real functions behind them:<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: tools.py\">\n<input type=\"radio\" name=\"v1\" id=\"v1f1\" class=\"f1\" checked>\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">tools.py \u2014 agentic-ai-part3 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v1f1\" class=\"t1\"><b class=\"ic py\">PY<\/b>tools.py<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a tools.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Step 1: describe your functions as tools (JSON Schema).<\/span><\/span>\n<span class=\"l\"><span class=\"n\">TOOLS<\/span> = [<\/span>\n<span class=\"l\">    {<\/span>\n<span class=\"l\">        <span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"name\"<\/span>: <span class=\"s\">\"get_weather\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"description\"<\/span>: <span class=\"s\">\"Get the current weather for a city. Use for any weather question.\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"parameters\"<\/span>: {<\/span>\n<span class=\"l\">            <span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"object\"<\/span>,<\/span>\n<span class=\"l\">            <span class=\"s\">\"properties\"<\/span>: {<\/span>\n<span class=\"l\">                <span class=\"s\">\"city\"<\/span>: {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"string\"<\/span>, <span class=\"s\">\"description\"<\/span>: <span class=\"s\">\"City name, e.g. 'Pune'\"<\/span>},<\/span>\n<span class=\"l\">                <span class=\"s\">\"unit\"<\/span>: {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"string\"<\/span>, <span class=\"s\">\"enum\"<\/span>: [<span class=\"s\">\"celsius\"<\/span>, <span class=\"s\">\"fahrenheit\"<\/span>]},<\/span>\n<span class=\"l\">            },<\/span>\n<span class=\"l\">            <span class=\"s\">\"required\"<\/span>: [<span class=\"s\">\"city\"<\/span>, <span class=\"s\">\"unit\"<\/span>],<\/span>\n<span class=\"l\">            <span class=\"s\">\"additionalProperties\"<\/span>: <span class=\"kc\">False<\/span>,<\/span>\n<span class=\"l\">        },<\/span>\n<span class=\"l\">        <span class=\"s\">\"strict\"<\/span>: <span class=\"kc\">True<\/span>,<\/span>\n<span class=\"l\">    },<\/span>\n<span class=\"l\">    {<\/span>\n<span class=\"l\">        <span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"name\"<\/span>: <span class=\"s\">\"convert_inr\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"description\"<\/span>: <span class=\"s\">\"Convert an amount in Indian rupees (INR) to another currency.\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"s\">\"parameters\"<\/span>: {<\/span>\n<span class=\"l\">            <span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"object\"<\/span>,<\/span>\n<span class=\"l\">            <span class=\"s\">\"properties\"<\/span>: {<\/span>\n<span class=\"l\">                <span class=\"s\">\"amount\"<\/span>: {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"number\"<\/span>},<\/span>\n<span class=\"l\">                <span class=\"s\">\"to\"<\/span>: {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"string\"<\/span>, <span class=\"s\">\"enum\"<\/span>: [<span class=\"s\">\"USD\"<\/span>, <span class=\"s\">\"EUR\"<\/span>, <span class=\"s\">\"GBP\"<\/span>]},<\/span>\n<span class=\"l\">            },<\/span>\n<span class=\"l\">            <span class=\"s\">\"required\"<\/span>: [<span class=\"s\">\"amount\"<\/span>, <span class=\"s\">\"to\"<\/span>],<\/span>\n<span class=\"l\">            <span class=\"s\">\"additionalProperties\"<\/span>: <span class=\"kc\">False<\/span>,<\/span>\n<span class=\"l\">        },<\/span>\n<span class=\"l\">        <span class=\"s\">\"strict\"<\/span>: <span class=\"kc\">True<\/span>,<\/span>\n<span class=\"l\">    },<\/span>\n<span class=\"l\">]<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"c\"># Step 2: the real Python functions behind the tools.<\/span><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">get_weather<\/span>(<span class=\"n\">city<\/span>, <span class=\"n\">unit<\/span>):<\/span>\n<span class=\"l\">    <span class=\"n\">fake<\/span> = {<span class=\"s\">\"pune\"<\/span>: <span class=\"m\">29<\/span>, <span class=\"s\">\"delhi\"<\/span>: <span class=\"m\">24<\/span>, <span class=\"s\">\"london\"<\/span>: <span class=\"m\">11<\/span>}<\/span>\n<span class=\"l\">    <span class=\"n\">c<\/span> = <span class=\"n\">fake<\/span>.<span class=\"n\">get<\/span>(<span class=\"n\">city<\/span>.<span class=\"n\">lower<\/span>())<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> <span class=\"n\">c<\/span> is <span class=\"kc\">None<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">raise<\/span> ValueError(<span class=\"s\">f\"No weather data for '{<\/span><span class=\"n\">city<\/span><span class=\"s\">}'\"<\/span>)<\/span>\n<span class=\"l\">    <span class=\"n\">t<\/span> = <span class=\"n\">c<\/span> <span class=\"k\">if<\/span> <span class=\"n\">unit<\/span> == <span class=\"s\">\"celsius\"<\/span> <span class=\"k\">else<\/span> <span class=\"nb\">round<\/span>(<span class=\"n\">c<\/span> * <span class=\"m\">9<\/span> \/ <span class=\"m\">5<\/span> + <span class=\"m\">32<\/span>)<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> {<span class=\"s\">\"city\"<\/span>: <span class=\"n\">city<\/span>, <span class=\"s\">\"temp\"<\/span>: <span class=\"n\">t<\/span>, <span class=\"s\">\"unit\"<\/span>: <span class=\"n\">unit<\/span>}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">convert_inr<\/span>(<span class=\"n\">amount<\/span>, <span class=\"n\">to<\/span>):<\/span>\n<span class=\"l\">    <span class=\"n\">rates<\/span> = {<span class=\"s\">\"USD\"<\/span>: <span class=\"m\">0.012<\/span>, <span class=\"s\">\"EUR\"<\/span>: <span class=\"m\">0.010<\/span>, <span class=\"s\">\"GBP\"<\/span>: <span class=\"m\">0.009<\/span>}  <span class=\"c\"># demo rates only<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> {<span class=\"s\">\"inr\"<\/span>: <span class=\"n\">amount<\/span>, <span class=\"n\">to<\/span>: <span class=\"nb\">round<\/span>(<span class=\"n\">amount<\/span> * <span class=\"n\">rates<\/span>[<span class=\"n\">to<\/span>], <span class=\"m\">2<\/span>)}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">FUNCTIONS<\/span> = {<span class=\"s\">\"get_weather\"<\/span>: <span class=\"n\">get_weather<\/span>, <span class=\"s\">\"convert_inr\"<\/span>: <span class=\"n\">convert_inr<\/span>}<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 48, Col 1<\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<\/div>\n<p>A few things to notice:<\/p>\n<ul>\n<li><strong><code>\"strict\": True<\/code><\/strong> turns on structured outputs for the tool in the OpenAI API, so the arguments always match your schema. Strict mode needs <code>\"additionalProperties\": False<\/code> and every field listed in <code>required<\/code>.<\/li>\n<li><strong><code>enum<\/code><\/strong> limits a field to fixed values (like <code>celsius<\/code> \/ <code>fahrenheit<\/code>). This removes a whole class of mistakes.<\/li>\n<li><strong>Descriptions say when to use the tool<\/strong>, not just what it does: &#8220;Use for any weather question.&#8221;<\/li>\n<\/ul>\n\n<h2 id=\"loop\">Build a tool-calling loop (runs offline)<\/h2>\n<p>Now the core of every agent: the loop. Below, <code>fake_model()<\/code> pretends to be an LLM and returns data in the <strong>same shape as the OpenAI Responses API<\/strong>. That means you can learn the full flow without an API key and later swap in a real model with almost no changes. The Node.js tab shows the same loop in JavaScript.<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: agent_loop.py, agent_loop.mjs\">\n<input type=\"radio\" name=\"v2\" id=\"v2f1\" class=\"f1\" checked>\n<input type=\"radio\" name=\"v2\" id=\"v2f2\" class=\"f2\">\n<input type=\"checkbox\" id=\"v2r1\" class=\"r1\">\n<input type=\"checkbox\" id=\"v2r2\" class=\"r2\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">2 files \u2014 agentic-ai-part3 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v2f1\" class=\"t1\"><b class=\"ic py\">PY<\/b>agent_loop.py<\/label>\n<label for=\"v2f2\" class=\"t2\"><b class=\"ic js\">JS<\/b>agent_loop.mjs<\/label>\n<label for=\"v2r1\" class=\"run run1\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<label for=\"v2r2\" class=\"run run2\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a agent_loop.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Step 3: the tool-calling loop (runs offline with a fake model).<\/span><\/span>\n<span class=\"l\"><span class=\"kn\">import<\/span> json<\/span>\n<span class=\"l\"><span class=\"kn\">from<\/span> tools <span class=\"kn\">import<\/span> <span class=\"n\">TOOLS<\/span>, <span class=\"n\">FUNCTIONS<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">fake_model<\/span>(<span class=\"n\">messages<\/span>, <span class=\"n\">tools<\/span>):<\/span>\n<span class=\"l\">    <span class=\"s\">\"\"\"Pretends to be an LLM. Same output shape as the OpenAI Responses API.\"\"\"<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> <span class=\"n\">messages<\/span>[-<span class=\"m\">1<\/span>].<span class=\"n\">get<\/span>(<span class=\"s\">\"type\"<\/span>) != <span class=\"s\">\"function_call_output\"<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> [  <span class=\"c\"># two tool calls in ONE turn (parallel tool calls)<\/span><\/span>\n<span class=\"l\">            {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function_call\"<\/span>, <span class=\"s\">\"call_id\"<\/span>: <span class=\"s\">\"call_1\"<\/span>, <span class=\"s\">\"name\"<\/span>: <span class=\"s\">\"get_weather\"<\/span>,<\/span>\n<span class=\"l\">             <span class=\"s\">\"arguments\"<\/span>: <span class=\"s\">'{\"city\": \"Pune\", \"unit\": \"celsius\"}'<\/span>},<\/span>\n<span class=\"l\">            {<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function_call\"<\/span>, <span class=\"s\">\"call_id\"<\/span>: <span class=\"s\">\"call_2\"<\/span>, <span class=\"s\">\"name\"<\/span>: <span class=\"s\">\"convert_inr\"<\/span>,<\/span>\n<span class=\"l\">             <span class=\"s\">\"arguments\"<\/span>: <span class=\"s\">'{\"amount\": 5000, \"to\": \"USD\"}'<\/span>},<\/span>\n<span class=\"l\">        ]<\/span>\n<span class=\"l\">    <span class=\"n\">results<\/span> = [<span class=\"n\">json<\/span>.<span class=\"n\">loads<\/span>(<span class=\"n\">m<\/span>[<span class=\"s\">\"output\"<\/span>]) <span class=\"k\">for<\/span> <span class=\"n\">m<\/span> in <span class=\"n\">messages<\/span> <span class=\"k\">if<\/span> <span class=\"n\">m<\/span>.<span class=\"n\">get<\/span>(<span class=\"s\">\"type\"<\/span>) == <span class=\"s\">\"function_call_output\"<\/span>]<\/span>\n<span class=\"l\">    <span class=\"n\">w<\/span>, <span class=\"n\">money<\/span> = <span class=\"n\">results<\/span>[<span class=\"m\">0<\/span>], <span class=\"n\">results<\/span>[<span class=\"m\">1<\/span>]<\/span>\n<span class=\"l\">    <span class=\"n\">text<\/span> = (<span class=\"s\">f\"It is {<\/span><span class=\"n\">w<\/span>[<span class=\"s\">'temp'<\/span>]<span class=\"s\">}\u00b0C in {<\/span><span class=\"n\">w<\/span>[<span class=\"s\">'city'<\/span>]<span class=\"s\">} right now, and \"<\/span><\/span>\n<span class=\"l\">            <span class=\"s\">f\"\u20b9{<\/span><span class=\"n\">money<\/span>[<span class=\"s\">'inr'<\/span>]<span class=\"s\">} is about ${<\/span><span class=\"n\">money<\/span>[<span class=\"s\">'USD'<\/span>]<span class=\"s\">}.\"<\/span>)<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> [{<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"message\"<\/span>, <span class=\"s\">\"content\"<\/span>: [{<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"output_text\"<\/span>, <span class=\"s\">\"text\"<\/span>: <span class=\"n\">text<\/span>}]}]<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">run_tool<\/span>(<span class=\"n\">call<\/span>):<\/span>\n<span class=\"l\">    <span class=\"s\">\"\"\"Run one tool safely and ALWAYS return a string for the model.\"\"\"<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">try<\/span>:<\/span>\n<span class=\"l\">        <span class=\"n\">args<\/span> = <span class=\"n\">json<\/span>.<span class=\"n\">loads<\/span>(<span class=\"n\">call<\/span>[<span class=\"s\">\"arguments\"<\/span>])<\/span>\n<span class=\"l\">        <span class=\"n\">result<\/span> = <span class=\"n\">FUNCTIONS<\/span>[<span class=\"n\">call<\/span>[<span class=\"s\">\"name\"<\/span>]](**<span class=\"n\">args<\/span>)<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"n\">json<\/span>.<span class=\"n\">dumps<\/span>(<span class=\"n\">result<\/span>)<\/span>\n<span class=\"l\">    <span class=\"k\">except<\/span> Exception <span class=\"k\">as<\/span> <span class=\"n\">err<\/span>:  <span class=\"c\"># send errors back instead of crashing<\/span><\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"n\">json<\/span>.<span class=\"n\">dumps<\/span>({<span class=\"s\">\"error\"<\/span>: <span class=\"nb\">str<\/span>(<span class=\"n\">err<\/span>)})<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">run_agent<\/span>(<span class=\"n\">question<\/span>, <span class=\"n\">max_turns<\/span>=<span class=\"m\">5<\/span>):<\/span>\n<span class=\"l\">    <span class=\"n\">messages<\/span> = [{<span class=\"s\">\"role\"<\/span>: <span class=\"s\">\"user\"<\/span>, <span class=\"s\">\"content\"<\/span>: <span class=\"n\">question<\/span>}]<\/span>\n<span class=\"l\">    <span class=\"k\">for<\/span> <span class=\"n\">turn<\/span> in <span class=\"nb\">range<\/span>(<span class=\"m\">1<\/span>, <span class=\"n\">max_turns<\/span> + <span class=\"m\">1<\/span>):<\/span>\n<span class=\"l\">        <span class=\"n\">output<\/span> = <span class=\"n\">fake_model<\/span>(<span class=\"n\">messages<\/span>, <span class=\"n\">TOOLS<\/span>)<\/span>\n<span class=\"l\">        <span class=\"n\">calls<\/span> = [<span class=\"n\">o<\/span> <span class=\"k\">for<\/span> <span class=\"n\">o<\/span> in <span class=\"n\">output<\/span> <span class=\"k\">if<\/span> <span class=\"n\">o<\/span>[<span class=\"s\">\"type\"<\/span>] == <span class=\"s\">\"function_call\"<\/span>]<\/span>\n<span class=\"l\">        <span class=\"k\">if<\/span> not <span class=\"n\">calls<\/span>:  <span class=\"c\"># no tool calls -&gt; final answer<\/span><\/span>\n<span class=\"l\">            <span class=\"k\">return<\/span> <span class=\"n\">output<\/span>[-<span class=\"m\">1<\/span>][<span class=\"s\">\"content\"<\/span>][<span class=\"m\">0<\/span>][<span class=\"s\">\"text\"<\/span>]<\/span>\n<span class=\"l\">        <span class=\"n\">messages<\/span> += <span class=\"n\">output<\/span>  <span class=\"c\"># keep the model's tool calls in history<\/span><\/span>\n<span class=\"l\">        <span class=\"k\">for<\/span> <span class=\"n\">call<\/span> in <span class=\"n\">calls<\/span>:<\/span>\n<span class=\"l\">            <span class=\"n\">result<\/span> = <span class=\"n\">run_tool<\/span>(<span class=\"n\">call<\/span>)<\/span>\n<span class=\"l\">            <span class=\"nb\">print<\/span>(<span class=\"s\">f\"turn {<\/span><span class=\"n\">turn<\/span><span class=\"s\">}: {<\/span><span class=\"n\">call<\/span>[<span class=\"s\">'name'<\/span>]<span class=\"s\">}({<\/span><span class=\"n\">call<\/span>[<span class=\"s\">'arguments'<\/span>]<span class=\"s\">}) -&gt; {<\/span><span class=\"n\">result<\/span><span class=\"s\">}\"<\/span>)<\/span>\n<span class=\"l\">            <span class=\"n\">messages<\/span>.<span class=\"n\">append<\/span>({<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function_call_output\"<\/span>,<\/span>\n<span class=\"l\">                             <span class=\"s\">\"call_id\"<\/span>: <span class=\"n\">call<\/span>[<span class=\"s\">\"call_id\"<\/span>], <span class=\"s\">\"output\"<\/span>: <span class=\"n\">result<\/span>})<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> <span class=\"s\">\"Stopped: too many turns.\"<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">print<\/span>(<span class=\"s\">\"Answer:\"<\/span>, <span class=\"n\">run_agent<\/span>(<span class=\"s\">\"Weather in Pune, and what is 5000 rupees in dollars?\"<\/span>))<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><\/div><pre><code>$ python agent_loop.py\nturn 1: get_weather({&quot;city&quot;: &quot;Pune&quot;, &quot;unit&quot;: &quot;celsius&quot;}) -&gt; {&quot;city&quot;: &quot;Pune&quot;, &quot;temp&quot;: 29, &quot;unit&quot;: &quot;celsius&quot;}\nturn 1: convert_inr({&quot;amount&quot;: 5000, &quot;to&quot;: &quot;USD&quot;}) -&gt; {&quot;inr&quot;: 5000, &quot;USD&quot;: 60.0}\nAnswer: It is 29\u00b0C in Pune right now, and \u20b95000 is about $60.0.<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 44, Col 1<\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p2\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a agent_loop.mjs<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\">\/\/ The same tool-calling loop in Node.js (runs offline with a fake model).<\/span><\/span>\n<span class=\"l\"><span class=\"k\">const<\/span> <span class=\"n\">FUNCTIONS<\/span> = {<\/span>\n<span class=\"l\">  <span class=\"n\">get_weather<\/span>: ({ <span class=\"n\">city<\/span>, <span class=\"n\">unit<\/span> }) =&gt; {<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">fake<\/span> = { <span class=\"n\">pune<\/span>: <span class=\"m\">29<\/span>, <span class=\"n\">delhi<\/span>: <span class=\"m\">24<\/span>, <span class=\"n\">london<\/span>: <span class=\"m\">11<\/span> };<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">c<\/span> = <span class=\"n\">fake<\/span>[<span class=\"n\">city<\/span>.<span class=\"n\">toLowerCase<\/span>()];<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> (<span class=\"n\">c<\/span> === <span class=\"kc\">undefined<\/span>) <span class=\"k\">throw<\/span> new Error(<span class=\"s\">`No weather data for '${<\/span><span class=\"n\">city<\/span><span class=\"s\">}'`<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> { <span class=\"n\">city<\/span>, <span class=\"n\">temp<\/span>: <span class=\"n\">unit<\/span> === <span class=\"s\">\"celsius\"<\/span> ? <span class=\"n\">c<\/span> : <span class=\"nb\">Math<\/span>.<span class=\"n\">round<\/span>(<span class=\"n\">c<\/span> * <span class=\"m\">9<\/span> \/ <span class=\"m\">5<\/span> + <span class=\"m\">32<\/span>), <span class=\"n\">unit<\/span> };<\/span>\n<span class=\"l\">  },<\/span>\n<span class=\"l\">  <span class=\"n\">convert_inr<\/span>: ({ <span class=\"n\">amount<\/span>, <span class=\"n\">to<\/span> }) =&gt; {<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">rates<\/span> = { <span class=\"n\">USD<\/span>: <span class=\"m\">0.012<\/span>, <span class=\"n\">EUR<\/span>: <span class=\"m\">0.01<\/span>, <span class=\"n\">GBP<\/span>: <span class=\"m\">0.009<\/span> }; <span class=\"c\">\/\/ demo rates only<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> { <span class=\"n\">inr<\/span>: <span class=\"n\">amount<\/span>, [<span class=\"n\">to<\/span>]: +(<span class=\"n\">amount<\/span> * <span class=\"n\">rates<\/span>[<span class=\"n\">to<\/span>]).<span class=\"n\">toFixed<\/span>(<span class=\"m\">2<\/span>) };<\/span>\n<span class=\"l\">  },<\/span>\n<span class=\"l\">};<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">function<\/span> <span class=\"n\">fakeModel<\/span>(<span class=\"n\">messages<\/span>) {<\/span>\n<span class=\"l\">  <span class=\"k\">if<\/span> (<span class=\"n\">messages<\/span>.<span class=\"n\">at<\/span>(-<span class=\"m\">1<\/span>).<span class=\"n\">type<\/span> !== <span class=\"s\">\"function_call_output\"<\/span>) {<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> [<\/span>\n<span class=\"l\">      { <span class=\"n\">type<\/span>: <span class=\"s\">\"function_call\"<\/span>, <span class=\"n\">call_id<\/span>: <span class=\"s\">\"call_1\"<\/span>, <span class=\"n\">name<\/span>: <span class=\"s\">\"get_weather\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"nb\">arguments<\/span>: <span class=\"s\">'{\"city\":\"Delhi\",\"unit\":\"fahrenheit\"}'<\/span> },<\/span>\n<span class=\"l\">      { <span class=\"n\">type<\/span>: <span class=\"s\">\"function_call\"<\/span>, <span class=\"n\">call_id<\/span>: <span class=\"s\">\"call_2\"<\/span>, <span class=\"n\">name<\/span>: <span class=\"s\">\"get_weather\"<\/span>,<\/span>\n<span class=\"l\">        <span class=\"nb\">arguments<\/span>: <span class=\"s\">'{\"city\":\"Atlantis\",\"unit\":\"celsius\"}'<\/span> },<\/span>\n<span class=\"l\">    ];<\/span>\n<span class=\"l\">  }<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">outs<\/span> = <span class=\"n\">messages<\/span>.<span class=\"n\">filter<\/span>((<span class=\"n\">m<\/span>) =&gt; <span class=\"n\">m<\/span>.<span class=\"n\">type<\/span> === <span class=\"s\">\"function_call_output\"<\/span>)<\/span>\n<span class=\"l\">    .<span class=\"n\">map<\/span>((<span class=\"n\">m<\/span>) =&gt; <span class=\"nb\">JSON<\/span>.<span class=\"n\">parse<\/span>(<span class=\"n\">m<\/span>.<span class=\"n\">output<\/span>));<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">text<\/span> = <span class=\"s\">`Delhi is ${<\/span><span class=\"n\">outs<\/span>[<span class=\"m\">0<\/span>].<span class=\"n\">temp<\/span><span class=\"s\">}\u00b0F. Sorry, I have no data for Atlantis (${<\/span><span class=\"n\">outs<\/span>[<span class=\"m\">1<\/span>].<span class=\"n\">error<\/span><span class=\"s\">}).`<\/span>;<\/span>\n<span class=\"l\">  <span class=\"k\">return<\/span> [{ <span class=\"n\">type<\/span>: <span class=\"s\">\"message\"<\/span>, <span class=\"n\">content<\/span>: [{ <span class=\"n\">type<\/span>: <span class=\"s\">\"output_text\"<\/span>, <span class=\"n\">text<\/span> }] }];<\/span>\n<span class=\"l\">}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">function<\/span> <span class=\"n\">runTool<\/span>(<span class=\"n\">call<\/span>) {<\/span>\n<span class=\"l\">  <span class=\"k\">try<\/span> {<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">args<\/span> = <span class=\"nb\">JSON<\/span>.<span class=\"n\">parse<\/span>(<span class=\"n\">call<\/span>.<span class=\"nb\">arguments<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">fn<\/span> = <span class=\"n\">FUNCTIONS<\/span>[<span class=\"n\">call<\/span>.<span class=\"n\">name<\/span>];<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> (!<span class=\"n\">fn<\/span>) <span class=\"k\">throw<\/span> new Error(<span class=\"s\">`Unknown tool: ${<\/span><span class=\"n\">call<\/span>.<span class=\"n\">name<\/span><span class=\"s\">}`<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> <span class=\"nb\">JSON<\/span>.<span class=\"n\">stringify<\/span>(<span class=\"n\">fn<\/span>(<span class=\"n\">args<\/span>));<\/span>\n<span class=\"l\">  } <span class=\"k\">catch<\/span> (<span class=\"n\">err<\/span>) {<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> <span class=\"nb\">JSON<\/span>.<span class=\"n\">stringify<\/span>({ <span class=\"n\">error<\/span>: <span class=\"n\">err<\/span>.<span class=\"n\">message<\/span> }); <span class=\"c\">\/\/ let the model recover<\/span><\/span>\n<span class=\"l\">  }<\/span>\n<span class=\"l\">}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">async<\/span> <span class=\"k\">function<\/span> <span class=\"n\">runAgent<\/span>(<span class=\"n\">question<\/span>, <span class=\"n\">maxTurns<\/span> = <span class=\"m\">5<\/span>) {<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">messages<\/span> = [{ <span class=\"n\">role<\/span>: <span class=\"s\">\"user\"<\/span>, <span class=\"n\">content<\/span>: <span class=\"n\">question<\/span> }];<\/span>\n<span class=\"l\">  <span class=\"k\">for<\/span> (<span class=\"k\">let<\/span> <span class=\"n\">turn<\/span> = <span class=\"m\">1<\/span>; <span class=\"n\">turn<\/span> &lt;= <span class=\"n\">maxTurns<\/span>; <span class=\"n\">turn<\/span>++) {<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">output<\/span> = <span class=\"n\">fakeModel<\/span>(<span class=\"n\">messages<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">const<\/span> <span class=\"n\">calls<\/span> = <span class=\"n\">output<\/span>.<span class=\"n\">filter<\/span>((<span class=\"n\">o<\/span>) =&gt; <span class=\"n\">o<\/span>.<span class=\"n\">type<\/span> === <span class=\"s\">\"function_call\"<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> (<span class=\"n\">calls<\/span>.<span class=\"n\">length<\/span> === <span class=\"m\">0<\/span>) <span class=\"k\">return<\/span> <span class=\"n\">output<\/span>.<span class=\"n\">at<\/span>(-<span class=\"m\">1<\/span>).<span class=\"n\">content<\/span>[<span class=\"m\">0<\/span>].<span class=\"n\">text<\/span>;<\/span>\n<span class=\"l\">    <span class=\"n\">messages<\/span>.<span class=\"n\">push<\/span>(...<span class=\"n\">output<\/span>);<\/span>\n<span class=\"l\">    <span class=\"k\">for<\/span> (<span class=\"k\">const<\/span> <span class=\"n\">call<\/span> <span class=\"k\">of<\/span> <span class=\"n\">calls<\/span>) {<\/span>\n<span class=\"l\">      <span class=\"k\">const<\/span> <span class=\"n\">result<\/span> = <span class=\"n\">runTool<\/span>(<span class=\"n\">call<\/span>);<\/span>\n<span class=\"l\">      <span class=\"n\">console<\/span>.<span class=\"n\">log<\/span>(<span class=\"s\">`turn ${<\/span><span class=\"n\">turn<\/span><span class=\"s\">}: ${<\/span><span class=\"n\">call<\/span>.<span class=\"n\">name<\/span><span class=\"s\">}(${<\/span><span class=\"n\">call<\/span>.<span class=\"nb\">arguments<\/span><span class=\"s\">}) -&gt; ${<\/span><span class=\"n\">result<\/span><span class=\"s\">}`<\/span>);<\/span>\n<span class=\"l\">      <span class=\"n\">messages<\/span>.<span class=\"n\">push<\/span>({ <span class=\"n\">type<\/span>: <span class=\"s\">\"function_call_output\"<\/span>, <span class=\"n\">call_id<\/span>: <span class=\"n\">call<\/span>.<span class=\"n\">call_id<\/span>, <span class=\"n\">output<\/span>: <span class=\"n\">result<\/span> });<\/span>\n<span class=\"l\">    }<\/span>\n<span class=\"l\">  }<\/span>\n<span class=\"l\">  <span class=\"k\">return<\/span> <span class=\"s\">\"Stopped: too many turns.\"<\/span>;<\/span>\n<span class=\"l\">}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">console<\/span>.<span class=\"n\">log<\/span>(<span class=\"s\">\"Answer:\"<\/span>, <span class=\"k\">await<\/span> <span class=\"n\">runAgent<\/span>(<span class=\"s\">\"Weather in Delhi and Atlantis?\"<\/span>));<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><\/div><pre><code>$ node agent_loop.mjs\nturn 1: get_weather({&quot;city&quot;:&quot;Delhi&quot;,&quot;unit&quot;:&quot;fahrenheit&quot;}) -&gt; {&quot;city&quot;:&quot;Delhi&quot;,&quot;temp&quot;:75,&quot;unit&quot;:&quot;fahrenheit&quot;}\nturn 1: get_weather({&quot;city&quot;:&quot;Atlantis&quot;,&quot;unit&quot;:&quot;celsius&quot;}) -&gt; {&quot;error&quot;:&quot;No weather data for &#x27;Atlantis&#x27;&quot;}\nAnswer: Delhi is 75\u00b0F. Sorry, I have no data for Atlantis (No weather data for &#x27;Atlantis&#x27;).<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 57, Col 1<\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>JavaScript<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Click the tabs to switch between Python and Node.js, then press <strong>\u25b6 Run<\/strong> to see the real output in the terminal.<\/p>\n<p>The important lines are the ones that change <code>messages<\/code>. After every model turn, we add the model&#8217;s tool calls to the history, then one <code>function_call_output<\/code> per call with the matching <code>call_id<\/code>. When the model returns no tool calls, the loop ends. The <code>max_turns<\/code> limit stops an agent that keeps calling tools forever.<\/p>\n\n<h2 id=\"parallel\">Parallel tool calls: several tools in one turn<\/h2>\n<p>In the Python run above, the model asked for <strong>two<\/strong> tools in one reply: the weather and the currency conversion. This is called <strong>parallel tool calling<\/strong>. The two calls do not depend on each other, so the model sends both at once and saves a full round trip.<\/p>\n\n<figure>\n<svg viewBox=\"0 0 900 260\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"Comparison of sequential tool calls needing three model turns and parallel tool calls needing two\">\n<rect width=\"900\" height=\"260\" fill=\"#0f1430\"\/>\n<g font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">\n<text x=\"30\" y=\"40\" font-size=\"18\" font-weight=\"700\" fill=\"#fff\">Sequential: 3 model turns<\/text>\n<rect x=\"30\" y=\"58\" width=\"120\" height=\"40\" rx=\"8\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"90\" y=\"83\" text-anchor=\"middle\">LLM<\/text>\n<rect x=\"170\" y=\"58\" width=\"150\" height=\"40\" rx=\"8\" fill=\"#13304f\" stroke=\"#61dafb\"\/><text x=\"245\" y=\"83\" text-anchor=\"middle\">get_weather<\/text>\n<rect x=\"340\" y=\"58\" width=\"120\" height=\"40\" rx=\"8\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"400\" y=\"83\" text-anchor=\"middle\">LLM<\/text>\n<rect x=\"480\" y=\"58\" width=\"150\" height=\"40\" rx=\"8\" fill=\"#13304f\" stroke=\"#61dafb\"\/><text x=\"555\" y=\"83\" text-anchor=\"middle\">convert_inr<\/text>\n<rect x=\"650\" y=\"58\" width=\"120\" height=\"40\" rx=\"8\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"710\" y=\"83\" text-anchor=\"middle\">LLM<\/text>\n<text x=\"790\" y=\"83\" fill=\"#a99bff\">answer<\/text>\n<text x=\"30\" y=\"150\" font-size=\"18\" font-weight=\"700\" fill=\"#fff\">Parallel: 2 model turns<\/text>\n<rect x=\"30\" y=\"180\" width=\"120\" height=\"40\" rx=\"8\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"90\" y=\"205\" text-anchor=\"middle\">LLM<\/text>\n<rect x=\"170\" y=\"164\" width=\"150\" height=\"34\" rx=\"8\" fill=\"#13304f\" stroke=\"#61dafb\"\/><text x=\"245\" y=\"186\" text-anchor=\"middle\">get_weather<\/text>\n<rect x=\"170\" y=\"204\" width=\"150\" height=\"34\" rx=\"8\" fill=\"#13304f\" stroke=\"#61dafb\"\/><text x=\"245\" y=\"226\" text-anchor=\"middle\">convert_inr<\/text>\n<rect x=\"340\" y=\"180\" width=\"120\" height=\"40\" rx=\"8\" fill=\"#1b2250\" stroke=\"#7c5cff\"\/><text x=\"400\" y=\"205\" text-anchor=\"middle\">LLM<\/text>\n<text x=\"480\" y=\"205\" fill=\"#a99bff\">answer, one round trip saved<\/text>\n<\/g>\n<\/svg>\n<figcaption>Parallel tool calls let the model request independent tools together, which makes agents faster and cheaper.<\/figcaption>\n<\/figure>\n\n<p>Your loop already supports this because it runs <em>every<\/em> call in the list. Two rules matter:<\/p>\n<ol>\n<li><strong>Answer every call.<\/strong> If the model made two calls, send two outputs. A missing output usually causes an API error.<\/li>\n<li><strong>Match by <code>call_id<\/code>, not by order.<\/strong> Two calls can use the same tool with different arguments, so the ID is the only safe way to pair results.<\/li>\n<\/ol>\n<p>If tools <em>depend<\/em> on each other (for example &#8220;find the user, then read their orders&#8221;), the model will call them one after another across turns. If your tools must never run together, OpenAI lets you set <code>parallel_tool_calls=False<\/code>.<\/p>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"errors\">Handling tool errors safely<\/h2>\n<p>Tools fail all the time: a city is not found, an API times out, or the model sends bad arguments. A beginner mistake is to let the exception crash the whole agent. A better pattern is to <strong>catch the error and send it back to the model as the tool result<\/strong>. The model reads it and can retry with fixed arguments, ask the user a question or explain the problem. You saw this in the Node.js tab above: Atlantis was not found, and the model still gave a useful answer.<\/p>\n<p>Even with strict schemas, check arguments yourself before running anything important (payments, deletes, emails). Here is a small validator you can run:<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: validate.py\">\n<input type=\"radio\" name=\"v3\" id=\"v3f1\" class=\"f1\" checked>\n<input type=\"checkbox\" id=\"v3r1\" class=\"r1\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">validate.py \u2014 agentic-ai-part3 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v3f1\" class=\"t1\"><b class=\"ic py\">PY<\/b>validate.py<\/label>\n<label for=\"v3r1\" class=\"run run1\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a validate.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Check the model's arguments before running a tool.<\/span><\/span>\n<span class=\"l\"><span class=\"kn\">import<\/span> json<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">SCHEMA<\/span> = {<span class=\"s\">\"required\"<\/span>: [<span class=\"s\">\"amount\"<\/span>, <span class=\"s\">\"to\"<\/span>], <span class=\"s\">\"allowed_to\"<\/span>: [<span class=\"s\">\"USD\"<\/span>, <span class=\"s\">\"EUR\"<\/span>, <span class=\"s\">\"GBP\"<\/span>]}<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">validate_convert<\/span>(<span class=\"n\">raw_arguments<\/span>):<\/span>\n<span class=\"l\">    <span class=\"k\">try<\/span>:<\/span>\n<span class=\"l\">        <span class=\"n\">args<\/span> = <span class=\"n\">json<\/span>.<span class=\"n\">loads<\/span>(<span class=\"n\">raw_arguments<\/span>)<\/span>\n<span class=\"l\">    <span class=\"k\">except<\/span> <span class=\"n\">json<\/span>.<span class=\"n\">JSONDecodeError<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>, <span class=\"s\">\"Arguments were not valid JSON\"<\/span><\/span>\n<span class=\"l\">    <span class=\"n\">missing<\/span> = [<span class=\"n\">k<\/span> <span class=\"k\">for<\/span> <span class=\"n\">k<\/span> in <span class=\"n\">SCHEMA<\/span>[<span class=\"s\">\"required\"<\/span>] <span class=\"k\">if<\/span> <span class=\"n\">k<\/span> not in <span class=\"n\">args<\/span>]<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> <span class=\"n\">missing<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>, <span class=\"s\">f\"Missing argument(s): {', '<\/span>.<span class=\"n\">join<\/span>(<span class=\"n\">missing<\/span>)<span class=\"s\">}\"<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> not <span class=\"nb\">isinstance<\/span>(<span class=\"n\">args<\/span>[<span class=\"s\">\"amount\"<\/span>], (<span class=\"nb\">int<\/span>, <span class=\"nb\">float<\/span>)) or <span class=\"n\">args<\/span>[<span class=\"s\">\"amount\"<\/span>] &lt;= <span class=\"m\">0<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>, <span class=\"s\">\"amount must be a positive number\"<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> <span class=\"n\">args<\/span>[<span class=\"s\">\"to\"<\/span>] not in <span class=\"n\">SCHEMA<\/span>[<span class=\"s\">\"allowed_to\"<\/span>]:<\/span>\n<span class=\"l\">        <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>, <span class=\"s\">f\"to must be one of {<\/span><span class=\"n\">SCHEMA<\/span>[<span class=\"s\">'allowed_to'<\/span>]<span class=\"s\">}\"<\/span><\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> <span class=\"n\">args<\/span>, <span class=\"kc\">None<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">tests<\/span> = [<span class=\"s\">'{\"amount\": 1000, \"to\": \"EUR\"}'<\/span>,<\/span>\n<span class=\"l\">         <span class=\"s\">'{\"amount\": -5, \"to\": \"USD\"}'<\/span>,<\/span>\n<span class=\"l\">         <span class=\"s\">'{\"to\": \"JPY\"}'<\/span>,<\/span>\n<span class=\"l\">         <span class=\"s\">'{amount: 10}'<\/span>]<\/span>\n<span class=\"l\"><span class=\"k\">for<\/span> <span class=\"n\">raw<\/span> in <span class=\"n\">tests<\/span>:<\/span>\n<span class=\"l\">    <span class=\"n\">args<\/span>, <span class=\"n\">error<\/span> = <span class=\"n\">validate_convert<\/span>(<span class=\"n\">raw<\/span>)<\/span>\n<span class=\"l\">    <span class=\"nb\">print<\/span>(<span class=\"s\">f\"{<\/span><span class=\"n\">raw<\/span><span class=\"s\">:32} -&gt; {'OK '<\/span> + <span class=\"nb\">str<\/span>(<span class=\"n\">args<\/span>) <span class=\"k\">if<\/span> <span class=\"n\">args<\/span> <span class=\"k\">else<\/span> <span class=\"s\">'ERROR: '<\/span> + <span class=\"n\">error<\/span><span class=\"s\">}\"<\/span>)<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><\/div><pre><code>$ python validate.py\n{&quot;amount&quot;: 1000, &quot;to&quot;: &quot;EUR&quot;}    -&gt; OK {&#x27;amount&#x27;: 1000, &#x27;to&#x27;: &#x27;EUR&#x27;}\n{&quot;amount&quot;: -5, &quot;to&quot;: &quot;USD&quot;}      -&gt; ERROR: amount must be a positive number\n{&quot;to&quot;: &quot;JPY&quot;}                    -&gt; ERROR: Missing argument(s): amount\n{amount: 10}                     -&gt; ERROR: Arguments were not valid JSON<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 26, Col 1<\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Press <strong>\u25b6 Run<\/strong> to see which arguments pass and which are rejected.<\/p>\n<div class=\"dd-warn\"><strong>Safety first:<\/strong> the model chooses the arguments, and its input may include text from users, web pages or emails. Treat tool arguments like any user input: validate them, limit what each tool can do, and ask a human before risky actions. We cover this in depth in Part 22 (Agent Security).<\/div>\n\n<h2 id=\"real\">Tool calling with the OpenAI and Claude APIs<\/h2>\n<p>Once the loop makes sense, connecting a real model is easy. Install the official SDKs:<\/p>\n<div class=\"dd-vsc dd-vsc-termonly\" role=\"group\" aria-label=\"Terminal: Terminal \u2014 install the SDKs\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">Terminal \u2014 install the SDKs<\/span><\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Python<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> pip install openai anthropic<\/span>\n<span class=\"l\"><span class=\"c\"># Node.js<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> npm install openai @anthropic-ai\/sdk<\/span>\n<span class=\"l\"><span class=\"c\"># Set your keys (macOS\/Linux; on Windows use \"set\")<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> export OPENAI_API_KEY=\"sk-...\"<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> export ANTHROPIC_API_KEY=\"sk-ant-...\"<\/span><\/code><\/pre>\n<\/div>\n<p>The two tabs below run the same weather tool with the <a href=\"https:\/\/platform.openai.com\/docs\/guides\/function-calling\" rel=\"noopener\" target=\"_blank\">OpenAI Responses API<\/a> and with <a href=\"https:\/\/docs.claude.com\/en\/docs\/agents-and-tools\/tool-use\/overview\" rel=\"noopener\" target=\"_blank\">Anthropic&#8217;s tool use API<\/a>. Both reuse <code>tools.py<\/code> from earlier. Model names change often, so use any current tool-capable model from your provider&#8217;s model list.<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: openai_tools.py, claude_tools.py\">\n<input type=\"radio\" name=\"v5\" id=\"v5f1\" class=\"f1\" checked>\n<input type=\"radio\" name=\"v5\" id=\"v5f2\" class=\"f2\">\n<input type=\"checkbox\" id=\"v5r1\" class=\"r1\">\n<input type=\"checkbox\" id=\"v5r2\" class=\"r2\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">2 files \u2014 agentic-ai-part3 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v5f1\" class=\"t1\"><b class=\"ic py\">PY<\/b>openai_tools.py<\/label>\n<label for=\"v5f2\" class=\"t2\"><b class=\"ic py\">PY<\/b>claude_tools.py<\/label>\n<label for=\"v5r1\" class=\"run run1\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<label for=\"v5r2\" class=\"run run2\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a openai_tools.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Real tool calling with the OpenAI Responses API (pip install openai).<\/span><\/span>\n<span class=\"l\"><span class=\"kn\">import<\/span> json<\/span>\n<span class=\"l\"><span class=\"kn\">from<\/span> openai <span class=\"kn\">import<\/span> <span class=\"n\">OpenAI<\/span><\/span>\n<span class=\"l\"><span class=\"kn\">from<\/span> tools <span class=\"kn\">import<\/span> <span class=\"n\">TOOLS<\/span>, <span class=\"n\">FUNCTIONS<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">client<\/span> = <span class=\"n\">OpenAI<\/span>()  <span class=\"c\"># reads OPENAI_API_KEY from your environment<\/span><\/span>\n<span class=\"l\"><span class=\"n\">MODEL<\/span> = <span class=\"s\">\"gpt-6-luna\"<\/span>  <span class=\"c\"># any tool-capable model from your model list<\/span><\/span>\n<span class=\"l\"><span class=\"n\">history<\/span> = [{<span class=\"s\">\"role\"<\/span>: <span class=\"s\">\"user\"<\/span>, <span class=\"s\">\"content\"<\/span>: <span class=\"s\">\"What's the weather in London in celsius?\"<\/span>}]<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">response<\/span> = <span class=\"n\">client<\/span>.<span class=\"n\">responses<\/span>.<span class=\"n\">create<\/span>(<span class=\"n\">model<\/span>=<span class=\"n\">MODEL<\/span>, <span class=\"nb\">input<\/span>=<span class=\"n\">history<\/span>, <span class=\"n\">tools<\/span>=<span class=\"n\">TOOLS<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">for<\/span> <span class=\"n\">item<\/span> in <span class=\"n\">response<\/span>.<span class=\"n\">output<\/span>:<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> <span class=\"n\">item<\/span>.<span class=\"n\">type<\/span> == <span class=\"s\">\"function_call\"<\/span>:<\/span>\n<span class=\"l\">        <span class=\"n\">args<\/span> = <span class=\"n\">json<\/span>.<span class=\"n\">loads<\/span>(<span class=\"n\">item<\/span>.<span class=\"n\">arguments<\/span>)<\/span>\n<span class=\"l\">        <span class=\"n\">result<\/span> = <span class=\"n\">FUNCTIONS<\/span>[<span class=\"n\">item<\/span>.<span class=\"n\">name<\/span>](**<span class=\"n\">args<\/span>)<\/span>\n<span class=\"l\">        <span class=\"nb\">print<\/span>(<span class=\"s\">\"Model asked for:\"<\/span>, <span class=\"n\">item<\/span>.<span class=\"n\">name<\/span>, <span class=\"n\">args<\/span>)<\/span>\n<span class=\"l\">        <span class=\"n\">history<\/span>.<span class=\"n\">append<\/span>(<span class=\"n\">item<\/span>)  <span class=\"c\"># the call itself must stay in the history<\/span><\/span>\n<span class=\"l\">        <span class=\"n\">history<\/span>.<span class=\"n\">append<\/span>({<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"function_call_output\"<\/span>,<\/span>\n<span class=\"l\">                        <span class=\"s\">\"call_id\"<\/span>: <span class=\"n\">item<\/span>.<span class=\"n\">call_id<\/span>,<\/span>\n<span class=\"l\">                        <span class=\"s\">\"output\"<\/span>: <span class=\"n\">json<\/span>.<span class=\"n\">dumps<\/span>(<span class=\"n\">result<\/span>)})<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">final<\/span> = <span class=\"n\">client<\/span>.<span class=\"n\">responses<\/span>.<span class=\"n\">create<\/span>(<span class=\"n\">model<\/span>=<span class=\"n\">MODEL<\/span>, <span class=\"nb\">input<\/span>=<span class=\"n\">history<\/span>, <span class=\"n\">tools<\/span>=<span class=\"n\">TOOLS<\/span>)<\/span>\n<span class=\"l\"><span class=\"nb\">print<\/span>(<span class=\"s\">\"Answer:\"<\/span>, <span class=\"n\">final<\/span>.<span class=\"n\">output_text<\/span>)<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><span class=\"dd-term-note\">Example output \u2013 needs an API key; wording varies<\/span><\/div><pre><code>$ python openai_tools.py\nModel asked for: get_weather {&#x27;city&#x27;: &#x27;London&#x27;, &#x27;unit&#x27;: &#x27;celsius&#x27;}\nAnswer: It&#x27;s currently about 11\u00b0C in London.<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 23, Col 1<\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p2\">\n<div class=\"dd-vsc-crumbs\">agentic-ai-part3 \u203a claude_tools.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># The same idea with Anthropic Claude (pip install anthropic).<\/span><\/span>\n<span class=\"l\"><span class=\"kn\">import<\/span> json<\/span>\n<span class=\"l\"><span class=\"kn\">import<\/span> anthropic<\/span>\n<span class=\"l\"><span class=\"kn\">from<\/span> tools <span class=\"kn\">import<\/span> <span class=\"n\">TOOLS<\/span>, <span class=\"n\">FUNCTIONS<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">client<\/span> = <span class=\"n\">anthropic<\/span>.<span class=\"n\">Anthropic<\/span>()  <span class=\"c\"># reads ANTHROPIC_API_KEY<\/span><\/span>\n<span class=\"l\"><span class=\"n\">MODEL<\/span> = <span class=\"s\">\"claude-sonnet-4-5\"<\/span>  <span class=\"c\"># any current Claude model works<\/span><\/span>\n<span class=\"l\"><span class=\"c\"># Claude uses \"input_schema\" instead of \"parameters\".<\/span><\/span>\n<span class=\"l\"><span class=\"n\">claude_tools<\/span> = [{<span class=\"s\">\"name\"<\/span>: <span class=\"n\">t<\/span>[<span class=\"s\">\"name\"<\/span>], <span class=\"s\">\"description\"<\/span>: <span class=\"n\">t<\/span>[<span class=\"s\">\"description\"<\/span>],<\/span>\n<span class=\"l\">                 <span class=\"s\">\"input_schema\"<\/span>: <span class=\"n\">t<\/span>[<span class=\"s\">\"parameters\"<\/span>]} <span class=\"k\">for<\/span> <span class=\"n\">t<\/span> in <span class=\"n\">TOOLS<\/span>]<\/span>\n<span class=\"l\"><span class=\"n\">messages<\/span> = [{<span class=\"s\">\"role\"<\/span>: <span class=\"s\">\"user\"<\/span>, <span class=\"s\">\"content\"<\/span>: <span class=\"s\">\"What's the weather in London in celsius?\"<\/span>}]<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">reply<\/span> = <span class=\"n\">client<\/span>.<span class=\"n\">messages<\/span>.<span class=\"n\">create<\/span>(<span class=\"n\">model<\/span>=<span class=\"n\">MODEL<\/span>, <span class=\"n\">max_tokens<\/span>=<span class=\"m\">1024<\/span>,<\/span>\n<span class=\"l\">                               <span class=\"n\">tools<\/span>=<span class=\"n\">claude_tools<\/span>, <span class=\"n\">messages<\/span>=<span class=\"n\">messages<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">if<\/span> <span class=\"n\">reply<\/span>.<span class=\"n\">stop_reason<\/span> == <span class=\"s\">\"tool_use\"<\/span>:<\/span>\n<span class=\"l\">    <span class=\"n\">messages<\/span>.<span class=\"n\">append<\/span>({<span class=\"s\">\"role\"<\/span>: <span class=\"s\">\"assistant\"<\/span>, <span class=\"s\">\"content\"<\/span>: <span class=\"n\">reply<\/span>.<span class=\"n\">content<\/span>})<\/span>\n<span class=\"l\">    <span class=\"n\">results<\/span> = []<\/span>\n<span class=\"l\">    <span class=\"k\">for<\/span> <span class=\"n\">block<\/span> in <span class=\"n\">reply<\/span>.<span class=\"n\">content<\/span>:<\/span>\n<span class=\"l\">        <span class=\"k\">if<\/span> <span class=\"n\">block<\/span>.<span class=\"n\">type<\/span> == <span class=\"s\">\"tool_use\"<\/span>:<\/span>\n<span class=\"l\">            <span class=\"nb\">print<\/span>(<span class=\"s\">\"Model asked for:\"<\/span>, <span class=\"n\">block<\/span>.<span class=\"n\">name<\/span>, <span class=\"n\">block<\/span>.<span class=\"n\">input<\/span>)<\/span>\n<span class=\"l\">            <span class=\"n\">out<\/span> = <span class=\"n\">FUNCTIONS<\/span>[<span class=\"n\">block<\/span>.<span class=\"n\">name<\/span>](**<span class=\"n\">block<\/span>.<span class=\"n\">input<\/span>)<\/span>\n<span class=\"l\">            <span class=\"n\">results<\/span>.<span class=\"n\">append<\/span>({<span class=\"s\">\"type\"<\/span>: <span class=\"s\">\"tool_result\"<\/span>, <span class=\"s\">\"tool_use_id\"<\/span>: <span class=\"n\">block<\/span>.<span class=\"n\">id<\/span>,<\/span>\n<span class=\"l\">                            <span class=\"s\">\"content\"<\/span>: <span class=\"n\">json<\/span>.<span class=\"n\">dumps<\/span>(<span class=\"n\">out<\/span>)})<\/span>\n<span class=\"l\">    <span class=\"n\">messages<\/span>.<span class=\"n\">append<\/span>({<span class=\"s\">\"role\"<\/span>: <span class=\"s\">\"user\"<\/span>, <span class=\"s\">\"content\"<\/span>: <span class=\"n\">results<\/span>})<\/span>\n<span class=\"l\">    <span class=\"n\">reply<\/span> = <span class=\"n\">client<\/span>.<span class=\"n\">messages<\/span>.<span class=\"n\">create<\/span>(<span class=\"n\">model<\/span>=<span class=\"n\">MODEL<\/span>, <span class=\"n\">max_tokens<\/span>=<span class=\"m\">1024<\/span>,<\/span>\n<span class=\"l\">                                   <span class=\"n\">tools<\/span>=<span class=\"n\">claude_tools<\/span>, <span class=\"n\">messages<\/span>=<span class=\"n\">messages<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">print<\/span>(<span class=\"s\">\"Answer:\"<\/span>, <span class=\"n\">reply<\/span>.<span class=\"n\">content<\/span>[<span class=\"m\">0<\/span>].<span class=\"n\">text<\/span>)<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><span class=\"dd-term-note\">Example output \u2013 needs an API key; wording varies<\/span><\/div><pre><code>$ python claude_tools.py\nModel asked for: get_weather {&#x27;city&#x27;: &#x27;London&#x27;, &#x27;unit&#x27;: &#x27;celsius&#x27;}\nAnswer: It&#x27;s currently 11\u00b0C in London.<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span class=\"sp\"><\/span><span>Ln 29, Col 1<\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Switch between the OpenAI and Claude tabs to compare the two APIs. Press <strong>\u25b6 Run<\/strong> for example output.<\/p>\n\n<div class=\"dd-tablewrap\"><table>\n<thead><tr><th>Idea<\/th><th>OpenAI Responses API<\/th><th>Anthropic Messages API<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>Tool schema field<\/td><td><code>parameters<\/code><\/td><td><code>input_schema<\/code><\/td><\/tr>\n<tr><td>Model asks for a tool<\/td><td>output item <code>type: \"function_call\"<\/code><\/td><td>content block <code>type: \"tool_use\"<\/code>, <code>stop_reason: \"tool_use\"<\/code><\/td><\/tr>\n<tr><td>Arguments<\/td><td><code>arguments<\/code> (JSON string, parse it)<\/td><td><code>input<\/code> (already a dict\/object)<\/td><\/tr>\n<tr><td>Call ID<\/td><td><code>call_id<\/code><\/td><td><code>id<\/code><\/td><\/tr>\n<tr><td>Send the result<\/td><td>input item <code>function_call_output<\/code><\/td><td><code>tool_result<\/code> block in a user message<\/td><\/tr>\n<\/tbody><\/table><\/div>\n\n<h2 id=\"choice\">Controlling when tools are used<\/h2>\n<p>By default the model decides by itself whether to call a tool (<code>tool_choice=\"auto\"<\/code>). You can change this:<\/p>\n<ul>\n<li><strong><code>\"auto\"<\/code><\/strong> \u2013 the model picks a tool or answers directly. Best for most agents.<\/li>\n<li><strong><code>\"required\"<\/code><\/strong> (OpenAI) \/ <strong><code>{\"type\": \"any\"}<\/code><\/strong> (Claude) \u2013 the model must call at least one tool. Useful for extraction tasks.<\/li>\n<li><strong>A specific tool<\/strong> \u2013 force one tool, for example always call <code>save_lead<\/code> to get structured data.<\/li>\n<li><strong><code>\"none\"<\/code><\/strong> \u2013 no tools this turn, just text.<\/li>\n<\/ul>\n<div class=\"dd-tip\"><strong>Tip:<\/strong> if your agent calls tools too often or too rarely, fix the <em>descriptions<\/em> first. Clear &#8220;use this when\u2026&#8221; sentences work better than forcing <code>tool_choice<\/code>. Part 6 of this series is all about writing good tool descriptions.<\/div>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"fixes\">Common errors and fixes<\/h2>\n<div class=\"dd-tablewrap\"><table>\n<thead><tr><th>Error or symptom<\/th><th>Why it happens<\/th><th>Fix<\/th><\/tr><\/thead>\n<tbody>\n<tr><td><code>No tool call found for function call output with call_id \u2026<\/code><\/td><td>You sent the result but not the original <code>function_call<\/code> item.<\/td><td>Append the model&#8217;s tool call to the history before the output (or use <code>previous_response_id<\/code>).<\/td><\/tr>\n<tr><td><code>TypeError: string indices must be integers<\/code><\/td><td><code>arguments<\/code> is a JSON string, not a dict.<\/td><td>Run <code>json.loads()<\/code> \/ <code>JSON.parse()<\/code> first.<\/td><\/tr>\n<tr><td>Strict schema rejected<\/td><td>Strict mode needs <code>additionalProperties: false<\/code> and all fields in <code>required<\/code>.<\/td><td>Add both; make optional fields nullable, e.g. <code>\"type\": [\"string\", \"null\"]<\/code>.<\/td><\/tr>\n<tr><td>Agent loops forever<\/td><td>The model keeps calling tools, often because a tool keeps failing.<\/td><td>Set <code>max_turns<\/code> and return clear error messages.<\/td><\/tr>\n<tr><td>Model ignores your tool<\/td><td>Vague name or description.<\/td><td>Use a clear verb name (<code>get_order_status<\/code>) and say when to use it.<\/td><\/tr>\n<tr><td>Tool result is huge<\/td><td>You returned a full API response or file.<\/td><td>Return only the fields the model needs; this saves tokens.<\/td><\/tr>\n<\/tbody><\/table><\/div>\n\n<h2 id=\"best\">Best practices for tool calling<\/h2>\n<ul>\n<li><strong>Keep tools small and focused.<\/strong> One clear job per tool. Start with 2\u20135 tools per agent.<\/li>\n<li><strong>Return strings the model can read.<\/strong> Short JSON with clear field names works best.<\/li>\n<li><strong>Always return something.<\/strong> On failure, return <code>{\"error\": \"\u2026\"}<\/code> instead of raising.<\/li>\n<li><strong>Log every call.<\/strong> Print or store the tool name, arguments and result. It is the easiest way to debug an agent.<\/li>\n<li><strong>Use read-only tools first.<\/strong> Add tools that change data (send, pay, delete) only with validation and human approval.<\/li>\n<li><strong>Set limits.<\/strong> Maximum turns, timeouts on slow tools, and a size limit on results.<\/li>\n<\/ul>\n<p>Want to share tools between many apps and agents? That is exactly what the Model Context Protocol does. See our guide <a href=\"https:\/\/devdojo.co.in\/?p=164\">How to Build an MCP Server in TypeScript<\/a> (and Part 10 of this series). If you prefer a framework that runs the loop for you, read the <a href=\"https:\/\/devdojo.co.in\/?p=182\">OpenAI Agents SDK tutorial<\/a>.<\/p>\n\n<h2 id=\"practice\">Practice task<\/h2>\n<div class=\"dd-card\">\n<b>Add a third tool to the agent<\/b>\n<ol>\n<li>In <code>tools.py<\/code>, add a new tool such as <code>count_words(text)<\/code> that returns the number of words in a text.<\/li>\n<li>Write its schema with a clear description, <code>required<\/code> fields and <code>\"additionalProperties\": False<\/code>.<\/li>\n<li>Change <code>fake_model()<\/code> so it asks for your new tool, then run <code>agent_loop.py<\/code> and check the printed log.<\/li>\n<li>Bonus: make your tool raise an error for bad input and confirm the agent still finishes with a helpful answer.<\/li>\n<\/ol>\n<\/div>\n\n<h2 id=\"faq\">FAQ<\/h2>\n<details><summary>Does the LLM run my function?<\/summary><p>No. The model only returns the tool name and arguments. Your code runs the function and sends the result back. This keeps you in control of security and side effects.<\/p><\/details>\n<details><summary>Is function calling the same as tool calling?<\/summary><p>Yes. &#8220;Function calling&#8221; is the older OpenAI name. &#8220;Tool calling&#8221; or &#8220;tool use&#8221; is the general term used by most providers today.<\/p><\/details>\n<details><summary>Which models support tool calling?<\/summary><p>All major modern LLMs from OpenAI, Anthropic, Google and most open models (for example through Ollama) support it. Check the model&#8217;s docs for &#8220;tools&#8221; or &#8220;function calling&#8221; support.<\/p><\/details>\n<details><summary>What does strict mode do?<\/summary><p>In the OpenAI API, <code>\"strict\": true<\/code> makes the model&#8217;s arguments always match your JSON Schema exactly. You still need to validate business rules, like &#8220;amount must be positive&#8221;.<\/p><\/details>\n<details><summary>How many tools can I give one agent?<\/summary><p>Technically many, but accuracy drops as the list grows and every tool definition costs tokens. Start with a few focused tools and split big jobs across several agents later.<\/p><\/details>\n<details><summary>Can a model call tools in parallel?<\/summary><p>Yes. Modern models can return several tool calls in one turn. Run them all (even at the same time with threads or <code>Promise.all<\/code>) and return one result per <code>call_id<\/code>.<\/p><\/details>\n\n<details class=\"dd-roadmap\">\n<summary>Full Agentic AI roadmap (30 parts)<\/summary>\n<h4>Beginner<\/h4>\n<ol start=\"1\">\n<li><a href=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/20\/agentic-ai-series-part-1-what-is-agentic-ai\/\">What Is Agentic AI and How Do AI Agents Work?<\/a><\/li>\n<li><a href=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/27\/agentic-ai-series-part-2-anatomy-of-an-ai-agent\/\">Anatomy of an AI Agent: Models, Tools, Instructions and Memory<\/a><\/li>\n<li>Tool Calling for Agents: Letting an LLM Use Your Functions <span class=\"here\">You are here<\/span><\/li>\n<li>Build Your First AI Agent from Scratch in Python (No Framework) <span class=\"soon\">Coming soon<\/span><\/li>\n<li>The ReAct Pattern: Reason, Act, Observe in Practice <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Writing Good Agent Instructions and Tool Descriptions <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Agent Memory: Short-Term, Long-Term and Scratchpads <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Planning Agents: Breaking Big Goals into Steps <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<h4>Intermediate<\/h4>\n<ol start=\"9\">\n<li>Workflow Patterns: Chaining, Routing and Parallel Steps <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Model Context Protocol (MCP): Connecting Agents to Tools and Data <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Agent Frameworks Compared: OpenAI Agents SDK, LangGraph, Claude Agent SDK and More <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Building Stateful Agents with LangGraph <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Agentic RAG: Agents That Search, Read and Cite <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Browser and Computer-Use Agents <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Coding Agents: How AI Writes, Runs and Fixes Code <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Human-in-the-Loop: Approvals, Interrupts and Checkpoints <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Multi-Agent Systems: Handoffs, Supervisors and Teams <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Agent-to-Agent Communication with the A2A Protocol <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Guardrails and Structured Outputs for Agents <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Tracing and Debugging Agents <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<h4>Advanced<\/h4>\n<ol start=\"21\">\n<li>Evaluating Agents: Task Success, Trajectories and Test Suites <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Agent Security: Prompt Injection, Permissions and Sandboxing <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Controlling Agent Cost and Latency <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Long-Running Agents: Queues, Retries and Durable Execution <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Deep Research Agents: Search, Synthesise and Report <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Reflection and Self-Correcting Agents <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Voice and Real-Time Agents <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Deploying Agents to Production: APIs, Serverless and Containers <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Monitoring and Improving Agents in Production <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Final Project: Build a Multi-Agent Developer Assistant <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<\/details>\n\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Tool calling is what turns an LLM into an agent. The model reads your tool descriptions, asks for a function with JSON arguments, and your code runs it and returns the result. You built the full loop in Python and Node.js, handled parallel calls and errors, and saw how the same pattern maps to the OpenAI and Claude APIs. Keep this loop in mind: almost every agent framework you will meet later is a polished version of these 40 lines.<\/p>\n\n<div class=\"dd-next\"><strong>Next part \u2013 Agentic AI Part 4: Build Your First AI Agent from Scratch in Python (No Framework).<\/strong> We will combine the model, tools, instructions and memory into one small but complete agent you can chat with in the terminal.<\/div>\n\n<div class=\"dd-cta\">\n<h3>New posts every day on DevDojo<\/h3>\n<p>Follow the full <strong>Agentic AI series<\/strong> \u2013 30 parts from &#8220;what is an agent&#8221; to a multi-agent developer assistant. Bookmark <a href=\"https:\/\/devdojo.co.in\/\">devdojo.co.in<\/a> and tell us in the comments which tool you will give your first agent.<\/p>\n<\/div>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.<\/p>\n","protected":false},"author":1,"featured_media":286,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38],"tags":[119,42,150,43,90,52,118,120],"class_list":["post-287","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","tag-agentic-ai","tag-ai-agents","tag-function-calling","tag-node-js","tag-openai-api","tag-python","tag-series-agentic-ai","tag-tool-calling"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Lokendra\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"DevDojo - Empowering Developers\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Tool Calling for AI Agents: Let an LLM Use Your Functions\" \/>\n\t\t<meta property=\"og:description\" content=\"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-11-03T14:01:57+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-11-03T14:01:58+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Tool Calling for AI Agents: Let an LLM Use Your Functions\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BlogPosting\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#blogposting\",\"name\":\"Tool Calling for AI Agents: LLM Function Calling Guide\",\"headline\":\"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions\",\"author\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/agentic-ai-series-part-3-tool-calling.jpg\",\"width\":1200,\"height\":630,\"caption\":\"Agentic AI Part 3 banner: tool calling for AI agents - the LLM requests a tool, your code runs it and returns the result\"},\"datePublished\":\"2026-11-03T14:01:57+00:00\",\"dateModified\":\"2026-11-03T14:01:58+00:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#webpage\"},\"articleSection\":\"AI, Agentic AI, AI Agents, Function Calling, Node.js, OpenAI API, Python, Series: Agentic AI, Tool Calling\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/devdojo.co.in\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/ai\\\/#listItem\",\"name\":\"AI\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/ai\\\/#listItem\",\"position\":2,\"name\":\"AI\",\"item\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/ai\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#listItem\",\"name\":\"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#listItem\",\"position\":3,\"name\":\"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/ai\\\/#listItem\",\"name\":\"AI\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\",\"name\":\"DevDojo\",\"description\":\"Empowering Developers\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/\",\"name\":\"Lokendra\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/99f102f0cc9080237ce54b91304fd1b3b6fa29925cbaeba93cd796872e58b45c?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Lokendra\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#webpage\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/\",\"name\":\"Tool Calling for AI Agents: LLM Function Calling Guide\",\"description\":\"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/agentic-ai-series-part-3-tool-calling.jpg\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#mainImage\",\"width\":1200,\"height\":630,\"caption\":\"Agentic AI Part 3 banner: tool calling for AI agents - the LLM requests a tool, your code runs it and returns the result\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/11\\\/03\\\/agentic-ai-series-part-3-tool-calling\\\/#mainImage\"},\"datePublished\":\"2026-11-03T14:01:57+00:00\",\"dateModified\":\"2026-11-03T14:01:58+00:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#website\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/\",\"name\":\"DevDojo\",\"description\":\"Empowering Developers\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Tool Calling for AI Agents: LLM Function Calling Guide","description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.","canonical_url":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BlogPosting","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#blogposting","name":"Tool Calling for AI Agents: LLM Function Calling Guide","headline":"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions","author":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"publisher":{"@id":"https:\/\/devdojo.co.in\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/devdojo.co.in\/wp-content\/uploads\/2026\/11\/agentic-ai-series-part-3-tool-calling.jpg","width":1200,"height":630,"caption":"Agentic AI Part 3 banner: tool calling for AI agents - the LLM requests a tool, your code runs it and returns the result"},"datePublished":"2026-11-03T14:01:57+00:00","dateModified":"2026-11-03T14:01:58+00:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#webpage"},"isPartOf":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#webpage"},"articleSection":"AI, Agentic AI, AI Agents, Function Calling, Node.js, OpenAI API, Python, Series: Agentic AI, Tool Calling"},{"@type":"BreadcrumbList","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/#listItem","position":1,"name":"Home","item":"https:\/\/devdojo.co.in\/","nextItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/ai\/#listItem","name":"AI"}},{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/ai\/#listItem","position":2,"name":"AI","item":"https:\/\/devdojo.co.in\/index.php\/category\/ai\/","nextItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#listItem","name":"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions"},"previousItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#listItem","position":3,"name":"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions","previousItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/ai\/#listItem","name":"AI"}}]},{"@type":"Organization","@id":"https:\/\/devdojo.co.in\/#organization","name":"DevDojo","description":"Empowering Developers","url":"https:\/\/devdojo.co.in\/"},{"@type":"Person","@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author","url":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/","name":"Lokendra","image":{"@type":"ImageObject","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/99f102f0cc9080237ce54b91304fd1b3b6fa29925cbaeba93cd796872e58b45c?s=96&d=mm&r=g","width":96,"height":96,"caption":"Lokendra"}},{"@type":"WebPage","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#webpage","url":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/","name":"Tool Calling for AI Agents: LLM Function Calling Guide","description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/devdojo.co.in\/#website"},"breadcrumb":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#breadcrumblist"},"author":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"creator":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/devdojo.co.in\/wp-content\/uploads\/2026\/11\/agentic-ai-series-part-3-tool-calling.jpg","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#mainImage","width":1200,"height":630,"caption":"Agentic AI Part 3 banner: tool calling for AI agents - the LLM requests a tool, your code runs it and returns the result"},"primaryImageOfPage":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/#mainImage"},"datePublished":"2026-11-03T14:01:57+00:00","dateModified":"2026-11-03T14:01:58+00:00"},{"@type":"WebSite","@id":"https:\/\/devdojo.co.in\/#website","url":"https:\/\/devdojo.co.in\/","name":"DevDojo","description":"Empowering Developers","inLanguage":"en-US","publisher":{"@id":"https:\/\/devdojo.co.in\/#organization"}}]},"og:locale":"en_US","og:site_name":"DevDojo - Empowering Developers","og:type":"article","og:title":"Tool Calling for AI Agents: Let an LLM Use Your Functions","og:description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.","og:url":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/","article:published_time":"2026-11-03T14:01:57+00:00","article:modified_time":"2026-11-03T14:01:58+00:00","twitter:card":"summary_large_image","twitter:title":"Tool Calling for AI Agents: Let an LLM Use Your Functions","twitter:description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code."},"aioseo_meta_data":{"post_id":"287","title":"Tool Calling for AI Agents: LLM Function Calling Guide","description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.","keywords":null,"keyphrases":{"focus":{"keyphrase":"tool calling","score":82},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":"Tool Calling for AI Agents: Let an LLM Use Your Functions","og_description":"Learn tool calling for AI agents: let an LLM call your functions with JSON Schema, parallel calls and error handling. Agentic AI series Part 3 with code.","og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"BlogPosting","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":0,"frequency":"default","local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":{"subject":"","preview":"","content":""},"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"created":"2026-11-03 13:11:54","updated":"2026-11-03 14:04:06","focus_keyword":"tool calling","additional_keywords":null,"truseo_locale":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/devdojo.co.in\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/devdojo.co.in\/index.php\/category\/ai\/\" title=\"AI\">AI<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tAgentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/devdojo.co.in\/"},{"label":"AI","link":"https:\/\/devdojo.co.in\/index.php\/category\/ai\/"},{"label":"Agentic AI Part 3: Tool Calling for Agents: Letting an LLM Use Your Functions","link":"https:\/\/devdojo.co.in\/index.php\/2026\/11\/03\/agentic-ai-series-part-3-tool-calling\/"}],"_links":{"self":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/287","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/comments?post=287"}],"version-history":[{"count":1,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/287\/revisions"}],"predecessor-version":[{"id":288,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/287\/revisions\/288"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/media\/286"}],"wp:attachment":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=287"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/categories?post=287"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/tags?post=287"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}