1. Giriş
Bu codelab'de, Google Cloud'daki Vertex AI'da barındırılan Gemini büyük dil modeli (LLM) ele alınmaktadır. Vertex AI, Google Cloud'daki tüm makine öğrenimi ürünlerini, hizmetlerini ve modellerini kapsayan bir platformdur.
LangChain4j çerçevesini kullanarak Gemini API ile etkileşim kurmak için Java'yı kullanacaksınız. Soru yanıtlama, fikir üretme, varlık ve yapılandırılmış içerik çıkarma, alma artırılmış üretimi ve işlev çağırma için LLM'den yararlanmak üzere somut örnekler üzerinden ilerleyeceksiniz.
Üretken yapay zeka nedir?
Üretken yapay zeka, metin, resim, müzik, ses ve video gibi yeni içerikler oluşturmak için yapay zekanın kullanılmasını ifade eder.
Üretken yapay zeka, çok görevli ve kullanıma hazır görevleri (ör. özetleme, soru-cevap, sınıflandırma) gerçekleştirebilen büyük dil modelleri (LLM'ler) tarafından desteklenir. Temel modeller, çok az eğitimle ve çok az örnek veriyle hedeflenen kullanım alanlarına uyarlanabilir.
Üretken yapay zeka nasıl çalışır?
Üretken yapay zeka, makine öğrenimi (ML) modeli kullanarak insan tarafından oluşturulan içeriklerden oluşan bir veri kümesindeki kalıpları ve ilişkileri öğrenir. Ardından, öğrendiği kalıpları kullanarak yeni içerikler üretir.
Üretken yapay zeka modelini eğitmenin en yaygın yolu, gözetimli öğrenmeyi kullanmaktır. Modele, insanlar tarafından oluşturulan bir dizi içerik ve bunlara karşılık gelen etiketler verilir. Ardından, insanlar tarafından oluşturulan içeriklere benzer içerikler üretmeyi öğrenir.
Üretken yapay zekanın yaygın kullanım alanları nelerdir?
Üretken yapay zeka şu amaçlarla kullanılabilir:
- Gelişmiş sohbet ve arama deneyimleriyle müşteri etkileşimlerini iyileştirin.
- Konuşma arayüzleri ve özetler aracılığıyla büyük miktarda yapılandırılmamış veriyi keşfedin.
- Teklif isteklerini yanıtlama, pazarlama içeriklerini farklı dillerde yerelleştirme ve müşteri sözleşmelerinin uygunluğunu kontrol etme gibi tekrarlayan görevlerde yardımcı olur.
Google Cloud'un sunduğu üretken yapay zeka teklifleri nelerdir?
Vertex AI ile temel modellerle etkileşim kurabilir, bunları özelleştirebilir ve uygulamalarınıza yerleştirebilirsiniz. Bu işlemler için makine öğrenimi konusunda uzman olmanız gerekmez. Model Garden'daki temel modellere erişebilir, Vertex AI Studio'daki basit bir kullanıcı arayüzü aracılığıyla modelleri ayarlayabilir veya modelleri bir veri bilimi not defterinde kullanabilirsiniz.
Vertex AI Arama ve Sohbet, geliştiricilere üretken yapay zeka destekli arama motorları ve chatbot'lar oluşturmanın en hızlı yolunu sunar.
Gemini destekli Google Cloud için Gemini, Google Cloud ve IDE'lerde kullanılabilen yapay zeka destekli bir ortak çalışma aracıdır. Bu araç, daha fazla işi daha kısa sürede yapmanıza yardımcı olur. Gemini Code Assist, kod tamamlama, kod oluşturma ve kod açıklamaları sunar. Ayrıca teknik sorular sormak için Gemini Code Assist ile sohbet edebilirsiniz.
Gemini nedir?
Gemini, Google DeepMind tarafından geliştirilen ve çok formatlı kullanım alanları için tasarlanmış bir üretken yapay zeka modeli ailesidir. Çok formatlı olması, metin, kod, resim ve ses gibi farklı içerik türlerini işleyip oluşturabileceği anlamına gelir.

Gemini farklı varyasyon ve boyutlarda sunulur:
- Gemini 2.0 Flash: En yeni nesil özelliklerimiz ve geliştirilmiş yeteneklerimiz.
- Gemini 2.0 Flash-Lite: Maliyet verimliliği ve düşük gecikme süresi için optimize edilmiş bir Gemini 2.0 Flash modeli.
- Gemini 2.5 Pro: Şimdiye kadarki en gelişmiş akıl yürütme modelimiz.
- Gemini 2.5 Flash: Çok yönlü özellikler sunan bir düşünme modeli. Fiyat ve performans arasında denge sunmak için tasarlanmıştır.
Temel Özellikler:
- Çoklu format desteği: Gemini'ın birden fazla bilgi formatını anlayıp işleyebilmesi, geleneksel yalnızca metin tabanlı dil modellerinin çok ötesinde bir adımdır.
- Performans: Gemini 2.5 Pro, birçok karşılaştırma standardında mevcut en iyi performansı geride bırakıyor ve zorlu MMLU (Massive Multitask Language Understanding) karşılaştırma standardında insan uzmanları aşan ilk model oldu.
- Esneklik: Farklı Gemini boyutları, büyük ölçekli araştırmalardan mobil cihazlara dağıtıma kadar çeşitli kullanım alanlarına uyarlanabilir.
Java'dan Vertex AI'daki Gemini ile nasıl etkileşim kurabilirsiniz?
Bunun için iki seçeneğiniz bulunmaktadır:
- Resmi Vertex AI Java API for Gemini kitaplığı.
- LangChain4j çerçevesi.
Bu codelab'de LangChain4j çerçevesini kullanacaksınız.
LangChain4j çerçevesi nedir?
LangChain4j çerçevesi, LLM'nin kendisi gibi çeşitli bileşenlerin yanı sıra vektör veritabanları (semantik aramalar için), belge yükleyiciler ve ayırıcılar (belgeleri analiz etmek ve onlardan öğrenmek için), çıkış ayrıştırıcılar gibi diğer araçları düzenleyerek LLM'leri Java uygulamalarınıza entegre etmenizi sağlayan açık kaynaklı bir kitaplıktır.
Bu proje, LangChain Python projesinden esinlenerek Java geliştiricilere hizmet vermek amacıyla oluşturuldu.

Neler öğreneceksiniz?
- Gemini ve LangChain4j'i kullanmak için Java projesi ayarlama
- Gemini'a programatik olarak ilk isteminizi gönderme
- Gemini'dan gelen yanıtları akış şeklinde gösterme
- Kullanıcı ile Gemini arasında sohbet oluşturma
- Hem metin hem de resim göndererek Gemini'ı çok formatlı bağlamda kullanma
- Yapılandırılmamış içerikten yararlı yapılandırılmış bilgileri ayıklama
- İstem şablonlarını değiştirme
- Duygu analizi gibi metin sınıflandırması nasıl yapılır?
- Kendi dokümanlarınızla sohbet etme (Veriyle Artırılmış Üretim)
- İşlev çağrısıyla chatbot'larınızı genişletme
- Gemma'yı Ollama ve TestContainers ile yerel olarak kullanma
Gerekenler
- Java programlama dili hakkında bilgi
- Google Cloud projesi
- Chrome veya Firefox gibi bir tarayıcı
2. Kurulum ve şartlar
Yönlendirmesiz ortam kurulumu
- Google Cloud Console'da oturum açın ve yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.



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

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

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

Bu sanal makineye, ihtiyaç duyacağınız tüm geliştirme araçları yüklenmiştir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu codelab'deki çalışmalarınızın neredeyse tamamını tarayıcıyla yapabilirsiniz.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, proje kimliğinize ayarlandığını görürsünüz.
- Kimliğinizin doğrulandığını onaylamak için Cloud Shell'de şu komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- gcloud komutunun projeniz hakkında bilgi sahibi olduğunu onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Değilse şu komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. Geliştirme ortamınızı hazırlama
Bu codelab'de, Java programlarınızı geliştirmek için Cloud Shell terminalini ve Cloud Shell düzenleyiciyi kullanacaksınız.
Vertex AI API'lerini etkinleştirme
Google Cloud Console'da proje adınızın Google Cloud Console'unuzun üst kısmında gösterildiğinden emin olun. Açılmıyorsa Proje seçin'i tıklayarak Proje Seçici'yi açın ve istediğiniz projeyi seçin.
Vertex AI API'lerini Google Cloud Console'un Vertex AI bölümünden veya Cloud Shell terminalinden etkinleştirebilirsiniz.
Google Cloud Console'dan etkinleştirmek için önce Google Cloud Console menüsünün Vertex AI bölümüne gidin:

Vertex AI kontrol panelinde Enable All Recommended APIs'i (Önerilen Tüm API'leri Etkinleştir) tıklayın.
Bu işlem birkaç API'yi etkinleştirir ancak codelab için en önemlisi aiplatform.googleapis.com API'sidir.
Alternatif olarak, bu API'yi Cloud Shell terminalinden aşağıdaki komutla da etkinleştirebilirsiniz:
gcloud services enable aiplatform.googleapis.com
GitHub deposunu klonlayın.
Cloud Shell terminalinde bu codelab'in deposunu klonlayın:
git clone https://github.com/glaforge/gemini-workshop-for-java-developers.git
Projenin çalışmaya hazır olup olmadığını kontrol etmek için "Hello World" programını çalıştırmayı deneyebilirsiniz.
En üst düzey klasörde olduğunuzdan emin olun:
cd gemini-workshop-for-java-developers/
Gradle sarmalayıcıyı oluşturun:
gradle wrapper
gradlew ile koşma:
./gradlew run
Aşağıdaki çıkışı göreceksiniz:
.. > Task :app:run Hello World!
Cloud Editor'ı açma ve ayarlama
Cloud Shell'den Cloud Code Editor ile kodu açın:

Cloud Code Düzenleyici'de File -> Open Folder seçerek codelab kaynak klasörünü açın ve codelab kaynak klasörünü gösterin (ör. /home/username/gemini-workshop-for-java-developers/).
Ortam değişkenlerini ayarlama
Terminal -> New Terminal seçeneğini belirleyerek Cloud Code Editor'da yeni bir terminal açın. Kod örneklerini çalıştırmak için gereken iki ortam değişkenini ayarlayın:
- PROJECT_ID: Google Cloud proje kimliğiniz
- LOCATION: Gemini modelinin dağıtıldığı bölge
Değişkenleri aşağıdaki şekilde dışa aktarın:
export PROJECT_ID=$(gcloud config get-value project) export LOCATION=us-central1
4. Gemini modeline yapılan ilk çağrı
Proje düzgün şekilde ayarlandığına göre artık Gemini API'yi çağırma zamanı.
app/src/main/java/gemini/workshop dizinindeki QA.java dosyasına göz atın:
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-2.0-flash")
.build();
System.out.println(model.generate("Why is the sky blue?"));
}
}
Bu ilk örnekte, ChatModel arayüzünü uygulayan VertexAiGeminiChatModel sınıfını içe aktarmanız gerekir.
main yönteminde, VertexAiGeminiChatModel için oluşturucuyu kullanarak sohbet dil modelini yapılandırır ve şunları belirtirsiniz:
- Proje
- Konum
- Model adı (
gemini-2.0-flash).
Dil modeli hazır olduğunda generate() yöntemini çağırabilir ve isteminizi, sorunuzu veya talimatlarınızı LLM'ye gönderebilirsiniz. Burada, gökyüzünün neden mavi olduğuyla ilgili basit bir soru soruyorsunuz.
Farklı soruları veya görevleri denemek için bu istemi değiştirebilirsiniz.
Örneği kaynak kodu kök klasöründe çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.QA
Şuna benzer bir çıkış görürsünüz:
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.
Tebrikler, Gemini'a ilk çağrınızı yaptınız.
Yanıtı akış şeklinde gösterme
Yanıtın birkaç saniye sonra tek seferde verildiğini fark ettiniz mi? Ayrıca, akış yanıtı varyantı sayesinde yanıtı kademeli olarak da alabilirsiniz. Akış yanıtı: Model, yanıtı hazır oldukça parça parça döndürür.
Bu codelab'de akış şeklinde olmayan yanıtı kullanacağız ancak nasıl yapılabileceğini görmek için akış şeklinde yanıta göz atalım.
app/src/main/java/gemini/workshop dizinindeki StreamQA.java içinde yayın yanıtını çalışırken görebilirsiniz:
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-2.0-flash")
.maxOutputTokens(4000)
.build();
model.generate("Why is the sky blue?", onNext(System.out::println));
}
}
Bu kez, StreamingChatLanguageModel arayüzünü uygulayan akış sınıfı varyantlarını VertexAiGeminiStreamingChatModel içe aktarıyoruz. Ayrıca, Java lambda ifadeleriyle bir akış işleyici oluşturmak için StreamingResponseHandler sağlayan kolaylık yöntemi olan LambdaStreamingResponseHandler.onNext öğesini statik olarak içe aktarmanız gerekir.
Bu kez, generate() yönteminin imzası biraz farklıdır. Dize döndürmek yerine döndürme türü boş (void) olur. İstemle birlikte bir akış yanıtı işleyici de iletmeniz gerekir. Burada, yukarıda bahsettiğimiz statik içe aktarma sayesinde, onNext() yöntemine ilettiğiniz bir lambda ifadesi tanımlayabiliriz. Lambda ifadesi, yanıtın yeni bir kısmı kullanılabilir olduğunda her seferinde çağrılır. İkincisi ise yalnızca bir hata oluştuğunda çağrılır.
Çalıştır:
./gradlew run -q -DjavaMainClass=gemini.workshop.StreamQA
Önceki sınıfa benzer bir yanıt alırsınız ancak bu kez yanıtın tamamının gösterilmesini beklemek yerine yanıtın kabuğunuzda kademeli olarak göründüğünü fark edersiniz.
Ek yapılandırma
Yapılandırma için yalnızca projeyi, konumu ve model adını tanımladık ancak model için belirleyebileceğiniz başka parametreler de vardır:
temperature(Float temp): Yanıtın ne kadar yaratıcı olmasını istediğinizi tanımlamak için kullanılır (0, yaratıcılığın düşük olduğu ve genellikle daha gerçekçi yanıtlar için, 2 ise daha yaratıcı yanıtlar için kullanılır).topP(Float topP): Toplam olasılığı bu kayan noktalı sayıya (0 ile 1 arasında) ulaşan olası kelimeleri seçmek için kullanılır.topK(Integer topK): Metin tamamlama için olası kelimeler arasından rastgele bir kelime seçmek üzere kullanılır (1-40 arasında).maxOutputTokens(Integer max): Modelin verdiği yanıtın maksimum uzunluğunu belirtmek için kullanılır (genellikle 4 parça yaklaşık 3 kelimeye karşılık gelir).maxRetries(Integer retries): Zaman başına istek kotasını aşıyorsanız veya platformda teknik bir sorun varsa modelin aramayı 3 kez yeniden denemesini sağlayabilirsiniz.
Şimdiye kadar Gemini'a tek bir soru sordunuz ancak çok turlu bir sohbet de yapabilirsiniz. Bir sonraki bölümde bu konuyu ele alacağız.
5. Gemini ile sohbet edin
Önceki adımda tek bir soru sormuş olmalısınız. Artık kullanıcı ile LLM arasında gerçek bir sohbet başlatma zamanı. Her soru ve yanıt, önceki soru ve yanıtların üzerine eklenerek gerçek bir tartışma oluşturabilir.
app/src/main/java/gemini/workshop klasöründeki Conversation.java dosyasına göz atın:
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-2.0-flash")
.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));
});
}
}
Bu sınıfa birkaç yeni ve ilgi çekici içe aktarma yapıldı:
MessageWindowChatMemory: Sohbetin çok turlu yönünü ele almaya ve önceki soruları ve yanıtları yerel bellekte tutmaya yardımcı olacak bir sınıfAiServices: Sohbet modelini ve sohbet belleğini birbirine bağlayacak daha üst düzey bir soyutlama sınıfı
Ana yöntemde modeli, sohbet belleğini ve yapay zeka hizmetini ayarlayacaksınız. Model, proje, konum ve model adı bilgileriyle her zamanki gibi yapılandırılır.
Sohbet belleği için, değiştirilen son 20 mesajı saklayan bir bellek oluşturmak üzere MessageWindowChatMemory'nın oluşturucusunu kullanırız. Bu, bağlamı Java sınıfı istemcimizde yerel olarak tutulan, görüşme üzerinde kayan bir penceredir.
Ardından, sohbet modelini sohbet belleğine bağlayan AI service oluşturursunuz.
Yapay zeka hizmetinin, tanımladığımız, LangChain4j'in uyguladığı, ConversationService sorgu alan ve String yanıt döndüren özel bir String arayüzü nasıl kullandığına dikkat edin.
Şimdi Gemini ile sohbet etme zamanı. Önce basit bir selamlama gönderiliyor, ardından Eyfel Kulesi'nin hangi ülkede bulunduğunu öğrenmek için ilk soru soruluyor. Son cümlenin, Eyfel Kulesi'nin bulunduğu ülkede kaç kişi yaşadığını merak ettiğiniz için ilk sorunun yanıtıyla ilgili olduğunu fark edebilirsiniz. Bu cümlede, önceki yanıtta verilen ülke açıkça belirtilmiyor. Geçmiş soru ve yanıtların her istemle birlikte gönderildiğini gösterir.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.Conversation
Şuna benzer üç yanıt görürsünüz:
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'a tek dönüşlü sorular sorabilir veya çok dönüşlü sohbetler edebilirsiniz ancak şu ana kadar yalnızca metin girişi yapılıyordu. Peki ya resimler? Bir sonraki adımda resimleri inceleyelim.
6. Gemini ile çok formatlılık
Gemini, çok formatlı bir modeldir. Bu model, giriş olarak yalnızca metni değil, resimleri ve hatta videoları da kabul eder. Bu bölümde, metin ve resimlerin karıştırılmasıyla ilgili bir kullanım alanı örneği göreceksiniz.
Gemini bu kediyi tanır mı?

Vikipedi'den alınan, karda bir kedinin resmi
app/src/main/java/gemini/workshop dizinindeki Multimodal.java öğesine göz atın:
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-2.0-flash")
.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());
}
}
İçe aktarma işlemlerinde, farklı türdeki mesajlar ve içerikler arasında ayrım yaptığımızı görebilirsiniz. Bir UserMessage hem TextContent hem de ImageContent nesnesi içerebilir. Bu, çok formatlılığın bir örneğidir: Metin ve görüntülerin karıştırılması. Basit bir dize istemi göndermeyiz. Bunun yerine, bir resim içerik parçası ve bir metin içerik parçasından oluşan, kullanıcı mesajını temsil eden daha yapılandırılmış bir nesne göndeririz. Model, AiMessage içeren bir Response döndürür.
Ardından, AiMessage değerini content() aracılığıyla yanıttan, mesajın metnini ise text() aracılığıyla alırsınız.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.Multimodal
Resmin adı, içeriği hakkında size ipucu vermiş olsa da Gemini'ın çıktısı aşağıdaki gibi:
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.
Resim ve metin istemlerini karıştırmak ilginç kullanım alanları sunar. Şunları yapabilen uygulamalar oluşturabilirsiniz:
- Resimlerdeki metinleri tanıma
- Bir görüntünün güvenli olup olmadığını kontrol etme
- Resim altyazıları oluşturabilirsiniz.
- Düz metin açıklamaları içeren bir resim veritabanında arama yapın.
Resimlerden bilgi ayıklamanın yanı sıra yapılandırılmamış metinlerden de bilgi ayıklayabilirsiniz. Bir sonraki bölümde bu konu hakkında bilgi edineceksiniz.
7. Yapılandırılmamış metinlerden yapılandırılmış bilgiler ayıklama
Rapor belgelerinde, e-postalarda veya diğer uzun metinlerde önemli bilgiler yapılandırılmamış bir şekilde verilebilir. İdeal olarak, yapılandırılmamış metinde yer alan temel ayrıntıları yapılandırılmış nesneler şeklinde ayıklayabilmek istersiniz. Bunu nasıl yapabileceğinize bakalım.
Bir kişinin biyografisi, CV'si veya açıklaması verildiğinde bu kişinin adını ve yaşını çıkarmak istediğinizi varsayalım. LLM'ye, akıllıca düzenlenmiş bir istemle yapılandırılmamış metinden JSON ayıklaması talimatını verebilirsiniz (bu işleme genellikle "istem mühendisliği" adı verilir).
Ancak aşağıdaki örnekte, JSON çıkışını açıklayan bir istem oluşturmak yerine Gemini'ın yapılandırılmış çıkış (bazen kısıtlanmış oluşturma olarak da adlandırılır) adlı güçlü bir özelliğini kullanacağız. Bu özellik, modele yalnızca belirtilen bir JSON şemasına uygun geçerli JSON içeriği çıkışı yapmasını zorlar.
app/src/main/java/gemini/workshop'deki ExtractData.java bölümüne göz atın:
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-2.0-flash")
.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
}
}
Bu dosyadaki çeşitli adımlara göz atalım:
Personkaydı, bir kişiyi tanımlayan ayrıntıları (ad ve yaş) temsil etmek için tanımlanır.PersonExtractorarayüzü, yapılandırılmamış bir metin dizesi verildiğindePersonörneği döndüren bir yöntemle tanımlanır.extractPerson(), bir talimat istemini kendisiyle ilişkilendiren@SystemMessageek açıklamasıyla açıklanır. Bu istem, modelin bilgileri ayıklarken yol göstermek için kullanacağı istemdir. Ayrıntılar, sizin için ayrıştırılacak vePersonörneğine dönüştürülecek bir JSON belgesi biçiminde döndürülür.
Şimdi de main() yönteminin içeriğine bakalım:
- Sohbet modeli yapılandırılır ve başlatılır. Model oluşturucu sınıfında 2 yeni yöntem kullanıyoruz:
responseMimeType()veresponseSchema(). İlk istem, Gemini'a çıkışta geçerli JSON oluşturmasını söyler. İkinci yöntem, döndürülmesi gereken JSON nesnesinin şemasını tanımlar. Ayrıca, ikincisi bir Java sınıfını veya kaydını uygun bir JSON şemasına dönüştürebilen bir kolaylık yöntemine delege eder. - LangChain4j'nin
AiServicessınıfı sayesinde birPersonExtractornesnesi oluşturulur. - Ardından, yapılandırılmamış metinden kişinin ayrıntılarını çıkarmak için
Person person = extractor.extractPerson(...)'ı arayabilir ve ad ile yaş bilgilerini içeren birPersonörneği alabilirsiniz.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.ExtractData
Aşağıdaki çıkışı göreceksiniz:
Anna 23
Evet, bu Ayşe ve 23 yaşında.
Bu AiServices yaklaşımla, kesin olarak türü belirlenmiş nesnelerle çalışırsınız. Doğrudan LLM ile etkileşimde bulunmuyorsunuz. Bunun yerine, çıkarılan kişisel bilgileri temsil eden Person kaydı gibi somut sınıflarla çalışırsınız ve Person örneği döndüren bir extractPerson() yöntemi olan bir PersonExtractor nesneniz vardır. LLM kavramı soyutlaştırılır ve bir Java geliştiricisi olarak bu PersonExtractor arayüzünü kullanırken yalnızca normal sınıfları ve nesneleri değiştirirsiniz.
8. İstem şablonlarıyla istemleri yapılandırma
Ortak bir talimat veya soru grubu kullanarak bir LLM ile etkileşim kurduğunuzda, istemin bir bölümü hiç değişmezken diğer bölümleri verileri içerir. Örneğin, yemek tarifleri oluşturmak istiyorsanız "Yetenekli bir şefsin. Lütfen aşağıdaki malzemelerle bir yemek tarifi oluştur: ..." gibi bir istem kullanabilir ve ardından malzemeleri bu metnin sonuna ekleyebilirsiniz. İstem şablonları, programlama dillerindeki enterpolasyonlu dizelere benzer şekilde bu amaçla kullanılır. İstem şablonu, LLM'ye yapılan belirli bir çağrı için doğru verilerle değiştirebileceğiniz yer tutucular içerir.
Daha somut bir örnek olarak, app/src/main/java/gemini/workshop dizinindeki TemplatePrompt.java dosyasını inceleyelim:
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-2.0-flash")
.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());
}
}
Her zamanki gibi, VertexAiGeminiChatModel modelini yüksek sıcaklık ve yüksek topP ve topK değerleriyle yüksek düzeyde yaratıcılık sağlayacak şekilde yapılandırıyorsunuz. Ardından, istemimizin dizesini ileterek from() statik yöntemiyle bir PromptTemplate oluşturur ve çift küme parantezli yer tutucu değişkenleri ({{dish}} ve {{ingredients}}) kullanırsınız.
Yer tutucunun adını ve yerine kullanılacak dize değerini temsil eden anahtar/değer çiftlerinin haritasını alan apply() işlevini çağırarak son istemi oluşturursunuz.
Son olarak, generate() talimatıyla istemden kullanıcı mesajı oluşturarak Gemini modelinin generate() yöntemini çağırırsınız.prompt.toUserMessage()
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.TemplatePrompt
Şuna benzer bir çıkış görürsünüz:
**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.
Haritada dish ve ingredients değerlerini değiştirebilir, sıcaklığı, topK ve tokP değerlerini ayarlayabilir ve kodu yeniden çalıştırabilirsiniz. Bu sayede, bu parametrelerin değiştirilmesinin LLM üzerindeki etkisini gözlemleyebilirsiniz.
İstem şablonları, LLM çağrıları için yeniden kullanılabilir ve parametrelendirilebilir talimatlar oluşturmanın iyi bir yoludur. Kullanıcılarınızın sağladığı farklı değerler için verileri iletebilir ve istemleri özelleştirebilirsiniz.
9. Az örnekli istemle metin sınıflandırma
LLM'ler, metinleri farklı kategorilere ayırma konusunda oldukça başarılıdır. Metin örnekleri ve bunlarla ilişkili kategoriler sağlayarak LLM'nin bu görevde başarılı olmasına yardımcı olabilirsiniz. Bu yaklaşıma genellikle birkaç görevli istem denir.
Belirli bir metin sınıflandırma türü olan duygu analizini yapmak için app/src/main/java/gemini/workshop dizinindeki TextClassification.java dosyasını açalım.
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-2.0-flash")
.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 numaralandırılmış türü, bir duygu için farklı değerleri (olumsuz, nötr veya olumlu) listeler.
main() yönteminde, Gemini sohbet modelini her zamanki gibi oluşturursunuz ancak yalnızca kısa bir yanıt istediğiniz için maksimum çıkış jetonu sayısını düşük tutarsınız: Metin POSITIVE, NEGATIVE veya NEUTRAL olur. Modelin yalnızca bu değerleri döndürmesini sağlamak için veri ayıklama bölümünde keşfettiğiniz yapılandırılmış çıkış desteğinden yararlanabilirsiniz. Bu nedenle responseSchema() yöntemi kullanılır. Bu kez, şema tanımını anlamak için SchemaHelper bölümündeki kolay yöntemi kullanmayacak, bunun yerine Schema oluşturucuyu kullanacaksınız.
Model yapılandırıldıktan sonra, LangChain4j'nin AiServices, LLM'yi kullanarak sizin için uygulayacağı bir SentimentAnalysis arayüzü oluşturursunuz. Bu arayüzde bir yöntem bulunur: analyze(). Girişte analiz edilecek metni alır ve bir Sentiment enum değeri döndürür. Bu nedenle, yalnızca tanınan duygu sınıfını temsil eden kesin türü belirlenmiş bir nesneyi değiştirirsiniz.
Ardından, modeli sınıflandırma görevini yapmaya yönlendirmek için "az sayıda örnek" vermek üzere, metni ve onunla ilişkili duyguyu temsil eden kullanıcı mesajları ve yapay zeka yanıtları çiftlerini iletmek için bir sohbet belleği oluşturursunuz.
SentimentAnalysis arayüzümüzü, kullanılacak modeli ve birkaç görevli örnekle sohbet belleğini ileterek her şeyi AiServices.builder() yöntemiyle birleştirelim. Son olarak, analiz edilecek metinle analyze() yöntemini çağırın.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.TextClassification
Tek bir kelime görmeniz gerekir:
POSITIVE
Çilekleri sevmek olumlu bir duygu gibi görünüyor.
10. Almayla Artırılmış Üretim
LLM'ler büyük miktarda metinle eğitilir. Ancak bilgileri yalnızca eğitimi sırasında gördüğü bilgileri kapsar. Model eğitiminin son tarihinden sonra yayınlanan yeni bilgiler model tarafından kullanılamaz. Bu nedenle, model görmediği bilgilerle ilgili soruları yanıtlayamaz.
Bu nedenle, bu bölümde ele alınacak olan Retrieval Augmented Generation (RAG) gibi yaklaşımlar, LLM'nin kullanıcı isteklerini yerine getirmek, daha güncel olabilecek bilgilerle veya eğitim sırasında erişilemeyen özel bilgilerle yanıt vermek için bilmesi gerekebilecek ek bilgileri sağlamaya yardımcı olur.
Görüşmelere geri dönelim. Bu kez dokümanlarınızla ilgili sorular sorabilirsiniz. Dokümanlarınızın daha küçük parçalara ("chunk") ayrıldığı bir veritabanından ilgili bilgileri alabilen bir chatbot oluşturacaksınız. Bu bilgiler, modelin yanıtlarını temellendirmek için kullanılacak ve model yalnızca eğitiminde yer alan bilgilere dayanmayacak.
RAG'de iki aşama vardır:
- Alım aşaması: Belgeler belleğe yüklenir, daha küçük parçalara bölünür ve parçaların yüksek çok boyutlu vektör gösterimi olan vektör yerleştirmeleri hesaplanıp semantik aramalar yapabilen bir vektör veritabanında saklanır. Bu alım aşaması normalde bir kez yapılır. Bu aşama, doküman külliyatına yeni dokümanlar eklenmesi gerektiğinde gerçekleştirilir.

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

Belgelerinizi hazırlama
Bu yeni örnekte, kurgusal bir araba üreticisinin kurgusal bir araba modeli olan Cymbal Starlight hakkında sorular soracaksınız. Buradaki fikir, kurgusal bir araba hakkındaki bir belgenin modelin bilgisi içinde yer almamasıdır. Bu nedenle, Gemini bu araba hakkındaki soruları doğru şekilde yanıtlayabiliyorsa RAG yaklaşımı işe yarıyor demektir: Dokümanınızda arama yapabiliyor.
Chatbot'u uygulama
2 aşamalı yaklaşımı nasıl oluşturacağımızı inceleyelim: önce belge alımı, ardından kullanıcıların belgeyle ilgili sorular sorduğu sorgu zamanı ("alma aşaması" olarak da adlandırılır).
Bu örnekte, her iki aşama da aynı sınıfta uygulanmaktadır. Normalde, alım işlemini gerçekleştiren bir uygulama ve kullanıcılarınıza chatbot arayüzü sunan başka bir uygulama olur.
Ayrıca, bu örnekte bellek içi vektör veritabanı kullanacağız. Gerçek bir üretim senaryosunda, alım ve sorgulama aşamaları iki ayrı uygulamada gerçekleştirilir ve vektörler bağımsız bir veritabanında kalıcı hale getirilir.
Doküman besleme
Belge alımı aşamasının ilk adımı, kurgusal arabamızla ilgili PDF dosyasını bulmak ve dosyayı okumak için bir PdfParser hazırlamaktır:
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());
Önce normal sohbet dili modelini oluşturmak yerine bir yerleştirme modeli örneği oluşturursunuz. Bu, metin parçalarının (kelimeler, cümleler veya paragraflar) vektör gösterimlerini oluşturmakla görevli özel bir modeldir. Metin yanıtları yerine kayan noktalı sayı vektörleri döndürür.
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();
Ardından, birlikte çalışmak için birkaç sınıfa ihtiyacınız olacak:
- PDF belgesini yükleyip parçalara ayırın.
- Bu parçaların tümü için vektör yerleştirmeleri oluşturun.
InMemoryEmbeddingStore<TextSegment> embeddingStore =
new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(500, 100))
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
storeIngestor.ingest(document);
Vektör yerleştirmelerini depolamak için bellek içi vektör veritabanı olan InMemoryEmbeddingStore örneği oluşturulur.
Doküman, DocumentSplitters sınıfı sayesinde parçalara ayrılır. PDF dosyasının metnini 500 karakterlik snippet'lere böler. Kelimelerin veya cümlelerin kesilmesini önlemek için 100 karakterlik bir örtüşme (bir sonraki parçayla) olur.
Mağaza alıcı, belge ayırıcıyı, vektörleri hesaplamak için kullanılan yerleştirme modelini ve bellek içi vektör veritabanını birbirine bağlar. Ardından, ingest() yöntemi aktarma işlemini gerçekleştirir.
İlk aşama tamamlandı. Belge, ilişkili vektör yerleştirmeleriyle birlikte metin parçalarına dönüştürüldü ve vektör veritabanında saklandı.
Soru sorma
Soru sormaya hazırlanma zamanı! Sohbeti başlatmak için bir sohbet modeli oluşturun:
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-2.0-flash")
.maxOutputTokens(1000)
.build();
Ayrıca, vektör veritabanını (embeddingStore değişkeninde) yerleştirme modeliyle bağlamak için bir alıcı sınıfına da ihtiyacınız vardır. Bu işlevin görevi, kullanıcının sorgusu için vektör yerleştirme işlemi yaparak vektör veritabanını sorgulamak ve veritabanında benzer vektörler bulmaktır:
EmbeddingStoreContentRetriever retriever =
new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);
Araba uzmanı asistanını temsil eden bir arayüz oluştur. Bu arayüz, AiServices sınıfı tarafından uygulanacak ve modelle etkileşim kurmanızı sağlayacak:
interface CarExpert {
Result<String> ask(String question);
}
CarExpert arayüzü, LangChain4j'nin Result sınıfına sarılmış bir dize yanıtı döndürür. Bu sarmalayıcı neden kullanılmalıdır? Çünkü bu araç yalnızca yanıt vermekle kalmaz, aynı zamanda içerik alıcı tarafından döndürülen veritabanındaki parçaları incelemenize de olanak tanır. Bu sayede, son yanıtı kullanıcıya sunmak için kullanılan dokümanların kaynaklarını gösterebilirsiniz.
Bu noktada yeni bir yapay zeka hizmeti yapılandırabilirsiniz:
CarExpert expert = AiServices.builder(CarExpert.class)
.chatLanguageModel(model)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.contentRetriever(retriever)
.build();
Bu hizmet şunları bir araya getirir:
- Daha önce yapılandırdığınız sohbet dili modeli.
- Sohbeti takip etmek için sohbet belleği.
- Alıcı, vektör yerleştirme sorgusunu veritabanındaki vektörlerle karşılaştırır.
.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}}
"""))
.build())
.contentRetriever(retriever)
.build())
Artık sorularınızı sormaya hazırsınız.
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());
});
Tam kaynak kodu, app/src/main/java/gemini/workshop dizinindeki RAG.java içinde yer alır.
Örneği çalıştırın:
./gradlew -q run -DjavaMainClass=gemini.workshop.RAG
Çıkışta sorularınızın yanıtlarını görürsünüz:
=== 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. İşlev çağırma
Bir LLM'nin bilgi alan veya bir işlem gerçekleştiren uzak bir web API'si ya da bir tür hesaplama yapan hizmetler gibi harici sistemlere erişmesini istediğiniz durumlar olabilir. Örneğin:
Uzak web API'leri:
- Müşteri siparişlerini takip edin ve güncelleyin.
- Sorun izleyicide bir bilet bulun veya oluşturun.
- Borsa fiyatları veya IoT sensör ölçümleri gibi gerçek zamanlı verileri getirme.
- E-posta gönderme
Hesaplama araçları:
- Daha ileri düzey matematik problemleri için hesap makinesi.
- LLM'lerin mantık yürütmesi gerektiğinde kodu çalıştırmak için kod yorumlama
- Doğal dil isteklerini SQL sorgularına dönüştürerek bir LLM'nin veritabanına sorgu göndermesini sağlar.
İşlev çağırma (bazen araçlar veya araç kullanımı olarak da adlandırılır), modelin kendi adına bir veya daha fazla işlev çağrısı yapılmasını isteme özelliğidir. Bu sayede, kullanıcının istemine daha yeni verilerle doğru şekilde yanıt verebilir.
Bir kullanıcının belirli bir istemi ve bu bağlamla alakalı olabilecek mevcut işlevlerin bilgisi verildiğinde, LLM bir işlev çağrısı isteğiyle yanıt verebilir. LLM'yi entegre eden uygulama, işlevi kendi adına çağırabilir, ardından LLM'ye bir yanıtla geri dönebilir ve LLM de metin yanıtıyla geri dönerek yorumlayabilir.
İşlev çağrısının dört adımı
İşlev çağırmayla ilgili bir örneğe göz atalım: Hava durumu tahmini hakkında bilgi alma.
Gemini'a veya başka bir LLM'ye Paris'teki hava durumu hakkında soru sorduğunuzda, mevcut hava durumu tahminiyle ilgili bilgiye sahip olmadığını belirterek yanıt verir. LLM'nin hava durumu verilerine gerçek zamanlı olarak erişmesini istiyorsanız kullanılmasını isteyebileceği bazı işlevler tanımlamanız gerekir.
Aşağıdaki diyagrama göz atın:

1️⃣ Öncelikle bir kullanıcı, Paris'teki hava durumu hakkında soru soruyor. Chatbot uygulaması (LangChain4j kullanılarak), LLM'nin sorguyu karşılamasına yardımcı olmak için kullanabileceği bir veya daha fazla işlev olduğunu biliyor. Chatbot hem ilk istemi hem de çağrılabilecek işlevlerin listesini gönderir. Burada, konum için dize parametresi alan getWeather() adlı bir işlev var.

LLM, hava durumu tahminleri hakkında bilgi sahibi olmadığı için metinle yanıt vermek yerine bir işlev yürütme isteği gönderir. Chatbot, konum parametresi olarak "Paris" ile getWeather() işlevini çağırmalıdır.
2️⃣ Chatbot, bu işlevi LLM adına çağırır ve işlev yanıtını alır. Burada, yanıtın {"forecast": "sunny"} olduğunu varsayıyoruz.

3️⃣ Chatbot uygulaması, JSON yanıtını LLM'ye geri gönderir.

4️⃣ LLM, JSON yanıtına bakar, bu bilgileri yorumlar ve sonunda Paris'te havanın güneşli olduğu metniyle yanıt verir.

Her adım kod olarak
Öncelikle Gemini modelini her zamanki gibi yapılandırın:
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-2.0-flash")
.maxOutputTokens(100)
.build();
Çağrılabilen işlevi açıklayan bir araç spesifikasyonu tanımlarsınız:
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();
İşlevin adı, parametrenin adı ve türü tanımlanır. Ancak hem işlevin hem de parametrelerin açıklaması verilir. Açıklamalar çok önemlidir ve LLM'nin bir işlevin ne yapabileceğini gerçekten anlamasına yardımcı olur. Böylece, bu işlevin sohbet bağlamında çağrılması gerekip gerekmediğini değerlendirebilir.
Paris'teki hava durumuyla ilgili ilk soruyu göndererek 1. adıma başlayalım:
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. adımda, modelin kullanmasını istediğimiz aracı iletiyoruz ve model, araç yürütme isteğiyle yanıt veriyor:
// 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. adım: Bu noktada, LLM'nin hangi işlevi çağırmamızı istediğini biliyoruz. Kodda, harici bir API'ye gerçek bir çağrı yapmıyoruz, yalnızca doğrudan varsayımsal bir hava durumu tahmini döndürüyoruz:
// 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. adımda ise LLM, işlev yürütme sonucu hakkında bilgi edinir ve ardından metin yanıtı sentezleyebilir:
// 4) The model answers with a sentence describing the weather
Response<AiMessage> weatherResponse = model.generate(allMessages);
System.out.println("Answer: " + weatherResponse.content().text());
Tam kaynak kodu, app/src/main/java/gemini/workshop dizinindeki FunctionCalling.java içinde yer alır.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.FunctionCalling
Şuna benzer bir çıkış alırsınız:
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.
Yukarıdaki çıktıda, araç yürütme isteğini ve yanıtı görebilirsiniz.
12. LangChain4j, işlev çağrısını yönetir
Önceki adımda, normal metin sorusu/yanıtı ile işlev isteği/yanıtı etkileşimlerinin nasıl iç içe geçtiğini görmüştünüz. Bu etkileşimlerin arasında, gerçek bir işlevi çağırmadan istenen işlev yanıtını doğrudan sağladınız.
Ancak LangChain4j, işlev çağrılarını sizin için şeffaf bir şekilde işleyebilen ve görüşmeyi her zamanki gibi yürütebilen daha üst düzey bir soyutlama da sunar.
Tek işlev çağrısı
FunctionCallingAssistant.java kodunu parça parça inceleyelim.
Öncelikle, işlevin yanıt veri yapısını temsil edecek bir kayıt oluşturursunuz:
record WeatherForecast(String location, String forecast, int temperature) {}
Yanıtta konum, tahmin ve sıcaklık hakkında bilgiler yer alır.
Ardından, modelde kullanılabilir hale getirmek istediğiniz gerçek işlevi içeren bir sınıf oluşturursunuz:
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);
}
}
}
Bu sınıfın tek bir işlev içerdiğini ancak modelin çağırmayı isteyebileceği işlevin açıklamasına karşılık gelen @Tool ek açıklamasıyla notlandırıldığını unutmayın.
İşlevin parametreleri (burada tek bir parametre var) de açıklama eklenir ancak bu kısa @P açıklamasıyla birlikte eklenir. Bu açıklama, parametrenin tanımını da verir. Daha karmaşık senaryolarda modelin kullanabilmesi için istediğiniz sayıda işlev ekleyebilirsiniz.
Bu sınıfta bazı hazır yanıtlar döndürüyorsunuz ancak gerçek bir harici hava durumu tahmini hizmetini çağırmak istiyorsanız bu hizmeti çağırma işlemini bu yöntemin gövdesinde yaparsınız.
Önceki yaklaşımda ToolSpecification oluştururken gördüğümüz gibi, bir fonksiyonun ne yaptığını belgelemek ve parametrelerin neye karşılık geldiğini açıklamak önemlidir. Bu, modelin bu işlevin nasıl ve ne zaman kullanılabileceğini anlamasına yardımcı olur.
Ardından, LangChain4j, modelle etkileşim kurmak için kullanmak istediğiniz sözleşmeye karşılık gelen bir arayüz sağlamanıza olanak tanır. Burada, kullanıcı mesajını temsil eden bir dizeyi alan ve modelin yanıtına karşılık gelen bir dize döndüren basit bir arayüz kullanılıyor:
interface WeatherAssistant {
String chat(String userMessage);
}
Daha karmaşık durumları ele almak istiyorsanız LangChain4j'nin UserMessage (kullanıcı mesajı için) veya AiMessage (model yanıtı için) içeren ya da hatta TokenStream içeren daha karmaşık imzalar da kullanabilirsiniz. Çünkü bu daha karmaşık nesneler, kullanılan jeton sayısı gibi ek bilgiler de içerir. Ancak basitlik adına yalnızca giriş olarak dize ve çıkış olarak dize alacağız.
Tüm parçaları bir araya getiren main() yöntemiyle bitirelim:
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-2.0-flash")
.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?"));
System.out.println(assistant.chat("Is it warmer in London or in Paris?"));
}
Gemini sohbet modelini her zamanki gibi yapılandırın. Ardından, modelin çağırmamızı isteyeceği "işlevi" içeren hava durumu tahmini hizmetinizi örneklendirirsiniz.
Şimdi sohbet modelini, sohbet belleğini ve aracı (ör. işleviyle birlikte hava durumu tahmini hizmeti) bağlamak için AiServices sınıfını tekrar kullanıyorsunuz. AiServices, tanımladığınız WeatherAssistant arayüzünü uygulayan bir nesne döndürür. Geriye yalnızca söz konusu asistanın chat() yöntemini çağırmak kalır. Bu işlevi çağırdığınızda yalnızca metin yanıtlarını görürsünüz. Ancak işlev çağrısı istekleri ve işlev çağrısı yanıtları geliştirici tarafından görünmez. Bu istekler otomatik ve şeffaf bir şekilde işlenir. Gemini bir işlevin çağrılması gerektiğini düşünürse işlev çağrısı isteğiyle yanıt verir ve LangChain4j, yerel işlevi sizin adınıza çağırır.
Örneği çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.FunctionCallingAssistant
Şuna benzer bir çıkış alırsınız:
OK. The weather in Paris is sunny with a temperature of 20 degrees.
It is warmer in Paris (20 degrees) than in London (15 degrees).
Bu, tek bir işlev örneğiydi.
Birden fazla işlev çağrısı
Ayrıca birden fazla işleviniz olabilir ve LangChain4j'nin sizin adınıza birden fazla işlev çağrısını işlemesine izin verebilirsiniz. Birden fazla işlev örneği için MultiFunctionCallingAssistant.java bölümüne bakın.
Para birimlerini dönüştürme işlevi vardır:
@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;
}
Bir hissenin değerini almak için kullanılan başka bir işlev:
@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;
}
Belirli bir tutara yüzde uygulamak için kullanabileceğiniz başka bir işlev:
@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;
}
Ardından, tüm bu işlevleri ve bir MultiTools sınıfını birleştirip "AAPL hisse senedi fiyatının% 10'u, USD'den EUR'ya dönüştürüldüğünde ne kadar eder?" gibi sorular sorabilirsiniz.
public static void main(String[] args) {
ChatLanguageModel model = VertexAiGeminiChatModel.builder()
.project(System.getenv("PROJECT_ID"))
.location(System.getenv("LOCATION"))
.modelName("gemini-2.0-flash")
.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?"));
}
Aşağıdaki şekilde çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.MultiFunctionCallingAssistant
Aşağıdaki işlevlerin çağrıldığını görmeniz gerekir:
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.
Temsilcilere Yönelik
İşlev çağrısı, Gemini gibi büyük dil modelleri için harika bir uzantı mekanizmasıdır. Bu sayede, genellikle "aracı" veya "yapay zeka asistanı" olarak adlandırılan daha karmaşık sistemler oluşturabiliriz. Bu aracılar, harici API'ler aracılığıyla dış dünyayla ve dış ortamda yan etkileri olabilecek hizmetlerle (ör. e-posta gönderme, bilet oluşturma vb.) etkileşimde bulunabilir.
Bu tür güçlü temsilciler oluştururken sorumluluk bilinciyle hareket etmeniz gerekir. Otomatik işlemler yapmadan önce insan müdahalesini göz önünde bulundurmalısınız. Dış dünyayla etkileşime giren LLM destekli aracıları tasarlarken güvenliği göz önünde bulundurmak önemlidir.
13. Gemma'yı Ollama ve TestContainers ile çalıştırma
Şimdiye kadar Gemini'ı kullandık ancak küçük kardeş modeli Gemma da var.
Gemma, Gemini modellerini oluşturmak için kullanılan aynı araştırma ve teknolojiyle geliştirilmiş, hafif ve son teknoloji açık model ailesidir. En yeni Gemma modeli, dört boyutta sunulan Gemma3'tür: 1B (yalnızca metin), 4B, 12B ve 27B. Ağırlıkları ücretsiz olarak kullanılabilir ve küçük boyutları sayesinde kendi başınıza, hatta dizüstü bilgisayarınızda veya Cloud Shell'de bile çalıştırabilirsiniz.
Gemma'yı nasıl çalıştırıyorsunuz?
Gemma'yı bulutta, Vertex AI aracılığıyla tek bir düğmeyle veya GKE ile bazı GPU'larla çalıştırabilirsiniz. Ayrıca yerel olarak da çalıştırabilirsiniz.
Gemma'yı yerel olarak çalıştırmak için iyi bir seçenek olan Ollama, Llama ve Mistral gibi küçük modelleri yerel makinenizde çalıştırmanıza olanak tanır. Docker'a benzer ancak LLM'ler için kullanılır.
İşletim sisteminize yönelik talimatları uygulayarak Ollama'yı yükleyin.
Linux ortamı kullanıyorsanız Ollama'yı yükledikten sonra etkinleştirmeniz gerekir.
ollama serve > /dev/null 2>&1 &
Yerel olarak yükledikten sonra bir modeli çekmek için komutlar çalıştırabilirsiniz:
ollama pull gemma3:1b
Modelin çekilmesini bekleyin. Bu işlem biraz zaman alabilir.
Modeli çalıştırın:
ollama run gemma3:1b
Artık modelle etkileşim kurabilirsiniz:
>>> Hello! Hello! It's nice to hear from you. What can I do for you today?
İstemden çıkmak için Ctrl+D tuşlarına basın.
TestContainers'da Ollama ile Gemma'yı çalıştırma
Ollama'yı yerel olarak yükleyip çalıştırmak yerine TestContainers tarafından işlenen bir container içinde kullanabilirsiniz.
TestContainers yalnızca test için değil, container'ları yürütmek için de kullanışlıdır. Hatta yararlanabileceğiniz özel bir OllamaContainer bile var.
İşte tüm resim:

Uygulama
GemmaWithOllamaContainer.java kodunu parça parça inceleyelim.
İlk olarak, Gemma modelini çeken türetilmiş bir Ollama kapsayıcısı oluşturmanız gerekir. Bu resim, önceki bir çalıştırmadan zaten mevcut veya oluşturulacak. Resim zaten varsa TestContainers'a varsayılan Ollama resmini Gemma destekli varyantınızla değiştirmek istediğinizi söylemeniz yeterlidir:
private static final String TC_OLLAMA_GEMMA3 = "tc-ollama-gemma3-1b";
public static final String GEMMA_3 = "gemma3:1b";
// Creating an Ollama container with Gemma 3 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_GEMMA3)
.exec();
if (listImagesCmd.isEmpty()) {
System.out.println("Creating a new Ollama container with Gemma 3 image...");
OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.7.1");
System.out.println("Starting Ollama...");
ollama.start();
System.out.println("Pulling model...");
ollama.execInContainer("ollama", "pull", GEMMA_3);
System.out.println("Committing to image...");
ollama.commitToImage(TC_OLLAMA_GEMMA3);
return ollama;
}
System.out.println("Ollama image substitution...");
// Substitute the default Ollama image with our Gemma variant
return new OllamaContainer(
DockerImageName.parse(TC_OLLAMA_GEMMA3)
.asCompatibleSubstituteFor("ollama/ollama"));
}
Ardından, bir Ollama test kapsayıcısı oluşturup başlatır ve kullanmak istediğiniz modeli içeren kapsayıcının adresini ve bağlantı noktasını belirterek bir Ollama sohbet modeli oluşturursunuz. Son olarak, her zamanki gibi model.generate(yourPrompt) öğesini çağırın:
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_3)
.build();
String response = model.generate("Why is the sky blue?");
System.out.println(response);
}
Aşağıdaki şekilde çalıştırın:
./gradlew run -q -DjavaMainClass=gemini.workshop.GemmaWithOllamaContainer
İlk çalıştırma sırasında kapsayıcının oluşturulması ve çalıştırılması biraz zaman alır. Ancak işlem tamamlandığında Gemma'nın yanıt verdiğini görürsünüz:
INFO: Container ollama/ollama:0.7.1 started in PT7.228339916S
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.
Gemma'yı Cloud Shell'de çalıştırıyorsunuz.
14. Tebrikler
Tebrikler! LangChain4j ve Gemini API'yi kullanarak Java'da ilk üretken yapay zeka sohbet uygulamanızı başarıyla oluşturdunuz. Bu süreçte, çok formatlı büyük dil modellerinin oldukça güçlü olduğunu ve soru/yanıt gibi çeşitli görevleri kendi belgelerinizde bile yerine getirebildiğini, veri ayıklama, harici API'lerle etkileşim kurma gibi işlemleri yapabildiğini keşfettiniz.
Yapabilecekleriniz
Uygulamalarınızı güçlü LLM entegrasyonlarıyla geliştirme sırası sizde!
Daha fazla bilgi
- Üretken yapay zekanın yaygın kullanım alanları
- Üretken yapay zeka ile ilgili eğitim kaynakları
- Üretken Yapay Zeka Studio aracılığıyla Gemini ile etkileşim kurma
- Sorumlu Yapay Zeka