DEV Community

Cover image for Building AI Agents with Spring AI — Tool Calling, Memory, and Autonomous Workflows
Ayush Shrivastava
Ayush Shrivastava

Posted on

Building AI Agents with Spring AI — Tool Calling, Memory, and Autonomous Workflows

Building AI Agents with Spring AI — Tool Calling, Memory, and Autonomous Workflows

Large Language Models are excellent at generating text.

But generation alone isn't enough to build truly useful AI applications.

Imagine asking an AI assistant:

What's the status of my order?
Enter fullscreen mode Exit fullscreen mode

A normal LLM can explain how order tracking works.

But it cannot magically access your order database.

Or suppose you ask:

Cancel my order #ORD-10291.
Enter fullscreen mode Exit fullscreen mode

The model can tell you how to cancel an order.

But it cannot actually cancel anything unless your application gives it the ability to perform that action.

This is where tool calling and AI agents come in.

Instead of simply generating an answer, an AI application can:

Understand the request
        ↓
Decide what action is required
        ↓
Select a tool
        ↓
Execute the tool
        ↓
Observe the result
        ↓
Continue reasoning
        ↓
Generate the final response
Enter fullscreen mode Exit fullscreen mode

In this article, we'll explore how to build this architecture using Spring AI.


What Is an AI Agent?

An AI agent is an application where an LLM can decide what actions need to be performed and use available tools to accomplish a goal.

A traditional LLM application looks like:

User
 ↓
Prompt
 ↓
LLM
 ↓
Response
Enter fullscreen mode Exit fullscreen mode

An agent-based application looks more like:

User
 ↓
LLM
 ↓
Decision
 ↓
Tool
 ↓
Result
 ↓
LLM
 ↓
Decision
 ↓
Another Tool
 ↓
Result
 ↓
Final Answer
Enter fullscreen mode Exit fullscreen mode

The important difference is:

The LLM is no longer limited to generating text.

It can interact with the application through controlled capabilities.


Tool Calling

Tool calling allows an LLM to request the execution of a function exposed by your application.

For example, imagine our application provides:

getOrderStatus()
cancelOrder()
getCustomer()
createSupportTicket()
Enter fullscreen mode Exit fullscreen mode

The user asks:

Where is my order?
Enter fullscreen mode Exit fullscreen mode

The model might determine that it needs:

getOrderStatus()
Enter fullscreen mode Exit fullscreen mode

The application executes the function and returns:

Order #10291
Status: Shipped
Expected delivery: September 10
Enter fullscreen mode Exit fullscreen mode

The LLM can then generate:

Your order has been shipped and is expected to arrive on September 10.
Enter fullscreen mode Exit fullscreen mode

The LLM didn't directly access the database.

Instead:

LLM
 ↓
Tool Request
 ↓
Application
 ↓
Database
 ↓
Tool Result
 ↓
LLM
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

This distinction is extremely important for enterprise applications.


Why Tool Calling Matters

Without tools:

LLM
 ↓
Text
Enter fullscreen mode Exit fullscreen mode

With tools:

LLM
 ↓
Tools
 ├── Database
 ├── REST APIs
 ├── Search
 ├── Payment systems
 ├── CRM
 ├── Internal services
 └── Business workflows
Enter fullscreen mode Exit fullscreen mode

This turns the LLM from a text-generation component into an interface for interacting with your application.

For example, an AI sales assistant could have:

getCustomer()
getCustomerOrders()
createLead()
updateLead()
sendEmail()
scheduleMeeting()
Enter fullscreen mode Exit fullscreen mode

A support agent could have:

searchKnowledgeBase()
getCustomerAccount()
getOrder()
createTicket()
updateTicket()
Enter fullscreen mode Exit fullscreen mode

An internal developer assistant could have:

searchDocumentation()
searchGitRepository()
getBuildStatus()
createIssue()
Enter fullscreen mode Exit fullscreen mode

The possibilities are much broader than simple question answering.


RAG vs Tool Calling

At this point, it is useful to distinguish RAG from tool calling.

RAG is primarily about retrieving information.

Tool calling is about performing actions or retrieving live data through application capabilities.

For example:

RAG
 ↓
Retrieve company documentation
 ↓
Answer question
Enter fullscreen mode Exit fullscreen mode

Tool calling:

LLM
 ↓
Call order API
 ↓
Get live order status
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

They can also be combined.

For example:

User
 ↓
AI Agent
 ├── RAG → Search company policies
 │
 ├── Tool → Get customer account
 │
 └── Tool → Check order status
          ↓
       LLM
          ↓
       Answer
Enter fullscreen mode Exit fullscreen mode

This combination is extremely powerful.


Spring AI and Tool Calling

Spring AI provides abstractions that make it easier to expose application capabilities to language models.

A simplified architecture looks like:

Spring Boot
     │
     ├── ChatModel
     │
     ├── Tools
     │
     ├── Advisors
     │
     ├── Chat Memory
     │
     └── Vector Store
Enter fullscreen mode Exit fullscreen mode

The application controls which tools are available.

The model decides whether a tool is needed.

This separation is important.

The model should not have unrestricted access to your application.

Instead, the application exposes specific capabilities.


Creating a Tool

Imagine we have an order service.

@Service
public class OrderService {

    public OrderStatus getOrderStatus(String orderId) {
        // Fetch order from database
        return orderRepository.findStatus(orderId);
    }
}
Enter fullscreen mode Exit fullscreen mode

We can expose a controlled method as an AI tool.

Conceptually:

@Tool(
    description = "Get the current status of an order"
)
public OrderStatus getOrderStatus(String orderId) {

    return orderService.getOrderStatus(orderId);
}
Enter fullscreen mode Exit fullscreen mode

The description is important.

The model uses the tool description to understand:

What does this tool do?
When should I use it?
What parameters does it require?
Enter fullscreen mode Exit fullscreen mode

For example:

Tool:

getOrderStatus

Description:
Returns the current shipping and delivery status
for a customer order.

Input:
orderId
Enter fullscreen mode Exit fullscreen mode

The model can then determine whether this tool is appropriate.


Tool Schema

A tool can be thought of as:

Tool Name
     +
Description
     +
Input Schema
     +
Execution Logic
Enter fullscreen mode Exit fullscreen mode

For example:

getOrderStatus(
    orderId: String
)
Enter fullscreen mode Exit fullscreen mode

The model might produce a tool request conceptually like:

{
  "name": "getOrderStatus",
  "arguments": {
    "orderId": "ORD-10291"
  }
}
Enter fullscreen mode Exit fullscreen mode

The application receives the request and executes the corresponding Java method.


The Tool Calling Loop

A typical interaction looks like this:

User
 │
 │ "What's the status of ORD-10291?"
 ↓
LLM
 │
 │ Tool Request
 ↓
getOrderStatus("ORD-10291")
 │
 ↓
Order Service
 │
 ↓
Database
 │
 ↓
Tool Result
 │
 ↓
LLM
 │
 ↓
Final Answer
Enter fullscreen mode Exit fullscreen mode

Notice something important.

The LLM doesn't execute Java code itself.

The application remains responsible for execution.

The model only requests the action.


Tool Calling with ChatClient

Spring AI's ChatClient provides a convenient API for interacting with chat models.

Conceptually:

ChatClient chatClient;

String response = chatClient.prompt()
        .user("What's the status of order ORD-10291?")
        .tools(orderTools)
        .call()
        .content();
Enter fullscreen mode Exit fullscreen mode

The exact APIs may vary depending on the Spring AI version you're using, but the architecture remains the same:

ChatClient
   ↓
ChatModel
   ↓
Tool Selection
   ↓
Tool Execution
   ↓
Tool Result
   ↓
Final Response
Enter fullscreen mode Exit fullscreen mode

Multiple Tools

A real agent usually has more than one tool.

For example:

CustomerAgentTools

├── getCustomer()
├── getCustomerOrders()
├── getOrderStatus()
├── createSupportTicket()
└── updateCustomer()
Enter fullscreen mode Exit fullscreen mode

Now consider this question:

My order is late. Please check the status
and create a support ticket if necessary.
Enter fullscreen mode Exit fullscreen mode

The model might determine:

1. getOrderStatus()
2. Analyze result
3. createSupportTicket()
4. Return final response
Enter fullscreen mode Exit fullscreen mode

The application executes each requested operation.

This is where the concept of an agent starts becoming much more interesting.


Agents and Decision Making

A simple agent loop can be represented as:

              ┌───────────────┐
              │     User      │
              └───────┬───────┘
                      ↓
                ┌───────────┐
                │    LLM    │
                └─────┬─────┘
                      ↓
                Need a Tool?
                /          \
              No            Yes
              ↓              ↓
          Final Answer    Tool Call
                             ↓
                        Tool Execution
                             ↓
                         Tool Result
                             ↓
                            LLM
                             ↓
                      Need Another Tool?
Enter fullscreen mode Exit fullscreen mode

The model can repeatedly interact with tools until it has enough information to produce the final response.


Tool Calling Is Not Full Autonomy

This distinction is important.

People often hear:

AI Agent

and immediately think:

Give AI access to everything
        ↓
Let AI do whatever it wants
Enter fullscreen mode Exit fullscreen mode

That is not how production systems should be designed.

A production agent should operate inside clear boundaries.

For example:

Allowed Tools
     ↓
Authorization
     ↓
Validation
     ↓
Execution
     ↓
Audit
Enter fullscreen mode Exit fullscreen mode

The application remains in control.

The model should not be trusted with unrestricted capabilities.


Tool Security

Imagine we expose:

@Tool
public void deleteCustomer(String customerId) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

This is potentially dangerous.

An LLM should not automatically receive unrestricted permission to perform destructive operations.

Instead, sensitive tools should have additional controls.

For example:

User
 ↓
Authentication
 ↓
Authorization
 ↓
Agent
 ↓
Tool Request
 ↓
Permission Check
 ↓
Confirmation
 ↓
Execution
Enter fullscreen mode Exit fullscreen mode

For destructive operations, you may require explicit user confirmation.

Example:

AI:
I found customer account C-19291.

Deleting this account is irreversible.
Do you want me to continue?

User:
Yes.

AI:
Executing deletion...
Enter fullscreen mode Exit fullscreen mode

The AI should assist with the decision process, not bypass your security model.


Tool Permissions

A useful production architecture is to classify tools.

READ

getCustomer()
getOrder()
searchDocuments()
getInvoice()
Enter fullscreen mode Exit fullscreen mode

Then:

WRITE

createTicket()
updateCustomer()
createLead()
Enter fullscreen mode Exit fullscreen mode

And:

DESTRUCTIVE

deleteCustomer()
cancelSubscription()
refundPayment()
Enter fullscreen mode Exit fullscreen mode

Different permission levels can then be applied.

For example:

READ
→ Automatically allowed

WRITE
→ Role-based authorization

DESTRUCTIVE
→ Authorization + confirmation
Enter fullscreen mode Exit fullscreen mode

This makes agent behavior much safer.


AI Agent Memory

Tool calling solves one problem.

But another problem appears quickly:

What does the agent remember?

Consider this conversation:

User:
My order is late.

AI:
What's your order number?

User:
ORD-10291.

AI:
Let me check it.
Enter fullscreen mode Exit fullscreen mode

Now the next message is:

Can you create a support ticket for it?
Enter fullscreen mode Exit fullscreen mode

The AI needs to understand that:

"it"
Enter fullscreen mode Exit fullscreen mode

refers to:

ORD-10291
Enter fullscreen mode Exit fullscreen mode

This requires conversational context.

That's where chat memory becomes important.


Chat Memory

A simple conversation can be represented as:

User:
My order is late.

Assistant:
What's your order number?

User:
ORD-10291.

Assistant:
Let me check that order.
Enter fullscreen mode Exit fullscreen mode

The application maintains the conversation history.

Conceptually:

Conversation ID
       ↓
Chat Memory
       ↓
Previous Messages
       ↓
Current Prompt
       ↓
LLM
Enter fullscreen mode Exit fullscreen mode

Spring AI provides abstractions for managing chat memory.


Short-Term vs Long-Term Memory

It is useful to distinguish two concepts.

Short-Term Memory

Conversation context.

User:
My order is late.

User:
It's order 10291.

User:
Can you check it?
Enter fullscreen mode Exit fullscreen mode

The system remembers the current conversation.

Long-Term Memory

Persistent information about the user.

For example:

Customer:
Ayush

Preferences:
Preferred language = English
Preferred notification = Email
Enter fullscreen mode Exit fullscreen mode

Long-term memory usually requires persistence in a database or another storage system.

A production architecture might look like:

Conversation
     ↓
Chat Memory Store
     ↓
PostgreSQL / Redis
Enter fullscreen mode Exit fullscreen mode

The exact storage mechanism depends on the application.


Agents + Memory

Now we can combine:

User
 ↓
Agent
 ↓
Memory
 ↓
LLM
 ↓
Tools
 ↓
Tool Results
 ↓
Memory
 ↓
LLM
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

This enables more natural multi-turn interactions.


Advisors

Another important Spring AI concept is the Advisor.

Advisors can intercept and influence the interaction between the application and the model.

They can be used for concerns such as:

Conversation memory
RAG
Logging
Security
Prompt modification
Context injection
Observability
Enter fullscreen mode Exit fullscreen mode

Conceptually:

User
 ↓
ChatClient
 ↓
Advisor
 ↓
ChatModel
 ↓
Advisor
 ↓
Response
Enter fullscreen mode Exit fullscreen mode

This allows cross-cutting AI behavior to be separated from business logic.


Combining RAG + Tools + Memory

Now things become much more powerful.

Imagine an enterprise support agent.

It has:

RAG
 ↓
Company documentation
Enter fullscreen mode Exit fullscreen mode

Tools:

getCustomer()
getOrder()
createTicket()
Enter fullscreen mode Exit fullscreen mode

Memory:

Conversation history
Enter fullscreen mode Exit fullscreen mode

The architecture becomes:

                    User
                     ↓
                 AI Agent
                     ↓
             ┌───────┼────────┐
             ↓       ↓        ↓
            RAG    Tools    Memory
             ↓       ↓        ↓
        Knowledge   APIs   Conversation
             │       │        │
             └───────┼────────┘
                     ↓
                    LLM
                     ↓
                  Response
Enter fullscreen mode Exit fullscreen mode

This is much closer to a production AI application.


Example: Customer Support Agent

Consider the request:

My payment failed for order ORD-19291.
Can you check what happened and tell me
what I should do?
Enter fullscreen mode Exit fullscreen mode

The agent could perform:

1. getOrder("ORD-19291")
2. getPaymentStatus("ORD-19291")
3. searchKnowledgeBase("payment failure")
4. Generate explanation
Enter fullscreen mode Exit fullscreen mode

The final answer could be:

Your payment attempt failed because the transaction
was declined by the payment provider.

According to the payment policy, you can retry the
payment using another payment method.

Would you like me to create a support ticket?
Enter fullscreen mode Exit fullscreen mode

The model combined:

Live application data
+
Knowledge base
+
Conversation context
Enter fullscreen mode Exit fullscreen mode

This is significantly more useful than a standalone chatbot.


Multi-Step Agent Workflow

Agents can also perform multi-step workflows.

For example:

User:
Find my overdue invoices and send reminders.
Enter fullscreen mode Exit fullscreen mode

The agent could reason through:

getCustomer()
      ↓
getInvoices()
      ↓
Filter overdue invoices
      ↓
sendReminder()
      ↓
Return summary
Enter fullscreen mode Exit fullscreen mode

The workflow becomes:

Goal
 ↓
Plan
 ↓
Tool
 ↓
Observe
 ↓
Next Decision
 ↓
Tool
 ↓
Observe
 ↓
Final Result
Enter fullscreen mode Exit fullscreen mode

This pattern is often called an agent loop.


Agent Loop

A simplified conceptual implementation looks like:

while (!completed) {

    AgentDecision decision =
            llm.decide(context);

    if (decision.requiresTool()) {

        ToolResult result =
                toolExecutor.execute(
                        decision.toolCall()
                );

        context.add(result);

    } else {

        return decision.finalAnswer();
    }
}
Enter fullscreen mode Exit fullscreen mode

In real applications, frameworks handle much of this interaction.

But understanding the underlying loop is important.


Don't Build Everything as an Agent

An important engineering lesson:

Not every AI feature needs an agent.

If your workflow is deterministic:

Validate request
 ↓
Call API
 ↓
Save result
 ↓
Return response
Enter fullscreen mode Exit fullscreen mode

you probably don't need an autonomous agent.

A normal service workflow may be better.

Agents become more useful when:

The next step depends on the current result.
Enter fullscreen mode Exit fullscreen mode

For example:

Check order
 ↓
If delayed
 ↓
Check refund policy
 ↓
If eligible
 ↓
Ask for confirmation
 ↓
Create refund request
Enter fullscreen mode Exit fullscreen mode

The dynamic decision-making is where agents become valuable.


Deterministic Workflow vs Agent

Traditional Workflow

A → B → C → D
Enter fullscreen mode Exit fullscreen mode

Everything is predetermined.

Agent Workflow

A
 ↓
LLM decides
 ├── B
 ├── C
 └── D
      ↓
   Observe result
      ↓
   Decide again
Enter fullscreen mode Exit fullscreen mode

Agents provide flexibility.

Traditional workflows provide predictability.

Production systems often use both.


Agent Architecture for Enterprise Java

A practical Spring Boot architecture might look like:

                    ┌───────────────┐
                    │   Frontend    │
                    └───────┬───────┘
                            ↓
                    ┌───────────────┐
                    │ Spring Boot   │
                    │     API       │
                    └───────┬───────┘
                            ↓
                     ┌────────────┐
                     │ ChatClient │
                     └─────┬──────┘
                           ↓
                    ┌──────────────┐
                    │    Agent     │
                    └──────┬───────┘
                           ↓
              ┌────────────┼────────────┐
              ↓            ↓            ↓
           Memory         RAG         Tools
              ↓            ↓            ↓
          PostgreSQL    pgvector      APIs
                                         ↓
                                    Microservices
Enter fullscreen mode Exit fullscreen mode

This architecture fits naturally into existing Spring Boot applications.


Observability

Agent systems can become difficult to debug.

Imagine an agent performs:

Tool 1
Tool 2
Tool 3
Tool 4
Enter fullscreen mode Exit fullscreen mode

and the final response is incorrect.

You need to know:

What did the model decide?
Which tools were selected?
What arguments were sent?
How long did each tool take?
What did each tool return?
How many model calls happened?
How many tokens were consumed?
Enter fullscreen mode Exit fullscreen mode

Therefore, observability is critical.

Track:

LLM latency
Tool latency
Retrieval latency
Token usage
Tool calls
Tool failures
Model responses
Agent iterations
Errors
Enter fullscreen mode Exit fullscreen mode

Preventing Infinite Agent Loops

An agent can potentially continue calling tools indefinitely.

For example:

LLM
 ↓
Tool
 ↓
LLM
 ↓
Tool
 ↓
LLM
 ↓
Tool
 ↓
...
Enter fullscreen mode Exit fullscreen mode

Production systems should enforce limits.

For example:

Maximum iterations = 10
Maximum tool calls = 20
Maximum execution time = 30 seconds
Enter fullscreen mode Exit fullscreen mode

You should also define clear failure behavior.

Agent limit reached
        ↓
Stop execution
        ↓
Return safe response
        ↓
Log failure
Enter fullscreen mode Exit fullscreen mode

Tool Validation

Never blindly trust model-generated tool arguments.

Suppose the model requests:

{
  "orderId": "ORD-999999999"
}
Enter fullscreen mode Exit fullscreen mode

Your application should still validate:

Does the order exist?
Does the user own the order?
Is the user authorized?
Is the order accessible to this tenant?
Enter fullscreen mode Exit fullscreen mode

The architecture should be:

LLM
 ↓
Tool Request
 ↓
Schema Validation
 ↓
Authorization
 ↓
Business Validation
 ↓
Tool Execution
Enter fullscreen mode Exit fullscreen mode

The LLM is not your security boundary.

Your application is.


Multi-Tenant AI Agents

This becomes especially important in SaaS applications.

Imagine:

Tenant A
 ├── Customers
 ├── Orders
 └── Documents

Tenant B
 ├── Customers
 ├── Orders
 └── Documents
Enter fullscreen mode Exit fullscreen mode

An AI agent must never retrieve Tenant B's information while processing a Tenant A request.

Every tool and retrieval operation should carry tenant context.

For example:

tenant_id
user_id
roles
permissions
Enter fullscreen mode Exit fullscreen mode

Then:

User
 ↓
Authentication
 ↓
Tenant Context
 ↓
Agent
 ↓
Tool
 ↓
Authorization
 ↓
Tenant-scoped Data
Enter fullscreen mode Exit fullscreen mode

The same principle applies to RAG.

Vector Search
 +
tenant_id filter
Enter fullscreen mode Exit fullscreen mode

should ensure that retrieved documents belong to the correct tenant.


AI Agent Guardrails

Production agents should have explicit guardrails.

Examples:

Input validation
Output validation
Tool authorization
Rate limiting
Token limits
Iteration limits
PII protection
Audit logging
Human approval
Enter fullscreen mode Exit fullscreen mode

For high-risk actions:

Agent
 ↓
Tool Request
 ↓
Risk Evaluation
 ↓
Human Approval
 ↓
Execution
Enter fullscreen mode Exit fullscreen mode

This creates a human-in-the-loop architecture.


Human-in-the-Loop

Not every decision should be fully automated.

For example:

Refund amount < $50
    ↓
Automatic

Refund amount > $50
    ↓
Human approval
Enter fullscreen mode Exit fullscreen mode

Or:

Create support ticket
    ↓
Automatic

Delete account
    ↓
Confirmation required
Enter fullscreen mode Exit fullscreen mode

This gives us a practical balance:

AI Automation
+
Business Rules
+
Human Oversight
Enter fullscreen mode Exit fullscreen mode

RAG + Tool Calling + Memory

At this point, we can combine everything we've discussed.

                         User
                          ↓
                     Spring Boot
                          ↓
                      ChatClient
                          ↓
                       AI Agent
                          ↓
              ┌───────────┼───────────┐
              ↓           ↓           ↓
            Memory       RAG         Tools
              ↓           ↓           ↓
          PostgreSQL   pgvector    REST APIs
                                      ↓
                               Business Services
                                      ↓
                                   Database
Enter fullscreen mode Exit fullscreen mode

This is a strong foundation for enterprise AI applications.


Example Enterprise Agent

Imagine a sales assistant.

The user asks:

Show me the latest opportunities for Acme
and tell me which ones are likely to close this month.
Enter fullscreen mode Exit fullscreen mode

The agent could:

1. getCustomer("Acme")
2. getOpportunities("Acme")
3. retrieve sales documentation
4. analyze opportunity information
5. generate summary
Enter fullscreen mode Exit fullscreen mode

Now the user says:

Create a follow-up task for the highest priority opportunity.
Enter fullscreen mode Exit fullscreen mode

The agent can:

1. Identify opportunity
2. createFollowUpTask()
3. Return task details
Enter fullscreen mode Exit fullscreen mode

This is where AI starts becoming an application interface rather than simply a chatbot.


A Useful Mental Model

Think about the responsibilities this way:

LLM
=
Reasoning + Language

RAG
=
Knowledge Retrieval

Tools
=
Actions + Live Data

Memory
=
Conversation Context

Spring Boot
=
Application + Security + Business Logic
Enter fullscreen mode Exit fullscreen mode

Together:

LLM
 +
RAG
 +
Tools
 +
Memory
 +
Business Logic
 =
AI Application
Enter fullscreen mode Exit fullscreen mode

What Spring AI Gives Java Developers

Spring AI provides abstractions that allow Java developers to work with AI capabilities using familiar Spring patterns.

Important building blocks include:

ChatClient
ChatModel
EmbeddingModel
VectorStore
Document
Advisors
Chat Memory
Tools
Enter fullscreen mode Exit fullscreen mode

This means an enterprise Java team can integrate AI into an existing Spring Boot architecture instead of creating an entirely separate AI stack.

For example:

Existing Spring Boot Application
              ↓
        Spring AI Layer
              ↓
      Model + RAG + Tools
              ↓
     Existing Microservices
Enter fullscreen mode Exit fullscreen mode

This makes AI integration much more practical for Java teams.


Production Architecture

A more complete production system might eventually look like:

                         ┌───────────────┐
                         │     User      │
                         └───────┬───────┘
                                 ↓
                         API Gateway
                                 ↓
                         Authentication
                                 ↓
                         Spring Boot API
                                 ↓
                            AI Agent
                                 ↓
          ┌──────────────────────┼──────────────────────┐
          ↓                      ↓                      ↓
       Memory                  RAG                    Tools
          ↓                      ↓                      ↓
     PostgreSQL              pgvector              Microservices
                                                        ↓
                                                Business Database
                                 ↓
                           LLM Provider
                                 ↓
                              Response
Enter fullscreen mode Exit fullscreen mode

And around the entire system:

Security
Observability
Rate Limiting
Audit Logging
Guardrails
Evaluation
Enter fullscreen mode Exit fullscreen mode

These are not optional concerns in serious enterprise deployments.


Agent vs Chatbot

It is useful to understand the difference.

Chatbot

User
 ↓
LLM
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

RAG Chatbot

User
 ↓
Retrieve Knowledge
 ↓
LLM
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

Tool-Enabled Assistant

User
 ↓
LLM
 ↓
Tool
 ↓
Result
 ↓
Answer
Enter fullscreen mode Exit fullscreen mode

AI Agent

User
 ↓
Agent
 ↓
Reason
 ↓
Tool
 ↓
Observe
 ↓
Reason
 ↓
Tool
 ↓
Observe
 ↓
Final Answer
Enter fullscreen mode Exit fullscreen mode

The complexity increases at every stage.


The Agentic AI Stack

We can now think about the evolution of an AI application:

Level 1
LLM
 ↓
Text Generation

Level 2
LLM + RAG
 ↓
Knowledge Retrieval

Level 3
LLM + Tools
 ↓
Actions

Level 4
LLM + Tools + Memory
 ↓
Contextual Assistant

Level 5
LLM + RAG + Tools + Memory
 ↓
Agent

Level 6
Multiple Agents + Workflows
 ↓
Agentic System
Enter fullscreen mode Exit fullscreen mode

This progression is useful when deciding how much complexity your application actually needs.


Final Takeaway

The evolution from traditional AI applications to agentic applications can be summarized as:

LLM
 ↓
Generate Text

RAG
 ↓
Retrieve Knowledge

Tool Calling
 ↓
Take Actions

Memory
 ↓
Remember Context

Agents
 ↓
Make Decisions

Workflows
 ↓
Coordinate Multiple Steps
Enter fullscreen mode Exit fullscreen mode

Spring AI provides Java developers with abstractions for building many of these capabilities inside the Spring ecosystem.

The most important engineering principle is:

Let the model decide, but let your application control.

The LLM can decide which tool may be useful.

Your application should decide whether that tool is actually allowed to execute.

That separation gives us a much safer architecture for enterprise AI.


What's Next?

We've now covered three major capabilities:

LLM
 ↓
Generate

RAG
 ↓
Retrieve

Tools
 ↓
Act
Enter fullscreen mode Exit fullscreen mode

But there is another challenge.

What happens when a system has:

Multiple agents
        ↓
Multiple tools
        ↓
Multiple services
        ↓
Multiple AI models
Enter fullscreen mode Exit fullscreen mode

How do these agents communicate?

How do we standardize tool discovery?

How can an AI agent securely interact with external tools and services?

This leads us toward another important concept in modern AI engineering:

Model Context Protocol — MCP.

In the next article, we'll explore:

Building MCP Clients and Tool-Based AI Applications with Spring AI.


Key Takeaways

  • Tool calling allows LLMs to interact with application capabilities.
  • The LLM requests tools; your application executes them.
  • Tools can expose APIs, databases, business operations, and services.
  • Chat memory provides conversational context.
  • RAG provides external knowledge.
  • Agents can combine RAG, memory, and tools.
  • Not every workflow requires an agent.
  • Deterministic workflows are often better for predictable business processes.
  • Tool permissions and authorization are critical.
  • Destructive operations should require stronger controls.
  • Multi-tenant applications must enforce tenant isolation at the tool and retrieval layers.
  • Agent loops should have iteration, timeout, and tool-call limits.
  • Observability is essential for debugging agent behavior.
  • Human-in-the-loop approval is useful for high-risk actions.
  • Spring AI provides abstractions that make these patterns accessible to Java and Spring Boot developers.

The future of enterprise AI isn't just:

LLM → Answer
Enter fullscreen mode Exit fullscreen mode

It's increasingly:

LLM
 ↓
Reason
 ↓
Retrieve
 ↓
Call Tools
 ↓
Observe
 ↓
Act
 ↓
Remember
 ↓
Complete the Goal
Enter fullscreen mode Exit fullscreen mode

And that's where AI agents with Spring AI become truly interesting.

Top comments (0)