{"id":3931,"date":"2025-11-24T10:00:00","date_gmt":"2025-11-24T15:00:00","guid":{"rendered":"https:\/\/www.mymiller.name\/wordpress\/?p=3931"},"modified":"2025-11-16T22:56:46","modified_gmt":"2025-11-17T03:56:46","slug":"advanced-spring-ai-creating-agentic-workflows-with-function-calling","status":"publish","type":"post","link":"https:\/\/www.mymiller.name\/wordpress\/uncategorized\/advanced-spring-ai-creating-agentic-workflows-with-function-calling\/","title":{"rendered":"Advanced Spring AI: Creating Agentic Workflows with Function Calling"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The landscape of AI is rapidly evolving, moving beyond simple request-response models to more sophisticated, agentic systems. These systems empower Large Language Models (LLMs) to not just generate text, but to <em>act<\/em> within your applications, making them an active and integral part of your business logic. Spring AI is at the forefront of this evolution, offering powerful capabilities for integrating LLMs into your Spring applications. Today, we&#8217;re going to dive deep into one of the most exciting features: <strong>function calling<\/strong>, and how it enables the creation of truly agentic workflows.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Beyond Text Generation: The Power of Function Calling<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Traditionally, an LLM might answer a query by generating a response based on its training data. But what if that answer requires real-time data or the execution of a specific business process? This is where function calling shines. Function calling allows you to expose your Spring service methods as &#8220;tools&#8221; that the LLM can invoke. The LLM, when faced with a query that can be best answered by executing one of these tools, will generate a structured call to that function, including any necessary parameters. Your application then intercepts this call, executes the corresponding service method, and feeds the result back to the LLM for further processing or final response generation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine an LLM that can not only tell you about product availability but can actually <em>check the inventory<\/em> in real-time, or even <em>place an order<\/em>. This is the power of agentic workflows enabled by function calling.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How it Works: A Spring AI Perspective<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s break down the core components of creating agentic workflows with Spring AI and function calling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Defining Your Tools (Spring Services):<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first step is to identify the business logic you want to expose to your LLM. These will typically be methods within your existing Spring services. Consider methods that perform actions, retrieve specific data, or interact with external systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Java<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Service\npublic class ProductService {\n\n    public String getProductAvailability(String productId) {\n        \/\/ Simulate checking a database or external API\n        if (\"PROD-001\".equals(productId)) {\n            return \"Product PROD-001 is in stock. Quantity: 10.\";\n        } else if (\"PROD-002\".equals(productId)) {\n            return \"Product PROD-002 is out of stock.\";\n        }\n        return \"Unknown product: \" + productId;\n    }\n\n    public String placeOrder(String productId, int quantity) {\n        \/\/ Simulate placing an order\n        if (quantity &gt; 0) {\n            return String.format(\"Order placed successfully for %d units of %s.\", quantity, productId);\n        }\n        return \"Cannot place order with zero or negative quantity.\";\n    }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Describing Your Tools for the LLM:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The LLM needs to understand what functions are available and how to use them. Spring AI provides a way to register these functions with the LLM model. You&#8217;ll typically define a <code>FunctionCallback<\/code> that describes the function&#8217;s name, description, and the parameters it expects. This description is crucial for the LLM to intelligently decide when and how to call your methods.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Java<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Configuration\npublic class FunctionConfig {\n\n    @Bean\n    public FunctionCallback productAvailabilityFunction(ProductService productService) {\n        return new FunctionCallbackWrapper&lt;ProductService.ProductAvailabilityRequest, String&gt;(\n            \"getProductAvailability\",\n            \"Gets the availability of a product by its ID\",\n            ProductService.ProductAvailabilityRequest.class,\n            request -&gt; productService.getProductAvailability(request.productId())\n        );\n    }\n\n    @Bean\n    public FunctionCallback placeOrderFunction(ProductService productService) {\n        return new FunctionCallbackWrapper&lt;ProductService.PlaceOrderRequest, String&gt;(\n            \"placeOrder\",\n            \"Places an order for a product with a specified quantity\",\n            ProductService.PlaceOrderRequest.class,\n            request -&gt; productService.placeOrder(request.productId(), request.quantity())\n        );\n    }\n\n    \/\/ Define record classes for function parameters\n    record ProductAvailabilityRequest(String productId) {}\n    record PlaceOrderRequest(String productId, int quantity) {}\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Orchestrating the Agentic Workflow:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, you&#8217;ll use the <code>ChatClient<\/code> from Spring AI, configured with your registered functions, to interact with the LLM. When a user&#8217;s prompt suggests the need for one of your exposed functions, the LLM will generate a <code>tool_code<\/code> message containing the function call. Your application then executes this function and sends the result back to the LLM as a <code>tool_response<\/code> message. This iterative process allows the LLM to continue the conversation with the newly acquired information.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Java<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@RestController\npublic class AgentController {\n\n    private final ChatClient chatClient;\n\n    public AgentController(ChatClient.Builder chatClientBuilder, List&lt;FunctionCallback&gt; functionCallbacks) {\n        this.chatClient = chatClientBuilder\n            .functionCallbacks(functionCallbacks)\n            .build();\n    }\n\n    @GetMapping(\"\/chat\")\n    public String chat(@RequestParam String message) {\n        PromptTemplate promptTemplate = new PromptTemplate(message);\n        ChatResponse response = chatClient.call(promptTemplate.create());\n\n        \/\/ The LLM might directly answer, or it might suggest a function call.\n        \/\/ Spring AI handles the orchestration of calling the function and feeding the result back.\n        \/\/ For a more advanced agent, you might need to inspect 'response.getCallArguments()'\n        \/\/ and manually invoke services if you're not using the automatic FunctionCallbackWrapper.\n\n        return response.getResult().getOutput().getContent();\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">A Practical Example: The Intelligent Shopping Assistant<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s envision a scenario: an intelligent shopping assistant that can answer questions about product availability and even help place orders.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>User Prompt:<\/strong> &#8220;Is product PROD-001 in stock?&#8221;<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>LLM receives prompt:<\/strong> The LLM analyzes the prompt and, based on the function descriptions it was provided, determines that <code>getProductAvailability<\/code> is the most relevant tool.<\/li>\n\n\n\n<li><strong>LLM generates function call:<\/strong> The LLM sends a structured message to your application, indicating it wants to call <code>getProductAvailability<\/code> with <code>productId: \"PROD-001\"<\/code>.<\/li>\n\n\n\n<li><strong>Application executes function:<\/strong> Your Spring application, through the configured <code>FunctionCallbackWrapper<\/code>, invokes <code>productService.getProductAvailability(\"PROD-001\")<\/code>.<\/li>\n\n\n\n<li><strong>Application returns result to LLM:<\/strong> The <code>ProductService<\/code> returns &#8220;Product PROD-001 is in stock. Quantity: 10.&#8221; This result is sent back to the LLM.<\/li>\n\n\n\n<li><strong>LLM generates final response:<\/strong> The LLM, now armed with the real-time stock information, can generate a natural language response: &#8220;Yes, product PROD-001 is currently in stock with 10 units available.&#8221;<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>User Prompt:<\/strong> &#8220;Can you place an order for 2 units of PROD-001?&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The workflow is similar, but the LLM would now choose the <code>placeOrder<\/code> function, passing <code>productId: \"PROD-001\"<\/code> and <code>quantity: 2<\/code>. The application would execute the <code>placeOrder<\/code> method, and the LLM would then confirm the order.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Benefits of Agentic Workflows with Function Calling<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Real-time Data Integration:<\/strong> LLMs can access and act upon the latest information within your systems.<\/li>\n\n\n\n<li><strong>Automated Business Processes:<\/strong> Empower your LLM to trigger complex business logic and workflows.<\/li>\n\n\n\n<li><strong>Enhanced User Experience:<\/strong> Provide more accurate, dynamic, and actionable responses to user queries.<\/li>\n\n\n\n<li><strong>Reduced Hallucinations:<\/strong> By grounding responses in actual data and actions, you mitigate the risk of the LLM generating incorrect or fabricated information.<\/li>\n\n\n\n<li><strong>Scalability and Maintainability:<\/strong> Your business logic remains within your well-tested Spring services, while the LLM acts as an intelligent orchestrator.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Looking Ahead<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI&#8217;s function calling capabilities unlock a new dimension of possibilities for building intelligent applications. As these agentic workflows become more sophisticated, we can expect to see LLMs taking on increasingly complex roles, moving from being mere assistants to active participants in our digital ecosystems. The future of AI in enterprise applications is bright, and Spring AI is providing the tools to build it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Are you ready to empower your LLMs with the ability to act? Start experimenting with Spring AI&#8217;s function calling today and transform your applications into truly intelligent agents.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The landscape of AI is rapidly evolving, moving beyond simple request-response models to more sophisticated, agentic systems. These systems empower Large Language Models (LLMs) to not just generate text, but to act within your applications, making them an active and integral part of your business logic. Spring AI is at the forefront of this evolution, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3933,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"series":[],"class_list":["post-3931","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/Gemini_Generated_Image_kg5i0ykg5i0ykg5i.avif","jetpack-related-posts":[{"id":3893,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/building-intelligent-apps-with-spring-ai\/","url_meta":{"origin":3931,"position":0},"title":"Building Intelligent Apps with Spring AI","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"In today's fast-paced world of software development, integrating artificial intelligence into applications is no longer just a trend\u2014it's a necessity. At the heart of this revolution is Generative AI, a type of artificial intelligence that can create new content, such as text, images, and code, in response to prompts. It's\u2026","rel":"","context":"In &quot;Spring AI&quot;","block_context":{"text":"Spring AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 3x"},"classes":[]},{"id":3965,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/bringing-worlds-to-life-integrating-ai-personas-in-multi-user-dungeons-muds\/","url_meta":{"origin":3931,"position":1},"title":"Bringing Worlds to Life: Integrating AI Personas in Multi-User Dungeons (MUDs)","author":"Jeffery Miller","date":"April 20, 2026","format":false,"excerpt":"A few weeks ago, I found myself pondering the ultimate objective for an artificial intelligence system. The answer kept returning to a single concept: the ability to truly mimic a human. This spark of an idea gave rise to a challenge\u2014I needed a sandbox where I could work with AI\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 3x"},"classes":[]},{"id":3671,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/spring-cloud-data-flow-orchestrating-machine-learning-pipelines\/","url_meta":{"origin":3931,"position":2},"title":"Spring Cloud Data Flow: Orchestrating Machine Learning Pipelines","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"In the dynamic world of machine learning, the journey from raw data to a deployed model involves a series of intricate steps. Spring Cloud Data Flow (SCDF) emerges as a powerful ally, offering a comprehensive platform to streamline and manage these complex data pipelines. In this guide, we\u2019ll delve into\u2026","rel":"","context":"In &quot;Spring AI&quot;","block_context":{"text":"Spring AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/ai-generated-8411275_1280-jpg.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/ai-generated-8411275_1280-jpg.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/ai-generated-8411275_1280-jpg.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/ai-generated-8411275_1280-jpg.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/ai-generated-8411275_1280-jpg.avif 3x"},"classes":[]},{"id":3557,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/spring-ai-simplifying-ai-development\/","url_meta":{"origin":3931,"position":3},"title":"Spring AI: Simplifying AI Development","author":"Jeffery Miller","date":"April 20, 2026","format":false,"excerpt":"Spring AI is a new framework aimed at making AI development easier for Java developers. It provides a simple, Spring-friendly way to integrate AI models into your applications, including the use of templates for more structured prompts. It currently supports models from various providers. Why Spring AI? Simplified Integration: Easily\u2026","rel":"","context":"In &quot;Spring AI&quot;","block_context":{"text":"Spring AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_ai\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/04\/ai-generated-8686301_640.jpg?fit=640%2C640&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/04\/ai-generated-8686301_640.jpg?fit=640%2C640&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/04\/ai-generated-8686301_640.jpg?fit=640%2C640&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":3897,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/a-beginners-guide-to-setting-up-ollama-with-docker-compose\/","url_meta":{"origin":3931,"position":4},"title":"A Beginner&#8217;s Guide to Setting Up Ollama with Docker Compose","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"Have you ever wanted to run a powerful large language model (LLM) like Llama 3 or Gemma right on your own computer, but you need a consistent and portable setup? That's where using Ollama with Docker and Docker Compose comes in. Docker Compose is a fantastic tool that allows you\u2026","rel":"","context":"In &quot;Spring AI&quot;","block_context":{"text":"Spring AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8012676_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8012676_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8012676_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8012676_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8012676_1280.avif 3x"},"classes":[]},{"id":3951,"url":"https:\/\/www.mymiller.name\/wordpress\/java\/scaling-streams-mastering-virtual-threads-in-spring-boot-4-and-java-25\/","url_meta":{"origin":3931,"position":5},"title":"Scaling Streams: Mastering Virtual Threads in Spring Boot 4 and Java 25","author":"Jeffery Miller","date":"April 20, 2026","format":false,"excerpt":"As a software architect, I\u2019ve seen the industry shift from heavy platform threads to reactive streams, and finally to the \"best of both worlds\": Virtual Threads. With the recent release of Spring Boot 4.0 and Java 25 (LTS), Project Loom's innovations have officially become the bedrock of high-concurrency enterprise Java.\u2026","rel":"","context":"In &quot;JAVA&quot;","block_context":{"text":"JAVA","link":"https:\/\/www.mymiller.name\/wordpress\/category\/java\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3931","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/comments?post=3931"}],"version-history":[{"count":2,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3931\/revisions"}],"predecessor-version":[{"id":3938,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3931\/revisions\/3938"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media\/3933"}],"wp:attachment":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media?parent=3931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/categories?post=3931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/tags?post=3931"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/series?post=3931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}