دردشة مستندة إلى الذكاء الاصطناعي التوليدي مع المستخدمين والمستندات في Java باستخدام PaLM وLangChain4J

1. مقدمة

تاريخ آخر تعديل: 05/02/2024

ما هو الذكاء الاصطناعي التوليدي؟

يشير الذكاء الاصطناعي التوليدي أو الذكاء الاصطناعي التوليدي إلى استخدام الذكاء الاصطناعي في إنشاء محتوى جديد، مثل النصوص والصور والموسيقى والمحتوى الصوتي والفيديوهات.

يستند الذكاء الاصطناعي التوليدي إلى النماذج الأساسية (نماذج الذكاء الاصطناعي الكبيرة) التي يمكنها تنفيذ مهام متعددة وتنفيذ مهام غير تقليدية، بما في ذلك التلخيص والأسئلة والأجوبة والتصنيف وغير ذلك. بالإضافة إلى ذلك، يمكن تعديل نماذج الأساس لتناسب حالات الاستخدام المستهدَفة باستخدام الحدّ الأدنى من التدريب المطلوب، وذلك مع توفير أمثلة قليلة جدًا من البيانات.

ما هي آلية عمل الذكاء الاصطناعي التوليدي؟

يستخدم الذكاء الاصطناعي التوليدي نموذج تعلُّم الآلة للتعرّف على الأنماط والعلاقات في مجموعة بيانات تتضمّن محتوًى من إنشاء البشر. وتعتمد بعدها على الأنماط التي تعلّمتها لإنشاء محتوى جديد.

إنّ الطريقة الأكثر شيوعًا لتدريب نموذج الذكاء الاصطناعي التوليدي هي استخدام التعلّم الخاضع للإشراف، حيث يتم منح النموذج مجموعة من المحتوى من إنشاء البشر والتصنيفات المقابلة. ويتعلّم النظام بعد ذلك إنشاء محتوى مشابه للمحتوى الذي أنشأه المستخدمون ومصنَّف باستخدام التصنيفات نفسها.

ما هي التطبيقات الشائعة للذكاء الاصطناعي التوليدي؟

يعالج الذكاء الاصطناعي التوليدي المحتوى الهائل، وينشئ إحصاءات وإجابات عبر النصوص والصور والتنسيقات السهلة الاستخدام. يمكن استخدام الذكاء الاصطناعي التوليدي للأغراض التالية:

  • تحسين تفاعلات العملاء من خلال تجارب بحث ومحادثات محسَّنة
  • استكشِف كميات هائلة من البيانات غير المنظَّمة من خلال واجهات وملخصات للمحادثات.
  • المساعدة في المهام المتكررة مثل الرد على طلبات تقديم العروض (RFP)، وأقلمة المحتوى التسويقي بخمس لغات، والتحقق من عقود العملاء للتأكد من الامتثال والمزيد

ما هي حلول الذكاء الاصطناعي التوليدي المتوفّرة في Google Cloud؟

باستخدام Vertex AI، يمكنك التفاعل مع النماذج الأساسية وتخصيصها وتضمينها في تطبيقاتك، مع العلم أنّ ذلك لا يتطلّب سوى خبرة قليلة في تكنولوجيا تعلُّم الآلة. يمكنك الوصول إلى نماذج الأساس في Model Garden، أو ضبط النماذج من خلال واجهة مستخدم بسيطة في أداة الذكاء الاصطناعي التوليدي، أو استخدام النماذج في دفتر ملاحظات لعلوم البيانات.

توفّر منصة Vertex AI Search and Conversation أسرع طريقة للمطوّرين لإنشاء محركات بحث وبرامج تتبُّع دردشة مستنِدة إلى الذكاء الاصطناعي التوليدي.

يمكنك أيضًا الاستعانة بخدمة Duet AI المستنِدة إلى الذكاء الاصطناعي (AI) والمتوفّرة في Google Cloud وبيئات IDE لمساعدتك في إنجاز المزيد من المهام بشكل أسرع.

ما الذي يركز عليه هذا الدرس التطبيقي حول الترميز؟

يركّز هذا الدرس التطبيقي حول الترميز على النموذج اللغوي الكبير PaLM 2 (LLM) المستضاف على Google Cloud Vertex AI والذي يشمل جميع منتجات وخدمات تعلُّم الآلة.

ستستخدم Java للتفاعل مع واجهة برمجة التطبيقات PaLM، بالإضافة إلى منسّق إطار العمل المستند إلى النموذج اللغوي الكبير LangChain4J. ستتمكّن من الاطّلاع على أمثلة ملموسة مختلفة للاستفادة من النموذج اللغوي الكبير في الإجابة عن الأسئلة وإنشاء الأفكار واستخراج الكيانات والمحتوى المنظَّم والتلخيص.

أريد معلومات أكثر عن إطار عمل LangChain4J

إنّ إطار العمل LangChain4J هو مكتبة مفتوحة المصدر لدمج النماذج اللغوية الكبيرة في تطبيقات Java، وذلك من خلال تنسيق مكونات مختلفة، مثل النموذج اللغوي الكبير نفسه، وكذلك أدوات أخرى مثل قواعد البيانات المتجهة (لعمليات البحث الدلالية)، وأدوات تحميل المستندات وأدوات تقسيمها (لتحليل المستندات والتعلّم منها)، وأدوات تحليل الإخراج، وغير ذلك.

c6d7f7c3fd0d2951.png

المعلومات التي ستطّلع عليها

  • كيفية إعداد مشروع Java لاستخدام PaLM وLangChain4J
  • كيفية استخراج المعلومات المفيدة من المحتوى غير المنظَّم (استخراج الكيانات أو الكلمات الرئيسية بتنسيق JSON)
  • كيفية إنشاء محادثة مع المستخدمين
  • كيفية استخدام نموذج الدردشة لطرح أسئلة على مستنداتك الخاصة

المتطلبات

  • معرفة لغة البرمجة Java
  • مشروع على Google Cloud
  • متصفح، مثل Chrome أو Firefox

2. الإعداد والمتطلبات

إعداد بيئة ذاتية

  1. سجِّل الدخول إلى Google Cloud Console وأنشئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي سلسلة أحرف لا تستخدمها Google APIs. ويمكنك تعديلها في أي وقت.
  • يكون رقم تعريف المشروع فريدًا في جميع مشاريع Google Cloud وغير قابل للتغيير (لا يمكن تغييره بعد تحديده). تنشئ Cloud Console سلسلة فريدة تلقائيًا. فعادةً لا تهتم بما هو. في معظم الدروس التطبيقية حول الترميز، يجب الإشارة إلى رقم تعريف المشروع (الذي يتم تحديده عادةً على أنّه PROJECT_ID). وإذا لم يعجبك رقم التعريف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. ويمكنك بدلاً من ذلك تجربة طلبك الخاص ومعرفة ما إذا كان متاحًا. ولا يمكن تغييره بعد هذه الخطوة ويبقى طوال مدة المشروع.
  • لمعلوماتك، هناك قيمة ثالثة، وهي رقم المشروع، الذي تستخدمه بعض واجهات برمجة التطبيقات. اطّلِع على مزيد من المعلومات حول هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام الموارد/واجهات برمجة التطبيقات في Cloud. لن يؤدي إكمال هذا الدرس التطبيقي حول الترميز إلى فرض أي تكاليف، إن وُجدت. لإيقاف تشغيل الموارد لتجنب تحمُّل الفواتير إلى ما هو أبعد من هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

بدء Cloud Shell

يمكنك إدارة Google Cloud عن بُعد من الكمبيوتر المحمول، إلا أنّك ستستخدم في هذا الدرس التطبيقي Cloud Shell، وهي بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

تفعيل Cloud Shell

  1. من Cloud Console، انقر على تفعيل Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

إذا كانت هذه هي المرة الأولى التي تبدأ فيها Cloud Shell، ستظهر لك شاشة وسيطة تصف ماهيتها. إذا ظهرت لك شاشة وسيطة، انقر على متابعة.

d95252b003979716.png

من المفترَض أن تستغرق عملية إدارة الحسابات والاتصال بخدمة Cloud Shell بضع دقائق فقط.

7833d5e1c5d18f54.png

يتم تحميل هذا الجهاز الافتراضي مع جميع أدوات التطوير اللازمة. وتوفّر هذه الشبكة دليلاً رئيسيًا دائمًا بسعة 5 غيغابايت ويتم تشغيله في Google Cloud، ما يحسّن بشكل كبير من أداء الشبكة والمصادقة. يمكنك تنفيذ معظم عملك، إن لم يكن كلّه، في هذا الدرس التطبيقي حول الترميز باستخدام متصفّح.

بعد الربط بخدمة Cloud Shell، من المفترض أن تتأكّد من أنّه تمّت مصادقتك وأنّ المشروع مضبوط على رقم تعريف مشروعك.

  1. شغِّل الأمر التالي في Cloud Shell لتأكيد مصادقتك:
gcloud auth list

مخرجات الأمر

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. شغّل الأمر التالي في Cloud Shell للتأكد من معرفة الأمر gcloud بمشروعك:
gcloud config list project

مخرجات الأمر

[core]
project = <PROJECT_ID>

إذا لم يكن كذلك، يمكنك تعيينه من خلال هذا الأمر:

gcloud config set project <PROJECT_ID>

مخرجات الأمر

Updated property [core/project].

3- جارٍ إعداد بيئة التطوير

في هذا الدرس التطبيقي حول الترميز، ستستخدم الوحدة الطرفية في Cloud Shell وأداة تعديل الرموز لتطوير برامج Java.

تفعيل واجهات Vertex AI API

  1. في وحدة تحكُّم Google Cloud، تأكَّد من عرض اسم مشروعك في أعلى وحدة تحكُّم Google Cloud. وإذا لم يكن الأمر كذلك، انقر على اختيار مشروع لفتح أداة اختيار المشروع واختَر المشروع المطلوب.
  2. إذا لم تكن تستخدم قسم Vertex AI في وحدة تحكُّم Google Cloud، اتّبِع الخطوات التالية:
  3. في قسم البحث، أدخِل Vertex AI، ثم ارجِع
  4. في نتائج البحث، انقر على Vertex AI. ستظهر لوحة بيانات Vertex AI.
  5. انقر على تفعيل جميع واجهات برمجة التطبيقات المقترَحة في لوحة بيانات Vertex AI.

سيؤدّي ذلك إلى تفعيل العديد من واجهات برمجة التطبيقات، ولكن الأهم في الدرس التطبيقي حول الترميز هو aiplatform.googleapis.com، الذي يمكنك أيضًا تفعيله في سطر الأوامر في الوحدة الطرفية Cloud Shell من خلال تنفيذ الأمر التالي:

$ gcloud services enable aiplatform.googleapis.com

إنشاء بنية المشروع باستخدام Gradle

لإنشاء أمثلة على رموز Java، ستستخدم أداة التصميم Gradle والإصدار 17 من Java. لإعداد مشروعك باستخدام Gradle، أنشِئ دليلاً (هنا، palm-workshop) في الوحدة الطرفية في Cloud Shell، وشغِّل الأمر gradle init في هذا الدليل:

$ 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 (الخيار 3)، وبدون استخدام المشاريع الفرعية (الخيار 1)، باستخدام بنية Groovy لملف الإصدار (الخيار 1)، وعدم استخدام ميزات الإصدار الجديدة (الخيار "لا")، وإنشاء اختبارات باستخدام JUnit Jupiter (الخيار 4)، وبالنسبة إلى اسم المشروع، يمكنك استخدام palm-workshop كما لو كانت الميزة المصدر،

سيبدو هيكل المشروع على النحو التالي:

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

والآن، سنعدّل ملف app/build.gradle لإضافة بعض الموارد المطلوبة. يمكنك إزالة تبعية guava إذا كانت متوفّرة، واستبدالها بالعناصر التابعة لمشروع LangChain4J ومكتبة التسجيل لتجنُّب الإخلال برسائل المسجّل المفقودة:

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:

  • واحد في المشروع الأساسي،
  • وأخرى لوحدة Vertex AI

لاستخدام Java 17 لتجميع برامجنا وتشغيلها، أضِف المجموعة التالية أسفل مجموعة plugins {}:

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

هناك تغيير آخر يجب إجراؤه: تعديل مجموعة application من app/build.gradle للسماح للمستخدمين بإلغاء الفئة الرئيسية لتشغيلها في سطر الأوامر عند استدعاء أداة التصميم:

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

للتأكّد من أنّ ملف الإصدار جاهز لتشغيل تطبيقك، يمكنك تشغيل الفئة الرئيسية التلقائية التي تطبع رسالة Hello World! بسيطة:

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

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

أصبحت الآن جاهزًا للبرمجة باستخدام نموذج النص اللغوي الكبير PaLM باستخدام مشروع LangChain4J.

إليك الشكل الذي من المفترض أن يبدو عليه ملف إصدار app/build.gradle الكامل الآن كمرجع لك:

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

والآن بعد أن تم إعداد المشروع بشكل صحيح، حان الوقت لاستدعاء PaLM API.

أنشِئ فئة جديدة باسم ChatPrompts.java في الدليل app/src/main/java/palm/workshop (بالإضافة إلى فئة App.java التلقائية)، واكتب المحتوى التالي:

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

في هذا المثال الأول، ستحتاج إلى استيراد فئة VertexAiChatModel وLangChain4J ConversationalChain لتسهيل التعامل مع الجانب المتعدد الأدوار في المحادثات.

بعد ذلك، وفي طريقة main، ستتمكّن من ضبط نموذج اللغة في المحادثة، باستخدام أداة إنشاء VertexAiChatModel، لتحديد ما يلي:

  • نقطة النهاية،
  • المشروع،
  • المنطقة،
  • الناشر،
  • واسم النموذج (chat-bison@001).

بعد أن أصبح النموذج اللغوي جاهزًا، يمكنك إعداد ConversationalChain. يقدّم مشروع LangChain4J تجربة تجريدية ذات مستوى أعلى لتكوين مكونات مختلفة معًا للتعامل مع المحادثة، مثل نموذج لغة الدردشة نفسه، لكن ربما مكونات أخرى للتعامل مع سجلّ محادثات الدردشة، أو لتوصيل أدوات أخرى مثل أداة استرداد المعلومات لجلب المعلومات من قواعد بيانات المتجهات. لا داعي للقلق. سنعود إلى ذلك لاحقًا في هذا الدرس التطبيقي حول الترميز.

بعد ذلك، ستجري محادثة متعددة الأدوار مع نموذج الدردشة، لطرح العديد من الأسئلة المترابطة. يجب أولاً أن تتساءل عن النماذج اللغوية الكبيرة (LLM)، ثم تسأل عن الإجراءات التي يمكنك تنفيذها باستخدام هذه النماذج، ثم يتساءل عن بعض الأمثلة عليها. لا حاجة إلى تكرار ما تقوله، فالنموذج اللغوي الكبير يعرف "هم" ويُقصد بها النماذج اللغوية الكبيرة في سياق تلك المحادثة.

لنقل هذه المحادثة المتعددة الأدوار، ما عليك سوى استدعاء طريقة execute() في السلسلة، وستضيفها إلى سياق المحادثة، وسينشئ نموذج المحادثة ردًا ويضيفه إلى سجلّ المحادثات أيضًا.

لتشغيل هذه الفئة، شغِّل الأمر التالي في الوحدة الطرفية في Cloud Shell:

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

من المفترض أن تظهر لك نتيجة مشابهة لما يلي:

$ ./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 على الأسئلة الثلاثة ذات الصلة.

تتيح لك أداة إنشاء VertexAIChatModel تحديد المَعلمات الاختيارية التي تحتوي على بعض القيم التلقائية التي يمكنك تجاوزها. وإليك بعض الأمثلة:

  • .temperature(0.2): لتحديد مدى إبداع الردّ (0 مستوى إبداعي منخفض وغالبًا ما يكون أكثر واقعية، بينما 1 للمخرجات الإبداعية الإضافية)
  • .maxOutputTokens(50): في المثال، تم طلب 400 رمز مميّز (3 رموز مميّزة تساوي 4 كلمات تقريبًا)، بناءً على المدة التي تريد أن تكون الإجابة عنها
  • .topK(20): لاختيار كلمة بشكل عشوائي من بين أقصى عدد ممكن من الكلمات لإكمال النص (من 1 إلى 40)
  • .topP(0.95): لاختيار الكلمات المحتمَلة التي يصل إجمالي احتمالية إجرائها إلى رقم النقطة العائمة (بين 0 و1)
  • .maxRetries(3): في حال تجاوز الحصة الزمنية للطلب، يمكنك أن تطلب من النموذج إعادة محاولة الاتصال 3 مرات، على سبيل المثال

5- روبوت دردشة مفيد بشخصية!

في القسم السابق، بدأت على الفور بطرح أسئلة على روبوت الدردشة الخاص بالنموذج اللغوي الكبير بدون تقديم أي سياق محدد. ولكن يمكنك التخصص في روبوت الدردشة هذا لتصبح خبيرًا في مهمة معينة أو في موضوع معين.

كيف تفعل ذلك؟ من خلال توضيح المهمة: من خلال شرح مهمة النموذج اللغوي الكبير (LLM) والسياق، وتقديم بعض الأمثلة على المهام المطلوب تنفيذها، والشخصية التي يجب أن تكون، والتنسيق المطلوب تلقّي الردود، والنبرة المحتملة إذا أردت أن يتصرف روبوت الدردشة بطريقة معيّنة.

توضّح هذه المقالة حول صياغة الطلبات هذه الطريقة بشكل جيد من خلال هذا الرسم:

8a4c67679dcbd085.png

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

لتوضيح هذه النقطة، دعونا نحصل على بعض الإلهام من مواقع الويب prompts.chat، التي تسرد الكثير من الأفكار الرائعة والممتعة لبرامج الدردشة المبرمجة المخصصة للسماح لها بالتصرف كما يلي:

في ما يلي مثال على كيفية تحويل برنامج محادثة آلي من النوع LLM إلى لاعب شطرنج. دعنا ننفذ ذلك!

عدِّل فئة ChatPrompts على النحو التالي:

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

لنحلل هذه المسألة خطوة بخطوة:

  • هناك حاجة إلى بعض عمليات الاستيراد الجديدة لمعالجة ذاكرة المحادثة.
  • أنت تنشئ مثيلاً لنموذج الدردشة، ولكن باستخدام عدد قليل من الرموز المميّزة القصوى (هنا 7)، لأنّنا نريد فقط إنشاء الخطوة التالية، وليس أطروحة كاملة عن لعبة الشطرنج.
  • بعد ذلك، يمكنك إنشاء متجر ذاكرة Chat لحفظ محادثات المحادثة.
  • يمكنك إنشاء ذاكرة محادثة فعلية في النافذة للاحتفاظ بالحركات الأخيرة.
  • في ذاكرة الدردشة، يمكنك إضافة "نظام" التي ترشد نموذج المحادثة إلى الشخص الذي يجب أن يكون عليه (أي لاعب شطرنج خبير). "النظام" الرسالة تضيف بعض السياق، في حين أن كلمة "مستخدم" و"الذكاء الاصطناعي" الرسائل هي المناقشة الفعلية.
  • يمكنك إنشاء سلسلة محادثات تجمع بين الذاكرة ونموذج المحادثة.
  • بعد ذلك، لدينا قائمة بالحركات البيضاء التي تكررها. ويتم تنفيذ السلسلة باستخدام الحركة البيضاء التالية في كل مرة، ويردّ نموذج المحادثة بالحركة التالية الأفضل.

عند تشغيل هذه الفئة مع هذه الحركات، من المفترض أن يظهر لك الناتج التالي:

$ ./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 كيفية لعب الشطرنج؟ ليس بالضبط، ولكن خلال التدريب، تبيّن أنّ النموذج قد رأى بعض التعليقات على لعبة الشطرنج أو حتى ملفات PGN (Portable Game Notation) للألعاب السابقة. على الأرجح لن يفوز برنامج الدردشة المبرمَجة هذا ضد AlphaZero (وهو الذكاء الاصطناعي الذي يهزم أفضل لاعبي Go وShoogi وChess)، وقد تنحرف المحادثة عن مسارها الآخر لأنّ النموذج لا يتذكّر حالة اللعبة الفعلية.

نماذج Chat فعّالة جدًا ويمكنها إنشاء تفاعلات مفيدة مع المستخدمين والتعامل مع العديد من المهام السياقية. في القسم التالي، سنلقي نظرة على مهمة مفيدة وهي: استخراج البيانات المنظَّمة من النص.

6- استخراج المعلومات من النص غير المنظَّم

في القسم السابق، أنشأت محادثات بين مستخدم ونموذج لغة محادثة. ولكن باستخدام LangChain4J، يمكنك أيضًا استخدام نموذج دردشة لاستخراج المعلومات المنظمة من النص غير المهيكل.

لنفترض أنّك تريد استخراج اسم شخص وعمره مع توفّر سيرة ذاتية أو وصف له. يمكنك توجيه النموذج اللغوي الكبير لإنشاء بُنى بيانات JSON باستخدام طلب تم تعديله بشكل ذكي (يُعرف هذا عادةً باسم "هندسة الطلبات").

سيتم تعديل الفئة ChatPrompts على النحو التالي:

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

لنلقِ نظرة على الخطوات المختلفة في هذا الملف:

  • يتم تعريف الفئة Person لتمثيل التفاصيل التي تصف الشخص (اسمه وعمره).
  • يتم إنشاء الواجهة PersonExtractor باستخدام طريقة تعرض سلسلة نصية غير منظَّمة لعرض مثيل Person ذي مثيل.
  • تتم إضافة تعليقات توضيحية إلى extractPerson() من خلال تعليق توضيحي @UserMessage يربط الطلب بها. هذا هو الطلب الذي سيستخدمه النموذج لاستخراج المعلومات وعرض التفاصيل في شكل مستند JSON الذي سيتم تحليله نيابةً عنك ودمجه في مثيل Person.

لنلقِ الآن نظرة على محتوى طريقة main():

  • يتم إنشاء مثيل لنموذج المحادثة.
  • يتم إنشاء كائن PersonExtractor باستخدام فئة AiServices في LangChain4J.
  • بعد ذلك، يمكنك ببساطة استدعاء Person person = extractor.extractPerson(...) لاستخراج تفاصيل الشخص من النص غير المنظَّم، واسترجاع مثيل Person بالاسم والعمر.

الآن، قم بتشغيل هذه الفئة باستخدام الأمر التالي:

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

> Task :app:run
Anna
23

نعم. اسمي "آنا"، وهي تبلغ من العمر 23 سنة.

ما يهمّنا في استخدام هذا الأسلوب في AiServices هو أنّك تعمل باستخدام عناصر مكتوبة بحروف كبيرة. أنت لا تتفاعل مباشرةً مع النموذج اللغوي الكبير في المحادثة. بدلاً من ذلك، أنت تستخدم فئات محددة، مثل فئة "الشخص" لتمثيل المعلومات الشخصية المستخرجة، ولديك فئة PersonExtractor بطريقة extractPerson() تعرض مثيل "شخص". ما مِن مفهوم حول النموذج اللغوي الكبير (LLM)، وبصفتك مطوِّرًا بلغة Java، تتلاعب بالفئات والكائنات العادية.

7. استرداد البيانات من الجيل المحسّن: الدردشة مع مستنداتك

لنعد إلى المحادثات. هذه المرة، ستتمكن من طرح أسئلة حول مستنداتك. ستنشئ روبوت دردشة قادرًا على استرداد المعلومات ذات الصلة من قاعدة بيانات مستخرجات المستندات، وسيستخدم النموذج هذه المعلومات لـ "تحديد" إجاباته، بدلاً من محاولة إنشاء ردود قادمة من التدريب. يسمى هذا النمط RAG، أو التوليف المعزز.

باختصار، هناك مرحلتان ضمن "الجيل المعزز للاسترجاع":

  1. مرحلة النقل: يتم تحميل المستندات، وتقسيمها إلى أجزاء أصغر، ويتم تخزين تمثيل اتجاهي لها ("تضمين متّجه") في "قاعدة بيانات متجه" قادرة على إجراء عمليات بحث دلالية.

6c5bb5cb2e3b8088.png

  1. مرحلة طلب البحث - يمكن للمستخدمين الآن طرح أسئلة على برنامج الدردشة المبرمَجة حول المستندات. سيتم تحويل السؤال إلى متجه أيضًا، ومقارنته بجميع المتجهات الأخرى في قاعدة البيانات. عادة ما تكون المتجهات الأكثر تماثلاً مرتبطة دلاليًا، ويتم عرضها بواسطة قاعدة بيانات المتجه. بعد ذلك، يحصل النموذج اللغوي الكبير على سياق المحادثة، وهو مقتطفات من النص المقابلة للخطوط المتجهة التي تعرضها قاعدة البيانات، ويُطلب منه تحديد إجابته من خلال الاطّلاع على تلك المقتطفات.

2c279c506d7606cd.png

جارٍ تحضير مستنداتك

في هذا العرض التوضيحي الجديد، ستطرح أسئلة حول بنية "المحولات" للشبكة العصبية، التي أصبحت رائدة في ابتكارها Google، وهي الطريقة التي يتم من خلالها تنفيذ جميع النماذج اللغوية الكبيرة الحديثة في الوقت الحالي.

يمكنك استرداد البحث الذي وصف هذه البنية ("الانتباه هو كل ما تحتاجه")، باستخدام الأمر wget لتنزيل ملف PDF من الإنترنت:

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

تنفيذ سلسلة استرجاعية حوارية

دعونا نستكشف، بالتفصيل، كيفية إنشاء نهج المرحلتين، أولاً من خلال نقل المستند، ثم وقت الاستعلام عندما يطرح المستخدمون أسئلة حول المستند.

نقل المستند

الخطوة الأولى في مرحلة نقل المستند هي تحديد موقع ملف PDF الذي ننزّله وإعداد PdfParser لقراءته:

PdfDocumentParser pdfParser = new PdfDocumentParser();
Document document = pdfParser.parse(
    new FileInputStream(new File("/home/YOUR_USER_NAME/palm-workshop/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();

بعد ذلك، ستحتاج إلى بعض الصفوف للتعاون معًا من أجل:

  • لتحميل مستند PDF وتقسيمه إلى مجموعات
  • قم بإنشاء تضمينات متجه لكل هذه المقاطع.
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);

يتم إنشاء مثيل لـ InMemoryEmbeddingStore، وهو قاعدة بيانات متجه في الذاكرة، لتخزين تضمينات المتجه.

تم تقسيم المستند إلى مجموعات بفضل الفئة DocumentSplitters. سيتم تقسيم نص ملف PDF إلى مقتطفات من 500 حرف، مع تداخل مكون من 100 حرف (مع المقطع التالي، لتجنب قص الكلمات أو الجمل، بأجزاء وأجزاء).

أداة نقل البيانات إلى المتجر يربط مُقسّم المستند ونموذج التضمين لحساب المتجهات وقاعدة بيانات المتجه في الذاكرة. بعد ذلك، ستتولى طريقة ingest() إجراء عملية النقل.

الآن، انتهت المرحلة الأولى، وتم تحويل المستند إلى أجزاء نصية مع تضمينات المتجهات المرتبطة بها، وتخزينها في قاعدة بيانات المتجه.

طرح الأسئلة

حان الوقت للاستعداد لطرح الأسئلة! يمكن اتّباع نموذج المحادثة المعتاد لبدء المحادثة باتّباع الخطوات التالية:

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

ستحتاج أيضًا إلى فئة "retriever" التي ستربط قاعدة بيانات المتجه (في المتغير embeddingStore) ونموذج التضمين. وتتمثل مهمتها في الاستعلام عن قاعدة بيانات المتجه عن طريق حساب تضمين متجه لاستعلام المستخدم، للعثور على متجهات مماثلة في قاعدة البيانات:

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

في هذه المرحلة، يمكنك إنشاء مثيل للفئة ConversationalRetrievalChain (هذا مجرد اسم مختلف لنمط الإنشاء المعزز لاسترجاع البيانات):

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

يمكنك تشغيل البرنامج باستخدام:

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

في الإخراج، يُفترض أن ترى الإجابة عن أسئلتك:

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.

الحل الكامل

لتسهيل النسخ واللصق، في ما يلي المحتوى الكامل للفئة 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. تهانينا

تهانينا، لقد أنشأت بنجاح أول تطبيق دردشة مستند إلى الذكاء الاصطناعي التوليدي في Java باستخدام LangChain4J وPaLM API. لقد اكتشفت على طول الطريق أنّ نماذج المحادثة اللغوية الكبيرة فعّالة جدًا وقادرة على التعامل مع مهام مختلفة مثل الأسئلة والإجابة، حتى من خلال مستنداتك الخاصة واستخراج البيانات، وتمكّنت إلى حدّ ما من لعب بعض ألعاب الشطرنج.

الخطوات التالية

يمكنك الاطّلاع على بعض الدروس التطبيقية التالية حول الترميز باستخدام نموذج PaLM في Java:

قراءة إضافية

المستندات المرجعية