Perguntei a um LLM quanto valeria a casa do meu vizinho, um lugar de 300m² com 4 quartos, não muito antigo. Ele me deu uma resposta vaga e evasiva que poderia ter se aplicado a quase qualquer propriedade. Então decidi construir algo melhor, e no processo aprendi uma lição importante sobre quando usar machine learning tradicional ao invés de um modelo de linguagem.
Com todo o hype em torno dos LLMs, é tentador tratá-los como balas de prata. Mas como veremos neste post, apoiado por experimentos de benchmark reais, existem tarefas onde algoritmos de ML tradicionais não são apenas alternativas viáveis, mas mensuravelmente superiores. E a melhor parte? As duas abordagens podem trabalhar juntas.
O Problema: Quanto Vale Aquela Casa?
Determinar um preço justo para uma propriedade está longe de ser trivial. Você pode filtrar por quartos, banheiros, metros quadrados e localização, mas transformar essas características em uma estimativa de preço confiável requer mais que intuição.
Um LLM pode te dar um valor aproximado, mas sua resposta não está fundamentada no seu conjunto de dados real. Está usando dados gerais de treinamento, e para uma tarefa que exige precisão numérica em entradas estruturadas, isso é uma limitação fundamental.
Uma abordagem mais confiável é usar um algoritmo de machine learning projetado exatamente para esse tipo de tarefa preditiva. Neste artigo, usaremos Random Forest e depois o colocaremos frente a frente com um LLM para provar o ponto com dados.
Como o Random Forest Funciona
Random Forest combina a saída de múltiplas árvores de decisão para produzir uma única predição. Cada árvore aprende a partir de um subconjunto aleatório dos dados e faz sua própria estimativa. A floresta agrega todas as respostas das árvores:
- Para regressão (prever um preço), ela calcula a média das predições.
- Para classificação (ex: “barato” vs. “caro”), ela pega o voto da maioria.
Uma única árvore de decisão funciona fazendo uma sequência de perguntas estruturadas sobre os dados de entrada. Começando no nó raiz, ela avalia uma condição (ex: “A área é > 100m²?”), ramifica baseada na resposta, e repete até chegar a um nó folha contendo a predição final.
O poder do Random Forest está em combinar muitas dessas árvores. Cada uma vê uma fatia ligeiramente diferente dos dados, então seus erros individuais tendem a se cancelar. O resultado é um modelo mais preciso e robusto que qualquer árvore individual.
Definindo Nosso Modelo
Para estimar o preço de uma propriedade, precisamos definir características (X) e um alvo (Y).
Características:
- Área (em metros quadrados)
- Número de Quartos
- Número de Banheiros
- Idade (em anos)
Alvo: Preço (em milhares)
Nosso conjunto de dados é um arquivo CSV onde cada linha contém essas 4 características mais o preço. Usamos um conjunto de dados sintético aqui – a seção Limitações abaixo discute o que isso significa para os resultados e como a abordagem escala para dados reais.
Treinando o Modelo em Ruby
Usaremos Rumale (uma biblioteca de machine learning para Ruby) e Numo::NArray (para arrays numéricos eficientes, similar ao NumPy em Python).
require 'csv'
require 'rumale'
require 'numo/narray'
# Carregar e dividir dados
data = CSV.read("houses.csv")
houses_features = data.map { |row| (0..row.length-2).map { |i| row[i].to_i } }
houses_prices = data.map { |row| row.last.to_i }
x = Numo::DFloat.asarray(houses_features)
y = Numo::DFloat.asarray(houses_prices)
# Treinar Random Forest
model = Rumale::Ensemble::RandomForestRegressor.new(
n_estimators: 100, # 100 árvores de decisão
max_depth: nil, # deixar árvores crescerem totalmente
random_seed: 42 # resultados reproduzíveis
)
model.fit(x, y)
# Salvar para uso posterior
File.open("house_model.dat", "wb") { |f| Marshal.dump(model, f) }Isso treina 100 árvores de decisão em nossos dados e salva o modelo em disco. O random_seed garante reprodutibilidade – execute duas vezes, obtenha o mesmo modelo.
Uma vez treinado, fazer predições é direto:
require 'rumale'
require 'numo/narray'
def predict_price(params)
model = Marshal.load(File.read("house_model.dat"))
input = Numo::DFloat[[
params[:area],
params[:rooms],
params[:bathrooms],
params[:age]
]]
puts "Preço previsto: #{model.predict(input)[0]}K"
end
predict_price(area: 500, rooms: 10, bathrooms: 5, age: 20)Envolvi isso em uma aplicação web simples onde usuários preenchem as características da propriedade e recebem uma estimativa de preço instantânea:


O código fonte está no GitHub – contribuições são bem-vindas.
Colocando à Prova: Random Forest vs. LLM
Em vez de apenas afirmar que Random Forest é melhor para essa tarefa, executei uma série de experimentos controlados para medir a diferença em quatro dimensões: precisão, latência, consistência e integração híbrida. Você pode reproduzir todos os resultados usando o script de benchmark incluído neste post.
Configuração Experimental
Para tornar esses resultados reproduzíveis, aqui estão as condições exatas:
Conjunto de dados: Arquivo CSV com 50050 linhas, cada uma contendo 4 características numéricas (área em m², quartos, banheiros, idade em anos) e um preço alvo em milhares. Dividido 80/20 em conjuntos de treinamento (40040 linhas) e teste (10010 linhas) usando uma semente fixa de embaralhamento de 42.
Configuração do Random Forest:
- Biblioteca: Rumale (Ruby)
n_estimators: 100max_depth: nil (ilimitado)random_seed: 42
Configuração do LLM:
- Provedor: OpenRouter
- Modelo:
anthropic/claude-opus-4.6(Claude Opus 4.6) max_tokens: 50 (para predições de preço), 100 (para extração de características)temperature: 1.0 (para experimentos de predição e consistência), 0.0 (para extração de características)
Prompts usados (textualmente):
Para predição de preço (Experimentos 1–3):
You are a house price estimator. Based on these features, predict the house
price in thousands (K). Reply with ONLY a number followed by K. Example: 450K
Features:
- Area: {area} m²
- Rooms: {rooms}
- Bathrooms: {bathrooms}
- Age: {age} years
Predicted price:Para extração de características (Experimento 4):
Extract house features from the following description. Return ONLY a JSON
object with these exact keys:
{"area": <number>, "rooms": <number>, "bathrooms": <number>, "age": <number>}
Description: "{user_text}"
JSON:Métricas de avaliação:
- MAE (Erro Médio Absoluto): média de |real − previsto| em casos de teste
- RMSE (Raiz Quadrada do Erro Médio): raiz quadrada da média dos erros quadrados
- Latência: tempo de relógio por predição (incluindo ida e volta da rede para LLM)
- Variância: desvio padrão em 10 predições repetidas da mesma entrada
Todos os experimentos com LLM foram executados no mesmo subconjunto de teste de 20 casos para manter os custos da API gerenciáveis. As métricas do Random Forest também são reportadas neste mesmo subconjunto para comparação justa.
Experimento 1: Precisão
Usando o subconjunto de teste de 20 casos descrito acima, executei ambos os modelos nas mesmas entradas e comparei seus erros:
| Métrica | Random Forest | LLM (anthropic/claude-opus-4.6) |
|---|---|---|
| MAE | 8.21K | 155.4K |
| RMSE | 10.8K | 213.5K |
O modelo Random Forest, treinado no conjunto de dados real, produz predições fundamentadas nos padrões que aprendeu. O LLM, apesar de ser notavelmente capaz em tarefas de linguagem, está essencialmente chutando baseado em conhecimento geral. Ele não tem acesso à nossa distribuição específica de dados.
Experimento 2: Latência e Custo
Velocidade importa, especialmente se você está servindo predições em uma aplicação web.
| Métrica | Random Forest | LLM |
|---|---|---|
| Latência média | 0.45 ms | 4040.5 ms |
| Aceleração | — | ~8985x mais lento |
A inferência do Random Forest é quase instantânea – microssegundos em uma única CPU. Uma chamada de API do LLM envolve idas e vindas de rede e tempo de inferência de GPU, tornando-o ordens de magnitude mais lento.
Experimento 3: Consistência
Pedi para cada modelo prever o mesmo preço de casa 10 vezes.
Random Forest retornou exatamente o mesmo número todas as vezes – é determinístico dada a mesma entrada e semente.
O LLM retornou um número diferente quase todas as vezes. Mesmo com o mesmo prompt, a natureza estocástica da geração de linguagem significa que você obtém variância nas saídas numéricas.
| Caso | Variância RF | Desvio Padrão LLM |
|---|---|---|
| 342, 6, 6, 22 | 0 (determinístico) | 70.06K |
| 280, 5, 5, 12 | 0 (determinístico) | 14.0K |
| 267, 5, 2, 32 | 0 (determinístico) | 32.33K |
Para uma ferramenta de precificação, essa inconsistência é um problema sério. Usuários esperam que a mesma entrada produza a mesma saída.
Experimento 4: A Abordagem Híbrida
Aqui está a reviravolta. Usuários reais não digitam números estruturados em formulários – eles dizem coisas como:
“Uma casa espaçosa de 250 metros quadrados com 5 quartos e 3 banheiros, construída há cerca de 10 anos”
Random Forest não pode processar isso. Mas um LLM pode.
Construí um pipeline híbrido onde o LLM extrai características estruturadas da linguagem natural, depois as passa para o Random Forest para predição:
Texto do usuário → LLM (extrair parâmetros) → Random Forest → Predição de preço| Entrada | Esperado | Extraído | Corresponde | Preço RF (extraído) | Preço RF (correto) |
|---|---|---|---|---|---|
| A spacious 250 square meter house with 5 … | [250, 5, 3, 10] | [250, 5, 3, 10] | ✅ | 669.0K | 669.0K |
| Small apartment, 60m², 2 rooms, 1 bathroo… | [60, 2, 1, 2] | [60, 2, 1, 2] | ✅ | 175.6K | 175.6K |
| Old colonial mansion with 400 square mete… | [400, 8, 4, 50] | [400, 8, 4, 50] | ✅ | 800.8K | 800.8K |
| Modern 120m² flat, 3 bedrooms, 2 bathroom… | [120, 3, 2, 5] | [120, 3, 2, 5] | ✅ | 324.2K | 324.2K |
| Cozy 80 sqm home, two bedrooms, one bathr… | [80, 2, 1, 15] | [80, 2, 1, 15] | ✅ | 175.7K | 175.7K |
Precisão da extração: 100.0%
Em Ruby, esse pipeline se parece com:
user_text = "Casa moderna de 300m², 4 quartos, menos de 10 anos"
# LLM extrai características estruturadas
structured_params = LLM.extract_features(user_text)
# => { area: 300, rooms: 4, bathrooms: 2, age: 10 }
# Random Forest prevê o preço
predict_price(structured_params)
# => "Preço previsto: 485K"Cada ferramenta faz o que faz melhor: o LLM lida com linguagem humana flexível, o modelo de ML lida com predição numérica.
O que Isso nos Ensina
Os experimentos acima mediram quatro dimensões específicas, e os resultados apontam para uma clara divisão de trabalho:
Onde o Random Forest vence: Em predição numérica estruturada, foi mais preciso (menor MAE/RMSE, já que realmente aprendeu da distribuição dos dados), mais rápido (microssegundos vs. segundos por predição), determinístico (zero variância em chamadas repetidas), e essencialmente gratuito no tempo de inferência. Essas não são vantagens menores – para uma ferramenta de precificação em produção, consistência e velocidade são requisitos básicos.
Onde o LLM vence: No Experimento 4, o LLM processou corretamente descrições em linguagem natural em características estruturadas com alta precisão. Essa é uma tarefa que o Random Forest simplesmente não pode fazer – não requer dados de treinamento, apenas a capacidade de entender linguagem humana. Crucialmente, a força do LLM aqui é extração, não predição. É processamento, não estimativa.
O princípio mais amplo: Esta não é uma história sobre Random Forest ser “melhor” que LLMs. É sobre escolher a ferramenta certa para cada subtarefa em um pipeline. LLMs se destacam em entender entrada não estruturada e gerar saída estruturada. ML tradicional se destaca em aprender padrões de dados específicos do domínio e produzir predições numéricas confiáveis. O pipeline híbrido – LLM como analisador, modelo ML como preditor – aproveita ambas as forças sem expor nenhuma a tarefas para as quais são inadequadas.
Este padrão se generaliza além de preços de casas. Qualquer sistema onde usuários fornecem entrada em linguagem natural mas a tarefa principal é predição numérica em características estruturadas (pontuação de crédito, previsão de demanda, avaliação de risco médico, precificação de seguros) é candidato para a mesma arquitetura. Antes de usar um LLM por padrão para todo o pipeline, pergunte: a parte difícil é entender a entrada, ou fazer a predição? Frequentemente é a primeira, e um modelo ML focado lida melhor com a última.
Limitações e Ressalvas
Esses experimentos têm limitações conhecidas que valem a pena reconhecer. O conjunto de dados é sintético, então os números absolutos de precisão não refletem avaliação imobiliária do mundo real – eles demonstram a vantagem relativa de um modelo treinado sobre um não treinado. Preços de casas do mundo real dependem de muito mais variáveis (localização, condição, distrito escolar, timing do mercado, comodidades próximas), mas a abordagem escala: apenas adicione mais características e troque por dados reais de listagens. O LLM não teve acesso à distribuição dos dados de treinamento, que é a razão principal de seu baixo desempenho na predição; em um cenário onde um LLM é ajustado nos mesmos dados ou tem acesso de recuperação a vendas comparáveis, a diferença de precisão diminuiria. A comparação de latência também depende da rede – um LLM auto-hospedado seria mais rápido que uma chamada de API, embora ainda ordens de magnitude mais lento que uma inferência local do Random Forest. Finalmente, testamos um único LLM (Claude Opus 4.6); outros modelos podem se comportar diferentemente em tarefas de estimativa numérica.
O que Vem a Seguir
Um modelo treinado só é útil se permanecer atual. À medida que novos dados de propriedades chegam, o modelo deveria retreinar periodicamente para capturar mudanças no mercado. Em uma aplicação Rails, isso é direto: agende um ActiveJob que puxa dados CSV frescos, retreina o Random Forest, e escreve um novo house_model.dat, tudo em segundo plano sem interromper a aplicação web.
Além do retreinamento, há algumas extensões naturais que valem a pena explorar: adicionar localização como característica (usando codificação de bairro ou latitude/longitude), incorporar análise de importância de características para entender quais variáveis mais influenciam o preço, e envolver o pipeline híbrido LLM + Random Forest em um único endpoint de API para que usuários possam consultar em linguagem natural e receber predições estruturadas de volta.
Referências
- Documentação do Rumale
- IBM — Random Forest
- Rokach, L., Maimon, O. (2005). Decision Trees. In: Maimon, O., Rokach, L. (eds) Data Mining and Knowledge Discovery Handbook. Springer, Boston, MA. https://doi.org/10.1007/0-387-25465-X_9
We want to work with you. Check out our Services page!

