Developing an AI Java Application using the OpenAI GPT-3.5 models

GPT Chat and other advanced Artificial Intelligence models are making waves in the tech world. Everyone talks about how new innovative business models can be built around them, and how they can be integrated into existing products. There are already plenty of resources describing how to do this with Python, but did you know that it's also possible to leverage AI features using Java?


In this article, we'll explore how to easily integrate with the OpenAI REST API in Java, while at the same time we will delve into the various concepts and capabilities that OpenAI provides. Additionally, we'll share our firsthand experience developing the 'GPT Code Assist' plugin for IntelliJ IDEA, which utilizes OpenAI's powerful natural language processing to assist developers in writing code. Read on to learn how you too can harness the power of AI in your Java-based projects.


Obtaining the OpenAI API Key

As we begin our journey of integrating AI with Java, the first step is to obtain the OpenAI API Key. The API Key acts as a unique identifier for your application, and is required to authenticate all requests made to the OpenAI platform.

Obtaining the API Key is a straightforward process that can be done for free on the OpenAI platform. Simply visit https://platform.openai.com/account/api-keys and follow the instructions to create your API Key.

It's important to note that while the free trial can be used for initial testing and basic usage of the API, for more advanced features, you may need to add billing information to your account.

While obtaining the Key is easy it's crucial to treat it as a password and store it in a secure manner. Anyone with access to your key can execute requests on your behalf. Therefore, it's recommended to never commit your API Key to your repository, and store it in an encrypted file.


Connecting to the API

Using the OpenAI API with a Java application requires a library that can handle HTTP requests. However, there's no need to reinvent the wheel, and write the API client yourself,  as the openai-java library provides a pre-implemented retrofit client that covers all currently available endpoints, along with providing an implementation of service that calls the client.

To use this library, simply add the maven or gradle dependency:

<dependency> 
    <groupId>com.theokanning.openai-gpt3-java</groupId>
    <artifactId>service</artifactId>
    <version>0.12.0</version> 
</dependency> 

Once you've added the dependency, you can immediately initiate the OpenAI API communication service by providing your API key. It's also a good idea to provide a timeout for OpenAI requests, as the default timeout may be insufficient while using the trial version of the token. 


Choosing an AI model

Before integrating with the OpenAI API, it's important to choose the right AI model that's suitable for the task at hand. Each of the available models is carefully tuned for specific purposes and can yield different results depending on the task.

The most important consideration when choosing an AI model are the available features. There are different models designed for chat, AI completions, search engines, image generation, and more. For this tutorial, we will be using two GPT-3.5 models, one for completions and the other for chat.

The text-davinci-003 model is perfect for AI completions, while the gpt-3.5-turbo model is great for chat applications. However, you can explore other available models and learn more about their unique features on the OpenAI platform documentation at https://platform.openai.com/docs/models.


Using AI Completions feature

The AI Completions feature of the GPT model is one of its most basic yet powerful API features. With just a prompt, the AI will try to understand the task at hand and generate a response. This feature can be used for a wide variety of tasks, from simple completion requests to executing complex tasks.

For example, a completion request could be just a simple unfinished sentence like:

The GPT AI is amazing because

Or alternatively you could directly specify the task to be done:

Write a short essay on why GPT AI is amazing.

Here's an example of how to execute a completion request to the OpenAI API using the davinci model in Java:

OpenAiService service = new OpenAiService(apiKey, Duration.ofSeconds(60));

CompletionRequest completionRequest = CompletionRequest.builder()
       .model("text-davinci-003")
       .temperature(0.1)
       .maxTokens(1024)
       .prompt("The GPT AI is amazing because")
       .n(1)
       .build();

CompletionResult result = service.createCompletion(completionRequest);
return result.getChoices().get(0).getText();

In the example above, there are a few optional parameters used. Here's what they mean:

  • temperature: This parameter controls how focused and deterministic the model answers are. The values may be anything between 0 and 2, but in my experience, values over 0.7 tend to be elaborate and sometimes a bit random.

  • maxTokens: This parameter specifies how many tokens the response can have. Each of the models imposes a maximum number of tokens that can be used for prompt and response (4095 for GPT 3.5 models). Using this parameter ensures that the generated response won’t exceed the limit and will be delivered as a whole.

  • n: This parameter specifies the number of responses that should be generated. In case of some tasks, it may be needed to generate multiple responses. Depending on this parameter, the provided CompletionResult will contain n choices.

Overall, the AI Completions feature is a simple but powerful way to generate responses to a wide variety of tasks. With just a few lines of code, you can leverage the power of the GPT model and OpenAI API to accomplish many different tasks.


Using AI Chat feature

The Chat API builds on the idea of completions by adding even more advanced layers of interaction with AI. Instead of providing a single prompt requesting a response, it allows for the inclusion of whole conversations. Each message in the conversation impacts the results in some way, and different messages can be assigned to different "roles":

  • user - it is a most basic role, representing the user asking a question in the chat. It can be used very similar as a standard ‘completion’ mechanism

  • assistant - it is a role representing the GPT Chat itself. It may be used to keep the previous conversation context, or provide examples of expected responses, and drive further behavior of the AI. 

  • system - it is a role that can be used to build system context, and give a specific purpose for the AI.

Here are  example, you could provide the following conversation as preparation:

user: one plus one equals two

assistant: 1+1=2

user: a squared plus b squared equals c squared

assistant: a^2+b^2=c^2

user: f function of x equals x times two

assistant: f(x)=2x

Then, you could ask a real question and expect a response:

user: logarithm of two times x

Alternatively, you could build the personality and expected role directly into the system:

system: You are an AI assistant that translates the provided natural language description of mathematical equations into proper mathematical notation. Respond only with equation

Then you could ask the same question and expect a similar answer.


Here is an example of using the gpt-3.5-turbo Chat model to interact with AI using the conversation feature:

ChatCompletionRequest completionRequest = ChatCompletionRequest.builder()
       .model("gpt-3.5-turbo")
       .temperature(0.1)
       .maxTokens(1024)
       .messages(Arrays.asList(
               new ChatMessage("user","one plus one equals two"),
               new ChatMessage("assistant","1+1=2"),
               new ChatMessage("user","a squared plus b squared equals c squared"),
               new ChatMessage("assistant","a^2+b^2=c^2"),
               new ChatMessage("user","f function of x equals x times two"),
               new ChatMessage("assistant","f(x)=2x"),
               new ChatMessage("user","log of two times x")
               ))
       .build();

ChatCompletionResult result = service.createChatCompletion(completionRequest);
return result.getChoices().get(0).getMessage().getContent();

While looking at examples, you may think that "if using Chat is so easy, why bother with completions?" However, there are multiple reasons why completions may be better in some cases:

  • Execution time: Sometimes, providing the response to the user in almost real time is crucial. Chat can be slower than completions in this regard.

  • Cost-effectiveness: Due to its longer execution time, Chat can also be less cost-effective than completions.

  • Different models: Even though the base GPT-3.5 model is the same, the differently fine-tuned models for Chat and Completions can produce slightly different responses.


It’s all about good prompt

Integrating with the API is a breeze with the openai-gpt3-java library - there's no need to worry about implementing an API client, one can jump straight into action. But that’s writing the effective prompt that is critical and requires most skill.


Whether it’s Java or Python you're using, creating the right prompt is the biggest challenge you'll face. Your prompt has to instruct the AI to perform a specific task, respond in a particular format, or focus on a critical detail. 


Developing a good prompt takes a lot of testing and experience. While we at Craftspire were building the GPT Code Review plugin, we tested dozens of different prompt variants to find the most satisfactory results. Only after that many attempts were we able to realize which approaches work, and which doesn't yield so good results. Sometimes even changing a single word, or providing one well defined example can change the results from unpredictable to satisfactory.

To help you develop effective prompts, we have gathered some tips:

 
  1. Be clear and specific about what you want the AI to do.

  2. Provide enough context for the AI to understand the task at hand.

  3. Avoid ambiguity and confusion by using simple and precise language.

  4. Abstain from using too long sentences and assigning complex tasks while providing system context

  5. Use examples to illustrate what you're looking for.

  6. Experiment with different prompts to see what works best.

 

Besides that we've compiled a list of resources that can help you build your initial AI knowledge:

  • Craftspire’s gpt-examples repository containing implementations of all examples used in this blog post, and more. When working on our next AI articles we will expand the repository with additional examples

  • Sourcecode of GPT Code Review Plugin developed by Craftspire.

  • OpenAI Playground is an excellent online sandbox where you can test various types of prompts and models without writing any code.

  • The OpenAI Cookbook contains a lot of various GPT prompt styles and tips on building effective queries.



That's it for today! Thanks for reading. 

If you found this topic interesting, be sure to check out our next blog post, where we'll cover more advanced OpenAI knowledge. 

We'll provide practical examples of complex topics including:

  • improving chat responsiveness with streaming

  • using tokenization to avoid problems with text exceeding maximum token count

  • patterns for handling common API errors like rate limits

  • practical examples using GPT embeddings for search, classification and clustering

  • using your own data to fine-tune the GPT models


Previous
Previous

Handling Most Common Performance Problems in SaaS Development

Next
Next

Analyzing Backend and API Performance Issues as a Startup or Scale-Up