Czy wiesz że w mniej niż godzinę zbudujesz i uruchomisz agenta AI? Agenta opartego o Spring AI, z wystawionym endpointem HTTP, gotowym do konteneryzacji i docker compose up. Pokażę Ci jak podłączyć narzędzia (Tools) w dwóch wariantach: własne metody oznaczone @Tool
oraz serwer MCP (np. Brave/DuckDuckGo) w Compose.
Co zbudujemy
- Spring Boot + Spring AI z prostym endpointem
POST /chat
. - Tool Calling: metoda Java oznaczona
@Tool
, którą model może wywołać. - (Opcjonalnie) MCP: drugi „zewnętrzny” tool przez Model Context Protocol (np. web search).
- Dockerfile + Docker Compose z sekretami i uruchamianiem całego stosu.
Wymagania
- Java 21, Maven
- Docker + Docker Compose
- (Opcjonalnie) Klucz API do dostawcy modelu (np. OpenAI) – trzymamy w sekrecie
1) Inicjalizacja projektu
Najprościej zacząć od Spring Initializr – wybierz Spring Boot 3.4+, dodaj „Web” oraz startery Spring AI. Ręcznie w pom.xml
możesz dodać:
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
<version>1.0.1</version>
</dependency>
<!-- MCP klient, żeby podpiąć zewnętrzne serwery narzędzi (np. Brave/DuckDuckGo) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Konfiguracja minimalna w src/main/resources/application.yml
:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY:} # NIE trzymaj klucza w repo; wstrzykniemy go z Dockera
chat:
options:
# Możesz wskazać model, np.:
# model: gpt-4o-mini
# temperature: 0.2
# (Opcjonalnie) MCP – rejestrujemy serwer zewnętrznych narzędzi
# ai:
# mcp:
# clients:
# search:
# transport: http-sse
# endpoint: http://mcp-brave:8080/ # nazwa usługi z Compose
# auto-initialize: true
2) Minimalny agent: ChatClient + @Tool
Spring AI pozwala wystawić metody jako tools, po które może sięgnąć model w trakcie rozmowy (Function/Tool Calling). Na start zróbmy prosty tool zwracający „plan dnia” na podstawie promptu.
package dev.softwareveteran.agent;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
record ChatRequest(String message) {}
record ChatResponse(String content) {}
@Component
class PlanningTools {
@Tool(name = "plan_day", description = "Tworzy krótki plan dnia na podstawie preferencji użytkownika.")
public String planDay(String preferences) {
// Tu mógłbyś podpiąć swoje API/kalendarz. Na razie demo.
return """
- 08:00 poranna kawa ☕
- 09:00 deep work nad najważniejszym zadaniem
- 12:30 szybki lunch
- 14:00 spotkania
- 17:30 sport/relaks
""";
}
}
@RestController
@RequestMapping("/chat")
class ChatController {
private final ChatClient chat;
ChatController(ChatClient.Builder builder, PlanningTools tools) {
this.chat = builder
.defaultSystem("Jesteś pomocnym asystentem architekta oprogramowania. " +
"Jeśli użytkownik pyta o plan dnia, skorzystaj z narzędzia 'plan_day'.")
.tools(tools) // <- .build="" chat="" chatrequest="" chatresponse="" code="" content="" equestbody="" new="" ool="" ostmapping="" public="" rejestrujemy="" req="" return="" var="">->
Test lokalny:
./mvnw spring-boot:run
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d '{"message":"Zaproponuj plan dnia dla pracy koncepcyjnej i sportu wieczorem"}'
3) (Opcjonalnie) Narzędzia przez MCP (np. web search)
Gdy potrzebujesz „prawdziwych” akcji – wyszukiwania w sieci, plików, pogody – nie musisz wszystkiego programować sam. MCP (Model Context Protocol) udostępnia gotowe serwery narzędzi, które Twój agent może wywoływać jak zwykłe tools. Wystarczy dodać starter klienta MCP i wskazać endpoint MCP w konfiguracji (sekcja powyżej), a następnie dorzucić poradnikowo prosty advisor w budowie klienta (Spring AI zrobi większość za Ciebie). W Compose dołożymy kontener z serwerem MCP, np. Brave Search lub DuckDuckGo.
4) Dockerfile – produkcyjny build Javy
# --- build stage ---
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn -q -DskipTests dependency:go-offline
COPY src ./src
RUN mvn -q -DskipTests package
# --- runtime stage ---
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
# Zadbaj o sensowne limity pamięci w runtime:
ENV JAVA_TOOL_OPTIONS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75"
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]
5) Docker Compose – jeden plik, cały stos
Przykładowy compose.yaml
uruchamia aplikację oraz (opcjonalnie) serwer MCP Brave Search. Klucz API do modelu przekazujemy jako secret – bezpiecznie i poza obrazem.
name: spring-ai-agent
services:
app:
build: .
image: swv/spring-ai-agent:latest
ports:
- "8080:8080"
environment:
# Spring AI pobierze klucz z env – nie wklejaj go do application.yml
OPENAI_API_KEY_FILE: /run/secrets/openai_api_key
# Jeśli korzystasz z MCP (sekcja application.yml):
# SPRING_AI_MCP_CLIENTS_SEARCH_ENDPOINT: http://mcp-brave:8080/
secrets:
- openai_api_key
depends_on:
- mcp-brave
# Opcjonalnie healthcheck
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/actuator/health"]
interval: 15s
timeout: 3s
retries: 10
# (opcjonalnie) Serwer MCP Brave Search – wymaga BRAVE_API_KEY
mcp-brave:
image: shoofio/brave-search-mcp-sse:latest
environment:
BRAVE_API_KEY_FILE: /run/secrets/brave_api_key
PORT: "8080"
ports:
- "18080:8080"
secrets:
- brave_api_key
secrets:
openai_api_key:
file: ./secret.openai-api-key
brave_api_key:
file: ./secret.brave-api-key
Uruchomienie:
# 1) Zapisz sekrety do plików (po jednym w linii)
echo "sk-...twoj-openai-key..." > secret.openai-api-key
echo "brv-...twoj-brave-key..." > secret.brave-api-key
# 2) Odpal całość
docker compose up --build
# 3) Test
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d '{"message":"Znajdź najnowsze wieści o Spring AI i zrób 3-punktowe streszczenie"}'
Uwaga: jeśli nie chcesz MCP – usuń usługę mcp-brave
i odpowiadające jej zmienne. Zamiast OpenAI możesz podłączyć lokalny model przez Docker Model Runner/Ollama – wtedy w konfiguracji Spring AI wybierz odpowiedniego providera i endpoint.
Co dalej?
- Dodaj pamięć rozmowy i RAG (Vector Store) – Spring AI ma gotowe adaptery.
- Dołóż drugi/zewnętrzny tool (np. pogodę/finanse) i pozwól modelowi decydować, którego użyć.
- Wydziel agenta do osobnego mikroserwisu; dziel się nim przez HTTP/GRPC.