Aula 2, Tool calling
Esta aula coloca o LLM no comando do agente. Em vez de um controlador por regras, o próprio modelo decide qual ferramenta usar, pedindo a chamada em formato estruturado. Vamos montar um registro de ferramentas e fazer o agente despachar as chamadas do modelo.
No agente da aula anterior, quem decidia a ferramenta era uma regra escrita por nós. Isso funciona para casos simples, mas não escala, teríamos que prever cada situação. O salto para um agente de verdade é deixar o LLM decidir. Ele lê a pergunta e as ferramentas disponíveis, e escolhe qual usar e com quais argumentos. Essa capacidade se chama tool calling, ou chamada de ferramentas.
A peça que torna isso possível é a saída estruturada do Módulo 8. O modelo não executa a ferramenta, ele pede a execução, devolvendo um JSON que diz qual ferramenta quer e com quais argumentos. Nosso código então lê esse pedido, executa a ferramenta de verdade, e devolve o resultado ao modelo. Nesta aula você vai montar esse mecanismo, um registro de ferramentas e um despachante que conecta a decisão do modelo à ação real.
Objetivos
Ao final desta aula, você deve ser capaz de:
- Explicar como o LLM decide e solicita uma chamada de ferramenta.
- Descrever uma ferramenta para o modelo, com nome, descrição e argumentos.
- Implementar um registro de ferramentas e um despachante.
- Conectar a chamada do modelo à execução real da ferramenta.
Teoria
O tool calling tem três partes. Primeiro, descrevemos as ferramentas para o modelo, dizendo o nome de cada uma, o que faz e quais argumentos espera. Segundo, instruímos o modelo a responder, quando precisar de uma ferramenta, com um JSON contendo o nome da ferramenta e os argumentos. Terceiro, o nosso código lê esse JSON, encontra a ferramenta no registro, a executa com os argumentos, e devolve o resultado.
O ponto crucial é a separação de papéis. O modelo decide e pede, mas quem executa é o código. Isso é o que mantém o sistema seguro e confiável, a ferramenta de calculadora roda o nosso código seguro, não algo que o modelo inventou, e a busca consulta a nossa base, não a memória do modelo. O modelo é o cérebro que escolhe, e as ferramentas são as mãos que agem, sob o nosso controle. Essa ideia de modelos que aprendem a usar ferramentas foi explorada em trabalhos como o Toolformer, de Schick e colegas.
flowchart LR
P[Pergunta + descrição das ferramentas] --> M[LLM]
M --> J[JSON: ferramenta + argumentos]
J --> D[Despachante]
D --> T[Executa a ferramenta no nosso código]
T --> R[Resultado volta ao modelo]
Os provedores de LLM modernos oferecem suporte nativo a tool calling, com formatos próprios. Mas entender o mecanismo na mão, com saída estruturada e um despachante, é o que permite usá-lo com qualquer modelo, inclusive os locais, e depurar quando algo dá errado.
Explicação Intuitiva
Pense em um gerente que coordena uma equipe de especialistas. O gerente não faz as contas nem busca os documentos, ele decide quem deve fazer o quê e passa a tarefa para o especialista certo. O LLM é esse gerente, e as ferramentas são os especialistas. O gerente diz preciso que a calculadora resolva isto, e o código, como um assistente, leva a tarefa ao especialista e traz a resposta de volta.
A descrição das ferramentas é como o organograma que o gerente consulta. Sem saber que existe uma calculadora e o que ela faz, o gerente não a usaria. Por isso descrevemos cada ferramenta com clareza, é assim que o modelo sabe o que tem à disposição e quando usar cada coisa. Quanto melhor a descrição, melhores as decisões do agente.
Explicação Matemática
A parte formal aqui é a do contrato de chamada. Definimos cada ferramenta como um nome associado a uma função, e um esquema dos seus argumentos. O modelo produz um objeto ${\text{nome}, \text{argumentos}}$, e o despachante calcula $\text{ferramenta}\text{nome}$.
A robustez vem da validação, herdada da aula de saída estruturada. Antes de despachar, verificamos que o JSON é válido, que o nome corresponde a uma ferramenta existente, e que os argumentos estão presentes. Se algo falha, tratamos o erro, em vez de quebrar, por exemplo devolvendo ao modelo uma mensagem dizendo que a chamada foi inválida, para que ele tente de novo. Essa disciplina é o que torna o tool calling confiável na prática.
Exemplo Prático
Vamos montar um registro de ferramentas, cada uma com nome, descrição e função, e um despachante que recebe um pedido em JSON, valida e executa. Para testar sem depender do modelo, simulamos a saída do LLM com pedidos em JSON, alguns válidos e um inválido, e vemos o despachante tratar cada caso.
No notebook, fechamos o ciclo enviando a pergunta ao LLM via Ollama, com a instrução de pedir ferramentas em JSON, e despachando o que ele decidir. O código está no notebook notebooks/modulo-10/02-tool-calling.ipynb, então abra-o ao lado para acompanhar.
Código Comentado
import re
import json
import ast
import operator
OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def calcular(expressao):
def ev(no):
if isinstance(no, ast.Constant):
return no.value
if isinstance(no, ast.BinOp):
return OPS[type(no.op)](ev(no.left), ev(no.right))
if isinstance(no, ast.UnaryOp):
return OPS[type(no.op)](ev(no.operand))
raise ValueError("expressão não permitida")
return ev(ast.parse(str(expressao), mode="eval").body)
def buscar(consulta):
base = {"derivada": "A derivada mede a taxa de variação de uma função."}
for chave, texto in base.items():
if chave in str(consulta).lower():
return texto
return "Não encontrei no material."
# Registro: nome -> (descrição, função, argumento esperado).
FERRAMENTAS = {
"calcular": ("Resolve uma expressão aritmética.", calcular, "expressao"),
"buscar": ("Busca um tema na base de notas de aula.", buscar, "consulta"),
}
def despachar(pedido_json):
"""Lê um pedido do modelo em JSON, valida e executa a ferramenta."""
m = re.search(r"\{.*\}", pedido_json, re.DOTALL)
if not m:
return "Erro: não veio um JSON."
try:
pedido = json.loads(m.group(0))
except json.JSONDecodeError:
return "Erro: JSON inválido."
nome = pedido.get("ferramenta")
if nome not in FERRAMENTAS:
return f"Erro: ferramenta '{nome}' não existe."
_, funcao, arg_nome = FERRAMENTAS[nome]
if arg_nome not in pedido:
return f"Erro: falta o argumento '{arg_nome}'."
try:
return funcao(pedido[arg_nome])
except Exception as erro:
return f"Erro ao executar: {erro}"
# Simula pedidos do modelo, incluindo um inválido.
pedidos = [
'{"ferramenta": "calcular", "expressao": "28*3/4"}',
'{"ferramenta": "buscar", "consulta": "o que é a derivada?"}',
'{"ferramenta": "voar", "destino": "lua"}',
]
for p in pedidos:
print(p, "->", despachar(p))
Ao rodar, o despachante executa corretamente os dois primeiros pedidos, calculando 21.0 e trazendo o trecho da derivada, e trata o terceiro com uma mensagem de erro clara, pois a ferramenta voar não existe. Esse é o coração do tool calling, o modelo decide e pede em JSON, o nosso código valida e executa. Note como reutilizamos a extração e a validação de JSON da aula de saída estruturada, agora a serviço do agente.
Exercícios
1) Conceitual: Por que o modelo pede a ferramenta em vez de executá-la, e por que isso é mais seguro? 2) Conceitual: Quais são as três partes do mecanismo de tool calling? 3) Prático: Acrescente uma nova ferramenta ao registro, com descrição e argumento, e teste um pedido para ela. 4) Prático: Envie ao despachante um pedido com o argumento errado e confirme que ele trata o erro. 5) Extensão: Pesquise o suporte nativo a tool calling de algum provedor de LLM e compare com o despachante feito à mão.
Projeto da Aula
Construa um agente com tool calling pelo LLM. A entrega é um agente que descreve as ferramentas ao modelo, recebe a decisão dele em JSON, valida e despacha, usando o Ollama. Inclua o tratamento de erros para chamadas inválidas.
Considere o projeto pronto quando o modelo conseguir escolher a ferramenta certa para diferentes perguntas e o despachante executar com segurança, tratando os erros. Esse agente, que já decide sozinho qual ferramenta usar, é a base para o planejamento de várias etapas da próxima aula.
Leituras Recomendadas
- O artigo Toolformer, de Schick e colegas, sobre modelos que aprendem a usar ferramentas.
- A documentação de tool calling ou function calling de provedores de LLM.
- Guias do LangChain e do LangGraph sobre a definição e o uso de ferramentas.
Referências Científicas
As referências abaixo são reais e estão registradas em references/referencias.bib. As chaves entre parênteses são as do BibTeX.
- Schick, T., et al. (2023). Toolformer: Language Models Can Teach Themselves to Use Tools.
NeurIPS. (
schick2023toolformer) - Yao, S., et al. (2023). ReAct: Synergizing Reasoning and Acting in Language Models. ICLR.
(
yao2023react) - Liu, P., et al. (2023). Pre-train, Prompt, and Predict. ACM Computing Surveys.
(
liu2023prompt)