Tutorial sobre chamada de função

A chamada de função facilita a geração de saídas de dados estruturados de modelos generativos. Depois, use essas saídas para chamar outras APIs e retornar os dados de resposta relevantes ao modelo. Em outras palavras, a chamada de função ajuda você a conectar modelos generativos a sistemas externos, para que o conteúdo gerado inclua as informações mais atualizadas e precisas.

É possível fornecer descrições de funções aos modelos do Gemini. Essas são funções que você escreve na linguagem do seu app (ou seja, não são funções do Google Cloud). O modelo pode pedir que você chame uma função e envie de volta o resultado para ajudar o modelo a lidar com sua consulta.

Caso ainda não tenha feito isso, confira a Introdução à chamada de função para saber mais. Também é possível testar esse recurso no Google Colab ou conferir o exemplo de código no repositório Manual da API Gemini (link em inglês).

Exemplo de API para controle de iluminação

Imagine que você tem um sistema básico de controle de iluminação com uma interface de programação do aplicativo (API) e quer permitir que os usuários controlem as luzes usando solicitações de texto simples. Use o recurso de chamada de função para interpretar solicitações de mudança de iluminação dos usuários e convertê-las em chamadas de API para definir os valores de iluminação. Esse sistema hipotético de controle de iluminação permite controlar o brilho da luz e a temperatura da cor, definidas por dois parâmetros separados:

Parâmetro Tipo Obrigatório Descrição
brightness number sim Nível de iluminação de 0 a 100. Zero é desativado e 100 é brilho total.
colorTemperature string sim A temperatura da cor da luminária, que pode ser daylight, cool ou warm.

Para simplificar, esse sistema de iluminação imaginário tem apenas uma luz. Portanto, o usuário não precisa especificar um ambiente ou local. Veja um exemplo de solicitação JSON que pode ser enviada à API de controle de iluminação para mudar o nível de luz para 50% usando a temperatura da cor diurna:

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

Neste tutorial, mostramos como configurar uma chamada de função para a API Gemini para interpretar solicitações de iluminação dos usuários e mapeá-las para as configurações da API para controlar o brilho e os valores de temperatura da cor de uma luz.

Antes de começar: configurar o projeto e a chave de API

Antes de chamar a API Gemini, você precisa configurar seu projeto e sua chave de API.

Definir uma função de API

Crie uma função que faça uma solicitação de API. Essa função precisa ser definida no código do aplicativo, mas pode chamar serviços ou APIs de fora do aplicativo. A API Gemini não chama essa função diretamente. Portanto, você pode controlar como e quando ela é executada pelo código do aplicativo. Para fins de demonstração, este tutorial define uma função de API simulada que apenas retorna os valores de iluminação 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
    }

Ao criar uma função a ser usada em uma chamada de função pelo modelo, inclua o máximo de detalhes possível nas descrições da função e do parâmetro. O modelo generativo usa essas informações para determinar qual função selecionar e como fornecer valores para os parâmetros na chamada de função.

Declarar funções durante a inicialização do modelo

Se quiser usar a chamada de função com um modelo, declare suas funções ao inicializar o objeto de modelo. Para declarar funções, defina o parâmetro tools do modelo:

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

Gerar uma chamada de função

Depois de inicializar o modelo com as declarações de função, é possível solicitar o modelo com a função definida. Use a chamada de função com os comandos de chat (sendMessage()), já que ela geralmente se beneficia de ter o contexto de comandos e respostas anteriores.

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

O objeto ChatSession do SDK para Python simplifica o gerenciamento de sessões de chat ao processar o histórico de conversas para você. Você pode usar enable_automatic_function_calling para que o SDK seja criado automaticamente.

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

Chamada de função paralela

Além da chamada de função básica descrita acima, você também pode chamar várias funções de uma só vez. Nesta seção, mostramos um exemplo de como usar a chamada de função paralela.

Definir as ferramentas.

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

Agora, chame o modelo com uma instrução que use todas as ferramentas 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 um dos resultados impressos reflete uma única chamada de função solicitada pelo modelo. Para enviar os resultados de volta, inclua as respostas na mesma ordem em que foram solicitadas.

# 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! 🕺💃

Mapeamento de tipo de dados de chamada de função

A extração automática do esquema das funções do Python não funciona em todos os casos. Por exemplo: ela não processa casos em que você descreve os campos de um objeto de dicionário aninhado, mas a API oferece suporte para isso. A API é capaz de descrever qualquer um dos seguintes tipos:

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

A biblioteca de cliente google.ai.generativelanguage fornece acesso aos tipos de nível inferior, oferecendo controle total para você.

Primeiro acesse o atributo _tools do modelo e observe como ele descreve as funções transmitidas para o 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"
   }
 }]

Isso retorna a lista de objetos genai.protos.Tool que seriam enviados à API. Se o formato impresso não for conhecido, é porque essas são classes protobuf do Google. Cada genai.protos.Tool (1, neste caso) contém uma lista de genai.protos.FunctionDeclarations, que descreve uma função e os argumentos dela.

Veja a seguir uma declaração para a mesma função de multiplicação escrita usando as classes genai.protos. Essas classes apenas descrevem a função da API, não incluem uma implementação dela. Portanto, usá-lo não funciona com chamadas automáticas de função, mas as funções nem sempre precisam de uma implementação.

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 maneira equivalente, você pode descrever isso como um objeto compatível com 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 qualquer forma, você transmite uma representação de um genai.protos.Tool ou uma lista de ferramentas para

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

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

Assim como antes, o modelo retorna um genai.protos.FunctionCall invocando a função multiply da 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
]

Execute a função:

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

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

Envie o resultado ao modelo para continuar a conversa:

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