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

1. Giriş

Son güncelleme tarihi: 05.02.2024

Üretken yapay zeka nedir?

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

Üretken yapay zeka, çoklu görevler gerçekleştirebilen ve özetleme, soru-cevap, sınıflandırma gibi kullanıma hazır görevleri gerçekleştirebilen temel modellerden (büyük yapay zeka modelleri) desteklenir. Ayrıca temel modeller, minimum eğitim gereksinimiyle, çok az örnek veriyle hedeflenen kullanım alanları için uyarlanabilir.

Ü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 ML (Makine Öğrenimi) modeli kullanarak çalışır. Ardından öğrenilen kalıpları kullanarak yeni içerikler üretir.

Üretken yapay zeka modellerini eğitmenin en yaygın yöntemi, gözetimli öğrenmedir. Modele, insan tarafından oluşturulan bir dizi içerik ve ilgili etiketler verilir. Ardından, insan tarafından oluşturulan içeriğe benzer ve aynı etiketlerle etiketlenmiş içerikler üretmeyi öğrenir.

Yaygın olarak kullanılan üretken yapay zeka uygulamaları nelerdir?

Üretken yapay zeka çok büyük içerikleri işleyerek metinler, resimler ve kullanıcı dostu biçimler aracılığıyla analizler ve yanıtlar oluşturur. Üretken yapay zeka şu amaçlarla kullanılabilir:

  • Gelişmiş sohbet ve arama deneyimleriyle müşteri etkileşimlerini iyileştirin
  • Sohbet arayüzleri ve özetler sayesinde çok sayıda yapılandırılmamış veriyi keşfedin
  • Teklif taleplerini (RFP'leri) yanıtlama, pazarlama içeriğini beş dilde yerelleştirme, müşteri sözleşmelerini uygunluk açısından kontrol etme gibi tekrarlanan görevler konusunda destek sağlama ve daha pek çok işlem

Google Cloud hangi üretken yapay zeka tekliflerini sunuyor?

Vertex AI sayesinde temel modellerle etkileşime girin, bunları özelleştirin ve uygulamalarınızda kullanın (makine öğrenimine çok az hakim olun veya hiç gerektirmez). Model Bahçe'de temel modellere erişin, Üretken Yapay Zeka Studio'daki basit bir kullanıcı arayüzüyle modellerde ince ayar yapı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 geliştirmenin en hızlı yolunu sunar.

Duet AI ise Google Cloud ve IDE'lerde daha fazla işi daha kısa sürede yapmanıza yardımcı olan yapay zeka destekli ortak çalışmanızdır.

Bu codelab'in odaklandığı konu nedir?

Bu codelab'de, Google Cloud Vertex AI'da barındırılan ve tüm makine öğrenimi ürün ve hizmetlerini kapsayan PaLM 2 Büyük Dil Modeli (LLM) üzerinde odaklanılmaktadır.

LangChain4J LLM çerçevesi orkestratörü ile birlikte PaLM API ile etkileşim kurmak için Java'yı kullanacaksınız. Soru yanıtlama, fikir üretme, varlık ve yapılandırılmış içerik ayıklama ve özetleme konularında LLM'den yararlanmak için farklı somut örnekler üzerinden yapacaksınız.

LangChain4J çerçevesi hakkında daha fazla bilgi

LangChain4J çerçevesi, büyük dil modellerini Java uygulamalarınıza entegre ederek LLM'nin kendisi gibi çeşitli bileşenlerin yanı sıra vektör veritabanları (anlamsal aramalar için), belge yükleyiciler ve ayırıcılar (belgeleri analiz etmek ve onlardan öğrenmek için), çıkış ayrıştırıcılar ve daha fazlasını düzenleyerek diğer araçları da entegre eden açık kaynak bir kitaplıktır.

c6d7f7c3fd0d2951.png

Neler öğreneceksiniz?

  • PaLM ve LangChain4J'yi kullanmak için bir Java projesi oluşturma
  • Yapılandırılmamış içerikten yararlı bilgileri ayıklama (varlık veya anahtar kelime ayıklama, JSON biçiminde çıkış)
  • Kullanıcılarınızla görüşme oluşturma
  • Kendi belgelerinizle ilgili soru sormak için sohbet modelini kullanma

Gerekenler

  • Java programlama dili bilgisi
  • Bir Google Cloud projesi
  • Chrome veya Firefox gibi bir tarayıcı

2. Kurulum ve şartlar

Kendi hızınızda ortam kurulumu

  1. Google Cloud Console'da oturum açıp 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.png

37d264871000675d.png

96d86d3d5655cdbe.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. İstediğiniz zaman güncelleyebilirsiniz.
  • Proje Kimliği, tüm Google Cloud projelerinde benzersizdir ve değiştirilemez (belirlendikten sonra değiştirilemez). Cloud Console, otomatik olarak benzersiz bir dize oluşturur. bunun ne olduğunu umursamıyorsunuz. Çoğu codelab'de proje kimliğinizi (genellikle PROJECT_ID olarak tanımlanır) belirtmeniz gerekir. Oluşturulan kimliği beğenmezseniz rastgele bir kimlik daha oluşturabilirsiniz. Alternatif olarak, kendi ölçümünüzü deneyip mevcut olup olmadığına bakabilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince kalır.
  • Bilginiz olması açısından, bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Sonraki adımda, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. Bu eğitim dışında faturalandırmanın tekrarlanmasını önlemek amacıyla kaynakları kapatmak için oluşturduğunuz kaynakları silebilir veya projeyi silebilirsiniz. Yeni Google Cloud kullanıcıları 300 ABD doları değerindeki ücretsiz denemeden yararlanabilir.

Cloud Shell'i başlatma

Google Cloud, dizüstü bilgisayarınızdan uzaktan çalıştırılabilse de bu codelab'de Cloud'da ç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 d1264ca30785e435.png simgesini 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 bir ekran görüntülendiyse Devam'ı tıklayın.

d95252b003979716.png

Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.

7833d5e1c5d18f54.png

Gereken tüm geliştirme araçları bu sanal makinede yüklüdür. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı tarayıcıyla yapılabilir.

Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını göreceksiniz.

  1. Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki 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 projenizi bildiğini onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project

Komut çıkışı

[core]
project = <PROJECT_ID>

Doğru değilse aşağıdaki 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 konsolunda projenizin adının, Google Cloud konsolunuzun en üst kısmında gösterildiğinden emin olun. Açık değilse Proje Seç'i tıklayarak Proje Seçici'yi açı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'ya Vertex AI yazıp geri dönün
  4. Arama sonuçlarında Vertex AI Vertex AI kontrol paneli görünür'ü tıklayın.
  5. Vertex AI kontrol panelinde Enable All Recommended APIs'ı (Önerilen Tüm API'leri Etkinleştir) tıklayın.

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

$ gcloud services enable aiplatform.googleapis.com

Gradle ile proje yapısı oluşturma

Java kodu örneklerinizi oluşturmak için Gradle derleme aracını ve Java'nın 17 sürümünü kullanacaksınız. Gradle ile projenizi ayarlamak için Cloud Shell terminalinde bir dizin oluşturun (burada palm-workshop), o 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

Java dilini (ikinci seçenek) kullanarak, alt projeler olmadan (1. seçenek) uygulama (ikinci seçenek) ile bir uygulama (1. seçenek) kullanarak, yeni derleme özelliklerini kullanma (seçenek no.) ile testler oluşturacaksınız (4. seçenek) ve proje adı için de palm.palmpalworkshop gibi kaynak paketi kullanabilirsiniz.

Proje yapısı şöyle görünecektir:

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

app/build.gradle dosyasını güncelleyerek gerekli olan bazı bağımlılıkları ekleyelim. Varsa guava bağımlılığını kaldırabilir, yerine LangChain4J projesi ve günlük kaydı kitaplığına ilişkin bağımlılıklarla değiştirerek kayıp günlük kaydedici iletilerinin sorun yaşamasını önleyebilirsiniz:

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 projede yer alıyor
  • diğeri de özel Vertex AI modülü içindir.

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

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

Yapılacak bir değişiklik daha var: app/build.gradle ürününün application bloğunu güncelleyerek 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ılabilmesini sağlayın:

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 olması amacıyla, app/build.gradle derleme dosyasının tamamı şu anda aşağıdaki gibi görünecektir:

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 modeliyle ilk kez arama yapıyorsunuz

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

app/src/main/java/palm/workshop dizininde (varsayılan App.java sınıfının yanında) ChatPrompts.java adında yeni bir sınıf oluşturun ve şu 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, ileti dizilerinin çok dönüşlü yönünü yönetmeyi kolaylaştırmak için VertexAiChatModel sınıfını ve LangChain4J ConversationalChain öğesini içe aktarmanız gerekir.

Ardından main yönteminde, VertexAiChatModel için oluşturucuyu kullanarak sohbet dili modelini yapılandırarak şunları belirtin:

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

Dil modeli hazır olduğuna göre artık bir ConversationalChain hazırlayabilirsiniz. Bu, LangChain4J tarafından bir konuşmayı yürütmek için farklı bileşenleri (ör. sohbet dili modelinin kendisi gibi) bir arada yapılandırmak için sunulan üst düzey bir soyutlamadır. Bu soyutlama, sohbet dili modelinin kendisi gibi, sohbet görüşmesinin geçmişini işlemeye veya alıcılar gibi diğer araçları vektör veritabanlarından bilgi getirmek üzere devreye sokmak için kullanılabilir. Merak etmeyin, bu codelab'in ilerleyen bölümlerinde bu konuya tekrar değineceğiz.

Ardından, birbiriyle alakalı birkaç soru sormak için sohbet modeliyle çok dönüşlü bir sohbet gerçekleştireceksiniz. Öncelikle LLM'leri merak edersiniz, ardından bunlarla ne yapabileceğinizi ve bunların bazı örneklerini sorarsınız. Kendinizi tekrarlamak zorunda olmadığınıza dikkat edin. LLM, "bunları" bilir. LLM'ler anlamına gelir.

Çok noktalı bu görüşmeyi almak için zincirde execute() yöntemini aramanız yeterlidir. Söz konusu 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ılabileceğiniz bazı varsayılan değerlere sahip isteğe bağlı parametreler tanımlamanızı sağlar. Aşağıda bazı örnekler verilmiştir:

  • .temperature(0.2): Yanıtın nasıl reklam öğesi olmasını istediğinizi tanımlamak için (0 az reklam öğesi ve genellikle daha gerçekçi, 1 ise daha fazla reklam öğesi içindir)
  • .maxOutputTokens(50): Örnekte, oluşturulan yanıtın ne kadar süre olmasını istediğinize bağlı olarak 400 jeton istendi (3 jeton yaklaşık olarak 4 kelimeye eşdeğerdir)
  • .topK(20) — metin tamamlama için mümkün olan maksimum sayıda kelime arasından rastgele bir kelime seçmek için (1 ile 40 arasında)
  • .topP(0.95) — Toplam olasılığı bu kayan nokta sayısına denk gelen olası kelimeleri seçmek için (0 ile 1 arasında)
  • .maxRetries(3): İstek başına zaman kotasını aşıyorsanız modelin aramayı 3 kez yeniden denemesini sağlayabilirsiniz.

5. Kişiliği olan faydalı bir chatbot.

Önceki bölümde, özel bir bağlam vermeden LLM chatbot'a hemen soru sormaya başladınız. Ancak böyle bir chatbot'u özelleştirerek belirli bir görevde veya konuda uzmanlaşabilirsiniz.

Bunu nasıl yapabilirsiniz? Zemin oluşturarak: LLM'nin görevi açıklayarak bağlam, ne yapması gerektiğine, karakterin nasıl olması gerektiğine, hangi biçimde yanıt almak istediğinize ve chatbot'un belirli bir şekilde davranmasını istiyorsanız üslubuna dair birkaç örnek vererek.

İstem hazırlamayla ilgili bu makale, bu yaklaşımı şu grafikle güzel bir şekilde açıklamaktadır:

8a4c67679dcbd085.png

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

Bu noktayı açıklamak için, prompts.chat web sitelerinden ilham alarak özel olarak uyarlanmış chatbot'larla ilgili çok sayıda muhteşem ve eğlenceli fikri listeleyebiliriz. Bu site, aşağıdaki işlevleri yerine getirmelerine olanak tanır:

Bu videoda bir LLM chatbot'unu satranç oyuncusuna dönüştürmeyle ilgili bir örnek yer alıyor. Şimdi 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);
        }
    }
}

Bunu adım adım açıklayalım:

  • Sohbetin belleğini işlemek için bazı yeni içe aktarma işlemleri yapılması gerekir.
  • Sohbet modelini somutlaştırıyorsunuz, ancak az sayıda maksimum jetonla (burada 7) sadece bir sonraki hamleyi oluşturmak istiyoruz. Satrançla ilgili tam bir inceleme yazmayın.
  • Ardından, sohbet görüşmelerini kaydetmek için bir sohbet belleği deposu oluşturursunuz.
  • Son hamleleri saklamak için gerçek pencereli bir sohbet belleği oluşturursunuz.
  • Sohbet belleğine bir "sistem" mesajı gösterilir. "Sistem" mesaj biraz bağlam ekler. "Kullanıcı" ve "AI" asıl tartışma alanı budur.
  • Hafıza ile sohbet modelini birleştiren bir sohbet zinciri oluşturuyorsunuz.
  • Sonra beyaz için sizin yinelediğiniz hamlelerin bir listesi var. 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 hareketlerle çalıştırdığınızda aşağıdaki çıkışı görürsünüz:

$ ./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 

Tüh! PaLM satranç oynamayı biliyor mu? Tam olarak değil ama eğitimi sırasında modelin bazı satranç oyunu anlatımları ve hatta eski oyunların PGN (Taşınabilir Oyun Notasyonu) dosyalarını görmüş olması gerekir. Ancak bu chatbot muhtemelen AlphaZero'ya (en iyi Go, Shogi ve Chess oyuncularını yenen yapay zeka) karşı kazanamayacak. Ayrıca model, oyunun gerçek durumunu tam olarak hatırlayameyeceğinden sohbet, daha ileri doğru rayından çıkabilir.

Chat modelleri son derece güçlü olup kullanıcılarınızla zengin etkileşimler kurabilir ve çeşitli bağlamsal görevleri yerine getirebilir. Bir sonraki bölümde, kullanışlı bir göreve göz atacağız: metinden yapılandırılmış verileri çıkarma.

6. Yapılandırılmamış metindeki bilgileri çıkarma

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

Bir kişinin adını ve yaşını, biyografisi veya açıklamasına göre çıkarmak istediğinizi varsayalım. Büyük dil modeline zekice düzenlenmiş bir istemle JSON veri yapıları oluşturma talimatı verebilirsiniz (bu genellikle "istem mühendisliği" olarak adlandırılır).

ChatPrompts sınıfını aşağıdaki şekilde 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 bakalım:

  • Person sınıfı, bir kişiyi tanımlayan ayrıntıları (ad ve yaşı) temsil edecek şekilde tanımlanır.
  • PersonExtractor arayüzü, yapılandırılmamış metin dizesine göre örneklendirilmiş bir Person örneği döndüren bir yöntemle oluşturuldu.
  • extractPerson(), bir istemi kendisiyle ilişkilendiren @UserMessage ek açıklamasına sahiptir. Bu, modelin bilgileri ayıklamak ve ayrıntıları sizin için ayrıştırılacak ve Person örneğine aktarılmadan JSON belgesi biçiminde döndürmek için kullanacağı istemdir.

Şimdi main() yönteminin içeriğine göz atalım:

  • Sohbet modeli örneklendirilir.
  • LangChain4J'nin AiServices sınıfı sayesinde bir PersonExtractor nesnesi oluşturuldu.
  • Ardından, yapılandırılmamış metindeki kişinin ayrıntılarını ayıklamak için Person person = extractor.extractPerson(...) öğesini çağırmanız yeterlidir. Ardından, ad ve yaş bilgilerini içeren bir Person örneği geri alabilirsiniz.

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

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

> Task :app:run
Anna
23

Evet! Bu Ayşe, 23 yaşında.

Bu AiServices yaklaşımının özellikle ilgisini çeken şey, güçlü bir şekilde yazılmış nesnelerle çalışmanızdır. Sohbet LLM'si ile doğrudan etkileşimde bulunmuyorsunuz. Bunun yerine, ayıklanan kişisel bilgileri temsil eden Person sınıfı gibi somut sınıflarla çalışıyorsunuz ve Person örneği döndüren extractPerson() yöntemine sahip bir PersonExtractor sınıfınız var. LLM kavramı soyutlanmış ve bir Java geliştiricisi olarak yalnızca normal sınıfları ve nesneleri değiştiriyorsunuz.

7. Alma Artırılmış Nesil: dokümanlarınızla sohbet etme

Şimdi sohbetlere dönelim. Bu kez, dokümanlarınız hakkında soru sorabileceksiniz. Belgelerinizin ayıklamalarından oluşan bir veritabanından alakalı bilgileri alabilen bir chatbot oluşturacaksınız ve bu bilgiler model tarafından eğitimden gelen yanıtlar üretmeye çalışmak yerine yanıtları "tespit etmek" için kullanılır. Bu kalıp, RAG veya Alma Artırılmış Nesil olarak adlandırılır.

Özetle alma için artırılmış oluşturmada iki aşama vardır:

  1. Besleme aşaması: Belgeler yüklenir, daha küçük parçalara bölünür ve bunların vektörsel gösterimi ("vektör yerleştirme"), anlamsal aramalar yapabilen bir "vektör veritabanı"nda depolanır.

6c5bb5cb2e3b8088

  1. Sorgu aşaması: Kullanıcılar artık chatbot'unuza dokümanlarla ilgili sorular sorabilir. Soru da bir 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 anlam açısından alakalıdır 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 snippet'leri verilir ve bu snippet'lere bakarak yanıtını temel alması istenir.

2c279c506d7606cd.png

Belgelerinizi hazırlama

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

PDF'yi internetten indirmek için wget komutunu kullanarak bu mimariyi ("Yalnızca ihtiyacınız olan şey Dikkat") açıklayan araştırma makalesini alabilirsiniz:

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

Konuşmaya dayalı bilgi alma zinciri uygulama

2 aşamalı yaklaşımın nasıl oluşturulacağını, önce belge beslemesini ve ardından kullanıcıların dokümanla ilgili sorular sorduğu sorgu süresini adım adım inceleyelim.

Belge besleme

Belge besleme aşamasının ilk adımı, indirdiğimiz PDF dosyasını bulmak ve okuması 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, "embedding" modelinin bir örneğini oluşturacaksınız. Bu, rolü metin parçalarının (kelimeler, cümleler, hatta paragraflar) vektör temsillerini oluşturmak olan 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();

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

  • PDF dokümanını parçalar halinde yükleyin ve bölü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şturuldu.

Doküman, DocumentSplitters sınıfı sayesinde parçalara ayrıldı. PDF dosyasındaki metin, 100 karakterlik örtüşmeyle 500 karakterlik snippet'lere bölünür (kelimeleri veya cümleleri parçalar halinde kesmemek için sonraki parçayla birlikte).

Mağaza "besleyici" belge ayırıcıyı, vektörleri hesaplamak için yerleştirme modelini ve bellek içi vektör veritabanını bağlar. Ardından ingest() yöntemi, besleme işlemini gerçekleştirir.

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

Soru sorma

Soru sormaya hazırlanma vakti geldi. Sohbeti başlatmak için her zamanki 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 "retriever" sınıfına da ihtiyacınız olacaktır. Görevi, kullanıcı sorgusu için vektör yerleştirmeyi hesaplayarak vektör veritabanını sorgulamak ve veritabanındaki benzer vektörleri bulmaktır.

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

Bu noktada, ConversationalRetrievalChain sınıfını örneklendirebilirsiniz (bu, Alma Artırılmış Oluşturma kalıbının yalnızca 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" birbirlerine bağlanır:

  • Daha önce yapılandırdığınız sohbet dili modeli.
  • retriever, bir vektör yerleştirme sorgusunu veritabanındaki vektörlerle karşılaştırır.
  • İstem şablonunda, sohbet modelinin verdiği bilgilere (ör. vektör yerleştirmesi kullanıcının sorusu vektörüne benzer olan dokümanlardan ilgili alıntılar) dayanarak yanıt vermesi gerektiğini açıkça belirten bir ifade vardır.

Artık nihayet 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ı şununla çalıştırın:

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

Çıktıda sorularınızın cevabı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.

Eksiksiz çözüm

Kopyalama ve yapıştırma işlemini 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 derlediniz. Bu süreçte büyük dilli sohbet modellerinin oldukça güçlü olduğunu ve kendi belgeleriniz, veri ayıklama ve hatta bir ölçüde Satranç oynama becerisine göre soru/cevap gibi çeşitli görevleri yerine getirebildiğini keşfettiniz.

Sırada ne var?

Java'da PaLM ile ilgili daha fazla bilgi edinmek için aşağıdaki codelab'lere göz atın:

Daha fazla bilgi

Referans belgeler