DEV Community

Said Olano
Said Olano

Posted on

AI Agents: Building Autonomous Systems with Spring AI

AI Agents: Building Autonomous Systems with Spring AI

AI agents are autonomous software systems that perceive their environment, make decisions, and take actions toward specific goals—without explicit step-by-step programming. They're the frontier of AI: beyond chatbots, toward real autonomy.

What is an AI Agent?

An agent is a system with:

  1. Perception - Observes environment via sensors/APIs
  2. Reasoning - Makes decisions using the LLM
  3. Action - Executes tasks via tools/functions
  4. Memory - Learns from past experiences
  5. Goals - Works toward defined objectives
User: "Schedule a meeting and send a summary email"
     ↓
[Agent] → What tools do I need?
       → What's the order?
       → Execute actions
       → Remember for next time
     ↓
Goal Achieved: Meeting scheduled + email sent
Enter fullscreen mode Exit fullscreen mode

Agent vs Chatbot

Chatbot: One-turn responses

User: "What's 2+2?"
Bot: "2+2 = 4"
Enter fullscreen mode Exit fullscreen mode

Agent: Multi-step autonomous execution

User: "Analyze Q3 sales, create report, email CEO"
Agent:
  1. Query database for Q3 data
  2. Analyze trends
  3. Generate PDF report
  4. Check CEO's calendar
  5. Send at optimal time
  6. Log action
Enter fullscreen mode Exit fullscreen mode

Building Agents with Spring AI

@Service
public class SimpleAgent {
    private final ChatClient chatClient;
    private final ToolRegistry toolRegistry;
    private final MessageHistory history;

    public String executeTask(String userGoal) {
        String response = userGoal;

        while (!isGoalAchieved(response)) {
            // 1. PERCEPTION: Get current state
            String state = perceiveEnvironment();

            // 2. REASONING: Ask LLM what to do
            String plan = chatClient.prompt()
                .system(AGENT_SYSTEM_PROMPT)
                .user(String.format(
                    "Goal: %s\nState: %s\nTools: %s",
                    userGoal, state, toolRegistry.listTools()
                ))
                .call()
                .content();

            // 3. ACTION: Execute the plan
            String result = executeAction(plan);
            response = result;

            // 4. MEMORY: Record in history
            history.add("Reasoning:", plan);
            history.add("Result:", result);
        }

        return response;
    }
}
Enter fullscreen mode Exit fullscreen mode

Agent System Prompt

private static final String AGENT_SYSTEM_PROMPT = """
You are an autonomous AI agent. Your role:

1. Analyze the user's goal and current state
2. Choose appropriate tools from available options
3. Execute them in the correct sequence
4. Adapt based on results
5. Continue until goal achieved

Think through:
- What is the goal?
- What tools are available?
- What's the optimal sequence?
- What could go wrong?
""";
Enter fullscreen mode Exit fullscreen mode

Tools & Functions

Agents need access to tools—functions they can call autonomously:

@Service
public class AgentTools {

    @Tool("query_sales_database")
    public String querySalesData(String quarter) {
        return "Q3 2024 Revenue: $5.2M";
    }

    @Tool("send_email")
    public String sendEmail(String to, String subject, String body) {
        return "Email sent to " + to;
    }

    @Tool("generate_pdf_report")
    public String generateReport(String data) {
        return "/reports/Report.pdf";
    }

    @Tool("check_calendar")
    public String checkCalendar(String person, String date) {
        return "Free from 2-3 PM";
    }
}
Enter fullscreen mode Exit fullscreen mode

Agent Decision Loop

public class AgentLoop {
    public void runAgent(String goal, int maxIterations) {
        String state = initialState();

        for (int i = 0; i < maxIterations; i++) {
            System.out.println("\n=== Iteration " + i + " ===");
            System.out.println("Goal: " + goal);
            System.out.println("State: " + state);

            // Get agent's reasoning
            String reasoning = askAgent(goal, state);
            System.out.println("Reasoning: " + reasoning);

            // Execute action
            String action = parseAction(reasoning);
            String result = executeAction(action);
            System.out.println("Result: " + result);

            // Update state
            state = updateState(state, result);

            // Check if goal achieved
            if (isGoalComplete(state, goal)) {
                System.out.println("\n✅ Goal Achieved!");
                return;
            }
        }
        System.out.println("\n❌ Max iterations reached");
    }
}
Enter fullscreen mode Exit fullscreen mode

Agent Types

Reactive - No memory, responds to current input

public String reactiveAgent(String input) {
    return generateResponse(input);
}
Enter fullscreen mode Exit fullscreen mode

Deliberative - Plans before executing

public String deliberativeAgent(String goal) {
    String plan = generatePlan(goal);
    return executePlan(plan);
}
Enter fullscreen mode Exit fullscreen mode

Hierarchical - Breaks goals into sub-goals

public void hierarchicalAgent(String goal) {
    List<String> subGoals = decompose(goal);
    subGoals.forEach(this::executeSubGoal);
}
Enter fullscreen mode Exit fullscreen mode

Real-World Example: Data Analysis Agent

@Service
public class DataAnalysisAgent {
    private final ChatClient chatClient;
    private final DatabaseClient dbClient;
    private final ChartGenerator chartGenerator;
    private final EmailService emailService;

    public void analyzeAndReport(String dataset, String recipient) {
        // Step 1: Fetch data
        String data = dbClient.query("SELECT * FROM " + dataset);

        // Step 2: Agent analyzes
        String analysis = chatClient.prompt()
            .system("You are a data analyst. Identify key insights.")
            .user(data)
            .call()
            .content();

        // Step 3: Visualize
        String chart = chartGenerator.create(analysis);

        // Step 4: Report
        String report = generateReport(analysis, chart);

        // Step 5: Send
        emailService.send(recipient, "Data Report", report);

        System.out.println("✅ Report sent");
    }
}
Enter fullscreen mode Exit fullscreen mode

Guardrails for Agents

Agents need safety constraints:

public class AgentGuardrails {
    private Set<String> allowedTools = Set.of(
        "query_database", "send_email", "generate_report"
    );

    public boolean isSafeAction(String action) {
        if (action.contains("DELETE")) return false;
        if (action.contains("DROP")) return false;
        if (!isToolAllowed(action)) return false;
        return true;
    }

    // Rate limiting
    private RateLimiter limiter = RateLimiter.create(10);

    public void executeWithGuardrails(String action) {
        if (!isSafeAction(action)) {
            throw new SecurityException("Not allowed: " + action);
        }
        if (!limiter.tryAcquire()) {
            throw new RateLimitException("Too fast");
        }
        executeAction(action);
    }
}
Enter fullscreen mode Exit fullscreen mode

Challenges & Solutions

Challenge Solution
Hallucination Constrain tools to verified sources
Infinite loops Max iterations + completion check
Safety Guardrails + action approval
Cost Cache results, batch operations
Debugging Log every step

Best Practices

  1. Start Simple - Reactive before planning
  2. Clear Goals - Define success explicitly
  3. Tool Design - Keep tools focused and safe
  4. Extensive Logging - Track every decision
  5. Gradual Autonomy - Human approval before full autonomy
  6. Test Thoroughly - Unit test each tool
  7. Monitor Production - Track success rates

Conclusion

AI agents represent the next evolution: from passive information retrieval to active, goal-oriented autonomy. They perceive, reason, act, and learn—transforming AI from tool into collaborator.

Start with simple tools, robust guardrails, and careful monitoring. Expand gradually as your agents succeed.

Top comments (0)