Instructivo sobre llamadas a funciones

Las llamadas a función facilitan la obtención de resultados de datos estructurados de modelos generativos. Luego, puedes 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 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. Estas son funciones que escribes en el lenguaje de tu app (es decir, no son Google Cloud Functions). El modelo puede pedirte que llames a una función y devuelvas el resultado para ayudar al modelo a controlar tu consulta.

Si aún no lo hiciste, consulta la Introducción a las llamadas a funciones para obtener más información. También puedes probar esta función en Google Colab o ver el código de ejemplo en el repositorio Guía de soluciones de la API de Gemini.

API de ejemplo para control de iluminación

Imagina que tienes un sistema de control de iluminación básico con una interfaz de programación de aplicaciones (API) y quieres permitir que los usuarios controlen las luces mediante solicitudes de texto simples. Puedes usar la función Llamadas a funciones para interpretar las solicitudes de cambio de iluminación de los usuarios y traducirlas en llamadas a la API para establecer los valores de iluminación. Este hipotético sistema de control de iluminación te permite controlar el brillo de la luz y la temperatura de color, definidos como dos parámetros separados:

Parámetro Tipo Obligatorio Descripción
brightness número Nivel de luz de 0 a 100. El cero está desactivado y el 100 es el brillo total.
colorTemperature cadena Es la temperatura del 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 tiene que especificar una habitación o ubicación. Esta es una solicitud JSON de ejemplo que podrías enviar a la API de control de iluminación para cambiar el nivel de luz al 50% con la temperatura de color de 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 interprete las solicitudes de iluminación de los usuarios y las asigne a la configuración de la API para controlar los valores de brillo y temperatura de color de una luz.

Antes de comenzar: Configura tu proyecto y clave de API

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

Define una función de API

Crea una función que realice una solicitud a la API. Esta función debe definirse dentro del código de tu aplicación, pero podría llamar a servicios o a las 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 la aplicación. A modo de demostración, en este instructivo, se define una función de API de prueba 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 para que el modelo la use 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 qué función seleccionar y cómo proporcionar valores para los parámetros en la llamada a función.

Declara funciones durante la inicialización del modelo

Si quieres usar las llamadas a funciones con un modelo, debes declarar tus funciones cuando inicialices el objeto del modelo. Para declarar funciones, debes configurar 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 la función, puedes solicitarle al modelo con la función definida. Debes usar las llamadas a función con instrucciones de chat (sendMessage()), ya que las llamadas a función generalmente se benefician de tener el contexto de las instrucciones y las 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 las sesiones de chat, ya que controla el historial de conversaciones por ti. Puedes usar enable_automatic_function_calling para que el SDK se ejecute 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 descritas 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.

Definir 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 devolver 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 del esquema de las funciones de Python no funciona en todos los casos. Por ejemplo, no se abordan 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"
   }
 }]

Esto muestra la lista de objetos genai.protos.Tool que se enviarán a la API. Si no te resulta familiar el formato impreso, es porque son clases de protobuf de Google. Cada genai.protos.Tool (1 en este caso) contiene una lista de genai.protos.FunctionDeclarations, que describen una función y sus argumentos.

A continuación, se muestra una declaración para la misma función de multiplicación escrita con las clases genai.protos. Ten en cuenta que estas clases solo describen la función para la API, no incluyen una implementación de ella. Por lo tanto, su uso no funciona con las llamadas automáticas a funciones, pero las funciones no siempre necesitan una implementación.

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 tú mismo:

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}))]))