# Modelos de chat

O guia de [fundamentos de chat](./conversations) explica como armazenar históricos de chat e gerar texto a partir de modelos de chat usando [TextGenerationPipeline](/docs/transformers/main/pt/main_classes/pipelines#transformers.TextGenerationPipeline).

Este guia é destinado a usuários mais avançados e aborda as classes e métodos subjacentes, bem como os conceitos-chave para entender o que realmente acontece quando você conversa com um modelo.

The critical insight needed to understand chat models is this: All causal LMs, whether chat-trained or not, continue a sequence of tokens. When causal LMs are trained, the training usually begins with "pre-training" on a huge corpus of text, which creates a "base" model. These base models are then often "fine-tuned" for chat, which means training them on data that is formatted as a sequence of messages. The chat is still just a sequence of tokens, though! The list of `role` and `content` dictionaries that you pass to a chat model get converted to a token sequence, often with control tokens like `<|user|>` or `<|assistant|>` or `<|end_of_message|>`, which allow the model to see the chat structure. There are many possible chat formats, and different models may use different formats or control tokens, even if they were fine-tuned from the same base model!

Mas não entre em pânico - você não precisa memorizar todos os possíveis formatos de chat para usar modelos de chat. Modelos de chat vêm com **modelos de chat**, que indicam como eles esperam que os chats sejam formatados. Você pode acessar esses modelos com o método `apply_chat_template`. Vamos ver dois exemplos. Ambos esses modelos foram ajustados a partir do mesmo modelo base `Mistral-7B`:

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
chat = [
  {"role": "user", "content": "Hello, how are you?"},
  {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
  {"role": "user", "content": "I'd like to show off how chat templating works!"},
]

tokenizer.apply_chat_template(chat, tokenize=False)
```

```md
<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]
```

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat = [
  {"role": "user", "content": "Hello, how are you?"},
  {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
  {"role": "user", "content": "I'd like to show off how chat templating works!"},
]

tokenizer.apply_chat_template(chat, tokenize=False)
```

```md
<|user|>\nHello, how are you?</s>\n<|assistant|>\nI'm doing great. How can I help you today?</s>\n<|user|>\nI'd like to show off how chat templating works!</s>\n
```

O Mistral-7B-Instruct usa os tokens `[INST]` e `[/INST]` para indicar o início e o fim das mensagens do usuário, enquanto o Zephyr-7B usa os tokens `<|user|>` e `<|assistant|>` para indicar os papéis dos interlocutores. É por isso que os modelos de chat são importantes: com os tokens de controle errados, esses modelos teriam um desempenho drasticamente pior.

## Usando `apply_chat_template`

A entrada para `apply_chat_template` deve ser estruturada como uma lista de dicionários com as chaves `role` e `content`. A chave `role` especifica o interlocutor e a chave `content` contém a mensagem. Os papéis comuns são:

- `user` para mensagens do usuário
- `assistant` para mensagens do modelo
- `system` para diretrizes sobre como o modelo deve agir (geralmente colocado no início do chat)

`apply_chat_template` recebe essa lista e retorna uma sequência formatada. Defina `tokenize=True` se você quiser tokenizar a sequência.

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

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceH4/zephyr-7b-beta", device_map="auto", dtype=torch.bfloat16)

messages = [
    {"role": "system", "content": "You are a friendly chatbot who always responds in the style of a pirate",},
    {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
 ]
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(model.device)
print(tokenizer.decode(tokenized_chat["input_ids"][0]))
```

```md
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
```

Passe o chat tokenizado para [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate) para gerar uma resposta.

```py
outputs = model.generate(**tokenized_chat, max_new_tokens=128)
print(tokenizer.decode(outputs[0]))
```

```md
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
```

> [!WARNING]
> Alguns tokenizers adicionam tokens especiais `<bos>` e `<eos>`. Os chat templates já devem incluir todos os tokens especiais necessários, e adicionar tokens especiais adicionais é frequentemente incorreto ou redundante, prejudicando o desempenho do modelo. Ao formatar o texto com `apply_chat_template(tokenize=False)`, certifique-se de definir `add_special_tokens=False` se for fazer a tokenização posteriormente, para evitar a duplicação desses tokens. Isso não é um problema se você usar `apply_chat_template(tokenize=True)`, o que significa que essa é geralmente a opção mais segura!

### add_generation_prompt

Você pode ter notado o argumento [add_generation_prompt](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) nos exemplos acima. Este argumento adiciona tokens ao final do chat que indicam o início de uma resposta do `assistant`. Lembre-se: por trás de todas as abstrações de chat, os modelos de chat ainda são apenas modelos de linguagem que continuam uma sequência de tokens! Se você incluir tokens que informam que agora está em uma resposta do `assistant`, ele escreverá corretamente uma resposta, mas, se não incluir esses tokens, o modelo pode se confundir e fazer algo estranho, como **continuar** a mensagem do usuário em vez de responder a ela!

Vamos ver um exemplo para entender o que `add_generation_prompt` está fazendo. Primeiro, vamos formatar um chat sem `add_generation_prompt`:

```py
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
tokenized_chat
```

```md
<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
```

Agora, vamos formatar o mesmo chat com `add_generation_prompt=True`:

```py
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
tokenized_chat
```

```md
<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
<|im_start|>assistant

```

Quando `add_generation_prompt=True`, `<|im_start|>assistant` é adicionado ao final para indicar o início de uma mensagem de `assistant`. Isso permite que o modelo saiba que uma resposta de `assistant` virá em seguida.

Nem todos os modelos exigem prompts de geração, e alguns modelos, como o [Llama](./model_doc/llama), não possuem tokens especiais antes da resposta do `assistant`. Nesses casos, [add_generation_prompt](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) não tem efeito.

### continue_final_message

O parâmetro [continue_final_message](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) controla se a mensagem final no chat deve ser continuada ou não, em vez de iniciar uma nova. Ele remove os tokens de fim de sequência para que o modelo continue a geração a partir da mensagem final.

Isso é útil para “preencher” uma resposta do modelo. No exemplo abaixo, o modelo gera texto que continua a string JSON, em vez de iniciar uma nova mensagem. Pode ser muito útil para melhorar a precisão no seguimento de instruções quando você sabe como iniciar as respostas.

```py
chat = [
    {"role": "user", "content": "Can you format the answer in JSON?"},
    {"role": "assistant", "content": '{"name": "'},
]

formatted_chat = tokenizer.apply_chat_template(chat, tokenize=True, return_dict=True, continue_final_message=True)
model.generate(**formatted_chat)
```

> [!WARNING]
> Você não deve usar [add_generation_prompt](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) e [continue_final_message](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) juntos. O primeiro adiciona tokens que iniciam uma nova mensagem, enquanto o segundo remove tokens de fim de sequência. Usá-los juntos retorna um erro.

Passe um nome de campo como string para preencher previamente esse campo em vez de `content`. Modelos de raciocínio leem seu raciocínio de um campo separado `reasoning_content`. Preencher previamente `content` fecha o bloco de raciocínio antes do início da geração, de modo que o modelo não pode continuar dentro dele. Preencher previamente `reasoning_content` diretamente mantém o bloco aberto.

```py
chat = [
    {"role": "user", "content": "Explain 1+1"},
    {"role": "assistant", "reasoning_content": "The user wants a simple addition. ", "content": ""},
]

formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False, continue_final_message="reasoning_content")
```

O campo nomeado deve existir na mensagem final e deve ser referenciado pelo modelo de chat. Um erro é lançado quando qualquer uma dessas verificações falha.

[TextGenerationPipeline](/docs/transformers/main/pt/main_classes/pipelines#transformers.TextGenerationPipeline) define [add_generation_prompt](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) como `True` por padrão para iniciar uma nova mensagem. No entanto, se a última mensagem no chat tiver o papel `assistant`, assume-se que a mensagem é um prefill e o comportamento muda para `continue_final_message=True`. Isso ocorre porque a maioria dos modelos não suporta múltiplas mensagens consecutivas do assistente. Para sobrescrever esse comportamento, passe explicitamente o argumento [continue_final_message](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) para o pipeline.

## Treinamento de modelos

Treinar um modelo com um chat template é uma boa maneira de garantir que o template corresponda aos tokens nos quais o modelo foi treinado. Aplique o chat template como uma etapa de pré-processamento no seu conjunto de dados. Defina `add_generation_prompt=False`, pois os tokens adicionais para solicitar uma resposta do assistente não são úteis durante o treinamento.

Um exemplo de pré-processamento de um conjunto de dados com um modelo de chat é mostrado abaixo.

```py
from transformers import AutoTokenizer
from datasets import Dataset

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")

chat1 = [
    {"role": "user", "content": "Which is bigger, the moon or the sun?"},
    {"role": "assistant", "content": "The sun."}
]
chat2 = [
    {"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
    {"role": "assistant", "content": "A bacterium."}
]

dataset = Dataset.from_dict({"chat": [chat1, chat2]})
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
print(dataset['formatted_chat'][0])
```

```md
<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>
```

Após esta etapa, você pode continuar seguindo a [receita de treinamento](./tasks/language_modeling) para modelos de linguagem causais usando a coluna `formatted_chat`.

