Acerca de este codelab
1. Introducción
Los modelos de IA generativa son excelentes para comprender el lenguaje natural y responder al lenguaje natural. Pero ¿qué sucede si se necesitan resultados precisos y predecibles para tareas críticas como la estandarización de direcciones? En ocasiones, los modelos generativos tradicionales pueden proporcionar respuestas distintas en momentos diferentes para las mismas instrucciones, lo que puede generar inconsistencias. Aquí es donde se destaca la función de llamadas a función de Gemini, que te permite controlar de manera determinista elementos de la respuesta de la IA.
En este codelab, se ilustra este concepto con el caso de uso de estandarización y finalización de direcciones. Para ello, compilaremos una Cloud Function de Java que realice las siguientes tareas:
- Toma las coordenadas de latitud y longitud
- Llama a la Google Maps Geocoding API para obtener las direcciones correspondientes.
- Usa la función de llamadas a función Pro de Gemini 1.0 para estandarizar y resumir de forma determinista esas direcciones en un formato específico que necesitamos.
¡Comencemos!
2. Llamadas a funciones de Gemini
Las llamadas a funciones de Gemini se destacan en la era de la IA generativa porque te permiten combinar la flexibilidad de los modelos de lenguaje generativo con la precisión de la programación tradicional.
Estas son las tareas que debes completar para implementar las llamadas a funciones de Gemini:
- Definir funciones: Describe las funciones con claridad. Las descripciones deben incluir la siguiente información:
- El nombre de la función, como
getAddress
- Los parámetros que espera la función, como
latlng
como una cadena - El tipo de datos que muestra la función, como una lista de cadenas de direcciones.
- Crear herramientas para Gemini: Empaqueta descripciones de funciones en forma de especificación de API en herramientas. Piensa en una herramienta como una caja de herramientas especializada que Gemini puede usar para comprender la funcionalidad de la API.
- Organiza las APIs con Gemini: Cuando envías una instrucción a Gemini, puede analizar tu solicitud y reconocer dónde puede usar las herramientas que proporcionaste. Luego, Gemini actúa como un organizador inteligente realizando las siguientes tareas:
- Genera los parámetros de API necesarios para llamar a tus funciones definidas. Gemini no llama a la API por ti. Debes llamar a la API en función de los parámetros y la firma que generó por ti la llamada a función de Gemini.
- Gemini procesa los resultados proporcionando los resultados de tus llamadas a la API a su generación y, luego, incorpora información estructurada en su respuesta final. Puedes procesar esta información de la manera que desees para tu solicitud.
En la siguiente imagen, se muestra el flujo de datos, los pasos involucrados en la implementación y el propietario de cada paso, como la aplicación, el LLM o la API:
Qué compilarás
Crearás e implementarás una Cloud Function de Java que hace lo siguiente:
- Toma las coordenadas de latitud y longitud.
- Llama a la Google Maps Geocoding API para obtener las direcciones correspondientes.
- Usa la función de llamada a funciones de Gemini 1.0 Pro para estandarizar y resumir de manera determinista esas direcciones en un formato específico.
4. Antes de comenzar
- En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
- Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo verificar si la facturación está habilitada en un proyecto.
- Activa Cloud Shell desde la consola de Google Cloud. Para obtener más información, consulta Usa Cloud Shell.
- Si tu proyecto no está configurado, usa el siguiente comando para configurarlo:
gcloud config set project <YOUR_PROJECT_ID>
- En Cloud Shell, configura las siguientes variables de entorno:
export GCP_PROJECT=<YOUR_PROJECT_ID>
export GCP_REGION=us-central1
- Habilita las APIs de Google Cloud necesarias ejecutando los siguientes comandos en Cloud Shell:
gcloud services enable cloudbuild.googleapis.com cloudfunctions.googleapis.com run.googleapis.com logging.googleapis.com storage-component.googleapis.com cloudaicompanion.googleapis.com aiplatform.googleapis.com
- Abre el Editor de Cloud Shell, haz clic en Extensiones y, luego, instala la extensión de Gemini y Google Cloud Code.
5. Implementa la Cloud Function
- Inicia el editor de Cloud Shell
- Haz clic en Cloud Code y, luego, expande la sección Cloud Functions.
- Haz clic en el ícono Crear función (+).
- En el diálogo Create New Application, selecciona la opción Java: Hello World.
- Proporciona un nombre para el proyecto en la ruta de acceso, como GeminiFunctionCalling.
- Haz clic en Explorer para ver la estructura del proyecto y, luego, abre el archivo pom.xml. En la siguiente imagen, se muestra la estructura del proyecto:
- Agrega las dependencias necesarias dentro de la etiqueta
<dependencies>... </dependencies>
en el archivopom.xml
. Puedes acceder a la totalidad depom.xml
desde el repositorio de GitHub de este proyecto. Copia el pom.xml desde allí al archivopom.xml
de tu proyecto actual que estás editando. - Copia la clase
HelloWorld.java
del vínculo de GeminiFunctionCalling de GitHub. Debes actualizarAPI_KEY
yproject_id
con tu clave de API de geocodificación y tu ID del proyecto de Google Cloud, respectivamente.
6. Comprende las llamadas a funciones con la clase HelloWorld.java
Entrada de instrucción
En este ejemplo, el siguiente es el mensaje de entrada: What's the address for the latlong value 40.714224,-73.961452.
A continuación, se muestra el fragmento de código correspondiente al mensaje de entrada en el archivo:
String promptText = "What's the address for the latlong value '" + latlngString + "'?"; //40.714224,-73.961452
Especificación de la API
En este ejemplo, se usa la API de Reverse Geocoding. A continuación, se detalla la especificación de la API:
/* Declare the function for the API to invoke (Geo coding API) */
FunctionDeclaration functionDeclaration =
FunctionDeclaration.newBuilder()
.setName("getAddress")
.setDescription("Get the address for the given latitude and longitude value.")
.setParameters(
Schema.newBuilder()
.setType(Type.OBJECT)
.putProperties(
"latlng",
Schema.newBuilder()
.setType(Type.STRING)
.setDescription("This must be a string of latitude and longitude coordinates separated by comma")
.build())
.addRequired("latlng")
.build())
.build();
Cómo organizar la instrucción con Gemini
La entrada de la instrucción y la especificación de la API se envían a Gemini:
// Add the function to a "tool"
Tool tool = Tool.newBuilder()
.addFunctionDeclarations(functionDeclaration)
.build();
// Invoke the Gemini model with the use of the tool to generate the API parameters from the prompt input.
GenerativeModel model = GenerativeModel.newBuilder()
.setModelName(modelName)
.setVertexAi(vertexAI)
.setTools(Arrays.asList(tool))
.build();
GenerateContentResponse response = model.generateContent(promptText);
Content responseJSONCnt = response.getCandidates(0).getContent();
La respuesta de esto son los parámetros organizados JSON a la API. Este es un resultado de ejemplo:
role: "model"
parts {
function_call {
name: "getAddress"
args {
fields {
key: "latlng"
value {
string_value: "40.714224,-73.961452"
}
}
}
}
}
Pasa el siguiente parámetro a la API de Reverse Geocoding
: "latlng=40.714224,-73.961452"
Haz coincidir el resultado organizado con el formato "latlng=VALUE"
.
Invoca la API
La siguiente es la sección del código que invoca la API:
// Create a request
String url = API_STRING + "?key=" + API_KEY + params;
java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
// Send the request and get the response
java.net.http.HttpResponse<String> httpresponse = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
// Save the response
String jsonResult = httpresponse.body().toString();
La cadena jsonResult
contiene la respuesta de la API de Geocoding inversa. La siguiente es una versión con formato del resultado:
"...277 Bedford Ave, Brooklyn, NY 11211, USA; 279 Bedford Ave, Brooklyn, NY 11211, USA; 277 Bedford Ave, Brooklyn, NY 11211, USA;..."
Procesa la respuesta de la API y prepara la instrucción
El siguiente código procesa la respuesta de la API y prepara la instrucción con instrucciones para procesar la respuesta:
// Provide an answer to the model so that it knows what the result
// of a "function call" is.
String promptString =
"You are an AI address standardizer for assisting with standardizing addresses accurately. Your job is to give the accurate address in the standard format as a JSON object containing the fields DOOR_NUMBER, STREET_ADDRESS, AREA, CITY, TOWN, COUNTY, STATE, COUNTRY, ZIPCODE, LANDMARK by leveraging the address string that follows in the end. Remember the response cannot be empty or null. ";
Content content =
ContentMaker.fromMultiModalData(
PartMaker.fromFunctionResponse(
"getAddress",
Collections.singletonMap("address", formattedAddress)));
String contentString = content.toString();
String address = contentString.substring(contentString.indexOf("string_value: \"") + "string_value: \"".length(), contentString.indexOf('"', contentString.indexOf("string_value: \"") + "string_value: \"".length()));
List<SafetySetting> safetySettings = Arrays.asList(
SafetySetting.newBuilder()
.setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH)
.setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)
.build(),
SafetySetting.newBuilder()
.setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT)
.setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)
.build()
);
Invoca a Gemini y devuelve la dirección estandarizada
El siguiente código pasa el resultado procesado del paso anterior como instrucción a Gemini:
GenerativeModel modelForFinalResponse = GenerativeModel.newBuilder()
.setModelName(modelName)
.setVertexAi(vertexAI)
.build();
GenerateContentResponse finalResponse = modelForFinalResponse.generateContent(promptString + ": " + address, safetySettings);
System.out.println("promptString + content: " + promptString + ": " + address);
// See what the model replies now
System.out.println("Print response: ");
System.out.println(finalResponse.toString());
String finalAnswer = ResponseHandler.getText(finalResponse);
System.out.println(finalAnswer);
La variable finalAnswer
tiene la dirección estandarizada en formato JSON. El siguiente es un resultado de ejemplo:
{"replies":["{ \"DOOR_NUMBER\": null, \"STREET_ADDRESS\": \"277 Bedford Ave\", \"AREA\": \"Brooklyn\", \"CITY\": \"New York\", \"TOWN\": null, \"COUNTY\": null, \"STATE\": \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null} null}"]}
Ahora que sabes cómo funcionan las llamadas a funciones de Gemini en el caso de uso de estandarización de direcciones, puedes implementar la Cloud Function.
7. Implementación y prueba
- Si ya creaste el proyecto GeminiFunctionCalling y, además, implementaste la Cloud Function, continúa con el paso 2. Si aún no creaste el proyecto, ve a la terminal de Cloud Shell y clona este repo:
git clone
https://github.com/AbiramiSukumaran/GeminiFunctionCalling - Navega a la carpeta del proyecto:
cd GeminiFunctionCalling
- Ejecuta la siguiente instrucción para compilar y, luego, implementar la Cloud Function:
gcloud functions deploy gemini-fn-calling --gen2 --region=us-central1 --runtime=java11 --source=. --entry-point=cloudcode.helloworld.HelloWorld --trigger-http
El siguiente es el formato de URL después de la implementación: https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling
- Ejecuta el siguiente comando desde la terminal para probar la Cloud Function:
gcloud functions call gemini-fn-calling --region=us-central1 --gen2 --data '{"calls":[["40.714224,-73.961452"]]}'
La siguiente es una respuesta para una instrucción de muestra aleatoria: '{"replies":["{ "DOOR_NUMBER": "277", "STREET_ADDRESS": "Bedford Ave", "AREA": null, "CITY": "Brooklyn", "TOWN": null, "COUNTY": "Kings County", "STATE": "NY", "COUNTRY": "USA", "ZIPCODE": "11211", "LANDMARK": null}}```"]}'
8. Limpia
Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta publicación:
- En la consola de Google Cloud, ve a la página Administrar recursos.
- En la lista de proyectos, elige el proyecto que deseas borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.
- Si quieres conservar tu proyecto, omite los pasos anteriores y borra la Cloud Function. Para ello, navega a Cloud Functions y, en la lista de funciones, marca la que quieras borrar y haz clic en BORRAR.
9. Felicitaciones
¡Felicitaciones! Usaste con éxito la función de llamada a funciones de Gemini en una aplicación de Java y transformaste una tarea de IA generativa en un proceso determinista y confiable. Para obtener más información sobre los modelos disponibles, consulta la documentación del producto Vertex AI LLM.