YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
🔬 POC: Web Scraping melhora Small Language Models no MMLU?
Pergunta de pesquisa: O quanto web scraping em tempo real pode melhorar a acurácia de um SLM (Small Language Model) rodando localmente em uma GPU?
Benchmark: CAIS/MMLU — Massive Multitask Language Understanding (~14K perguntas de múltipla escolha em 57 matérias)
📋 Resumo
Esta POC compara 3 modos de resposta do SLM:
| Modo | Descrição |
|---|---|
| Baseline | SLM responde apenas com seu conhecimento interno |
| RAG | SLM recebe contexto de páginas web scrapeadas em tempo real |
| Rewrite + RAG | SLM reescreve a pergunta como query de busca otimizada → busca → scraping → responde |
🏗️ Arquitetura
Pergunta MMLU + Opções A/B/C/D
│
├──────────────────────────── [Baseline] ──→ SLM → Resposta
│
├── [RAG] ──→ Query direta ──→ Web Search ──→ Scraping ──→ Chunk + Rerank
│ │
│ Decontaminação (13-gram)
│ │
│ Top-3 passages ──→ SLM → Resposta
│
└── [Rewrite+RAG] ──→ SLM reescreve query ──→ Web Search ──→ Scraping ──→ ...
│
"abstract algebra factor group"
(em vez da pergunta completa)
Pipeline detalhado do RAG:
- Web Search — busca no DuckDuckGo (grátis) ou Google via SerpApi
- Scraping paralelo — extrai texto limpo das top-5 URLs (BeautifulSoup + lxml)
- Chunking — divide textos em segmentos de ~256 palavras com overlap
- Reranking — seleciona os 3 chunks mais relevantes via similaridade semântica (sentence-transformers)
- Decontaminação — remove chunks que contenham a pergunta do benchmark (13-gram Jaccard overlap, ref)
- Geração — SLM responde com os chunks como contexto
📚 Fundamentação Científica
| Paper | Resultado | Relevância |
|---|---|---|
| Frustratingly Simple Retrieval (2507.01297) | +10% MMLU STEM, +33% MMLU Pro com LLaMA 3.1 8B + retrieval | Pipeline principal, decontaminação |
| FreshLLMs (2310.03214) | +47% absoluto no FreshQA com Google Search + few-shot CoT | Formato de evidências no prompt |
| Query Rewriting for RAG (2305.14283) | Vicuna-13B: 34.9→41.5 MMLU STEM com query rewriting | Reescrita de query |
🖥️ Requisitos
Hardware
- GPU: NVIDIA com ≥6GB VRAM (4-bit quantizado) ou ≥12GB (float16)
- RAM: ≥16GB
- Disco: ~10GB (para o modelo)
- Internet: necessário para web scraping
Software
- Python 3.10+
- CUDA 11.8+ (ou 12.x)
- Driver NVIDIA compatível
🚀 Instalação
# 1. Clonar repositório
git clone https://huggingface.co/gustavo-fluz/web-scraping-slm-mmlu-poc
cd web-scraping-slm-mmlu-poc
# 2. Criar ambiente virtual
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# 3. Instalar dependências
pip install -r requirements.txt
📖 Como usar
Rodada rápida (recomendado para primeira execução)
# ~30-45 minutos em GPU, 300 perguntas amostradas estratificadamente
python main.py
Rodada completa
# ~4-6 horas, todas as ~14K perguntas
python main.py --num-samples 0
Apenas baseline (testar se o setup funciona)
# ~5 minutos, sem web scraping
python main.py --baseline-only --num-samples 50
Modelo diferente
# Llama 3.2 3B
python main.py --model "meta-llama/Llama-3.2-3B-Instruct"
# Qwen 2.5 3B
python main.py --model "Qwen/Qwen2.5-3B-Instruct"
# Phi-3 Mini
python main.py --model "microsoft/Phi-3-mini-4k-instruct"
Matérias específicas
# Apenas STEM
python main.py --subjects "abstract_algebra,anatomy,astronomy,college_biology,college_chemistry,college_computer_science,college_mathematics,college_physics"
Com Google Search (melhor qualidade de busca)
# SerpApi (precisa de API key — $50/mês, 5000 buscas)
python main.py --engine serpapi --serpapi-key "YOUR_KEY"
5-shot (como no paper original do MMLU)
python main.py --few-shot 5
⚙️ Todos os parâmetros
python main.py --help
| Parâmetro | Default | Descrição |
|---|---|---|
--model |
microsoft/Phi-4-mini-instruct |
ID do modelo no HuggingFace |
--no-4bit |
False |
Desabilitar quantização 4-bit |
--dtype |
bfloat16 |
Tipo de ponto flutuante |
--engine |
duckduckgo |
Motor de busca (duckduckgo ou serpapi) |
--serpapi-key |
None |
API key para SerpApi |
--max-search-results |
5 |
URLs por busca |
--num-samples |
300 |
Perguntas para avaliar (0 = todas) |
--subjects |
None |
Matérias específicas (vírgula-separadas) |
--few-shot |
0 |
Exemplos few-shot |
--seed |
42 |
Seed para reprodutibilidade |
--baseline-only |
False |
Apenas baseline |
--no-rewrite |
False |
Sem query rewriting |
--output-dir |
results |
Diretório de saída |
--no-plots |
False |
Não gerar gráficos |
📊 Output
Após a execução, a pasta results/ conterá:
results/
├── report.json # Relatório completo com métricas
├── predictions_baseline.json # Cada predição do baseline
├── predictions_rag.json # Cada predição do RAG
├── predictions_rewrite_rag.json # Cada predição do Rewrite+RAG
├── accuracy_comparison.png # Gráfico: barras comparando os 3 modos
├── accuracy_by_subject.png # Gráfico: accuracy por matéria
└── run.log # Log completo da execução
Exemplo de report.json
{
"metadata": {
"model_id": "microsoft/Phi-4-mini-instruct",
"num_samples": 300,
"search_engine": "duckduckgo",
"timestamp": "2025-04-26 10:30:00"
},
"modes": {
"baseline": {
"accuracy": 0.65,
"correct": 195,
"total": 300,
"by_subject": { "abstract_algebra": { "accuracy": 0.5, "correct": 3, "total": 6 } }
},
"rag": {
"accuracy": 0.72,
"correct": 216,
"total": 300
},
"rewrite_rag": {
"accuracy": 0.74,
"correct": 222,
"total": 300
}
},
"comparison": {
"baseline_vs_rag": {
"baseline_accuracy": 0.65,
"rag_accuracy": 0.72,
"absolute_improvement": 0.07,
"relative_improvement": 0.107
}
}
}
🔧 Estrutura do código
| Arquivo | Responsabilidade |
|---|---|
main.py |
Entry point, CLI, orquestração |
config.py |
Todas as configurações (dataclasses) |
web_scraper.py |
Web search (DDG/SerpApi) + scraping paralelo |
rag_pipeline.py |
Chunking, reranking semântico, decontaminação |
slm.py |
Carregamento do modelo, prompts, extração de resposta |
evaluator.py |
Dataset MMLU, loop de avaliação, métricas, gráficos |
⚠️ Notas importantes
Decontaminação: O pipeline remove automaticamente chunks que contenham texto muito similar à pergunta do MMLU. Sem isso, os scores podem inflar em até 3.6% (ref).
Rate limiting: O DuckDuckGo é gratuito mas tem rate limiting. Se estiver rodando com muitas perguntas, pode haver pausas. Para avaliações em larga escala, use o SerpApi.
Reprodutibilidade: As buscas web retornam resultados diferentes ao longo do tempo. Os resultados exatos podem variar entre execuções. Os arquivos
predictions_*.jsonsalvam tudo para análise posterior.Domínios bloqueados: Por padrão, resultados de
huggingface.co,github.com,chegg.comecoursehero.comsão filtrados para evitar contaminação.VRAM: Com quantização 4-bit, o Phi-4-mini usa ~3-4GB de VRAM. O reranker (sentence-transformers) usa ~200MB adicionais.
📄 Licença
Este código é fornecido como POC para fins de pesquisa.
📚 Referências
- Hendrycks et al. "Measuring Massive Multitask Language Understanding" (2021) — MMLU
- Shi et al. "Frustratingly Simple Retrieval Improves Reasoning Benchmarks" (2025) — arxiv 2507.01297
- Vu et al. "FreshLLMs: Refreshing LLMs with Search Engine Augmentation" (2023) — arxiv 2310.03214
- Ma et al. "Query Rewriting for Retrieval-Augmented LLMs" (2023) — arxiv 2305.14283