1. Tổng quan
Hãy tưởng tượng bạn bước vào một cửa hàng đồ chơi ảo hoặc trực tiếp, nơi bạn có thể dễ dàng tìm thấy món quà hoàn hảo. Bạn có thể mô tả những gì mình đang tìm kiếm, tải ảnh đồ chơi lên hoặc thậm chí thiết kế đồ chơi của riêng mình. Cửa hàng sẽ ngay lập tức hiểu được nhu cầu của bạn và mang đến trải nghiệm phù hợp. Đây không phải là một viễn cảnh giả tưởng trong tương lai mà là một thực tế được hỗ trợ bởi AI, công nghệ đám mây và tầm nhìn về thương mại điện tử được cá nhân hoá.
Thách thức: Việc tìm được sản phẩm hoàn hảo như bạn tưởng tượng có thể rất khó khăn. Các cụm từ tìm kiếm, từ khoá chung chung và cụm từ tìm kiếm tương tự thường không hiệu quả, việc duyệt qua vô số trang có thể gây nhàm chán và sự khác biệt giữa những gì bạn tưởng tượng và những gì có sẵn có thể khiến bạn thất vọng.
Giải pháp: Ứng dụng minh hoạ này trực tiếp giải quyết thách thức này bằng cách tận dụng sức mạnh của AI để mang lại trải nghiệm liền mạch và thực sự được cá nhân hoá với tính năng tìm kiếm theo bối cảnh và tạo tuỳ chỉnh sản phẩm phù hợp với bối cảnh tìm kiếm.
Sản phẩm bạn sẽ tạo ra
Trong phần này, bạn sẽ:
- Tạo một thực thể AlloyDB và tải Tập dữ liệu đồ chơi
- Bật tiện ích mô hình AI tạo sinh và pgvector trong AlloyDB
- Tạo các vectơ nhúng từ nội dung mô tả sản phẩm và thực hiện tìm kiếm độ tương đồng Cosine theo thời gian thực cho văn bản tìm kiếm của người dùng
- Gọi Gemini 2.0 Flash để mô tả hình ảnh do người dùng tải lên nhằm tìm kiếm đồ chơi theo ngữ cảnh
- Gọi Imagen 3 để tạo đồ chơi tuỳ chỉnh dựa trên mối quan tâm của người dùng
- Gọi một công cụ dự đoán giá được tạo bằng Hộp công cụ AI tạo sinh cho Cơ sở dữ liệu để biết thông tin chi tiết về giá của đồ chơi được tạo tuỳ chỉnh
- Triển khai giải pháp trong các hàm Cloud Run không máy chủ
Yêu cầu
2. Kiến trúc
Luồng dữ liệu: Hãy xem xét kỹ hơn cách dữ liệu di chuyển qua hệ thống của chúng tôi:
- Tìm kiếm theo bối cảnh bằng RAG (Tạo sinh tăng cường khả năng truy xuất) dựa trên AI
Hãy nghĩ như thế này: thay vì chỉ tìm kiếm "ô tô màu đỏ", hệ thống sẽ hiểu những nội dung sau:
"xe nhỏ phù hợp với bé trai 3 tuổi".
AlloyDB làm nền tảng: Chúng tôi sử dụng AlloyDB (cơ sở dữ liệu tương thích với PostgreSQL và được quản lý hoàn toàn của Google Cloud) để lưu trữ dữ liệu về đồ chơi, bao gồm cả nội dung mô tả, URL hình ảnh và các thuộc tính liên quan khác.
pgvector để tìm kiếm ngữ nghĩa: pgvector (một tiện ích PostgreSQL) cho phép chúng ta lưu trữ các giá trị nhúng vectơ của cả nội dung mô tả đồ chơi và cụm từ tìm kiếm của người dùng. Điều này cho phép tìm kiếm ngữ nghĩa, tức là hệ thống hiểu được ý nghĩa đằng sau các từ, chứ không chỉ từ khoá chính xác.
Độ tương đồng cosine để đo mức độ liên quan: Chúng tôi sử dụng độ tương đồng cosine để đo độ tương đồng ngữ nghĩa giữa vectơ tìm kiếm của người dùng và vectơ mô tả đồ chơi, từ đó hiển thị những kết quả phù hợp nhất.
Chỉ mục ScaNN để tăng tốc độ và độ chính xác: Để đảm bảo kết quả nhanh chóng và chính xác, đặc biệt là khi kho đồ chơi của chúng tôi ngày càng lớn, chúng tôi tích hợp chỉ mục ScaNN (Tìm kiếm lân cận có thể mở rộng). Điều này giúp cải thiện đáng kể hiệu quả và khả năng thu hồi của tính năng tìm kiếm vectơ.
- Tìm kiếm và hiểu thông tin dựa trên hình ảnh bằng Gemini 2.0 Flash
Thay vì nhập ngữ cảnh dưới dạng văn bản, giả sử người dùng muốn tải lên hình ảnh của một món đồ chơi quen thuộc mà họ muốn tìm kiếm. Người dùng có thể tải hình ảnh của một món đồ chơi mà họ thích lên và nhận được các tính năng liên quan. Chúng tôi tận dụng mô hình Gemini 2.0 Flash của Google (được gọi bằng LangChain4j) để phân tích hình ảnh và trích xuất ngữ cảnh có liên quan, chẳng hạn như màu sắc, chất liệu, loại và nhóm tuổi dự kiến của đồ chơi.
- Tạo món đồ chơi trong mơ theo ý muốn bằng AI tạo sinh: Imagen 3
Điều kỳ diệu thực sự xảy ra khi người dùng quyết định tạo ra món đồ chơi của riêng mình. Nhờ Imagen 3, chúng tôi có thể cho phép trẻ mô tả món đồ chơi mơ ước bằng câu lệnh văn bản đơn giản. Hãy tưởng tượng bạn có thể nói: "Tôi muốn một con rồng nhồi bông có đôi cánh màu tím và khuôn mặt thân thiện" rồi thấy con rồng đó xuất hiện trên màn hình! Sau đó, Imagen 3 sẽ tạo hình ảnh của món đồ chơi được thiết kế riêng, giúp người dùng hình dung rõ ràng về tác phẩm của họ.
- Dự đoán giá nhờ các tác nhân và Bộ công cụ MCP cho cơ sở dữ liệu
Chúng tôi đã triển khai một tính năng dự đoán giá để ước tính chi phí sản xuất đồ chơi được thiết kế riêng. Tính năng này được hỗ trợ bởi một tác nhân bao gồm công cụ tính giá tinh vi.
Bộ công cụ MCP cho cơ sở dữ liệu: Tác nhân này được tích hợp liền mạch với cơ sở dữ liệu của chúng tôi bằng công cụ nguồn mở mới của Google, Bộ công cụ MCP cho cơ sở dữ liệu. Điều này cho phép trợ lý truy cập vào dữ liệu theo thời gian thực về chi phí vật liệu, quy trình sản xuất và các yếu tố liên quan khác để đưa ra mức giá ước tính chính xác. Đọc thêm về vấn đề này tại đây.
- Java Spring Boot, Gemini Code Assist và Cloud Run để đơn giản hoá quy trình phát triển và triển khai không cần máy chủ
Toàn bộ ứng dụng được xây dựng bằng Java Spring Boot, một khung mạnh mẽ và có khả năng mở rộng. Chúng tôi đã tận dụng Gemini Code Assist trong suốt quá trình phát triển, đặc biệt là đối với quá trình phát triển giao diện người dùng, giúp đẩy nhanh đáng kể chu kỳ phát triển và cải thiện chất lượng mã. Chúng tôi đã sử dụng Cloud Run để triển khai toàn bộ ứng dụng và Cloud Run Functions để triển khai cơ sở dữ liệu và các chức năng dựa trên tác nhân dưới dạng các điểm cuối độc lập.
3. Trước khi bắt đầu
Tạo dự án
- Trong Google Cloud Console, trên trang chọn dự án, hãy chọn hoặc tạo một dự án trên Google Cloud.
- Đảm bảo rằng bạn đã bật tính năng thanh toán cho dự án trên Cloud. Tìm hiểu cách kiểm tra xem tính năng thanh toán có được bật trong một dự án hay không .
- Bạn sẽ sử dụng Cloud Shell, một môi trường dòng lệnh chạy trong Google Cloud và được tải sẵn bq. Nhấp vào Kích hoạt Cloud Shell ở đầu bảng điều khiển Cloud.

- Sau khi kết nối với Cloud Shell, hãy kiểm tra để đảm bảo bạn đã được xác thực và dự án được đặt thành mã dự án của bạn bằng lệnh sau:
gcloud auth list
- Chạy lệnh sau trong Cloud Shell để xác nhận rằng lệnh gcloud biết về dự án của bạn.
gcloud config list project
- Nếu bạn chưa đặt dự án, hãy dùng lệnh sau để đặt:
gcloud config set project <YOUR_PROJECT_ID>
- Bật các API bắt buộc bằng cách chạy lần lượt các lệnh sau trong Cloud Shell Terminal:
Ngoài ra, còn có một lệnh duy nhất để chạy các lệnh bên dưới, nhưng nếu là người dùng tài khoản dùng thử, bạn có thể gặp phải vấn đề về hạn mức khi cố gắng bật các lệnh này hàng loạt. Đó là lý do các lệnh được tách riêng, mỗi lệnh trên một dòng.
gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
gcloud services enable aiplatform.googleapis.com
Bạn có thể thay thế lệnh gcloud bằng cách tìm kiếm từng sản phẩm trên bảng điều khiển hoặc sử dụng đường liên kết này.
Nếu bỏ lỡ API nào, bạn luôn có thể bật API đó trong quá trình triển khai.
Tham khảo tài liệu để biết các lệnh và cách sử dụng gcloud.
4. Thiết lập cơ sở dữ liệu
Trong phòng thí nghiệm này, chúng ta sẽ sử dụng AlloyDB làm cơ sở dữ liệu để lưu trữ dữ liệu của cửa hàng đồ chơi. Nó sử dụng cụm để lưu giữ tất cả các tài nguyên, chẳng hạn như cơ sở dữ liệu và nhật ký. Mỗi cụm có một phiên bản chính cung cấp một điểm truy cập vào dữ liệu. Các bảng sẽ chứa dữ liệu thực tế.
Hãy tạo một cụm, thực thể và bảng AlloyDB nơi tập dữ liệu thương mại điện tử sẽ được tải.
Tạo một cụm và phiên bản
- Chuyển đến trang AlloyDB trong Cloud Console. Một cách dễ dàng để tìm hầu hết các trang trong Cloud Console là tìm kiếm các trang đó bằng thanh tìm kiếm của bảng điều khiển.
- Chọn TẠO CỤM trên trang đó:

- Bạn sẽ thấy một màn hình như màn hình bên dưới. Tạo một cụm và thực thể bằng các giá trị sau (Đảm bảo các giá trị khớp nhau trong trường hợp bạn đang sao chép mã xử lý ứng dụng từ kho lưu trữ):
- mã nhận dạng cụm: "
vector-cluster" - password: "
alloydb" - Tương thích với PostgreSQL 15
- Vùng: "
us-central1" - Mạng: "
default"

- Khi chọn mạng mặc định, bạn sẽ thấy một màn hình như màn hình bên dưới.
Chọn THIẾT LẬP KẾT NỐI.
- Tại đó, hãy chọn "Sử dụng dải IP được phân bổ tự động" rồi chọn Tiếp tục. Sau khi xem xét thông tin, hãy chọn TẠO KẾT NỐI.

- Sau khi thiết lập mạng, bạn có thể tiếp tục tạo cụm. Nhấp vào TẠO CỤM để hoàn tất việc thiết lập cụm như minh hoạ bên dưới:

Hãy nhớ thay đổi mã nhận dạng phiên bản thành
vector-instance
Nếu không thể thay đổi, hãy nhớ thay đổi mã nhận dạng phiên bản trong tất cả các thông tin tham chiếu sắp tới.
Xin lưu ý rằng quá trình tạo Cụm sẽ mất khoảng 10 phút. Sau khi tạo thành công, bạn sẽ thấy một màn hình cho biết thông tin tổng quan về cụm mà bạn vừa tạo.
5. Nhập dữ liệu
Bây giờ, đã đến lúc thêm một bảng có dữ liệu về cửa hàng. Chuyển đến AlloyDB, chọn cụm chính rồi chọn AlloyDB Studio:

Bạn có thể phải đợi phiên bản của mình được tạo xong. Sau khi tạo, hãy đăng nhập vào AlloyDB bằng thông tin đăng nhập mà bạn đã tạo khi tạo cụm. Sử dụng dữ liệu sau để xác thực với PostgreSQL:
- Tên người dùng : "
postgres" - Cơ sở dữ liệu : "
postgres" - Mật khẩu : "
alloydb"
Sau khi bạn xác thực thành công vào AlloyDB Studio, các lệnh SQL sẽ được nhập vào Trình chỉnh sửa. Bạn có thể thêm nhiều cửa sổ Trình chỉnh sửa bằng cách nhấp vào dấu cộng ở bên phải cửa sổ cuối cùng.

Bạn sẽ nhập các lệnh cho AlloyDB trong cửa sổ trình chỉnh sửa, sử dụng các lựa chọn Chạy, Định dạng và Xoá khi cần.
Bật tiện ích
Để tạo ứng dụng này, chúng ta sẽ sử dụng các tiện ích pgvector và google_ml_integration. Tiện ích pgvector cho phép bạn lưu trữ và tìm kiếm các vectơ nhúng. Tiện ích google_ml_integration cung cấp các hàm mà bạn dùng để truy cập vào các điểm cuối dự đoán của Vertex AI nhằm nhận thông tin dự đoán bằng SQL. Bật các tiện ích này bằng cách chạy các DDL sau:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Nếu bạn muốn kiểm tra các tiện ích đã được bật trên cơ sở dữ liệu, hãy chạy lệnh SQL sau:
select extname, extversion from pg_extension;
Tạo bảng
Tạo bảng bằng câu lệnh DDL bên dưới:
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
Khi thực thi thành công lệnh trên, bạn sẽ có thể xem bảng trong cơ sở dữ liệu.
Nhập dữ liệu
Trong phòng thí nghiệm này, chúng ta có dữ liệu kiểm thử gồm khoảng 72 bản ghi trong tệp SQL này. Nó chứa các trường id, name, description, quantity, price, image_url. Các trường khác sẽ được điền vào sau trong phòng thí nghiệm.
Chỉ sao chép 5 dòng/câu lệnh chèn đầu tiên từ đó, sau đó dán các dòng đó vào một thẻ trình chỉnh sửa trống rồi chọn CHẠY. Nếu KHÔNG sử dụng tài khoản thanh toán dùng thử, có thể bạn sẽ sao chép được tất cả câu lệnh chèn và chạy.
Để xem nội dung của bảng, hãy mở rộng phần Trình khám phá cho đến khi bạn thấy bảng có tên là quần áo. Chọn biểu tượng ba dấu chấm dọc (⋮) để xem lựa chọn Truy vấn bảng. Câu lệnh SELECT sẽ mở ra trong một thẻ Trình chỉnh sửa mới.

Cấp quyền
Chạy câu lệnh bên dưới để cấp quyền thực thi cho hàm embedding đối với người dùng postgres:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Cấp vai trò Người dùng Vertex AI cho tài khoản dịch vụ AlloyDB
Chuyển đến cửa sổ dòng lệnh Cloud Shell và đưa ra lệnh sau:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
6. Tạo các vectơ nhúng cho bối cảnh
Máy tính xử lý các con số dễ dàng hơn nhiều so với xử lý văn bản. Một hệ thống nhúng sẽ chuyển đổi văn bản thành một chuỗi các số thực dấu phẩy động để biểu thị văn bản, bất kể văn bản đó được diễn đạt như thế nào, sử dụng ngôn ngữ gì, v.v.
Hãy cân nhắc việc mô tả một địa điểm ven biển. Ví dụ: "trên mặt nước", "bên bờ biển", "đi bộ từ phòng ra biển", "sur la mer", "на берегу океана", v.v. Những cụm từ này đều có vẻ khác nhau, nhưng ý nghĩa ngữ nghĩa của chúng (hoặc theo thuật ngữ học máy, các embeddings của chúng) phải rất gần nhau.
Giờ đây, khi dữ liệu và bối cảnh đã sẵn sàng, chúng ta sẽ chạy SQL để thêm các mục nhúng của nội dung mô tả sản phẩm vào bảng trong trường embedding. Bạn có thể sử dụng nhiều mô hình nhúng. Chúng tôi đang sử dụng text-embedding-005 từ Vertex AI. Hãy nhớ sử dụng cùng một mô hình nhúng trong suốt dự án!
Lưu ý: Nếu đang sử dụng một Dự án Google Cloud đã được tạo cách đây một thời gian, thì có thể bạn cần tiếp tục sử dụng các phiên bản cũ hơn của mô hình nhúng văn bản, chẳng hạn như textembedding-gecko.
Quay lại thẻ AlloyDB Studio rồi nhập DML sau:
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
Hãy xem lại bảng toys để xem một số thành phần được nhúng. Hãy nhớ chạy lại câu lệnh SELECT để xem các thay đổi.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
Thao tác này sẽ trả về vectơ nhúng (có dạng như một mảng số thực) cho nội dung mô tả đồ chơi như minh hoạ bên dưới:

Lưu ý: Các Dự án mới được tạo trên Google Cloud trong gói miễn phí có thể gặp phải vấn đề về hạn mức đối với số lượng yêu cầu nhúng được phép mỗi giây đối với các mô hình Nhúng. Bạn nên sử dụng một truy vấn bộ lọc cho mã nhận dạng, sau đó chọn có chọn lọc 1 đến 5 bản ghi, v.v. trong khi tạo vectơ nhúng.
7. Thực hiện tìm kiếm vectơ
Giờ đây, khi bảng, dữ liệu và các thành phần nhúng đều đã sẵn sàng, hãy thực hiện tìm kiếm vectơ theo thời gian thực cho văn bản tìm kiếm của người dùng.
Giả sử người dùng hỏi:
"I want a white plush teddy bear toy with a floral pattern."
Bạn có thể tìm thấy các kết quả trùng khớp cho trường hợp này bằng cách chạy truy vấn bên dưới:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 2;
Hãy xem xét cụm từ tìm kiếm này một cách chi tiết:
Trong truy vấn này,
- Văn bản tìm kiếm của người dùng là: "
I want a white plush teddy bear toy with a floral pattern." - Chúng ta sẽ chuyển đổi nó thành các mục nhúng trong phương thức
embedding()bằng mô hình:text-embedding-005. Bước này có vẻ quen thuộc sau bước cuối cùng, trong đó chúng ta đã áp dụng hàm nhúng cho tất cả các mục trong bảng. - "
<=>" biểu thị việc sử dụng phương thức khoảng cách COSINE SIMILARITY. Bạn có thể tìm thấy tất cả các chỉ số về mức độ tương đồng có trong tài liệu của pgvector. - Chúng tôi đang chuyển đổi kết quả của phương thức nhúng thành loại vectơ để tương thích với các vectơ được lưu trữ trong cơ sở dữ liệu.
- LIMIT 5 cho biết rằng chúng ta muốn trích xuất 5 hàng xóm gần nhất cho văn bản tìm kiếm.
Kết quả sẽ có dạng như sau:

Như bạn có thể thấy trong kết quả, các kết quả khớp khá gần với văn bản tìm kiếm. Hãy thử thay đổi văn bản để xem kết quả thay đổi như thế nào.
Lưu ý quan trọng:
Giả sử chúng ta muốn tăng hiệu suất (thời gian truy vấn), hiệu quả và khả năng thu hồi của kết quả Tìm kiếm vectơ này bằng cách sử dụng chỉ mục ScaNN. Vui lòng đọc các bước trong blog này để so sánh sự khác biệt về kết quả có và không có chỉ mục.
Bước không bắt buộc: Cải thiện hiệu quả và khả năng thu hồi bằng chỉ mục ScaNN
Bỏ qua bước này nếu số lượng bản ghi của bạn ít hơn 100.
Sau đây là các bước tạo chỉ mục để thuận tiện cho bạn:
- Vì chúng ta đã tạo cụm, thực thể, bối cảnh và các mục nhúng, nên chúng ta chỉ cần cài đặt tiện ích ScaNN bằng câu lệnh sau:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- Tiếp theo, chúng ta sẽ tạo chỉ mục (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
Trong DDL ở trên, apparel_index là tên của chỉ mục
"toys" là bảng của tôi
"scann" là phương thức chỉ mục
"embedding" là cột trong bảng mà tôi muốn lập chỉ mục
"cosine" là phương thức khoảng cách mà tôi muốn sử dụng với chỉ mục
"8" là số lượng phân vùng cần áp dụng cho chỉ mục này. Đặt thành giá trị bất kỳ trong khoảng từ 1 đến 1048576. Để biết thêm thông tin về cách quyết định giá trị này, hãy xem phần Điều chỉnh chỉ mục ScaNN.
Tôi đã sử dụng CĂN BẬC HAI của số lượng điểm dữ liệu như được đề xuất trong kho lưu trữ ScaNN (Khi phân vùng, num_leaves phải xấp xỉ căn bậc hai của số lượng điểm dữ liệu).
- Kiểm tra xem chỉ mục có được tạo bằng truy vấn sau hay không:
SELECT * FROM pg_stat_ann_indexes;
- Thực hiện Tìm kiếm vectơ bằng chính truy vấn mà chúng ta đã sử dụng mà không có chỉ mục:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;
Truy vấn trên cũng là truy vấn mà chúng ta đã dùng trong phòng thí nghiệm ở bước 8. Tuy nhiên, hiện tại chúng tôi đã lập chỉ mục trường này.
- Thử nghiệm bằng một cụm từ tìm kiếm đơn giản có và không có chỉ mục (bằng cách thả chỉ mục):
Trường hợp sử dụng này chỉ có 72 bản ghi nên chỉ mục không thực sự có hiệu lực. Đối với một thử nghiệm được thực hiện trong một trường hợp sử dụng khác, kết quả như sau:
Cùng một cụm từ tìm kiếm Vector Search trên dữ liệu nhúng ĐƯỢC LẬP CHỈ MỤC sẽ mang lại kết quả tìm kiếm chất lượng và hiệu quả. Hiệu suất được cải thiện đáng kể (về thời gian thực thi: 10,37 mili giây không có ScaNN và 0,87 mili giây có ScaNN) với chỉ mục. Để biết thêm thông tin về chủ đề này, vui lòng tham khảo blog này.
8. Xác thực kết quả trùng khớp bằng LLM
Trước khi chuyển sang bước tiếp theo và tạo một dịch vụ để trả về kết quả phù hợp nhất cho một ứng dụng, hãy sử dụng mô hình AI tạo sinh để xác thực xem những câu trả lời tiềm năng này có thực sự phù hợp và an toàn để chia sẻ với người dùng hay không.
Đảm bảo phiên bản được thiết lập cho Gemini
Trước tiên, hãy kiểm tra xem bạn đã bật tính năng Tích hợp ML của Google cho Cụm và Phiên bản của mình hay chưa. Trong AlloyDB Studio, hãy đưa ra lệnh sau:
show google_ml_integration.enable_model_support;
Nếu giá trị hiển thị là "on", bạn có thể bỏ qua 2 bước tiếp theo và chuyển thẳng đến bước thiết lập chế độ tích hợp AlloyDB và Vertex AI Model.
- Chuyển đến phiên bản chính của cụm AlloyDB rồi nhấp vào CHỈNH SỬA PHIÊN BẢN CHÍNH

- Chuyển đến phần Cờ trong mục Lựa chọn cấu hình nâng cao. và đảm bảo rằng
google_ml_integration.enable_model_support flagđược đặt thành "on" như minh hoạ bên dưới:

Nếu bạn chưa đặt thành "on", hãy đặt thành "on" rồi nhấp vào nút UPDATE INSTANCE (CẬP NHẬT THỰC THỂ). Bước này sẽ mất vài phút.
Tích hợp Mô hình AlloyDB và Vertex AI
Giờ đây, bạn có thể kết nối với AlloyDB Studio và chạy câu lệnh DML sau đây để thiết lập quyền truy cập vào mô hình Gemini từ AlloyDB, bằng cách sử dụng mã dự án của bạn ở nơi được chỉ định. Bạn có thể nhận được cảnh báo về lỗi cú pháp trước khi chạy lệnh, nhưng lệnh sẽ chạy bình thường.
Trước tiên, chúng ta sẽ tạo kết nối mô hình Gemini 1.5 như minh hoạ bên dưới. Đừng quên thay thế $PROJECT_ID trong lệnh bên dưới bằng mã dự án của bạn trên Google Cloud.
CALL
google_ml.create_model( model_id => 'gemini-1.5',
model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
model_provider => 'google',
model_auth_type => 'alloydb_service_agent_iam');
Bạn có thể kiểm tra các mô hình được định cấu hình để truy cập thông qua lệnh sau trong AlloyDB Studio:
select model_id,model_type from google_ml.model_info_view;
Cuối cùng, chúng ta cần cấp quyền cho người dùng cơ sở dữ liệu để thực thi hàm ml_predict_row nhằm chạy các dự đoán thông qua các mô hình Vertex AI của Google. Chạy lệnh sau:
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
Lưu ý: Nếu đang sử dụng một Dự án Google Cloud hiện có và một cụm/phiên bản AlloyDB hiện có đã được tạo cách đây một thời gian, thì bạn có thể cần xoá các thông tin tham chiếu cũ đến mô hình Gemini 1.5 và tạo lại bằng câu lệnh CALL ở trên, đồng thời chạy lại lệnh cấp quyền thực thi trên hàm ml_predict_row trong trường hợp bạn gặp vấn đề khi gọi Gemini 1.5 trong tương lai.
Đánh giá câu trả lời
Mặc dù chúng ta sẽ sử dụng một truy vấn lớn trong phần tiếp theo để đảm bảo các câu trả lời từ truy vấn là hợp lý, nhưng truy vấn này có thể khó hiểu. Bây giờ, chúng ta sẽ xem xét các phần và cách chúng kết hợp với nhau trong vài phút nữa.
- Trước tiên, chúng ta sẽ gửi một yêu cầu đến cơ sở dữ liệu để lấy 10 kết quả phù hợp nhất với một cụm từ tìm kiếm của người dùng.
- Để xác định mức độ hợp lệ của các câu trả lời, chúng ta sẽ sử dụng một truy vấn bên ngoài để giải thích cách đánh giá các câu trả lời. Truy vấn này sử dụng trường
recommended_text(văn bản tìm kiếm) vàcontent(trường mô tả đồ chơi) của bảng bên trong làm một phần của truy vấn. - Dựa vào đó, chúng tôi sẽ xem xét "mức độ phù hợp" của các câu trả lời được trả về.
predict_rowsẽ trả về kết quả ở định dạng JSON. Mã "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"" được dùng để trích xuất văn bản thực tế từ JSON đó. Để xem JSON thực tế được trả về, bạn có thể xoá mã này.- Cuối cùng, để nhận được câu trả lời của LLM, chúng ta sẽ trích xuất câu trả lời đó bằng cách sử dụng
REGEXP_REPLACE(gemini_validation,'[^a-zA-Z,: ]','','g')
SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ', recommended_text, '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ', content, '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
FROM (SELECT id,
name,
description AS content,
quantity,
price,
image_url,
'Pink panther standing' AS recommended_text
FROM toys
ORDER BY text_embeddings <=> embedding('text-embedding-005',
'Pink panther standing')::VECTOR
LIMIT 1) AS xyz) AS X
GROUP BY id,
name,
content,
quantity,
price,
image_url,
recommended_text) AS final_matches
-- WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';
Mặc dù điều đó vẫn có vẻ khó khăn, nhưng hy vọng bạn có thể hiểu rõ hơn một chút. Kết quả cho biết có trùng khớp hay không, tỷ lệ phần trăm trùng khớp và một số giải thích về điểm xếp hạng.
Xin lưu ý rằng mô hình Gemini mặc định sẽ bật tính năng truyền trực tuyến, nên câu trả lời thực tế sẽ trải dài trên nhiều dòng:

9. Đưa tính năng Tìm kiếm đồ chơi lên Cloud mà không cần máy chủ
Bạn đã sẵn sàng đưa ứng dụng này lên web chưa? Hãy làm theo các bước bên dưới để tạo Knowledge Engine Serverless bằng Cloud Run Functions:
- Truy cập vào Cloud Run Functions trong Google Cloud Console để TẠO một Cloud Run Function mới hoặc sử dụng đường liên kết: https://console.cloud.google.com/functions/add.
- Chọn Môi trường là "Hàm Cloud Run". Cung cấp Tên hàm "get-toys-alloydb" và chọn Khu vực là "us-central1". Đặt chế độ Xác thực thành "Cho phép lệnh gọi chưa xác thực" rồi nhấp vào TIẾP THEO. Chọn Java 17 làm thời gian chạy và Trình chỉnh sửa nội tuyến cho mã nguồn.
- Theo mặc định, chế độ này sẽ đặt Điểm truy cập thành "
gcfv2.HelloHttpFunction". Thay thế mã giữ chỗ trongHelloHttpFunction.javavàpom.xmlcủa Hàm Cloud Run bằng mã tương ứng trong HelloHttpFunction.java và pom.xml. - Hãy nhớ thay đổi phần giữ chỗ <<YOUR_PROJECT>> và thông tin đăng nhập kết nối AlloyDB bằng các giá trị của bạn trong tệp Java. Thông tin đăng nhập AlloyDB là thông tin mà chúng ta đã dùng khi bắt đầu lớp học lập trình này. Nếu bạn đã sử dụng các giá trị khác nhau, vui lòng sửa đổi các giá trị đó trong tệp Java.
- Nhấp vào Triển khai.
Sau khi triển khai, để cho phép Cloud Function truy cập vào phiên bản cơ sở dữ liệu AlloyDB, chúng ta sẽ tạo trình kết nối VPC.
BƯỚC QUAN TRỌNG:
Sau khi thiết lập để triển khai, bạn sẽ có thể thấy các hàm trong bảng điều khiển Google Cloud Run Functions. Tìm hàm mới tạo (get-toys-alloydb), nhấp vào hàm đó, sau đó nhấp vào CHỈNH SỬA và thay đổi những nội dung sau:
- Chuyển đến phần Cài đặt thời gian chạy, bản dựng, kết nối và bảo mật
- Tăng thời gian chờ lên 180 giây
- Chuyển đến thẻ KẾT NỐI:

- Trong phần cài đặt Ingress, hãy nhớ chọn "Cho phép tất cả lưu lượng truy cập".
- Trong phần Egress settings (Cài đặt lưu lượng truy cập đi), hãy nhấp vào trình đơn thả xuống Network (Mạng) rồi chọn "Add New VPC Connector" (Thêm trình kết nối VPC mới) và làm theo hướng dẫn mà bạn thấy trên hộp thoại bật lên:

- Cung cấp tên cho Trình kết nối VPC và đảm bảo khu vực này giống với phiên bản của bạn. Để nguyên giá trị Mạng là mặc định và đặt Mạng con thành Dải IP tuỳ chỉnh với dải IP là 10.8.0.0 hoặc một dải IP tương tự có sẵn.
- Mở rộng mục HIỂN THỊ CÁC CHẾ ĐỘ CÀI ĐẶT THANG ĐO và đảm bảo bạn đã đặt cấu hình chính xác như sau:

- Nhấp vào CREATE (Tạo) và trình kết nối này sẽ xuất hiện trong phần cài đặt lưu lượng truy cập đi.
- Chọn giắc cắm mới tạo
- Chọn định tuyến tất cả lưu lượng truy cập thông qua trình kết nối VPC này.
- Nhấp vào TIẾP THEO rồi nhấp vào TRIỂN KHAI.
10. Kiểm thử Cloud Run Function
Sau khi triển khai Cloud Function đã cập nhật, bạn sẽ thấy điểm cuối được tạo. Sao chép khoá đó và thay thế trong lệnh sau:
Ngoài ra, bạn có thể kiểm thử Hàm Cloud Run như sau:
PROJECT_ID=$(gcloud config get-value project)
curl -X POST <<YOUR_ENDPOINT>> \
-H 'Content-Type: application/json' \
-d '{"search":"I want a standing pink panther toy"}' \
| jq .
Kết quả là:

Vậy là xong! Bạn có thể thực hiện Tìm kiếm vectơ tương tự một cách đơn giản bằng cách sử dụng mô hình Nhúng trên dữ liệu AlloyDB.
11. Xây dựng ứng dụng web!
Trong phần này, chúng ta sẽ tạo một ứng dụng web để người dùng tương tác và tìm thấy đồ chơi phù hợp dựa trên văn bản, hình ảnh và thậm chí tạo một đồ chơi mới dựa trên nhu cầu của họ. Vì ứng dụng đã được tạo, nên bạn có thể làm theo các bước bên dưới để sao chép ứng dụng đó vào IDE và chạy ứng dụng.
- Vì chúng ta sử dụng Gemini 2.0 Flash để mô tả hình ảnh mà người dùng có thể tải lên để tìm đồ chơi phù hợp, nên chúng ta cần lấy API KEY cho ứng dụng này. Để làm việc đó, hãy truy cập vào https://aistudio.google.com/apikey và lấy Khoá API cho Dự án đang hoạt động trên Google Cloud mà bạn đang triển khai ứng dụng này, sau đó lưu khoá ở đâu đó:

- Chuyển đến Cửa sổ dòng lệnh Cloud Shell
- Sao chép kho lưu trữ bằng lệnh sau:
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- Sau khi sao chép kho lưu trữ, bạn sẽ có thể truy cập vào dự án thông qua Cloud Shell Editor.
- Bạn cần xoá các thư mục "get-toys-alloydb" và "toolbox-toys" khỏi dự án đã sao chép vì đây là 2 mã Cloud Run Functions mà bạn có thể tham chiếu từ kho lưu trữ khi cần.
- Chuyển đến GenerateToy.java trong thư mục web và tìm dòng sau rồi xoá dòng đó vì allow adult có thể yêu cầu quyền đặc biệt mà một số tài khoản thanh toán dùng thử có thể không có:
paramsMap.put("personGeneration", "allow_adult");
- Đảm bảo bạn đã thiết lập tất cả các biến môi trường cần thiết trước khi tạo và triển khai ứng dụng. Chuyển đến Cloud Shell Terminal rồi thực thi các lệnh sau:
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID=$PROJECT_ID
export GOOGLE_API_KEY=<YOUR API KEY that you saved>
- Tạo bản dựng và chạy ứng dụng cục bộ:
Đảm bảo bạn đang ở trong thư mục dự án, hãy chạy các lệnh sau:
mvn package
mvn spring-boot:run
- Triển khai trên Cloud Run
gcloud run deploy --source .
12. Tìm hiểu thông tin chi tiết về AI tạo sinh
Bạn không cần làm gì cả. Để bạn hiểu rõ hơn:
Giờ đây, bạn đã có ứng dụng để triển khai, hãy dành chút thời gian để tìm hiểu cách chúng tôi thực hiện việc tìm kiếm (văn bản và hình ảnh) cũng như tạo nội dung.
- Tìm kiếm vectơ dựa trên văn bản của người dùng:
Vấn đề này đã được giải quyết trong Cloud Run Functions mà chúng ta triển khai trong phần "Sử dụng ứng dụng tìm kiếm vectơ".
- Tìm kiếm bằng vectơ dựa trên hình ảnh tải lên:
Thay vì nhập ngữ cảnh dưới dạng văn bản, giả sử người dùng muốn tải lên hình ảnh của một món đồ chơi quen thuộc mà họ muốn tìm kiếm. Người dùng có thể tải hình ảnh của một món đồ chơi mà họ thích lên và nhận được các tính năng liên quan.
Chúng tôi tận dụng mô hình Gemini 2.0 Flash của Google (được gọi bằng LangChain4j) để phân tích hình ảnh và trích xuất ngữ cảnh có liên quan, chẳng hạn như màu sắc, chất liệu, loại và nhóm tuổi dự kiến của đồ chơi.
Chỉ trong 5 bước, chúng tôi đã lấy thông tin đầu vào dữ liệu đa phương thức của người dùng để so khớp kết quả bằng cách gọi mô hình ngôn ngữ lớn thông qua một khung nguồn mở. Tìm hiểu cách làm:
package cloudcode.helloworld.web;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
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;
import java.util.Base64;
import java.util.Optional;
public class GeminiCall {
public String imageToBase64String(byte[] imageBytes) {
String base64Img = Base64.getEncoder().encodeToString(imageBytes);
return base64Img;
}
public String callGemini(String base64ImgWithPrefix) throws Exception {
String searchText = "";
// 1. Remove the prefix
String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");
// 2. Decode base64 to bytes
byte[] imageBytes = Base64.getDecoder().decode(base64Img);
String image = imageToBase64String(imageBytes);
// 3. Get API key from environment variable
String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
.orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));
// 4. Invoke Gemini 2.0
ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
.apiKey(apiKey)
.modelName("gemini-2.0-flash-001")
.build();
Response<AiMessage> response = gemini.generate(
UserMessage.from(
ImageContent.from(image, "image/jpeg"),
TextContent.from(
"The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send response stating that no toy is found in the input image.")));
// 5. Get the text from the response and send it back to the controller
searchText = response.content().text().trim();
System.out.println("searchText inside Geminicall: " + searchText);
return searchText;
}
}
- Tìm hiểu cách chúng tôi sử dụng Imagen 3 để tạo ra một món đồ chơi tuỳ chỉnh dựa trên yêu cầu của người dùng bằng AI tạo sinh.
Sau đó, Imagen 3 sẽ tạo hình ảnh của món đồ chơi được thiết kế riêng, giúp người dùng hình dung rõ ràng về tác phẩm của họ. Đây là cách chúng tôi thực hiện chỉ trong 5 bước:
// Generate an image using a text prompt using an Imagen model
public String generateImage(String projectId, String location, String prompt)
throws ApiException, IOException {
final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
PredictionServiceSettings predictionServiceSettings =
PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
// 1. Set up the context and prompt
String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
prompt = context + prompt;
// 2. Initialize a client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests.
try (PredictionServiceClient predictionServiceClient =
PredictionServiceClient.create(predictionServiceSettings)) {
// 3. Invoke Imagen 3
final EndpointName endpointName =
EndpointName.ofProjectLocationPublisherModelName(
projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
Map<String, Object> instancesMap = new HashMap<>();
instancesMap.put("prompt", prompt);
Value instances = mapToValue(instancesMap);
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("sampleCount", 1);
paramsMap.put("aspectRatio", "1:1");
paramsMap.put("safetyFilterLevel", "block_few");
paramsMap.put("personGeneration", "allow_adult");
paramsMap.put("guidanceScale", 21);
paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
Value parameters = mapToValue(paramsMap);
// 4. Get prediction response image
PredictResponse predictResponse =
predictionServiceClient.predict(
endpointName, Collections.singletonList(instances), parameters);
// 5. Return the Base64 Encoded String to the controller
for (Value prediction : predictResponse.getPredictionsList()) {
Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
if (fieldsMap.containsKey("bytesBase64Encoded")) {
bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
}
}
return bytesBase64EncodedOuput.toString();
}
}
Dự đoán giá
Trong phần trước ở trên, chúng ta đã thảo luận về cách Imagen tạo hình ảnh của một món đồ chơi mà người dùng muốn tự thiết kế. Để người dùng có thể mua đồ chơi này, ứng dụng cần đặt giá cho đồ chơi và chúng tôi đã sử dụng một logic trực quan để xác định giá cho đồ chơi đặt làm riêng. Logic là sử dụng giá trung bình của 5 món đồ chơi phù hợp nhất (về nội dung mô tả) với món đồ chơi mà người dùng thiết kế.
Dự đoán giá cho đồ chơi được tạo là một phần quan trọng của ứng dụng này và chúng tôi đã sử dụng phương pháp dựa trên tác nhân để tạo ra dự đoán này. Giới thiệu Gen AI Toolbox for Databases.
13. Hộp công cụ AI tạo sinh cho cơ sở dữ liệu
Hộp công cụ AI tạo sinh cho Cơ sở dữ liệu là một máy chủ nguồn mở của Google, giúp bạn dễ dàng tạo các công cụ AI tạo sinh để tương tác với cơ sở dữ liệu. Nhờ đó, bạn có thể phát triển các công cụ cho nhà phát triển dễ dàng, nhanh chóng và an toàn hơn bằng cách xử lý các điểm phức tạp như nhóm kết nối, xác thực và nhiều điểm khác. Công cụ này giúp bạn tạo các công cụ AI tạo sinh cho phép các tác nhân truy cập vào dữ liệu trong cơ sở dữ liệu của bạn.
Sau đây là các bước bạn cần làm theo để có thể thiết lập tính năng này nhằm chuẩn bị Công cụ và giúp ứng dụng của chúng ta có khả năng hành động: Đường liên kết đến Lớp học lập trình về Hộp công cụ
Giờ đây, ứng dụng của bạn có thể sử dụng điểm cuối Cloud Run Function đã triển khai này để điền giá cùng với kết quả Imagen đã tạo cho hình ảnh đồ chơi đặt làm riêng.
14. Kiểm thử ứng dụng web
Giờ đây, tất cả các thành phần của ứng dụng đã được tạo và triển khai, ứng dụng đã sẵn sàng được phân phát trên đám mây. Kiểm thử ứng dụng của bạn trong mọi trường hợp. Dưới đây là đường liên kết đến video về những gì bạn có thể mong đợi:
https://www.youtube.com/shorts/ZMqUAWsghYQ
Đây là giao diện của trang đích:

15. Dọn dẹp
Để tránh bị tính phí vào tài khoản Google Cloud của bạn cho các tài nguyên được dùng trong bài đăng này, hãy làm theo các bước sau:
- Trong bảng điều khiển Cloud, hãy chuyển đến trang Quản lý tài nguyên.
- Trong danh sách dự án, hãy chọn dự án mà bạn muốn xoá, rồi nhấp vào Xoá.
- Trong hộp thoại, hãy nhập mã dự án rồi nhấp vào Tắt để xoá dự án.
16. Xin chúc mừng
Xin chúc mừng! Bạn đã thực hiện thành công một hoạt động Tìm kiếm theo bối cảnh và Tạo nội dung cho Cửa hàng đồ chơi bằng AlloyDB, pgvector, Imagen và Gemini 2.0, đồng thời tận dụng các thư viện nguồn mở để xây dựng các hoạt động tích hợp mạnh mẽ. Bằng cách kết hợp các chức năng của AlloyDB, Vertex AI và Vector Search, chúng tôi đã có một bước tiến vượt bậc trong việc giúp các hoạt động tìm kiếm theo ngữ cảnh và tìm kiếm vectơ trở nên dễ tiếp cận, hiệu quả và thực sự dựa trên ý nghĩa.