Bloqlara qayıt
13.10.2026 11 dəqiqə

Java ilə Süni İntellekt — Part 2: Spring AI ilə chatbot

JavaSpring AIChatbotSüni İntellekt
Java ilə Süni İntellekt — Part 2: Spring AI ilə chatbot

Seriyanın birinci hissəsində Java-nın öz HttpClient-i ilə AI API-sinə sorğu göndərdik. Bu hissədə eyni işi Spring AI ilə edəcəyik və Spring Boot üzərində tam işlək bir Java chatbot quracağıq. Gördüyünüz kimi, əvvəl 50 sətir tutan kod burada bir neçə sətrə enir. Ən əsası, bu kod real layihəyə hazırdır.

Bu məqalədə nə öyrənəcəksiniz

  • Spring AI layihəsini sıfırdan qurmağı
  • ChatClient ilə REST chatbot endpoint-i yazmağı
  • Cavabı ChatGPT-dəki kimi söz-söz göstərmək üçün streaming-i
  • Söhbət yaddaşını (chat memory) və cavabı Java record-una çevirməyi
  • Tool calling: AI-ın öz Java metodlarınızı çağırmasını

📚 "Java ilə Süni İntellekt" seriyası

  1. Part 1: Giriş və ilk AI tətbiqi
  2. Part 2: Spring AI ilə chatbot (bu məqalə)
  3. Part 3: RAG, öz datanla işləyən AI

Spring AI nədir?

Spring AI, Spring komandasının rəsmi layihəsidir və AI modelləri ilə işləməyi Spring-in tanış üslubuna gətirir: avtomatik konfiqurasiya, dependency injection, application.properties ilə idarə. Onun ən böyük üstünlüyü provayderdən asılı olmamasıdır: kodunuz eyni qalır, yalnız asılılığı və konfiqurasiyanı dəyişməklə Anthropic Claude, OpenAI, Google Gemini və ya lokal Ollama modelinə keçə bilərsiniz.

Layihənin qurulması

start.spring.io saytında Java 21, Maven və Spring Web seçərək yeni layihə yaradın. Sonra pom.xml-a Spring AI BOM-u və model asılılığını əlavə edin:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Claude modeli üçün. OpenAI üçün: spring-ai-starter-model-openai -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-anthropic</artifactId>
    </dependency>
</dependencies>

application.properties faylında API açarı mühit dəyişənindən oxunur:

spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
spring.ai.anthropic.chat.options.model=claude-sonnet-5-5
spring.ai.anthropic.chat.options.max-tokens=1000

İlk chatbot endpoint-i

Spring AI avtomatik olaraq ChatClient.Builder bean-i yaradır. Biz ondan öz ChatClient-imizi qururuq və botun "xarakterini" system prompt ilə təyin edirik:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder
                .defaultSystem("""
                        Sən ITBrains akademiyasının köməkçisisən.
                        Azərbaycan dilində, qısa və aydın cavab ver.
                        Proqramlaşdırma suallarında kod nümunəsi göstər.
                        """)
                .build();
    }

    @GetMapping("/api/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

Tətbiqi işə salıb sınayın:

./mvnw spring-boot:run

curl "http://localhost:8080/api/chat?message=Java-da%20record%20nədir"

Part 1-də əl ilə yazdığımız HTTP sorğusu, başlıqlar, JSON çevrilməsi və xəta idarəsi indi Spring AI-ın içindədir. prompt().user(...).call().content() zənciri oxunaqlıdır və hər addımı aydındır.

Streaming: cavabı söz-söz göstərmək

Uzun cavabı tam hazır olana qədər gözləmək istifadəçi üçün darıxdırıcıdır. ChatGPT-dəki kimi mətnin yazıldıqca görünməsi üçün call() əvəzinə stream() istifadə edirik. Bunun üçün layihədə spring-boot-starter-webflux da olmalıdır (Flux tipi üçün).

import org.springframework.http.MediaType;
import reactor.core.publisher.Flux;

@GetMapping(value = "/api/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .stream()
            .content();
}

Brauzer tərəfində bu axını EventSource ilə oxumaq olar:

const source = new EventSource('/api/chat/stream?message=' + encodeURIComponent(sual));
source.onmessage = (event) => {
    cavabElementi.textContent += event.data;
};
source.onerror = () => source.close();

Söhbət yaddaşı (Chat Memory)

Part 1-dən xatırlayırsınız: LLM yaddaşsızdır və tarixçəni hər dəfə özümüz göndərməliyik. Spring AI bunu advisor mexanizmi ilə avtomatik edir. Hər istifadəçinin söhbəti ayrıca conversationId ilə saxlanılır:

import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;

@RestController
public class MemoryChatController {

    private final ChatClient chatClient;

    public MemoryChatController(ChatClient.Builder builder) {
        // Hər söhbətdən yalnız son 20 mesaj saxlanılır: xərc nəzarətdə qalır
        ChatMemory memory = MessageWindowChatMemory.builder()
                .maxMessages(20)
                .build();

        this.chatClient = builder
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(memory).build())
                .build();
    }

    @GetMapping("/api/chat/{sessionId}")
    public String chat(@PathVariable String sessionId, @RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, sessionId))
                .call()
                .content();
    }
}

Default olaraq yaddaş serverin RAM-ında saxlanılır və server yenidən başlayanda silinir. Production üçün Spring AI-ın JDBC əsaslı yaddaşından istifadə edib söhbətləri PostgreSQL-də saxlaya bilərsiniz.

Cavabı Java obyektinə çevirmək (Structured Output)

Çox vaxt AI-dan mətn yox, struktur məlumat lazımdır, məsələn tələbəyə kurs tövsiyəsi. Spring AI cavabı birbaşa Java record-una çevirə bilir. Lazım olan JSON formatını modelə özü izah edir:

record KursTovsiyesi(String kurs, String sebeb, List<String> ilkMovzular, int tehminiAy) {}

@GetMapping("/api/tovsiye")
public KursTovsiyesi tovsiye(@RequestParam String maraq) {
    return chatClient.prompt()
            .user(u -> u.text("""
                    Tələbənin maraqları: {maraq}.
                    Ona Back End (Java), Front End, UX/UI və Data Analitika
                    kurslarından birini tövsiyə et.
                    """).param("maraq", maraq))
            .call()
            .entity(KursTovsiyesi.class);
}

Nəticə tipli Java obyektidir və onu birbaşa bazaya yaza, başqa servisə ötürə və ya JSON kimi qaytara bilərsiniz:

{
  "kurs": "Back End (Java)",
  "sebeb": "Məntiqi tapşırıqları və sistemlərin necə işlədiyini öyrənməyi sevirsiniz.",
  "ilkMovzular": ["Core Java", "OOP", "SQL", "Spring Boot"],
  "tehminiAy": 6
}

Tool Calling: AI sizin Java metodlarınızı çağırır

Model təlim datasından kənar məlumatı, məsələn kursun bugünkü qiymətini və ya qrupun başlama tarixini bilmir. Tool calling ilə modelə Java metodlarınızı "alət" kimi veririk. Model lazım bildikdə onları çağırır, nəticəni alıb cavabını onun əsasında qurur:

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;

@Component
public class KursAletleri {

    private final CourseRepository courseRepository;

    public KursAletleri(CourseRepository courseRepository) {
        this.courseRepository = courseRepository;
    }

    @Tool(description = "Kursun növbəti qrupunun başlama tarixini və qiymətini qaytarır")
    public String kursMelumati(@ToolParam(description = "Kursun adı, məs. Back End") String kursAdi) {
        return courseRepository.findByNameContainingIgnoreCase(kursAdi)
                .map(k -> "Başlama: " + k.getStartDate() + ", qiymət: " + k.getPrice())
                .orElse("Belə kurs tapılmadı");
    }
}
@GetMapping("/api/assistant")
public String assistant(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .tools(kursAletleri)   // modelə alətləri təqdim edirik
            .call()
            .content();
}

İndi istifadəçi "Back End kursu nə vaxt başlayır?" soruşduqda model özü kursMelumati("Back End") metodunu çağırır və cavabı bazadakı real məlumatla verir. AI agentləri məhz bu prinsiplə qurulur.

Təhlükəsizlik qaydası: modelə yalnız oxuyan (read-only) və ya təhlükəsiz alətlər verin. "Sifarişi sil" kimi alətləri mütləq əlavə yoxlama və istifadəçi təsdiqi ilə qoruyun.

Production üçün məsləhətlər

  • Rate limiting: bir istifadəçinin dəqiqədə neçə sorğu göndərə biləcəyini məhdudlaşdırın, yoxsa AI xərci gözlənilmədən arta bilər.
  • Timeout və retry: Spring AI 429 və 5xx xətalarında avtomatik təkrar cəhd edir. Bunu spring.ai.retry.* parametrləri ilə tənzimləyin.
  • Loglama: sorğu və cavabların token sayını loglayın. SimpleLoggerAdvisor debug üçün rahatdır.
  • Prompt injection: istifadəçi "əvvəlki təlimatları unut" yaza bilər. Kritik qaydaları kodda yoxlayın, yalnız prompt-a güvənməyin.

Spring Boot-u real layihələrdə öyrənmək istəyirsiniz? ITBrains-in Back End (Java) proqramında REST API, Spring Security, verilənlər bazası və deploy mövzularını praktiki tapşırıqlarla keçirik.

Tədris proqramlarına baxın →

Tez-tez verilən suallar

Spring AI pulsuzdur?

Bəli, Spring AI açıq mənbəli (Apache 2.0) kitabxanadır. Ödəniş yalnız istifadə etdiyiniz AI provayderinin API-si üçündür. Lokal Ollama modelləri ilə tamamilə pulsuz işləmək də mümkündür.

Spring AI ilə LangChain4j arasında fərq nədir?

Hər ikisi Java-da AI tətbiqləri qurmaq üçündür. Spring AI Spring Boot ilə dərin inteqrasiya olunub və Spring üslubunu izləyir. LangChain4j isə framework-dən asılı deyil, Quarkus və sadə Java layihələrində də rahat işləyir. Layihəniz Spring Boot-dadırsa, Spring AI daha təbii seçimdir.

Spring AI üçün hansı Java versiyası lazımdır?

Spring AI 1.x Spring Boot 3.4+ və Java 17+ tələb edir. Yeni layihələr üçün Java 21 tövsiyə olunur, çünki virtual thread-lər AI API-lərinə gedən çoxlu paralel sorğu üçün çox faydalıdır.

OpenAI-dan Claude-a keçmək üçün kodu dəyişməliyəm?

Xeyr. ChatClient kodu eyni qalır. Yalnız pom.xml-dakı starter asılılığını və application.properties-dəki açarı dəyişirsiniz.

Növbəti addım

Artıq yaddaşı olan, cavabı axınla göstərən və öz Java metodlarımızı çağıran chatbot-umuz var. Amma model hələ də sizin şirkətinizin sənədlərini, kurs proqramlarını, daxili qaydalarını bilmir. Part 3: RAG, öz datanla işləyən AI hissəsində embedding və vector store ilə AI-a öz biliyimizi verəcəyik.