Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security NachrichtenKI-Agenten hebeln klassisches IT-Asset-Management aus(24.09.2026 um 07:14 Uhr)
IT Security NachrichtenMicrosoft erneuert Surface Pro und Laptop mit Snapdragon X2 Plus(24.09.2026 um 07:42 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/shared/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/llms/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/agents/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/core/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vcli-v3.0.65 (24.09.2026)(24.09.2026 um 07:54 Uhr)
IT Security NachrichtenKI-Agenten hebeln klassisches IT-Asset-Management aus(24.09.2026 um 07:14 Uhr)
IT Security NachrichtenMicrosoft erneuert Surface Pro und Laptop mit Snapdragon X2 Plus(24.09.2026 um 07:42 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/shared/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/llms/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/agents/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/core/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vcli-v3.0.65 (24.09.2026)(24.09.2026 um 07:54 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

A Practical Guide to Building AI Agents With Java and Spring AI - Part 1 - Create an AI Agent

Building AI-powered applications has become increasingly important for modern Java developers. With the rise of large language models and AI services, integrating intelligent capabilities into Java applications is no longer a luxury — it's …

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Building AI-powered applications has become increasingly important for modern Java developers. With the rise of large language models and AI services, integrating intelligent capabilities into Java applications is no longer a luxury — it's a necessity for staying competitive.



Spring AI makes this integration seamless by providing a unified framework for building AI-powered applications with Java. Combined with Amazon Bedrock, developers can create sophisticated AI agents that leverage state-of-the-art foundation models without managing complex infrastructure.



In this post, I'll guide you through creating your first AI agent using Java and Spring AI, connected to Amazon Bedrock. We'll build a complete application with both REST API and web interface, demonstrating how to integrate AI capabilities into your Java applications.






Overview of the Solution






What is Spring AI?



Spring AI is a framework that brings the familiar Spring programming model to AI applications. It provides:





  • Unified API: A consistent interface for working with different AI models and providers


  • Seamless Integration: Native Spring Boot integration with auto-configuration


  • Multiple Providers: Support for OpenAI, Azure OpenAI, Amazon Bedrock, Ollama, and more


  • Advanced Features: Built-in support for RAG (Retrieval Augmented Generation), function calling, and chat memory


  • Production Ready: Observability, error handling, and resilience patterns



The framework abstracts the complexity of working with different AI providers, allowing you to focus on building your application logic rather than dealing with API specifics.






What is Amazon Bedrock?



Amazon Bedrock is a fully managed service that provides access to high-performing foundation models from leading AI companies including Anthropic, Meta, Stability AI, and Amazon's own models. Key benefits include:





  • No Infrastructure Management: Serverless architecture with automatic scaling


  • Multiple Models: Access to various foundation models through a single API


  • Security & Privacy: Your data stays within your AWS account


  • Cost Effective: Pay only for what you use with no upfront commitments



We'll create a Spring Boot application that demonstrates the core concepts of building AI agents.



The application will include:




  • Spring Boot web application with Thymeleaf templates

  • REST API for chat interactions

  • Integration with Amazon Bedrock via Spring AI

  • Streaming responses for better user experience






Prerequisites



Before you start, ensure you have:




  • Java 21 JDK installed (we'll use Amazon Corretto 21)

  • Maven 3.6+ installed

  • AWS CLI configured with appropriate permissions for Amazon Bedrock

  • Access to Amazon Bedrock models in your AWS account






Creating the AI Agent






Use Spring Initializer



We'll use Spring Initializer to bootstrap our project with the necessary dependencies:




curl https://start.spring.io/starter.zip \
-d type=maven-project \
-d language=java \
-d bootVersion=3.5.7 \
-d baseDir=ai-agent \
-d groupId=com.example \
-d artifactId=ai-agent \
-d name=ai-agent \
-d description="AI Agent with Spring AI and Amazon Bedrock" \
-d packageName=com.example.ai.agent \
-d packaging=jar \
-d javaVersion=21 \
-d dependencies=spring-ai-bedrock-converse,web,thymeleaf,actuator,devtools \
-o ai-agent.zip

unzip ai-agent.zip
cd ai-agent









Add a Git repository to the project to track changes






git init -b main
git add .
git commit -m "Initialize the AI agent"









Configure Amazon Bedrock Integration



Create the application configuration in src/main/resources/application.properties:




cat >> src/main/resources/application.properties << 'EOL'

# Simplified logging pattern - only show the message
logging.pattern.console=%msg%n

# Debugging
logging.level.org.springframework.ai=DEBUG
spring.ai.chat.observations.log-completion=true
spring.ai.chat.observations.include-error-logging=true
spring.ai.tools.observations.include-content=true

# Thymeleaf Configuration
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# Amazon Bedrock Configuration
spring.ai.bedrock.aws.region=us-east-1
spring.ai.bedrock.converse.chat.options.max-tokens=10000
spring.ai.bedrock.converse.chat.options.model=openai.gpt-oss-120b-1:0
EOL






The most important part of the properties is the GenAI model which we are going to use.

In this example, we use OpenAI’s open-weight model gpt-oss-120b.




This model is offered on Amazon Bedrock and provides an excellent cost/performance ratio and can be recommended as a migration path from proprietary OpenAI models.






Create the Chat Service



The ChatClient interface is the core abstraction in Spring AI that provides:





  1. Unified API: Works with different AI model providers without code changes


  2. Streaming Support: Real-time response streaming for better user experience


  3. Prompt Management: Built-in support for structured prompts and templates


  4. Response Handling: Consistent response format across different models



Key methods include:





  • call(Prompt prompt): Synchronous response


  • stream(Prompt prompt): Streaming response


  • generate(List<Prompt> prompts): Batch processing



Create a service to handle chat interactions with the AI model:




mkdir -p src/main/java/com/example/ai/agent/service
cat <<'EOF' > src/main/java/com/example/ai/agent/service/ChatService.java
package com.example.ai.agent.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import org.springframework.ai.chat.client.ChatClient;

@Service
public class ChatService {
private static final Logger logger = LoggerFactory.getLogger(ChatService.class);

private final ChatClient chatClient;

public ChatService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder
.build();

logger.info("ChatService initialized with embedded ChatClient");
}

public String processChat(String prompt) {
logger.info("Processing text chat request - prompt: '{}'", prompt);
try {
var chatResponse = chatClient
.prompt().user(prompt)
.call()
.chatResponse();
return extractTextFromResponse(chatResponse);
} catch (Exception e) {
logger.error("Error processing chat request", e);
return "I don't know - there was an error processing your request.";
}
}

public String extractTextFromResponse(org.springframework.ai.chat.model.ChatResponse chatResponse) {
if (chatResponse != null) {
// First try the standard approach
String text = chatResponse.getResult().getOutput().getText();
if (text != null && !text.isEmpty()) {
return text;
}

// Fallback: iterate through generations for models with reasoning content
if (!chatResponse.getResults().isEmpty()) {
for (var generation : chatResponse.getResults()) {
String textContent = generation.getOutput().getText();
if (textContent != null && !textContent.isEmpty()) {
logger.info("Found text content: '{}'", textContent);
return textContent;
}
}
}
}

return "I don't know - no response received.";
}
}
EOF









Create the Chat Controller



Create the REST controller that handles chat interactions:




mkdir -p src/main/java/com/example/ai/agent/controller
cat <<'EOF' > src/main/java/com/example/ai/agent/controller/ChatController.java
package com.example.ai.agent.controller;

import com.example.ai.agent.service.ChatService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api")
public class ChatController {
private final ChatService chatService;

public ChatController(ChatService chatService) {
this.chatService = chatService;
}

@PostMapping("chat")
public String chat(@RequestBody ChatRequest request) {
return chatService.processChat(request.prompt());
}

public record ChatRequest(String prompt) {}
}
EOF









Create the Web Controller



Create a controller to serve the web interface:




cat <<'EOF' > src/main/java/com/example/ai/agent/controller/WebViewController.java
package com.example.ai.agent.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class WebViewController {
@GetMapping("/")
public String index() {
return "chat";
}
}
EOF









Create the Web Interface



Create a modern chat interface using Thymeleaf and Tailwind CSS:




cat <<'EOF' > src/main/resources/templates/chat.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Agent</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
'dev-dark': '#1a1a1a',
'dev-darker': '#121212',
'dev-accent': '#6366f1',
'dev-accent-hover': '#4f46e5',
'dev-secondary': '#3b82f6',
'dev-text': '#e2e8f0',
'dev-text-muted': '#94a3b8',
'dev-border': '#2d3748',
'dev-message-user': '#1e293b',
'dev-message-ai': '#1e1e2d',
// Light theme colors
'light-bg': '#ffffff',
'light-bg-secondary': '#f8fafc',
'light-text': '#1f2937',
'light-text-muted': '#6b7280',
'light-border': '#e5e7eb',
'light-message-user': '#f3f4f6',
'light-message-ai': '#ffffff'
}
}
}
}
</script>
<style>
.chat-container {
height: calc(100vh - 180px);
}
.message-container {
height: calc(100vh - 280px);
overflow-y: auto;
}
/* Custom scrollbar for dark mode */
.dark ::-webkit-scrollbar {
width: 8px;
}
.dark ::-webkit-scrollbar-track {
background: #1a1a1a;
}
.dark ::-webkit-scrollbar-thumb {
background: #3b3b3b;
border-radius: 4px;
}
.dark ::-webkit-scrollbar-thumb:hover {
background: #4b4b4b;
}

/* Light theme scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f5f9;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* Markdown table styling */
.ai-response table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
border-radius: 8px;
overflow: hidden;
background: #ffffff;
border: 1px solid #e5e7eb;
}
.dark .ai-response table {
background: #1e1e2d !important;
border: 1px solid #2d3748 !important;
}
.ai-response th {
background: #6366f1 !important;
color: white !important;
padding: 12px;
text-align: left;
font-weight: 600;
}
.ai-response td {
padding: 10px 12px;
border-bottom: 1px solid #e5e7eb;
color: #111827 !important;
background: #ffffff !important;
font-weight: 600 !important;
}
.dark .ai-response td {
border-bottom: 1px solid #2d3748 !important;
color: #f9fafb !important;
background: #1e1e2d !important;
}
.ai-response tr:last-child td {
border-bottom: none;
}
.ai-response tr:nth-child(even) td {
background: #f1f5f9 !important;
color: #111827 !important;
}
.dark .ai-response tr:nth-child(even) td {
background: #2a2a3a !important;
color: #f9fafb !important;
}
.ai-response h1, .ai-response h2, .ai-response h3 {
color: #6366f1;
margin: 1rem 0 0.5rem 0;
}
.ai-response strong {
color: #111827 !important;
font-weight: 700 !important;
}
.dark .ai-response strong {
color: #f9fafb !important;
font-weight: 700 !important;
}
.ai-response em {
color: #6b7280;
}
.dark .ai-response em {
color: #94a3b8;
}
.ai-response p {
color: #1f2937;
}
.dark .ai-response p {
color: #e2e8f0;
}

/* Message bubble backgrounds */
.message-bubble-ai {
background: #ffffff;
border: 1px solid #e5e7eb;
color: #1f2937;
}
.dark .message-bubble-ai {
background: #1e1e2d !important;
border: 1px solid #2d3748 !important;
color: #e2e8f0 !important;
}
.message-bubble-user {
background: #f3f4f6;
border: 1px solid #e5e7eb;
color: #1f2937;
}
.dark .message-bubble-user {
background: #1e293b !important;
border: 1px solid #2d3748 !important;
color: #e2e8f0 !important;
}

/* Text inside message bubbles */
.message-bubble-ai p, .message-bubble-ai * {
color: #1f2937 !important;
}
.dark .message-bubble-ai p, .dark .message-bubble-ai * {
color: #e2e8f0 !important;
}
.message-bubble-user p, .message-bubble-user * {
color: #1f2937 !important;
}
.dark .message-bubble-user p, .dark .message-bubble-user * {
color: #e2e8f0 !important;
}
.image-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
}
.image-modal img {
margin: auto;
display: block;
max-width: 90%;
max-height: 90%;
margin-top: 5%;
}
.image-modal .close {
position: absolute;
top: 15px;
right: 35px;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
cursor: pointer;
}
.image-modal .close:hover {
color: #bbb;
}

/* Copy button styling */
.copy-button {
position: absolute;
top: 8px;
right: 8px;
background: rgba(99, 102, 241, 0.8);
color: white;
border: none;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s;
}
.copy-button:hover {
background: rgba(99, 102, 241, 1);
}
.message-bubble-ai:hover .copy-button,
.message-bubble-user:hover .copy-button {
opacity: 1;
}
.message-bubble-ai,
.message-bubble-user {
position: relative;
}
</style>
</head>
<body class="bg-light-bg dark:bg-dev-darker min-h-screen text-light-text dark:text-dev-text transition-colors duration-300">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-8">
<div class="flex justify-between items-center">
<div class="flex items-center">
<h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
</div>
<button id="themeToggle" class="bg-dev-accent text-white px-4 py-2 rounded hover:bg-dev-accent-hover transition">
🌙 Dark
</button>
</div>
<p class="text-light-text-muted dark:text-dev-text-muted mt-2">Chat with our AI Agent to help you with your questions!</p>
</header>

<!-- Chat Interface -->
<div class="bg-light-bg-secondary dark:bg-dev-dark rounded-xl shadow-lg p-6 chat-container border border-light-border dark:border-dev-border flex flex-col">
<div class="message-container flex-grow mb-4 bg-light-bg dark:bg-dev-darker rounded-lg p-4" id="messageContainer">
<div class="flex mb-4">
<div class="w-10 h-10 rounded-full bg-dev-accent bg-opacity-20 flex items-center justify-center mr-3">
<span class="text-lg">🤖</span>
</div>
<div class="message-bubble-ai rounded-lg p-3 max-w-3xl">
<p>Welcome to the AI Agent! How can I help you today?</p>
</div>
</div>
<!-- Messages will be added here dynamically -->
</div>

<!-- Input Area -->
<div class="border-t border-light-border dark:border-dev-border pt-4 mt-auto">
<form id="chatForm" class="flex w-full">
<input type="file" id="fileInput" class="hidden" accept=".jpg,.jpeg,.png">
<button type="button" id="fileButton" class="bg-dev-accent text-white px-4 py-3 rounded-l-lg hover:bg-dev-accent-hover transition flex items-center justify-center">
📎
</button>
<input type="text" id="userInput" class="flex-grow bg-light-bg dark:bg-dev-darker border border-light-border dark:border-dev-border px-4 py-3 focus:outline-none focus:ring-2 focus:ring-dev-accent text-light-text dark:text-dev-text" placeholder="Please ask your question...">
<button type="submit" class="bg-dev-accent text-white px-6 py-3 rounded-r-lg hover:bg-dev-accent-hover transition">Send</button>
</form>
</div>
</div>
</div>

<!-- Image zoom modal -->
<div id="imageModal" class="image-modal">
<span class="close">&times;</span>
<img id="modalImage" src="" alt="">
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
// Configure marked.js for tables
marked.setOptions({
gfm: true,
tables: true,
breaks: true
});

const messageContainer = document.getElementById('messageContainer');
const chatForm = document.getElementById('chatForm');
const userInput = document.getElementById('userInput');
const fileInput = document.getElementById('fileInput');
const fileButton = document.getElementById('fileButton');

// File upload button click handler
fileButton.addEventListener('click', function() {
fileInput.click();
});

let selectedFile = null;
let currentFileBase64 = null;
let currentFileName = null;

// File selection handler
fileInput.addEventListener('change', async function(e) {
const file = e.target.files[0];
if (file) {
try {
// Convert file to base64 and store locally
currentFileBase64 = await fileToBase64(file);
currentFileName = file.name;

// Show file attached message with image preview
addImageMessage(file);
console.log('File processed successfully, base64 length:', currentFileBase64.length);

// Automatically analyze the document by sending empty prompt
await sendDocumentAnalysis();

} catch (error) {
console.error('Error processing file:', error);
addMessage('Error processing file. Please try again.', 'ai');
}
}
});

// Function to add image message with preview
function addImageMessage(file) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex mb-4';

// Create image preview URL
const imageUrl = URL.createObjectURL(file);

messageDiv.innerHTML = `
<div class="ml-auto flex">
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
<button class="copy-button" data-copy-text="File attached:
${file.name}">📋</button>
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached:
${file.name}</p>
<img src="
${imageUrl}" alt="${file.name}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
</div>
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
<span class="text-lg">👤</span>
</div>
</div>
`
;
messageContainer.appendChild(messageDiv);
messageContainer.scrollTop = messageContainer.scrollHeight;
}

// Copy to clipboard function
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(function() {
console.log('Text copied to clipboard');
}).catch(function(err) {
console.error('Failed to copy text: ', err);
});
}

// Event delegation for copy buttons
messageContainer.addEventListener('click', function(e) {
if (e.target.classList.contains('copy-button')) {
const textToCopy = e.target.getAttribute('data-copy-text');
copyToClipboard(textToCopy);
}
});

// Function to send document analysis with empty prompt and clear file after
async function sendDocumentAnalysis() {
try {
// Show loading indicator
const loadingId = showLoading();

console.log('Sending document analysis with empty prompt');
const response = await fetch('api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: "", // Empty prompt - server will use default analysis prompt
fileBase64: currentFileBase64,
fileName: currentFileName
})
});

// Remove loading indicator
removeLoading(loadingId);

if (!response.ok) {
throw new Error('Failed to analyze document');
}

const analysisResult = await response.text();
addMessage(analysisResult, 'ai');

// Clear file data so subsequent chats are text-only
currentFileBase64 = null;
currentFileName = null;
fileInput.value = ''; // Clear file input

} catch (error) {
console.error('Error analyzing document:', error);
addMessage('I don\'t know - there was an error analyzing the document.', 'ai');
// Clear file data even on error
currentFileBase64 = null;
currentFileName = null;
fileInput.value = '';
}
};

chatForm.addEventListener('submit', async function(e) {
e.preventDefault();

const message = userInput.value.trim();
if (!message) return;

// Add user message to chat
addMessage(message, 'user');
userInput.value = '';

try {
// Show loading indicator
const loadingId = showLoading();

// Always use the unified chat endpoint
console.log('Sending request to unified endpoint');
if (currentFileBase64) {
console.log('Including file data:', currentFileName, 'Base64 length:', currentFileBase64.length);
}

const response = await fetch('api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: message,
fileBase64: currentFileBase64 || null,
fileName: currentFileName || null
})
});

if (!response.ok) {
throw new Error('Failed to get response');
}

const data = await response.text();

// Remove loading indicator
removeLoading(loadingId);

// Add AI response to chat
addMessage(data, 'ai');
} catch (error) {
console.error('Error:', error);
addMessage('Sorry, I encountered an error. Please try again.', 'ai');
}
});

function addMessage(content, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex mb-4';

if (sender === 'user') {
messageDiv.innerHTML = `
<div class="ml-auto flex">
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
<button class="copy-button" data-copy-text="
${escapeHtml(content)}">📋</button>
<p class="text-light-text dark:text-dev-text">
${escapeHtml(content)}</p>
</div>
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
<span class="text-lg">👤</span>
</div>
</div>
`
;
} else {
// Always parse AI responses as markdown
console.log('Parsing AI response as markdown:', content.substring(0, 200));
const renderedContent = marked.parse(content);
console.log('Rendered HTML:', renderedContent.substring(0, 200));

messageDiv.innerHTML = `
<div class="w-10 h-10 rounded-full bg-dev-accent bg-opacity-20 flex items-center justify-center mr-3">
<span class="text-lg">🤖</span>
</div>
<div class="message-bubble-ai rounded-lg p-3 max-w-4xl ai-response">
<button class="copy-button" data-copy-text="
${escapeHtml(content)}">📋</button>
${renderedContent}
</div>
`
;
}

messageContainer.appendChild(messageDiv);
messageContainer.scrollTop = messageContainer.scrollHeight;
}

function showLoading() {
const loadingId = 'loading-' + Date.now();
const loadingDiv = document.createElement('div');
loadingDiv.id = loadingId;
loadingDiv.className = 'flex mb-4';
loadingDiv.innerHTML = `
<div class="w-10 h-10 rounded-full bg-dev-accent bg-opacity-20 flex items-center justify-center mr-3">
<span class="text-lg">🤖</span>
</div>
<div class="message-bubble-ai rounded-lg p-3">
<div class="flex space-x-2">
<div class="w-2 h-2 bg-dev-accent rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-dev-accent rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
<div class="w-2 h-2 bg-dev-accent rounded-full animate-bounce" style="animation-delay: 0.4s"></div>
</div>
</div>
`
;
messageContainer.appendChild(loadingDiv);
messageContainer.scrollTop = messageContainer.scrollHeight;
return loadingId;
}

function removeLoading(loadingId) {
const loadingDiv = document.getElementById(loadingId);
if (loadingDiv) {
loadingDiv.remove();
}
}

function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = error => reject(error);
});
}

function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}

// Image zoom functionality
window.openImageModal = function(imageSrc) {
const modal = document.getElementById('imageModal');
const modalImg = document.getElementById('modalImage');
modal.style.display = 'block';
modalImg.src = imageSrc;
}

// Close modal when clicking the X or outside the image
document.getElementById('imageModal').addEventListener('click', function(e) {
if (e.target === this || e.target.className === 'close') {
this.style.display = 'none';
}
});

// Theme toggle functionality
const themeToggle = document.getElementById('themeToggle');
const body = document.body;

themeToggle.addEventListener('click', function() {
const html = document.documentElement;
html.classList.toggle('dark');

if (html.classList.contains('dark')) {
themeToggle.innerHTML = '☀️ Light';
} else {
themeToggle.innerHTML = '🌙 Dark';
}
});
});
</script>
</body>
</html>
EOF











Running the AI Agent



Configure AWS credentials in the terminal. The assumed role or user should have access to Amazon Bedrock models.




export AWS_REGION=us-east-1









Start the Application






./mvnw spring-boot:run









Test the Application




  1. Open your browser and navigate to http://localhost:8080

  2. Try some sample interactions:




Hi, my name is Alex. Who are you?




The first chat with the AI Agent



The AI agent will respond, but its responses will be generic.



Let's fix this and add an AI Agent Persona.



Stop the application with Ctrl+C.






Commit Changes






git add .
git commit -m "Create the AI agent"









Defining System Prompt and Persona



The system prompt defines the AI agent's personality and behavior:



ChatService.java




    ...
public static final String SYSTEM_PROMPT = """
You are a helpful and honest AI Agent for our company.
You can help with questions related to travel and expenses.

Follow these guidelines strictly:
1. ACCURACY FIRST: Only provide information you are confident about based on your training data.
2. ADMIT UNCERTAINTY: If you are unsure about any fact, detail, or answer, respond with "I don't know" or "I'm not certain about that."
3. NO SPECULATION: Do not guess, speculate, or make up information. It's better to say "I don't know" than to provide potentially incorrect information.
4. PARTIAL KNOWLEDGE: If you know some aspects of a topic but not others, clearly state what you know and what you don't know.
5. SOURCES: Do not claim to have access to real-time information, current events after your training cutoff, or specific databases unless explicitly provided.
6. TABLE FORMAT: Always use clean markdown tables for structured data presentation.

Example responses:
- "I don't know the current stock price of that company."
- "I'm not certain about the specific details of that recent event."
- "I don't have enough information to answer that question accurately."
Remember: Being honest about limitations builds trust. Always choose "I don't know" over potentially incorrect information.
"""
;
...
this.chatClient = chatClientBuilder
.defaultSystem(SYSTEM_PROMPT)
.build();
...






This gives the AI agent:




  • A specific business context (Travel and Expenses Agent)

  • Behavioral guidelines (friendly, helpful, concise)

  • Honesty constraints (admit when it doesn't know something)






Test the Application



Now you can test the AI Agent using the Web UI:




Hi, my name is Alex. Who are you?




or the REST API directly:




curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{"prompt": Hi, my name is Alex. Who are you?"}' \
--no-buffer






The AI Agent has a Persona now



Nice! Now the AI Agent has a persona which is aligned with our requirements!



Let's continue the chat:




What is my name?




The AI Agent doesn't yet have memory



Unfortunately, the AI Agent doesn't remember my name, even though I provided it.



We will fix this in the next part of the blog series! Stay tuned!






Commit Changes






git add .
git commit -m "Add the Persona"









Cleaning Up



To stop the application, press Ctrl+C in the terminal where it's running.






Conclusion



In this blog post, we've successfully created a complete AI agent application using Java and Spring AI with Amazon Bedrock integration. We've covered:




  • Setting up a Spring Boot project with Spring AI dependencies

  • Configuring Amazon Bedrock integration

  • Creating REST APIs with streaming responses

  • Building a modern web interface with real-time chat

  • Implementing AI agent personas with system prompts



The application demonstrates the power of Spring AI's unified programming model, making it easy to integrate sophisticated AI capabilities into Java applications. The streaming responses provide an excellent user experience, while the persona system allows for customized AI behavior.



GenAI Challenges and Solutions



In the next part of this series, we'll explore advanced features of the AI agent.



Let's continue building intelligent Java applications with Spring AI!

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - A Practical Guide to Building AI Agents With Java and Spring AI - Part 1 - Create an AI Agent
id: d6b6cb9f-78da-4c5d-b31e-c0137020f1ab
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "A Practical Guide to Building " ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich A Practical Guide to Building AI Agents .... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten A Practical Guide to Building AI Agents With Java and Spring AI - Part 1 - Create an AI Agent

Thematisch verwandte Begriffe: Practical, Guide, Building, Agents · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96676 | A vulnerability was identified in Fast FAC1900R 20190827_2.0.2. The impa…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick