Lucas S. Vieira


Primeira Ferramenta


Dando poderes ao agente


Guilda de IA

Recap: Semana 06

  • Agente = LLM + harness: instruções, memória, input, output
  • O histórico vai inteiro a cada chamada
  • Histórico infinito não cabe: rotação
  • ReAct: Thought → Action → Observation → Answer

"Semana passada ele aprendeu a lembrar. Hoje aprende a agir."

O problema do LLM puro

LLMs são modelos de linguagem. Eles preveem texto, não calculam.

Pergunta: "Quanto é 234 × 987?"

O modelo não calcula. Ele prevê a resposta baseado em padrões. Pode acertar, pode errar.

A solução: ferramentas

Ferramenta = função Python que o agente pode chamar.

📓 Colab

Como funciona:

  1. O LLM recebe a descrição das ferramentas disponíveis
  2. Analisa a pergunta
  3. Decide: preciso dessa ferramenta?
  4. Gera os argumentos no formato correto
  5. Python executa e devolve resultado
  6. O LLM usa o resultado na resposta

Exemplo: calculadora

@tool
def calculate(a: float, b: float, operation: str) -> float:
    """Performs a math operation between two numbers
    and returns the exact result.
    Use when you need to do calculations.
    operation: 'add', 'subtract', 'multiply', 'divide'
    """
    ops = {'add': a+b, 'subtract': a-b,
           'multiply': a*b, 'divide': a/b}
    return ops[operation]

Parâmetros nomeados: seguro e simples. Sem eval, sem parsing.

Exemplo: tamanho de palavra

@tool
def get_word_length(word: str) -> int:
    """Returns the number of characters in a word.
    Use when the user asks about the length
    of a word or how many letters it has.
    """
    return len(word)

O segredo: descrição clara

O modelo decide baseado na descrição.

Descrição ruim:

"Calculadora."

→ Modelo não sabe quando usar.

Descrição boa:

"Performs a math operation between two numbers and returns the exact result. Use when you need to do calculations."

→ Modelo entende quando E como usar.

@tool: Pydantic resolve o parsing

  • @tool gera o schema JSON automaticamente
  • Pydantic valida e converte os tipos
  • "234" → 234.0 (conversão automática)
  • ValidationError se o LLM manda lixo

Sem @tool:

a = float(args["a"])       # manual
b = float(args["b"])       # manual

Com @tool:

resultado = calculate.invoke(args)  # Pydantic!

O ciclo da ferramenta

  1. Você descreve as ferramentas pro LLM (nome, descrição, parâmetros)
  2. O LLM lê a pergunta e decide se alguma serve
  3. Ele devolve os argumentos — não a resposta
  4. Python executa a função de verdade
  5. O resultado volta pro LLM, que formula a resposta final

O ciclo manual: bind_tools

  1. invoke → LLM decide (retorna tool_calls, não executa)
  2. Você executa a ferramenta com os argumentos
  3. invoke de novo com ToolMessage → resposta final

Passo 1 — o LLM decide:

resposta = llm_com_ferramentas.invoke(
    "Quanto é 234 vezes 987?")
pprint(resposta.tool_calls)
# [{'name': 'calculate',
#   'args': {'a': 234, 'b': 987,
#            'operation': 'multiply'},
#   'id': 'call_abc123'}]

resposta.content é string vazia — o LLM não executou!

Passo 2 — você executa:

tc = resposta.tool_calls[0]
resultado = FERRAMENTAS[tc['name']].invoke(tc['args'])
print(resultado)  # 230958.0

Passo 3 — resultado volta pro LLM:

mensagens = [
    HumanMessage(content="Quanto é 234 vezes 987?"),
    resposta,  # AIMessage com tool_call
    ToolMessage(content=str(resultado),
                tool_call_id=tc['id']),
]
resposta_final = llm_com_ferramentas.invoke(mensagens)
# "O resultado é 230.958."

ReAct se completa

O ciclo manual é ReAct em ação:

  • Thought → LLM raciocina ("preciso calcular")
  • Action → LLM chama ferramenta (tool_calls)
  • Observation → você executa e devolve o resultado
  • Answer → LLM formula a resposta final

(Yao et al., 2022)

E quando precisa de duas?

"Quanto é 10 mais 100 vezes 3?" não é uma conta só:

10 + (100 * 3)   →   duas operações

O modelo pede a primeira, recebe o resultado, e aí pede a segunda.

O ciclo repete até ele ter tudo que precisa:

while resposta.tool_calls:
    ...executa a ferramenta e devolve...
    resposta = llm_com_ferramentas.invoke(historico)

Sem esse laço, a resposta final chega vazia — ele ainda está pedindo ferramenta.

O ciclo automático: create_agent

O ciclo manual é bom pra entender. Na prática:

from langchain.agents import create_agent

agente = create_agent(llm, [calculate, get_word_length])

resultado = agente.invoke(
    {"messages": "Quanto é 234 vezes 987?"})
print(resultado["messages"][-1].content)

Uma linha. Decide, executa, responde — tudo automático.

Para lembrar

"Ferramenta transforma conversa em ação."

LLM puro: só fala. Agente com ferramenta: fala e faz.

  • Manual (bind_tools): entender o que acontece por baixo
  • Automático (create_agent): produzir

Para a próxima aula

  • Ter um modelo local rodando (Ollama ou llama-swap)
  • Próxima aula: Ferramentas múltiplas! O agente escolhe entre várias e encadeia mais de uma na mesma pergunta.

Perguntas?