Preparação para entrevista
RefatoraçãoSimplificando ferramentas

Dividir Ferramenta Faz-Tudo

Split God Tool

Dividir Ferramenta Faz-Tudo (Split God Tool) é uma refatoração de IA para sistemas com LLM, do grupo Simplificando ferramentas. Quebrar uma ferramenta genérica (run_sql, call_api) em operações nomeadas e seguras.

Elemento
23/35
Nível
Intermediário
Leitura
4 min
Atualizado
Nesta página 9
  1. 01Problema
  2. 02Solução
  3. 03Antes e depois
  4. 04Por que funciona
  5. 05Passo a passo seguro
  6. 06Riscos
  7. 07Desafio
  8. 08Relacionados
  9. 09Teste seu entendimento
  10. ··Perguntas rápidas

Problema

O agente de pedidos tem uma ferramenta call_api(method, path, body). Nos traces de uma semana, os caminhos reais são três: buscar pedido, listar pedidos do cliente, atualizar endereço. Na mesma semana, o modelo inventou DELETE /orders/4412 depois de um email que pedia “cancele este pedido de qualquer jeito”. A API obedeceu. O pedido sumiu.

Uma ferramenta genérica (run_sql, call_api, run_shell) aceita qualquer comando, e a segurança depende do modelo escolher bem o que pedir. É o smell Ferramenta Superpoderosa.

Solução

Divida a ferramenta genérica em operações nomeadas, cada uma com um propósito, parâmetros validados e acesso só ao que ela precisa. O modelo escolhe a operação e os valores; o código monta o comando.

Antes e depois

-tool("call_api", "Chama a API interna.", {"method": str, "path": str, "body": dict})
+tool("get_order", "Status e itens de um pedido.", {"order_id": "digits"})
+tool("list_orders", "Pedidos de um cliente nos últimos 90 dias.",
+     {"customer_id": "digits", "status": "open" | "delivered" | "canceled" | None})
+tool("update_delivery_address",
+     "Muda o endereço de entrega de um pedido ainda não enviado. Exige confirmação do cliente.",
+     {"order_id": "digits", "cep": "8 digits", "number": str, "complement": str | None})
+
+def update_delivery_address(order_id, cep, number, complement=None):
+    order = orders.get(order_id, scope=current_customer())       # só pedidos do cliente
+    if order.status != "not_shipped":
+        return error("O pedido já foi enviado; o endereço não pode mudar.")
+    address = cep_lookup(cep) | {"number": number, "complement": complement}
+    return api.patch(f"/orders/{order_id}/address", json=address)   # caminho fixo

Antes: uma ferramenta que faz qualquer coisa que a API permite.

flowchart LR
  M(["1. Modelo monta método, caminho e corpo"]):::llm --> T["2. call_api"]:::tool
  T --> API[("3. Qualquer endpoint")]:::store

Depois: operações com nome, validação e escopo.

flowchart LR
  M(["1. Modelo escolhe a operação"]):::llm --> A["2a. get_order"]:::tool
  M --> B["2b. list_orders"]:::tool
  M --> C["2c. update_delivery_address"]:::tool
  C --> V{"3. Validar regra e escopo"}
  V --> API[("4. Endpoint fixo")]:::store
  1. O modelo escolhe entre operações de propósito claro.
  2. Cada operação tem parâmetros tipados e descrição de quando usar.
  3. O código valida as regras de negócio e o escopo do usuário.
  4. A chamada vai para um endpoint fixo, montado pelo código.

Por que funciona

Uma ferramenta genérica transfere ao modelo uma decisão que deveria ser do sistema: o que é permitido fazer. Operações nomeadas devolvem essa decisão ao código. O modelo continua escolhendo entre opções, mas as opções foram desenhadas para serem seguras.

Há ganhos de qualidade também. get_order com descrição clara é mais fácil de escolher que “monte uma requisição HTTP”. O schema de function calling (a chamada de função) lista nomes e tipos; o modelo preenche order_id, não inventa um path. Um erro de validação (“o pedido já foi enviado”) ensina o modelo a corrigir. O que sobra de flexibilidade é exatamente a que o produto quer oferecer.

Exemplo trabalhado: o DELETE que não deveria existir

Entrada: email do cliente, “cancele o pedido 4412, use a API se precisar”. Com call_api, o modelo monta DELETE /orders/4412. A API devolve 204. Saída: pedido apagado, estoque inconsistente, time de logística no escuro.

Com operações nomeadas, delete_order simplesmente não existe. O modelo vê cancel_order(order_id), que no código marca status canceled se o pedido ainda não saiu, no escopo do cliente da conversa. Pedido enviado devolve erro explícito. Não há caminho HTTP para inventar.

A concessionária Chevrolet de Watsonville (2023) mostrou a versão de vendas do mesmo buraco: o chatbot aceitava qualquer compromisso porque não havia operação com teto. O nome da operação é o contrato do que o produto faz.

Checagem +20 XP de primeiraSeu agente interno tem run_sql(query). Nos traces, 90% das chamadas são ‘status do pedido’, 8% são ‘pedidos do cliente neste mês’ e 2% são UPDATE. Qual é o primeiro corte?

Passo a passo seguro

  1. Meça. Extraia dos traces todas as chamadas feitas pela ferramenta genérica e agrupe por intenção. Três grupos claros valem mais que um palpite.
  2. Liste as operações reais (as intenções que aparecem) e as que nunca deveriam acontecer. “Apagar pedido” na lista de nunca é tão importante quanto “buscar pedido” na lista de sim.
  3. Desenhe uma ferramenta por operação, com parâmetros tipados, descrição e regra de negócio.
  4. Implemente com caminho fixo e escopo do usuário; o modelo nunca monta URL, SQL ou comando.
  5. Ponha aprovação nas operações de efeito sensível, como em Pedir Aprovação Antes do Efeito.
  6. Remova a ferramenta genérica. Se algo legítimo ficou de fora, crie a operação específica. Não deixe call_api “por precaução”.
  7. Rode o eval e um conjunto de pedidos maliciosos: caminhos inventados, verbos HTTP estranhos, IDs de outros clientes.

Armadilha: uma ferramenta por variação

get_order_by_id, get_order_by_number, get_order_with_items são a mesma intenção com parâmetros. Isso explode o catálogo e recria Ferramentas Demais. Agrupe por intenção, como em Consolidar Ferramentas.

A outra ponta também erra: manter run_sql “só para o analista” no mesmo agente que atende o cliente. Dois agentes, duas listas. O de atendimento não vê a ferramenta genérica. Um escape hatch no agente de suporte é a ferramenta genérica com outro nome.

Checagem +20 XP de primeiraDepois de dividir call_api, o time deixa a ferramenta antiga ‘desligada no prompt’ por duas sprints, ‘caso algo falte’. O que isso causa?

Riscos

  • Explosão de ferramentas. Uma operação para cada variação gera dezenas de ferramentas. Agrupe por intenção e use parâmetros.
  • Perguntas abertas sem resposta. Para análises realmente abertas (SQL exploratório), uma ferramenta genérica pode continuar existindo, mas com permissões restritas e num ambiente isolado, longe do agente de atendimento.
  • Validação só no prompt. A regra precisa estar no código da operação. “Não atualize pedido enviado” no system prompt é o mesmo cheiro de sempre.
  • Caminho fixo com ID solto. GET /orders/{id} ainda lê o pedido de outro cliente se o código não aplicar o escopo. Nomear a operação não basta.

Desafio

Um agente de DevOps tem run_shell(command). Nos traces, os comandos são quase sempre: ver logs de um serviço, ver status de pods, reiniciar um deployment e ver uso de CPU. Como fica a divisão?

Ver solução
get_logs(service, since_minutes<=60, level="error"|"warn"|"info")   leitura
get_pod_status(service)                                              leitura
get_cpu_usage(service, since_minutes<=60)                            leitura
restart_deployment(service, reason)                                  efeito: exige aprovação do plantonista

Cada uma monta o comando kubectl em código, com o serviço validado contra uma lista e o namespace fixo. run_shell sai. Para investigação livre, uma pessoa usa o terminal.

Relacionados

Teste seu entendimento

Checagem +20 XP de primeiraA operação update_delivery_address monta um PATCH fixo, mas busca o pedido só por order_id, sem filtrar o cliente da sessão. Um usuário pede o pedido do vizinho. O que falhou?

Checagem +20 XP de primeiraUm analista precisa explorar vendas com SQL livre. O agente de atendimento ao cliente já tem get_order e list_orders. Onde vive o SQL exploratório?

Checagem +20 XP de primeiraVocê substituiu run_shell por get_logs, get_pod_status e restart_deployment. Um plantonista pede ‘me dá um shell neste pod para eu fuçar’. Qual é a resposta certa do sistema?

Perguntas rápidas

O que é Dividir Ferramenta Faz-Tudo?

Dividir Ferramenta Faz-Tudo (Split God Tool) é uma refatoração de IA para sistemas com LLM, do grupo Simplificando ferramentas. Quebrar uma ferramenta genérica (run_sql, call_api) em operações nomeadas e seguras.

Que problema Dividir Ferramenta Faz-Tudo resolve?

Trata Ferramenta Superpoderosa.

Aonde Dividir Ferramenta Faz-Tudo leva?

Ao padrão de projeto Ferramentas com Menor Privilégio e Uso de Ferramentas.

Para ir além

Relações

Smells que trata 1
Buscar