# Uso de ferramentas

Modelos de chat são comumente treinados com suporte a "function-calling" ou "tool-use". Ferramentas são funções fornecidas pelo usuário, que o modelo pode escolher chamar como parte de sua resposta. Por exemplo, os modelos poderiam ter acesso a uma ferramenta de calculadora para realizar operações aritméticas sem precisar executar o cálculo internamente.

Este guia demonstrará como definir ferramentas, como passá-las a um modelo de chat e como lidar com a saída do modelo quando ele chama uma ferramenta.

## Passando ferramentas

Quando um modelo suporta o uso de ferramentas, passe as funções para o argumento `tools` de [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). As ferramentas são passadas como um [JSON schema](https://json-schema.org/learn) ou como funções Python. Se você passar funções Python, os argumentos, os tipos de argumentos e a docstring da função são analisados para gerar o JSON schema automaticamente.

Embora passar funções Python seja muito conveniente, o parser só consegue lidar com docstrings no [estilo Google](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). Consulte os exemplos abaixo para saber como formatar uma função pronta para uso como ferramenta.

```py
def get_current_temperature(location: str, unit: str):
    """
    Get the current temperature at a location.

    Args:
        location: The location to get the temperature for, in the format "City, Country"
        unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
    """
    return 22.  # A real function should probably actually get the temperature!

def get_current_wind_speed(location: str):
    """
    Get the current wind speed in km/h at a given location.

    Args:
        location: The location to get the wind speed for, in the format "City, Country"
    """
    return 6.  # A real function should probably actually get the wind speed!

tools = [get_current_temperature, get_current_wind_speed]
```

Você pode, opcionalmente, adicionar um bloco `Returns:` à docstring e um tipo de retorno ao cabeçalho da função, mas a maioria dos modelos não usará essas informações. O parser também ignorará o código real dentro da função!

O que realmente importa é o nome da função, os nomes dos argumentos, os tipos dos argumentos e a docstring que descreve o propósito da função e o propósito de seus argumentos. Esses elementos criam a "assinatura" que o modelo usará para decidir se deve chamar a ferramenta.

## Exemplo de chamada de ferramenta

Carregue um modelo e um tokenizador que suportem o uso de ferramentas, como [NousResearch/Hermes-2-Pro-Llama-3-8B](https://hf.co/NousResearch/Hermes-2-Pro-Llama-3-8B), mas você também pode considerar um modelo maior, como [Command-R](./model_doc/cohere) e [Mixtral-8x22B](./model_doc/mixtral), se seu hardware for capaz de suportá-lo.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")
```

Crie um histórico de chat.

```py
messages = [
  {"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
  {"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
]
```

Em seguida, passe `messages` e uma lista de ferramentas para [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). Tokenize o chat e gere uma resposta.

```py
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=128)
print(tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):]))
```

```txt
<tool_call>
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
</tool_call><|im_end|>
```

O modelo de chat chamou a ferramenta `get_current_temperature` com os parâmetros corretos da docstring. Ele inferiu a França como a localização com base em Paris e que deveria usar Celsius para as unidades de temperatura.

Um modelo **na verdade não consegue chamar a ferramenta por conta própria**. Ele solicita uma chamada de ferramenta, e cabe a você processar essa chamada e adicioná-la, junto com o resultado, ao histórico do chat. Para modelos que suportam [response parsing](./chat_response_parsing), o parsing da resposta é tratado automaticamente e você pode simplesmente usar [parse_response()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response) para extrair a chamada de ferramenta. Para outros modelos, você precisará traduzir manualmente a string de saída para um dict de chamada de ferramenta.

Independentemente da abordagem que você usar, a chamada de ferramenta deve estar na chave `tool_calls` de uma mensagem `assistant`. Esta é a API recomendada e deve ser suportada pelo modelo de chat da maioria dos modelos que utilizam ferramentas.

> [!WARNING]
> Embora `tool_calls` seja semelhante à API da OpenAI, a API da OpenAI usa uma string JSON como formato de `tool_calls`. Isso pode causar erros ou comportamento estranho do modelo se for usado no Transformers, que espera um dict.

```py
tool_call = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
messages.append({"role": "assistant", "tool_calls": [{"type": "function", "function": tool_call}]})
```

Anexe a resposta da ferramenta ao histórico do chat com o papel `tool`.

```py
messages.append({"role": "tool", "content": "22"})  # Note that the returned content is always a string!
```

Por fim, permita que o modelo leia a resposta da ferramenta e responda ao usuário.

```py
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
out = model.generate(**inputs.to(model.device), max_new_tokens=128)
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
```

```txt
The temperature in Paris, France right now is 22°C.<|im_end|>
```

> [!WARNING]
> Embora a chave na mensagem do assistente seja chamada de `tool_calls`, na maioria dos casos, os modelos emitem apenas uma chamada de ferramenta por vez. Alguns modelos mais antigos emitem múltiplas chamadas de ferramenta ao mesmo tempo, mas esse é um processo significativamente mais complexo, pois é necessário lidar com múltiplas respostas de ferramentas simultaneamente e desambiguá-las, frequentemente usando IDs de chamada de ferramenta. Consulte o cartão do modelo para ver exatamente qual formato o modelo espera para as chamadas de ferramenta.

## Esquemas JSON

Outra forma de definir ferramentas é passando um [JSON schema](https://json-schema.org/learn/getting-started-step-by-step).

Você também pode chamar manualmente as funções de baixo nível que convertem funções Python em esquemas JSON e, em seguida, verificar ou editar os esquemas gerados. Isso geralmente não é necessário, mas é útil para entender a mecânica subjacente. É particularmente importante para os autores de modelos de chat que precisam acessar o esquema JSON para renderizar as definições de ferramentas.

O método [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template) usa a função [get_json_schema](https://github.com/huggingface/transformers/blob/14561209291255e51c55260306c7d00c159381a5/src/transformers/utils/chat_template_utils.py#L205) para converter chamáveis do Python em um esquema JSON. Isso inclui métodos: `self` e `cls` são tratados como argumentos de receptor implícitos e são ignorados.

```py
from transformers.utils import get_json_schema

def multiply(a: float, b: float):
    """
    A function that multiplies two numbers

    Args:
        a: The first number to multiply
        b: The second number to multiply
    """
    return a * b

schema = get_json_schema(multiply)
print(schema)
```

```json
{
  "type": "function",
  "function": {
    "name": "multiply",
    "description": "A function that multiplies two numbers",
    "parameters": {
      "type": "object",
      "properties": {
        "a": {
          "type": "number",
          "description": "The first number to multiply"
        },
        "b": {
          "type": "number",
          "description": "The second number to multiply"
        }
      },
      "required": ["a", "b"]
    }
  }
}
```

Não entraremos nos detalhes do próprio esquema JSON aqui, pois ele já está [muito bem documentado](https://json-schema.org/) em outros lugares. No entanto, mencionaremos que você pode passar dicionários de esquema JSON para o argumento `tools` de [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template) em vez de funções Python:

```py
# A simple function that takes no arguments
current_time = {
  "type": "function",
  "function": {
    "name": "current_time",
    "description": "Get the current local time as a string.",
    "parameters": {
      'type': 'object',
      'properties': {}
    }
  }
}

# A more complete function that takes two numerical arguments
multiply = {
  'type': 'function',
  'function': {
    'name': 'multiply',
    'description': 'A function that multiplies two numbers',
    'parameters': {
      'type': 'object',
      'properties': {
        'a': {
          'type': 'number',
          'description': 'The first number to multiply'
        },
        'b': {
          'type': 'number', 'description': 'The second number to multiply'
        }
      },
      'required': ['a', 'b']
    }
  }
}

model_input = tokenizer.apply_chat_template(
    messages,
    tools = [current_time, multiply]
)
```

