Chuyển đến nội dung chính

Hướng dẫn LangChain4j Tool Memory: Xây dựng Agent Java với Oracle AI Database

Tìm hiểu cách xây dựng một agent LangChain4j đơn giản có thể ghi nhớ các ghi chú quan trọng xuyên suốt nhiều cuộc hội thoại.
· 8 phút đọc

Khám phá cùng AI

Trong hướng dẫn này, chúng ta sẽ cùng đi qua một mô-đun Java nhỏ cung cấp các công cụ tùy chỉnh, lưu ghi chú dưới dạng JSON trong Oracle AI Database và truy xuất chúng bằng tìm kiếm toàn văn.

Nếu bạn đang xây dựng agent AI, lịch sử chat ngắn hạn thường là chưa đủ. Trợ lý thực tế thường cần một lượng nhỏ bộ nhớ bền vững để có thể lưu trữ các thông tin quan trọng và truy xuất lại khi cần.

Hướng dẫn này cho thấy cách xây dựng mẫu đó với một mô-đun Java tối giản. Bạn sẽ sử dụng công cụ của LangChain4j, một giao diện agent đơn giản, và Oracle AI Database làm kho lưu trữ. Thay vì thêm embeddings hay cả một pipeline truy xuất, ví dụ này cố ý giữ thiết kế thật nhỏ gọn: ghi chú được lưu dưới dạng tài liệu JSON và tìm kiếm bằng Oracle Text.

Kết thúc, bạn sẽ hiểu cách mô-đun kết nối các phần sau:

  • Một giao diện agent LangChain4j
  • Hai phương thức @Tool tùy chỉnh
  • Kho JDBC để lưu trữ ghi chú bền vững
  • Ứng dụng console kết nối toàn bộ luồng

LangChain4j Tool-Based Memory là gì?

LangChain4j cho phép bạn xuất các phương thức Java thông thường như các công cụ mà mô hình có thể gọi khi cần năng lực bên ngoài. Trong mô-đun này, các năng lực đó hướng vào bộ nhớ:

  • searchMemories(String question) tìm các ghi chú đã lưu có liên quan
  •  storeMemory(String note) ghi một ghi chú bền vững mới

Điều này khác với lịch sử chat tiêu chuẩn vốn lưu tin nhắn trong một cửa sổ ngữ cảnh trên bộ nhớ tạm.

Bộ nhớ bền vững dựa trên công cụ quyết định khi nào cần tìm kiếm hoặc lưu ghi chú, và dữ liệu nền được lưu trong cơ sở dữ liệu.

Mẫu này hữu ích khi bạn muốn agent ghi nhớ các sự kiện như ghi chú sự cố, nhắc nhở runbook, hoặc hành động theo dõi mà chưa cần xây dựng hệ thống truy xuất lớn ngay từ đầu. 

Bộ nhớ bền vững được hỗ trợ bởi cơ sở dữ liệu cũng có thể được truy cập đồng thời bởi một hoặc nhiều agent mà không bị tranh chấp dữ liệu.

Flow showing a user request reaching a LangChain4j assistant, which searches or stores durable JSON notes in Oracle AI Database before returning a concise response.

Bộ nhớ dựa trên công cụ cho phép trợ lý truy xuất ghi chú hiện có hoặc lưu ghi chú mới trong cơ sở dữ liệu bền vững.

Các tính năng chính của mô-đun LangChain4j và Oracle AI DB

Ví dụ này nhỏ, nhưng minh họa một số ý tưởng thiết kế agent quan trọng.

Công cụ LangChain4j tùy chỉnh

Lớp MemoryTools cung cấp hai phương thức có chú thích @Tool. Điều đó có nghĩa LangChain4j có thể cung cấp chúng cho agent mà không cần mã bọc bổ sung.

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

Phương thức này làm hai việc hữu ích. Nó ủy quyền việc truy xuất cho kho (repository), và định dạng kết quả theo cách thân thiện với mô hình như [M12] some note text. 

Điều đó giúp agent dễ dàng trích dẫn đầu ra của công cụ trong câu trả lời cuối cùng.

Bộ nhớ bền vững trong Oracle AI Database

Ghi chú được lưu trong bảng agent_memories dưới dạng tài liệu JSON gốc. Mỗi hàng chứa:

  • Một cột định danh id
  • Một cột JSON tên là memory_doc
  • Dấu thời gian created_at

Mô-đun khởi tạo lược đồ tự động:

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

Điều này giữ mô hình lưu trữ đơn giản nhưng vẫn cung cấp dữ liệu có cấu trúc và độ bền do cơ sở dữ liệu quản lý.

Tìm kiếm từ khóa với Oracle Text

Kho không tạo embeddings. Thay vào đó, nó trích xuất từ khóa từ câu hỏi của người dùng, loại bỏ stop word, xây dựng biểu thức Oracle Text với ACCUM và tìm kiếm nội dung tài liệu JSON bằng json_textcontains.

Điều này đặc biệt hữu ích cho các định danh và thuật ngữ vận hành như CHG2145, nơi việc khớp token chính xác hoặc gần chính xác thường quan trọng hơn tương đồng ngữ nghĩa.

Quy trình console tối giản

Lớp Application tạo kho, khởi tạo lược đồ, gieo một vài ghi chú, dựng mô hình chat và bắt đầu vòng lặp terminal. Điều đó giúp ví dụ dễ chạy và dễ thích ứng thành một dịch vụ khác về sau.

Bắt đầu với dự án bộ nhớ LangChain4j của bạn

Trước khi chạy mô-đun, hãy đảm bảo môi trường cục bộ của bạn khớp với yêu cầu của dự án.

Điều kiện tiên quyết

Bạn cần:

  • Java 21 trở lên
  • Maven 3.9 trở lên
  • Oracle AI Database Free chạy cục bộ hoặc từ xa
  • Biến môi trường OPENAI_API_KEY

Dự án Maven phụ thuộc vào:

  • langchain4j
  • langchain4j-open-ai
  • ojdbc11
  • JUnit và Testcontainers cho kiểm thử tích hợp

Chạy mẫu

Đặt khóa OpenAI API của bạn trước:

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

Sau đó chạy ứng dụng từ thư mục dự á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"

Ứng dụng yêu cầu đúng ba đối số:

1. JDBC URL

2. Tên người dùng cơ sở dữ liệu

3. Mật khẩu cơ sở dữ liệu

Nếu thiếu các tham số đó, Application.main() sẽ ném IllegalArgumentException. Nếu thiếu OPENAI_API_KEY, nó sẽ ném IllegalStateException.

Điều xảy ra khi khởi động

Khi ứng dụng khởi chạy, nó:

1. Tạo một MemoryRepository

2. Khởi tạo lược đồ cơ sở dữ liệu

3. Gieo ba ghi chú mẫu nếu bảng trống

4. Xây dựng một OpenAiChatModel

5. Kết nối mô hình và công cụ vào AiServices

6. Bắt đầu vòng lặp CLI đọc đầu vào người dùng cho đến khi bạn gõ exit

Điều đó có nghĩa bạn có thể thử truy xuất bộ nhớ ngay mà không cần chèn hàng thủ công trước.

Cách xây dựng một agent Java có bộ nhớ với LangChain4j

Giờ hãy đi qua mô-đun theo đúng thứ tự ứng dụng sử dụng.

Định nghĩa giao diện agent

LangChain4j sử dụng một giao diện Java để mô tả hợp đồng của agent. Trong dự án này, giao diện đó là MemoryAssistant.

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

Phần quan trọng là thông điệp hệ thống. Nó cho mô hình biết khi nào dùng từng công cụ:

  • Tìm kiếm khi các ghi chú trước đó có thể hữu ích
  • Lưu trữ khi người dùng yêu cầu rõ ràng trợ lý ghi nhớ điều gì đó

Đó là một ví dụ tốt về chính sách công cụ gọn nhẹ. Prompt ngắn, nhưng đủ cụ thể để định hướng chọn công cụ.

Cung cấp các thao tác bộ nhớ dưới dạng công cụ

Agent không nói chuyện trực tiếp với kho. Thay vào đó, nó gọi lớp MemoryTools.

Đây là phương thức lưu trữ:

// 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 + ".";
 }

Phần này được cố ý viết gọn. Người dùng có thể nói:

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

Nếu mô hình làm theo prompt hệ thống đúng cách, nó sẽ gọi storeMemory(), kho sẽ ghi bền ghi chú, và công cụ sẽ trả về dạng như:

Stored memory M4.

Sau đó, người dùng có thể hỏi:

What should the next shift verify?

Lúc này, agent có thể gọi searchMemories() và dùng ghi chú trả về để trả lời.

Tạo lớp kho (repository)

Kho là nơi chứa phần lớn logic bộ nhớ bền vững. Nó vẫn là JDBC thuần túy, giúp thiết kế dễ kiểm tra.

Ở mức cao, MemoryRepository chịu trách nhiệm:

  • Tạo lược đồ
  • Gieo dữ liệu tùy chọn
  • Chèn ghi chú
  • Trích xuất từ khóa
  • Oracle Text search
  • Truy xuất dự phòng các ghi chú gần đây khi không có từ khóa hữu ích

Luồng chèn chuẩn hóa và kiểm tra văn bản ghi chú trước khi lưu:

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

Bản thân tài liệu JSON trông như sau:

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

Cấu trúc này đơn giản, nhưng đủ để hỗ trợ cả lưu trữ và tìm kiếm văn bản.

Hiểu chiến lược tìm kiếm

Phần thú vị nhất của kho là phương thức search():

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

Phương thức này làm theo một luồng thực dụng:

1. Tách token câu hỏi của người dùng

2. Chuyển token về chữ thường

3. Loại bỏ stop word như the, what và remember

4. Giữ lại các token ngắn có ý nghĩa khi chúng chứa chữ số

5. Xây dựng biểu thức Oracle Text với ACCUM

6. Tìm kiếm dữ liệu JSON bằng json_textcontains

Chi tiết “cho phép có chữ số” rất quan trọng. Nó giúp các thuật ngữ như CHG2145 sống sót qua bước trích xuất từ khóa, đúng với kiểu tra cứu nhiều định danh mà các agent vận hành thường cần.

Six-step flow from a user question through keyword extraction, stop-word removal, an ACCUM expression, and json_textcontains to ranked memory notes.

Quy trình tìm kiếm chuyển một câu hỏi thành biểu thức từ khóa và trả về các ghi chú bộ nhớ được xếp hạng.

Câu lệnh SQL tìm kiếm là:

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

Nếu câu hỏi không tạo ra từ khóa hữu ích, kho sẽ chuyển sang các ghi chú gần đây. Điều đó cho agent một mặc định hợp lý thay vì trả về tìm kiếm rỗng quá sớm.

Kết nối mọi thứ trong ứng dụng

Ứng dụng kết nối các phần với AiServices.builder():

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

Đây là toàn bộ mẫu ở một nơi:

  • Xây dựng mô hình chat
  • Xuất các phương thức công cụ
  • Gắn các công cụ đó vào một agent dựa trên giao diện

Sau đó, vòng lặp console chỉ việc truyền đầu vào người dùng vào assistant.chat(input).

Thử các prompt demo

Ứng dụng in ra một vài prompt khởi đầu:

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?

Các prompt này hữu ích vì chúng bao trùm toàn bộ vòng đời bộ nhớ:

  • Truy xuất một ghi chú đã gieo sẵn
  • Lưu một ghi chú mới
  • Truy xuất lại ghi chú vừa lưu sau đó

Mẹo và xử lý sự cố

Mô-đun này cố ý hẹp, đây là điểm mạnh khi bạn đang học mẫu. Tuy vậy, có vài chi tiết thực tế cần lưu ý.

Giữ hướng dẫn cho công cụ thật rõ ràng

Prompt hệ thống chỉ dẫn mô hình chỉ lưu bộ nhớ khi người dùng yêu cầu rõ ràng. Điều đó giúp giảm ghi chép ngoài ý muốn. Nếu bạn nới lỏng prompt một cách thiếu cẩn trọng, mô hình có thể bắt đầu lưu những ghi chú giá trị thấp.

Xem đây là bộ nhớ ghi chú bền vững, không phải truy xuất tri thức đầy đủ

Kho này phù hợp nhất cho các ghi chú vận hành ngắn, nhắc nhở và định danh. Nó chưa phải hệ thống RAG đầy đủ với embeddings, chia khối, tìm kiếm lai hay xếp hạng.

Dùng Oracle Text khi định danh là quan trọng

Với các chuỗi như ID sự cố, số ticket và tham chiếu yêu cầu thay đổi, truy xuất theo từ khóa thường là điểm khởi đầu tốt hơn so với tìm kiếm ngữ nghĩa. Ví dụ này phản ánh rõ sự đánh đổi đó.

Xác thực riêng hạ tầng cơ sở dữ liệu và Docker của bạn

Các bài kiểm thử của dự án là kiểm thử tích hợp dùng Testcontainers. Nếu Docker không khả dụng, mvn test sẽ thất bại trước khi logic kho chạy. Đó là vấn đề môi trường, không nhất thiết là lỗi ứng dụng.

Chạy kiểm thử bằng:

# Run the integration tests.
 mvn test

Các bài kiểm thử bao phủ hai hành vi quan trọng:

  • Các ghi chú có thể được lưu và truy xuất qua kho
  • Đầu ra công cụ bao gồm ID bộ nhớ và văn bản ghi chú liên quan

Bắt đầu đơn giản trước khi thêm nhiều tính năng bộ nhớ

Sai lầm phổ biến trong các dự án agent là thêm kho vector, lịch sử hội thoại, tóm tắt và chính sách truy xuất cùng lúc. Ví dụ này cho thấy một lộ trình tốt hơn:

1. Xác định một trường hợp sử dụng bộ nhớ cụ thể

2. Xuất các công cụ rõ ràng

3. Hậu thuẫn các công cụ đó bằng lưu trữ bền vững

4. Xác minh hành vi truy xuất

5. Chỉ sau đó mới cân nhắc các mẫu bộ nhớ nâng cao hơn

Tiếp tục học

Nếu bạn muốn tiếp tục xây dựng kỹ năng về agent sau hướng dẫn này, các tài nguyên DataCamp sau là bước tiếp theo phù hợp:

Kết luận

Bạn vừa thấy cách xây dựng một agent nhỏ nhưng hữu ích có bộ nhớ với LangChain4j, Java và Oracle AI Database. Ý tưởng cốt lõi rất đơn giản: cung cấp cho mô hình các công cụ bộ nhớ rõ ràng, lưu ghi chú bền vững dưới dạng JSON và truy xuất chúng với chiến lược tìm kiếm trực diện.

Thiết kế này là nền tảng vững chắc vì dễ hiểu và dễ mở rộng. Khi mẫu này vận hành tốt, bạn có thể thêm lọc tốt hơn, lược đồ ghi chú phong phú hơn, phạm vi theo người dùng, hoặc thậm chí tìm kiếm vector nếu trường hợp sử dụng yêu cầu.

Nếu bạn muốn tiếp tục tìm hiểu về thiết kế agent, bước tiếp theo tốt là so sánh mẫu bộ nhớ dựa trên công cụ này với các framework agent rộng hơn và quy trình điều phối. Đặc biệt, đáng để khám phá cách các công cụ rõ ràng, mẫu truy xuất và agent đa bước khớp với nhau trong hệ thống AI lớn hơn.

Câu hỏi thường gặp

Hướng dẫn này triển khai loại bộ nhớ nào?

Hướng dẫn này triển khai bộ nhớ bền vững dựa trên công cụ. Ghi chú được lưu trong một bảng cơ sở dữ liệu và được truy xuất qua các lời gọi công cụ rõ ràng thay vì tự động nối vào cửa sổ prompt.

Dự án này có dùng vector embeddings không?

Không. Ví dụ này cố ý tránh embeddings, tìm kiếm vector và reranking. Nó sử dụng Oracle Text cùng json_textcontains để tìm kiếm nội dung ghi chú.

Vì sao dùng công cụ cho bộ nhớ thay vì giữ mọi thứ trong lịch sử chat?

Bộ nhớ dựa trên công cụ giúp bạn kiểm soát tốt hơn những gì được lưu, khi nào lưu và cách truy xuất. Nó cũng phù hợp hơn cho các ghi chú bền vững cần tồn tại lâu hơn một cuộc hội thoại.

Tôi cần gì để chạy bản demo trực tiếp?

Bạn cần Java 21 trở lên, Maven 3.9 trở lên, quyền truy cập Oracle AI Database và một OPENAI_API_KEY trong shell.

Các bài kiểm thử có cần Docker không?

Có. Các kiểm thử tích hợp sử dụng Testcontainers để khởi động Oracle AI Database Free, nên Docker phải khả dụng trong môi trường của bạn.

Anders Swanson

Tác giả

Anders Swanson

Với vai trò Developer Evangelist tại Oracle, tôi hỗ trợ các nhà phát triển xây dựng ứng dụng hiện đại, bao gồm microservices, hệ thống hướng sự kiện, kiến trúc cloud-native và hơn thế nữa. Nếu bạn đang làm việc với các công cụ như Kubernetes, Spring Boot hoặc Kafka và tự hỏi Oracle phù hợp như thế nào trong hệ sinh thái đó, đó chính là nơi tôi có mặt.Mục tiêu của tôi là chia sẻ các hướng dẫn thực tiễn, có thể áp dụng ngay, giúp bạn xây nhanh hơn, phát hành thông minh hơn và tận dụng tối đa công nghệ cơ sở dữ liệu của Oracle. Dù bạn đang dùng JSON, truyền phát sự kiện, tìm kiếm vector hay chỉ mới bắt đầu, tôi ở đây để giúp mọi thứ rõ ràng hơn và thân thiện với nhà phát triển hơn.

Chủ đề

Liên quan