Trò chuyện dựa trên AI tạo sinh với người dùng và tài liệu trong Java thông qua PaLM và LangChain4J

1. Giới thiệu

Lần cập nhật gần đây nhất: 5/2/2024

AI tạo sinh là gì

AI tạo sinh hay trí tuệ nhân tạo tạo sinh là việc sử dụng AI để tạo ra nội dung mới, chẳng hạn như văn bản, hình ảnh, nhạc, âm thanh và video.

AI tạo sinh hoạt động dựa trên các mô hình nền tảng (các mô hình AI lớn), có khả năng làm nhiều việc cùng lúc và thực hiện ngay những việc có thể làm, chẳng hạn như tóm tắt, hỏi và đáp, phân loại, v.v. Ngoài ra, yêu cầu đào tạo rất ít, các mô hình nền tảng có thể được điều chỉnh cho phù hợp với các trường hợp sử dụng được nhắm mục tiêu mà có rất ít dữ liệu mẫu.

AI tạo sinh hoạt động như thế nào?

AI tạo sinh hoạt động bằng cách sử dụng mô hình ML (Máy học) để tìm hiểu các mẫu hình và mối quan hệ trong một tập dữ liệu gồm nội dung do con người tạo ra. Sau đó, công cụ này sử dụng các mẫu đã học để tạo nội dung mới.

Cách phổ biến nhất để huấn luyện một mô hình AI tạo sinh là sử dụng phương pháp học có giám sát. Mô hình này được cung cấp một tập hợp nội dung do con người tạo và các nhãn tương ứng. Sau đó, công nghệ này sẽ học cách tạo ra nội dung tương tự như nội dung do con người tạo và được gắn nhãn có cùng nhãn.

Các ứng dụng AI tạo sinh phổ biến là gì?

AI tạo sinh xử lý nội dung khổng lồ, tạo thông tin chi tiết và câu trả lời bằng văn bản, hình ảnh và các định dạng thân thiện với người dùng. AI tạo sinh có thể được dùng để:

  • Cải thiện mức độ tương tác với khách hàng thông qua trải nghiệm tìm kiếm và trò chuyện nâng cao
  • Khám phá lượng lớn dữ liệu phi cấu trúc thông qua giao diện trò chuyện và nội dung tóm tắt
  • Hỗ trợ những công việc lặp đi lặp lại như phản hồi yêu cầu đề xuất (RFP), bản địa hoá nội dung tiếp thị bằng 5 ngôn ngữ, kiểm tra hợp đồng với khách hàng để đảm bảo tuân thủ, v.v.

Google Cloud cung cấp sản phẩm/dịch vụ AI tạo sinh nào?

Nhờ Vertex AI, bạn có thể tương tác, tuỳ chỉnh và nhúng các mô hình nền tảng vào ứng dụng của mình – mà không cần hoặc không cần kiến thức chuyên môn về công nghệ học máy. Sử dụng các mô hình nền tảng trong Model Garden, điều chỉnh các mô hình thông qua giao diện người dùng đơn giản trên AI Studio tạo sinh hoặc sử dụng các mô hình trong sổ tay khoa học dữ liệu.

Công cụ tìm kiếm và trò chuyện bằng AI tạo sinh mang đến cho nhà phát triển cách nhanh nhất để xây dựng công cụ tìm kiếm và bot trò chuyện dựa trên AI tạo sinh.

Ngoài ra, Duet AI là một cộng sự dựa trên AI, hiện có trên Google Cloud và các môi trường phát triển tích hợp (IDE) để giúp bạn làm được nhiều việc hơn và nhanh hơn.

Lớp học lập trình này tập trung vào chủ đề nào?

Lớp học lập trình này tập trung vào Mô hình ngôn ngữ lớn (LLM) PaLM 2, được lưu trữ trên Vertex AI của Google Cloud, trong đó bao gồm tất cả sản phẩm và dịch vụ học máy.

Bạn sẽ sử dụng Java để tương tác với PaLM API, kết hợp với trình điều phối khung mô hình ngôn ngữ lớn (LLM) LangChain4J. Bạn sẽ tìm hiểu các ví dụ cụ thể để tận dụng LLM (mô hình ngôn ngữ lớn) nhằm trả lời câu hỏi, tạo ý tưởng, trích xuất thực thể và nội dung có cấu trúc cũng như tóm tắt.

Hãy cho tôi biết thêm về khung LangChain4J!

Khung LangChain4J là một thư viện nguồn mở để tích hợp các mô hình ngôn ngữ lớn trong các ứng dụng Java, bằng cách sắp xếp nhiều thành phần, chẳng hạn như chính LLM và các công cụ khác như cơ sở dữ liệu vectơ (để tìm kiếm ngữ nghĩa), trình tải và bộ chia tài liệu (để phân tích và học hỏi từ các tài liệu đó), trình phân tích cú pháp đầu ra, v.v.

c6d7f7c3fd0d2951.png

Kiến thức bạn sẽ học được

  • Cách thiết lập dự án Java để sử dụng PaLM và LangChain4J
  • Cách trích xuất thông tin hữu ích từ nội dung phi cấu trúc (trích xuất thực thể hoặc từ khoá, kết quả ở định dạng JSON)
  • Cách tạo cuộc trò chuyện với người dùng của bạn
  • Cách sử dụng mô hình trò chuyện để đặt câu hỏi bằng tài liệu của bạn

Bạn cần có

  • Kiến thức về ngôn ngữ lập trình Java
  • Một dự án trên Google Cloud
  • Một trình duyệt, chẳng hạn như Chrome hoặc Firefox

2. Thiết lập và yêu cầu

Thiết lập môi trường theo tiến độ riêng

  1. Đăng nhập vào Google Cloud Console rồi tạo dự án mới hoặc sử dụng lại dự án hiện có. Nếu chưa có tài khoản Gmail hoặc Google Workspace, bạn phải tạo một tài khoản.

295004821bab6a87.pngS

37d264871000675d.png.

96d86d3d5655cdbe.png.

  • Tên dự án là tên hiển thị của những người tham gia dự án này. Đây là một chuỗi ký tự không được API của Google sử dụng. Bạn luôn có thể cập nhật ứng dụng.
  • Mã dự án là duy nhất trong tất cả các dự án Google Cloud và không thể thay đổi (không thể thay đổi sau khi đã đặt). Cloud Console sẽ tự động tạo một chuỗi duy nhất; thường bạn không quan tâm đến sản phẩm đó là gì. Trong hầu hết các lớp học lập trình, bạn sẽ cần tham khảo Mã dự án của mình (thường được xác định là PROJECT_ID). Nếu không thích mã đã tạo, bạn có thể tạo một mã nhận dạng ngẫu nhiên khác. Ngoài ra, bạn có thể thử cách riêng của mình để xem có thể sử dụng hay không. Bạn không thể thay đổi mã này sau bước này và mã vẫn giữ nguyên trong thời gian dự án.
  • Đối với thông tin của bạn, có giá trị thứ ba, Project Number (Số dự án), mà một số API sử dụng. Tìm hiểu thêm về cả ba giá trị này trong tài liệu này.
  1. Tiếp theo, bạn sẽ phải bật tính năng thanh toán trong Cloud Console để sử dụng API/tài nguyên trên đám mây. Việc chạy qua lớp học lập trình này sẽ không tốn nhiều chi phí. Để tắt các tài nguyên nhằm tránh phát sinh việc thanh toán ngoài hướng dẫn này, bạn có thể xoá các tài nguyên bạn đã tạo hoặc xoá dự án. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí 300 USD.

Khởi động Cloud Shell

Mặc dù bạn có thể vận hành Google Cloud từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, bạn sẽ sử dụng Cloud Shell, một môi trường dòng lệnh chạy trong Đám mây.

Kích hoạt Cloud Shell

  1. Trong Cloud Console, hãy nhấp vào Kích hoạt Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Nếu đây là lần đầu tiên khởi động Cloud Shell, bạn sẽ thấy một màn hình trung gian mô tả về Cloud Shell. Nếu bạn nhìn thấy màn hình trung gian, hãy nhấp vào Tiếp tục.

d95252b003979716.png

Quá trình cấp phép và kết nối với Cloud Shell chỉ mất vài phút.

7833d5e1c5d18f54.pngS

Máy ảo này được tải tất cả các công cụ phát triển cần thiết. Dịch vụ này cung cấp thư mục gốc có dung lượng ổn định 5 GB và chạy trên Google Cloud, giúp nâng cao đáng kể hiệu suất và khả năng xác thực của mạng. Nhiều (nếu không nói là) tất cả công việc của bạn trong lớp học lập trình này đều có thể thực hiện bằng trình duyệt.

Sau khi kết nối với Cloud Shell, bạn sẽ thấy mình đã được xác thực và dự án được đặt thành mã dự án.

  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng bạn đã được xác thực:
gcloud auth list

Kết quả lệnh

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng lệnh gcloud biết về dự án của bạn:
gcloud config list project

Kết quả lệnh

[core]
project = <PROJECT_ID>

Nếu chưa, bạn có thể thiết lập chế độ này bằng lệnh sau:

gcloud config set project <PROJECT_ID>

Kết quả lệnh

Updated property [core/project].

3. Chuẩn bị môi trường phát triển

Trong lớp học lập trình này, bạn sẽ sử dụng cửa sổ dòng lệnh và trình soạn thảo mã Cloud Shell để phát triển các chương trình Java.

Bật các API Vertex AI

  1. Trong bảng điều khiển Google Cloud, hãy đảm bảo tên dự án của bạn xuất hiện ở đầu bảng điều khiển Google Cloud. Nếu chưa, hãy nhấp vào Chọn dự án để mở Bộ chọn dự án và chọn dự án bạn muốn.
  2. Nếu bạn không có quyền truy cập vào phần Vertex AI trên bảng điều khiển của Google Cloud, hãy làm như sau:
  3. Trong lệnh Tìm kiếm, hãy nhập Vertex AI rồi quay lại
  4. Trong kết quả tìm kiếm, hãy nhấp vào Vertex AI. Bảng điều khiển Vertex AI sẽ xuất hiện.
  5. Nhấp vào Enable All Recommended API (Bật tất cả API được đề xuất) trong trang tổng quan của Vertex AI.

Thao tác này sẽ bật nhiều API, nhưng API quan trọng nhất đối với lớp học lập trình này là aiplatform.googleapis.com. Bạn cũng có thể bật API này trên dòng lệnh trong cửa sổ dòng lệnh của Cloud Shell bằng cách chạy lệnh sau:

$ gcloud services enable aiplatform.googleapis.com

Tạo cấu trúc dự án bằng Gradle

Để xây dựng các ví dụ về mã Java, bạn sẽ sử dụng công cụ xây dựng Gradle và phiên bản 17 của Java. Để thiết lập dự án với Gradle, trong thiết bị đầu cuối Cloud Shell, hãy tạo một thư mục (tại đây, palm-workshop), chạy lệnh gradle init trong thư mục đó:

$ 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

Bạn sẽ xây dựng một ứng dụng (lựa chọn 2), sử dụng ngôn ngữ Java (lựa chọn 3), không sử dụng dự án phụ (lựa chọn 1), sử dụng cú pháp Groovy cho tệp bản dựng (lựa chọn 1), không dùng các tính năng bản dựng mới (lựa chọn không), tạo chương trình kiểm thử bằng JUnit Jupiter (lựa chọn 4), và đối với tên dự án, bạn có thể sử dụng palm-workshop tương tự, bạn có thể sử dụng gói palmworkshop.

Cấu trúc dự án sẽ như sau:

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

Hãy cập nhật tệp app/build.gradle để thêm một số phần phụ thuộc cần thiết. Bạn có thể xoá phần phụ thuộc guava (nếu có) rồi thay thế bằng các phần phụ thuộc cho dự án LangChain4J và thư viện ghi nhật ký để tránh việc thiếu thông điệp của người ghi nhật ký:

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'
}

Có 2 phần phụ thuộc cho LangChain4J:

  • một cho dự án cốt lõi,
  • và một cho mô-đun Vertex AI chuyên dụng.

Để sử dụng Java 17 cho việc biên dịch và chạy các chương trình, hãy thêm khối sau bên dưới khối plugins {}:

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

Một thay đổi nữa cần thực hiện: cập nhật khối application của app/build.gradle để cho phép người dùng có thể ghi đè lớp chính chạy trên dòng lệnh khi gọi công cụ bản dựng:

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

Để kiểm tra xem tệp bản dựng đã sẵn sàng chạy ứng dụng hay chưa, bạn có thể chạy lớp chính mặc định để in thông báo Hello World! đơn giản:

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

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Bây giờ, bạn đã sẵn sàng lập trình với mô hình văn bản ngôn ngữ lớn PaLM bằng cách sử dụng dự án LangChain4J!

Để tham khảo, hiện tệp bản dựng app/build.gradle đầy đủ sẽ có dạng như sau:

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. Thực hiện cuộc gọi đầu tiên đến mô hình trò chuyện của PaLM

Hiện tại, dự án đã được thiết lập đúng cách, đã đến lúc gọi API PaLM.

Tạo một lớp mới có tên là ChatPrompts.java trong thư mục app/src/main/java/palm/workshop (cùng với lớp App.java mặc định) rồi nhập nội dung sau:

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);
    }
}

Trong ví dụ đầu tiên này, bạn cần nhập lớp VertexAiChatModel và LangChain4J ConversationalChain để dễ dàng xử lý khía cạnh đa biến của các cuộc trò chuyện.

Tiếp theo, trong phương thức main, bạn sẽ định cấu hình mô hình ngôn ngữ trò chuyện bằng cách sử dụng trình tạo cho VertexAiChatModel để chỉ định:

  • điểm cuối,
  • dự án,
  • khu vực,
  • nhà xuất bản,
  • và tên mô hình (chat-bison@001).

Mô hình ngôn ngữ hiện đã sẵn sàng, bạn có thể chuẩn bị một ConversationalChain. Đây là một bản tóm tắt cấp cao hơn mà LangChain4J cung cấp để định cấu hình kết hợp các thành phần khác nhau nhằm xử lý cuộc trò chuyện (chẳng hạn như chính mô hình ngôn ngữ trò chuyện), nhưng có thể là các thành phần khác để xử lý nhật ký trò chuyện hoặc cắm các công cụ khác như trình truy xuất để tìm nạp thông tin từ cơ sở dữ liệu vectơ. Nhưng đừng lo, chúng ta sẽ quay lại chủ đề đó sau trong lớp học lập trình này.

Sau đó, bạn sẽ thực hiện một cuộc trò chuyện nhiều lượt với mô hình trò chuyện để đặt một số câu hỏi liên quan đến nhau. Trước tiên, bạn thắc mắc về các LLM, sau đó bạn hỏi các bạn có thể làm gì với các LLM này và một số ví dụ về các LLM này. Lưu ý rằng bạn không cần phải tự lặp lại, LLM biết rằng "chúng" nghĩa là các LLM, trong bối cảnh của cuộc trò chuyện đó.

Để nhận cuộc trò chuyện đa lượt đó, bạn chỉ cần gọi phương thức execute() trên chuỗi. Phương thức này sẽ thêm vào ngữ cảnh của cuộc trò chuyện, mô hình trò chuyện sẽ tạo câu trả lời và cũng thêm vào nhật ký trò chuyện.

Để chạy lớp này, hãy chạy lệnh sau trong cửa sổ dòng lệnh của Cloud Shell:

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

Bạn sẽ thấy kết quả tương tự như kết quả sau:

$ ./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 đã trả lời 3 câu hỏi liên quan đến bạn!

Trình tạo VertexAIChatModel cho phép bạn xác định các tham số không bắt buộc đã có một số giá trị mặc định mà bạn có thể ghi đè. Dưới đây là một số ví dụ:

  • .temperature(0.2) – để xác định mức độ phù hợp của mẫu quảng cáo bạn muốn nhận được (0 là mẫu quảng cáo thấp và thường là thực tế hơn, trong khi 1 là dành cho nhiều mẫu quảng cáo hơn)
  • .maxOutputTokens(50) – trong ví dụ, 400 mã thông báo đã được yêu cầu (3 mã thông báo gần tương đương với 4 từ), tuỳ thuộc vào thời lượng bạn muốn câu trả lời được tạo
  • .topK(20) – để chọn ngẫu nhiên một từ trong số tối đa số từ có thể cần để hoàn thành văn bản (từ 1 đến 40)
  • .topP(0.95) – để chọn những từ có thể có tổng xác suất cộng lại bằng số thực đó (từ 0 đến 1)
  • .maxRetries(3) – trong trường hợp bạn chạy vượt quá hạn mức yêu cầu cho mỗi thời gian, bạn có thể yêu cầu mô hình thử gọi lại lệnh gọi 3 lần, ví dụ:

5. Một bot trò chuyện hữu ích với tính cách riêng!

Trong phần trước, bạn đã bắt đầu ngay lập tức đặt câu hỏi cho bot trò chuyện LLM mà không cần cung cấp bất kỳ ngữ cảnh cụ thể nào. Tuy nhiên, bạn có thể chuyên môn hoá một bot trò chuyện như vậy để trở thành chuyên gia về một nhiệm vụ cụ thể hoặc về một chủ đề cụ thể.

Bạn làm được như thế nào? Chuẩn bị sẵn sàng: bằng cách giải thích nhiệm vụ đang thực hiện, bối cảnh cho LLM, có thể là đưa ra một vài ví dụ về việc cần làm, cá tính mà mô hình này nên có, định dạng mà bạn muốn nhận được phản hồi và có thể là giọng điệu, nếu bạn muốn bot trò chuyện hành xử theo một cách nhất định.

Bài viết về cách tạo câu lệnh dưới đây minh hoạ phương pháp này một cách độc đáo:

8a4c67679dcbd085.pngS

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

Để minh hoạ điểm này, hãy lấy cảm hứng từ trang web prompts.chat. Trang web này liệt kê nhiều ý tưởng hay và thú vị về bot trò chuyện tuỳ chỉnh để các bot có thể hoạt động như:

Có một ví dụ giúp biến bot trò chuyện LLM thành người chơi cờ! Hãy cùng triển khai!

Cập nhật lớp ChatPrompts như sau:

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);
        }
    }
}

Hãy cùng phân tích từng bước:

  • Cần có một số lệnh nhập mới để xử lý bộ nhớ của cuộc trò chuyện.
  • Bạn tạo thực thể cho mô hình trò chuyện, nhưng với một số ít mã thông báo tối đa (ở đây là 7), vì chúng ta chỉ muốn tạo nước đi tiếp theo, chứ không phải toàn bộ một luận văn về cờ vua!
  • Tiếp theo, bạn sẽ tạo một kho lưu trữ kỷ niệm trò chuyện để lưu các cuộc trò chuyện.
  • Bạn tạo một bộ nhớ trò chuyện thực tế theo khung cửa sổ để lưu giữ các lượt di chuyển cuối cùng.
  • Trong kỷ niệm trò chuyện, bạn thêm một "hệ thống" nội dung hướng dẫn mô hình trò chuyện về người mà hệ thống cần xác định (ví dụ: một người chơi cờ vua chuyên nghiệp). "Hệ thống" thông báo thêm một số ngữ cảnh, trong khi "người dùng" và "AI" tin nhắn chính là nội dung thảo luận thực tế.
  • Bạn tạo một chuỗi trò chuyện kết hợp bộ nhớ và mô hình trò chuyện.
  • Sau đó, chúng tôi có một danh sách nước đi cho cờ trắng mà bạn sẽ lặp lại. Mỗi lần, chuỗi này sẽ được thực thi với nước đi màu trắng tiếp theo và mô hình trò chuyện sẽ phản hồi bằng nước đi phù hợp nhất tiếp theo.

Khi chạy lớp này bằng các bước di chuyển này, bạn sẽ thấy kết quả sau:

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

Ồ! PaLM biết cách chơi cờ? Chưa chính xác, nhưng trong quá trình huấn luyện, mô hình này chắc hẳn đã xem một số video bình luận về trò chơi cờ vua hoặc thậm chí là tệp PGN (Ký hiệu trò chơi di động) của các trò chơi trước đây. Tuy nhiên, bot trò chuyện này nhiều khả năng sẽ không chiến thắng trước AlphaZero (trí tuệ nhân tạo đánh bại những người chơi cờ vây, cờ Shogi và cờ vua giỏi nhất) và cuộc trò chuyện có thể bị lệch đường vì mô hình này không thực sự ghi nhớ trạng thái thực tế của trò chơi.

Các mô hình Chat rất hiệu quả, có thể tạo ra nhiều hoạt động tương tác phong phú với người dùng, đồng thời xử lý nhiều thao tác theo bối cảnh. Trong phần tiếp theo, chúng ta sẽ tìm hiểu một công việc hữu ích: trích xuất dữ liệu có cấu trúc khỏi văn bản.

6. Trích xuất thông tin từ văn bản không có cấu trúc

Trong phần trước, bạn đã tạo cuộc trò chuyện giữa người dùng và một mô hình ngôn ngữ trò chuyện. Nhưng với LangChain4J, bạn cũng có thể sử dụng mô hình trò chuyện để trích xuất thông tin có cấu trúc từ văn bản không có cấu trúc.

Giả sử bạn muốn trích xuất tên và tuổi của một người dựa trên tiểu sử hoặc thông tin mô tả về người đó. Bạn có thể hướng dẫn mô hình ngôn ngữ lớn tạo cấu trúc dữ liệu JSON bằng một câu lệnh được tinh chỉnh thông minh (thường được gọi là "prompt kỹ thuật").

Bạn sẽ cập nhật lớp ChatPrompts như sau:

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);
    }
}

Hãy cùng tìm hiểu các bước trong tệp này:

  • Lớp Person được định nghĩa để biểu thị thông tin chi tiết mô tả một người (tên và tuổi của người đó).
  • Giao diện PersonExtractor được tạo bằng một phương thức mà trong đó, với một chuỗi văn bản không có cấu trúc, sẽ trả về một thực thể Person được tạo bản sao.
  • extractPerson() được chú thích bằng chú thích @UserMessage liên kết một lời nhắc với câu lệnh đó. Đó là lời nhắc mà mô hình sẽ sử dụng để trích xuất thông tin và trả về thông tin chi tiết dưới dạng tài liệu JSON. Tài liệu này sẽ được phân tích cú pháp cho bạn và được phân tích cú pháp thành một thực thể Person.

Bây giờ, hãy xem nội dung của phương thức main():

  • Mô hình trò chuyện đã được tạo thực thể.
  • Đối tượng PersonExtractor được tạo nhờ lớp AiServices của LangChain4J.
  • Sau đó, bạn chỉ cần gọi Person person = extractor.extractPerson(...) để trích xuất thông tin chi tiết về người đó từ văn bản không có cấu trúc và lấy lại một thực thể Person có tên và tuổi.

Bây giờ, hãy chạy lớp này bằng lệnh sau:

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

> Task :app:run
Anna
23

Có! Đây là Anna, cô ấy 23 tuổi!

Điều bạn đặc biệt quan tâm trong cách tiếp cận AiServices này là bạn hoạt động với các đối tượng được nhập mạnh. Bạn hiện không tương tác trực tiếp với mô hình ngôn ngữ lớn (LLM) trò chuyện. Thay vào đó, bạn đang làm việc với các lớp cụ thể, chẳng hạn như lớp Person để biểu thị thông tin cá nhân được trích xuất, đồng thời bạn có một lớp PersonExtractor với phương thức extractPerson() trả về một thực thể Person. Khái niệm LLM bị loại bỏ và là nhà phát triển Java, bạn chỉ thao tác với các lớp và đối tượng thông thường.

7. Truy xuất Thế hệ tăng cường: trò chuyện với tài liệu

Hãy quay lại các cuộc trò chuyện. Lần này, bạn sẽ có thể đặt câu hỏi về giấy tờ của mình. Bạn sẽ xây dựng một bot trò chuyện có khả năng truy xuất thông tin liên quan từ cơ sở dữ liệu gồm các bản trích xuất tài liệu của bạn và thông tin đó sẽ được mô hình này sử dụng để "dựa trên" câu trả lời, thay vì cố gắng tạo câu trả lời qua quá trình huấn luyện. Mẫu này được gọi là RAG hay Thế hệ tăng cường truy xuất.

Tóm lại, có hai giai đoạn trong quá trình Thế hệ tăng cường truy xuất:

  1. Giai đoạn truyền dẫn – Tài liệu được tải, chia thành các phần nhỏ hơn và một đại diện vectơ của tài liệu đó ("Nhúng vectơ") được lưu trữ trong "cơ sở dữ liệu vectơ" có khả năng thực hiện tìm kiếm theo ngữ nghĩa.

6c5bb5cb2e3b8088.pngS

  1. Giai đoạn truy vấn – Giờ đây, người dùng có thể đặt câu hỏi cho bot trò chuyện của bạn về tài liệu. Câu hỏi cũng sẽ được chuyển đổi thành một vectơ và được so sánh với tất cả các vectơ khác trong cơ sở dữ liệu. Các vectơ giống nhau nhất thường có liên quan về mặt ngữ nghĩa và được cơ sở dữ liệu vectơ trả về. Sau đó, LLM được cung cấp ngữ cảnh của cuộc trò chuyện, các đoạn trích văn bản tương ứng với các vectơ mà cơ sở dữ liệu trả về và được yêu cầu đặt nền móng cho câu trả lời bằng cách xem xét các đoạn mã đó.

2c279c506d7606cd.png.

Đang chuẩn bị giấy tờ

Trong bản minh hoạ mới này, bạn sẽ đặt câu hỏi về kiến trúc mạng nơron "Transformer", do Google tiên phong triển khai. Đây là cách triển khai tất cả các mô hình ngôn ngữ lớn hiện đại hiện nay.

Bạn có thể truy xuất bài viết nghiên cứu mô tả cấu trúc này ("Cần chú ý là tất cả những gì bạn cần"), bằng cách sử dụng lệnh wget để tải tệp PDF xuống từ Internet:

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

Triển khai chuỗi truy xuất trò chuyện

Chúng ta hãy cùng tìm hiểu từng phần cách xây dựng phương pháp tiếp cận 2 giai đoạn, đầu tiên với việc nhập tài liệu, sau đó là thời gian truy vấn khi người dùng đặt câu hỏi về tài liệu.

Nhập tài liệu

Bước đầu tiên của giai đoạn nhập tài liệu là xác định tệp PDF mà chúng ta tải xuống rồi chuẩn bị PdfParser để đọc tệp đó:

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

Thay vì tạo mô hình ngôn ngữ trò chuyện thông thường, trước đó, bạn sẽ tạo một phiên bản của mô hình "nhúng". Đây là một mô hình và điểm cuối cụ thể có vai trò tạo các đại diện vectơ của các đoạn văn bản (từ, câu hoặc thậm chí đoạn).

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();

Tiếp theo, bạn cần cộng tác với một số lớp để:

  • Tải và chia tài liệu PDF theo nhiều phần.
  • Tạo các mục nhúng vectơ cho tất cả các phần này.
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);

Một thực thể của InMemoryEmbeddingStore (cơ sở dữ liệu vectơ trong bộ nhớ) được tạo để lưu trữ các vectơ nhúng.

Tài liệu được chia thành nhiều phần nhờ lớp DocumentSplitters. Nó sẽ chia văn bản của tệp PDF thành các đoạn mã gồm 500 ký tự, với sự chồng chéo 100 ký tự (với đoạn sau, để tránh cắt từ hoặc câu, thành từng đoạn).

Cửa hàng "nhập" liên kết bộ chia tài liệu, mô hình nhúng để tính vectơ và cơ sở dữ liệu vectơ trong bộ nhớ. Sau đó, phương thức ingest() sẽ xử lý quá trình nhập.

Giờ đây, giai đoạn đầu tiên đã kết thúc, tài liệu đã được chuyển đổi thành các phần văn bản với các mục nhúng vectơ liên quan và được lưu trữ trong cơ sở dữ liệu vectơ.

Đặt câu hỏi

Đã đến lúc chuẩn bị đặt câu hỏi! Bạn có thể tạo mô hình trò chuyện thông thường để bắt đầu cuộc trò chuyện:

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();

Bạn cũng cần một lớp "truy xuất" liên kết cơ sở dữ liệu vectơ (trong biến embeddingStore) và mô hình nhúng. Nhiệm vụ của nó là truy vấn cơ sở dữ liệu vectơ bằng cách tính toán nhúng vectơ cho truy vấn của người dùng, để tìm các vectơ tương tự trong cơ sở dữ liệu:

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

Tại thời điểm này, bạn có thể tạo thực thể cho lớp ConversationalRetrievalChain (đây chỉ là một tên khác của mẫu Thế hệ tăng cường truy xuất):

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();

"Chuỗi" này liên kết với nhau:

  • Mô hình ngôn ngữ trò chuyện mà bạn đã thiết lập trước đó.
  • Trình truy xuất so sánh một truy vấn nhúng vectơ với các vectơ trong cơ sở dữ liệu.
  • Mẫu lời nhắc cho biết rõ rằng mô hình trò chuyện phải trả lời bằng cách đưa ra câu trả lời dựa trên thông tin được cung cấp (tức là các phần trích dẫn có liên quan của tài liệu có nhúng vectơ tương tự như vectơ câu hỏi của người dùng).

Và giờ đây, bạn đã sẵn sàng đặt câu hỏi!

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);

Chạy chương trình bằng:

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

Trong kết quả, bạn sẽ thấy câu trả lời cho các câu hỏi của mình:

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.

Giải pháp đầy đủ

Để tạo điều kiện cho việc sao chép và dán, sau đây là toàn bộ nội dung của lớp ChatPrompts:

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. Xin chúc mừng

Xin chúc mừng! Bạn đã tạo thành công ứng dụng trò chuyện dựa trên AI tạo sinh đầu tiên trong Java bằng LangChain4J và PaLM API! Bạn đã phát hiện ra rằng các mô hình trò chuyện bằng ngôn ngữ lớn khá mạnh mẽ và có thể xử lý nhiều loại nhiệm vụ như hỏi/trả lời, thậm chí cả trên tài liệu, trích xuất dữ liệu của riêng bạn và ở một mức độ nào đó, mô hình này thậm chí còn có thể chơi cờ!

Tiếp theo là gì?

Hãy tham khảo một số lớp học lập trình sau đây để tìm hiểu sâu hơn về PaLM trong Java:

Tài liệu đọc thêm

Tài liệu tham khảo