# Escrevendo um modelo de chat

Um chat template é um template [Jinja](https://jinja.palletsprojects.com/en/stable/templates/) armazenado no atributo `~PreTrainedTokenizer.chat_template` do tokenizer. O Jinja é uma linguagem de templates que permite escrever código e sintaxe semelhantes aos do Python.

```jinja
{%- for message in messages %}
    {{- '<|' + message['role'] + '|>\n' }}
    {{- message['content'] + eos_token }}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|assistant|>\n' }}
{%- endif %}
```

Se você observar isso por um tempo, deve perceber que é muito parecido com Python, embora tenha uma sintaxe estranha de `{%-`. O template itera sobre uma lista de mensagens e, para cada mensagem, imprime o papel e o conteúdo da mensagem, seguido por um token de fim de sequência. Se `add_generation_prompt=True`, ele adiciona o cabeçalho inicial de uma mensagem do assistente ao final da conversa.

Carregue o template escrito como uma string e atribua-o ao atributo `chat_template` do tokenizer. Uma vez definido, o template é usado sempre que você chama [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). Ele também é salvo com o tokenizer sempre que [save_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.save_pretrained) ou [push_to_hub()](/docs/transformers/main/pt/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub) é chamado. O template é salvo no arquivo `chat_template.jinja` no diretório do tokenizer. Você pode editar esse arquivo diretamente para alterar o template, o que muitas vezes é mais fácil do que manipular uma string de template. Consulte [Armazenar e carregar templates de chat](#storing-and-loading-chat-templates) abaixo para as outras formas em disco que o Transformers suporta.

## Dicas para escrever templates

A maneira mais fácil de começar a escrever templates Jinja é consultar templates existentes. Use `print(tokenizer.chat_template)` em qualquer modelo de chat para ver o template que ele está usando. Tente começar com modelos simples que não chamam ferramentas nem suportam RAG, pois modelos de uso de ferramentas podem ter templates muito complexos. Por fim, consulte a [documentação do Jinja](https://jinja.palletsprojects.com/en/stable/templates/#synopsis) para mais detalhes sobre formatação e sintaxe.

Há algumas dicas e armadilhas específicas que você pode encontrar ao escrever templates de chat, e esta seção abordará alguns deles em mais detalhes.

### Escrevendo modelos de chat multimodais

Para modelos multimodais, o atributo `chat_template` é definido no **processor**, e não no tokenizer. A chave `content` de uma mensagem é frequentemente uma lista de dicionários de conteúdo, em vez de apenas uma única string. Você pode querer verificar o tipo de cada item de conteúdo na lista e tratá-lo de acordo.

Em geral, o template não deve acessar diretamente dados de imagem ou vídeo. Normalmente, isso é tratado pelo processador após a renderização do template ser concluída. Em vez disso, seu template deve emitir um único token especial, como `<|image|>` ou `<|video|>`, quando encontrar conteúdo de imagem ou vídeo. O processador expandirá o único token especial em uma sequência de tokens de imagem ou vídeo posteriormente. Os tokens exatos a serem emitidos dependem do modelo com o qual você está trabalhando. Recomendamos fortemente carregar um processador multimodal existente para ver como ele trata os dados.

O modelo de exemplo abaixo trata conteúdo misto de imagem e texto.

```jinja
{%- for message in messages %}
    {%- if loop.index0 == 0 %}
        {{- bos_token }}
    {%- endif %}
    {{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n' }}
    {%- if message['content'] is string %}
        {{- message['content'] }}
    {%- else %}
        {%- for content in message['content'] %}
            {%- if content['type'] == 'image' %}
                {{- '<|image|>' }}
            {%- elif content['type'] == 'text' %}
                {{- content['text'] }}
            {%- endif %}
        {%- endfor %}
    {%- endif %}
    {{- '<|eot_id|>' }}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|start_header_id|>assistant<|end_header_id|>\n\n' }}
{%- endif %}
```

Este template multimodal é muito semelhante ao template mais simples acima, mas ele verifica listas de `content` e itera sobre elas para renderizar tokens `<|image|>` onde necessário. Isso permite que as imagens sejam inseridas "no fluxo" do texto do usuário.

Nem todos os modelos funcionam assim — alguns, por exemplo, podem mover todas as imagens para o final da mensagem do usuário. O modelo de chat deve sempre corresponder ao formato com o qual o modelo foi treinado.

### Removendo espaços em branco

O Jinja imprime qualquer espaço em branco antes ou depois de um bloco de texto. Isso pode ser um problema para modelos de chat, pois adicionar espaços em branco extras que não estavam presentes durante o treinamento do modelo pode prejudicar o desempenho. Para remover os espaços em branco, adicione `-` à sintaxe de linha do Jinja. Isso permite que você escreva seu modelo com indentação e quebras de linha no estilo Python, sem imprimir acidentalmente uma indentação na saída renderizada.

O modelo de exemplo abaixo não usa `-`, resultando em espaços em branco extras na saída.

```jinja
{% for message in messages %}
    {{ message['role'] + message['content'] }}
{% endfor %}
```

Recomendamos fortemente o uso de `-` para garantir que apenas o conteúdo pretendido seja exibido.

```jinja
{%- for message in messages %}
    {{- message['role'] + message['content'] }}
{%- endfor %}
```

### Variáveis e chamáveis especiais

As únicas constantes em um template são a variável `messages` e o booleano `add_generation_prompt`. No entanto, você tem acesso a **quaisquer outros argumentos de palavra-chave que forem passados** ao método [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template).

Isso oferece flexibilidade e permite o suporte a casos de uso que talvez não tenhamos considerado ao projetar a especificação. A variável adicional mais comum é `tools`, que contém uma lista de ferramentas em formato de esquema JSON. Embora você possa usar qualquer nome de variável que desejar, recomendamos fortemente seguir a convenção e usar `tools` para esse fim. Isso torna os modelos mais compatíveis com a API padrão.

Você também tem acesso a quaisquer tokens contidos em `tokenizer.special_tokens_map`, que frequentemente inclui tokens especiais como `bos_token` e `eos_token`. Acesse-os diretamente pelo nome, como `{{- bos_token }}`.

Há duas funções chamáveis disponíveis para você. Para chamá-las, use `{{- function_name(argument) }}`.

- `raise_exception(msg)` levanta uma `TemplateException`. Isso é útil para depuração ou para alertar os usuários sobre o uso incorreto de modelos.
- `strftime_now(format_str)` recupera a data e a hora atuais em um formato específico, o que é frequentemente necessário em mensagens de sistema. É equivalente a [datetime.now().strftime(format_str)](https://docs.python.org/3/library/datetime.html#datetime.datetime.now) em Python.

### Compatibilidade com Jinja não em Python

O Jinja é implementado em várias linguagens e, em geral, possui a mesma sintaxe. Escrever um modelo em Python permite o uso de métodos do Python, como [lower](https://docs.python.org/3/library/stdtypes.html#str.lower) em strings ou [items](https://docs.python.org/3/library/stdtypes.html#dict.items) em dicts. No entanto, isso não funcionará se o modelo for usado em uma implementação que não seja em Python, por exemplo, ao fazer o deploy com Javascript ou Rust.

Faça as alterações abaixo para garantir compatibilidade em todas as implementações do Jinja.

- Substitua os métodos Python por filtros Jinja. Por exemplo, substitua `string.lower()` por `string|lower` ou `dict.items()` por `dict|dictitems`. A maioria das alterações segue o mesmo padrão, exceto `string.strip()`, que é substituído por `string|trim`. Consulte a lista de [filtros integrados](https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters) para obter a lista completa de filtros.
- Substitua `True`, `False` e `None` (específicos do Python) por `true`, `false` e `none`, respectivamente.
- Renderizar diretamente um dict ou uma list pode retornar resultados diferentes em outras implementações. Por exemplo, entradas de string podem mudar de aspas simples para aspas duplas. Para evitar isso, adicione o filtro [tojson](https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.tojson) para manter a consistência.

### Modelos grandes

Modelos mais recentes ou modelos com recursos como [tool-calling](./chat_extras) e RAG exigem templates maiores, que podem ter mais de 100 linhas. Pode ser mais fácil escrever templates maiores em um arquivo separado. Os números de linha no arquivo separado correspondem exatamente aos números de linha nos erros de análise ou execução do template, o que facilita a depuração de possíveis problemas.

Escreva o template em um arquivo separado e extraia-o para o chat template.

```py
open("template.jinja", "w").write(tokenizer.chat_template)
```

Você também pode carregar um modelo editado de volta no tokenizer.

```py
tokenizer.chat_template = open("template.jinja").read()
```

## Armazenar e carregar modelos de chat

Os modelos de chat são armazenados em disco em vários formatos diferentes. Os checkpoints modernos salvam os modelos como arquivos `.jinja` independentes, enquanto os checkpoints antigos os incorporam na configuração do tokenizer ou do processor.

### Formatos de armazenamento

Os modelos podem ser armazenados em qualquer um dos seguintes formatos.

- `chat_template.jinja` (recomendado). Um arquivo Jinja independente na raiz do repositório, contendo um único chat template. É isso que o [save_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.save_pretrained) grava por padrão. Armazenar o template em um arquivo próprio facilita inspecioná-lo, editá-lo e comparar diferenças. Tanto tokenizers quanto processors carregam o `chat_template.jinja` da mesma forma.
- `additional_chat_templates/<name>.jinja`. Um diretório de arquivos Jinja independentes usado quando um modelo é distribuído com vários templates nomeados (por exemplo, um template `default` e um template `tool_use` separado). O template `default` continua em `chat_template.jinja` na raiz do repositório, mas todos os outros templates nomeados ficam em `additional_chat_templates/<name>.jinja`, em que o nome do arquivo (sem a extensão) é o nome do template.

> [!WARNING]
> Os formatos legados abaixo são mantidos apenas para carregamento com compatibilidade reversa. Não escreva modelos de chat em nenhum deles.

- campo `chat_template` em `tokenizer_config.json`. Um formato legado somente para carregamento, usado antes dos arquivos `.jinja` independentes. O template é incorporado como uma string JSON em `tokenizer_config.json`. Quando um modelo possui múltiplos templates nomeados, o campo é uma lista de dicts `{"name": ..., "template": ...}` em vez de uma única string. Repositórios existentes que usam esse formato continuam a ser carregados, mas [save_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.save_pretrained) grava o formato moderno `.jinja` em vez disso.

- `chat_template.json`. Um formato legado somente para carregamento, usado por checkpoints de processadores multimodais mais antigos. Um arquivo JSON no formato `{"chat_template": "<template string>"}`. Repositórios existentes que usam esse formato continuam a ser carregados, mas [save_pretrained()](/docs/transformers/main/pt/model_doc/wav2vec2#transformers.Wav2Vec2Processor.save_pretrained) grava o formato moderno `.jinja` em vez disso. Um repositório de processador que mistura um `chat_template.json` legado com arquivos modernos `.jinja` gera um erro no carregamento.

### Prioridade de carregamento

Ao chamar [from_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.from_pretrained), o Transformers resolve os formatos de armazenamento com uma precedência fixa. Arquivos `.jinja` independentes têm prioridade sobre os modelos embutidos na configuração. O carregador:

1. Lê qualquer campo `chat_template` presente em `tokenizer_config.json` (ou, para processadores, o legado `chat_template.json`).
2. Lê `chat_template.jinja` na raiz do repositório, se existir, e o usa como o modelo `default`, substituindo a etapa 1.
3. Lê todos os arquivos `.jinja` em `additional_chat_templates/`, indexados pelo nome do arquivo, e os mescla.

Se o resultado tiver um único modelo `default`, `~PreTrainedTokenizer.chat_template` é definido como essa string. Se existirem vários modelos nomeados, `chat_template` se torna um dicionário de `{name: template_string}`. Nesse caso, [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template) seleciona a entrada `tool_use` quando ferramentas são passadas e `default` caso contrário.

### Salvando

[save_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.save_pretrained) e [push_to_hub()](/docs/transformers/main/pt/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub) gravam o formato `.jinja` por padrão. Um único modelo de string se torna `chat_template.jinja`. Um dicionário de modelos nomeados grava a entrada `default` em `chat_template.jinja` e um arquivo para cada entrada restante sob `additional_chat_templates/`. O campo `chat_template` é removido de `tokenizer_config.json` para evitar duplicação.

Não há uma maneira suportada para salvar um template em um dos formatos legados. Eles são mantidos apenas para carregar repositórios mais antigos.

### Atualizando um repositório mais antigo

Migre um template embutido em `tokenizer_config.json` ou `chat_template.json` para o formato `.jinja` recomendado, carregando-o e salvando-o novamente.

A etapa de carregamento normaliza o formato legado que o repositório utiliza em `chat_template`, e `~PushToHubMixin.push_to_hub` retorna um arquivo `chat_template.jinja`.

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("your-org/your-model")
tokenizer.push_to_hub("your-org/your-model")
```

## Modelos para ferramentas

Não há um formato específico para escrever templates de ferramentas, mas é melhor seguir a API padrão. Isso garante que o template seja amplamente acessível entre os modelos, sem exigir que os usuários escrevam código personalizado para usar ferramentas com o seu modelo.

> [!WARNING]
> Formatações, como espaços em branco e tokens especiais, são específicas de cada modelo. Certifique-se de que tudo corresponda exatamente ao formato com o qual o modelo foi treinado.

A seção a seguir lista os elementos da API padrão para a criação de modelos para ferramentas.

### Definições de ferramentas

As [Ferramentas](./chat_extras) são passadas como funções Python ou um esquema JSON. Quando funções são passadas, um esquema JSON é gerado automaticamente e enviado ao template. Quando um template acessa a variável `tools`, ela é sempre uma lista de esquemas JSON.

Embora um template sempre receba ferramentas como um esquema JSON, pode ser necessário alterar radicalmente esse formato ao renderizá-las para corresponder ao formato com o qual um modelo foi treinado. Por exemplo, o [Command-R](./model_doc/cohere) foi treinado com ferramentas definidas por cabeçalhos de funções Python. O template converte internamente os tipos do esquema JSON e renderiza as ferramentas de entrada como cabeçalhos Python.

O exemplo abaixo mostra como uma ferramenta é definida no formato de esquema JSON.

```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"]
    }
  }
}
```

Um exemplo de como lidar com definições de ferramentas em um modelo de chat é mostrado abaixo. Os tokens e layouts específicos devem ser alterados para corresponder aos com os quais o modelo foi treinado.

```jinja
{%- if tools %}
    {%- for tool in tools %}
        {{- '<tool>' + tool['function']['name'] + '\n' }}
        {%- for argument in tool['function']['parameters']['properties'] %}
            {{- argument + ': ' + tool['function']['parameters']['properties'][argument]['description'] + '\n' }}
        {%- endfor %}
        {{- '\n</tool>' }}
    {%- endfor %}
{%- endif %}
```

### Chamadas de ferramentas

Além de renderizar as definições das ferramentas, você também precisa renderizar **chamadas de ferramentas** e **respostas de ferramentas** no modelo.

As chamadas de ferramentas são geralmente passadas na chave `tool_calls` de uma mensagem `"assistant”`. Isso é sempre uma lista, mesmo que a maioria dos modelos de chamada de ferramentas suporte apenas chamadas únicas, o que significa que a lista geralmente contém apenas um elemento.

```json
{
  "role": "assistant",
  "tool_calls": [
    {
      "type": "function",
      "function": {
        "name": "multiply",
        "arguments": {
          "a": 5,
          "b": 6
        }
      }
    }
  ]
}
```

Um padrão comum para lidar com chamadas de ferramentas é mostrado abaixo. Você pode usá-lo como ponto de partida, mas certifique-se de que seu template realmente corresponde ao formato com o qual o modelo foi treinado!

```jinja
{%- if message['role'] == 'assistant' and 'tool_calls' in message %}
    {%- for tool_call in message['tool_calls'] %}
            {{- '<tool_call>' + tool_call['function']['name'] + '\n' + tool_call['function']['arguments']|tojson + '\n</tool_call>' }}
    {%- endfor %}
{%- endif %}
```

### Respostas de ferramentas

As respostas de ferramentas são dicionários de mensagens com o papel `tool`. Elas são muito mais simples que as chamadas de ferramentas e geralmente contêm apenas as chaves `role`, `name` e `content`.

```json
{
  "role": "tool",
  "name": "multiply",
  "content": "30"
}
```

Alguns modelos podem nem precisar da chave `name`, caso em que você pode escrever seu modelo para ler apenas a chave `content`.

```jinja
{%- if message['role'] == 'tool' %}
    {{- "<tool_result>" + message['content'] + "</tool_result>" }}
{%- endif %}
```

## Contribuir

Quando um template estiver pronto, defina-o no atributo `chat_template` do tokenizer e teste-o com [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). Se funcionar como esperado, envie-o para o Hub com [push_to_hub()](/docs/transformers/main/pt/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub).

Mesmo que você não seja o proprietário do modelo, ainda é útil adicionar um template para um modelo com um template de chat vazio ou incorreto. Abra um [pull request](https://hf.co/docs/hub/repositories-pull-requests-discussions) no repositório do modelo para adicionar o template!

```py
tokenizer.chat_template = template
tokenizer.push_to_hub("amazing_company/cool_model", commit_message="Add chat template", create_pr=True)
```

