o problema
Um modelo de linguagem de bilhões de parâmetros erra 27 + 4 * 2. Uma calculadora de bolso não erra. O mesmo modelo não sabe que dia é hoje, inventa fatos com confiança e tropeça em idioma de baixo recurso — enquanto sistemas muito menores e mais burros resolvem cada uma dessas coisas com precisão. O paper chama isso de paradoxo e argumenta que escalar não conserta: data de hoje não está nos pesos, e nunca vai estar.
A saída óbvia é dar ferramenta ao modelo. O problema era como ensinar. As abordagens de 2022 se dividiam em duas: pagar anotação humana em volume (caro, e o que um humano acha útil não é necessariamente o que o modelo acha útil) ou montar um prompt few-shot para uma tarefa específica, em que já se sabe de antemão qual ferramenta usar. Nenhuma das duas serve para o caso que interessa: o usuário faz uma pergunta qualquer e o modelo decide sozinho se vale chamar alguma coisa, qual, e com que argumento.
a ideia
Deixe o modelo anotar o próprio corpus e use a perda como juiz.
Pegue um texto cru de pré-treino. Peça ao modelo, com um punhado de exemplos escritos à mão, que insira chamadas de API onde ele achar que cabem. Execute todas. Depois compare: prever o resto do texto ficou mais fácil com o resultado da chamada na frente, ou não? Se ficou, a chamada era útil e vira dado de treino. Se não ficou, joga fora. Nenhum humano opina sobre quais chamadas eram boas; o sinal é a própria loss do modelo.
O detalhe elegante é que o corpus final é o mesmo corpus original, só com chamadas intercaladas. O modelo é finetunado exatamente no texto que ele já viu, mais as anotações. Por isso ele não perde generalidade nem vira um modelo de tarefa.
como funciona
O pipeline tem três passos, para cada uma das cinco ferramentas (question answering via Atlas, busca na Wikipédia via BM25, calculadora com as quatro operações, calendário e tradução via NLLB de 600 milhões de parâmetros).
para cada texto x do corpus:
# 1. amostrar
posições = { i : p(<API> | prompt(x), x[:i]) > 0,05 } # top 5
para cada i: amostre até 5 chamadas candidatas c
# 2. executar
r = api(c)
# 3. filtrar
L+ = loss(x[i:] | prefixo = "[ api(args) -> r ]")
L- = min( loss(x[i:]), loss(x[i:] | prefixo = "[ api(args) ]") )
mantém se L- - L+ >= 1,0
L- é o mínimo entre não chamar nada e chamar sem receber resposta — isso impede que a chamada passe no filtro só por ser um prefixo bonito. A loss é ponderada com decaimento linear (peso max(0, 1 - 0,2t)), para que a chamada caia perto de onde a informação serve, não vinte tokens antes.
Os tokens especiais são literalmente [, ] e ->. Nada de mexer no vocabulário. Na inferência, a decodificação segue normal até o modelo emitir ->; aí o processo é interrompido, a API é chamada de verdade, o resultado e o ] são inseridos, e a geração continua.
Uma correção prática: na avaliação, o modelo emite <API> se esse token estiver entre os 10 mais prováveis, não só se for o mais provável, e no máximo uma chamada por entrada.
o que isso custou
O truque do top-10 é onde o preço aparece. Com decodificação gulosa pura, o modelo chama API em 40,3% dos exemplos do T-REx — e é calibrado: ele chama justamente nos casos em que iria mal sem ajuda. Subindo para k igual a 10, a cobertura vai a 98,1% e o score sobe de 47,8 para 53,5, mas a calibração some. Compra-se cobertura com discernimento.
Os autores listam o resto sem enfeite. Não há encadeamento: as chamadas são amostradas independentemente, então não existe exemplo de usar a saída de uma ferramenta como entrada de outra. Não há interação: o modelo faz uma busca e engole o resultado, sem reformular a query nem navegar entre os resultados — e é exatamente isso que explica ficar atrás do GPT-3 em NQ e TriviaQA, já que o retriever devolve lixo com frequência. O método é sensível à formulação exata da entrada. E é caro: mais de um milhão de documentos para produzir 994 exemplos de calculadora no limiar padrão.
Duas ferramentas simplesmente não pegaram. O calendário é usado em 0,2% do TempLAMA — o ganho ali veio de busca e QA. No MLQA, a tradução é chamada em até 94,9% dos casos, mas o finetuning em CCNet degrada o modelo o suficiente para que Toolformer não bata o GPT-J puro de forma consistente. E o modelo nunca considera o custo computacional de chamar a ferramenta.
onde isso aparece hoje
A receita de gerar dado com o próprio modelo e filtrar por um critério automático virou padrão de bootstrapping. Mais visível ainda: as duas limitações que o paper declara — encadear ferramentas e interagir com elas em várias rodadas — são hoje a definição operacional de agente, e o loop de chamar, ler o resultado e decidir o próximo passo é o que as APIs de function calling expõem. O Toolformer resolveu a parte de decidir sozinho quando chamar; a parte de continuar chamando ficou para depois.