Bloqlara qayıt
13.10.2026 12 dəqiqə

Java ilə Süni İntellekt — Part 3: RAG, öz datanla AI

JavaRAGSpring AIVector Store
Java ilə Süni İntellekt — Part 3: RAG, öz datanla AI

Seriyanın son hissəsinə xoş gəldiniz. Part 2-də Spring AI ilə chatbot qurduq, amma onun bir böyük çatışmazlığı var: model yalnız öyrədildiyi ümumi məlumatı bilir. Sizin kurs proqramlarınızı, şirkət sənədlərinizi və ya daxili qaydalarınızı bilmir və bilmədiyi şeyi "uydura" bilir. Bu məqalədə Java ilə RAG (Retrieval-Augmented Generation) quraraq bu problemi həll edəcəyik: süni intellekt cavabı öz datanız əsasında verəcək.

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

  • RAG nədir və nə üçün fine-tuning-dən daha praktikdir
  • Embedding və vector store anlayışlarını sadə dillə
  • Spring AI ilə sənədləri hissələrə bölüb vector store-a yükləməyi
  • QuestionAnswerAdvisor ilə öz datanızla cavab verən chatbot-u
  • Pulsuz lokal modellər (Ollama) və production üçün PostgreSQL pgvector

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

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

RAG nədir?

RAG-ın ideyası sadədir: modelə sual verməzdən əvvəl öz bazamızdan bu suala aid məlumatı tapırıq və onu sualla birlikdə modelə göndəririk. Model cavabı yaddaşından yox, ona verdiyimiz mətndən qurur. Bu, imtahanda "açıq kitab" icazəsi kimidir.

  1. Hazırlıq (bir dəfə): sənədləri kiçik hissələrə bölürük, hər hissəni embedding-ə çeviririk və vector store-da saxlayırıq.
  2. Axtarış (hər sualda): istifadəçinin sualını da embedding-ə çeviririk və mənaca ona ən yaxın hissələri tapırıq.
  3. Cavab: tapılan hissələri sualla birlikdə LLM-ə göndəririk: "Yalnız bu məlumata əsasən cavab ver."
RAGFine-tuning
Məlumat yeniləməSənədi əlavə etmək kifayətdir, dərhal işləyirModeli yenidən öyrətmək lazımdır
XərcAşağıYüksək
Mənbə göstərməkMümkündür, hansı sənəddən götürüldüyü məlumdurÇətindir
Uydurma (hallucination)Xeyli azalırQalır

Embedding və vector store sadə dillə

Embedding mətnin mənasını rəqəmlər siyahısına (vektora) çevirməkdir. Mənaca yaxın cümlələrin vektorları da bir-birinə yaxın olur. Məsələn, "Java kursu neçə ay çəkir?" və "Back End proqramının müddəti" cümlələrində ortaq söz demək olar yoxdur, amma vektorları çox yaxındır. Adi LIKE '%...%' axtarışından fərqi budur.

float[] vektor = embeddingModel.embed("Java kursu neçə ay çəkir?");
System.out.println(vektor.length);   // məs. 768: mətnin "mənası" 768 rəqəmlə ifadə olunub

Vector store bu vektorları saxlayan və "mənə buna ən oxşar 4 mətni tap" sorğusunu sürətlə icra edən bazadır. Spring AI-da öyrənmək üçün yaddaşda işləyən SimpleVectorStore, production üçün PostgreSQL pgvector, Redis, Elasticsearch, Qdrant və başqaları var.

Layihənin qurulması: pulsuz lokal modellərlə

Bu hissədə embedding üçün Ollama istifadə edirik: açıq modelləri öz kompüterinizdə pulsuz işə salır. Cavab üçün isə Part 2-dəki Claude modeli qalır.

# Ollama-nı quraşdırdıqdan sonra embedding modelini yükləyin
ollama pull nomic-embed-text
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<!-- QuestionAnswerAdvisor üçün -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
# Chat cavabları Claude-dan, embedding isə lokal Ollama-dan
spring.ai.model.chat=anthropic
spring.ai.model.embedding=ollama

spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
spring.ai.anthropic.chat.options.model=claude-sonnet-5-5
spring.ai.ollama.embedding.options.model=nomic-embed-text

Addım 1: Vector store bean-i

import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;

@Configuration
public class RagConfig {

    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel) {
        // Öyrənmək üçün: vektorlar RAM-da saxlanılır
        return SimpleVectorStore.builder(embeddingModel).build();
    }
}

Addım 2: Datanı yükləmək (ingestion)

Real nümunə götürək: akademiyanın kurs məlumatlarını və tez-tez verilən sualları AI-a öyrədək. Tətbiq işə düşəndə bazadakı kursları Document obyektlərinə çevirib vector store-a yazırıq. Metadata-da kursun adını saxlayırıq ki, lazım olsa süzgəc qoya və ya mənbəni göstərə bilək.

import org.springframework.ai.document.Document;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;

@Component
public class KursBilikYukleyicisi {

    private final VectorStore vectorStore;
    private final CourseRepository courseRepository;
    private final FaqRepository faqRepository;

    public KursBilikYukleyicisi(VectorStore vectorStore, CourseRepository courseRepository,
                                FaqRepository faqRepository) {
        this.vectorStore = vectorStore;
        this.courseRepository = courseRepository;
        this.faqRepository = faqRepository;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void yukle() {
        List<Document> senedler = new ArrayList<>();

        for (Course kurs : courseRepository.findAll()) {
            String metn = """
                    Kurs: %s
                    Kateqoriya: %s
                    Müddət: %s, dərs günləri: %s, saat: %s
                    Təsvir: %s
                    """.formatted(kurs.getName(), kurs.getCategoryName(), kurs.getDuration(),
                    kurs.getDays(), kurs.getTime(), kurs.getDescription());
            senedler.add(new Document(metn, Map.of("menbe", "kurs", "kurs", kurs.getName())));
        }

        for (Faq faq : faqRepository.findAll()) {
            senedler.add(new Document("Sual: " + faq.getQuestion() + "\nCavab: " + faq.getAnswer(),
                    Map.of("menbe", "faq")));
        }

        // Uzun mətnləri modelin rahat işləyəcəyi ölçüdə hissələrə bölürük
        List<Document> hisseler = new TokenTextSplitter().apply(senedler);
        vectorStore.add(hisseler);   // burada hər hissə embedding-ə çevrilir
    }
}
Niyə hissələrə bölürük? 30 səhifəlik sənədi bütöv vektora çevirsəniz, onun mənası "bulanıqlaşır" və axtarış dəqiqliyi düşür. 300-800 tokenlik hissələr adətən ən yaxşı nəticəni verir.

Addım 3: RAG ilə cavab verən chatbot

Spring AI-ın QuestionAnswerAdvisor-u yuxarıdakı 3 addımı avtomatik edir: sualı vector store-da axtarır, ən uyğun hissələri tapır və onları prompt-a əlavə edir.

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.SearchRequest;

@RestController
public class KursMeslehetcisiController {

    private final ChatClient chatClient;

    public KursMeslehetcisiController(ChatClient.Builder builder, VectorStore vectorStore) {
        this.chatClient = builder
                .defaultSystem("""
                        Sən ITBrains akademiyasının kurs məsləhətçisisən.
                        Yalnız sənə verilən kontekstdəki məlumata əsasən cavab ver.
                        Kontekstdə cavab yoxdursa, "Bu barədə dəqiq məlumatım yoxdur,
                        zəhmət olmasa bizimlə əlaqə saxlayın" de. Heç vaxt məlumat uydurma.
                        """)
                .defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore)
                        .searchRequest(SearchRequest.builder()
                                .topK(4)                     // ən oxşar 4 hissə
                                .similarityThreshold(0.6)    // çox uzaq nəticələri at
                                .build())
                        .build())
                .build();
    }

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

Sınayaq:

curl "http://localhost:8080/api/meslehetci?sual=Back%20End%20kursu%20həftədə%20neçə%20gün%20olur"

İndi model cavabı ümumi biliklərindən yox, sizin bazanızdakı real kurs məlumatından verir. Bazada kursun günlərini dəyişsəniz və yenidən yükləsəniz, cavab da dəyişəcək. Modeli yenidən öyrətməyə ehtiyac yoxdur.

Production üçün: PostgreSQL pgvector

SimpleVectorStore server yenidən başlayanda silinir və böyük həcmlər üçün uyğun deyil. Artıq PostgreSQL istifadə edirsinizsə, ən rahat seçim pgvector genişlənməsidir: vektorlar adi cədvəldə, digər datanızla yanaşı saxlanılır.

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
spring.ai.vectorstore.pgvector.initialize-schema=true
spring.ai.vectorstore.pgvector.dimensions=768
spring.ai.vectorstore.pgvector.index-type=HNSW

Bu halda RagConfig-dəki SimpleVectorStore bean-ini silirsiniz və Spring AI pgvector store-u avtomatik yaradır. Controller kodunda heç nə dəyişmir. dimensions dəyəri embedding modelinin vektor ölçüsü ilə eyni olmalıdır.

RAG keyfiyyətini artırmaq üçün 5 məsləhət

  1. Datanı təmizləyin. HTML teqləri, təkrarlanan menyular və boş sətirlər axtarışı korlayır.
  2. Metadata əlavə edin. Filial, kateqoriya, tarix. Sonra filterExpression ilə yalnız lazımi sənədlərdə axtarın.
  3. topK və similarityThreshold-u sınaqla seçin. Çox az kontekst cavabı natamam edir, çox kontekst isə modeli çaşdırır və xərci artırır.
  4. Datanı yeniləyin. Kurs dəyişəndə uyğun sənədi vector store-da da yeniləyin, məsələn JPA @EntityListeners ilə.
  5. Test sualları toplayın. 20-30 real istifadəçi sualı ilə hər dəyişiklikdən sonra cavabları yoxlayın.

Seriyanın xülasəsi

Üç hissədə Java ilə süni intellektin əsas yolunu keçdik:

  • Part 1: AI API-si əslində HTTP + JSON-dur və Java-nın öz alətləri ilə işləyir.
  • Part 2: Spring AI ilə chatbot, streaming, yaddaş, struktur cavab və tool calling.
  • Part 3: RAG ilə AI-ın öz datanızla, uydurmadan cavab verməsi.

Bu biliklərlə artıq real layihə qura bilərsiniz: şirkət daxili sənəd köməkçisi, müştəri dəstək botu, e-ticarət üçün məhsul məsləhətçisi. Növbəti addım Java-nın özünü möhkəm bilməkdir. Hansı mövzuları hansı ardıcıllıqla öyrənəcəyinizi Java Roadmap 2026 məqaləmizdə tapa bilərsiniz.

Java və Spring Boot-u mentorla, real layihələr üzərində öyrənin. ITBrains-in Back End (Java) proqramında sıfırdan başlayıb portfolionuza qoya biləcəyiniz layihələrə qədər gəlirsiniz.

Tədris proqramlarına baxın →

Tez-tez verilən suallar

Java-da RAG qurmaq üçün Python lazımdırmı?

Xeyr. Spring AI və LangChain4j sənədlərin bölünməsi, embedding, vector store və axtarış daxil olmaqla RAG-ın bütün addımlarını Java-da həyata keçirir. Bütün sistem bir Spring Boot tətbiqində işləyə bilər.

RAG üçün hansı vector store-u seçməliyəm?

Öyrənmək üçün SimpleVectorStore kifayətdir. Artıq PostgreSQL istifadə edirsinizsə, pgvector ən sadə production seçimidir. Çox böyük həcmlər və mürəkkəb axtarış üçün Qdrant, Weaviate və ya Elasticsearch-ə baxa bilərsiniz.

RAG və fine-tuning arasında necə seçim etməli?

Modelin tez-tez dəyişən faktiki məlumatı (qiymətlər, sənədlər, qaydalar) bilməsi lazımdırsa, RAG seçin. Modelin müəyyən üslubda yazması və ya xüsusi formatı öyrənməsi lazımdırsa, fine-tuning faydalı ola bilər. Praktikada layihələrin böyük əksəriyyəti üçün RAG kifayətdir.

Embedding modeli pulludurmu?

Bulud provayderlərinin embedding modelləri çox ucuzdur. Ollama ilə nomic-embed-text kimi açıq modelləri isə öz serverinizdə tamamilə pulsuz işlədə bilərsiniz. Bu məqalədəki nümunə də belədir.