1. परिचय
इस कोडलैब में, Google Cloud पर Vertex AI पर होस्ट किए गए Gemini लार्ज लैंग्वेज मॉडल (एलएलएम) पर फ़ोकस किया गया है. Vertex AI एक ऐसा प्लैटफ़ॉर्म है जिसमें Google Cloud के सभी मशीन लर्निंग प्रॉडक्ट, सेवाएं, और मॉडल शामिल हैं.
LangChain4j फ़्रेमवर्क का इस्तेमाल करके, Gemini API के साथ इंटरैक्ट करने के लिए, आपको Java का इस्तेमाल करना होगा. सवालों के जवाब देने, आइडिया जनरेट करने, इकाई और स्ट्रक्चर्ड कॉन्टेंट निकालने, ज़्यादा जानकारी के साथ कॉन्टेंट जनरेट करने, और फ़ंक्शन कॉल करने के लिए, एलएलएम का फ़ायदा पाने के कुछ उदाहरण देखे जाएंगे.
जनरेटिव एआई क्या है?
जनरेटिव एआई का मतलब है, आर्टिफ़िशियल इंटेलिजेंस (एआई) का इस्तेमाल करके नया कॉन्टेंट बनाना. जैसे, टेक्स्ट, इमेज, संगीत, ऑडियो, और वीडियो.
जनरेटिव एआई, लार्ज लैंग्वेज मॉडल (एलएलएम) की मदद से काम करता है. ये मॉडल एक साथ कई टास्क पूरे कर सकते हैं. साथ ही, ये अलग-अलग तरह के काम कर सकते हैं. जैसे- बड़े लेख की खास जानकारी लिखना, सवालों के जवाब देना, अलग-अलग कैटगरी बनाना वगैरह. कम से कम ट्रेनिंग के साथ, बुनियादी मॉडल को टारगेट किए गए इस्तेमाल के उदाहरणों के लिए, बहुत कम डेटा के साथ अडैप्ट किया जा सकता है.
जनरेटिव एआई कैसे काम करता है?
जनरेटिव एआई, मशीन लर्निंग (एमएल) मॉडल का इस्तेमाल करके काम करता है. इससे, यह इंसानों के बनाए गए कॉन्टेंट के डेटासेट में पैटर्न और रिलेशनशिप को समझ पाता है. इसके बाद, यह नया कॉन्टेंट जनरेट करने के लिए, सीखे गए पैटर्न का इस्तेमाल करता है.
जनरेटिव एआई मॉडल को ट्रेन करने का सबसे सामान्य तरीका, सुपरवाइज़्ड लर्निंग का इस्तेमाल करना है. मॉडल को लोगों के बनाए गए कॉन्टेंट और उससे जुड़े लेबल का एक सेट दिया जाता है. इसके बाद, यह एआई, लोगों के बनाए गए कॉन्टेंट जैसा कॉन्टेंट जनरेट करना सीखता है.
जनरेटिव एआई के सामान्य इस्तेमाल क्या हैं?
जनरेटिव एआई का इस्तेमाल इन कामों के लिए किया जा सकता है:
- बेहतर चैट और खोज के अनुभवों की मदद से, ग्राहकों के इंटरैक्शन को बेहतर बनाएं.
- बातचीत वाले इंटरफ़ेस और खास जानकारी की मदद से, ज़्यादा डेटा एक्सप्लोर करें.
- बार-बार होने वाले कामों में मदद करता है. जैसे, प्रस्तावों के अनुरोधों का जवाब देना, मार्केटिंग कॉन्टेंट को अलग-अलग भाषाओं में स्थानीय भाषा में उपलब्ध कराना, और ग्राहक के अनुबंधों की शर्तों का पालन हो रहा है या नहीं, यह देखना वगैरह.
Google Cloud में जनरेटिव एआई से जुड़ी कौनसी सुविधाएं उपलब्ध हैं?
Vertex AI की मदद से, फ़ाउंडेशन मॉडल के साथ इंटरैक्ट किया जा सकता है, उन्हें पसंद के मुताबिक बनाया जा सकता है, और अपने ऐप्लिकेशन में एम्बेड किया जा सकता है. इसके लिए, आपको एमएल के बारे में ज़्यादा जानकारी की ज़रूरत नहीं है. Model Garden पर फ़ाउंडेशन मॉडल ऐक्सेस किए जा सकते हैं. इसके अलावा, Vertex AI Studio पर आसान यूज़र इंटरफ़ेस (यूआई) की मदद से मॉडल को ट्यून किया जा सकता है या डेटा साइंस नोटबुक में मॉडल का इस्तेमाल किया जा सकता है.
Vertex AI Search and Conversation की मदद से, डेवलपर जनरेटिव एआई की मदद से काम करने वाले सर्च इंजन और चैटबॉट तेज़ी से बना सकते हैं.
Gemini की मदद से काम करने वाला Gemini for Google Cloud, एआई की मदद से काम करने वाला एक कोलैबोरेटर है. यह Google Cloud और IDEs पर उपलब्ध है. इससे आपको ज़्यादा काम तेज़ी से करने में मदद मिलती है. Gemini Code Assist, कोड पूरा करने, कोड जनरेट करने, और कोड के बारे में जानकारी देने की सुविधा देता है. साथ ही, तकनीकी सवाल पूछने के लिए, इसकी मदद से चैट की जा सकती है.
Gemini क्या है?
Gemini, जनरेटिव एआई मॉडल का एक फ़ैमिली है. इसे Google DeepMind ने बनाया है. इसे अलग-अलग तरह के इस्तेमाल के उदाहरणों के लिए डिज़ाइन किया गया है. मल्टीमोडल का मतलब है कि यह अलग-अलग तरह के कॉन्टेंट को प्रोसेस और जनरेट कर सकता है. जैसे, टेक्स्ट, कोड, इमेज, और ऑडियो.
Gemini अलग-अलग वैरिएंट और साइज़ में उपलब्ध है:
- Gemini Ultra: मुश्किल कामों को पूरा करने के लिए, यह सबसे बड़ा और बेहतर वर्शन है.
- Gemini Flash: यह सबसे तेज़ और किफ़ायती मॉडल है. इसे ज़्यादा संख्या में टास्क के लिए ऑप्टिमाइज़ किया गया है.
- Gemini Pro: यह मॉडल मध्यम साइज़ का है. इसे अलग-अलग टास्क के लिए ऑप्टिमाइज़ किया गया है.
- Gemini Nano: यह सबसे बेहतर एआई मॉडल है. इसे डिवाइस पर मौजूद टास्क पूरे करने के लिए बनाया गया है.
मुख्य सुविधाएं:
- मल्टीमोडल: Gemini, जानकारी के अलग-अलग फ़ॉर्मैट को समझने और मैनेज करने की सुविधा देता है. यह सुविधा, सिर्फ़ टेक्स्ट वाले लैंग्वेज मॉडल की तुलना में काफ़ी बेहतर है.
- परफ़ॉर्मेंस: Gemini Ultra, कई बेंचमार्क पर मौजूदा मॉडल की तुलना में बेहतर परफ़ॉर्म करता है. यह पहला मॉडल है जिसने एमएमएलयू (बड़े पैमाने पर मल्टीटास्क लैंग्वेज को समझने की सुविधा) बेंचमार्क में, मानव विशेषज्ञों की परफ़ॉर्मेंस को पीछे छोड़ा है.
- ज़रूरत के मुताबिक इस्तेमाल: Gemini के अलग-अलग साइज़, इसे अलग-अलग तरह के कामों के लिए इस्तेमाल करने लायक बनाते हैं. जैसे, बड़े पैमाने पर रिसर्च से लेकर मोबाइल डिवाइसों पर डिप्लॉयमेंट तक.
Java से Vertex AI पर Gemini के साथ कैसे इंटरैक्ट किया जा सकता है?
आपके पास दो विकल्प हैं:
- Gemini के लिए Vertex AI Java API की आधिकारिक लाइब्रेरी.
- LangChain4j फ़्रेमवर्क.
इस कोडलैब में, आपको LangChain4j फ़्रेमवर्क का इस्तेमाल करना होगा.
LangChain4j फ़्रेमवर्क क्या है?
LangChain4j फ़्रेमवर्क, एक ओपन सोर्स लाइब्रेरी है. इसका इस्तेमाल करके, अपने Java ऐप्लिकेशन में एलएलएम इंटिग्रेट किए जा सकते हैं. इसके लिए, अलग-अलग कॉम्पोनेंट को ऑर्केस्ट्रेट किया जाता है. जैसे, एलएलएम के साथ-साथ वेक्टर डेटाबेस (सेमांटिक सर्च के लिए), दस्तावेज़ लोडर और स्प्लिटर (दस्तावेज़ों का विश्लेषण करने और उनसे सीखने के लिए), आउटपुट पार्सर वगैरह.
इस प्रोजेक्ट को LangChain Python प्रोजेक्ट से प्रेरणा मिली है. हालांकि, इसका मकसद Java डेवलपर की मदद करना है.
आपको क्या सीखने को मिलेगा
- Gemini और LangChain4j का इस्तेमाल करने के लिए, Java प्रोजेक्ट को सेट अप करने का तरीका
- प्रोग्राम के हिसाब से Gemini को अपना पहला प्रॉम्प्ट भेजने का तरीका
- Gemini से मिले जवाबों को स्ट्रीम करने का तरीका
- उपयोगकर्ता और Gemini के बीच बातचीत बनाने का तरीका
- टेक्स्ट और इमेज, दोनों भेजकर Gemini को मल्टीमोडल कॉन्टेक्स्ट में इस्तेमाल करने का तरीका
- अनस्ट्रक्चर्ड कॉन्टेंट से काम का स्ट्रक्चर्ड डेटा निकालने का तरीका
- प्रॉम्प्ट टेंप्लेट में बदलाव करने का तरीका
- टेक्स्ट की कैटगरी तय करने का तरीका, जैसे कि सेंटीमेंट का विश्लेषण
- अपने दस्तावेज़ों के साथ चैट करने का तरीका (Retrieval Augmented Generation)
- फ़ंक्शन कॉलिंग की मदद से, अपने चैटबॉट को बेहतर बनाने का तरीका
- Ollama और TestContainers के साथ, Gemma को लोकल तौर पर इस्तेमाल करने का तरीका
आपको इन चीज़ों की ज़रूरत होगी
- Java प्रोग्रामिंग लैंग्वेज के बारे में जानकारी
- Google Cloud प्रोजेक्ट
- Chrome या Firefox जैसा कोई ब्राउज़र
2. सेटअप और ज़रूरी शर्तें
अपने हिसाब से एनवायरमेंट सेट अप करना
- Google Cloud Console में साइन इन करें और नया प्रोजेक्ट बनाएं या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें. अगर आपके पास पहले से कोई Gmail या Google Workspace खाता नहीं है, तो आपको एक खाता बनाना होगा.
- प्रोजेक्ट का नाम, इस प्रोजेक्ट में हिस्सा लेने वाले लोगों के लिए डिसप्ले नेम होता है. यह एक वर्ण स्ट्रिंग है, जिसका इस्तेमाल Google API नहीं करते. इसे कभी भी अपडेट किया जा सकता है.
- प्रोजेक्ट आईडी, Google Cloud के सभी प्रोजेक्ट के लिए यूनीक होता है. साथ ही, इसे सेट करने के बाद बदला नहीं जा सकता. Cloud Console, अपने-आप एक यूनीक स्ट्रिंग जनरेट करता है. आम तौर पर, आपको यह जानने की ज़रूरत नहीं होती कि यह स्ट्रिंग क्या है. ज़्यादातर कोडलैब में, आपको अपने प्रोजेक्ट आईडी का रेफ़रंस देना होगा. आम तौर पर, इसे
PROJECT_ID
के तौर पर पहचाना जाता है. अगर आपको जनरेट किया गया आईडी पसंद नहीं आता है, तो कोई दूसरा आईडी जनरेट किया जा सकता है. इसके अलावा, आपके पास खुद का कोई दूसरा नाम चुनने का विकल्प भी है. इस चरण के बाद, इसे बदला नहीं जा सकता. यह प्रोजेक्ट के दौरान बना रहता है. - आपकी जानकारी के लिए बता दें कि तीसरी वैल्यू, प्रोजेक्ट नंबर होती है. इसका इस्तेमाल कुछ एपीआई करते हैं. दस्तावेज़ में इन तीनों वैल्यू के बारे में ज़्यादा जानें.
- इसके बाद, आपको Cloud के संसाधनों/एपीआई का इस्तेमाल करने के लिए, Cloud Console में बिलिंग की सुविधा चालू करनी होगी. इस कोडलैब को चलाने के लिए, आपसे कोई शुल्क नहीं लिया जाएगा. इस ट्यूटोरियल के बाद बिलिंग से बचने के लिए, बनाए गए संसाधनों को बंद किया जा सकता है या प्रोजेक्ट को मिटाया जा सकता है. Google Cloud के नए उपयोगकर्ता, 300 डॉलर के मुफ़्त ट्रायल वाले कार्यक्रम में शामिल हो सकते हैं.
Cloud Shell शुरू करना
Google Cloud को आपके लैपटॉप से रिमोट तौर पर इस्तेमाल किया जा सकता है. हालांकि, इस कोडलैब में आपको Cloud Shell का इस्तेमाल करना होगा. यह Cloud में चलने वाला कमांड-लाइन एनवायरमेंट है.
Cloud Shell चालू करें
- Cloud Console में, Cloud Shell चालू करें
पर क्लिक करें.
अगर Cloud Shell पहली बार शुरू किया जा रहा है, तो आपको एक इंटरमीडियरी स्क्रीन दिखेगी. इसमें Cloud Shell के बारे में बताया गया होगा. अगर आपको इंटरमीडियरी स्क्रीन दिखती है, तो जारी रखें पर क्लिक करें.
Cloud Shell को प्रोवाइड करने और उससे कनेक्ट करने में सिर्फ़ कुछ मिनट लगेंगे.
इस वर्चुअल मशीन में, डेवलपमेंट के लिए ज़रूरी सभी टूल लोड होते हैं. यह 5 जीबी की होम डायरेक्ट्री उपलब्ध कराती है और Google Cloud में चलती है. इससे नेटवर्क की परफ़ॉर्मेंस और पुष्टि करने की प्रोसेस बेहतर होती है. इस कोडलैब में, ज़्यादातर काम ब्राउज़र से किया जा सकता है.
Cloud Shell से कनेक्ट होने के बाद, आपको यह दिखेगा कि आपने पुष्टि कर ली है और प्रोजेक्ट आपके प्रोजेक्ट आईडी पर सेट है.
- पुष्टि करने के लिए, 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`
- gcloud कमांड को आपके प्रोजेक्ट के बारे में पता है या नहीं, इसकी पुष्टि करने के लिए Cloud Shell में यह कमांड चलाएं:
gcloud config list project
कमांड आउटपुट
[core] project = <PROJECT_ID>
अगर ऐसा नहीं है, तो इसे इस निर्देश से सेट किया जा सकता है:
gcloud config set project <PROJECT_ID>
कमांड आउटपुट
Updated property [core/project].
3. डेवलपमेंट एनवायरमेंट तैयार करना
इस कोडलैब में, आपको Java प्रोग्राम डेवलप करने के लिए, Cloud Shell टर्मिनल और Cloud Shell एडिटर का इस्तेमाल करना होगा.
Vertex AI API चालू करना
पक्का करें कि Google Cloud Console में, आपके प्रोजेक्ट का नाम Google Cloud Console में सबसे ऊपर दिख रहा हो. अगर ऐसा नहीं है, तो प्रोजेक्ट चुनने वाला टूल खोलने के लिए, कोई प्रोजेक्ट चुनें पर क्लिक करें. इसके बाद, अपनी पसंद का प्रोजेक्ट चुनें.
Vertex AI एपीआई को Google Cloud Console के Vertex AI सेक्शन या Cloud Shell टर्मिनल से चालू किया जा सकता है.
Google Cloud Console से चालू करने के लिए, सबसे पहले Google Cloud Console मेन्यू के Vertex AI सेक्शन पर जाएं:
Vertex AI डैशबोर्ड में, सुझाए गए सभी एपीआई चालू करें पर क्लिक करें.
इससे कई एपीआई चालू हो जाएंगे, लेकिन कोडलैब के लिए aiplatform.googleapis.com
सबसे ज़रूरी है.
इसके अलावा, इस एपीआई को Cloud Shell टर्मिनल से भी चालू किया जा सकता है. इसके लिए, यह कमांड इस्तेमाल करें:
gcloud services enable aiplatform.googleapis.com
GitHub रिपॉज़िटरी का क्लोन बनाएं
Cloud Shell टर्मिनल में, इस कोडलैब के लिए डेटा स्टोर करने की जगह को क्लोन करें:
git clone https://github.com/glaforge/gemini-workshop-for-java-developers.git
यह देखने के लिए कि प्रोजेक्ट चलने के लिए तैयार है या नहीं, "Hello World" प्रोग्राम को चलाकर देखें.
पक्का करें कि आप टॉप लेवल फ़ोल्डर में हों:
cd gemini-workshop-for-java-developers/
Gradle रैपर बनाएं:
gradle wrapper
gradlew
के साथ चलाएं:
./gradlew run
आपको यह आउटपुट दिखेगा:
.. > Task :app:run Hello World!
Cloud Editor खोलना और सेटअप करना
Cloud Shell में Cloud Code Editor की मदद से कोड खोलें:
Cloud Code Editor में, File
-> Open Folder
को चुनकर कोडलैब का सोर्स फ़ोल्डर खोलें. इसके बाद, कोडलैब का सोर्स फ़ोल्डर चुनें (उदाहरण के लिए, /home/username/gemini-workshop-for-java-developers/
).
एनवायरमेंट वैरिएबल सेट अप करना
Terminal
-> New Terminal
को चुनकर, Cloud Code Editor में नया टर्मिनल खोलें. कोड के उदाहरणों को चलाने के लिए, दो एनवायरमेंट वैरिएबल सेट अप करें:
- PROJECT_ID — आपका Google Cloud प्रोजेक्ट आईडी
- LOCATION — वह इलाका जहां Gemini मॉडल डिप्लॉय किया गया है
वैरिएबल को इस तरह एक्सपोर्ट करें:
export PROJECT_ID=$(gcloud config get-value project) export LOCATION=us-central1
4. Gemini मॉडल को पहला कॉल
प्रोजेक्ट सही तरीके से सेट अप हो गया है. अब Gemini API को कॉल करने का समय आ गया है.
app/src/main/java/gemini/workshop
डायरेक्ट्री में QA.java
पर जाएं:
package gemini.workshop;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
public class QA {
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.build();
System.out.println(model.generate("Why is the sky blue?"));
}
}
इस पहले उदाहरण में, आपको VertexAiGeminiChatModel
क्लास इंपोर्ट करनी होगी, जो ChatModel
इंटरफ़ेस को लागू करती है.
main
तरीके में, VertexAiGeminiChatModel
के लिए बिल्डर का इस्तेमाल करके चैट भाषा मॉडल को कॉन्फ़िगर किया जाता है. साथ ही, यह जानकारी दी जाती है:
- प्रोजेक्ट
- जगह
- मॉडल का नाम (
gemini-1.5-flash-002
).
अब भाषा मॉडल तैयार है. इसलिए, generate()
तरीके को कॉल करके, एलएलएम को अपना प्रॉम्प्ट, सवाल या निर्देश भेजे जा सकते हैं. यहां, आसमान नीला क्यों होता है, इस बारे में एक आसान सवाल पूछा गया है.
अलग-अलग सवाल या टास्क आज़माने के लिए, इस प्रॉम्प्ट को बदलें.
सोर्स कोड के रूट फ़ोल्डर में सैंपल चलाएं:
./gradlew run -q -DjavaMainClass=gemini.workshop.QA
आपको इससे मिलता-जुलता आउटपुट दिखेगा:
The sky appears blue because of a phenomenon called Rayleigh scattering. When sunlight enters the atmosphere, it is made up of a mixture of different wavelengths of light, each with a different color. The different wavelengths of light interact with the molecules and particles in the atmosphere in different ways. The shorter wavelengths of light, such as those corresponding to blue and violet light, are more likely to be scattered in all directions by these particles than the longer wavelengths of light, such as those corresponding to red and orange light. This is because the shorter wavelengths of light have a smaller wavelength and are able to bend around the particles more easily. As a result of Rayleigh scattering, the blue light from the sun is scattered in all directions, and it is this scattered blue light that we see when we look up at the sky. The blue light from the sun is not actually scattered in a single direction, so the color of the sky can vary depending on the position of the sun in the sky and the amount of dust and water droplets in the atmosphere.
बधाई हो, आपने Gemini पर अपना पहला कॉल कर लिया है!
जवाब स्ट्रीम करना
क्या आपको पता चला कि जवाब कुछ सेकंड के बाद, एक बार में दिया गया था? स्ट्रीमिंग रिस्पॉन्स वैरिएंट की मदद से, जवाब को धीरे-धीरे भी पाया जा सकता है. स्ट्रीमिंग रिस्पॉन्स, मॉडल रिस्पॉन्स को धीरे-धीरे उपलब्ध कराता है.
इस कोडलैब में, हम स्ट्रीमिंग रिस्पॉन्स के बजाय, नॉन-स्ट्रीमिंग रिस्पॉन्स का इस्तेमाल करेंगे. हालांकि, स्ट्रीमिंग रिस्पॉन्स को देखने के लिए, यह देखें कि इसे कैसे किया जा सकता है.
app/src/main/java/gemini/workshop
डायरेक्ट्री में StreamQA.java
में, स्ट्रीमिंग रिस्पॉन्स को ऐक्शन में देखा जा सकता है:
package gemini.workshop;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiStreamingChatModel;
import static dev.langchain4j.model.LambdaStreamingResponseHandler.onNext;
public class StreamQA {
public static void main(String[] args) {
StreamingChatLanguageModel model = VertexAiGeminiStreamingChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(4000)
.build();
model.generate("Why is the sky blue?", onNext(System.out::println));
}
}
इस बार, हम VertexAiGeminiStreamingChatModel
इंटरफ़ेस को लागू करने वाली स्ट्रीमिंग क्लास के वैरिएंट StreamingChatLanguageModel
इंपोर्ट करते हैं. आपको LambdaStreamingResponseHandler.onNext
को स्टैटिक तौर पर इंपोर्ट भी करना होगा. यह एक आसान तरीका है, जो Java लैम्ब्डा एक्सप्रेशन की मदद से स्ट्रीमिंग हैंडलर बनाने के लिए StreamingResponseHandler
उपलब्ध कराता है.
इस बार, generate()
तरीके का सिग्नेचर थोड़ा अलग है. स्ट्रिंग के बजाय, रिटर्न टाइप के तौर पर कोई वैल्यू नहीं दी जाती. प्रॉम्प्ट के अलावा, आपको स्ट्रीमिंग रिस्पॉन्स हैंडलर भी पास करना होगा. यहां, ऊपर बताए गए स्टैटिक इंपोर्ट की मदद से, हम एक ऐसा लैम्ब्डा एक्सप्रेशन तय कर सकते हैं जिसे onNext()
तरीके में पास किया जाता है. जब भी जवाब का कोई नया हिस्सा उपलब्ध होता है, तब हर बार Lambda एक्सप्रेशन को कॉल किया जाता है. वहीं, गड़बड़ी होने पर ही फ़ंक्शन को कॉल किया जाता है.
चलाएं:
./gradlew run -q -DjavaMainClass=gemini.workshop.StreamQA
आपको पिछली क्लास की तरह ही जवाब मिलेगा. हालांकि, इस बार आपको पूरा जवाब दिखने का इंतज़ार करने के बजाय, जवाब धीरे-धीरे दिखेगा.
अतिरिक्त कॉन्फ़िगरेशन
कॉन्फ़िगरेशन के लिए, हमने सिर्फ़ प्रोजेक्ट, जगह, और मॉडल का नाम तय किया है. हालांकि, मॉडल के लिए अन्य पैरामीटर भी तय किए जा सकते हैं:
temperature(Float temp)
— यह तय करने के लिए कि आपको जवाब कितना क्रिएटिव चाहिए (0 का मतलब है कि जवाब कम क्रिएटिव है और अक्सर ज़्यादा तथ्यों पर आधारित होता है, जबकि 2 का मतलब है कि जवाब ज़्यादा क्रिएटिव है)topP(Float topP)
— उन संभावित शब्दों को चुनने के लिए जिनकी कुल संभावना, फ़्लोटिंग-पॉइंट नंबर (0 से 1 के बीच) के बराबर होtopK(Integer topK)
— टेक्स्ट पूरा करने के लिए, संभावित शब्दों में से कोई एक शब्द चुनने के लिए. संभावित शब्दों की संख्या 1 से 40 तक हो सकती हैmaxOutputTokens(Integer max)
— मॉडल के दिए गए जवाब की ज़्यादा से ज़्यादा लंबाई तय करने के लिए (आम तौर पर, चार टोकन में करीब तीन शब्द होते हैं)maxRetries(Integer retries)
— अगर आपने हर बार के लिए तय किए गए कोटे से ज़्यादा अनुरोध कर लिए हैं या प्लैटफ़ॉर्म को कोई तकनीकी समस्या आ रही है, तो मॉडल को कॉल को तीन बार फिर से आज़माने के लिए कहा जा सकता है
अब तक, आपने Gemini से सिर्फ़ एक सवाल पूछा है. हालांकि, आपके पास एक से ज़्यादा बार बातचीत करने का विकल्प भी है. अगले सेक्शन में, आपको इस बारे में जानकारी मिलेगी.
5. Gemini के साथ चैट करें
पिछले चरण में, आपने एक सवाल पूछा था. अब उपयोगकर्ता और एलएलएम के बीच रीयल बातचीत करने का समय आ गया है. असली बातचीत बनाने के लिए, हर सवाल और जवाब को पिछले सवालों और जवाबों के आधार पर बनाया जा सकता है.
app/src/main/java/gemini/workshop
फ़ोल्डर में Conversation.java
को देखें:
package gemini.workshop;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.service.AiServices;
import java.util.List;
public class Conversation {
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.build();
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(20)
.build();
interface ConversationService {
String chat(String message);
}
ConversationService conversation =
AiServices.builder(ConversationService.class)
.chatLanguageModel(model)
.chatMemory(chatMemory)
.build();
List.of(
"Hello!",
"What is the country where the Eiffel tower is situated?",
"How many inhabitants are there in that country?"
).forEach( message -> {
System.out.println("\nUser: " + message);
System.out.println("Gemini: " + conversation.chat(message));
});
}
}
इस क्लास में कुछ नए और दिलचस्प इंपोर्ट:
MessageWindowChatMemory
— यह एक ऐसी क्लास है जो बातचीत के कई चरणों को मैनेज करने में मदद करेगी. साथ ही, पिछले सवालों और जवाबों को लोकल मेमोरी में सेव रखेगीAiServices
— यह एक हाई-लेवल एब्स्ट्रैक्शन क्लास है, जो चैट मॉडल और चैट मेमोरी को एक साथ जोड़ती है
मुख्य तरीके में, आपको मॉडल, चैट मेमोरी, और एआई सेवा सेट अप करनी होगी. मॉडल को प्रोजेक्ट, जगह, और मॉडल के नाम की जानकारी के साथ हमेशा की तरह कॉन्फ़िगर किया जाता है.
चैट मेमोरी बनाने के लिए, हम MessageWindowChatMemory
के बिल्डर का इस्तेमाल करते हैं. इससे, आपके बीच हुई बातचीत के पिछले 20 मैसेज सेव रहते हैं. यह बातचीत के ऊपर एक स्लाइडिंग विंडो होती है. इसका कॉन्टेक्स्ट, हमारे Java क्लास क्लाइंट में स्थानीय तौर पर सेव होता है.
इसके बाद, AI service
बनाएं, जो चैट मॉडल को चैट मेमोरी से जोड़ता है.
ध्यान दें कि एआई सेवा, हमारे तय किए गए कस्टम ConversationService
इंटरफ़ेस का इस्तेमाल कैसे करती है. यह इंटरफ़ेस, LangChain4j लागू करता है. यह String
क्वेरी लेता है और String
रिस्पॉन्स देता है.
अब, Gemini से बातचीत करने का समय आ गया है. सबसे पहले, एक सामान्य ग्रीटिंग भेजी जाती है. इसके बाद, आइफ़िल टावर के बारे में पहला सवाल पूछा जाता है, ताकि यह पता चल सके कि यह टावर किस देश में है. ध्यान दें कि आखिरी वाक्य, पहले सवाल के जवाब से जुड़ा है. इसमें, उस देश के लोगों की संख्या के बारे में बताया गया है जहां आइफ़िल टावर मौजूद है. हालांकि, इसमें उस देश का नाम नहीं दिया गया है जिसका नाम पिछले जवाब में दिया गया था. इससे पता चलता है कि हर प्रॉम्प्ट के साथ, पिछले सवाल और जवाब भेजे जाते हैं.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.Conversation
आपको इन जैसे तीन जवाब दिखेंगे:
User: Hello! Gemini: Hi there! How can I assist you today? User: What is the country where the Eiffel tower is situated? Gemini: France User: How many inhabitants are there in that country? Gemini: As of 2023, the population of France is estimated to be around 67.8 million.
Gemini से एक बार में एक सवाल पूछा जा सकता है या उससे कई बार बातचीत की जा सकती है. हालांकि, फ़िलहाल सिर्फ़ टेक्स्ट इनपुट का इस्तेमाल किया जा सकता है. इमेज के लिए क्या है? अगले चरण में, इमेज के बारे में जानें.
6. Gemini के साथ मल्टीमोडलिटी
Gemini एक मल्टीमोडल मॉडल है. यह इनपुट के तौर पर टेक्स्ट के साथ-साथ इमेज या वीडियो भी स्वीकार करता है. इस सेक्शन में, आपको टेक्स्ट और इमेज को मिलाने के उदाहरण के बारे में जानकारी मिलेगी.
क्या आपको लगता है कि Gemini इस बिल्ली को पहचान पाएगा?
Wikipedia से ली गई, बर्फ़ में बैठी बिल्ली की तस्वीरhttps://upload.wikimedia.org/wikipedia/commons/b/b6/Felis_catus-cat_on_snow.jpg
app/src/main/java/gemini/workshop
डायरेक्ट्री में Multimodal.java
पर एक नज़र डालें:
package gemini.workshop;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
public class Multimodal {
static final String CAT_IMAGE_URL =
"https://upload.wikimedia.org/wikipedia/" +
"commons/b/b6/Felis_catus-cat_on_snow.jpg";
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.build();
UserMessage userMessage = UserMessage.from(
ImageContent.from(CAT_IMAGE_URL),
TextContent.from("Describe the picture")
);
Response<AiMessage> response = model.generate(userMessage);
System.out.println(response.content().text());
}
}
इंपोर्ट किए गए डेटा में, हम अलग-अलग तरह के मैसेज और कॉन्टेंट के बीच अंतर करते हैं. UserMessage
में TextContent
और ImageContent
, दोनों ऑब्जेक्ट हो सकते हैं. यह एक तरह का मल्टीमोडल कॉन्टेंट है: इसमें टेक्स्ट और इमेज को मिलाया गया है. हम सिर्फ़ एक आसान स्ट्रिंग प्रॉम्प्ट नहीं भेजते, बल्कि हम एक ज़्यादा व्यवस्थित ऑब्जेक्ट भेजते हैं. यह ऑब्जेक्ट, उपयोगकर्ता के मैसेज को दिखाता है. इसमें इमेज कॉन्टेंट और टेक्स्ट कॉन्टेंट का एक-एक पीस होता है. मॉडल, Response
भेजता है, जिसमें AiMessage
शामिल होता है.
इसके बाद, content()
की मदद से जवाब से AiMessage
को वापस पाएं. इसके बाद, text()
की मदद से मैसेज का टेक्स्ट पाएं.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.Multimodal
इमेज के नाम से आपको यह पता चलता है कि उसमें क्या है, लेकिन Gemini का आउटपुट कुछ ऐसा होता है:
A cat with brown fur is walking in the snow. The cat has a white patch of fur on its chest and white paws. The cat is looking at the camera.
इमेज और टेक्स्ट प्रॉम्प्ट को मिलाकर, इस्तेमाल के दिलचस्प उदाहरण मिलते हैं. ऐसे ऐप्लिकेशन बनाए जा सकते हैं जो:
- तस्वीरों में मौजूद टेक्स्ट की पहचान करना.
- यह देखना कि किसी इमेज को दिखाना सुरक्षित है या नहीं.
- इमेज के कैप्शन बनाएं.
- सामान्य टेक्स्ट की जानकारी वाली इमेज के डेटाबेस में खोजें.
इमेज से जानकारी निकालने के अलावा, अनियमित टेक्स्ट से भी जानकारी निकाली जा सकती है. अगले सेक्शन में आपको इस बारे में जानकारी मिलेगी.
7. अनस्ट्रक्चर्ड टेक्स्ट से स्ट्रक्चर्ड जानकारी निकालना
कई मामलों में, रिपोर्ट दस्तावेज़ों, ईमेल या लंबी अवधि के अन्य टेक्स्ट में अहम जानकारी, बिना क्रम के दी जाती है. आम तौर पर, आपको अनस्ट्रक्चर्ड टेक्स्ट में मौजूद अहम जानकारी को स्ट्रक्चर्ड ऑब्जेक्ट के तौर पर निकालना होता है. चलिए देखते हैं कि ऐसा कैसे किया जा सकता है.
मान लें कि आपको किसी व्यक्ति की जीवनी, सीवी या ब्यौरे से उसका नाम और उम्र निकालनी है. एलएलएम को, बेहतर तरीके से बदले गए प्रॉम्प्ट की मदद से, अनस्ट्रक्चर्ड टेक्स्ट से JSON निकालने का निर्देश दिया जा सकता है. इसे आम तौर पर "प्रॉम्प्ट इंजीनियरिंग" कहा जाता है.
हालांकि, नीचे दिए गए उदाहरण में, JSON आउटपुट के बारे में बताने वाले प्रॉम्प्ट को तैयार करने के बजाय, हम Gemini की एक बेहतरीन सुविधा का इस्तेमाल करेंगे. इसे स्ट्रक्चर्ड आउटपुट कहा जाता है. इसके अलावा, कभी-कभी हम JSON स्कीमा के हिसाब से, मॉडल को सिर्फ़ मान्य JSON कॉन्टेंट आउटपुट करने के लिए मजबूर करते हैं.
app/src/main/java/gemini/workshop
में ExtractData.java
को देखें:
package gemini.workshop;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import static dev.langchain4j.model.vertexai.SchemaHelper.fromClass;
public class ExtractData {
record Person(String name, int age) { }
interface PersonExtractor {
@SystemMessage("""
Your role is to extract the name and age
of the person described in the biography.
""")
Person extractPerson(String biography);
}
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.responseMimeType("application/json")
.responseSchema(fromClass(Person.class))
.build();
PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);
String bio = """
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.
""";
Person person = extractor.extractPerson(bio);
System.out.println(person.name()); // Anna
System.out.println(person.age()); // 23
}
}
चलिए, इस फ़ाइल में मौजूद अलग-अलग चरणों पर एक नज़र डालते हैं:
Person
रिकॉर्ड में किसी व्यक्ति की जानकारी (नाम और उम्र) दी जाती है.PersonExtractor
इंटरफ़ेस को एक ऐसे तरीके से तय किया जाता है जो किसी अनस्ट्रक्चर्ड टेक्स्ट स्ट्रिंग कोPerson
इंस्टेंस के तौर पर दिखाता है.extractPerson()
को@SystemMessage
एनोटेशन से एनोटेट किया गया है, जो इसके साथ निर्देश प्रॉम्प्ट को जोड़ता है. मॉडल, जानकारी निकालने के लिए इस प्रॉम्प्ट का इस्तेमाल करेगा. साथ ही, जानकारी को JSON दस्तावेज़ के तौर पर दिखाएगा. इस दस्तावेज़ को आपके लिए पार्स किया जाएगा औरPerson
इंस्टेंस में अनमार्शल किया जाएगा.
अब main()
तरीके के कॉन्टेंट पर नज़र डालते हैं:
- चैट मॉडल को कॉन्फ़िगर और इंस्टैंशिएट किया गया है. हम मॉडल बिल्डर क्लास के दो नए तरीकों का इस्तेमाल कर रहे हैं:
responseMimeType()
औरresponseSchema()
. पहला विकल्प, Gemini को आउटपुट में मान्य JSON जनरेट करने के लिए कहता है. दूसरे तरीके से, उस JSON ऑब्जेक्ट का स्कीमा तय किया जाता है जिसे दिखाना है. इसके अलावा, यह एक सुविधाजनक तरीके को डेलिगेट करता है, जो किसी Java क्लास या रिकॉर्ड को सही JSON स्कीमा में बदल सकता है. - LangChain4j की
AiServices
क्लास की मदद से,PersonExtractor
ऑब्जेक्ट बनाया जाता है. - इसके बाद, बिना स्ट्रक्चर वाले टेक्स्ट से व्यक्ति की जानकारी निकालने के लिए,
Person person = extractor.extractPerson(...)
को कॉल करें. इससे आपको नाम और उम्र के साथPerson
का एक इंस्टेंस मिलेगा.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.ExtractData
आपको यह आउटपुट दिखेगा:
Anna 23
हां, यह ऐना है और उनकी उम्र 23 साल है!
इस AiServices
तरीके से, स्ट्रोंग टाइप वाले ऑब्जेक्ट का इस्तेमाल किया जाता है. आप सीधे तौर पर एलएलएम के साथ इंटरैक्ट नहीं कर रहे हैं. इसके बजाय, आपने निजी जानकारी को दिखाने के लिए Person
रिकॉर्ड जैसी खास क्लास का इस्तेमाल किया है. साथ ही, आपके पास PersonExtractor
ऑब्जेक्ट है, जिसमें extractPerson()
तरीका है, जो Person
इंस्टेंस दिखाता है. एलएलएम की अवधारणा को हटा दिया गया है. Java डेवलपर के तौर पर, इस PersonExtractor
इंटरफ़ेस का इस्तेमाल करते समय, आपको सिर्फ़ सामान्य क्लास और ऑब्जेक्ट में बदलाव करना होता है..
8. प्रॉम्प्ट टेंप्लेट की मदद से प्रॉम्प्ट बनाना
निर्देशों या सवालों के सामान्य सेट का इस्तेमाल करके एलएलएम से इंटरैक्ट करने पर, प्रॉम्प्ट का एक हिस्सा कभी नहीं बदलता. वहीं, दूसरे हिस्सों में डेटा होता है. उदाहरण के लिए, अगर आपको रेसिपी बनानी हैं, तो "आप एक कुशल शेफ हैं. कृपया इन चीज़ों से कोई रेसिपी बनाएं: ..." जैसे प्रॉम्प्ट का इस्तेमाल किया जा सकता है. इसके बाद, उस टेक्स्ट के आखिर में, चीज़ों को जोड़ें. प्रॉम्प्ट टेंप्लेट इसी काम के लिए होते हैं — जैसे प्रोग्रामिंग भाषाओं में इंटरपोलेशन की गई स्ट्रिंग. प्रॉम्प्ट टेंप्लेट में प्लेसहोल्डर होते हैं. इन्हें LLM को किए जाने वाले किसी खास कॉल के लिए, सही डेटा से बदला जा सकता है.
उदाहरण के लिए, app/src/main/java/gemini/workshop
डायरेक्ट्री में TemplatePrompt.java
को देखें:
package gemini.workshop;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.output.Response;
import java.util.HashMap;
import java.util.Map;
public class TemplatePrompt {
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(500)
.temperature(1.0f)
.topK(40)
.topP(0.95f)
.maxRetries(3)
.build();
PromptTemplate promptTemplate = PromptTemplate.from("""
You're a friendly chef with a lot of cooking experience.
Create a recipe for a {{dish}} with the following ingredients: \
{{ingredients}}, and give it a name.
"""
);
Map<String, Object> variables = new HashMap<>();
variables.put("dish", "dessert");
variables.put("ingredients", "strawberries, chocolate, and whipped cream");
Prompt prompt = promptTemplate.apply(variables);
Response<AiMessage> response = model.generate(prompt.toUserMessage());
System.out.println(response.content().text());
}
}
हमेशा की तरह, VertexAiGeminiChatModel
मॉडल को कॉन्फ़िगर किया जाता है. इसमें क्रिएटिविटी का लेवल ज़्यादा होता है और तापमान भी ज़्यादा होता है. साथ ही, topP और topK की वैल्यू भी ज़्यादा होती हैं. इसके बाद, हमारे प्रॉम्प्ट की स्ट्रिंग को पास करके, from()
स्टैटिक तरीके से PromptTemplate
बनाएं. साथ ही, डबल कर्ली ब्रैकेट प्लेसहोल्डर वैरिएबल: {{dish}}
और {{ingredients}}
का इस्तेमाल करें.
apply()
को कॉल करके, आखिरी प्रॉम्प्ट बनाया जाता है. यह की/वैल्यू पेयर का एक मैप लेता है, जो प्लेसहोल्डर का नाम और उसे बदलने के लिए स्ट्रिंग वैल्यू दिखाता है.
आखिर में, prompt.toUserMessage()
निर्देश के साथ उस प्रॉम्प्ट से उपयोगकर्ता मैसेज बनाकर, Gemini मॉडल के generate()
तरीके को कॉल किया जाता है.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.TemplatePrompt
आपको जनरेट किया गया आउटपुट कुछ ऐसा दिखेगा:
**Strawberry Shortcake** Ingredients: * 1 pint strawberries, hulled and sliced * 1/2 cup sugar * 1/4 cup cornstarch * 1/4 cup water * 1 tablespoon lemon juice * 1/2 cup heavy cream, whipped * 1/4 cup confectioners' sugar * 1/4 teaspoon vanilla extract * 6 graham cracker squares, crushed Instructions: 1. In a medium saucepan, combine the strawberries, sugar, cornstarch, water, and lemon juice. Bring to a boil over medium heat, stirring constantly. Reduce heat and simmer for 5 minutes, or until the sauce has thickened. 2. Remove from heat and let cool slightly. 3. In a large bowl, combine the whipped cream, confectioners' sugar, and vanilla extract. Beat until soft peaks form. 4. To assemble the shortcakes, place a graham cracker square on each of 6 dessert plates. Top with a scoop of whipped cream, then a spoonful of strawberry sauce. Repeat layers, ending with a graham cracker square. 5. Serve immediately. **Tips:** * For a more elegant presentation, you can use fresh strawberries instead of sliced strawberries. * If you don't have time to make your own whipped cream, you can use store-bought whipped cream.
मैप में dish
और ingredients
की वैल्यू बदलें. साथ ही, तापमान, topK
, और tokP
में बदलाव करें और कोड को फिर से चलाएं. इससे, आपको एलएलएम पर इन पैरामीटर में बदलाव करने का असर देखने में मदद मिलेगी.
प्रॉम्प्ट टेंप्लेट, एलएलएम कॉल के लिए फिर से इस्तेमाल किए जा सकने वाले और पैरामीटर के हिसाब से निर्देश पाने का एक अच्छा तरीका है. उपयोगकर्ताओं की दी गई अलग-अलग वैल्यू के लिए, डेटा पास किया जा सकता है और प्रॉम्प्ट को पसंद के मुताबिक बनाया जा सकता है.
9. उदाहरण के साथ डाले गए प्रॉम्प्ट की मदद से टेक्स्ट का क्लासिफ़िकेशन
एलएलएम, टेक्स्ट को अलग-अलग कैटगरी में बांटने में काफ़ी अच्छे होते हैं. टेक्स्ट और उनसे जुड़ी कैटगरी के कुछ उदाहरण देकर, एलएलएम को इस काम में मदद की जा सकती है. इस तरीके को अक्सर कुछ शॉट के लिए प्रॉम्प्ट कहा जाता है.
टेक्स्ट को किसी खास कैटगरी में बांटने के लिए, app/src/main/java/gemini/workshop
डायरेक्ट्री में TextClassification.java
खोलें. जैसे, सेंटिमेंट विश्लेषण.
package gemini.workshop;
import com.google.cloud.vertexai.api.Schema;
import com.google.cloud.vertexai.api.Type;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import java.util.List;
public class TextClassification {
enum Sentiment { POSITIVE, NEUTRAL, NEGATIVE }
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(10)
.maxRetries(3)
.responseSchema(Schema.newBuilder()
.setType(Type.STRING)
.addAllEnum(List.of("POSITIVE", "NEUTRAL", "NEGATIVE"))
.build())
.build();
interface SentimentAnalysis {
@SystemMessage("""
Analyze the sentiment of the text below.
Respond only with one word to describe the sentiment.
""")
Sentiment analyze(String text);
}
MessageWindowChatMemory memory = MessageWindowChatMemory.withMaxMessages(10);
memory.add(UserMessage.from("This is fantastic news!"));
memory.add(AiMessage.from(Sentiment.POSITIVE.name()));
memory.add(UserMessage.from("Pi is roughly equal to 3.14"));
memory.add(AiMessage.from(Sentiment.NEUTRAL.name()));
memory.add(UserMessage.from("I really disliked the pizza. Who would use pineapples as a pizza topping?"));
memory.add(AiMessage.from(Sentiment.NEGATIVE.name()));
SentimentAnalysis sentimentAnalysis =
AiServices.builder(SentimentAnalysis.class)
.chatLanguageModel(model)
.chatMemory(memory)
.build();
System.out.println(sentimentAnalysis.analyze("I love strawberries!"));
}
}
Sentiment
एनम में, सेंटीमेंट की अलग-अलग वैल्यू की सूची होती है: नेगेटिव, न्यूट्रल या पॉज़िटिव.
main()
तरीके में, Gemini Chat मॉडल को हमेशा की तरह बनाया जाता है. हालांकि, इसमें आउटपुट के लिए ज़्यादा से ज़्यादा टोकन का नंबर छोटा रखा जाता है, क्योंकि आपको सिर्फ़ छोटा जवाब चाहिए: टेक्स्ट POSITIVE
, NEGATIVE
या NEUTRAL
है. मॉडल को सिर्फ़ उन वैल्यू को दिखाने के लिए, डेटा निकालने वाले सेक्शन में मिले स्ट्रक्चर्ड आउटपुट के सहायता फ़ंक्शन का इस्तेमाल किया जा सकता है. इसलिए, responseSchema()
तरीके का इस्तेमाल किया जाता है. इस बार, स्कीमा की परिभाषा का अनुमान लगाने के लिए, SchemaHelper
के आसान तरीके का इस्तेमाल नहीं किया जा रहा है. इसके बजाय, स्कीमा की परिभाषा कैसी दिखती है, यह समझने के लिए Schema
बिल्डर का इस्तेमाल किया जाएगा.
मॉडल कॉन्फ़िगर होने के बाद, एक SentimentAnalysis
इंटरफ़ेस बनाया जाता है. LangChain4j का AiServices
, LLM का इस्तेमाल करके आपके लिए इसे लागू करेगा. इस इंटरफ़ेस में एक तरीका शामिल है: analyze()
. यह इनपुट के तौर पर टेक्स्ट लेता है और Sentiment
की वैल्यू दिखाता है. इसलिए, सिर्फ़ उस ऑब्जेक्ट में बदलाव किया जा रहा है जिसे स्ट्रोंग टाइप किया गया है. यह ऑब्जेक्ट, पहचाने गए सेंटीमेंट की क्लास को दिखाता है.
इसके बाद, मॉडल को कैटगरी तय करने के लिए "कुछ उदाहरण" देने के मकसद से, चैट मेमोरी बनाई जाती है. इसमें उपयोगकर्ता के मैसेज और एआई के जवाबों के जोड़े शामिल किए जाते हैं. इनसे टेक्स्ट और उससे जुड़ी भावना के बारे में पता चलता है.
AiServices.builder()
तरीके का इस्तेमाल करके, सभी चीज़ों को एक साथ जोड़ते हैं. इसके लिए, SentimentAnalysis
इंटरफ़ेस, इस्तेमाल किए जाने वाले मॉडल, और चैट मेमोरी को फ़्यू-शॉट के उदाहरणों के साथ पास करें. आखिर में, विश्लेषण के लिए टेक्स्ट के साथ analyze()
तरीके को कॉल करें.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.TextClassification
आपको एक शब्द दिखेगा:
POSITIVE
ऐसा लगता है कि स्ट्रॉबेरी पसंद करना एक सकारात्मक भावना है!
10. रीट्रिवल ऑगमेंटेड जनरेशन
एलएलएम को बहुत ज़्यादा टेक्स्ट की मदद से ट्रेन किया जाता है. हालांकि, एआई सिर्फ़ उस जानकारी के बारे में जानता है जो उसे ट्रेनिंग के दौरान मिली है. अगर मॉडल की ट्रेनिंग की कट-ऑफ़ तारीख के बाद कोई नई जानकारी रिलीज़ की जाती है, तो वह जानकारी मॉडल के लिए उपलब्ध नहीं होगी. इसलिए, मॉडल उस जानकारी के बारे में सवालों के जवाब नहीं दे पाएगा जिसे उसने नहीं देखा है.
इसलिए, इस सेक्शन में रिट्रीवल ऑगमेंटेड जनरेशन (आरएजी) जैसे तरीकों के बारे में बताया गया है. इनसे एलएलएम को ज़्यादा जानकारी मिलती है, ताकि वह अपने उपयोगकर्ताओं के अनुरोधों को पूरा कर सके. साथ ही, ज़्यादा अप-टू-डेट जानकारी या ट्रेनिंग के समय ऐक्सेस नहीं की जा सकने वाली निजी जानकारी के साथ जवाब दे सके.
आइए, बातचीत पर वापस आते हैं. इस बार, आपके पास अपने दस्तावेज़ों के बारे में सवाल पूछने का विकल्प होगा. आपको एक ऐसा चैटबॉट बनाना होगा जो आपके दस्तावेज़ों को छोटे-छोटे हिस्सों ("चंक") में बांटकर, डेटाबेस से ज़रूरी जानकारी हासिल कर सके. मॉडल इस जानकारी का इस्तेमाल, अपने जवाब देने के लिए करेगा. इसके लिए, वह सिर्फ़ ट्रेनिंग में शामिल जानकारी पर निर्भर नहीं रहेगा.
आरएजी में दो चरण होते हैं:
- डेटा डालने का चरण — दस्तावेज़ों को मेमोरी में लोड किया जाता है और छोटे-छोटे हिस्सों में बांटा जाता है. साथ ही, वेक्टर एम्बेडिंग (चंक का हाई मल्टीडाइमेंशनल वेक्टर) का हिसाब लगाया जाता है और उसे वेक्टर डेटाबेस में सेव किया जाता है. यह डेटाबेस, सेमैनटिक सर्च करने में सक्षम होता है. आम तौर पर, दस्तावेज़ों को डालने की यह प्रोसेस एक बार ही की जाती है. ऐसा तब किया जाता है, जब दस्तावेज़ों के कॉर्पस में नए दस्तावेज़ जोड़ने होते हैं.
- क्वेरी वाला चरण — उपयोगकर्ता अब दस्तावेज़ों के बारे में सवाल पूछ सकते हैं. सवाल को भी वेक्टर में बदल दिया जाएगा और डेटाबेस में मौजूद अन्य सभी वेक्टर के साथ इसकी तुलना की जाएगी. सबसे मिलते-जुलते वैक्टर, आम तौर पर एक जैसे होते हैं और इन्हें वैक्टर डेटाबेस से दिखाया जाता है. इसके बाद, एलएलएम को बातचीत का कॉन्टेक्स्ट और टेक्स्ट के ऐसे हिस्से दिए जाते हैं जो डेटाबेस से मिले वैक्टर से मेल खाते हैं. साथ ही, उन हिस्सों को देखकर जवाब देने के लिए कहा जाता है.
दस्तावेज़ तैयार करना
इस नए उदाहरण में, आपको एक काल्पनिक कार मॉडल और कार बनाने वाली कंपनी के बारे में सवाल पूछने होंगे: Cymbal Starlight कार! इसका मतलब है कि किसी काल्पनिक कार के बारे में दस्तावेज़, मॉडल की जानकारी का हिस्सा नहीं होना चाहिए. इसलिए, अगर Gemini इस कार के बारे में सही जवाब दे पाता है, तो इसका मतलब है कि आरएजी (रेड, ऐंबर, ग्रीन) का तरीका काम कर रहा है: यह आपके दस्तावेज़ में खोज कर सकता है.
चैटबॉट लागू करना
आइए, दो चरणों वाले तरीके को बनाने का तरीका जानें: पहला, दस्तावेज़ को डालना और दूसरा, क्वेरी का समय (इसे "वापस पाने का चरण" भी कहा जाता है), जब उपयोगकर्ता दस्तावेज़ के बारे में सवाल पूछते हैं.
इस उदाहरण में, दोनों फ़ेज़ एक ही क्लास में लागू किए गए हैं. आम तौर पर, आपके पास एक ऐसा ऐप्लिकेशन होता है जो डेटा डालने की प्रोसेस को मैनेज करता है और दूसरा ऐप्लिकेशन, आपके उपयोगकर्ताओं को चैटबॉट इंटरफ़ेस उपलब्ध कराता है.
साथ ही, इस उदाहरण में हम इन-मेमोरी वेक्टर डेटाबेस का इस्तेमाल करेंगे. असल प्रोडक्शन परिदृश्य में, डेटा डालने और क्वेरी करने के चरणों को दो अलग-अलग ऐप्लिकेशन में अलग किया जाएगा. साथ ही, वेक्टर को स्टैंडअलोन डेटाबेस में सेव किया जाएगा.
दस्तावेज़ डालना
दस्तावेज़ डालने के चरण का पहला चरण, हमारी काल्पनिक कार के बारे में PDF फ़ाइल ढूंढना और उसे पढ़ने के लिए PdfParser
तैयार करना है:
URL url = new URI("https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/grounding/vertexai-search/cymbal-starlight-2024.pdf").toURL();
ApachePdfBoxDocumentParser pdfParser = new ApachePdfBoxDocumentParser();
Document document = pdfParser.parse(url.openStream());
सबसे पहले, चैट की सामान्य भाषा का मॉडल बनाने के बजाय, एम्बेड किए गए मॉडल का एक इंस्टेंस बनाया जाता है. यह एक खास मॉडल है, जिसकी भूमिका टेक्स्ट के हिस्सों (शब्दों, वाक्यों या पैराग्राफ़) के वेक्टर वर्शन बनाना है. यह टेक्स्ट के जवाबों के बजाय, फ़्लोटिंग पॉइंट नंबर के वैक्टर दिखाता है.
VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
.endpoint(System.getenv("LOCATION") + "-aiplatform.googleapis.com:443")
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.publisher("google")
.modelName("text-embedding-005")
.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);
वेक्टर एम्बेडमेंट को सेव करने के लिए, InMemoryEmbeddingStore
का एक इंस्टेंस बनाया जाता है. यह इंस्टेंस, मेमोरी में मौजूद वेक्टर डेटाबेस होता है.
DocumentSplitters
क्लास की मदद से, दस्तावेज़ को अलग-अलग हिस्सों में बांटा गया है. यह PDF फ़ाइल के टेक्स्ट को 500 वर्णों के स्निपेट में बांटेगा. साथ ही, हर स्निपेट में 100 वर्ण ओवरलैप होंगे. ऐसा इसलिए किया जाता है, ताकि शब्दों या वाक्यों को काट-छांट करके न दिखाया जाए.
स्टोर इंजेस्टर, वेक्टर का हिसाब लगाने के लिए दस्तावेज़ स्प्लिटर, एम्बेडिंग मॉडल, और इन-मेमोरी वेक्टर डेटाबेस को लिंक करता है. इसके बाद, ingest()
तरीका डेटा डालने की प्रोसेस को पूरा करेगा.
अब पहला चरण पूरा हो गया है. दस्तावेज़ को टेक्स्ट के ऐसे हिस्सों में बदल दिया गया है जिनमें वेक्टर एम्बेडिंग शामिल हैं. साथ ही, इन्हें वेक्टर डेटाबेस में सेव कर दिया गया है.
सवाल पूछना
सवाल पूछने का समय आ गया है! बातचीत शुरू करने के लिए चैट मॉडल बनाएं:
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(1000)
.build();
आपको embeddingStore
वैरिएबल में मौजूद वेक्टर डेटाबेस को एम्बेडिंग मॉडल से लिंक करने के लिए, एक 'रीट्रिवर क्लास' भी चाहिए. इसका काम, उपयोगकर्ता की क्वेरी के लिए वेक्टर एम्बेडिंग का हिसाब लगाकर, वेक्टर डेटाबेस में मिलते-जुलते वेक्टर ढूंढना है:
EmbeddingStoreContentRetriever retriever =
new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);
कार के विशेषज्ञ की तरह काम करने वाला इंटरफ़ेस बनाएं. यह ऐसा इंटरफ़ेस है जिसे AiServices
क्लास लागू करेगी, ताकि आप मॉडल के साथ इंटरैक्ट कर सकें:
interface CarExpert {
Result<String> ask(String question);
}
CarExpert
इंटरफ़ेस, LangChain4j की Result
क्लास में रैप की गई स्ट्रिंग रिस्पॉन्स दिखाता है. इस रैपर का इस्तेमाल क्यों करना चाहिए? ऐसा इसलिए, क्योंकि इससे आपको न सिर्फ़ जवाब मिलेगा, बल्कि डेटाबेस के उन हिस्सों की जांच करने में भी मदद मिलेगी जिन्हें कॉन्टेंट रीट्रिवर ने वापस किया है. इस तरह, उन दस्तावेज़ों के सोर्स दिखाए जा सकते हैं जिनका इस्तेमाल, उपयोगकर्ता को आखिरी जवाब देने के लिए किया जाता है.
अब आपके पास एआई की नई सेवा कॉन्फ़िगर करने का विकल्प है:
CarExpert expert = AiServices.builder(CarExpert.class)
.chatLanguageModel(model)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.contentRetriever(retriever)
.build();
यह सेवा इन चीज़ों को एक साथ जोड़ती है:
- चैट की भाषा का वह मॉडल जिसे आपने पहले कॉन्फ़िगर किया था.
- बातचीत का ट्रैक रखने के लिए, चैट मेमोरी.
- retriever, वेक्टर एम्बेडिंग क्वेरी की तुलना डेटाबेस में मौजूद वेक्टर से करता है.
.retrievalAugmentor(DefaultRetrievalAugmentor.builder()
.contentInjector(DefaultContentInjector.builder()
.promptTemplate(PromptTemplate.from("""
You are an expert in car automotive, and you answer concisely.
Here is the question: {{userMessage}}
Answer using the following information:
{{contents}}
the following information:
{{contents}}
"""))
.build())
.contentRetriever(retriever)
.build())
अब आपके पास सवाल पूछने का विकल्प है!
List.of(
"What is the cargo capacity of Cymbal Starlight?",
"What's the emergency roadside assistance phone number?",
"Are there some special kits available on that car?"
).forEach(query -> {
Result<String> response = expert.ask(query);
System.out.printf("%n=== %s === %n%n %s %n%n", query, response.content());
System.out.println("SOURCE: " + response.sources().getFirst().textSegment().text());
});
पूरा सोर्स कोड, app/src/main/java/gemini/workshop
डायरेक्ट्री में RAG.java
में मौजूद है.
सैंपल चलाने के लिए:
./gradlew -q run -DjavaMainClass=gemini.workshop.RAG
आउटपुट में, आपको अपने सवालों के जवाब दिखेंगे:
=== What is the cargo capacity of Cymbal Starlight? === The Cymbal Starlight 2024 has a cargo capacity of 13.5 cubic feet. SOURCE: Cargo The Cymbal Starlight 2024 has a cargo capacity of 13.5 cubic feet. The cargo area is located in the trunk of the vehicle. To access the cargo area, open the trunk lid using the trunk release lever located in the driver's footwell. When loading cargo into the trunk, be sure to distribute the weight evenly. Do not overload the trunk, as this could affect the vehicle's handling and stability. Luggage === What's the emergency roadside assistance phone number? === The emergency roadside assistance phone number is 1-800-555-1212. SOURCE: Chapter 18: Emergencies Roadside Assistance If you experience a roadside emergency, such as a flat tire or a dead battery, you can call roadside assistance for help. Roadside assistance is available 24 hours a day, 7 days a week. To call roadside assistance, dial the following number: 1-800-555-1212 When you call roadside assistance, be prepared to provide the following information: Your name and contact information Your vehicle's make, model, and year Your vehicle's location === Are there some special kits available on that car? === Yes, the Cymbal Starlight comes with a tire repair kit. SOURCE: Lane keeping assist: This feature helps to keep you in your lane by gently steering the vehicle back into the lane if you start to drift. Adaptive cruise control: This feature automatically adjusts your speed to maintain a safe following distance from the vehicle in front of you. Forward collision warning: This feature warns you if you are approaching another vehicle too quickly. Automatic emergency braking: This feature can automatically apply the brakes to avoid a collision.
11. फ़ंक्शन कॉल करना
कुछ मामलों में, आपको एलएलएम को बाहरी सिस्टम का ऐक्सेस देना पड़ता है. जैसे, जानकारी हासिल करने या कोई कार्रवाई करने वाला रिमोट वेब एपीआई या किसी तरह का हिसाब लगाने वाली सेवाएं. उदाहरण के लिए:
रिमोट वेब एपीआई:
- ग्राहक के ऑर्डर ट्रैक और अपडेट करें.
- समस्या ट्रैकर में कोई टिकट ढूंढें या बनाएं.
- स्टॉक कोट या IoT सेंसर से मिले मेज़रमेंट जैसे रीयल टाइम डेटा को फ़ेच करें.
- ईमेल भेजें.
कैलकुलेशन टूल:
- गणित के ज़्यादा बेहतर सवालों के लिए कैलकुलेटर.
- जब एलएलएम को तर्क के लॉजिक की ज़रूरत होती है, तब कोड चलाने के लिए कोड का विश्लेषण.
- नैचुरल लैंग्वेज के अनुरोधों को SQL क्वेरी में बदलना, ताकि एलएलएम किसी डेटाबेस से क्वेरी कर सके.
फ़ंक्शन कॉलिंग (इसे कभी-कभी टूल या टूल का इस्तेमाल भी कहा जाता है) मॉडल की वह क्षमता है जिससे वह अपनी ओर से एक या उससे ज़्यादा फ़ंक्शन कॉल करने का अनुरोध कर सकता है. इससे वह उपयोगकर्ता के प्रॉम्प्ट का जवाब, नए डेटा के साथ सही तरीके से दे सकता है.
उपयोगकर्ता के किसी खास प्रॉम्प्ट और उस संदर्भ से जुड़े मौजूदा फ़ंक्शन की जानकारी के आधार पर, एलएलएम किसी फ़ंक्शन कॉल के अनुरोध के साथ जवाब दे सकता है. इसके बाद, एलएलएम को इंटिग्रेट करने वाला ऐप्लिकेशन, अपनी ओर से फ़ंक्शन को कॉल कर सकता है. इसके बाद, एलएलएम को जवाब देकर, उसे वापस भेज सकता है. इसके बाद, एलएलएम टेक्स्ट के ज़रिए जवाब देकर, उसका विश्लेषण करता है.
फ़ंक्शन कॉल करने के चार चरण
फ़ंक्शन को कॉल करने के उदाहरण पर नज़र डालें: मौसम के पूर्वानुमान की जानकारी पाना.
अगर Gemini या किसी अन्य एलएलएम से पेरिस के मौसम के बारे में पूछा जाता है, तो वह जवाब में कहेगा कि उसके पास मौसम के मौजूदा पूर्वानुमान की कोई जानकारी नहीं है. अगर आपको एलएलएम को मौसम के डेटा का रीयल-टाइम ऐक्सेस देना है, तो आपको कुछ फ़ंक्शन तय करने होंगे. इन फ़ंक्शन का इस्तेमाल करने का अनुरोध किया जा सकता है.
नीचे दिया गया डायग्राम देखें:
1️⃣ सबसे पहले, कोई उपयोगकर्ता पेरिस के मौसम के बारे में पूछता है. LangChain4j का इस्तेमाल करने वाले चैटबॉट ऐप्लिकेशन को पता होता है कि उसके पास एक या उससे ज़्यादा फ़ंक्शन हैं, जिनसे एलएलएम को क्वेरी को पूरा करने में मदद मिलती है. चैटबॉट, शुरुआती प्रॉम्प्ट के साथ-साथ उन फ़ंक्शन की सूची भी भेजता है जिन्हें कॉल किया जा सकता है. यहां getWeather()
नाम का एक फ़ंक्शन है, जो जगह के लिए स्ट्रिंग पैरामीटर लेता है.
एलएलएम को मौसम के पूर्वानुमान की जानकारी नहीं होती. इसलिए, वह टेक्स्ट के ज़रिए जवाब देने के बजाय, फ़ंक्शन को लागू करने का अनुरोध भेजता है. चैटबॉट को जगह की जानकारी के पैरामीटर के तौर पर "Paris"
का इस्तेमाल करके, getWeather()
फ़ंक्शन को कॉल करना होगा.
2️⃣ चैटबॉट, एलएलएम की ओर से उस फ़ंक्शन को लागू करता है और फ़ंक्शन का रिस्पॉन्स पाता है. यहां, हम मानते हैं कि जवाब {"forecast": "sunny"}
है.
3️⃣ चैटबॉट ऐप्लिकेशन, JSON रिस्पॉन्स को एलएलएम को वापस भेजता है.
4️⃣ एलएलएम, JSON रिस्पॉन्स को देखता है और उस जानकारी का विश्लेषण करता है. आखिर में, वह इस टेक्स्ट के साथ जवाब देता है कि पेरिस में धूप खिली हुई है.
हर चरण को कोड के तौर पर
सबसे पहले, आपको Gemini मॉडल को हमेशा की तरह कॉन्फ़िगर करना होगा:
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(100)
.build();
आपने टूल की खास जानकारी दी है, जिसमें उस फ़ंक्शन के बारे में बताया गया है जिसे कॉल किया जा सकता है:
ToolSpecification weatherToolSpec = ToolSpecification.builder()
.name("getWeather")
.description("Get the weather forecast for a given location or city")
.parameters(JsonObjectSchema.builder()
.addStringProperty(
"location",
"the location or city to get the weather forecast for")
.build())
.build();
फ़ंक्शन का नाम, पैरामीटर का नाम, और टाइप तय किया गया है. हालांकि, ध्यान दें कि फ़ंक्शन और पैरामीटर, दोनों के बारे में जानकारी दी गई है. ब्यौरे काफ़ी अहम होते हैं. इनसे एलएलएम को यह समझने में मदद मिलती है कि कोई फ़ंक्शन क्या कर सकता है. साथ ही, इससे यह भी तय किया जा सकता है कि बातचीत के संदर्भ में इस फ़ंक्शन को इस्तेमाल करना है या नहीं.
पहला चरण शुरू करने के लिए, पेरिस के मौसम के बारे में शुरुआती सवाल भेजें:
List<ChatMessage> allMessages = new ArrayList<>();
// 1) Ask the question about the weather
UserMessage weatherQuestion = UserMessage.from("What is the weather in Paris?");
allMessages.add(weatherQuestion);
दूसरे चरण में, हम उस टूल को पास करते हैं जिसका इस्तेमाल मॉडल को करना है. इसके बाद, मॉडल टूल को लागू करने का अनुरोध करता है:
// 2) The model replies with a function call request
Response<AiMessage> messageResponse = model.generate(allMessages, weatherToolSpec);
ToolExecutionRequest toolExecutionRequest = messageResponse.content().toolExecutionRequests().getFirst();
System.out.println("Tool execution request: " + toolExecutionRequest);
allMessages.add(messageResponse.content());
तीसरा चरण. इस समय, हमें पता है कि एलएलएम को कौनसा फ़ंक्शन कॉल करना है. कोड में, हम किसी बाहरी एपीआई को रीयल कॉल नहीं कर रहे हैं. हम सीधे तौर पर मौसम के अनुमान का अनुमानित डेटा दिखाते हैं:
// 3) We send back the result of the function call
ToolExecutionResultMessage toolExecResMsg = ToolExecutionResultMessage.from(toolExecutionRequest,
"{\"location\":\"Paris\",\"forecast\":\"sunny\", \"temperature\": 20}");
allMessages.add(toolExecResMsg);
चौथे चरण में, एलएलएम फ़ंक्शन के लागू होने के नतीजे के बारे में जानता है. इसके बाद, वह टेक्स्ट के तौर पर जवाब दे सकता है:
// 4) The model answers with a sentence describing the weather
Response<AiMessage> weatherResponse = model.generate(allMessages);
System.out.println("Answer: " + weatherResponse.content().text());
आउटपुट:
Tool execution request: ToolExecutionRequest { id = null, name = "getWeatherForecast", arguments = "{"location":"Paris"}" }
Answer: The weather in Paris is sunny with a temperature of 20 degrees Celsius.
ऊपर दिए गए आउटपुट में, टूल को चलाने के अनुरोध के साथ-साथ जवाब भी देखा जा सकता है.
पूरा सोर्स कोड, app/src/main/java/gemini/workshop
डायरेक्ट्री में FunctionCalling.java
में मौजूद है:
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.FunctionCalling
आपको इससे मिलता-जुलता आउटपुट दिखेगा:
Tool execution request: ToolExecutionRequest { id = null, name = "getWeatherForecast", arguments = "{"location":"Paris"}" }
Answer: The weather in Paris is sunny with a temperature of 20 degrees Celsius.
12. LangChain4j, फ़ंक्शन कॉल को मैनेज करता है
पिछले चरण में, आपने देखा कि सामान्य टेक्स्ट वाले सवाल/जवाब और फ़ंक्शन के अनुरोध/जवाब के इंटरैक्शन को कैसे इंटरलीव किया जाता है. साथ ही, आपने किसी असल फ़ंक्शन को कॉल किए बिना, सीधे तौर पर अनुरोध किए गए फ़ंक्शन का जवाब दिया.
हालांकि, LangChain4j एक बेहतर लेवल का एब्स्ट्रैक्शन भी उपलब्ध कराता है. यह सामान्य तरीके से बातचीत को मैनेज करने के साथ-साथ, आपके लिए फ़ंक्शन कॉल को भी साफ़ तौर पर मैनेज कर सकता है.
सिंगल फ़ंक्शन कॉल
आइए, FunctionCallingAssistant.java
के हर हिस्से पर एक नज़र डालते हैं.
सबसे पहले, एक ऐसा रिकॉर्ड बनाएं जो फ़ंक्शन के रिस्पॉन्स डेटा स्ट्रक्चर को दिखाएगा:
record WeatherForecast(String location, String forecast, int temperature) {}
जवाब में जगह, मौसम के पूर्वानुमान, और तापमान की जानकारी शामिल होती है.
इसके बाद, एक क्लास बनाएं जिसमें वह असल फ़ंक्शन शामिल हो जिसे आपको मॉडल के लिए उपलब्ध कराना है:
static class WeatherForecastService {
@Tool("Get the weather forecast for a location")
WeatherForecast getForecast(@P("Location to get the forecast for") String location) {
if (location.equals("Paris")) {
return new WeatherForecast("Paris", "Sunny", 20);
} else if (location.equals("London")) {
return new WeatherForecast("London", "Rainy", 15);
} else {
return new WeatherForecast("Unknown", "Unknown", 0);
}
}
}
ध्यान दें कि इस क्लास में एक फ़ंक्शन है, लेकिन इसे @Tool
एनोटेशन के साथ एनोटेट किया गया है. यह एनोटेशन, उस फ़ंक्शन के ब्यौरे से जुड़ा है जिसे मॉडल कॉल करने का अनुरोध कर सकता है.
फ़ंक्शन के पैरामीटर (यहां एक) को भी एनोटेट किया गया है, लेकिन इस छोटे @P
एनोटेशन के साथ, जो पैरामीटर के बारे में जानकारी भी देता है. ज़्यादा जटिल स्थितियों के लिए, मॉडल में जितने चाहें उतने फ़ंक्शन जोड़े जा सकते हैं.
इस क्लास में, कुछ तैयार जवाब दिखाए जाते हैं. हालांकि, अगर आपको किसी बाहरी मौसम की जानकारी देने वाली सेवा को कॉल करना है, तो इस तरीके के मुख्य हिस्से में जाकर, उस सेवा को कॉल किया जा सकता है.
जैसा कि हमने पिछले तरीके में ToolSpecification
बनाते समय देखा था, यह दस्तावेज़ में बताना ज़रूरी है कि कोई फ़ंक्शन क्या करता है. साथ ही, यह भी बताना ज़रूरी है कि पैरामीटर किससे जुड़े हैं. इससे मॉडल को यह समझने में मदद मिलती है कि इस फ़ंक्शन का इस्तेमाल कब और कैसे किया जा सकता है.
इसके बाद, LangChain4j की मदद से, मॉडल के साथ इंटरैक्ट करने के लिए इस्तेमाल किए जाने वाले कॉन्ट्रैक्ट से जुड़ा इंटरफ़ेस दिया जा सकता है. यहां एक आसान इंटरफ़ेस है, जो उपयोगकर्ता के मैसेज की जानकारी देने वाली स्ट्रिंग को लेता है और मॉडल के जवाब से जुड़ी स्ट्रिंग दिखाता है:
interface WeatherAssistant {
String chat(String userMessage);
}
अगर आपको ज़्यादा बेहतर तरीके से काम करना है, तो ज़्यादा जटिल हस्ताक्षर का इस्तेमाल भी किया जा सकता है. जैसे, LangChain4j के UserMessage
(उपयोगकर्ता के मैसेज के लिए) या AiMessage
(मॉडल के जवाब के लिए) या TokenStream
. इन जटिल ऑब्जेक्ट में, ज़्यादा जानकारी भी होती है. जैसे, इस्तेमाल किए गए टोकन की संख्या वगैरह. हालांकि, आसानी के लिए, हम इनपुट में सिर्फ़ स्ट्रिंग और आउटपुट में स्ट्रिंग का इस्तेमाल करेंगे.
आखिर में, main()
वाले तरीके के बारे में बताते हैं, जो सभी चीज़ों को एक साथ जोड़ता है:
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-pro-002")
.build();
WeatherForecastService weatherForecastService = new WeatherForecastService();
WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
.chatLanguageModel(model)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.tools(weatherForecastService)
.build();
System.out.println(assistant.chat("What is the weather in Paris?"));
}
हमेशा की तरह, Gemini Chat मॉडल को कॉन्फ़िगर करें. इसके बाद, मौसम के पूर्वानुमान की सेवा को इंस्टैंशिएट करें. इसमें वह "फ़ंक्शन" शामिल होता है जिसे मॉडल हमें कॉल करने का अनुरोध करेगा.
अब, चैट मॉडल, चैट मेमोरी, और टूल (जैसे, मौसम के पूर्वानुमान की सेवा और उसका फ़ंक्शन) को बांधने के लिए, AiServices
क्लास का फिर से इस्तेमाल किया जाता है. AiServices
एक ऐसा ऑब्जेक्ट दिखाता है जो आपके तय किए गए WeatherAssistant
इंटरफ़ेस को लागू करता है. अब सिर्फ़ उस असिस्टेंट के chat()
तरीके को कॉल करना बाकी है. इसे चालू करने पर, आपको सिर्फ़ टेक्स्ट के जवाब दिखेंगे. हालांकि, फ़ंक्शन कॉल के अनुरोध और फ़ंक्शन कॉल के जवाब, डेवलपर को नहीं दिखेंगे. साथ ही, उन अनुरोधों को अपने-आप और साफ़ तौर पर मैनेज किया जाएगा. अगर Gemini को लगता है कि किसी फ़ंक्शन को कॉल किया जाना चाहिए, तो वह फ़ंक्शन कॉल के अनुरोध के साथ जवाब देगा. इसके बाद, LangChain4j आपकी ओर से स्थानीय फ़ंक्शन को कॉल करेगा.
सैंपल चलाने के लिए:
./gradlew run -q -DjavaMainClass=gemini.workshop.FunctionCallingAssistant
आपको इससे मिलता-जुलता आउटपुट दिखेगा:
OK. The weather in Paris is sunny with a temperature of 20 degrees.
यह एक फ़ंक्शन का उदाहरण था.
एक से ज़्यादा फ़ंक्शन कॉल
आपके पास एक से ज़्यादा फ़ंक्शन भी हो सकते हैं. साथ ही, LangChain4j को अपनी ओर से एक से ज़्यादा फ़ंक्शन कॉल मैनेज करने की अनुमति दी जा सकती है. एक से ज़्यादा फ़ंक्शन के उदाहरण के लिए, MultiFunctionCallingAssistant.java
देखें.
इसमें मुद्रा बदलने की सुविधा है:
@Tool("Convert amounts between two currencies")
double convertCurrency(
@P("Currency to convert from") String fromCurrency,
@P("Currency to convert to") String toCurrency,
@P("Amount to convert") double amount) {
double result = amount;
if (fromCurrency.equals("USD") && toCurrency.equals("EUR")) {
result = amount * 0.93;
} else if (fromCurrency.equals("USD") && toCurrency.equals("GBP")) {
result = amount * 0.79;
}
System.out.println(
"convertCurrency(fromCurrency = " + fromCurrency +
", toCurrency = " + toCurrency +
", amount = " + amount + ") == " + result);
return result;
}
स्टॉक की वैल्यू पाने के लिए एक और फ़ंक्शन:
@Tool("Get the current value of a stock in US dollars")
double getStockPrice(@P("Stock symbol") String symbol) {
double result = 170.0 + 10 * new Random().nextDouble();
System.out.println("getStockPrice(symbol = " + symbol + ") == " + result);
return result;
}
किसी दी गई रकम पर प्रतिशत लागू करने के लिए, एक और फ़ंक्शन:
@Tool("Apply a percentage to a given amount")
double applyPercentage(@P("Initial amount") double amount, @P("Percentage between 0-100 to apply") double percentage) {
double result = amount * (percentage / 100);
System.out.println("applyPercentage(amount = " + amount + ", percentage = " + percentage + ") == " + result);
return result;
}
इसके बाद, इन सभी फ़ंक्शन और MultiTools क्लास को जोड़कर, "USD से EUR में बदले गए AAPL स्टॉक की कीमत का 10% क्या है?" जैसे सवाल पूछे जा सकते हैं.
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-1.5-flash-002")
.maxOutputTokens(100)
.build();
MultiTools multiTools = new MultiTools();
MultiToolsAssistant assistant = AiServices.builder(MultiToolsAssistant.class)
.chatLanguageModel(model)
.chatMemory(withMaxMessages(10))
.tools(multiTools)
.build();
System.out.println(assistant.chat(
"What is 10% of the AAPL stock price converted from USD to EUR?"));
}
इसे इस तरह चलाएं:
./gradlew run -q -DjavaMainClass=gemini.workshop.MultiFunctionCallingAssistant
आपको कई फ़ंक्शन दिखेंगे, जिन्हें इन नामों से बुलाया जाता है:
getStockPrice(symbol = AAPL) == 172.8022224055534 convertCurrency(fromCurrency = USD, toCurrency = EUR, amount = 172.8022224055534) == 160.70606683716468 applyPercentage(amount = 160.70606683716468, percentage = 10.0) == 16.07060668371647 10% of the AAPL stock price converted from USD to EUR is 16.07060668371647 EUR.
एजेंट के लिए
फ़ंक्शन कॉलिंग, Gemini जैसे बड़े लैंग्वेज मॉडल के लिए एक बेहतरीन एक्सटेंशन मैकेनिज्म है. इसकी मदद से, हम ज़्यादा जटिल सिस्टम बना पाते हैं. इन्हें अक्सर "एजेंट" या "एआई असिस्टेंट" कहा जाता है. ये एजेंट, बाहरी एपीआई और उन सेवाओं के ज़रिए बाहरी दुनिया के साथ इंटरैक्ट कर सकते हैं जिनका बाहरी एनवायरमेंट पर असर पड़ सकता है. जैसे, ईमेल भेजना, टिकट बनाना वगैरह
ऐसे असरदार एजेंट बनाते समय, आपको ज़िम्मेदारी के साथ काम करना चाहिए. अपने-आप होने वाली कार्रवाइयां करने से पहले, आपको मानवीय हस्तक्षेप पर विचार करना चाहिए. बाहरी दुनिया के साथ इंटरैक्ट करने वाले एलएलएम (लंबी अवधि के लिए याद रखने वाले मशीन लर्निंग मॉडल) वाले एजेंट डिज़ाइन करते समय, सुरक्षा का ध्यान रखना ज़रूरी है.
13. Ollama और TestContainers के साथ Gemma चलाना
अब तक, हम Gemini का इस्तेमाल कर रहे हैं. हालांकि, इसका छोटा बहन मॉडल Gemma भी है.
Gemma, लाइटवेट और बेहतरीन ओपन मॉडल का फ़ैमिली है. इसे Gemini मॉडल में इस्तेमाल की गई रिसर्च और तकनीक का इस्तेमाल करके बनाया गया है. Gemma, Gemma1 और Gemma2 नाम के दो वैरिएंट में उपलब्ध है. दोनों वैरिएंट के अलग-अलग साइज़ हैं. Gemma1 दो साइज़ में उपलब्ध है: 2B और 7B. Gemma2 दो साइज़ में उपलब्ध है: 9B और 27B. इनका वज़न कम होता है और इन्हें आसानी से चलाया जा सकता है. इन्हें अपने लैपटॉप या Cloud Shell में भी चलाया जा सकता है.
Gemma को कैसे चलाया जाता है?
Gemma को चलाने के कई तरीके हैं: क्लाउड में, Vertex AI के ज़रिए एक बटन पर क्लिक करके या कुछ जीपीयू के साथ GKE का इस्तेमाल करके. हालांकि, इसे स्थानीय तौर पर भी चलाया जा सकता है.
Gemma को लोकल तौर पर चलाने के लिए, Ollama एक अच्छा विकल्प है. यह एक ऐसा टूल है जिसकी मदद से, अपनी लोकल मशीन पर Llama 2, Mistral जैसे छोटे मॉडल और कई अन्य मॉडल चलाए जा सकते हैं. यह Docker की तरह ही है, लेकिन LLM के लिए.
अपने ऑपरेटिंग सिस्टम के लिए दिए गए निर्देश का पालन करके, Ollama इंस्टॉल करें.
अगर Linux एनवायरमेंट का इस्तेमाल किया जा रहा है, तो आपको Ollama को इंस्टॉल करने के बाद उसे चालू करना होगा.
ollama serve > /dev/null 2>&1 &
स्थानीय तौर पर इंस्टॉल करने के बाद, मॉडल को खींचने के लिए निर्देश चलाए जा सकते हैं:
ollama pull gemma:2b
मॉडल के खींचे जाने का इंतज़ार करें. इसमें कुछ समय लग सकता है.
मॉडल चलाएं:
ollama run gemma:2b
अब, मॉडल के साथ इंटरैक्ट किया जा सकता है:
>>> Hello! Hello! It's nice to hear from you. What can I do for you today?
प्रॉम्प्ट से बाहर निकलने के लिए, Ctrl+D दबाएं
TestContainers पर Ollama में Gemma को चलाना
Ollama को स्थानीय तौर पर इंस्टॉल और चलाने के बजाय, TestContainers की मदद से कंटेनर में Ollama का इस्तेमाल किया जा सकता है.
TestContainers का इस्तेमाल सिर्फ़ टेस्टिंग के लिए नहीं किया जा सकता. इसका इस्तेमाल कंटेनर को चलाने के लिए भी किया जा सकता है. यहां तक कि एक खास OllamaContainer
भी है जिसका फ़ायदा लिया जा सकता है!
पूरी जानकारी यहां दी गई है:
लागू करना
आइए, GemmaWithOllamaContainer.java
के हर हिस्से पर एक नज़र डालते हैं.
सबसे पहले, आपको एक ऐसा Ollama कंटेनर बनाना होगा जो Gemma मॉडल को खींचता हो. यह इमेज, पिछले रन से पहले से मौजूद है या इसे बनाया जाएगा. अगर इमेज पहले से मौजूद है, तो आपको TestContainers को सिर्फ़ यह बताना होगा कि आपको डिफ़ॉल्ट Ollama इमेज को Gemma के साथ काम करने वाले वैरिएंट से बदलना है:
private static final String TC_OLLAMA_GEMMA_2_B = "tc-ollama-gemma-2b";
// Creating an Ollama container with Gemma 2B if it doesn't exist.
private static OllamaContainer createGemmaOllamaContainer() throws IOException, InterruptedException {
// Check if the custom Gemma Ollama image exists already
List<Image> listImagesCmd = DockerClientFactory.lazyClient()
.listImagesCmd()
.withImageNameFilter(TC_OLLAMA_GEMMA_2_B)
.exec();
if (listImagesCmd.isEmpty()) {
System.out.println("Creating a new Ollama container with Gemma 2B image...");
OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26");
ollama.start();
ollama.execInContainer("ollama", "pull", "gemma:2b");
ollama.commitToImage(TC_OLLAMA_GEMMA_2_B);
return ollama;
} else {
System.out.println("Using existing Ollama container with Gemma 2B image...");
// Substitute the default Ollama image with our Gemma variant
return new OllamaContainer(
DockerImageName.parse(TC_OLLAMA_GEMMA_2_B)
.asCompatibleSubstituteFor("ollama/ollama"));
}
}
इसके बाद, Ollama टेस्ट कंटेनर बनाएं और उसे शुरू करें. इसके बाद, Ollama चैट मॉडल बनाएं. इसके लिए, आपको उस मॉडल के साथ कंटेनर का पता और पोर्ट डालना होगा जिसका इस्तेमाल करना है. आखिर में, model.generate(yourPrompt)
को हमेशा की तरह इस्तेमाल करें:
public static void main(String[] args) throws IOException, InterruptedException {
OllamaContainer ollama = createGemmaOllamaContainer();
ollama.start();
ChatLanguageModel model = OllamaChatModel.builder()
.baseUrl(String.format("http://%s:%d", ollama.getHost(), ollama.getFirstMappedPort()))
.modelName("gemma:2b")
.build();
String response = model.generate("Why is the sky blue?");
System.out.println(response);
}
इसे इस तरह चलाएं:
./gradlew run -q -DjavaMainClass=gemini.workshop.GemmaWithOllamaContainer
पहली बार चलाने पर, कंटेनर बनाने और उसे चलाने में कुछ समय लगेगा. हालांकि, इसके बाद आपको Gemma का जवाब दिखेगा:
INFO: Container ollama/ollama:0.1.26 started in PT2.827064047S
The sky appears blue due to Rayleigh scattering. Rayleigh scattering is a phenomenon that occurs when sunlight interacts with molecules in the Earth's atmosphere.
* **Scattering particles:** The main scattering particles in the atmosphere are molecules of nitrogen (N2) and oxygen (O2).
* **Wavelength of light:** Blue light has a shorter wavelength than other colors of light, such as red and yellow.
* **Scattering process:** When blue light interacts with these molecules, it is scattered in all directions.
* **Human eyes:** Our eyes are more sensitive to blue light than other colors, so we perceive the sky as blue.
This scattering process results in a blue appearance for the sky, even though the sun is actually emitting light of all colors.
In addition to Rayleigh scattering, other atmospheric factors can also influence the color of the sky, such as dust particles, aerosols, and clouds.
आपके पास Cloud Shell में Gemma चल रहा है!
14. बधाई हो
बधाई हो, आपने LangChain4j और Gemini API का इस्तेमाल करके, Java में अपना पहला जनरेटिव एआई चैट ऐप्लिकेशन बना लिया है! आपको पता चला है कि मल्टीमोडल लार्ज लैंग्वेज मॉडल काफ़ी असरदार हैं. ये आपके दस्तावेज़ों, डेटा निकालने, बाहरी एपीआई के साथ इंटरैक्ट करने वगैरह पर भी सवाल पूछने/जवाब देने जैसे कई टास्क को हैंडल कर सकते हैं.
आगे क्या करना है?
अब आपकी बारी है कि आप एलएलएम के बेहतर इंटिग्रेशन की मदद से, अपने ऐप्लिकेशन को बेहतर बनाएं!
इसके बारे में और पढ़ें
- जनरेटिव एआई के सामान्य इस्तेमाल के उदाहरण
- जनरेटिव एआई के बारे में ट्रेनिंग के संसाधन
- Generative AI Studio की मदद से Gemini के साथ इंटरैक्ट करना
- ज़िम्मेदारी के साथ एआई का इस्तेमाल