Instructivo sobre llamadas a funciones

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

Puedes proporcionarles descripciones de funciones a los modelos de Gemini. Son funciones que escribes en el lenguaje de tu app (es decir, Google Cloud Functions). Es posible que el modelo te solicite que llames a una función y le envíes el resultado para ayudarlo a controlar tu consulta.

Si aún no lo has hecho, consulta la Introducción a la llamada a función para aprender más. También puedes prueba esta función en Google Colab o mira el código de ejemplo en la Repositorio de la guía de soluciones de la API de Gemini.

Ejemplo de API para el control de iluminación

Imagina que tienes un sistema de control de iluminación básico con una aplicación (API), y quieres permitir que los usuarios controlen las luces mediante solicitudes de texto. Puedes usar la función Llamadas a función para interpretar la iluminación de los usuarios y convertirlas en llamadas a la API para establecer la iluminación de salida. Este hipotético sistema de control de iluminación te permite controlar la el brillo de la luz y su temperatura de color, que se definen como dos parámetros:

Parámetro Tipo Obligatorio Descripción
brightness número Nivel de luz de 0 a 100. Cero es la opción de apagado y 100 es el brillo máximo.
colorTemperature string Temperatura de color de la lámpara, que puede ser daylight, cool o warm.

Para simplificar, este sistema de iluminación imaginario solo tiene una luz, por lo que el usuario no necesita especificar una sala o ubicación. Este es un ejemplo de una solicitud JSON podrías enviar a la API de control de iluminación para cambiar el nivel de luz al 50% usando la temperatura de color de la luz diurna:

{
  "brightness": "50",
  "colorTemperature": "daylight"
}

En este instructivo, se muestra cómo configurar una llamada a función para que la API de Gemini haga lo siguiente: interpretar las solicitudes de iluminación de los usuarios y asignarlas a la configuración de la API para controlar un el brillo de la luz y los valores de temperatura de color.

Antes de comenzar: Configura tu proyecto y clave de API

Antes de llamar a la API de Gemini, debes configurar tu proyecto y tu clave de API.

Define una función de API

Crea una función que realice una solicitud a la API. Esta función se debe definir dentro del código de tu aplicación, pero podría llamar a servicios o APIs fuera de tu aplicación. La API de Gemini no llama a esta función directamente, por lo que puedes controlar cómo y cuándo se ejecuta a través del código de tu aplicación. A modo de demostración, este instructivo define una función de API simulada que solo muestra los valores de iluminación solicitados:

def set_light_values(brightness, color_temp):
    """Set the brightness and color temperature of a room light. (mock API).

    Args:
        brightness: Light level from 0 to 100. Zero is off and 100 is full brightness
        color_temp: Color temperature of the light fixture, which can be `daylight`, `cool` or `warm`.

    Returns:
        A dictionary containing the set brightness and color temperature.
    """
    return {
        "brightness": brightness,
        "colorTemperature": color_temp
    }

Cuando creas una función que el modelo usará en una llamada a función, debes incluir tantos detalles como sea posible en las descripciones de la función y los parámetros. El modelo generativo usa esta información para determinar función para seleccionar y cómo proporcionar valores para los parámetros en la función llamada.

Cómo declarar funciones durante la inicialización del modelo

Cuando quieras usar las llamadas a función con un modelo, debes declarar tu cuando inicializas el objeto del modelo. Para declarar las funciones, establece el parámetro tools del modelo:

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                              tools=[set_light_values])

Genera una llamada a función

Una vez que hayas inicializado el modelo con las declaraciones de tu función, puedes indicar al modelo con la función definida. Deberías usar las llamadas a funciones con las instrucciones de chat (sendMessage()), ya que las llamadas a función suelen beneficiarse de con el contexto de instrucciones y respuestas anteriores.

chat = model.start_chat()
response = chat.send_message('Dim the lights so the room feels cozy and warm.')
response.text

El objeto ChatSession del SDK de Python simplifica la administración de sesiones de chat, ya que controla el historial de conversaciones por ti. Puedes usar enable_automatic_function_calling para tener el SDK automáticamente.

# Create a chat session that automatically makes suggested function calls
chat = model.start_chat(enable_automatic_function_calling=True)

Llamadas a funciones paralelas

Además de las llamadas a funciones básicas que se describieron anteriormente, también puedes llamar a varias funciones en un solo turno. En esta sección, se muestra un ejemplo de cómo puedes usar las llamadas a funciones paralelas.

Define las herramientas.

def power_disco_ball(power: bool) -> bool:
    """Powers the spinning disco ball."""
    print(f"Disco ball is {'spinning!' if power else 'stopped.'}")
    return True


def start_music(energetic: bool, loud: bool, bpm: int) -> str:
    """Play some music matching the specified parameters.

    Args:
      energetic: Whether the music is energetic or not.
      loud: Whether the music is loud or not.
      bpm: The beats per minute of the music.

    Returns: The name of the song being played.
    """
    print(f"Starting music! {energetic=} {loud=}, {bpm=}")
    return "Never gonna give you up."


def dim_lights(brightness: float) -> bool:
    """Dim the lights.

    Args:
      brightness: The brightness of the lights, 0.0 is off, 1.0 is full.
    """
    print(f"Lights are now set to {brightness:.0%}")
    return True

Ahora llama al modelo con una instrucción que pueda usar todas las herramientas especificadas.

# Set the model up with tools.
house_fns = [power_disco_ball, start_music, dim_lights]

model = genai.GenerativeModel(model_name="gemini-1.5-flash", tools=house_fns)

# Call the API.
chat = model.start_chat()
response = chat.send_message("Turn this place into a party!")

# Print out each of the function calls requested from this single call.
for part in response.parts:
    if fn := part.function_call:
        args = ", ".join(f"{key}={val}" for key, val in fn.args.items())
        print(f"{fn.name}({args})")
power_disco_ball(power=True)
start_music(energetic=True, loud=True, bpm=120.0)
dim_lights(brightness=0.3)

Cada uno de los resultados impresos refleja una única llamada a función que el modelo solicitó. Para enviar los resultados, incluye las respuestas en el mismo orden en que se solicitaron.

# Simulate the responses from the specified tools.
responses = {
    "power_disco_ball": True,
    "start_music": "Never gonna give you up.",
    "dim_lights": True,
}

# Build the response parts.
response_parts = [
    genai.protos.Part(function_response=genai.protos.FunctionResponse(name=fn, response={"result": val}))
    for fn, val in responses.items()
]

response = chat.send_message(response_parts)
print(response.text)
Let's get this party started! I've turned on the disco ball, started playing some upbeat music, and dimmed the lights. 🎶✨  Get ready to dance! 🕺💃

Asignación de tipos de datos de llamadas a función

La extracción automática de esquemas a partir de funciones de Python no funciona en todos los casos. Por ejemplo, no controla los casos en los que describes los campos de un objeto de diccionario anidado, pero la API sí lo admite. La API puede describir cualquiera de los siguientes tipos:

AllowedType = (int | float | bool | str | list['AllowedType'] | dict[str, AllowedType])

La biblioteca cliente google.ai.generativelanguage proporciona acceso a los tipos de bajo nivel, lo que te da control total.

Primero, un vistazo al atributo _tools del modelo, puedes ver cómo describe las funciones que le pasaste al modelo:

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                             tools=[multiply])

model._tools.to_proto()
[function_declarations {
   name: "multiply"
   description: "returns a * b."
   parameters {
     type_: OBJECT
     properties {
       key: "b"
       value {
         type_: NUMBER
       }
     }
     properties {
       key: "a"
       value {
         type_: NUMBER
       }
     }
     required: "a"
     required: "b"
   }
 }]

Muestra la lista de objetos genai.protos.Tool que se enviarían al API de gcloud. Si no te resulta familiar el formato impreso, es porque son productos de Google protobufs. Cada genai.protos.Tool (1 en este caso) contiene una lista de genai.protos.FunctionDeclarations, que describe una función y su argumentos.

Esta es una declaración de la misma función de multiplicación escrita con las clases genai.protos. Ten en cuenta que estas clases solo describen la función de la API, no incluyen una implementación de esta. Por lo tanto, no funciona con las llamadas automáticas a funciones, pero las funciones no siempre necesitan un para implementarlos.

calculator = genai.protos.Tool(
    function_declarations=[
      genai.protos.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={
                'a':genai.protos.Schema(type=genai.protos.Type.NUMBER),
                'b':genai.protos.Schema(type=genai.protos.Type.NUMBER)
            },
            required=['a','b']
        )
      )
    ])

De manera equivalente, puedes describir esto como un objeto compatible con JSON:

calculator = {'function_declarations': [
      {'name': 'multiply',
       'description': 'Returns the product of two numbers.',
       'parameters': {'type_': 'OBJECT',
       'properties': {
         'a': {'type_': 'NUMBER'},
         'b': {'type_': 'NUMBER'} },
       'required': ['a', 'b']} }]}
genai.protos.Tool(calculator)
function_declarations {
  name: "multiply"
  description: "Returns the product of two numbers."
  parameters {
    type_: OBJECT
    properties {
      key: "b"
      value {
        type_: NUMBER
      }
    }
    properties {
      key: "a"
      value {
        type_: NUMBER
      }
    }
    required: "a"
    required: "b"
  }
}

De cualquier manera, pasas una representación de un genai.protos.Tool o una lista de herramientas a

model = genai.GenerativeModel('gemini-1.5-flash', tools=calculator)
chat = model.start_chat()

response = chat.send_message(
    f"What's 234551 X 325552 ?",
)

Al igual que antes, el modelo muestra un genai.protos.FunctionCall que invoca la función multiply de la calculadora:

response.candidates
[index: 0
content {
  parts {
    function_call {
      name: "multiply"
      args {
        fields {
          key: "b"
          value {
            number_value: 325552
          }
        }
        fields {
          key: "a"
          value {
            number_value: 234551
          }
        }
      }
    }
  }
  role: "model"
}
finish_reason: STOP
]

Ejecuta la función por tu cuenta:

fc = response.candidates[0].content.parts[0].function_call
assert fc.name == 'multiply'

result = fc.args['a'] * fc.args['b']
result
76358547152.0

Envía el resultado al modelo para continuar la conversación:

response = chat.send_message(
    genai.protos.Content(
    parts=[genai.protos.Part(
        function_response = genai.protos.FunctionResponse(
          name='multiply',
          response={'result': result}))]))