{"id":411,"date":"2025-09-19T13:40:34","date_gmt":"2025-09-19T12:40:34","guid":{"rendered":"https:\/\/guillaumesblog.net\/?p=411"},"modified":"2025-09-19T14:48:21","modified_gmt":"2025-09-19T13:48:21","slug":"rapid-set-up-of-ai-agents-in-the-cloud","status":"publish","type":"post","link":"https:\/\/guillaumesblog.net\/index.php\/rapid-set-up-of-ai-agents-in-the-cloud\/","title":{"rendered":"Hook Your Tools Into Cloud AI Agents \u2014 Fast"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Everyone\u2019s talking about \u201cAgentic AI,\u201d so I decided to experiment. My goal: a custom agent that can leverage my data and tools, set up quickly in the cloud using OCI.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s imagine we want it to be a boss at calculus and we don&#8217;t want the agent and its embedded LLM to do it &#8211; because we know this is something they are (were?) bad at &#8211; We want to subcontract the &#8220;maths&#8221; to a &#8220;tool&#8221; so the LLM could decide to call on it autonomously if required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Disclaimer: This guide is for demonstration only, I assume you have a good comprehension of the cloud &amp; its setup, you know there is a cost involved and that I am not securing the APIs. You should always secure API in a production setting.<\/em> <em>I also trust that you know what you are doing about firewalls, VCN, subnets and the like. All of it is not the point here so I won&#8217;t address it.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is what we are going to do:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a simple back-end with 4 random maths functions and APIs.<\/li>\n\n\n\n<li>Launch the back-end.<\/li>\n\n\n\n<li>Create an agent on my cloud console.<\/li>\n\n\n\n<li>Register a tool now part of the agent capabilities.<\/li>\n\n\n\n<li>Prompt and verify function calling by the agent.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s go &#8211; Get your VM up, python, pip, venv, copy paste the <a href=\"https:\/\/github.com\/geddegda\/agentic_ai\/blob\/main\/script.py\">code<\/a> available in my repo and save the file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we want the APIs in our code to be reachable from the outside world via HTTPS. Install <a href=\"https:\/\/caddyserver.com\/\" data-type=\"link\" data-id=\"https:\/\/caddyserver.com\/\">Caddy<\/a> the super simple HTTPS reverse proxy, edit the caddy conf file at \/etc\/caddy\/Caddyfile this <a href=\"https:\/\/idroot.us\/install-caddy-ubuntu-24-04\/\">way<\/a> and start it up with systemctl. Caddy now reverse proxies to localhost:8000.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>couincouin.click<\/strong> {\n        root * \/usr\/share\/caddy\n        file_server\n        <strong>reverse_proxy localhost:8000<\/strong>\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Launch your python virtual env &#8211; if you are not sure more info <a href=\"https:\/\/fastapi.tiangolo.com\/virtual-environments\/\">here<\/a> &#8211; and launch script.py. You should get something like that showing up in the terminal&#8230; <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>(back-end-env) ubuntu@instance-gpu:~\/backend$ fastapi dev backend.py<\/strong>\n&#91;...]\n    server   Server started at http:\/\/127.0.0.1:8000\n    server   Documentation at http:\/\/127.0.0.1:8000\/docs\n&#91;...]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Last step is to attach my VM public IP to my domain as a A record &#8211; I will tell you why later &#8211; I end up with 4 APIs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/couincouin.click\/add\">https:\/\/couincouin.click\/add<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/couincouin.click\/subtract\">https:\/\/couincouin.click\/subtract<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/couincouin.click\/multiply\">https:\/\/couincouin.click\/multiply<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/couincouin.click\/divide\">https:\/\/couincouin.click\/divide<\/a><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"511\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-1024x511.png\" alt=\"\" class=\"wp-image-429\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-1024x511.png 1024w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-300x150.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-768x383.png 768w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-1536x766.png 1536w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website-1200x598.png 1200w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/fastapi_website.png 1578w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And we are done. Great, now let&#8217;s build the agent itself, shall we?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Go to <a href=\"https:\/\/www.oracle.com\/cloud\/sign-in.html\">OCI console<\/a> &gt; click on the hamburger menu &gt; Analytics and AI &gt; Generative AI agent &gt; Agents and create Agent. Give it a name and enter a fit for purpose system prompt, in my example &#8220;if you have to do a calculation, use the maths tool first and foremost&#8221;. Then, on the second screen you can add tools as you can see below; it can be a RAG related knowledge base, to shoot SQL from natural language to a target DB, connect a custom app (what I am doing now) or connect another Agent &#8211; super slick no? Select custom tool.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"193\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-1024x193.png\" alt=\"\" class=\"wp-image-430\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-1024x193.png 1024w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-300x57.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-768x145.png 768w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-1536x290.png 1536w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents-1200x227.png 1200w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/build_agents.png 1896w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It will then ask you about how to reach out to your app&#8217;s API. Enter the OpenAPI format of your app , select None for Auth (<strong>in my case there&#8217;s none,  but you make sure to secure your APIs in prod<\/strong>) and select a subnet you want the custom tool to shoot its request out from, highlighted in yellow below.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"668\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit-1024x668.png\" alt=\"\" class=\"wp-image-432\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit-1024x668.png 1024w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit-300x196.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit-768x501.png 768w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit-1200x783.png 1200w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths_edit.png 1303w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">At that stage, here are gour gotchas in the plumbing that cost me time&#8230;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>I&#8217;ve exported the OpenAPI format from couincouin.click\/openapi.json; it was 99% accurate but I had to add my domain to it wit the &#8220;servers&#8221; directive.<\/li>\n\n\n\n<li>It needs a domain, an IP address does not work. (for my setup at least)<\/li>\n\n\n\n<li>The public subnet you are tying the agent tool with needs to access the internet via a NAT gateway, not an Internet gateway.<\/li>\n\n\n\n<li>Endpoint needs to be HTTPS, not HTTP hence the use of caddy ealier.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Below the API format in purple you&#8217;d copy paste from your app and then the &#8220;maths&#8221; tool description with its subnet and the copy paste plus the <\/em>&#8220;<em>servers&#8221; directive.<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"631\" height=\"985\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/openapi_standard_3.1.0.png\" alt=\"\" class=\"wp-image-437\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/openapi_standard_3.1.0.png 631w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/openapi_standard_3.1.0-192x300.png 192w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"440\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-1024x440.png\" alt=\"\" class=\"wp-image-436\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-1024x440.png 1024w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-300x129.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-768x330.png 768w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-1536x659.png 1536w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths-1200x515.png 1200w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/maths.png 1903w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Wonderful! Now we end up with a fully functional agent, it is an agent that does calculus and it has a list of tools at its disposal, in my case only one, but could be hundreds, see below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"982\" height=\"556\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/agent_that_does_maths.png\" alt=\"\" class=\"wp-image-441\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/agent_that_does_maths.png 982w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/agent_that_does_maths-300x170.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/agent_that_does_maths-768x435.png 768w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s try it out! I ask a question to it on the left, please see below, and if it plans to use a tool &#8211; And it does! We see the server on the right receiving 4 request for add, subtract, multiply and divide in real-time.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"285\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-1024x285.png\" alt=\"\" class=\"wp-image-442\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-1024x285.png 1024w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-300x84.png 300w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-768x214.png 768w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-1536x428.png 1536w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api-1200x334.png 1200w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/calls_from_agent_to_api.png 1780w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you are still unsure I am showing you the trace for the first call below<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"730\" height=\"378\" src=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/a_call-1.png\" alt=\"\" class=\"wp-image-444\" srcset=\"https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/a_call-1.png 730w, https:\/\/guillaumesblog.net\/wp-content\/uploads\/2025\/09\/a_call-1-300x155.png 300w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And that\u2019s it \u2013 we\u2019ve shown end-to-end how to set up a cloud agent that can call our own tools, tailored to our needs. Now imagine the possibilities when a personal agent has access to hundreds of tools!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As a next step, we could also code the agent ourselves on our own VM or container using Ollama and the <a href=\"https:\/\/ollama.com\/blog\/functions-as-tools\">ollama library<\/a> &#8211; but its enough for now &#8211; see you later.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Everyone\u2019s talking about \u201cAgentic AI,\u201d so I decided to experiment. My goal: a custom agent that can leverage my data and tools, set up quickly in the cloud using OCI.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-411","post","type-post","status-publish","format-standard","hentry","category-conversation"],"_links":{"self":[{"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/posts\/411","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/comments?post=411"}],"version-history":[{"count":52,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/posts\/411\/revisions"}],"predecessor-version":[{"id":478,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/posts\/411\/revisions\/478"}],"wp:attachment":[{"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/media?parent=411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/categories?post=411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guillaumesblog.net\/index.php\/wp-json\/wp\/v2\/tags?post=411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}