Uso de ferramentas


Uso de ferramentas (frequentemente chamado de function calling) é como um modelo de linguagem alcança além de sua própria caixa de texto: você entrega uma lista de funções que ele pode pedir para executar, e ele decide quando usá-las. O modelo nunca executa nada por si só, apenas solicita uma chamada, e seu código faz o trabalho.
Um modelo por si só está fechado em uma caixa. Ele não pode verificar o clima de hoje, procurar um usuário em seu banco de dados ou enviar um email. Ele apenas prevê texto do que aprendeu, congelado no momento do treinamento, a mesma imagem de como os LLMs funcionam. Uso de ferramentas é como você deixa alcançar fora da caixa, e é a base em que agentes são construídos.
A palavra para lembrar é "pedir". O modelo diz qual função quer e com quais argumentos. Seu código executa e retorna o resultado. Você permanece no controle o tempo todo.
O loop
Uso de ferramentas é um idas e vindas, não uma única chamada:
- Você envia a mensagem do usuário mais uma lista de ferramentas que o modelo pode usar.
- O modelo responde de uma de duas formas: uma resposta normal ou uma solicitação para chamar uma ferramenta, com os argumentos que quer.
- Se pediu uma ferramenta, seu código executa essa função e envia o resultado de volta ao modelo.
- O modelo usa o resultado para escrever sua resposta final.
Esse é o padrão completo. O modelo pede, seu código executa. Os passos 2 e 3 podem se repetir se o modelo precisar de várias ferramentas, que é o germe de agentes alguns capítulos adiante.
O que realmente está acontecendo
Uso de ferramentas pode parecer que o modelo ganhou novos poderes, e não ganhou. Internamente, o modelo faz a única coisa que sempre faz: prever texto. Nada mudou sobre a caixa em que vive.
Quando você inclui definições de ferramentas na solicitação, você está adicionando-as ao contexto a partir do qual o modelo prevê. O modelo foi treinado em exemplos onde, dadas ferramentas como essas, a continuação correta é às vezes uma mensagem especialmente formatada que significa "chame get_weather com a cidade São Paulo" em vez de uma frase normal. Então quando sua pergunta torna uma ferramenta útil, a saída mais provável é essa mensagem de chamada de ferramenta estruturada, e a API a superficializa para você como tool_calls.
O modelo não alcançou e executou nada. Ele previu que uma chamada de ferramenta é o movimento certo e escreveu uma solicitação para uma, em um formato que seu código sabe ler.
Então você, não o modelo, executa a função. Você pega o resultado real e o coloca de volta nas mensagens como mais contexto, e o modelo prevê sua resposta final a partir desse contexto ampliado. Toda a funcionalidade são duas previsões ordinárias com seu código fazendo o trabalho real no meio.
Você é a ponte entre a caixa de texto do modelo e o mundo real. Mantenha essa imagem e o resto do capítulo, agentes inclusos, para de parecer misterioso: cada ação que uma IA toma é uma solicitação prevista que seu código escolhe executar.
tool_calls. O modelo nunca executa nada, ele prevê uma solicitação. Seu código executa a função e alimenta o resultado de volta como mais contexto para a próxima previsão, então você é a ponte entre o modelo e o mundo real. Definindo uma ferramenta
Você descreve cada ferramenta para o modelo: seu nome, o que faz e os argumentos que toma. A descrição não é documentação para você, é uma instrução para o modelo sobre quando usar a ferramenta, então escreva como o prompt que é.
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtenha o clima atual de uma cidade. Use quando o usuário pergunta sobre clima.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "O nome da cidade, ex: 'São Paulo'"},
},
"required": ["city"],
},
},
},
]O bloco parameters é um esquema, a mesma ideia de saída estruturada: ele define os argumentos que o modelo deve produzir. Quando o modelo decide chamar get_weather, ele envia de volta um argumento city correspondendo a essa forma. Uma descrição vaga ("obtém clima") leva o modelo a usar a ferramenta nos momentos errados. Uma clara ("Use quando o usuário pergunta sobre clima") a guia bem.
parameters para seus argumentos. A descrição é realmente um prompt: ela diz ao modelo quando usar a ferramenta, então escreva com cuidado. O esquema de parâmetros é o mesmo mecanismo de saída estruturada, restringindo os argumentos que o modelo envia. Manipulando a chamada
Quando o modelo quer uma ferramenta, a resposta contém tool_calls em vez de uma resposta final. Você lê a função solicitada e os argumentos, executa a função real e envia o resultado de volta como uma mensagem tool. Então você chama o modelo novamente para que ele possa terminar.
import json
# implementação real da ferramenta
def get_weather(city):
# em um app real isso chama uma API de clima; aqui fingimos
return {"city": city, "tempC": 18, "condition": "cloudy"}
messages = [{"role": "user", "content": "Qual é o clima em São Paulo?"}]
# 1. primeira chamada: ofereça as ferramentas
response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
tool_calls = response.choices[0].message.tool_calls
tool_call = tool_calls[0] if tool_calls else None
if tool_call:
# 2. execute a função solicitada com os argumentos do modelo
args = json.loads(tool_call.function.arguments)
result = get_weather(args["city"])
# 3. envie a solicitação do modelo e seu resultado de volta
messages.append(response.choices[0].message) # a solicitação de ferramenta do assistente
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result),
})
# 4. chame novamente para o modelo poder responder usando o resultado
response = client.chat.completions.create(model=MODEL, messages=messages)
print(response.choices[0].message.content)
# "Está atualmente 18 graus e nublado em São Paulo."Os argumentos chegam como uma string JSON, então você json.loads para um objeto real, depois verifica antes de usar. Você coloca duas mensagens no histórico: a solicitação de ferramenta do modelo e seu resultado tool, ligados por tool_call_id. A chamada final transforma os dados de clima brutos em uma frase natural.
tool_calls em vez de texto. Você analisa os argumentos de uma string JSON, executa a função real e coloca duas mensagens de volta: a solicitação do modelo e seu resultado, ligadas por tool_call_id. Uma chamada de modelo final transforma seu resultado bruto em uma resposta natural. Na prática
O mesmo fluxo que uma função reutilizável. Repare que a única coisa entre o modelo e seus sistemas é código que você escreveu e controla:
import json
tool_impls = {"get_weather": lambda args: get_weather(args["city"])}
def answer_with_tools(user_text):
messages = [{"role": "user", "content": user_text}]
response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
calls = response.choices[0].message.tool_calls
if not calls:
return response.choices[0].message.content # modelo respondeu diretamente
call = calls[0]
args = json.loads(call.function.arguments)
result = tool_impls[call.function.name](args)
messages.append(response.choices[0].message)
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
response = client.chat.completions.create(model=MODEL, messages=messages)
return response.choices[0].message.contentIsso manipula uma chamada de ferramenta. Um modelo também pode solicitar várias de uma vez, chamadas de ferramentas paralelas, que você manipularia ao fazer um loop sobre cada entrada em tool_calls. E se você deixar o modelo continuar chamando ferramentas em um loop até terminar, decidindo seu próprio próximo passo a cada vez, você fica com um agente, que é exatamente para onde o próximo capítulo vai.

