Llama3.1 & Java & OOPS
4 min readAug 11, 2024
Core Java Program to add remove functions at runtime. while calling LLMs.
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
// Class to represent a variable definition
class VariableDefinition {
private final String name;
private final String type;
private final String description;
private final String[] enumValues;
public VariableDefinition(String name, String type, String description, String[] enumValues) {
this.name = name;
this.type = type;
this.description = description;
this.enumValues = enumValues;
}
public JSONObject toJSON() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", this.type);
jsonObject.put("description", this.description);
if (enumValues != null) {
jsonObject.put("enum", new JSONArray(enumValues));
}
return jsonObject;
}
public String getName() {
return name;
}
}
// Interface for handling functions
interface FunctionHandler {
String getFunctionName();
String getDescription();
JSONObject getFunctionJSON();
Map<String, VariableDefinition> getVariables();
void execute(JSONObject arguments);
}
// Concrete class for getCurrentWeather function
class GetCurrentWeatherFunction implements FunctionHandler {
@Override
public String getFunctionName() {
return "get_current_weather";
}
@Override
public String getDescription() {
return "Get the current weather for a location";
}
@Override
public JSONObject getFunctionJSON() {
JSONObject functionObject = new JSONObject();
functionObject.put("name", getFunctionName());
functionObject.put("description", getDescription());
JSONObject parametersObject = new JSONObject();
parametersObject.put("type", "object");
JSONObject propertiesObject = new JSONObject();
for (VariableDefinition variable : getVariables().values()) {
propertiesObject.put(variable.getName(), variable.toJSON());
}
parametersObject.put("properties", propertiesObject);
parametersObject.put("required", new JSONArray(getVariables().keySet()));
functionObject.put("parameters", parametersObject);
return functionObject;
}
@Override
public Map<String, VariableDefinition> getVariables() {
Map<String, VariableDefinition> variables = new HashMap<>();
variables.put("location", new VariableDefinition("location", "string", "The location to get the weather for, e.g. San Francisco, CA", null));
variables.put("format", new VariableDefinition("format", "string", "The format to return the weather in, e.g. 'celsius' or 'fahrenheit'", new String[]{"celsius", "fahrenheit"}));
return variables;
}
@Override
public void execute(JSONObject arguments) {
String location = arguments.getString("location");
String format = arguments.getString("format");
System.out.println("Executing getCurrentWeather with location: " + location + " and format: " + format);
// Logic to get weather data (you can integrate with a real weather API here)
}
}
// Concrete class for getForecast function
class GetForecastFunction implements FunctionHandler {
@Override
public String getFunctionName() {
return "get_forecast";
}
@Override
public String getDescription() {
return "Get the weather forecast for a location";
}
@Override
public JSONObject getFunctionJSON() {
JSONObject functionObject = new JSONObject();
functionObject.put("name", getFunctionName());
functionObject.put("description", getDescription());
JSONObject parametersObject = new JSONObject();
parametersObject.put("type", "object");
JSONObject propertiesObject = new JSONObject();
for (VariableDefinition variable : getVariables().values()) {
propertiesObject.put(variable.getName(), variable.toJSON());
}
parametersObject.put("properties", propertiesObject);
parametersObject.put("required", new JSONArray(getVariables().keySet()));
functionObject.put("parameters", parametersObject);
return functionObject;
}
@Override
public Map<String, VariableDefinition> getVariables() {
Map<String, VariableDefinition> variables = new HashMap<>();
variables.put("location", new VariableDefinition("location", "string", "The location to get the weather forecast for, e.g. San Francisco, CA", null));
variables.put("days", new VariableDefinition("days", "integer", "The number of days to get the forecast for", null));
return variables;
}
@Override
public void execute(JSONObject arguments) {
String location = arguments.getString("location");
int days = arguments.getInt("days");
System.out.println("Executing getForecast with location: " + location + " for " + days + " days");
// Logic to get forecast data (you can integrate with a real forecast API here)
}
}
// ApiClient class to handle the API request and response
public class ApiClient {
private Map<String, FunctionHandler> functionHandlers = new HashMap<>();
public ApiClient() {
// Registering available functions
registerFunction(new GetCurrentWeatherFunction());
registerFunction(new GetForecastFunction());
}
public void registerFunction(FunctionHandler handler) {
functionHandlers.put(handler.getFunctionName(), handler);
}
public void callApiAndHandleResponse() {
try {
// Construct the JSON payload
JSONObject payload = new JSONObject();
payload.put("model", "llama3.1");
JSONArray messagesArray = new JSONArray();
JSONObject messageObject = new JSONObject();
messageObject.put("role", "user");
messageObject.put("content", "What forecast for tomorrow in Paris?"); //forecast for a location What is the weather today
messagesArray.put(messageObject);
payload.put("messages", messagesArray);
payload.put("stream", false);
JSONArray toolsArray = new JSONArray();
// Add each function's JSON to the payload
for (FunctionHandler handler : functionHandlers.values()) {
JSONObject toolObject = new JSONObject();
toolObject.put("type", "function");
toolObject.put("function", handler.getFunctionJSON());
toolsArray.put(toolObject);
}
payload.put("tools", toolsArray);
System.out.println(payload.toString(1));
// URL of the API endpoint
String value_name = System.getenv("LLM_OLLAMA_HOST");
URL url = new URL(value_name+"/api/chat");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Set request method to POST
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
// Send JSON payload
try (OutputStream os = connection.getOutputStream()) {
byte[] input = payload.toString().getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// Handle the response
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// Parse the JSON response
JSONObject jsonResponse = new JSONObject(response.toString());
// Extract tool calls and execute corresponding functions
JSONObject messageObjectResponse = jsonResponse.getJSONObject("message");
JSONArray toolCallsArray = messageObjectResponse.getJSONArray("tool_calls");
for (int i = 0; i < toolCallsArray.length(); i++) {
JSONObject toolCall = toolCallsArray.getJSONObject(i);
JSONObject functionResponse = toolCall.getJSONObject("function");
String functionName = functionResponse.getString("name");
// Execute the registered function
FunctionHandler handler = functionHandlers.get(functionName);
if (handler != null) {
JSONObject arguments = functionResponse.getJSONObject("arguments");
handler.execute(arguments);
} else {
System.out.println("No handler registered for function: " + functionName);
}
}
System.out.println("Response handled successfully");
} else {
System.out.println("POST request failed with response code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ApiClient apiClient = new ApiClient();
apiClient.callApiAndHandleResponse();
}
}
Output:
“What forecast for tomorrow in Paris?”
Executing getForecast with location: Paris for 1 days
Response handled successfully
------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time: 10.276 s
Finished at: 2024-08-11T23:10:58+05:30
------------------------------------------------------------------------
“What is the weather today in Paris?”
Executing getCurrentWeather with location: Paris and format: celsius
Response handled successfully
------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time: 34.383 s
Finished at: 2024-08-11T23:15:17+05:30
------------------------------------------------------------------------
Installation -> https://github.com/ollama/ollama/blob/main/docs/faq.md
Reference: https://github.com/ollama/ollama/blob/main/docs/api.md
What is Function calling in GenAI?
Llama3.1 Function Call in Java
Design Pattern For AI Backend: Chain of Responsibility Pattern & Strategy Pattern