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.
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.
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.
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.
-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
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.
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.
call_api “por precauçã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.
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.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?
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 plantonistaCada 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.
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.
Trata Ferramenta Superpoderosa.
Ao padrão de projeto Ferramentas com Menor Privilégio e Uso de Ferramentas.