Ana içeriğe geç

LangChain4j Araç Tabanlı Bellek Eğitimi: Oracle AI Database ile Java Aracısı Oluşturun

Konuşmalar arasında önemli notları hatırlayabilen basit bir LangChain4j aracısını nasıl oluşturacağınızı öğrenin.
· 8 dk. oku

Yapay Zeka ile Keşfedin

Bu eğitimde, özel araçlar sunan, notları JSON olarak Oracle AI Database içinde depolayan ve tam metin aramayla geri alan küçük bir Java modülünü adım adım inceleyeceğiz.

Yapay zekâ aracıları geliştiriyorsanız, kısa süreli sohbet geçmişi genellikle yeterli olmaz. Gerçek asistanların, önemli bilgileri saklayıp daha sonra geri çağırabilmeleri için az miktarda kalıcı belleğe ihtiyaçları olur.

Bu eğitim, bu deseni minimal bir Java modülüyle nasıl kuracağınızı gösterir. LangChain4j araçlarını, basit bir aracı arayüzünü ve arka uç mağazası olarak Oracle AI Database’i kullanacaksınız. Gömme vektörler veya tam bir getirme hattı eklemek yerine, bu örnek tasarımı bilerek küçük tutar: notlar JSON belgeleri olarak kaydedilir ve Oracle Text ile aranır.

Sonunda, modülün şu bileşenleri nasıl bir araya getirdiğini anlayacaksınız:

  • Bir LangChain4j aracı arayüzü
  • İki özel @Tool yöntemi
  • Kalıcı not depolama için bir JDBC deposu
  • Tüm akışı birleştiren bir konsol uygulaması

LangChain4j Araç Tabanlı Bellek Nedir?

LangChain4j, modele dış yeteneklere ihtiyaç duyduğunda çağırabileceği araçlar olarak sıradan Java yöntemlerini açığa çıkarmanızı sağlar. Bu modülde bu yetenekler bellek odaklıdır:

  • searchMemories(String question) ilgili kaydedilmiş notları bulur
  •  storeMemory(String note) yeni bir kalıcı not yazar

Bu, sohbet mesajlarını bellek içi bağlam penceresinde tutan standart sohbet geçmişinden farklıdır.

Kalıcı araç tabanlı bellek ne zaman arama yapması veya not depolaması gerektiğine karar verir ve alttaki veriler bir veritabanında yaşar.

Bu desen, bir aracının olay notları, çalışma kılavuzu hatırlatmaları veya takip aksiyonları gibi bilgileri fazla erken büyük bir getirme sistemi kurmadan hatırlamasını istediğinizde faydalıdır. 

Kalıcı, veritabanı destekli bellek, veri çekişmesi olmadan bir veya daha fazla aracı tarafından eşzamanlı olarak da erişilebilir.

Bir kullanıcı isteğinin LangChain4j asistanına ulaşıp Oracle AI Database'te kalıcı JSON notları aradıktan veya depoladıktan sonra özlü bir yanıt döndürdüğünü gösteren akış.

Araç tabanlı bellek, asistanın mevcut notları getirmesine veya yeni notları kalıcı bir veritabanına depolamasına olanak tanır.

LangChain4j ve Oracle AI DB Modülünün Temel Özellikleri

Bu örnek küçük olsa da birkaç önemli aracı tasarım fikrini gösterir.

Özel LangChain4j araçları

MemoryTools sınıfı, @Tool ile açıklanmış iki yöntemi açığa çıkarır. Bu, LangChain4j’in ilave sarmalayıcı koda gerek kalmadan bunları aracıya sunabilmesi anlamına gelir.

// Retrieve relevant notes and format them for the assistant.
 @Tool(
     	"Search saved memory notes when earlier context might help answer the user."
 )
 public String searchMemories(String question) {
 	List<MemoryRepository.Note> matches = repository.search(question, 3);
 	if (matches.isEmpty()) {
     	return "No saved memory matched that question.";
 	}

 	StringBuilder builder = new StringBuilder();
 	for (int i = 0; i < matches.size(); i++) {
     	MemoryRepository.Note note = matches.get(i);
     	builder.append(i + 1)
             	.append(". [M")
             	.append(note.id())
             	.append("] ")
             	.append(note.text());
     	if (i + 1 < matches.size()) {
         	builder.append('\n');
     	}
 	}
 	return builder.toString();
 }

Bu yöntem iki faydalı iş yapar. Getirmeyi depoya devreder ve sonuçları modele uygun bir biçimde, örneğin [M12] some note text şeklinde biçimlendirir. 

Bu da araç çıktısını, aracının nihai yanıtında alıntı yapmasını kolaylaştırır.

Oracle AI Database’te kalıcı bellek

Notlar, yerel JSON belgeleri olarak agent_memories tablosunda depolanır. Her satır şunları içerir:

  • Bir kimlik sütunu id
  • memory_doc adlı bir JSON sütunu
  • Bir created_at zaman damgası

Modül şemayı otomatik olarak başlatır:

-- Create a JSON-backed table for durable agent notes.
 CREATE TABLE IF NOT EXISTS agent_memories (
 	id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
 	memory_doc JSON NOT NULL,
 	created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
 )

Bu, depolama modelini basit tutarken yine de size yapılandırılmış veri ve veritabanı tarafından yönetilen dayanıklılık sağlar.

Oracle Text ile anahtar kelime arama

Depo, gömme vektörler üretmez. Bunun yerine, kullanıcının sorusundan anahtar kelimeleri çıkarır, durak sözcükleri kaldırır, ACCUM ile bir Oracle Text ifadesi oluşturur ve JSON belge içeriğini json_textcontains ile arar.

Bu, özellikle CHG2145 gibi tanımlayıcılar ve operasyonel terimler için faydalıdır; burada tam veya tama yakın token eşleşmesi, çoğu zaman anlamsal benzerlikten daha önemlidir.

Asgari bir konsol iş akışı

Application sınıfı depoyu oluşturur, şemayı başlatır, birkaç not ekler, sohbet modelini kurar ve bir terminal döngüsü başlatır. Bu, örneği çalıştırmayı kolaylaştırır ve daha sonra başka bir hizmete uyarlamayı basit kılar.

LangChain4j Bellek Projenize Başlarken

Modülü çalıştırmadan önce, yerel ortamınızın projenin gereksinimlerini karşıladığından emin olun.

Önkoşullar

Gerekenler:

  • Java 21 veya üstü
  • Maven 3.9 veya üstü
  • Yerel veya uzaktan çalışan Oracle AI Database Free
  • Bir OPENAI_API_KEY ortam değişkeni

Maven projesi şu bağımlılıklara dayanır:

  • langchain4j
  • langchain4j-open-ai
  • ojdbc11
  • Entegrasyon testleri için JUnit ve Testcontainers

Örneği çalıştırın

Önce OpenAI API anahtarınızı ayarlayın:

# Set the API key used by the chat model.
 export OPENAI_API_KEY=<your key>

Ardından uygulamayı proje dizininden çalıştırın:

# Compile and run the sample with the database connection details.
 mvn compile exec:java \
     -Dexec.args="jdbc:oracle:thin:@localhost:1521/freepdb1 testuser testpwd"

Uygulama tam olarak üç argüman bekler:

1. JDBC URL

2. Veritabanı kullanıcı adı

3. Veritabanı parolası

Bunlar eksikse, Application.main() bir IllegalArgumentException fırlatır. OPENAI_API_KEY eksikse, IllegalStateException fırlatır.

Başlangıçta ne olur

Uygulama başladığında şunları yapar:

1. Bir MemoryRepository oluşturur

2. Veritabanı şemasını başlatır

3. Tablo boşsa üç örnek not ekler

4. Bir OpenAiChatModel oluşturur

5. Modeli ve araçları AiServices içine bağlar

6. exit yazana kadar kullanıcı girdisini okuyan bir CLI döngüsü başlatır

Bu, satırları önceden elle eklemeden bellek getirmeyi hemen deneyebileceğiniz anlamına gelir.

LangChain4j ile Bellek Etkin Java Aracısı Nasıl Oluşturulur

Şimdi modülü, uygulamanın kullandığı sırayla birlikte inceleyelim.

Aracı arayüzünü tanımlayın

LangChain4j, aracı sözleşmesini tanımlamak için bir Java arayüzü kullanır. Bu projede o arayüz MemoryAssistant’tır.

// Define the interface that receives each user message.
 public interface MemoryAssistant {

 	@SystemMessage("""
         	You are a simple assistant with access to durable memory notes.
         	Use searchMemories when earlier notes might help answer the user.
         	If the user explicitly asks you to remember something for later, call storeMemory.
         	Keep answers concise.
         	""")
 	@UserMessage("{{message}}")
 	String chat(@V("message") String message);
 }

Buradaki önemli kısım sistem mesajıdır. Modele her aracı ne zaman kullanacağını söyler:

  • Önceki notlar yardımcı olabilecekse ara
  • Kullanıcı asistanın bir şeyi daha sonra hatırlamasını açıkça isterse depola

Bu, hafif bir araç politikası için iyi bir örnektir. İstem kısa ama araç seçimini yönlendirecek kadar belirgindir.

Bellek işlemlerini araç olarak açığa çıkarın

Aracı doğrudan depoyla konuşmaz. Bunun yerine MemoryTools katmanını çağırır.

İşte depolama yöntemi:

// Save a note and return its generated memory identifier.
 @Tool(
     	"Store a new memory note when the user asks you to remember something "
             	+ "important for later."
 )
 public String storeMemory(String note) {
 	long id = repository.store(note);
 	return "Stored memory M" + id + ".";
 }

Bu bilerek derli topludur. Bir kullanıcı şöyle diyebilir:

Remember that the next shift should verify the checkout retry queue stays below 50.

Model sistem istemini doğru izlerse, storeMemory() çağrılır, depo notu kalıcılaştırır ve araç aşağıdakine benzer bir yanıt döndürür:

Stored memory M4.

Daha sonra kullanıcı şunu sorabilir:

What should the next shift verify?

Bu noktada aracı searchMemories() çağrısını yapabilir ve döndürülen notu kullanarak yanıt verebilir.

Depo katmanını oluşturun

Kalıcı bellek mantığının çoğu depoda yaşar. Yine de dümdüz JDBC’dir; bu da tasarımı incelemeyi kolaylaştırır.

Yüksek seviyede, MemoryRepository şunlardan sorumludur:

  • Şema oluşturma
  • İsteğe bağlı tohumlama
  • Not ekleme
  • Anahtar kelime çıkarma
  • Oracle Text araması
  • Kullanışlı anahtar kelime yoksa yakın tarihli notların geri dönüş getirilmesi

Ekleme yolu, depolamadan önce not metnini normalize eder ve doğrular:

// Normalize the note, store its JSON document, and return the generated ID.
 public long store(String note) {
 	String normalized = normalizeNote(note);
 	Instant createdAt = Instant.now();
 	try (
         	Connection connection = dataSource.getConnection();
         	PreparedStatement statement = connection.prepareStatement(
                 	INSERT_SQL,
                 	new String[]{"id"})
 	) {
     	statement.setObject(
             	1,
                 toJsonDocument(normalized, createdAt),
             	OracleTypes.JSON
     	);
     	statement.setTimestamp(2, Timestamp.from(createdAt));
     	statement.executeUpdate();
     	try (ResultSet keys = statement.getGeneratedKeys()) {
         	if (keys.next()) {
             	return keys.getLong(1);
         	}
     	}
     	throw new IllegalStateException(
             	"No generated id returned for stored memory."
     	);
 	} catch (SQLException e) {
     	throw new RuntimeException("Failed to store memory", e);
 	}
 }

JSON belgesinin kendisi şöyle görünür:

{
 	"noteText": "Runbook note: use section 3 to validate checkout recovery after a rollback.",
 	"createdAt": "2026-04-27T17:00:00Z"
 }

Bu yapı basittir, ancak hem kalıcılığı hem de metin aramasını desteklemek için yeterlidir.

Arama stratejisini anlayın

Depodaki en ilginç kısım search() yöntemidir:

// Search by extracted keywords or fall back to recent notes.
 public List<Note> search(String question, int maxResults) {
 	List<String> keywords = extractKeywords(question);
 	if (keywords.isEmpty()) {
     	return findRecent(maxResults);
 	}
 	return textSearch(buildTextExpression(keywords), maxResults);
 }

Bu yöntem pratik bir akışı takip eder:

1. Kullanıcı sorusunu token’lara ayırın

2. Token’ları küçük harfe çevirin

3. the, what ve remember gibi durak sözcükleri kaldırın

4. Rakam içerdiklerinde anlamlı kısa token’ları koruyun

5. ACCUM ile bir Oracle Text ifadesi oluşturun

6. JSON verisini json_textcontains ile arayın

Bu “rakamlar serbest” detayı önemlidir. CHG2145 gibi terimlerin anahtar kelime çıkarımından sağ çıkmasına yardımcı olur; bu da birçok operasyonel aracının ihtiyaç duyduğu tanımlayıcı ağırlıklı aramaların tam kendisidir.

Bir kullanıcı sorusundan anahtar kelime çıkarımı, durak sözcük kaldırma, bir ACCUM ifadesi ve json_textcontains üzerinden derecelendirilmiş bellek notlarına giden altı adımlı akış.

Arama iş akışı, bir soruyu anahtar kelime ifadesine dönüştürür ve derecelendirilmiş bellek notları döndürür.

SQL arama sorgusu şöyledir:

-- Rank matching notes by Oracle Text relevance.
 SELECT id,
    	JSON_VALUE(
        	memory_doc,
        	'$.noteText' RETURNING VARCHAR2(2000 CHAR)
    	) AS note_text,
    	created_at,
    	SCORE(1) AS text_score
 FROM agent_memories
 WHERE JSON_TEXTCONTAINS(memory_doc, '$', ?, 1)
 ORDER BY SCORE(1) DESC, id DESC
 FETCH FIRST ? ROWS ONLY

Soru kullanışlı anahtar kelimeler üretmiyorsa, depo yakın tarihli notlara geri döner. Bu, aracının çok erken boş bir arama döndürmesi yerine makul bir varsayılan sağlar.

Her şeyi uygulamada bir araya getirin

Uygulama parçaları AiServices.builder() ile bir araya getirir:

// Build the chat model, then attach the memory tools to the assistant.
 ChatModel chatModel = OpenAiChatModel.builder()
     	.apiKey(apiKey)
         .modelName("gpt-5-nano")
     	.build();

 MemoryAssistant assistant = AiServices.builder(MemoryAssistant.class)
     	.chatModel(chatModel)
     	.tools(new MemoryTools(repository))
     	.build();

Tüm desen tek yerde şöyledir:

  • Bir sohbet modeli oluşturun
  • Araç yöntemlerini açığa çıkarın
  • Bu araçları arayüz odaklı bir aracıya bağlayın

Bundan sonra, konsol döngüsü kullanıcı girdisini assistant.chat(input) içine iletir.

Demo istemlerini deneyin

Uygulama birkaç başlangıç istemini yazdırır:

What do we know about CHG2145?
 Remember that the next shift should verify the checkout retry queue stays below 50.
 What should the next shift verify?

Bu istemler, tüm bellek yaşam döngüsünü çalıştırdıkları için faydalıdır:

  • Mevcut bir tohumlanmış notu getirin
  • Yeni bir not depolayın
  • Daha sonra yeni depolanan notu geri çağırın

İpuçları ve Sorun Giderme

Bu modül bilerek dar tutulmuştur; bu da deseni öğrenirken bir güçtür. Yine de akılda tutulması gereken birkaç pratik detay vardır.

Araç talimatlarını açık tutun

Sistem istemi, modele yalnızca kullanıcı açıkça istediğinde bellek depolamasını söyler. Bu, kazara yazımları azaltmaya yardımcı olur. İstemi dikkatsizce genişletirseniz, model düşük değerli notları kalıcılaştırmaya başlayabilir.

Bunu tam bilgi getirme değil, kalıcı not belleği olarak ele alın

Bu depo, kısa operasyonel notlar, hatırlatmalar ve tanımlayıcılar için en iyisidir. Henüz gömme vektörler, parçalama, hibrit arama veya sıralama içeren tam bir getirme destekli üretim sistemi değildir.

Tanımlayıcılar önemliyse Oracle Text kullanın

Olay kimlikleri, bilet numaraları ve değişiklik talebi referansları gibi dizgeler için anahtar kelime odaklı getirme, çoğu zaman anlamsal aramadan daha iyi bir başlangıçtır. Bu örnek, bu tercihi net şekilde yansıtır.

Veritabanı ve Docker kurulumunuzu ayrı doğrulayın

Projenin testleri, Testcontainers tarafından çalıştırılan entegrasyon testleridir. Docker mevcut değilse, mvn test depo mantığı çalışmadan önce başarısız olur. Bu bir ortam sorunudur; mutlaka bir uygulama hatası değildir.

Testleri şöyle çalıştırın:

# Run the integration tests.
 mvn test

Testler iki önemli davranışı kapsar:

  • Notlar depo üzerinden depolanabilir ve geri alınabilir
  • Araç çıktısı bellek kimliklerini ve ilgili not metnini içerir

Daha fazla bellek özelliği eklemeden önce basit başlayın

Aracı projelerinde yaygın bir hata; vektör depolama, konuşma geçmişi, özetleme ve getirme politikalarını aynı anda eklemektir. Bu örnek daha iyi bir ilerleyiş gösterir:

1. Somut bir bellek kullanım senaryosu tanımlayın

2. Açık araçlar sunun

3. Bu araçları kalıcı depolamayla destekleyin

4. Getirme davranışını doğrulayın

5. Ancak ondan sonra daha gelişmiş bellek desenlerini düşünün

Öğrenmeye Devam Edin

Bu eğitimden sonra aracı becerilerinizi geliştirmeye devam etmek istiyorsanız, şu DataCamp kaynakları iyi birer sonraki adımdır:

Sonuç

LangChain4j, Java ve Oracle AI Database ile küçük ama işe yarar, bellek özellikli bir aracı nasıl oluşturacağınızı artık gördünüz. Temel fikir basittir: modele açık bellek araçları verin, notları JSON olarak kalıcı biçimde depolayın ve bunları yalın bir arama stratejisiyle geri alın.

Bu tasarım güçlü bir temeldir; çünkü anlaması ve genişletmesi kolaydır. Bu desen çalıştıktan sonra, daha iyi filtreleme, daha zengin not şemaları, kullanıcı kapsamı veya kullanım durumu gerektiriyorsa vektör arama gibi özellikler ekleyebilirsiniz.

Aracı tasarımı hakkında öğrenmeye devam etmek istiyorsanız, bir sonraki iyi adım bu araç tabanlı bellek desenini daha geniş aracı çerçeveleri ve orkestrasyon iş akışları ile karşılaştırmaktır. Özellikle, açık araçların, getirme desenlerinin ve çok adımlı aracıların daha büyük yapay zekâ sistemlerinde nasıl bir araya geldiğini keşfetmeye değer.

FAQs

Bu eğitim hangi tür belleği uygular?

Bu eğitim, araç tabanlı kalıcı belleği uygular. Notlar, istem penceresine otomatik olarak eklenmek yerine açık araç çağrılarıyla bir veritabanı tablosunda depolanır ve geri alınır.

Bu proje vektör gömmeleri kullanıyor mu?

Hayır. Bu örnek bilerek gömme vektörleri, vektör araması ve yeniden sıralamadan kaçınır. Not içeriğini aramak için Oracle Text ile json_textcontains kullanır.

Neden her şeyi sohbet geçmişinde tutmak yerine bellek için araçlar kullanılıyor?

Araç tabanlı bellek; neyin, ne zaman depolandığı ve nasıl geri alındığı üzerinde daha fazla kontrol sağlar. Ayrıca tek bir konuşmanın ötesinde kalması gereken kalıcı notlar için daha iyi çalışır.

Canlı demoyu çalıştırmak için neye ihtiyacım var?

Canlı demoyu çalıştırmak için Java 21 veya üstü, Maven 3.9 veya üstü, Oracle AI Database erişimi ve kabuğunuzda bir OPENAI_API_KEY gerekir.

Testler Docker gerektiriyor mu?

Evet. Entegrasyon testleri, Testcontainers kullanarak Oracle AI Database Free’i başlatır; bu nedenle ortamınızda Docker mevcut olmalıdır.

Anders Swanson

Yazar

Anders Swanson

Oracle'da Geliştirici Elçisi olarak, mikro hizmetler, olay odaklı sistemler, bulut yerlisi mimariler ve daha fazlası dahil olmak üzere geliştiricilerin modern uygulamalar oluşturmasına yardımcı oluyorum. Kubernetes, Spring Boot veya Kafka gibi araçlarla çalışıyor ve Oracle'ın bu dünyaya nasıl uyduğunu merak ediyorsanız, devreye ben giriyorum.Amacım, daha hızlı geliştirmenize, daha akıllıca yayınlamanıza ve Oracle'ın veritabanı teknolojisinden en iyi şekilde yararlanmanıza yardımcı olan pratik, uygulamalı rehberlik sunmak. JSON, olay akışı, vektör arama kullanıyorsanız ya da sadece nereden başlayacağınızı anlamaya çalışıyorsanız, işleri daha net ve geliştirici dostu hale getirmek için buradayım.

Konular

İlgili