# Análise de Respostas

É cada vez mais comum que modelos de chat gerem saídas estruturadas, em vez de apenas uma única string de resposta. Por exemplo, um [modelo de raciocínio](https://huggingface.co/reasoning-course) pode emitir uma cadeia de raciocínio contendo seu rastro de raciocínio, enquanto um modelo de [chamada de ferramentas](./chat_extras) pode emitir nomes de funções e argumentos.

O problema com saídas estruturadas, no entanto, é que as saídas dos LLMs não são estruturadas por natureza. As APIs de LLMs geralmente aceitam e retornam dicionários de mensagens, com chaves como `role` e `content` e `reasoning_content`, mas internamente, os LLMs apenas continuam uma única sequência de tokens. Usamos uma camada de conexão para ligar a API voltada ao usuário ao fluxo real de tokens do modelo. Para transformar as entradas em um fluxo de tokens, usamos [`chat_templates`](./chat_templating), que são abordados em outros documentos. Este documento trata da outra metade dessa camada de conexão: **Response templates**, o sistema para transformar os tokens gerados pela saída do modelo de volta em um dicionário de resposta estruturado.

Em muitos aspectos, os templates de resposta executam a operação inversa dos templates de chat. Com os templates de chat, você fornece uma lista de mensagens e obtém tokens prontos para serem inseridos no modelo. Com os templates de resposta, você fornece os tokens de saída bruta do modelo e obtém uma mensagem estruturada. Assim como os templates de chat, os templates de resposta permitem que os usuários ignorem os detalhes complexos dos formatos específicos e dos tokens de controle que um modelo espera, utilizando uma API universal de dicionários de mensagens que funciona com qualquer modelo.

A melhor forma de entender os modelos de resposta é vê-los em ação. O ponto de entrada principal é o método [parse_response()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response), que aceita uma única sequência ou um lote:

```python
from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "HuggingFaceTB/SmolLM3-3B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")

messages = [{"role": "user", "content": "Summarize the end of the Cold War, very briefly."}]
input_ids = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")["input_ids"].to(model.device)
outputs = model.generate(input_ids, max_new_tokens=1024)[0, input_ids.shape[1]:]
out_text = tokenizer.decode(outputs)
print(tokenizer.parse_response(out_text, prefix=input_ids[0]))
# Outputs a structured dict: {"role": "assistant", "reasoning_content": "...", "content": "..."}
```

Quando um tokenizer possui um `response_template`, o método `parse_response` converte limpa e diretamente uma mensagem de saída em um dicionário estruturado, pronto para ser adicionado ao chat. Observe que precisamos passar o `prefix` (os tokens do prompt) para este método também. Isso ocorre porque muitos modelos de chat iniciam mensagens ou abrem blocos de raciocínio antes de permitir que o modelo comece sua resposta, e, portanto, nosso parser precisa ver o prompt para entender a mensagem. Todo o prefixo antes do turno final é descartado; analisamos apenas uma mensagem por vez. Precisamos do prefixo apenas para garantir que estamos vendo a mensagem final inteira, sem perder campos pré-preenchidos!

Como um prefixo ausente pode fazer com que uma mensagem pré-preenchida seja interpretada incorretamente de forma silenciosa, `prefix` é obrigatório. Omiti-lo gera um erro. No raro caso em que você tenha certeza de que a geração já contém a mensagem completa e nenhum contexto de prefixo é necessário, passe `prefix=""` (ou uma lista vazia de ids de tokens) para desativar explicitamente.

Se o tokenizer não tiver um template de resposta definido, `parse_response` lançará um erro. Estamos trabalhando para adicionar templates a mais modelos o mais rápido possível!

## Análise de respostas em streaming

No exemplo acima, analisamos a resposta do modelo de uma só vez, após o término da geração. No entanto, muitas vezes podemos querer analisar mensagens parciais conforme são geradas, especialmente em aplicativos voltados ao usuário, em que não queremos apenas exibir uma página estática por um ou dois minutos até que o modelo termine.

Quando você deseja análise em streaming, chame `tokenizer.get_response_parser()`, que retorna um `ResponseParser`. Assim como em `parse_response`, passe o prompt de chat como `prefix=` para que o parser saiba sobre as partes da mensagem que foram pré-preenchidas pelo modelo de chat. O objeto retornado é um parser com estado que você pode alimentar com texto à medida que o modelo o gera:

```python
parser = tokenizer.get_response_parser(prefix=input_ids[0])
for event in parser.initial_events:
    render(event)  # Display the partial message to the user however you want to
for chunk in model_output:
    for event in parser.feed(chunk):
        render(event)
message, final_events = parser.finalize()
for event in final_events:
    render(event)
```

Se a solicitação incluir ferramentas, transmita-as também (`get_response_parser(..., tools=tools)`). Os argumentos de chamada de ferramenta são então tipados a partir do JSON Schema da ferramenta chamada à medida que cada região é fechada, de modo que os consumidores de streaming vejam argumentos tipados por schema em `region_close`, em vez de apenas após `finalize()`. Consulte [Tipagem de argumentos de chamada de ferramenta](#typing-tool-call-arguments) para mais detalhes.

O parser emitirá **eventos** conforme o texto do processo de geração é fornecido. Isso indica qual região está sendo gerada no momento. Quando a região é concluída, ela será emitida em um evento separado com o conteúdo totalmente analisado. No final da geração, o método `finalize()` descarta qualquer texto restante e emite os eventos finais, bem como o dicionário completo da mensagem.

Observe que, embora `parse_response` possa aceitar lotes, o processamento em streaming é sempre de uma única sequência: cada `ResponseParser` rastreia o estado de uma geração. Se você deseja transmitir várias gerações ao mesmo tempo, crie um `ResponseParser` por sequência.

## Eventos de streaming

Cada evento de análise transmitido é um dicionário com a chave `type`. Existem três tipos:

| Tipo           | Descrição                                                                         | Conteúdos                                                                                                                        |
|----------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| `region_open`  | Indica que o modelo iniciou uma nova região, como `content` ou `reasoning_content`. | `field` (str): o nome do campo.                                                                                                  |
| `region_chunk` | Um trecho de texto para a região atual.                                             | `field` (str): o nome do campo. `text` (str): o novo fragmento. `dirty` (bool): `True` se o fragmento for texto bruto que precisa de análise. |
| `region_close` | Indica que uma região foi concluída e que a chave agora está finalizada.                | `field` (str): o nome do campo. `value` (any): o valor totalmente analisado para a região                                             |

Os eventos `region_chunk` são emitidos para cada região conforme os bytes chegam, permitindo que uma interface de streaming renderize o progresso mesmo para regiões estruturadas. Para regiões semelhantes a texto (`text`, `int`, `float`, `bool`), os blocos são marcados como `dirty=False`: cada bloco já faz parte do valor final (exceto por espaços em branco finais removidos no fechamento). Para regiões estruturadas, como chamadas de ferramentas em formato JSON, os blocos são marcados como `dirty=True`. Isso significa que o texto é o corpo bruto, não analisado; é seguro exibi-lo incrementalmente, mas o valor *parsed* (um dict, list, etc.) só chega no evento correspondente de `region_close`. De qualquer forma, o valor finalizado de uma região é sempre transportado pelo `region_close`, de modo que consumidores que não se importam com a renderização intermediária podem simplesmente ignorar os eventos `region_chunk`.

Se o `prefix` do chat escreveu algo na mensagem (por exemplo, o template abriu um bloco de raciocínio, ou um prefill do assistente iniciou uma resposta antes de passar o controle para o modelo), o parser expõe esses eventos como `parser.initial_events`, uma lista que você pode reproduzir no seu renderer antes de alimentar qualquer saída do modelo. Regiões que foram abertas *e* fechadas dentro do prefixo geram uma sequência completa de `region_open` / `region_chunk` / `region_close` e o valor analisado delas é colocado no dicionário de saída, exatamente como se o próprio modelo as tivesse escrito.

Um fluxo de eventos típico pode ser parecido com o seguinte:

```python
{"type": "region_open",  "field": "reasoning_content"}
{"type": "region_chunk", "field": "reasoning_content", "text": "I should ", "dirty": False}
{"type": "region_chunk", "field": "reasoning_content", "text": "greet the user", "dirty": False}
{"type": "region_close", "field": "reasoning_content", "value": "I should greet the user"}
{"type": "region_open",  "field": "tool_calls"}
{"type": "region_chunk", "field": "tool_calls", "text": '{"name": "greet_user", ', "dirty": True}
{"type": "region_chunk", "field": "tool_calls", "text": '"arguments": {"greeting": "Hi!"}}', "dirty": True}
{"type": "region_close", "field": "tool_calls", "value": {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}}
```

Observe como `reasoning_content` é emitido com `dirty=False`, pois campos como `reasoning_content` e `content` geralmente são apenas texto bruto. Isso significa que você pode tratar os blocos como uma "saída parcial" válida. No entanto, `tool_calls` é marcado como `dirty` porque o texto bruto precisa de uma limpeza significativa — as chamadas de ferramenta frequentemente precisam ser analisadas como JSON ou outro formato e, em seguida, reestruturadas para gerar o dicionário final da chamada de ferramenta. Como resultado, a saída final para essas regiões geralmente é muito, muito diferente do texto bruto. Essa análise final só ocorrerá quando `region_close` for atingido. Cabe a você decidir o que fazer com os blocos `dirty` até lá — você pode exibi-los como estão para mostrar ao usuário a saída "bruta", ou simplesmente esperar até ter algo limpo para exibir.

Isso encerra a maior parte do que você precisa saber para usar modelos de resposta. O restante deste documento é focado nos detalhes internos do sistema de análise e em como escrever modelos de resposta. Isso é relevante principalmente para desenvolvedores e autores de modelos. A maioria das pessoas pode parar com segurança por aqui!

## Avançado: Criando um modelo de resposta

A melhor maneira de entender como escrever um modelo de resposta é escolher um exemplo concreto. Veja como uma resposta bruta do `SmolLM` pode ser:

```txt
<think>
I should greet the user
</think>

<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
```

Ao analisarmos essa saída no formato padrão de dicionário de mensagens, ela deve ficar assim:

```json
{
    "role": "assistant",
    "reasoning_content": "I should greet the user",
    "tool_calls": [
        {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}
    ]
}
```

E aqui está o template que faz o parsing. Não se intimide — grande parte dele é bastante autoexplicativo!

```python
{
    "defaults": {"role": "assistant"},
    "start_anchor": "<|im_start|>assistant\n",
    "fields": {
        "reasoning_content": {"open": "<think>", "close": "</think>", "content": "text"},
        "tool_calls": {
            "open": "<tool_call>",
            "close": "</tool_call>",
            "repeats": True,
            "content": "json",
            "transform": {"type": "function", "function": "{content}"},
        },
        "content": {
            "close": "<|im_end|>",
            "content": "text",
        },
    },
}
```

Em essência, o template define **campos** e **delimitadores**. Cada campo corresponde a uma chave no dicionário de saída. Os campos também incluem informações para analisar o texto dentro de seus delimitadores. Há uma sutileza: o campo `content` não possui `open`, pois no SmolLM (e em vários outros modelos), ele não é marcado por um token especial. Em vez disso, `content` é armazenado no espaço após as outras regiões, mas antes do fim da sequência. No nosso template, representamos isso como um campo **implícito / residual** que captura qualquer texto não reivindicado por outra região.

Os nomes dos campos devem corresponder às chaves que o modelo de chat template lê, para que uma mensagem analisada possa ser adicionada ao chat e renderizada novamente. Em particular, nomeie o campo de raciocínio como `reasoning_content`. Esta é a chave padrão para raciocínio em dicionários de mensagens e a que quase todos os chat templates leem para obter o raciocínio.

Além dos `fields`, o modelo suporta duas chaves de nível superior:

- `defaults` (opcional) — Um dicionário de valores pré-preenchidos na saída (por exemplo, `{"role": "assistant"}`). As chaves aqui são sempre mantidas na saída analisada, mesmo que nenhum campo tenha gravado nelas; as outras chaves são descartadas quando seu campo não capturou nada.
- `start_anchor` (str) / `start_anchor_pattern` (str regex) — Indica onde a mensagem atual do assistente começa dentro de um prompt de chat. Quando você passa `prefix=` para `parse_response` ou `get_response_parser`, o parser faz o truncamento à direita do prefixo a partir da **última** ocorrência desta âncora antes de processá-lo, para que as rodadas anteriores em uma conversa de múltiplas rodadas não contaminem o estado da mensagem atual. A âncora é aplicada apenas ao `prefix`, nunca à resposta/geração que você analisa — alguns formatos reemitem legítimamente a âncora no meio da mensagem (a saída harmony do gpt-oss inicia cada canal com `<|start|>assistant`), então remover a resposta a partir da âncora descartaria o próprio raciocínio e as chamadas de ferramentas do modelo. É por isso que apenas a geração nunca é suficiente para se proteger contra vazamento de histórico: passe o prompt como `prefix=`. Para modelos no estilo ChatML, a âncora é tipicamente `"<|im_start|>assistant\n"`. Exatamente um de `start_anchor` ou `start_anchor_pattern` deve ser definido.

Por exemplo, dado este prefixo de múltiplas rodadas (note as **duas** turnos do assistente):

```txt
<|im_start|>user
Hi<|im_end|>
<|im_start|>assistant
Hello!<|im_end|>
<|im_start|>user
Again?<|im_end|>
<|im_start|>assistant
```

o parser truncará tudo até o **último** `<|im_start|>assistant\n`, descartando a rodada anterior `"Hello!"`. A regra é que _tudo, exceto a última rodada do assistente, é sempre descartado._

Assim como os modelos de chat, os modelos de resposta são armazenados como atributos do tokenizer e salvos junto com ele. Diferentemente dos modelos de chat, salvamos os modelos de resposta dentro de `tokenizer_config.json` e não como um arquivo separado, pois seu formato se encaixa naturalmente em JSON, ao contrário de um script Jinja de modelo de chat.

```python
tokenizer.response_template = template
tokenizer.save_pretrained(...)  # Written as a key in tokenizer_config.json
```

## Avançado: Referência da API de Field

Cada campo suporta várias chaves. Podemos dividi-las em dois tipos. Primeiro, existem as chaves que definem como o campo deve ser capturado:

| Chave             | Tipo               | Propósito                                                                                       |
|-----------------|--------------------|-----------------------------------------------------------------------------------------------|
| `open`          | str ou list[str]   | String literal que abre esta região. Uma lista de strings significa "corresponder a qualquer uma destas".          |
| `open_pattern`  | str (regex)        | Alternativa por regex para `open`. Os grupos nomeados se tornam variáveis de captura disponíveis para `transform`.  |
| `close`         | str ou list[str]   | String literal (ou lista de strings) que fecha esta região. Omita para executar até o fim do stream.    |
| `close_pattern` | str (regex)        | Alternativa por regex para `close`. Os grupos nomeados se tornam variáveis de captura disponíveis para `transform`. |
| `repeats`       | bool               | Se verdadeiro, o campo é uma lista e cada correspondência é adicionada. Padrão `false`.                         |
| `join`          | str                | Com `repeats`, concatene as correspondências em uma única string com este separador, em vez de uma lista.    |
| `optional`      | bool               | Se for false e a região nunca corresponder, geramos um erro. Padrão `true`.                     |

Um campo deve ter **ou** `open` ou `open_pattern`, mas não ambos, e o mesmo vale para `close` e `close_pattern`.

Um campo pode omitir completamente `close`/`close_pattern`, caso em que a região permanece aberta até o final do texto gerado. Isso é útil para um campo final que se estende até o fim da mensagem.

Um campo com **nenhum** `open` nem `open_pattern` é o campo **implícito**: ele fica ativo sempre que nenhuma região explícita está aberta, capturando assim o texto restante. No máximo, um campo pode ser implícito. Isso é usado com mais frequência quando `content` não possui tags de tokens especiais, sendo escrito apenas como texto simples após os outros campos.

Além dos delimitadores de abertura e fechamento, você também pode especificar `repeats`, o que indica que o campo é uma lista e que os delimitadores podem corresponder várias vezes. Isso é mais comum para chamadas de ferramentas paralelas, quando um modelo emite várias chamadas de ferramentas simultaneamente:

```python
'<tool_call>{"name": "a", ...}</tool_call><tool_call>{"name": "b", ...}</tool_call>'
# Returns `"tool_calls": [{... "a" ...}, {... "b" ...}]` in a template with repeats: true
```

Nem todo campo repetido deve se tornar uma lista, no entanto. Alguns modelos emitem vários blocos de `reasoning_content` ou `content` em uma única mensagem, e a saída natural para esses casos é uma única string concatenada. Definir `join` (uma string separadora, muitas vezes apenas `""`) altera um campo `repeats` de coletar uma lista para concatenar suas correspondências:

```python
field = {"reasoning_content": {"open": "<think>", "close": "</think>", "repeats": True, "join": "\n"}}
input = "<think>first</think>...<think>second</think>"
# Returns: {"reasoning_content": "first\nsecond"}
```

Cada correspondência de um campo `join` deve ser analisada como uma string. Durante o streaming, `region_close` ainda carrega o valor próprio de cada bloco; o separador só aparece no dicionário da mensagem final.

Por fim, você pode especificar `optional: false` para campos que devem estar presentes. Se esse campo estiver ausente, geramos um erro em vez de simplesmente retornar um dicionário de mensagem sem ele.

O fim da geração encerrará e finalizará qualquer região aberta, mesmo que seu delimitador de fechamento não tenha sido visto.

### Analisando o conteúdo de um campo

Depois de definir como capturar um campo, também precisamos especificar como analisar o texto bruto dentro dessa captura. Existem quatro chaves que controlam isso:

| Chave              | Tipo         | Propósito                                                                                  |
|------------------|--------------|------------------------------------------------------------------------------------------|
| `content`        | str          | O tipo de conteúdo dentro desta região. O padrão é `"text"`. Cada tipo possui seu próprio parser. |
| `content_args`   | dict         | Argumentos a serem passados ao parser de conteúdo para esta região.                            |
| `transform`      | dict/list    | Template opcional pós-análise que reorganiza o corpo analisado (veja **Transform**).          |
| `transform_each` | bool         | Se for verdadeiro, o conteúdo analisado deve ser uma lista e `transform` é aplicado elemento a elemento.       |

A primeira (e mais importante) chave é `content`. Ela indica o tipo de conteúdo do campo, o que determina o parser que será usado para converter o texto bruto capturado no campo para a saída final. `content_args` são usados para configurar o parser e permitem que suportemos várias peculiaridades de formato sem a necessidade de código personalizado. Vamos examinar cada tipo de parser e seus argumentos em sequência.

#### Tipos básicos
`text`, `int`, `float` e `bool` são os tipos básicos. Todos esses tipos de conteúdo apenas removem espaços em branco e, se necessário, realizam uma conversão de tipo simples. Eles não possuem `content_args`, exceto `text`, que suporta o argumento `strip`, que remove espaços em branco do início e do fim do texto capturado, com valor padrão `true`.

```python
field = {"count": {"open": "<n>", "close": "</n>", "content": "int"}}
input = "<n> 42 </n>"
# Returns: {"count": 42}
```

#### json

O parser `json` interpreta o texto capturado como JSON. Ele é a ferramenta principal para argumentos de chamadas de ferramentas e para qualquer outra coisa com estrutura aninhada. Ele aceita alguns `content_args` opcionais para lidar com as diversas formas como os modelos distorcem o JSON no mundo real:

- `unquoted_keys` (bool, padrão `false`): Ative quando os nomes das chaves não estão entre aspas (por exemplo, `{name: "foo"}`). Útil para modelos que emitem literais de objetos no estilo Javascript em vez de JSON estrito.
- `string_delims` (lista de pares `[open, close]`, opcional): para modelos que envolvem valores de string em delimitadores personalizados em vez de `"..."`. Cada par fornece um marcador de abertura e um de fechamento.
- `allow_non_json` (bool, padrão `false`): se a análise falhar, retorna o texto bruto removido em vez de lançar uma exceção. Útil como alternativa para campos em que o modelo *geralmente* emite JSON, mas ocasionalmente passa para texto simples.

`unquoted_keys` e `string_delims` existem para lidar com modelos que emitem saídas não padrão, quase-JSON, portanto, você deve precisar deles apenas para alguns modelos.

```python
field = {"args": {"open": "<args>", "close": "</args>", "content": "json", "content_args": {"unquoted_keys": True}}}
input = '<args>{city: "London"}</args>'
# Returns: {"args": {"city": "London"}}
```

#### xml-inline

O parser `xml-inline` é destinado a regiões compostas por uma sequência plana de tags semelhantes a XML, em que cada tag se torna uma entrada em um dict. Ele é mais frequentemente usado dentro de um campo `tool_calls` para modelos que emitem cada argumento como sua própria tag, em vez de como um blob JSON:

- `tag_pattern` (str, **obrigatório**): expressão regular que corresponde a uma única tag. Deve conter os grupos nomeados `key` (a chave resultante no dicionário) e `value` (o texto bruto que se torna o valor no dicionário).
- `value_parser` (dict, opcional): parser de conteúdo aninhado aplicado a cada `value` capturado. Um dict com `name` (o parser, por exemplo, `"json"`, `"int"`) e `args` opcional (seus `content_args`). Se omitido, os valores permanecem como strings brutas.
- `merge_duplicates` (bool, padrão `false`): quando a mesma chave aparece várias vezes, os valores são coletados em uma lista em vez de permitir que correspondências posteriores sobrescrevam as anteriores.

Por exemplo, o Qwen3 emite cada argumento de chamada de ferramenta como sua própria tag `<parameter>`, e fazemos o parsing da seguinte forma:

```python
"tool_calls": {
    "open_pattern": r"<tool_call>\s*<function=(?P<name>\w+)>",
    "close": "</tool_call>",
    "repeats": True,
    "content": "xml-inline",
    "content_args": {
        "tag_pattern": r"<parameter=(?P<key>\w+)>\s*(?P<value>.*?)\s*</parameter>",
        "value_parser": {"name": "json", "args": {"allow_non_json": True}},
    },
    "transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
}
```

Observe o `value_parser` aninhado: cada valor de parâmetro é processado pelo parser `json` (com `allow_non_json` para que strings simples ainda passem). Alimentando o campo `tool_calls` acima com esta entrada:

```python
input = "<tool_call><function=get_weather><parameter=city>London</parameter><parameter=units>celsius</parameter></function></tool_call>"
# Returns: {"tool_calls": [{"type": "function", "function": {"name": "get_weather", "arguments": {"city": "London", "units": "celsius"}}}]}
```

#### kv-lines

O parser `kv-lines` processa pares `key: value` delimitados por linha (pense em metadados no estilo YAML ou arquivos `.env`). Cada linha se torna uma entrada no dicionário resultante. Todos os argumentos são opcionais:

- `line_sep` (str, padrão `"\n"`): separador entre pares.
- `kv_sep` (str, padrão `":"`): separador entre uma chave e seu valor dentro de uma única linha. Apenas a primeira ocorrência é usada como ponto de divisão, portanto, os valores podem conter o separador.
- `strip` (bool, padrão `true`): remove espaços em branco ao redor de cada chave e valor.
- `value_parser` (dict, opcional): parser de conteúdo aninhado aplicado a cada valor, no mesmo formato `{"name": ..., "args": ...}` do `xml-inline`. Se omitido, os valores permanecem como strings brutas.

Linhas que estão vazias ou não contêm `kv_sep` são ignoradas silenciosamente, de modo que linhas em branco acidentais na região capturada são toleradas.

```python
field = {"metadata": {"open": "<meta>", "close": "</meta>", "content": "kv-lines"}}
input = "<meta>name: alice\nage: 30</meta>"
# Returns: {"metadata": {"name": "alice", "age": "30"}}
```

Observe que `age` mantém `"30"` como string; adicione um `value_parser` de `{"name": "int"}` para convertê-lo em `30`.

### Digitação dos argumentos de chamada de ferramenta

Às vezes, o parser de respostas pode interpretar as saídas do modelo com o tipo incorreto. Por exemplo, ele pode interpretar o float `1.5` como "1.50". Isso pode causar problemas na chamada de ferramentas, caso as ferramentas esperem um argumento em um tipo, mas o recebam em outro. Para evitar isso, você pode passar as `tools` da requisição para [parse_response()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response) ou `ResponseParser` para convertê-las usando o `parameters` do JSON Schema de cada ferramenta. As ferramentas são aceitas no mesmo formato de [apply_chat_template()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template): schemas JSON, ou funções Python com type hints e docstrings que são convertidas automaticamente em schemas.

```python
tools = [{
    "type": "function",
    "function": {
        "name": "set_alarm",
        "parameters": {
            "type": "object",
            "properties": {
                "hour": {"type": "integer"},
                "enabled": {"type": "boolean"},
                "label": {"type": "string"},
            },
        },
    },
}]
message = parse_response(model_out, template, prefix="", tools=tools)
# message["tool_calls"][0]["function"]["arguments"] ==
# {"hour": 7, "enabled": True, "label": "wake up"}
```

### Transform

Na maioria dos campos, a chave `transform` é desnecessária. Ela é usada quando o corpo analisado precisa ser reformatado para a saída final, ou quando informações dos delimitadores precisam ser mescladas no resultado. Ela aparece com mais frequência nos campos `tool_calls`, pois esses costumam ter uma estrutura complexa.

`transform` é um **template**: um dict (ou list) que descreve o formato de saída, onde qualquer string no formato `"{name}"` é substituída pelo valor correspondente. Os valores podem ser acessados a partir de `content` (o corpo analisado desta região) e de quaisquer grupos nomeados capturados por `open_pattern` / `close_pattern`. Um caso de uso muito comum é envolver um dict de chamada de ferramenta em um dict externo com a chave `function`, pois esses fazem parte do nosso formato padrão de chamada de ferramenta:

```python
"tool_calls": {
    "open": "<tool_call>",
    "close": "</tool_call>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": "{content}"},
},
```

Então, esta saída bruta:

```txt
<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
```

becomes (observe que `repeats: True` faz com que `tool_calls` seja uma lista):

```json
[{"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}]
```

Um placeholder de string inteira, como `"{content}"`, retorna o valor consultado com seu tipo preservado — portanto, acima, o dicionário JSON analisado é inserido diretamente como o valor de `function`. O placeholder deve ser a string inteira: misturar texto e placeholders (`"abc {name} def"`) não é permitido. Eles não são f-strings!

Placeholders também podem aceitar um caminho pontilhado como `"{content.args}"`, que busca `content` e depois desce para a chave `args` do dicionário analisado. É assim que você reestrutura corpos de chamadas de ferramenta cujos nomes de chave não correspondem ao nosso formato padrão. Por exemplo, um modelo que emite `{"name": ..., "args": ...}` precisa que `args` seja renomeado para `arguments`:

```python
"tool_calls": {
    "open": "<tool>",
    "close": "</tool>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": {"name": "{content.name}", "arguments": "{content.args}"}},
},
```

Um caminho que não é resolvido (aqui, uma chamada de ferramenta cujo corpo não possui `args`) gera um erro em vez de emitir uma chamada de ferramenta malformada.

`transform` é bastante versátil, o que se torna necessário quando a saída do modelo tem um formato muito diferente da nossa API padrão. O GPT-OSS é um bom exemplo — ele embute o nome da função no cabeçalho do canal em vez de no corpo JSON, então precisamos capturá-lo com um grupo nomeado em `open_pattern` e mesclá-lo com `content` dentro do transform. Todos os grupos nomeados em `open_pattern` e `close_pattern` ficam disponíveis como variáveis ao lado de `content`:

```python
"tool_calls": {
    "open_pattern": r"<\|channel\|>commentary to=functions\.(?P<name>\w+).*?<\|message\|>",
    "close": "<|call|>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
},
```

O nome da função fica no cabeçalho do canal, não no corpo JSON, então isso:

```txt
<|channel|>commentary to=functions.get_current_weather <|constrain|>json<|message|>{"location": "San Francisco, CA"}<|call|>
```

torna-se:

```json
[{"type": "function", "function": {"name": "get_current_weather", "arguments": {"location": "San Francisco, CA"}}}]
```

Às vezes, o conteúdo analisado de um campo é *ele mesmo* uma lista de registros e você deseja reformatar cada um deles. O template da Cohere é um bom exemplo: ele emite todas as chamadas de ferramentas dentro de um único array JSON, então definimos `transform_each: True` para aplicar a transformação por elemento. As chaves de cada elemento do array são descompactadas no escopo do template, de modo que `"{tool_name}"` consulta `tool_name` no elemento atual:

```python
"tool_calls": {
    "open": "<|START_ACTION|>",
    "close": "<|END_ACTION|>",
    "content": "json",
    "transform_each": True,
    "transform": {"type": "function", "function": {"name": "{tool_name}", "arguments": "{parameters}"}},
},
```

Isso converterá uma saída como esta:

```json
[
    {"tool_name": "greet_user", "parameters": {"greeting": "Hi!"}},
    {"tool_name": "search", "parameters": {"query": "weather tomorrow"}}
]
```

Para uma saída como esta, que se encaixa na nossa API padrão:

```json
[
    {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}},
    {"type": "function", "function": {"name": "search", "arguments": {"query": "weather tomorrow"}}}
]
```

A flag `transform_each` é necessária apenas quando `content` já é uma lista; para o caso mais comum, em que cada correspondência contribui com um elemento (e `repeats: True` os acumula), a transformação será aplicada a cada elemento por padrão.

## Desenvolvedores de frameworks: Portabilidade de expressões regulares

`open_pattern`, `close_pattern` e `start_anchor_pattern` são strings de regex. Para a maioria dos usuários e até mesmo para a maioria dos autores de modelos, isso não deve ser um problema, mas, se você é um desenvolvedor escrevendo uma implementação de análise de resposta em outra linguagem, deve estar ciente dos detalhes da nossa implementação. Esta seção é dedicada a todos que tiveram que implementar um parser Jinja completo para fazer o chat templating não em Python funcionar — esperamos que, se você seguir as diretrizes simples abaixo, os templates de resposta sejam muito menos dolorosos:

- Usamos o módulo [`regex`](https://pypi.org/project/regex/) do Python para todas as expressões regulares usadas na análise de chat. Como todas as strings do Python3 são unicode, **todas as nossas correspondências de regex são conscientes de unicode**. Isso afeta particularmente caracteres comuns como `\w`. Certifique-se de definir as flags de unicode relevantes no seu mecanismo.
- Compilamos todas as expressões regulares com `re.DOTALL` habilitado e `re.MULTILINE` desabilitado, de modo que `.` corresponda a `\n`, mas `^` e `$` correspondam apenas ao início/fim de toda a entrada, e não a quebras de linha.
- Usamos a sintaxe `(?P<name>...)` para grupos nomeados. Outras implementações de regex possuem sintaxes de grupos de captura nomeados muito diferentes, portanto, você pode precisar procurar esse padrão em regexes e reescrevê-lo para corresponder à sua implementação local.
- Usamos correspondência parcial de regex para decidir quando podemos emitir dados. Isso é necessário porque o final de uma região pode consistir em múltiplos tokens, e não queremos emitir esse delimitador de fim de região, então seguramos os tokens até termos certeza de que estão dentro da região e não fazem parte da fronteira. Isso significa que, sempre que a regex de fim de região tem uma correspondência parcial, seguramos os dados até que a regex corresponda ou falhe. Se o seu mecanismo de regex não suporta correspondência parcial, você ainda pode implementar modelos de resposta, mas pode precisar encontrar outra solução para esse problema. Uma abordagem simples é apenas segurar essas regiões / emití-las como `dirty` até que você veja definitivamente o delimitador de término.
- Seu mecanismo de expressões regulares pode (raramente) não suportar lookarounds como `(?!...)`. Embora esses não sejam comumente usados em modelos de resposta, eles podem aparecer e nós os suportamos! Você pode precisar lançar um erro nesses casos ou extrair manualmente os lookarounds e aplicá-los no seu código quando o mecanismo de expressões regulares encontrar uma possível correspondência.
- Outros recursos avançados, como backreferences, grupos atômicos, quantificadores possessivos, recursão e assim por diante, geralmente não são usados em modelos de resposta. Tentaremos dissuadir os autores de modelos de usá-los, para que você possa, com segurança, ignorá-los.

