Common shared infrastructure for integrating Google Gemini AI models with Quarkus applications through the LangChain4j framework, providing base chat model functionality, schema mapping, and embedding model support.
Complete support for Gemini's function calling capabilities, including function declarations with parameter schemas, function calls from the model, and function responses back to the model. Function calling enables the model to interact with external tools and APIs.
Declares a function that the model can call, including its name, description, and parameter schema. Function declarations are provided to the model in the request to enable tool use.
/**
* Declares a function available for the model to call.
*
* @param name The function name
* @param description Human-readable description of what the function does
* @param parameters Schema defining the function's parameters
*/
public record FunctionDeclaration(String name, String description, Parameters parameters);Defines the parameter schema for a function using JSON Schema-like structure.
/**
* Parameter schema for a function.
*
* @param type The parameter type (typically "object")
* @param properties Map of parameter names to their schema definitions
* @param required List of required parameter names
*/
public record Parameters(
String type,
Map<String, Map<String, Object>> properties,
List<String> required
) {
/**
* Creates an object-type parameter schema.
*
* @param properties Map of parameter names to their schemas
* @param required List of required parameter names
* @return Parameters instance with type "object"
*/
public static Parameters objectType(
Map<String, Map<String, Object>> properties,
List<String> required
);
/**
* Creates an empty parameter schema (for functions with no parameters).
*
* @return Parameters instance with no properties
*/
public static Parameters empty();
}Represents a function call made by the model. When the model decides to use a tool, it returns a FunctionCall in the response.
/**
* A function call from the model.
*
* @param name The name of the function to call
* @param args Map of argument names to values provided by the model
*/
public record FunctionCall(String name, Map<String, Object> args);Represents the result of executing a function. The application executes the function and returns the result to the model in this format.
/**
* A function execution response to send back to the model.
*
* @param name The name of the function that was executed
* @param response The response data from the function execution
*/
public record FunctionResponse(String name, Response response);
/**
* Response data from function execution.
*
* @param name The function name
* @param content The function's return value (any JSON-serializable object)
*/
public record Response(String name, Object content);// Declare a weather function
FunctionDeclaration getWeather = new FunctionDeclaration(
"get_weather",
"Get the current weather for a location",
FunctionDeclaration.Parameters.objectType(
Map.of(
"location", Map.of(
"type", "string",
"description", "City and state, e.g., San Francisco, CA"
),
"unit", Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit"),
"description", "Temperature unit"
)
),
List.of("location") // only location is required
)
);FunctionDeclaration getCurrentTime = new FunctionDeclaration(
"get_current_time",
"Returns the current date and time",
FunctionDeclaration.Parameters.empty()
);// Function with nested object parameters
FunctionDeclaration createEvent = new FunctionDeclaration(
"create_calendar_event",
"Creates a new event in the user's calendar",
FunctionDeclaration.Parameters.objectType(
Map.of(
"title", Map.of(
"type", "string",
"description", "Event title"
),
"start_time", Map.of(
"type", "string",
"description", "Start time in ISO 8601 format"
),
"end_time", Map.of(
"type", "string",
"description", "End time in ISO 8601 format"
),
"attendees", Map.of(
"type", "array",
"items", Map.of("type", "string"),
"description", "List of attendee email addresses"
),
"reminder_minutes", Map.of(
"type", "integer",
"description", "Minutes before event to send reminder"
)
),
List.of("title", "start_time", "end_time")
)
);// Step 1: Declare functions and create a tool
FunctionDeclaration getWeather = new FunctionDeclaration(
"get_weather",
"Get current weather for a location",
FunctionDeclaration.Parameters.objectType(
Map.of(
"location", Map.of("type", "string", "description", "City name")
),
List.of("location")
)
);
GenerateContentRequest.Tool weatherTool =
GenerateContentRequest.Tool.ofFunctionDeclarations(List.of(getWeather));
// Step 2: Send request with tools
GenerateContentRequest request = new GenerateContentRequest(
List.of(Content.ofPart(
Content.Part.ofText("What's the weather in Paris?")
)),
null,
List.of(weatherTool),
null
);
GenerateContentResponse response = chatModel.generateContext(request);
// Step 3: Check if model wants to call a function
List<ToolExecutionRequest> toolCalls =
GenerateContentResponseHandler.getToolExecutionRequests(response);
if (!toolCalls.isEmpty()) {
// Step 4: Extract function call details
GenerateContentResponse.Candidate candidate = response.candidates().get(0);
Content.Part callPart = candidate.content().parts().get(0);
FunctionCall call = callPart.functionCall();
System.out.println("Function: " + call.name());
System.out.println("Arguments: " + call.args());
// Step 5: Execute the function
Map<String, Object> weatherData = executeWeatherFunction(
(String) call.args().get("location")
);
// Step 6: Create function response
FunctionResponse.Response responseData = new FunctionResponse.Response(
"get_weather",
weatherData
);
FunctionResponse functionResponse = new FunctionResponse(
"get_weather",
responseData
);
// Step 7: Send function result back to model
List<Content> conversationHistory = new ArrayList<>(request.contents());
conversationHistory.add(candidate.content()); // Add model's function call
conversationHistory.add(Content.ofPart(
Content.Part.ofFunctionResponse(functionResponse)
));
GenerateContentRequest followUpRequest = new GenerateContentRequest(
conversationHistory,
null,
List.of(weatherTool),
null
);
GenerateContentResponse finalResponse = chatModel.generateContext(followUpRequest);
String answer = GenerateContentResponseHandler.getText(finalResponse);
System.out.println("Final answer: " + answer);
}
// Helper method
private Map<String, Object> executeWeatherFunction(String location) {
// Call actual weather API
return Map.of(
"temperature", 22,
"condition", "sunny",
"humidity", 65,
"location", location
);
}// Declare multiple functions
FunctionDeclaration getWeather = new FunctionDeclaration(
"get_weather",
"Get current weather",
FunctionDeclaration.Parameters.objectType(
Map.of("location", Map.of("type", "string")),
List.of("location")
)
);
FunctionDeclaration getForecast = new FunctionDeclaration(
"get_forecast",
"Get weather forecast for the next 7 days",
FunctionDeclaration.Parameters.objectType(
Map.of(
"location", Map.of("type", "string"),
"days", Map.of("type", "integer", "description", "Number of days (1-7)")
),
List.of("location")
)
);
FunctionDeclaration getAirQuality = new FunctionDeclaration(
"get_air_quality",
"Get current air quality index",
FunctionDeclaration.Parameters.objectType(
Map.of("location", Map.of("type", "string")),
List.of("location")
)
);
// Create tool with multiple functions
GenerateContentRequest.Tool weatherTools =
GenerateContentRequest.Tool.ofFunctionDeclarations(
List.of(getWeather, getForecast, getAirQuality)
);
// Model can now choose which function(s) to callGenerateContentResponse response = chatModel.generateContext(request);
// Model might call multiple functions in one response
for (GenerateContentResponse.Candidate candidate : response.candidates()) {
for (GenerateContentResponse.Candidate.Part part : candidate.content().parts()) {
if (part.functionCall() != null) {
FunctionCall call = part.functionCall();
// Execute each function
Object result = executeFunctionByName(call.name(), call.args());
// Collect function responses
// ...
}
}
}try {
Map<String, Object> result = executeFunction(call.name(), call.args());
FunctionResponse.Response response = new FunctionResponse.Response(
call.name(),
result
);
functionResponse = new FunctionResponse(call.name(), response);
} catch (Exception e) {
// Return error information to the model
FunctionResponse.Response errorResponse = new FunctionResponse.Response(
call.name(),
Map.of(
"error", true,
"message", e.getMessage(),
"type", e.getClass().getSimpleName()
)
);
functionResponse = new FunctionResponse(call.name(), errorResponse);
}string: Text valuesinteger: Whole numbersnumber: Floating point numbersboolean: true/false valuesarray: Lists of valuesobject: Nested objectstype: The data typedescription: Human-readable descriptionenum: List of allowed values (for string/integer types)items: Schema for array elementsproperties: Nested properties for objectsrequired: List of required property namesMap<String, Map<String, Object>> complexProperties = Map.of(
"user", Map.of(
"type", "object",
"properties", Map.of(
"name", Map.of("type", "string"),
"age", Map.of("type", "integer")
),
"required", List.of("name")
),
"preferences", Map.of(
"type", "array",
"items", Map.of("type", "string")
),
"priority", Map.of(
"type", "string",
"enum", List.of("low", "medium", "high")
)
);
FunctionDeclaration.Parameters params =
FunctionDeclaration.Parameters.objectType(complexProperties, List.of("user"));When using these types with LangChain4j's abstractions:
Install with Tessl CLI
npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-gemini-common@1.7.0