PaLM ve LangChain4J ile Java'da kullanıcılar ve dokümanlarla üretken yapay zeka destekli sohbet

1. Giriş

Last Updated: 2024-02-05

Üretken yapay zeka nedir?

Üretken yapay zeka; metin, görüntü, müzik, ses ve video gibi yeni içerikler oluşturmak için yapay zekanın kullanımını ifade eder.

Üretken yapay zeka, özetleme, soru-cevap, sınıflandırma gibi kullanıma hazır görevleri yerine getirebilen ve çoklu görev yapabilen temel modeller (büyük yapay zeka modelleri) tarafından desteklenir. Ayrıca, temel modeller çok az örnek veriyle hedef kullanım alanlarına uyarlanabilir ve minimum eğitim gerektirir.

Üretken yapay zeka nasıl çalışır?

Üretken yapay zeka, insan tarafından oluşturulan içeriklerden oluşan bir veri kümesindeki kalıpları ve ilişkileri öğrenmek için bir makine öğrenimi modeli kullanarak çalışır. Ardından, öğrendiği kalıpları kullanarak yeni içerikler üretir.

Üretken yapay zeka modelini eğitmenin en yaygın yolu, gözetimli öğrenmeyi kullanmaktır. Bu yöntemde modele, insanlar tarafından oluşturulan bir dizi içerik ve bunlara karşılık gelen etiketler verilir. Ardından, kullanıcılar tarafından oluşturulan içeriklere benzer ve aynı etiketlerle etiketlenmiş içerikler üretmeyi öğrenir.

Üretken yapay zekanın yaygın uygulamaları nelerdir?

Üretken yapay zeka, metin, resim ve kullanıcı dostu formatlar aracılığıyla analizler ve yanıtlar oluşturarak büyük miktarda içeriği işler. Üretken yapay zeka şu amaçlarla kullanılabilir:

  • Gelişmiş sohbet ve arama deneyimleriyle müşteri etkileşimlerini iyileştirme
  • Sohbet arayüzleri ve özetler aracılığıyla büyük miktarda yapılandırılmamış veriyi keşfedin
  • Teklif isteklerini (RFP) yanıtlama, pazarlama içeriklerini beş dilde yerelleştirme ve müşteri sözleşmelerinin uygunluğunu kontrol etme gibi tekrarlayan görevlere yardımcı olma

Google Cloud'un üretken yapay zeka teklifleri nelerdir?

Vertex AI ile temel modellerle etkileşim kurabilir, bunları özelleştirebilir ve uygulamalarınıza yerleştirebilirsiniz. Makine öğrenimi konusunda uzman olmanız gerekmez. Model Garden'daki temel modellere erişin, Generative AI Studio'da basit bir kullanıcı arayüzü aracılığıyla modelleri ayarlayın veya modelleri bir veri bilimi not defterinde kullanın.

Vertex AI Arama ve Sohbet, geliştiricilere üretken yapay zeka destekli arama motorları ve chatbot'lar oluşturmanın en hızlı yolunu sunar.

Ayrıca, Duet AI, Google Cloud ve IDE'lerde kullanılabilen yapay zeka destekli ortak çalışma aracınızdır. Bu araç, daha fazla işi daha kısa sürede yapmanıza yardımcı olur.

Bu codelab neye odaklanıyor?

Bu codelab'de, tüm makine öğrenimi ürün ve hizmetlerini kapsayan Google Cloud Vertex AI'da barındırılan PaLM 2 büyük dil modeli (LLM) ele alınmaktadır.

PaLM API ile etkileşim kurmak için LangChain4J LLM çerçeve düzenleyicisiyle birlikte Java'yı kullanacaksınız. Soru yanıtlama, fikir üretme, varlık ve yapılandırılmış içerik ayıklama ve özetleme için LLM'den yararlanmak üzere farklı somut örnekleri inceleyeceksiniz.

LangChain4J çerçevesi hakkında daha fazla bilgi ver.

LangChain4J çerçevesi; LLM'nin kendisi, vektör veritabanları (semantik aramalar için), belge yükleyiciler ve ayırıcılar (belgeleri analiz etmek ve bunlardan öğrenmek için), çıkış ayrıştırıcılar gibi çeşitli bileşenleri düzenleyerek büyük dil modellerini Java uygulamalarınıza entegre etmenizi sağlayan açık kaynaklı bir kitaplıktır.

c6d7f7c3fd0d2951.png

Neler öğreneceksiniz?

  • PaLM ve LangChain4J kullanmak için Java projesi ayarlama
  • Yapılandırılmamış içerikten yararlı bilgileri çıkarma (varlık veya anahtar kelime çıkarma, JSON biçiminde çıktı)
  • Kullanıcılarınızla görüşme oluşturma
  • Kendi dokümanlarınızla ilgili sorular sormak için sohbet modelini kullanma

Gerekenler

  • Java programlama dili hakkında bilgi
  • Google Cloud projesi
  • Chrome veya Firefox gibi bir tarayıcı

2. Kurulum ve şartlar

Yönlendirmesiz ortam kurulumu

  1. Google Cloud Console'da oturum açın ve yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.

295004821bab6a87.png37d264871000675d.png96d86d3d5655cdbe.png

  • Proje adı, bu projenin katılımcıları için görünen addır. Google API'leri tarafından kullanılmayan bir karakter dizesidir. Dilediğiniz zaman güncelleyebilirsiniz.
  • Proje kimliği, tüm Google Cloud projelerinde benzersizdir ve sabittir (ayarlandıktan sonra değiştirilemez). Cloud Console otomatik olarak benzersiz bir dize oluşturur. Genellikle bu dizenin ne olduğuyla ilgilenmezsiniz. Çoğu codelab'de proje kimliğinize (genellikle PROJECT_ID olarak tanımlanır) başvurmanız gerekir. Oluşturulan kimliği beğenmezseniz başka bir rastgele kimlik oluşturabilirsiniz. Dilerseniz kendi adınızı deneyerek kullanılabilir olup olmadığını kontrol edebilirsiniz. Bu adım tamamlandıktan sonra değiştirilemez ve proje süresince geçerli kalır.
  • Bazı API'lerin kullandığı üçüncü bir değer olan Proje Numarası da vardır. Bu üç değer hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Ardından, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i tamamlamak çok fazla zamanınızı almaz. Bu eğitimin ötesinde faturalandırılmayı önlemek için kaynakları kapatmak üzere oluşturduğunuz kaynakları veya projeyi silebilirsiniz. Yeni Google Cloud kullanıcıları 300 ABD doları değerinde ücretsiz deneme programından yararlanabilir.

Cloud Shell'i başlatma

Google Cloud, dizüstü bilgisayarınızdan uzaktan çalıştırılabilir ancak bu codelab'de bulutta çalışan bir komut satırı ortamı olan Cloud Shell'i kullanacaksınız.

Cloud Shell'i etkinleştirme

  1. Cloud Console'da Cloud Shell'i etkinleştir 'i d1264ca30785e435.png tıklayın.

cb81e7c8e34bc8d.png

Cloud Shell'i ilk kez başlatıyorsanız ne olduğunu açıklayan bir ara ekran gösterilir. Ara ekran gösterildiyse Devam'ı tıklayın.

d95252b003979716.png

Cloud Shell'in temel hazırlığı ve bağlanması yalnızca birkaç dakikanızı alır.

7833d5e1c5d18f54.png

Bu sanal makine, ihtiyaç duyulan tüm geliştirme araçlarıyla birlikte yüklenir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu codelab'deki çalışmalarınızın neredeyse tamamını tarayıcıyla yapabilirsiniz.

Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, proje kimliğinize ayarlandığını görürsünüz.

  1. Kimliğinizin doğrulandığını onaylamak için Cloud Shell'de şu komutu çalıştırın:
gcloud auth list

Komut çıkışı

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. gcloud komutunun projeniz hakkında bilgi sahibi olduğunu onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project

Komut çıkışı

[core]
project = <PROJECT_ID>

Ayarlanmamışsa şu komutla ayarlayabilirsiniz:

gcloud config set project <PROJECT_ID>

Komut çıkışı

Updated property [core/project].

3. Geliştirme ortamınızı hazırlama

Bu codelab'de Java programlarınızı geliştirmek için Cloud Shell terminalini ve kod düzenleyiciyi kullanacaksınız.

Vertex AI API'lerini etkinleştirme

  1. Google Cloud Console'da proje adınızın Google Cloud Console'unuzun üst kısmında gösterildiğinden emin olun. Açılmıyorsa Proje Seçici'yi açmak için Proje seçin'i tıklayın ve istediğiniz projeyi seçin.
  2. Google Cloud Console'un Vertex AI bölümünde değilseniz aşağıdakileri yapın:
  3. Arama bölümüne Vertex AI yazıp Enter tuşuna basın.
  4. Arama sonuçlarında Vertex AI'ı tıklayın. Vertex AI kontrol paneli görünür.
  5. Vertex AI kontrol panelinde Enable All Recommended APIs'i (Önerilen Tüm API'leri Etkinleştir) tıklayın.

Bu işlem birkaç API'yi etkinleştirir ancak codelab için en önemlisi aiplatform.googleapis.com API'sidir. Bu API'yi komut satırında, Cloud Shell terminalinde aşağıdaki komutu çalıştırarak da etkinleştirebilirsiniz:

$ gcloud services enable aiplatform.googleapis.com

Gradle ile proje yapısını oluşturma

Java kod örneklerinizi oluşturmak için Gradle derleme aracını ve Java'nın 17. sürümünü kullanacaksınız. Projenizi Gradle ile ayarlamak için Cloud Shell terminalinde bir dizin oluşturun (burada palm-workshop) ve bu dizinde gradle init komutunu çalıştırın:

$ mkdir palm-workshop
$ cd palm-workshop

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4

Project name (default: palm-workshop): 
Source package (default: palm.workshop): 

> Task :init
Get more help with your project: https://docs.gradle.org/7.4/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 51s
2 actionable tasks: 2 executed

Alt projeleri kullanmadan (1. seçenek), Java dilini (3. seçenek) kullanarak uygulama (2. seçenek) oluşturacak, derleme dosyası için Groovy söz dizimini (1. seçenek) kullanacak, yeni derleme özelliklerini kullanmayacak (seçenek yok), JUnit Jupiter ile testler oluşturacak (4. seçenek) ve proje adı olarak palm-workshop, kaynak paketi olarak da palm.workshop kullanacaksınız.

Proje yapısı şu şekilde görünür:

├── gradle 
│   └── ...
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
└── app
    ├── build.gradle 
    └── src
        ├── main
        │   └── java 
        │       └── palm
        │           └── workshop
        │               └── App.java
        └── test
            └── ...

Gerekli bazı bağımlılıkları eklemek için app/build.gradle dosyasını güncelleyelim. guava bağımlılığını kaldırabilir ve eksik günlükçü mesajlarının gösterilmesini önlemek için LangChain4J projesinin bağımlılıkları ve günlük kaydı kitaplığıyla değiştirebilirsiniz:

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // Logging library
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
}

LangChain4J için 2 bağımlılık vardır:

  • biri temel proje,
  • ve özel Vertex AI modülü için bir tane olmak üzere iki farklı modül vardır.

Programlarımızı derlemek ve çalıştırmak için Java 17'yi kullanmak üzere aşağıdaki bloğu plugins {} bloğunun altına ekleyin:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Yapılacak bir değişiklik daha var: Kullanıcıların, derleme aracını çağırırken komut satırında çalıştırılacak ana sınıfı geçersiz kılabilmesi için app/build.gradle öğesinin application bloğunu güncelleyin:

application {
    mainClass = providers.systemProperty('javaMainClass')
                         .orElse('palm.workshop.App')
}

Derleme dosyanızın uygulamanızı çalıştırmaya hazır olup olmadığını kontrol etmek için basit bir Hello World! mesajı yazdıran varsayılan ana sınıfı çalıştırabilirsiniz:

$ ./gradlew run -DjavaMainClass=palm.workshop.App

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Artık LangChain4J projesini kullanarak PaLM büyük dil metin modeliyle programlamaya hazırsınız.

Referans olarak, tam app/build.gradle derleme dosyasının artık nasıl görünmesi gerektiği aşağıda verilmiştir:

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

java {
    toolchain {
        // Ensure we compile and run on Java 17
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'
}

application {
    mainClass = providers.systemProperty('javaMainClass').orElse('palm.workshop.App')
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

4. PaLM'nin sohbet modeline ilk çağrınızı yapma

Proje düzgün şekilde ayarlandığına göre artık PaLM API'yi çağırma zamanı.

app/src/main/java/palm/workshop dizininde (varsayılan App.java sınıfının yanında) ChatPrompts.java adlı yeni bir sınıf oluşturun ve aşağıdaki içeriği yazın:

package palm.workshop;

import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.chain.ConversationalChain;

public class ChatPrompts {
    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(400)
            .maxRetries(3)
            .build();

        ConversationalChain chain = ConversationalChain.builder()
            .chatLanguageModel(model)
            .build();

        String message = "What are large language models?";
        String answer = chain.execute(message);
        System.out.println(answer);

        System.out.println("---------------------------");

        message = "What can you do with them?";
        answer = chain.execute(message);
        System.out.println(answer);

        System.out.println("---------------------------");

        message = "Can you name some of them?";
        answer = chain.execute(message);
        System.out.println(answer);
    }
}

Bu ilk örnekte, görüşmelerin çok turlu yönünü ele almayı kolaylaştırmak için VertexAiChatModel sınıfını ve LangChain4J ConversationalChain'yi içe aktarmanız gerekir.

Ardından, main yönteminde, VertexAiChatModel için oluşturucuyu kullanarak sohbet dil modelini yapılandıracak ve şunları belirteceksiniz:

  • uç nokta,
  • gösterir.
  • bölge,
  • yayıncı,
  • ve modelin adı (chat-bison@001).

Dil modeli hazır olduğunda ConversationalChain hazırlayabilirsiniz. Bu, LangChain4J tarafından sunulan daha yüksek düzeyde bir soyutlamadır. Sohbet dil modeli gibi bir konuşmayı işlemek için farklı bileşenleri birlikte yapılandırmanın yanı sıra sohbet konuşmasının geçmişini işlemek veya bilgi almak için alıcılar gibi diğer araçları vektör veritabanlarından çekmek için de kullanılabilir. Ancak endişelenmeyin, bu konuya bu codelab'in ilerleyen bölümlerinde tekrar değineceğiz.

Ardından, birbiriyle ilişkili birkaç soru sormak için sohbet modeliyle çok adımlı bir görüşme yapacaksınız. Önce LLM'leri merak edersiniz, ardından onlarla neler yapabileceğinizi ve örneklerini sorarsınız. Kendinizi tekrar etmenize gerek kalmadığını fark edin. LLM, bu görüşme bağlamında "onlar "ın LLM'ler anlamına geldiğini biliyor.

Bu çok turlu görüşmeyi yapmak için zincirdeki execute() yöntemini çağırmanız yeterlidir. Bu yöntem, görüşmenin bağlamına eklenir. Sohbet modeli bir yanıt oluşturur ve bunu sohbet geçmişine de ekler.

Bu sınıfı çalıştırmak için Cloud Shell terminalinde aşağıdaki komutu çalıştırın:

./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

Şuna benzer bir çıkış görürsünüz:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Starting a Gradle Daemon, 2 incompatible and 2 stopped Daemons could not be reused, use --status for details

> Task :app:run
Large language models (LLMs) are artificial neural networks that are trained on massive datasets of text and code. They are designed to understand and generate human language, and they can be used for a variety of tasks, such as machine translation, question answering, and text summarization.
---------------------------
LLMs can be used for a variety of tasks, such as:

* Machine translation: LLMs can be used to translate text from one language to another.
* Question answering: LLMs can be used to answer questions posed in natural language.
* Text summarization: LLMs can be used to summarize text into a shorter, more concise form.
* Code generation: LLMs can be used to generate code, such as Python or Java code.
* Creative writing: LLMs can be used to generate creative text, such as poems, stories, and scripts.

LLMs are still under development, but they have the potential to revolutionize a wide range of industries. For example, LLMs could be used to improve customer service, create more personalized marketing campaigns, and develop new products and services.
---------------------------
Some of the most well-known LLMs include:

* GPT-3: Developed by OpenAI, GPT-3 is a large language model that can generate text, translate languages, write different kinds of creative content, and answer your questions in an informative way.
* LaMDA: Developed by Google, LaMDA is a large language model that can chat with you in an open-ended way, answering your questions, telling stories, and providing different kinds of creative content.
* PaLM 2: Developed by Google, PaLM 2 is a large language model that can perform a wide range of tasks, including machine translation, question answering, and text summarization.
* T5: Developed by Google, T5 is a large language model that can be used for a variety of tasks, including text summarization, question answering, and code generation.

These are just a few examples of the many LLMs that are currently being developed. As LLMs continue to improve, they are likely to play an increasingly important role in our lives.

BUILD SUCCESSFUL in 25s
2 actionable tasks: 2 executed

PaLM, ilgili 3 sorunuzu yanıtladı.

VertexAIChatModel oluşturucu, geçersiz kılınabilecek bazı varsayılan değerlere sahip isteğe bağlı parametreler tanımlamanıza olanak tanır. Aşağıda bazı örnekler verilmiştir:

  • .temperature(0.2): Yanıtın ne kadar yaratıcı olmasını istediğinizi tanımlamak için kullanılır (0 değeri yaratıcılığın düşük ve genellikle daha gerçekçi olduğu, 1 değeri ise daha yaratıcı çıktılar için kullanılır).
  • .maxOutputTokens(50) — örnekte, oluşturulan yanıtın ne kadar uzun olmasını istediğinize bağlı olarak 400 jeton istendi (3 jeton yaklaşık 4 kelimeye eşittir).
  • .topK(20): Metin tamamlama için olası kelimeler arasından rastgele bir kelime seçmek üzere kullanılır (1-40 arasında).
  • .topP(0.95): Toplam olasılığı bu kayan noktalı sayıya (0 ile 1 arasında) ulaşan olası kelimeleri seçmek için kullanılır.
  • .maxRetries(3) — Zaman başına istek kotasını aşıyorsanız modelin aramayı örneğin 3 kez yeniden denemesini sağlayabilirsiniz.

5. Karakter sahibi, faydalı bir chatbot

Önceki bölümde, LLM chatbot'a herhangi bir bağlam vermeden hemen soru sormaya başlamıştınız. Ancak bu tür bir chatbot'u belirli bir görevde veya konuda uzmanlaşacak şekilde özelleştirebilirsiniz.

Bunu nasıl yapıyorsunuz? Görevi açıklayarak: LLM'ye görevi, bağlamı açıklayarak, belki yapması gerekenler, hangi karakteri kullanması gerektiği, yanıtları hangi biçimde almak istediğiniz ve chatbot'un belirli bir şekilde davranmasını istiyorsanız üslup hakkında birkaç örnek vererek.

İstem oluşturma ile ilgili bu makalede, bu yaklaşım aşağıdaki grafik ile güzel bir şekilde açıklanmaktadır:

8a4c67679dcbd085.png

https://medium.com/@eldatero/master-the-perfect-chatgpt-prompt-formula-c776adae8f19

Bu noktayı açıklamak için prompts.chat web sitesinden ilham alalım. Bu web sitesinde, aşağıdakiler gibi davranmalarını sağlamak için özel olarak tasarlanmış chatbot'larla ilgili birçok harika ve eğlenceli fikir listeleniyor:

LLM chatbot'u satranç oyuncusuna dönüştürme örneğini inceleyin. Haydi bunu uygulayalım.

ChatPrompts sınıfını aşağıdaki şekilde güncelleyin:

package palm.workshop;

import dev.langchain4j.chain.ConversationalChain;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;

public class ChatPrompts {
    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(7)
            .maxRetries(3)
            .build();

        InMemoryChatMemoryStore chatMemoryStore = new InMemoryChatMemoryStore();

        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
            .chatMemoryStore(chatMemoryStore)
            .maxMessages(200)
            .build();

        chatMemory.add(SystemMessage.from("""
            You're an expert chess player with a high ELO ranking.
            Use the PGN chess notation to reply with the best next possible move.
            """
        ));


        ConversationalChain chain = ConversationalChain.builder()
            .chatLanguageModel(model)
            .chatMemory(chatMemory)
            .build();

        String pgn = "";
        String[] whiteMoves = { "Nf3", "c4", "Nc3", "e3", "Dc2", "Cd5"};
        for (int i = 0; i < whiteMoves.length; i++) {
            pgn += " " + (i+1) + ". " + whiteMoves[i];
            System.out.println("Playing " + whiteMoves[i]);
            pgn = chain.execute(pgn);
            System.out.println(pgn);
        }
    }
}

Şimdi adım adım inceleyelim:

  • Sohbetin belleğini işlemek için bazı yeni içe aktarmalar gerekir.
  • Satranç üzerine uzun bir makale değil, yalnızca bir sonraki hamleyi oluşturmak istediğimiz için sohbet modelini en fazla 7 jetonla başlatırsınız.
  • Ardından, sohbet görüşmelerini kaydetmek için bir sohbet hafızası deposu oluşturursunuz.
  • Son hamleleri korumak için gerçek bir pencereli sohbet hafızası oluşturursunuz.
  • Sohbet belleğine, sohbet modeline kim olması gerektiği (ör. uzman bir satranç oyuncusu) konusunda talimat veren bir "sistem" mesajı eklersiniz. "Sistem" mesajı bağlam bilgisi eklerken "kullanıcı" ve "yapay zeka" mesajları asıl tartışmayı oluşturur.
  • Belleği ve sohbet modelini birleştiren bir etkileşim zinciri oluşturursunuz.
  • Ardından, beyazın hamlelerinin listesi üzerinde yineleme yaparsınız. Zincir, her seferinde bir sonraki beyaz hamleyle yürütülür ve sohbet modeli, bir sonraki en iyi hamleyle yanıt verir.

Bu sınıfı bu hamlelerle çalıştırdığınızda aşağıdaki çıkışı görmeniz gerekir:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :app:run
Playing Nf3
1... e5
Playing c4
2... Nc6
Playing Nc3
3... Nf6
Playing e3
4... Bb4
Playing Dc2
5... O-O
Playing Cd5
6... exd5 

Vay canına! PaLM satranç oynamayı biliyor mu? Tam olarak değil ancak eğitim sırasında model, bazı satranç oyunu yorumlarını veya hatta geçmiş oyunların PGN (Portable Game Notation) dosyalarını görmüş olmalıdır. Ancak bu chatbot, AlphaZero'ya (en iyi Go, Shogi ve satranç oyuncularını yenen yapay zeka) karşı kazanamayabilir ve sohbet, model oyunun gerçek durumunu tam olarak hatırlamadığı için daha sonra rayından çıkabilir.

Sohbet modelleri çok güçlüdür. Kullanıcılarınızla zengin etkileşimler oluşturabilir ve çeşitli bağlamsal görevleri yerine getirebilir. Bir sonraki bölümde, metinden yapılandırılmış veri ayıklama gibi faydalı bir göreve göz atacağız.

6. Yapılandırılmamış metinlerden bilgi ayıklama

Önceki bölümde, bir kullanıcı ile sohbet dil modeli arasında görüşmeler oluşturmuştunuz. Ancak LangChain4J ile yapılandırılmamış metinlerden yapılandırılmış bilgileri ayıklamak için bir sohbet modeli de kullanabilirsiniz.

Bir kişinin biyografisi veya açıklaması verildiğinde bu kişinin adını ve yaşını çıkarmak istediğinizi varsayalım. Büyük dil modeline, akıllıca düzenlenmiş bir istemle JSON veri yapıları oluşturmasını söyleyebilirsiniz (bu işleme genellikle "istem mühendisliği" denir).

ChatPrompts sınıfını aşağıdaki gibi güncelleyeceksiniz:

package palm.workshop;

import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.UserMessage;

public class ChatPrompts {

    static class Person {
        String name;
        int age;
    }

    interface PersonExtractor {
        @UserMessage("""
            Extract the name and age of the person described below.
            Return a JSON document with a "name" and an "age" property, \
            following this structure: {"name": "John Doe", "age": 34}
            Return only JSON, without any markdown markup surrounding it.
            Here is the document describing the person:
            ---
            {{it}}
            ---
            JSON: 
            """)
        Person extractPerson(String text);
    }

    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(300)
            .build();
        
        PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);

        Person person = extractor.extractPerson("""
            Anna is a 23 year old artist based in Brooklyn, New York. She was born and 
            raised in the suburbs of Chicago, where she developed a love for art at a 
            young age. She attended the School of the Art Institute of Chicago, where 
            she studied painting and drawing. After graduating, she moved to New York 
            City to pursue her art career. Anna's work is inspired by her personal 
            experiences and observations of the world around her. She often uses bright 
            colors and bold lines to create vibrant and energetic paintings. Her work 
            has been exhibited in galleries and museums in New York City and Chicago.    
            """
        );

        System.out.println(person.name);
        System.out.println(person.age);
    }
}

Bu dosyadaki çeşitli adımlara göz atalım:

  • Person sınıfı, bir kişiyi tanımlayan ayrıntıları (adı ve yaşı) temsil etmek için tanımlanır.
  • PersonExtractor arayüzü, yapılandırılmamış bir metin dizesi verildiğinde oluşturulmuş bir Person örneğini döndüren bir yöntemle oluşturulur.
  • extractPerson(), istemi kendisiyle ilişkilendiren bir @UserMessage ek açıklamasıyla açıklanmıştır. Bu istem, modelin bilgileri ayıklamak için kullanacağı istemdir. Ayrıntılar, sizin için ayrıştırılacak ve Person örneğine dönüştürülecek bir JSON belgesi biçiminde döndürülür.

Şimdi de main() yönteminin içeriğine bakalım:

  • Sohbet modeli oluşturulur.
  • LangChain4J'nin AiServices sınıfı sayesinde bir PersonExtractor nesnesi oluşturulur.
  • Ardından, yapılandırılmamış metinden kişinin ayrıntılarını çıkarmak için Person person = extractor.extractPerson(...)'ı arayabilir ve ad ile yaşı içeren bir Person örneği alabilirsiniz.

Şimdi bu sınıfı aşağıdaki komutla çalıştırın:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

> Task :app:run
Anna
23

Evet! Bu Anna, 23 yaşında.

Bu AiServices yaklaşımında özellikle dikkat çeken nokta, kesin olarak belirlenmiş türlere sahip nesnelerle çalışmanızdır. Doğrudan sohbet LLM'siyle etkileşim kurmuyorsunuz. Bunun yerine, çıkarılan kişisel bilgileri temsil etmek için Person sınıfı gibi somut sınıflarla çalışıyorsunuz ve extractPerson() bir Person örneği döndüren bir PersonExtractor sınıfınız var. LLM kavramı soyutlaştırılır ve bir Java geliştiricisi olarak yalnızca normal sınıfları ve nesneleri değiştirirsiniz.

7. Veriyle Artırılmış Üretim: Dokümanlarınızla sohbet etme

Görüşmelere geri dönelim. Bu kez dokümanlarınızla ilgili sorular sorabilirsiniz. Dokümanlarınızın alıntılarından oluşan bir veritabanından alakalı bilgileri alabilen bir chatbot oluşturacaksınız. Bu bilgiler, modelin yanıtlarını "temellendirmek" için kullanılacak. Model, eğitiminden gelen yanıtlar oluşturmaya çalışmayacak. Bu kalıba RAG veya Veriyle Artırılmış Üretim denir.

Çok Formatlı Veriyle Artırılmış Üretim'de kısaca iki aşama vardır:

  1. Alım aşaması: Belgeler yüklenir, daha küçük parçalara bölünür ve bunların vektörel temsili ("vektör yerleştirme") semantik aramalar yapabilen bir "vektör veritabanında" saklanır.

6c5bb5cb2e3b8088.png

  1. Sorgu aşaması: Kullanıcılar artık chatbot'unuza dokümanlarla ilgili sorular sorabilir. Soru da vektöre dönüştürülür ve veritabanındaki diğer tüm vektörlerle karşılaştırılır. En benzer vektörler genellikle anlamsal olarak ilişkilidir ve vektör veritabanı tarafından döndürülür. Ardından, LLM'ye konuşmanın bağlamı, veritabanı tarafından döndürülen vektörlere karşılık gelen metin parçaları verilir ve bu parçalara bakarak yanıtını temellendirmesi istenir.

2c279c506d7606cd.png

Belgelerinizi hazırlama

Bu yeni demoda, Google'ın öncülüğünü yaptığı ve günümüzde tüm modern büyük dil modellerinin uygulandığı "Transformer" nöral ağ mimarisi hakkında sorular soracaksınız.

Bu mimariyi açıklayan araştırma makalesini ("Attention is all you need"), internetten PDF'yi indirmek için wget komutunu kullanarak alabilirsiniz:

wget -O attention-is-all-you-need.pdf \
    https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf

Sohbete dayalı alma zinciri uygulama

Öncelikle belge alımı, ardından kullanıcıların belgeyle ilgili sorular sorduğu sorgu zamanı olmak üzere 2 aşamalı yaklaşımı nasıl oluşturacağımızı adım adım inceleyelim.

Doküman alımı

Belge alımı aşamasının ilk adımı, indirdiğimiz PDF dosyasını bulmak ve okumak için bir PdfParser hazırlamaktır:

PdfDocumentParser pdfParser = new PdfDocumentParser();
Document document = pdfParser.parse(
    new FileInputStream(new File("/home/YOUR_USER_NAME/palm-workshop/attention-is-all-you-need.pdf")));

Normal sohbet dili modelini oluşturmak yerine, önce bir "gömme" modeli örneği oluşturacaksınız. Bu, metin parçalarının (kelimeler, cümleler veya paragraflar) vektör gösterimlerini oluşturmakla görevli belirli bir model ve uç noktadır.

VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
    .endpoint("us-central1-aiplatform.googleapis.com:443")
    .project("YOUR_PROJECT_ID")
    .location("us-central1")
    .publisher("google")
    .modelName("textembedding-gecko@001")
    .maxRetries(3)
    .build();

Ardından, birlikte çalışmak için birkaç sınıfa ihtiyacınız olacak:

  • PDF belgesini yükleyip parçalara ayırın.
  • Bu parçaların tümü için vektör yerleştirmeleri oluşturun.
InMemoryEmbeddingStore<TextSegment> embeddingStore = 
    new InMemoryEmbeddingStore<>();

EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
    .documentSplitter(DocumentSplitters.recursive(500, 100))
    .embeddingModel(embeddingModel)
    .embeddingStore(embeddingStore)
    .build();
storeIngestor.ingest(document);

EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

Vektör yerleştirmelerini depolamak için bellek içi vektör veritabanı olan InMemoryEmbeddingStore örneği oluşturulur.

Belge, DocumentSplitters sınıfı sayesinde parçalara ayrılır. PDF dosyasının metnini 500 karakterlik snippet'lere böler. Kelimelerin veya cümlelerin kesilmesini önlemek için 100 karakterlik bir çakışma (sonraki parçayla) olur.

Mağaza "ingestor"u, belge ayırıcıyı, vektörleri hesaplamak için kullanılan gömme modelini ve bellek içi vektör veritabanını birbirine bağlar. Ardından, ingest() yöntemi beslemeyi gerçekleştirir.

İlk aşama tamamlandı. Belge, ilişkili vektör yerleştirmeleriyle birlikte metin parçalarına dönüştürüldü ve vektör veritabanında saklandı.

Soru sorma

Soru sormaya hazırlanma zamanı! Görüşmeyi başlatmak için normal sohbet modeli oluşturulabilir:

VertexAiChatModel model = VertexAiChatModel.builder()
    .endpoint("us-central1-aiplatform.googleapis.com:443")
    .project("YOUR_PROJECT_ID")
    .location("us-central1")
    .publisher("google")
    .modelName("chat-bison@001")
    .maxOutputTokens(1000)
    .build();

Ayrıca, vektör veritabanını (embeddingStore değişkeninde) ve yerleştirme modelini bağlayacak bir "alıcı" sınıfına da ihtiyacınız olacaktır. Bu işlevin görevi, kullanıcının sorgusu için bir vektör yerleştirme işlemi yaparak vektör veritabanını sorgulamak ve veritabanında benzer vektörler bulmaktır:

EmbeddingStoreRetriever retriever = 
    EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

Bu noktada ConversationalRetrievalChain sınıfını başlatabilirsiniz (bu, yalnızca Retrieval Augmented Generation kalıbının farklı bir adıdır):

ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
    .chatLanguageModel(model)
    .retriever(retriever)
    .promptTemplate(PromptTemplate.from("""
        Answer to the following query the best as you can: {{question}}
        Base your answer on the information provided below:
        {{information}}
        """
    ))
    .build();

Bu "zincir" şunları birbirine bağlar:

  • Daha önce yapılandırdığınız sohbet dili modeli.
  • Alıcı, vektör yerleştirme sorgusunu veritabanındaki vektörlerle karşılaştırır.
  • Bir istem şablonu, sohbet modelinin yanıtını sağlanan bilgilere (ör. kullanıcının sorusunun vektörüne benzer vektör yerleştirme özelliğine sahip belgelerin alakalı alıntıları) dayandırarak vermesi gerektiğini açıkça belirtir.

Artık sorularınızı sormaya hazırsınız.

String result = rag.execute("What neural network architecture can be used for language models?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What are the different components of a transformer neural network?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What is attention in large language models?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What is the name of the process that transforms text into vectors?");
System.out.println(result);

Programı şu şekilde çalıştırın:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

Çıkışta sorularınızın yanıtlarını görürsünüz:

The Transformer is a neural network architecture that can be used for 
language models. It is based solely on attention mechanisms, dispensing 
with recurrence and convolutions. The Transformer has been shown to 
outperform recurrent neural networks and convolutional neural networks on 
a variety of language modeling tasks.
------------
The Transformer is a neural network architecture that can be used for 
language models. It is based solely on attention mechanisms, dispensing 
with recurrence and convolutions. The Transformer has been shown to 
outperform recurrent neural networks and convolutional neural networks on a 
variety of language modeling tasks. The Transformer consists of an encoder 
and a decoder. The encoder is responsible for encoding the input sequence 
into a fixed-length vector representation. The decoder is responsible for 
decoding the output sequence from the input sequence. The decoder uses the 
attention mechanism to attend to different parts of the input sequence when 
generating the output sequence.
------------
Attention is a mechanism that allows a neural network to focus on specific 
parts of an input sequence. In the context of large language models, 
attention is used to allow the model to focus on specific words or phrases 
in a sentence when generating output. This allows the model to generate 
more relevant and informative output.
------------
The process of transforming text into vectors is called word embedding. 
Word embedding is a technique that represents words as vectors in a 
high-dimensional space. The vectors are typically learned from a large 
corpus of text, and they capture the semantic and syntactic relationships 
between words. Word embedding has been shown to be effective for a variety 
of natural language processing tasks, such as machine translation, question 
answering, and sentiment analysis.

Tam çözüm

Kopyalama ve yapıştırma işlemlerini kolaylaştırmak için ChatPrompts sınıfının tam içeriğini aşağıda bulabilirsiniz:

package palm.workshop;

import dev.langchain4j.chain.ConversationalRetrievalChain;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.parser.PdfDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment; 
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.model.vertexai.VertexAiEmbeddingModel;
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ChatPrompts {
    public static void main(String[] args) throws IOException {
        PdfDocumentParser pdfParser = new PdfDocumentParser();
        Document document = pdfParser.parse(new FileInputStream(new File("/ABSOLUTE_PATH/attention-is-all-you-need.pdf")));

        VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("textembedding-gecko@001")
            .maxRetries(3)
            .build();

        InMemoryEmbeddingStore<TextSegment> embeddingStore = 
            new InMemoryEmbeddingStore<>();

        EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
            .documentSplitter(DocumentSplitters.recursive(500, 100))
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build();
        storeIngestor.ingest(document);

        EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("genai-java-demos")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(1000)
            .build();

        ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
            .chatLanguageModel(model)
            .retriever(retriever)
            .promptTemplate(PromptTemplate.from("""
                Answer to the following query the best as you can: {{question}}
                Base your answer on the information provided below:
                {{information}}
                """
            ))
            .build();

        String result = rag.execute("What neural network architecture can be used for language models?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What are the different components of a transformer neural network?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What is attention in large language models?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What is the name of the process that transforms text into vectors?");
        System.out.println(result);
    }
}

8. Tebrikler

Tebrikler! LangChain4J ve PaLM API'yi kullanarak Java'da ilk üretken yapay zeka sohbet uygulamanızı başarıyla oluşturdunuz. Bu süreçte, büyük dil modeli sohbet modellerinin oldukça güçlü olduğunu ve kendi dokümanlarınızda soru/cevap, veri ayıklama gibi çeşitli görevleri yerine getirebildiğini, hatta bir ölçüde satranç bile oynayabildiğini keşfettiniz.

Yapabilecekleriniz

Java'da PaLM ile daha fazlasını yapmak için aşağıdaki codelab'lere göz atın:

Daha fazla bilgi

Referans belgeleri