Cómo interactuar con las APIs usando llamadas a funciones en Gemini

1. Descripción general

¿Qué son las llamadas a funciones en Gemini?

La API de Vertex AI Gemini es una familia de modelos de IA generativa que desarrolló Google DeepMind y que están diseñados para casos de uso multimodales. Las llamadas a funciones son una función de los modelos de Gemini que les facilita a los desarrolladores obtener resultados de datos estructurados de los modelos generativos.

Luego, los desarrolladores pueden usar estos resultados para llamar a otras APIs y mostrar los datos de respuesta relevantes al modelo. En otras palabras, las llamadas a función te ayudan a conectar tus modelos generativos a sistemas externos para que el contenido generado incluya la información más actualizada y precisa.

Cómo funciona la llamada a función

Las funciones se describen usando declaraciones de funciones, que ayudan al modelo generativo a comprender el propósito y los parámetros de una función. Después de pasar declaraciones de funciones en una consulta a un modelo generativo, el modelo devuelve un objeto estructurado que incluye los nombres de funciones relevantes y sus argumentos basados en la consulta del usuario. Ten en cuenta que, con la llamada a función, el modelo en realidad no llama a la función. En su lugar, puedes usar la función y los parámetros mostrados para llamar a la función en cualquier lenguaje, biblioteca o framework que desees.

Interfaz de API

Qué compilarás

En este codelab, crearás una canalización de IA generativa con la API de Vertex AI Gemini y Python. Cuando usas tu app, los usuarios pueden preguntar por los tipos de cambio, y el sistema recuperará los datos más recientes de una API externa y responderá al usuario con la respuesta.

Qué aprenderás

  • Cómo interactuar con el modelo de Gemini usando la biblioteca cliente de Python
  • Cómo definir una declaración de función y registrarla como una herramienta
  • Cómo llamar a Gemini y obtener una respuesta de llamada a función
  • Cómo mostrar la respuesta de la función a Gemini y responder al usuario

Requisitos

2. Configuración y requisitos

Antes de que puedas comenzar a usar las llamadas a funciones en Gemini, debes habilitar la API de Vertex AI y, luego, instalar la versión más reciente de la biblioteca cliente de Vertex AI para Python.

Habilitar la API de Vertex AI

Para habilitar la API de Vertex AI, sigue estos pasos:

  1. En el navegador, navega a la página Detalles del servicio de la API de Vertex AI.
  2. Haz clic en el botón Habilitar para habilitar la API de Vertex AI en tu proyecto de Google Cloud.

Instala la biblioteca cliente de Python para Vertex AI

Sigue estos pasos para instalar las bibliotecas cliente de Python para Vertex AI:

  1. Abre una terminal en tu entorno de desarrollo.
  2. Verifica que tienes un entorno de desarrollo de Python válido y consulta estos lineamientos si es necesario.
  3. Ejecuta el siguiente comando para instalar la biblioteca cliente de Python para Vertex AI:
    pip install --upgrade google-cloud-aiplatform
    
  4. Si estás ejecutando en un entorno de notebook, es posible que debas reiniciar tu entorno de ejecución o kernel para usar los paquetes recién instalados.

Ya tienes todo listo para usar la API de Vertex AI.

3. Comprende el problema

¿Alguna vez interactuaste con un modelo grande de lenguaje o un modelo de IA generativa y le preguntaste sobre información actual o en tiempo real solo para obtener una respuesta con información desactualizada o imprecisa?

¡Intentémoslo ahora! Primero, importaremos los paquetes de Python relevantes y, luego, inicializaremos el modelo de Gemini. Puedes ejecutar el siguiente código en un entorno de desarrollo de Python, como Colab o Colab Enterprise, e instalando la versión más reciente del SDK de Vertex AI para Python:

import vertexai
from vertexai.generative_models import GenerativeModel
model = GenerativeModel("gemini-1.5-pro-001")

Ahora, hagamos una pregunta sobre el tipo de cambio de las distintas monedas de hoy:

response = model.generate_content(
    "What's the exchange rate for euros to dollars today?"
)
print(response.text)

El modelo debería generar una respuesta limitada o desactualizada para ti, similar a la siguiente:

As an AI language model, I don't have access to real-time currency exchange
rates. However, as of my last update in September 2021, the approximate exchange
rate between euros (EUR) and US dollars (USD) was:

1 EUR ≈ 1.18 USD

Please note that currency exchange rates constantly fluctuate and can vary
depending on various factors such as economic conditions, supply and demand,
political events, and more. To obtain the most up-to-date and accurate exchange
rate, I recommend using a reliable currency converter or financial website that
provides live rates.

[...]

Si un usuario final recibiera este tipo de respuesta, tendría que cambiar de contexto para buscar las monedas que le interesan, obtener el tipo de cambio más reciente y realizar las conversiones por su cuenta.

Lo ideal sería que una canalización de modelos generativos se encargue de algunas o todas estas tareas del usuario. En la siguiente sección, probarás algunas soluciones comunes para obtener respuestas estructuradas de modelos generativos de modo que puedas llamar a sistemas externos.

4. Prueba las soluciones comunes

Cuando trabajas con modelos generativos en situaciones en las que necesitas información o datos actualizados de fuentes externas, puedes llamar a una API externa y, luego, enviar los resultados al modelo generativo para que los use en su respuesta.

Antes de llamar a un sistema externo, debes determinar cuál es la función correcta, extraer los parámetros relevantes del usuario y colocar los parámetros en un objeto de datos estructurados. Esto suele implicar una ingeniería de instrucciones exhaustiva para obligar al modelo generativo a que genere datos estructurados válidos.

Revisemos la pregunta que hicimos en la sección anterior y agreguemos algunas instrucciones adicionales para el modelo. Intenta enviar la siguiente solicitud al modelo de Gemini:

user_prompt = "What's the exchange rate from euros to US dollars today?"

response = model.generate_content("""
Your task is to extract parameters from the user's input and return it as a
structured JSON payload. The user will ask about the exchange rate and which
currency they are converting from and converting to.

User input: {user_prompt}

Please extract the currencies as parameters and put them in a JSON object.
""".format(user_prompt=user_prompt))
print(response.text)

Este resultado es la siguiente respuesta de texto, que no es un JSON válido y nos será difícil trabajar con él:

```json
{
  "currency_from": "euros",
  "currency_to": "US dollars"
}
```

En particular, las primeras y las últimas líneas de la respuesta de texto incluyen acentos graves para delimitar el bloque de código, la primera línea incluye un especificador de idioma y los valores en el objeto JSON no son las abreviaturas estándar de moneda de tres letras que una API de cambio de monedas esperaría como parámetros de entrada.

Podríamos intentar usar Python para procesar posteriormente este texto y convertirlo en un JSON válido y un diccionario, agregar más instrucciones a la instrucción, proporcionar uno o más ejemplos del resultado deseado, ajustar el modelo o hacer otra llamada al modelo generativo para pedirle que limpie el JSON.

Pero existe una manera más determinista. Veamos cómo usar las llamadas a funciones en Gemini para consultar información en servicios externos y mostrar respuestas relevantes a los usuarios finales.

5. Cómo funciona la llamada a función

Antes de comenzar con la extracción de parámetros y la llamada a funciones, revisemos los pasos de la llamada a función y los componentes que se usan en el entorno de ejecución.

Descripción general de las llamadas a funciones en Gemini

Entrada del usuario a la API de Gemini

La instrucción del usuario se envía a la API de Gemini y, en esa llamada al modelo de Gemini, el desarrollador definió una o más declaraciones de funciones en una herramienta para que el modelo de Gemini sepa a qué funciones puede llamar y cómo llamarlas.

La API de Gemini devuelve una llamada a función

Según el contenido de la entrada y la instrucción del usuario, Gemini mostrará una respuesta de llamada a función con datos estructurados que incluyan el nombre de la función a la que se llamará y los parámetros correspondientes que se usarán.

Realiza una solicitud a la API

Luego, usarás el nombre de la función y los parámetros para realizar una solicitud a la API y recuperar información de un sistema externo o una API. El desarrollador implementa esta solicitud y respuesta a la API en el código de la aplicación, y estas se llevan a cabo fuera del alcance del SDK y la API de Gemini. Por ejemplo, puedes usar la biblioteca requests en Python para llamar a una API de REST y recibir una respuesta JSON. O puedes llamar a la función mediante el enfoque que prefieras y la biblioteca cliente.

Cómo devolver la respuesta de la API a Gemini

Por último, pasarás la respuesta de la API al modelo de Gemini para que pueda generar una respuesta a la instrucción inicial del usuario final o invocar otra respuesta de llamada a función si el modelo de Gemini determina que necesita información adicional.

6. Elige tu API

Ahora que comprendes el flujo general y los pasos específicos de las llamadas a funciones, crearás una canalización de IA generativa para recuperar las tasas de cambio de moneda más recientes. En primer lugar, debemos seleccionar qué API queremos usar como fuente de información.

Para nuestra app de cambio de moneda, usaremos la API de REST que se encuentra en https://www.frankfurter.app/ para recuperar la información más reciente sobre los tipos de cambio globales.

Para interactuar con esta API de REST, podríamos realizar una llamada a la API de REST con requests en Python de la siguiente manera:

import requests
url = "https://api.frankfurter.app/latest"
response = requests.get(url)
response.text

o una solicitud cURL, como la siguiente:

curl https://api.frankfurter.app/latest

que devuelve una respuesta similar a la siguiente:

{
  "amount": 1,
  "base": "EUR",
  "date": "2023-12-20",
  "rates": {
    "AUD": 1.6186, "BGN": 1.9558, "BRL": 5.3287,
    "CAD": 1.4609, "CHF": 0.946, "CNY": 7.8121,
    "CZK": 24.538, "DKK": 7.4565, "GBP": 0.86555,
    "HKD": 8.5439, "HUF": 385.23, "IDR": 16994,
    "ILS": 3.9983, "INR": 91.06, "ISK": 150.3,
    "JPY": 157.12, "KRW": 1425.62, "MXN": 18.6867,
    "MYR": 5.0977, "NOK": 11.2895, "NZD": 1.7421,
    "PHP": 60.991, "PLN": 4.3413, "RON": 4.9699,
    "SEK": 11.129, "SGD": 1.4562, "THB": 38.252,
    "TRY": 31.883, "USD": 1.0944, "ZAR": 20.111
  }
}

Debido a que las llamadas a función en Gemini en realidad no realizan la llamada a la API externa por ti, no existen esas restricciones para el tipo de API que uses. Puedes usar un servicio de Cloud Run, una Cloud Function, una solicitud a la API para un servicio de Google Cloud o cualquier API de REST externa.

7. Cómo definir una función y una herramienta

Ahora que seleccionaste una API de REST para usar, podemos definir una especificación de API y registrar la función en una herramienta.

Asegúrate de haber instalado la versión más reciente del SDK de Vertex AI para Python.

Luego, importa los módulos necesarios del SDK de Python y, luego, inicializa el modelo de Gemini:

from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

Si hacemos referencia a la API de REST en https://api.frankfurter.app/, podemos ver que acepta los siguientes parámetros de entrada:

Parámetro

Tipo

Descripción

from

String

Moneda de la que quiere convertir

to

String

Moneda que se convertirá en

date

String

Fecha para recuperar el tipo de cambio del

Con estos parámetros, una especificación parcial de OpenAPI para esta API de REST en formato YAML se verá así:

openapi: 3.0.0
info:
  title: Frankfurter Exchange Rate API
  description: This API provides current and historical exchange rates
  version: 1.0.0
servers:
  - url: https://api.frankfurter.app
paths:
  /{date}:
    get:
      summary: Get the latest currency exchange rates.
      parameters:
        - name: date
          in: path
          description: Get currency rates for a specific date or 'latest' if a date is not specified
          required: true
          schema:
            type: string
        - name: from
          in: query
          description: The currency to convert from.
          required: true
          schema:
            type: string
        - name: to
          in: query
          description: The currency to convert to.
          schema:
            type: string

Ahora, registraremos esto como FunctionDeclaration con el SDK de Python para Gemini:

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

Asegúrate de usar la mayor cantidad de detalles posible en las descripciones de funciones y parámetros, ya que el modelo generativo usará esta información para determinar qué función seleccionar y cómo completar los parámetros en la llamada a función.

Por último, definirás un Tool que incluya la declaración de la función:

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

Aquí, usas una declaración de función dentro de una herramienta, pero ten en cuenta que puedes registrar una o más declaraciones de función en una herramienta, y el modelo seleccionará la función adecuada para usar en el tiempo de ejecución. Consulta la documentación sobre llamadas a funciones en la API de Gemini para obtener más detalles sobre FunctionDeclaration, Tool y las clases relacionadas en el SDK de Gemini para Python.

Completaste la configuración de las definiciones de la función y la herramienta. En la próxima sección, llamaremos al modelo generativo con esta herramienta y recibiremos una llamada a función que podemos usar para llamar a la API de REST.

8. Genera una llamada a función

Ahora puedes indicarle al modelo generativo e incluir el tool que definiste:

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

Veamos el objeto de respuesta:

print(response.candidates[0].content)

role: "model"
parts {
  function_call {
    name: "get_exchange_rate"
    args {
      fields {
        key: "currency_to"
        value {
          string_value: "SEK"
        }
      }
      fields {
        key: "currency_from"
        value {
          string_value: "AUD"
        }
      }
      fields {
        key: "currency_date"
        value {
          string_value: "latest"
        }
      }
    }
  }
}

Parece que el modelo seleccionó la única función disponible y mostró una llamada a función para la función get_exchange_rate junto con los parámetros. Y los parámetros están en el formato correcto que queríamos. ¡Felicitaciones por recibir respuestas estructuradas de los modelos generativos!

En la siguiente sección, usarás la información de la respuesta para realizar una solicitud a la API.

9. Realiza una solicitud a la API

Recuerda que las llamadas a función de Gemini en realidad no realizan la llamada a la API externa por ti. En su lugar, tienes la libertad de usar cualquier lenguaje, biblioteca o framework que desees.

Aquí, usarás la biblioteca requests en Python para llamar a la API de REST de tipo de cambio.

Descomprimamos la respuesta en un diccionario de Python:

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

Ahora, podemos llamar a requests o a cualquier otro método:

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

Esto da como resultado una respuesta similar a esta:

'{"amount":1.0,"base":"AUD","date":"2024-01-16","rates":{"SEK":6.8682}}'

Y tenemos nuestra respuesta de la API de REST con la información más reciente sobre el tipo de cambio de hoy. En la siguiente sección, pasaremos esta información al modelo para que pueda generar una respuesta relevante para el usuario.

10. Genera una respuesta

Por último, generemos una respuesta para el usuario pasando la respuesta de la función al modelo en el siguiente turno de la conversación:

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

Una vez que pasemos la respuesta de la función al modelo, este responderá al mensaje del usuario junto con información relevante de la respuesta de la API.

The exchange rate from Australian dollars to Swedish krona on January 16, 2024,
is 1 Australian dollar is equal to 6.8663 Swedish krona.

So, 500 Australian dollars would be worth 500 * 6.8663 = 3,433.15 Swedish krona.

11. Ver el ejemplo de código completo

En este punto, puedes colocar tu código de Python en una API de backend con un servicio de Cloud Run, una Cloud Function o algún otro servicio de Cloud y, luego, implementar una app de frontend que use esta API de backend para realizar consultas de modelos y llamadas a la API.

Este es el ejemplo de código completo de nuestra solución final:

import requests
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

response.candidates[0].content

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

En esta implementación, usamos dos solicitudes al modelo generativo: una para generar una llamada a función y otra para mostrar la respuesta de la función. Ten en cuenta que este es solo un método para manejar las llamadas y respuestas a funciones con Gemini. También puedes realizar llamadas a función adicionales para obtener más información sobre tu consulta o usar las llamadas a función con chat y métodos asíncronos.

Para ver muestras de código adicionales, consulta el notebook de muestra para las llamadas a funciones en Gemini.

12. Felicitaciones

Con las llamadas a funciones en Gemini, compilaste correctamente una canalización de IA generativa que se usa con la API de Vertex AI Gemini y Python. Los usuarios pueden preguntar por los tipos de cambio, y el sistema recuperará los datos más recientes de una API externa y responderá con una respuesta.

Si se proporciona una instrucción de un usuario final, las llamadas a función en Gemini se encargan de seleccionar la función adecuada, extraer parámetros de la instrucción y mostrar un objeto de datos estructurados para que realices una llamada a la API externa.

El diseño de las llamadas a funciones en Gemini tiene como objetivo ofrecerte lo mejor de ambos mundos para extraer parámetros de forma determinista, a la vez que le deja al modelo generativo el resumen y la creación de contenido. No dudes en probar otras APIs y instrucciones en tu canalización, y explorar otras funciones disponibles relacionadas con la API de Gemini de Vertex AI.

Interfaz de API

Realiza una limpieza

Puedes realizar la siguiente limpieza para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que se usaron en este codelab:

Más información

Continúa con el aprendizaje sobre la IA conversacional y la IA generativa con las siguientes guías y recursos:

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.