Skip to content
rodrigogducaPublic

About

Pergunte em linguagem natural sobre editais de bolsas e regulamentos. O EditalBot responde só com base nos documentos, cita a página da fonte e diz quando não sabe, em vez de inventar prazos e valores como um LLM sem contexto faz.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

📄 EditalBot — assistente RAG para editais e regulamentos acadêmicos

CI Python 3.11+ Licença MIT

Pergunte em linguagem natural sobre editais de bolsas e regulamentos. O EditalBot responde só com base nos documentos, cita a página da fonte e diz quando não sabe, em vez de inventar prazos e valores como um LLM sem contexto faz.

Projeto desenvolvido por Rodrigo Gandarela Soares de Farias Duca (Engenharia de Computação — Universidade SENAI CIMATEC), set/2026. Temáticas: LLMs, NLP e Engenharia de Dados. Especificação completa (Spec-Driven Development) em specs/.

📖 Documentação técnica detalhada, passo a passo: DOCUMENTACAO.md

Arquitetura

        INDEXAÇÃO                                            CONSULTA
PDF ─► extrair (pypdf) ─► limpar ─► chunks de 800 caracteres     pergunta
       (cabeçalhos, hifenização)    (nunca cruzam páginas)          │
                                   │                     ┌──────────┴──────────┐
                     embeddings E5 ("passage:")          E5 ("query:")      BM25
                                   │                     └─────► RRF ◄───────┘
                                   ▼                              │  top-5 trechos
                          ChromaDB (persistente) ───────────────►─┤
                                                                  ▼
                                      prompt: só os trechos, cite [doc, p. N], recuse se faltar
                                                                  │
                                                  LLM (Claude Haiku 4.5 | Ollama local)
                                                                  │
                                 validação das citações contra os trechos ─► resposta + fontes

Resultados

Conjunto-ouro escrito antes de testar o sistema: data/avaliacao/ouro.json, com 30 perguntas (20 factuais, 4 de raciocínio, 3 sobre outros documentos e 3 fora do escopo), sobre um corpus de 4 PDFs públicos (187 trechos).

Recuperação (sem LLM)

Configuração hit@1 hit@3 hit@5 MRR
Semântica (E5), chunk 400 0,30 0,56 0,67 0,45
Semântica (E5), chunk 800 0,41 0,59 0,74 0,54
Semântica (E5), chunk 1200 0,37 0,63 0,67 0,50
Híbrida (E5 + BM25, RRF), chunk 800 0,59 0,85 0,89 0,73

A busca híbrida supera a meta de hit@5 ≥ 0,85. A busca lexical (BM25) recupera o que os embeddings não pegam bem: números, datas e códigos como "2.600", "BDIA-IT02-2026.09" e "B.5".

Geração

Resultados E1 (LLM sem RAG) × E2 (RAG) em reports/avaliacao.md, gerados por python -m src.avaliar quando há um LLM configurado.

Como rodar

python -m venv .venv && .venv\Scripts\activate          # Linux/Mac: source .venv/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt
copy .env.example .env                                  # e escolha um LLM (abaixo)

Coloque os PDFs em data/pdfs/ (links oficiais em data/documentos.json), e depois:

python -m src.ingestao                     # indexa (reexecutar não duplica: deduplicação por SHA-256)
python -m src.avaliar --so-recuperacao     # métricas de busca, sem custo
python -m src.avaliar                      # + geração E1 × E2 (precisa de LLM)
streamlit run app/app.py                   # chat
pytest                                     # 11 testes

Escolha do LLM (.env):

  • Claude — ANTHROPIC_API_KEY=... e LLM_PROVIDER=claude. Modelo padrão: claude-haiku-4-5. A avaliação completa custa centavos de dólar.
  • Ollama (gratuito, local) — instale o Ollama, rode ollama pull qwen2.5:3b e use LLM_PROVIDER=ollama.
  • Sem LLM, o app funciona em modo de busca: mostra os trechos mais relevantes com a página.

Decisões técnicas

  • Chunks que não cruzam páginas. Cada trecho pertence a uma única página, então a citação [doc, p. N] é sempre exata.
  • Prefixos do E5. O multilingual-e5-small foi treinado com query: / passage:, e omitir esses prefixos degrada a busca.
  • Guardrail de citações (src/citacoes.py). Toda citação da resposta é conferida contra os trechos recuperados. Citação inexistente aparece como "⚠ fonte não verificada".
  • Recusa explícita. O prompt exige uma frase fixa quando a resposta não está nos trechos, e a avaliação mede a taxa de recusa correta nas perguntas fora do escopo.
  • Privacidade e observabilidade. logs/consultas.jsonl registra latências, tokens, trechos usados e se as citações eram válidas, mas não o texto da pergunta, a menos que LOG_PERGUNTAS=1.

Estrutura

src/ingestao.py     PDF → páginas limpas → fragmentos que nunca cruzam páginas
src/recuperacao.py  ChromaDB + embeddings E5, busca semântica, BM25 e fusão RRF
src/citacoes.py     extração e validação das citações [documento, p. N]
src/llm.py          provedores Claude e Ollama com interface comum
src/rag.py          prompt, geração, guardrail de citações e log de observabilidade
src/avaliar.py      conjunto-ouro: hit@k, MRR, E1 (sem RAG) × E2 (RAG)
app/app.py          chat Streamlit com upload de PDF e seletor de k/modo
tests/              11 testes (fragmentação, limpeza, citações) — sem PDF, sem LLM
specs/              visão, requisitos, dados, design, experimentos, tarefas, entrega
DOCUMENTACAO.md     guia técnico completo, passo a passo

Qualidade: 11 testes (pytest) e lint (ruff) rodam a cada push pelo CI, sem precisar de PDFs nem de chave de API.

Dados

PDFs públicos da Universidade SENAI CIMATEC: Edital 032/2026 (Bolsas IT em IA), Edital 002/2026 (PRH 27), Edital 001/2026 (Manufatura Aditiva) e Regulamento do Programa de Bolsas de Estudo. Os PDFs não são versionados, para não redistribuir versões desatualizadas. Os links estão em data/documentos.json.

Limitações

  • Não substitui o documento oficial: editais têm retificações, e a resposta vale para a versão indexada.
  • Tabelas extraídas do PDF perdem a estrutura (ex.: barema, valores por carga horária), o que dificulta algumas buscas.
  • Sem OCR: PDFs escaneados são recusados com aviso.
  • Com a API externa, a pergunta e os trechos saem da máquina. Para dados sensíveis, use o Ollama local.
  • Um PDF enviado pelo usuário pode conter prompt injection. O prompt trata os trechos como dados, mas isso não é uma garantia completa.

Licença

Código sob MIT. Os editais e regulamentos são documentos públicos de terceiros, apenas referenciados por link (data/documentos.json), nunca redistribuídos aqui.

About

Pergunte em linguagem natural sobre editais de bolsas e regulamentos. O EditalBot responde só com base nos documentos, cita a página da fonte e diz quando não sabe, em vez de inventar prazos e valores como um LLM sem contexto faz.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages