Xây dựng recommendation service với OpenAI và Java
Một trong những khía cạnh đáng chú ý hơn của ChatGPT là công cụ của nó, không chỉ các tính năng được cung cấp cho chatbot dựa trên web mà còn có thể tích hợp vào các ứng dụng Java của bạn.
Trong bài viết này sẽ hướng dẫn các bạn cách bắt đầu sử dụng công cụ OpenAI GPT trong các dự án Java theo các có thể mở rộng bằng cách chỉ gửi lời nhắc tới GPT engine khi cần thiết.
Budget Journey App
Hãy tưởng tượng bạn muốn đến thăm một thành phố và có một khoản ngân sách cụ thể trong đầu. Làm thế nào bạn nên tiêu tiền và làm cho chuyến đi của bạn đáng nhớ? Đây là một câu hỏi tuyệt vời để ủy quyền cho công cụ OpenAI.
Hãy giúp người dùng tận dụng tối đa các chuyến đi của họ bằng cách xây dựng một ứng dụng Java đơn giản có tên là BudgetJourney . Ứng dụng có thể đề xuất nhiều điểm ưa thích trong một thành phố, được điều chỉnh để phù hợp với những hạn chế về ngân sách cụ thể.
Kiến trúc của ứng dụng BudgetJourney trông như sau:
- Người dùng mở giao diện web BudgetJourney chạy trên Vaadin .
- Vaadin kết nối với backend Spring Boot khi người dùng muốn nhận đề xuất cho một thành phố và ngân sách cụ thể.
- Spring Boot kết nối với cơ sở dữ liệu YugabyteDB để kiểm tra xem đã có bất kỳ đề xuất nào cho thành phố và ngân sách được yêu cầu chưa. Nếu dữ liệu đã có trong cơ sở dữ liệu, phản hồi sẽ được gửi lại cho người dùng.
- Trái lại, Spring Boot kết nối đến các API của OpenAI để nhận các đề xuất từ neural network. Phản hồi được lưu trữ trong YugabyteDB để tham khảo trong tương lai và gửi lại cho người dùng.
Bây giờ, hãy xem cách ứng dụng giao tiếp với công cụ Open AI (bước 4) và cách sử dụng cơ sở dữ liệu (bước 3) giúp giải pháp có thể mở rộng và tiết kiệm chi phí.
Thư viện OpenAI Java
Công cụ OpenAI có thể được truy vấn thông qua API HTTP. Bạn cần tạo một tài khoản, nhận mã thông báo của mình (tức là khóa API) và sử dụng mã thông báo đó trong khi gửi yêu cầu tới một trong các mô hình OpenAI.
Một mô hình trong ngữ cảnh của OpenAI là một cấu trúc tính toán được đào tạo trên một tập dữ liệu lớn để nhận dạng các mẫu, đưa ra dự đoán hoặc thực hiện các tác vụ cụ thể dựa trên dữ liệu đầu vào. Hiện tại, dịch vụ hỗ trợ một số mô hình có thể hiểu và tạo ngôn ngữ tự nhiên, mã, hình ảnh hoặc chuyển đổi âm thanh thành văn bản.
Ứng dụng BudgetJourney sử dụng mô hình GPT-3.5 để hiểu và tạo mã hoặc ngôn ngữ tự nhiên. Ứng dụng yêu cầu mô hình đề xuất một số điểm ưa thích trong thành phố trong khi xem xét các hạn chế về ngân sách. Sau đó, mô hình sẽ trả về các đề xuất ở định dạng JSON.
Thư viện Java OpenAI mã nguồn mở triển khai các API HTTP GPT-3.5, giúp dễ dàng giao tiếp với dịch vụ thông qua các API Java được xác định rõ. Đây là cách bạn bắt đầu với thư viện:
- Thêm dependency OpenAI Java mới nhất vào tệp pom.xml của bạn .
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>${version}</version>
</dependency>
- Tạo một instance của class OpenAiService bằng cách cung cấp khóa API của bạn và setting thời gian timeout cho các yêu cầu giữa ứng dụng và công cụ OpenAI.
OpenAiService openAiService = new OpenAiService(apiKey, Duration.ofSeconds(apiTimeout));
Tiếp theo, hãy xem cách bạn có thể làm việc với mô hình GPT-3.5 thông qua đối tượng OpenAiService.
Gửi lời nhắc tới GPT-3.5 model
Bạn giao tiếp với các mô hình OpenAI bằng cách gửi lời nhắc văn bản cho biết những gì bạn mong đợi một mô hình thực hiện. Mô hình hoạt động tốt nhất khi hướng dẫn của bạn rõ ràng và bao gồm các ví dụ.
Để xây dựng lời nhắc cho mô hình GPT-3.5, bạn sử dụng ChatCompletionRequestAPI của thư viện OpenAI Java:
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
.builder()
.model(“gpt-3.5-turbo”)
.temperature(0.8)
.messages(
List.of(
new ChatMessage("system", SYSTEM_TASK_MESSAGE),
new ChatMessage("user", String.format("I want to visit %s and have a budget of %d dollars", city, budget))))
.build();
- model(“gpt-3.5-turbo”) là phiên bản tối ưu hóa của mô hình GPT-3.5.
- temperature(...) kiểm soát mức độ ngẫu nhiên và sáng tạo mong đợi trong phản ứng của mô hình. Chẳng hạn, các giá trị cao hơn như 0,8 sẽ làm cho đầu ra ngẫu nhiên hơn, trong khi các giá trị thấp hơn như 0,2 sẽ làm cho nó trở nên chính xác hơn.
- messages(...) là các hướng dẫn thực tế hoặc lời nhắc cho mô hình. ChatMessage “system” hướng dẫn mô hình hoạt động theo một cách nhất định, “assistant” lưu trữ các phản hồi trước đó và “user” mang yêu cầu của người dùng kèm theo yêu cầu.
SYSTEM_TASK_MESSAGE
sẽ trông như sau:
You are an API server that responds in a JSON format. Don't say anything else. Respond only with the JSON.
The user will provide you with a city name and available budget. While considering that budget, you must suggest a list of places to visit.
Allocate 30% of the budget to restaurants and bars. Allocate another 30% to shows, amusement parks, and other sightseeing. Dedicate the remainder of the budget to shopping. Remember, the user must spend 90-100% of the budget.
Respond in a JSON format, including an array named 'places'. Each item of the array is another JSON object that includes 'placename' as a text, 'placeshortinfo' as a text, and 'placevisitcost' as a number.
Don't add anything else after you respond with the JSON.
Thông báo hệ thống trên mặc dù dài dòng và cần tối ưu hóa, nhưng thông báo này truyền đạt hành động mong muốn: đề xuất nhiều điểm ưa thích với mức sử dụng ngân sách tối đa và cung cấp phản hồi ở định dạng JSON, điều đặc biệt cần thiết cho phần còn lại của ứng dụng.
Khi bạn đã tạo lời nhắc (ChatCompletionRequest) cung cấp cả thông báo của hệ thống và người dùng cũng như các thông số khác, bạn có thể gửi nó qua OpenAiService:
OpenAiService openAiService = … //created earlier
StringBuilder builder = new StringBuilder();
openAiService.createChatCompletion(chatCompletionRequest)
.getChoices().forEach(choice -> {
builder.append(choice.getMessage().getContent());
});
Sau đó, đối tượng jsonResponse được xử lý thêm bởi phần còn lại của logic ứng dụng, chuẩn bị danh sách các điểm ưa thích và hiển thị chúng với sự trợ giúp của Vaadin.
Ví dụ: giả sử một người dùng đến thăm Tokyo và muốn chi tiêu tới 900 đô la trong thành phố. Mô hình sẽ tuân thủ nghiêm ngặt hướng dẫn của chúng tôi từ thông báo hệ thống và phản hồi bằng JSON sau:
{
"places": [
{
"place_name": "Tsukiji Fish Market",
"place_short_info": "Famous fish market where you can eat fresh sushi",
"place_visit_cost": 50
},
{
"place_name": "Meiji Shrine",
"place_short_info": "Beautiful Shinto shrine in the heart of Tokyo",
"place_visit_cost": 0
},
{
"place_name": "Shibuya Crossing",
"place_short_info": "Iconic pedestrian crossing with bright lights and giant video screens",
"place_visit_cost": 0
},
{
"place_name": "Tokyo Skytree",
"place_short_info": "Tallest tower in the world, offering stunning views of Tokyo",
"place_visit_cost": 30
},
{
"place_name": "Robot Restaurant",
"place_short_info": "Unique blend of futuristic robots, dancers, and neon lights",
"place_visit_cost": 80
},
// More places
]}
JSON này sau đó được chuyển đổi thành một danh sách các điểm ưa thích khác nhau. Sau đó được hiển thị cho người dùng:
LƯU Ý: Mô hình GPT-3.5 đã được đào tạo trên tập dữ liệu từ tháng 9 năm 2021. Do đó, nó không thể cung cấp các đề xuất chuyến đi phù hợp và chính xác 100%. Tuy nhiên, sự thiếu chính xác này có thể được cải thiện với sự trợ giúp của các plugin OpenAI cho phép các mô hình truy cập vào dữ liệu thời gian thực. Chẳng hạn, khi plugin Expedia dành cho OpenAI được cung cấp công khai dưới dạng API, điều này sẽ cho phép bạn cải thiện ứng dụng BudgetJourney này hơn nữa.
Mở rộng quy mô với cơ sở dữ liệu
Như bạn có thể thấy, thật đơn giản để tích hợp neural network vào các ứng dụng Java của bạn và giao tiếp với nó theo cách tương tự như các API của bên thứ 3 khác. Bạn cũng có thể điều chỉnh hành vi API, chẳng hạn như thêm định dạng đầu ra mong muốn.
Tuy nhiên, đây vẫn là API của bên thứ 3 tính phí cho bạn đối với mọi yêu cầu. Bạn gửi càng nhiều lời nhắc và thời gian gửi càng dài thì bạn càng phải trả nhiều tiền. Không có gì đến miễn phí.
Ngoài ra, cần có thời gian để mô hình xử lý lời nhắc của bạn. Chẳng hạn, có thể mất 10-30 giây trước khi ứng dụng BudgetJourney nhận được danh sách đề xuất đầy đủ từ OpenAI. Điều này có thể là quá mức cần thiết, đặc biệt nếu những người dùng khác nhau gửi lời nhắc tương tự.
Để làm cho các ứng dụng OpenAI GPT có thể mở rộng, cần lưu trữ các phản hồi của mô hình trong cơ sở dữ liệu. Cơ sở dữ liệu đó cho phép bạn:
- Giảm khối lượng yêu cầu đối với API OpenAI và do đó, giảm các chi phí liên quan.
- Phục vụ các yêu cầu của người dùng với độ trễ thấp bằng cách trả về các đề xuất được xử lý trước đó (hoặc được tải trước) từ cơ sở dữ liệu.
Ứng dụng BudgetJourney sử dụng cơ sở dữ liệu YugabyteDB do khả năng mở rộng quy mô toàn cầu và lưu trữ các phản hồi của mô hình gần với vị trí của người dùng. Với chế độ triển khai được phân vùng địa lý , bạn có thể có một cụm cơ sở dữ liệu duy nhất với dữ liệu được tự động ghim vào và cung cấp từ nhiều khu vực địa lý khác nhau với độ trễ thấp.
Cột phân vùng địa lý ( “region”) cho phép cơ sở dữ liệu quyết định vị trí hàng mục tiêu. Chẳng hạn, các nút cơ sở dữ liệu từ Châu Âu đã lưu trữ các đề xuất cho chuyến đi đến Miami với ngân sách $1500. Tiếp theo, giả sử một người dùng từ Châu Âu muốn đến Miami và chi tiêu số tiền đó. Trong trường hợp đó, ứng dụng có thể phản hồi trong vòng vài mili giây bằng cách nhận các đề xuất trực tiếp từ các nút cơ sở dữ liệu trong cùng một khu vực địa lý.
Ứng dụng BudgetJourney sử dụng kho lưu trữ JPA sau để nhận đề xuất từ cụm YugabyteDB:
@Repository
public interface CityTripRepository extends JpaRepository<CityTrip, Integer> {
@Query("SELECT pointsOfInterest FROM CityTrip WHERE cityName=?1 and budget=?2 and region=?3")
String findPointsOfInterest(String cityName, Integer budget, String region);
}
Với một lớp Entity tìm kiếm như sau:
@Entity
public class CityTrip {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "landmark_generator")
@SequenceGenerator(name = "landmark_generator", sequenceName = "landmark_sequence", allocationSize = 5)
int id;
@NotEmpty
String cityName;
@NotNull
Integer budget;
@NotEmpty
@Column(columnDefinition = "text")
String pointsOfInterest;
@NotEmpty
String region;
//The rest of the logic
}
Vì vậy, tất cả những gì bạn cần làm là thực hiện cuộc gọi đến cơ sở dữ liệu trước, sau đó hoàn nguyên về API OpenAI nếu các đề xuất liên quan chưa có sẵn trong cơ sở dữ liệu. Khi ứng dụng của bạn ngày càng phổ biến, sẽ có càng nhiều đề xuất địa phương, làm cho phương pháp này thậm chí còn tiết kiệm chi phí hơn theo thời gian.
Kết thúc
Chatbot dựa trên web ChatGPT là một cách tuyệt vời để thể hiện khả năng của công cụ OpenAI. Khám phá các mô hình mạnh mẽ của công cụ sẽ giúp ích rất nhiều trong việc xây dựng các ứng dụng Java. Chỉ cần chắc chắn rằng bạn làm điều đó theo cách có thể mở rộng!
All rights reserved