Chatbot que responde perguntas sobre documentos PDF usando RAG (Retrieval-Augmented Generation). O sistema busca os trechos mais relevantes nos documentos e usa um LLM para gerar a resposta com base nesse contexto, citando a fonte (arquivo e página) de onde a informação foi extraída.
O pipeline funciona em duas fases:
Indexação (executada uma vez, ou sempre que os documentos mudam)
PDFs → carregamento → chunking com overlap → embeddings → índice FAISS salvo em disco
Consulta (executada a cada pergunta)
Pergunta → embedding da pergunta → busca por similaridade no FAISS
→ top-k chunks mais relevantes → prompt com contexto → LLM → resposta + fontes
| Componente | Tecnologia | Motivo |
|---|---|---|
| API | FastAPI | validação automática, documentação interativa, async nativo |
| Orquestração | LangChain (LCEL) | composição declarativa do pipeline RAG |
| LLM | Groq (Llama 3.3 70B) | gratuito, alta velocidade de inferência |
| Embeddings | HuggingFace all-MiniLM-L6-v2 |
roda localmente, sem custo, sem enviar dados para fora |
| Vector Store | FAISS | busca por similaridade local, sem infraestrutura externa |
| Validação | Pydantic / pydantic-settings | schemas tipados e configuração via .env |
| Containerização | Docker / Docker Compose | ambiente reproduzível |
rag-chatbot/
├── app/
│ ├── __init__.py
│ ├── config.py # configurações centralizadas (lidas do .env)
│ ├── ingest.py # pipeline de indexação: PDF → chunks → embeddings → FAISS
│ ├── retriever.py # carrega o índice FAISS e expõe a busca por similaridade
│ ├── chain.py # monta o pipeline RAG: prompt + LLM + formatação de contexto
│ ├── schemas.py # modelos Pydantic de request/response da API
│ └── main.py # endpoints FastAPI: /chat, /ingest, /health
├── tests/
│ ├── conftest.py
│ └── test_rag.py # testes unitários, de integração e de API
├── data/ # PDFs a serem indexados (não versionados)
├── vectorstore/ # índice FAISS gerado (não versionado)
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── .env.example
- Python 3.11+
- Conta gratuita no Groq Console para obter uma API key
git clone https://github.com/Arthurss123/rag-chatbot.git
cd rag-chatbot
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install -r requirements.txtcp .env.example .envEdite o .env e preencha sua chave do Groq:
GROQ_API_KEY=chave_aqui
LLM_MODEL=llama-3.3-70b-versatileColoque os arquivos PDF que deseja indexar dentro da pasta data/.
python -m app.ingestEsse comando carrega os PDFs, divide o texto em chunks, gera os embeddings e salva o índice FAISS em vectorstore/. Na primeira execução, o modelo de embedding (~90MB) é baixado e fica em cache local.
uvicorn app.main:app --reloadA API fica disponível em http://localhost:8000, com documentação interativa (Swagger) em http://localhost:8000/docs.
docker-compose up --buildAs pastas data/ e vectorstore/ são montadas como volumes, então é possível adicionar PDFs e reindexar sem reconstruir a imagem.
Verifica se a API está no ar e se o índice FAISS está carregado.
Reprocessa todos os PDFs da pasta data/ e reconstrói o índice FAISS. Use sempre que adicionar, remover ou atualizar documentos.
Recebe uma pergunta e retorna uma resposta baseada nos documentos indexados, com a lista de fontes (arquivo e página) usadas para gerar a resposta.
Request:
{
"question": "Quais são as boas práticas em RAG?",
"history": []
}Response:
{
"answer": "As boas práticas em RAG incluem usar chunk overlap para preservar contexto, limitar o top-k a 3-5 chunks, citar sempre a fonte dos trechos recuperados, separar o prompt template do código e monitorar a qualidade com métricas como faithfulness e relevancy.",
"sources": [
{ "file": "manual.pdf", "page": 6 }
],
"model": "llama-3.3-70b-versatile"
}O campo history aceita uma lista de mensagens anteriores (role: user ou assistant, content: texto), permitindo perguntas de follow-up que dependem do contexto da conversa. A API é stateless: o histórico é enviado pelo cliente a cada requisição, o servidor não mantém estado entre chamadas.
Chunking com overlap. Os documentos são divididos em chunks de ~500 caracteres com 150 caracteres de sobreposição entre chunks consecutivos. O overlap evita que uma informação fique cortada exatamente na borda entre dois chunks, perdendo contexto.
Top-k limitado a 4 chunks. Passar muitos chunks para o LLM não melhora a resposta — degrada. Contextos muito longos fazem o modelo perder atenção em informações no meio do prompt. Entre 3 e 5 chunks é o equilíbrio entre contexto suficiente e foco.
Prompt template com fallback explícito. O prompt instrui o modelo a responder apenas com base no contexto fornecido e a admitir explicitamente quando a informação não está disponível, em vez de inventar uma resposta. Isso reduz significativamente a taxa de alucinação.
Citação de fontes. Toda resposta inclui o arquivo e a página de onde a informação foi extraída, permitindo verificação e auditoria.
Modelo de embedding local. A vetorização roda na CPU via HuggingFace, sem custo por requisição e sem enviar o conteúdo dos documentos para serviços externos.
Temperatura zero no LLM. Para tarefas de Q&A sobre documentos, respostas determinísticas e factuais são preferíveis a respostas criativas.
Singletons para modelo de embedding e índice FAISS. Carregados uma única vez na inicialização da API e reutilizados em todas as requisições, evitando recarregar ~90MB a cada chamada.
O projeto inclui testes unitários, de integração e de API:
pytest tests/ -v- Unitários: funções de formatação de contexto, histórico e extração de fontes, testadas isoladamente.
- Integração: o pipeline RAG completo (
ask()), com o LLM e o índice FAISS mockados. - API: endpoints testados via
TestClientdo FastAPI, incluindo validação de schemas e tratamento de erros.
- Substituir FAISS por um vector store com servidor dedicado (Qdrant, Weaviate) para cenários de maior escala.
- Adicionar uma etapa de reranking após o retrieval para refinar a seleção dos chunks.
- Implementar streaming de resposta via
StreamingResponse. - Avaliação automática da qualidade das respostas com métricas de faithfulness e relevancy (RAGAS).