Ver em ai.google.dev | Executar no Google Colab | Consulte o código-fonte no GitHub |
É possível fornecer modelos do Gemini com descrições de funções. O modelo pode pedir que você chame uma função e envie o resultado de volta para ajudar o modelo a processar a consulta.
Configuração
Instalar o SDK do Python
O SDK do Python para a API Gemini está incluído no pacote google-generativeai
. Instale a dependência usando pip:
pip install -U -q google-generativeai
Importar pacotes
Importe os pacotes necessários.
import pathlib
import textwrap
import time
import google.generativeai as genai
from IPython import display
from IPython.display import Markdown
def to_markdown(text):
text = text.replace('•', ' *')
return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))
Configurar sua chave de API
Antes de usar a API Gemini, é necessário ter uma chave de API. Se você ainda não tiver uma, crie uma chave com um clique no Google AI Studio.
No Colab, adicione a chave ao gerenciador de secrets abaixo do "", no painel à esquerda. Dê o nome API_KEY
a ela.
Quando você tiver a chave de API, transmita-a ao SDK. Faça isso de duas maneiras:
- Coloque a chave na variável de ambiente
GOOGLE_API_KEY
. O SDK vai selecioná-la automaticamente de lá. - Transmita a chave para
genai.configure(api_key=...)
try:
# Used to securely store your API key
from google.colab import userdata
# Or use `os.getenv('API_KEY')` to fetch an environment variable.
GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
except ImportError:
import os
GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY']
genai.configure(api_key=GOOGLE_API_KEY)
Noções básicas de funções
É possível transmitir uma lista de funções para o argumento tools
ao criar um genai.GenerativeModel
.
def multiply(a:float, b:float):
"""returns a * b."""
return a*b
model = genai.GenerativeModel(model_name='gemini-1.0-pro',
tools=[multiply])
model
genai.GenerativeModel( model_name='models/gemini-1.0-pro', generation_config={}, safety_settings={}, tools=<google.generativeai.types.content_types.FunctionLibrary object at 0x10e73fe90>, )
A maneira recomendada de usar a chamada de funções é pela interface de chat. O principal motivo é que o FunctionCalls
se encaixa bem na estrutura de várias interações do chat.
chat = model.start_chat(enable_automatic_function_calling=True)
Com a chamada automática de funções ativada, o chat.send_message
vai chamar sua função automaticamente se o modelo pedir.
Ele parece simplesmente retornar uma resposta de texto, contendo a resposta correta:
response = chat.send_message('I have 57 cats, each owns 44 mittens, how many mittens is that in total?')
response.text
'The total number of mittens is 2508.'
57*44
2508
No ChatSession.history
, você verá a sequência de eventos:
- Você enviou a pergunta.
- O modelo respondeu com um
glm.FunctionCall
. - O
genai.ChatSession
executou a função localmente e enviou o modelo de volta umglm.FunctionResponse
. - O modelo usou a saída da função na resposta.
for content in chat.history:
part = content.parts[0]
print(content.role, "->", type(part).to_dict(part))
print('-'*80)
user -> {'text': 'I have 57 cats, each owns 44 mittens, how many mittens is that in total?'} -------------------------------------------------------------------------------- model -> {'function_call': {'name': 'multiply', 'args': {'a': 57.0, 'b': 44.0} } } -------------------------------------------------------------------------------- user -> {'function_response': {'name': 'multiply', 'response': {'result': 2508.0} } } -------------------------------------------------------------------------------- model -> {'text': 'The total number of mittens is 2508.'} --------------------------------------------------------------------------------
Em geral, o diagrama de estado é:
O modelo pode responder com várias chamadas de função antes de retornar uma resposta de texto, e as chamadas de função vêm antes da resposta de texto.
Embora tudo isso seja automático, você pode fazer o seguinte para ter mais controle:
- Deixe o valor padrão
enable_automatic_function_calling=False
e processe as respostasglm.FunctionCall
por conta própria. - Ou use o
GenerativeModel.generate_content
, onde você também precisa gerenciar o histórico de chat.
[Opcional] Acesso de baixo nível
A extração automática do esquema de 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 suporta 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, proporcionando controle total.
import google.ai.generativelanguage as glm
Primeiro, confira o atributo _tools
do modelo para saber como ele descreve as funções que você transmitiu ao modelo:
def multiply(a:float, b:float):
"""returns a * b."""
return a*b
model = genai.GenerativeModel(model_name='gemini-1.0-pro',
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 glm.Tool
que seriam enviados à API. Se o formato impresso não for familiar, é porque essas são classes protobuf do Google. Cada glm.Tool
(1, neste caso) contém uma lista de glm.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 glm
.
Essas classes apenas descrevem a função da API, e não incluem uma implementação dela. Portanto, usar isso não funciona com a chamada automática de funções, mas as funções nem sempre precisam de uma implementação.
calculator = glm.Tool(
function_declarations=[
glm.FunctionDeclaration(
name='multiply',
description="Returns the product of two numbers.",
parameters=glm.Schema(
type=glm.Type.OBJECT,
properties={
'a':glm.Schema(type=glm.Type.NUMBER),
'b':glm.Schema(type=glm.Type.NUMBER)
},
required=['a','b']
)
)
])
Da mesma forma, é possível descrever esse objeto 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']} }]}
glm.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 glm.Tool
ou uma lista de ferramentas para
model = genai.GenerativeModel('gemini-pro', tools=calculator)
chat = model.start_chat()
response = chat.send_message(
f"What's 234551 X 325552 ?",
)
Como antes, o modelo retorna um glm.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
Para continuar a conversa, envie o resultado ao modelo:
response = chat.send_message(
glm.Content(
parts=[glm.Part(
function_response = glm.FunctionResponse(
name='multiply',
response={'result': result}))]))
Resumo
A chamada de função básica é compatível com o SDK. Lembre-se de que é mais fácil gerenciar usando o modo de chat devido à estrutura natural de idas e vindas. Você é responsável por chamar as funções e enviar os resultados de volta ao modelo para que ele produza uma resposta de texto.