Guia de Implementação do Pipeline RAG
em Python
Este documento serve como um guia detalhado para entender e fazer funcionar o
código Python fornecido para um pipeline de Geração Aumentada por Recuperação
(RAG). Ele aborda cada módulo, sua funcionalidade, e como integrá-los para construir
um sistema RAG completo.
Estrutura do Projeto
O projeto é composto pelos seguintes arquivos Python:
API_key.py : (Esperado) Arquivo para armazenar chaves de API.
install_pen.py : Script de configuração inicial do ambiente.
pdf_processor.py : Módulo para extração e pré-processamento de conteúdo de
PDFs.
intelligent_chunker.py : Módulo para dividir o texto em chunks inteligentes.
vector_manager.py : Módulo para gerenciar a criação e armazenamento de
embeddings vetoriais.
retrieval_system.py : Módulo para realizar a busca de similaridade e
recuperação de informações.
response_generator.py : Módulo para gerar respostas usando um Large
Language Model (LLM).
[Link] : O script principal que orquestra todo o pipeline.
Fase 1: Análise e Explicação do Arquivo install_pen.py e
Configuração Inicial
O arquivo install_pen.py é responsável por configurar o ambiente necessário para o
projeto. Ele verifica e instala as dependências Python, cria diretórios essenciais e
verifica a presença de arquivos de configuração importantes.
Propósito:
Este script automatiza a preparação do seu ambiente de desenvolvimento, garantindo
que todas as bibliotecas necessárias estejam instaladas e que a estrutura de diretórios
esteja correta. Ele é o ponto de partida para que os outros scripts funcionem sem
problemas.
Como funciona:
1. verificar_dependencias() : Esta função verifica se as bibliotecas Python
listadas (dotenv, openai, fitz, pandas, numpy, sentence_transformers, faiss) já
estão instaladas no seu ambiente. Se alguma estiver faltando, ela retorna uma
lista dos pacotes que precisam ser instalados.
2. instalar_dependencias() : Se houver dependências faltando, esta função tenta
instalá-las usando pip . Ela itera sobre a lista de pacotes faltantes e executa o
comando pip install para cada um.
3. criar_ambiente() : Esta é a função principal que orquestra a configuração:
Cria os diretórios Data e data (o diretório data é especificamente
mencionado para ser usado pelo VectorManager ).
Chama instalar_dependencias() para garantir que todas as bibliotecas
estejam prontas.
Verifica a existência de arquivos essenciais como [Link] (onde sua chave
da API da OpenAI deve ser configurada) e [Link] (que
provavelmente contém o prompt para análise de editais). Se [Link] não
existir, ele cria um arquivo com um template para você preencher.
O que você precisa fazer:
Como você não quer que eu instale nada, você precisará garantir que as dependências
listadas no script ( python-dotenv , openai , PyMuPDF , pandas , numpy , sentence-
transformers , faiss-cpu ) estejam instaladas no seu ambiente Python. Você pode
fazer isso manualmente executando pip install <nome_do_pacote> para cada uma
delas no seu terminal.
Além disso, você precisará criar o arquivo [Link] na mesma pasta dos seus scripts e
adicionar sua chave da OpenAI nele, no formato:
OPENAI_API_KEY=sua_chave_da_openai_aqui
E também criar o arquivo [Link] com o conteúdo do prompt que você
deseja usar para a análise de editais.
Uma vez que essas configurações manuais estejam feitas, o script install_pen.py
serviria apenas para verificar se tudo está no lugar, mas você não precisaria executá-lo
para a instalação em si. Ele é um bom ponto de verificação para garantir que seu
ambiente está pronto antes de rodar o [Link] .
Fase 2: Análise e Explicação do Arquivo pdf_processor.py e
Processamento de PDFs
O arquivo pdf_processor.py contém a classe PDFProcessor , que é a primeira etapa
do seu pipeline RAG, focada na extração e pré-processamento de conteúdo de
arquivos PDF. Este módulo é crucial para transformar documentos PDF brutos em
texto limpo e estruturado, pronto para as próximas fases de chunking e vetorização.
Propósito:
Conforme detalhado na seção "Etapa 1: Parsing do PDF (Texto + Imagens)" do seu guia
em PDF, o PDFProcessor tem como objetivo principal:
Carregar arquivos PDF.
Extrair o texto bruto de todas as páginas.
Limpar o texto, removendo caracteres indesejados e normalizando espaços.
Extrair tabelas (embora de forma básica nesta implementação).
Preparar um placeholder para a descrição de imagens, reconhecendo a
importância de elementos visuais em PDFs complexos.
Como funciona:
A classe PDFProcessor é orientada a objetos e possui os seguintes métodos:
1. __init__(self) : O construtor inicializa a instância da classe, definindo
[Link] como None .
2. load_pdf(self, pdf_path: str) :
Função: Carrega um arquivo PDF usando a biblioteca fitz (PyMuPDF).
Importância: É o ponto de entrada para o processamento de qualquer PDF.
Ele abre o documento e o torna acessível para as outras funções de
extração.
Exemplo de uso:
processor.load_pdf("caminho/para/seu/[Link]")
3. extract_raw_text(self) -> str :
Função: Itera sobre todas as páginas do PDF carregado e concatena o texto
bruto de cada uma.
Importância: Fornece a base textual para o processamento subsequente.
No entanto, o texto bruto pode conter ruídos, quebras de linha indesejadas
e caracteres especiais, o que leva à próxima etapa.
4. clean_text(self, text: str) -> str :
Função: Recebe uma string de texto e aplica expressões regulares para:
Remover caracteres não-ASCII e símbolos indesejados (mantendo
caracteres acentuados comuns em português).
Substituir múltiplos espaços, quebras de linha e tabulações por um
único espaço, e remover espaços no início/fim da string.
Importância: Essencial para normalizar o texto e remover ruídos que
poderiam prejudicar o chunking e a vetorização. Um texto limpo melhora a
qualidade dos embeddings e a precisão da recuperação.
5. extract_tables(self) -> list[[Link]] :
Função: Tenta extrair tabelas de cada página do PDF usando a
funcionalidade find_tables() do PyMuPDF e as converte em DataFrames
do Pandas.
Importância: Reconhece que tabelas contêm informações estruturadas
valiosas. O guia em PDF menciona que "tabelas contêm informações
estruturadas valiosas". No entanto, o próprio código comenta que "Esta é
uma implementação básica e pode precisar de refinamento para tabelas
complexas", sugerindo a integração com bibliotecas mais robustas como
camelot ou tabula-py para cenários mais desafiadores.
6. describe_images(self) -> list[str] :
Função: Atualmente, é um método placeholder. Ele apenas retorna strings
indicando a presença de imagens ( [IMAGEM_PAGINA_X_INDICE_Y] ).
Importância: Este método destaca um ponto crucial abordado no seu guia
em PDF na seção "Impacto da Formatação do PDF (Imagens e Símbolos)".
Para um RAG multimodal completo, este método precisaria ser expandido
para integrar modelos de visão computacional (como Azure OpenAI Vision,
conforme mencionado no PDF) para gerar descrições textuais reais das
imagens. Essas descrições seriam então incorporadas ao texto para
vetorização, garantindo que o contexto visual não seja perdido.
7. preprocess_pdf(self, pdf_path: str) -> dict :
Função: Orquestra todo o processo de pré-processamento. Ele carrega o
PDF, extrai o texto bruto, limpa-o, extrai tabelas e chama a função de
descrição de imagens. Em seguida, ele combina o texto limpo, as tabelas
(convertidas para string) e as descrições de imagens em uma única string
full_processed_text .
Importância: Este é o método principal que você chamará para obter o
conteúdo processado do seu PDF. Ele encapsula toda a lógica de extração e
preparação, entregando um dicionário com o texto combinado, os
DataFrames das tabelas e as descrições das imagens.
Como usar este módulo no seu projeto:
Você instanciará a classe PDFProcessor e chamará o método preprocess_pdf()
passando o caminho do seu arquivo PDF. O resultado será um dicionário contendo o
texto processado, que será a entrada para a próxima fase do pipeline RAG (o
chunking).
from pdf_processor import PDFProcessor
# Instanciar o processador
processor = PDFProcessor()
# Caminho para o seu arquivo PDF
pdf_file = "./Data/seu_documento.pdf" # Certifique-se de que o PDF esteja na
pasta Data
# Processar o PDF
processed_data = processor.preprocess_pdf(pdf_file)
# O texto processado estará em processed_data["text"]
print(processed_data["text"][:500]) # Imprime os primeiros 500 caracteres do
texto processado
Fase 3: Análise e Explicação do Arquivo intelligent_chunker.py e
Chunking Inteligente
O arquivo intelligent_chunker.py contém a classe IntelligentChunker , que é
responsável por dividir o texto pré-processado (gerado pelo PDFProcessor ) em
segmentos menores e semanticamente coerentes, os chamados "chunks". Esta etapa é
fundamental para o RAG, pois chunks bem definidos garantem que a recuperação de
informações seja precisa e que o LLM receba contexto relevante e conciso.
Propósito:
Conforme abordado na seção "Explicação Técnica: Tokenização, Segmentação de
Texto e Preservação de Contexto" do seu guia em PDF, o IntelligentChunker tem
como objetivo:
Dividir textos longos em pedaços menores ( chunks ).
Priorizar a preservação do contexto semântico, tentando dividir o texto por
parágrafos e sentenças.
Gerenciar a sobreposição entre os chunks para evitar a perda de contexto nas
fronteiras.
Como funciona:
A classe IntelligentChunker é composta pelos seguintes métodos:
1. __init__(self, max_chunk_size: int = 500, overlap: int = 50) :
Função: Inicializa o chunker com um tamanho máximo de chunk (em
caracteres) e uma quantidade de sobreposição. Os valores padrão são 500
caracteres para o tamanho máximo e 50 caracteres para a sobreposição.
Importância: Permite configurar a granularidade dos chunks. O
max_chunk_size é crucial para garantir que os chunks se encaixem na
janela de contexto do LLM e que os embeddings sejam eficazes. A overlap
ajuda a manter a continuidade do contexto entre chunks adjacentes, o que
é vital para a recuperação de informações.
2. chunk_text(self, text: str) -> List[str] :
Função: Este é o método principal que realiza o chunking. Ele tenta dividir o
texto de forma "inteligente" da seguinte maneira:
Primeiro, divide o texto em parágrafos ( \n\n ).
Para cada parágrafo, verifica se ele excede o max_chunk_size .
Se um parágrafo for muito longo, ele tenta dividi-lo em sentenças
( [Link](r'(?<=[.!?])\s+', paragraph) ). Isso é uma forma de
preservar o contexto, pois sentenças geralmente representam ideias
completas.
Ele constrói os chunks adicionando parágrafos ou sentenças até que o
max_chunk_size seja atingido, garantindo que a sobreposição seja
aplicada quando um novo chunk é iniciado.
Importância: Implementa a lógica de chunking que busca equilibrar o
tamanho do chunk com a preservação do contexto. A estratégia de dividir
por parágrafos e sentenças é uma boa prática para manter a coerência
semântica, conforme discutido no PDF.
3. _get_overlap_text(self, chunk: str) -> str :
Função: Um método auxiliar (privado, indicado pelo _ ) que retorna a parte
final de um chunk para ser usada como sobreposição no próximo chunk.
Ele pega os últimos [Link] caracteres do chunk.
Importância: Garante que haja uma sobreposição entre os chunks, o que é
fundamental para que o modelo de recuperação possa encontrar
informações relevantes mesmo que a resposta esteja dividida entre dois
chunks.
Considerações sobre a implementação:
Tamanho do Chunk em Caracteres: O max_chunk_size e overlap são
definidos em caracteres. Em muitos sistemas RAG, o tamanho do chunk é medido
em tokens, que é uma unidade mais precisa para modelos de linguagem. No
entanto, para uma implementação inicial, o chunking por caracteres é mais
simples e pode ser eficaz. Se a precisão se tornar um problema, você pode
considerar a integração de um tokenizador (como o tiktoken da OpenAI ou o
tokenizador do sentence-transformers ) para medir o tamanho dos chunks em
tokens.
Divisão por Sentenças: A regex (?<=[.!?])\s+ é uma forma simples de dividir
por sentenças. Para uma robustez maior, especialmente com textos complexos
ou em diferentes idiomas, bibliotecas de segmentação de sentenças mais
avançadas (como as do NLTK ou SpaCy) poderiam ser consideradas.
Marcadores de Tabela/Imagem: O exemplo de uso no script mostra que ele lida
com os marcadores de tabela e imagem gerados pelo PDFProcessor . Isso é
importante para que essas informações sejam incluídas nos chunks e,
posteriormente, vetorizadas.
Como usar este módulo no seu projeto (integrando com PDFProcessor ):
Agora, vamos ver como você pode usar o IntelligentChunker após ter processado
seu PDF com o PDFProcessor . Você precisará criar um script (ou adicionar ao seu
[Link] quando chegarmos lá) que orquestre essas duas etapas.
Crie um novo arquivo, por exemplo, pipeline_example.py , e adicione o seguinte
código:
# pipeline_example.py
from pdf_processor import PDFProcessor
from intelligent_chunker import IntelligentChunker
import os
# 1. Configuração (certifique-se de que seu PDF de teste esteja na pasta
'Data')
pdf_file_path = [Link]("Data", "EDITAL(1).pdf") # Substitua pelo nome do
seu PDF
# 2. Processamento do PDF
print("\n--- Processando o PDF ---")
pdf_processor = PDFProcessor()
processed_data = pdf_processor.preprocess_pdf(pdf_file_path)
if not processed_data["text"]:
print("Erro: Não foi possível extrair texto do PDF. Verifique o caminho do
arquivo ou o conteúdo do PDF.")
else:
print(f"Texto extraído e limpo (primeiros 500
caracteres):\n{processed_data['text'][:500]}...")
# 3. Chunking Inteligente
print("\n--- Realizando o Chunking Inteligente ---")
# Você pode ajustar max_chunk_size e overlap conforme a necessidade do seu
projeto
chunker = IntelligentChunker(max_chunk_size=500, overlap=50)
chunks = chunker.chunk_text(processed_data["text"])
print(f"Total de chunks gerados: {len(chunks)}")
for i, chunk in enumerate(chunks[:5]): # Imprime os 5 primeiros chunks para
visualização
print(f"\n--- Chunk {i+1} (Tamanho: {len(chunk)} caracteres) ---")
print(chunk)
# Agora 'chunks' é uma lista de strings, onde cada string é um chunk do seu
PDF.
# Esta lista será a entrada para a próxima fase: a vetorização.
Para fazer este código funcionar:
1. Certifique-se de que os arquivos pdf_processor.py e intelligent_chunker.py
(e o pipeline_example.py que você acabou de criar) estejam no mesmo
diretório.
2. Crie uma pasta chamada Data no mesmo diretório e coloque um arquivo PDF de
teste (por exemplo, EDITAL(1).pdf ) dentro dela.
3. Abra seu terminal, navegue até o diretório onde esses arquivos estão e execute:
bash python3 pipeline_example.py
Você deverá ver a saída do processamento do PDF e, em seguida, a lista dos chunks
gerados. Esta é a base para a próxima etapa, onde esses chunks serão transformados
em vetores.
Fase 4: Análise e Explicação do Arquivo vector_manager.py e
Gerenciamento de Vetores
O arquivo vector_manager.py contém a classe VectorManager , que é a espinha
dorsal da funcionalidade de vetorização e gerenciamento de banco de dados vetorial
no seu pipeline RAG. Ele é responsável por transformar os chunks de texto (gerados
pelo IntelligentChunker ) em representações numéricas (embeddings) e armazená-
los de forma eficiente para buscas futuras.
Propósito:
Conforme detalhado na seção "Modelos de Embeddings Semânticos" e "Etapa 2:
Ingestão de Dados (Chunking e Vetorização)" do seu guia em PDF, o VectorManager
tem como objetivo principal:
Carregar um modelo de embedding semântico (Sentence-Transformer).
Converter textos (chunks) em vetores numéricos (embeddings).
Inicializar e gerenciar um índice FAISS (Facebook AI Similarity Search) para
armazenamento e busca eficiente de embeddings.
Salvar e carregar o índice FAISS e os textos associados para persistência.
Realizar buscas de similaridade para encontrar os chunks mais relevantes para
uma dada consulta.
Como funciona:
A classe VectorManager é orientada a objetos e possui os seguintes métodos:
1. __init__(self, model_name: str = 'sentence-transformers/paraphrase-
multilingual-MiniLM-L12-v2', vector_db_path: str =
'data/faiss_index.bin') :
Função: Inicializa o gerenciador. Define o nome do modelo Sentence-
Transformer a ser usado (padrão é um modelo multilíngue eficiente) e o
caminho onde o índice FAISS e os textos serão salvos
( data/faiss_index.bin ). Ele também chama load_model() para carregar
o modelo de embedding.
Importância: Permite configurar qual modelo de embedding será utilizado
e onde os dados vetorizados serão persistidos. A escolha do modelo é
crucial para a qualidade dos embeddings e, consequentemente, para a
precisão da recuperação.
2. load_model(self) :
Função: Carrega o modelo Sentence-Transformer especificado em
self.model_name usando a biblioteca sentence_transformers . Este
modelo será usado para gerar os embeddings.
Importância: É a ponte entre o texto e o espaço vetorial. Sem um modelo
carregado, a vetorização não pode ocorrer.
3. vectorize_texts(self, texts: List[str]) -> [Link] :
Função: Recebe uma lista de strings (seus chunks) e as converte em um
array NumPy de embeddings usando o modelo carregado. Cada linha do
array representa o vetor de um chunk.
Importância: Realiza a transformação fundamental de texto para vetor,
capturando o significado semântico dos chunks. Esta é a essência da
"vetorização" mencionada no guia em PDF.
4. initialize_faiss_index(self, dimension: int) :
Função: Cria uma instância de um índice FAISS. O tipo IndexFlatL2 é
usado aqui, que realiza uma busca exata por vizinhos mais próximos
usando distância euclidiana. A dimension deve corresponder à dimensão
dos embeddings gerados pelo seu modelo (por exemplo, paraphrase-
multilingual-MiniLM-L12-v2 gera embeddings de 384 dimensões).
Importância: Prepara a estrutura de dados otimizada para armazenar e
buscar os embeddings eficientemente. O FAISS é uma biblioteca de alto
desempenho para busca de similaridade em grandes conjuntos de dados
vetoriais.
5. add_embeddings(self, embeddings: [Link], texts: List[str]) :
Função: Adiciona os embeddings gerados ao índice FAISS e armazena os
textos originais correspondentes em uma lista ( [Link] ). É vital manter
a associação entre o vetor e o texto que ele representa.
Importância: Popula o banco de dados vetorial com os dados do seu
conhecimento base (os chunks do PDF).
6. save_faiss_index(self) :
Função: Salva o índice FAISS em um arquivo binário ( .bin ) e os textos
associados em um arquivo de texto separado ( .txt ). Isso permite que você
persista o banco de dados vetorial e não precise vetorizar os documentos
novamente a cada execução.
Importância: Garante a persistência dos dados vetorizados, economizando
tempo e recursos computacionais em execuções futuras. O diretório data é
criado se não existir, conforme previsto no install_pen.py .
7. load_faiss_index(self) :
Função: Carrega o índice FAISS e os textos associados do disco. Ele verifica
se os arquivos existem e tenta carregá-los.
Importância: Permite reutilizar um banco de dados vetorial já construído,
acelerando o processo de inicialização do sistema RAG.
8. search_similar_texts(self, query_text: str, k: int = 5) ->
List[Tuple[str, float]] :
Função: Recebe um texto de consulta, o vetoriza usando o mesmo modelo,
e então realiza uma busca no índice FAISS para encontrar os k chunks mais
similares. Retorna uma lista de tuplas contendo o texto do chunk e sua
distância (similaridade) em relação à consulta.
Importância: Esta é a função central para a etapa de "Recuperação
(Retrieval)" do pipeline RAG. Ela permite que o sistema encontre as
informações mais relevantes no seu conhecimento base para responder à
pergunta do usuário.
Como usar este módulo no seu projeto (integrando com PDFProcessor e
IntelligentChunker ):
Vamos estender o pipeline_example.py para incluir a vetorização e o gerenciamento
do índice FAISS. Certifique-se de que as bibliotecas sentence-transformers e faiss-
cpu estejam instaladas no seu ambiente Python.
# pipeline_example.py (continuação)
from pdf_processor import PDFProcessor
from intelligent_chunker import IntelligentChunker
from vector_manager import VectorManager
import os
# 1. Configuração
pdf_file_path = [Link]("Data", "EDITAL(1).pdf") # Substitua pelo nome do
seu PDF
vector_db_dir = "data" # Diretório para salvar o índice FAISS
# Certifique-se de que o diretório 'data' existe
[Link](vector_db_dir, exist_ok=True)
# 2. Processamento do PDF
print("\n--- Processando o PDF ---")
pdf_processor = PDFProcessor()
processed_data = pdf_processor.preprocess_pdf(pdf_file_path)
if not processed_data["text"]:
print("Erro: Não foi possível extrair texto do PDF. Verifique o caminho do
arquivo ou o conteúdo do PDF.")
else:
print(f"Texto extraído e limpo (primeiros 500
caracteres):\n{processed_data["text"][:500]}...")
# 3. Chunking Inteligente
print("\n--- Realizando o Chunking Inteligente ---")
chunker = IntelligentChunker(max_chunk_size=500, overlap=50)
chunks = chunker.chunk_text(processed_data["text"])
print(f"Total de chunks gerados: {len(chunks)}")
# 4. Gerenciamento de Vetores (Vetorização e FAISS)
print("\n--- Gerenciando Vetores ---")
# O caminho do banco de dados vetorial é configurado no VectorManager
vector_manager = VectorManager(vector_db_path=[Link](vector_db_dir,
'faiss_index.bin'))
# Verificar se o índice já existe e carregá-lo, ou criá-lo
if vector_manager.load_faiss_index():
print("Índice FAISS carregado com sucesso.")
else:
print("Índice FAISS não encontrado ou erro ao carregar. Criando novo
índice...")
# Vetorizar os chunks
embeddings = vector_manager.vectorize_texts(chunks)
if [Link] > 0:
# A dimensão do índice FAISS deve ser a dimensão dos embeddings
embedding_dimension = [Link][1]
vector_manager.initialize_faiss_index(embedding_dimension)
vector_manager.add_embeddings(embeddings, chunks)
vector_manager.save_faiss_index()
else:
print("Não foi possível gerar embeddings. Verifique o modelo ou os
chunks.")
# Exemplo de busca (após o índice ser carregado ou criado)
if vector_manager.index:
query = "Quais são os requisitos para participar de um edital?"
print(f"\n--- Buscando por: \"{query}\" ---")
results = vector_manager.search_similar_texts(query, k=3)
if results:
for i, (text, dist) in enumerate(results):
print(f"Resultado {i+1} (Distância: {dist:.4f}):\n{text}\n")
else:
print("Nenhum resultado encontrado.")
Para fazer este código funcionar:
1. Certifique-se de que os arquivos pdf_processor.py , intelligent_chunker.py ,
vector_manager.py e o pipeline_example.py (com o código acima) estejam
no mesmo diretório.
2. Crie uma pasta chamada Data no mesmo diretório e coloque um arquivo PDF de
teste (por exemplo, EDITAL(1).pdf ) dentro dela.
3. Crie uma pasta chamada data no mesmo diretório. Esta pasta será usada para
armazenar o índice FAISS e os textos.
4. Instale as dependências necessárias manualmente: bash pip install
PyMuPDF pandas numpy sentence-transformers faiss-cpu
5. Abra seu terminal, navegue até o diretório onde esses arquivos estão e execute:
bash python3 pipeline_example.py
Você verá o processo de extração, chunking, vetorização e, finalmente, uma busca de
exemplo. Na primeira execução, o modelo Sentence-Transformer será baixado (pode
demorar um pouco) e o índice FAISS será criado e salvo. Nas execuções subsequentes,
o índice será carregado do disco, tornando o processo mais rápido.
Esta etapa é crucial, pois ela transforma seus documentos em um formato que pode
ser consultado semanticamente, preparando o terreno para o sistema de recuperação
e a geração de respostas.
Fase 5: Análise e Explicação do Arquivo retrieval_system.py e
Sistema de Recuperação
O arquivo retrieval_system.py contém a classe RetrievalSystem , que é a ponte
entre a consulta do usuário e o banco de dados vetorial que você construiu. Sua
função principal é encontrar os pedaços de informação (chunks) mais relevantes para
uma dada pergunta, utilizando a capacidade de busca de similaridade do
VectorManager .
Propósito:
Conforme descrito na seção "Etapa 3: Recuperação (Retrieval)" do seu guia em PDF, o
RetrievalSystem tem como objetivo:
Receber uma consulta do usuário.
Utilizar o VectorManager para vetorizar essa consulta.
Buscar no índice FAISS os chunks de texto que são semanticamente mais
próximos da consulta.
Retornar esses chunks relevantes para serem usados na próxima etapa (geração
da resposta).
Como funciona:
A classe RetrievalSystem é orientada a objetos e possui os seguintes métodos:
1. __init__(self, vector_manager: VectorManager) :
Função: Inicializa o sistema de recuperação. Ele recebe uma instância já
configurada do VectorManager como argumento. Isso significa que o
RetrievalSystem não se preocupa em carregar o modelo de embedding
ou o índice FAISS; ele confia que o VectorManager já fez isso.
Importância: Estabelece a dependência entre o sistema de recuperação e o
gerenciador de vetores. Garante que o RetrievalSystem tenha acesso ao
modelo de embedding e ao índice FAISS para realizar as buscas.
2. retrieve_relevant_chunks(self, query: str, k: int = 5) ->
List[Tuple[str, float]] :
Função: Este é o método principal para realizar a recuperação. Ele recebe a
query (a pergunta do usuário) e um número k (quantos chunks mais
relevantes devem ser retornados).
Internamente, ele chama o método search_similar_texts() do
self.vector_manager , passando a consulta e o k .
Retorna uma lista de tuplas, onde cada tupla contém o texto do chunk
relevante e sua pontuação de similaridade (distância) em relação à
consulta.
Importância: Implementa a lógica de recuperação de informações. É o
coração da fase de "Retrieval" do RAG, onde o sistema busca no seu
conhecimento base (os PDFs processados e vetorizados) as informações
que podem ajudar a responder à pergunta do usuário.
Considerações sobre a implementação:
Reutilização do VectorManager : A abordagem de passar uma instância de
VectorManager para o RetrievalSystem é um bom exemplo de Programação
Orientada a Objetos (POO) e reutilização de código. O RetrievalSystem não
precisa duplicar a lógica de carregamento de modelo ou gerenciamento de
FAISS.
Reranking: O guia em PDF menciona a etapa de "Reranking (Opcional, mas
Recomendado)" na fase de Recuperação. A implementação atual do
RetrievalSystem não inclui uma etapa explícita de reranking. Para adicionar
isso, você precisaria integrar um modelo de reranking (como um cross-encoder)
após a chamada a self.vector_manager.search_similar_texts() para
reordenar os resultados com base em uma pontuação de relevância mais
refinada.
Como usar este módulo no seu projeto (integrando com PDFProcessor ,
IntelligentChunker e VectorManager ):
Vamos continuar estendendo o pipeline_example.py para incluir o
RetrievalSystem . Este script agora começará a se parecer mais com o [Link] final.
# pipeline_example.py (continuação)
from pdf_processor import PDFProcessor
from intelligent_chunker import IntelligentChunker
from vector_manager import VectorManager
from retrieval_system import RetrievalSystem # Importar o novo módulo
import os
# 1. Configuração
pdf_file_path = [Link]("Data", "EDITAL(1).pdf") # Substitua pelo nome do
seu PDF
vector_db_dir = "data" # Diretório para salvar o índice FAISS
vector_db_path = [Link](vector_db_dir, \'faiss_index.bin\')
# Certifique-se de que o diretório \'data\' existe
[Link](vector_db_dir, exist_ok=True)
# 2. Inicializar VectorManager e carregar/criar índice
print("\n--- Inicializando Gerenciador de Vetores ---")
vector_manager = VectorManager(vector_db_path=vector_db_path)
if not vector_manager.load_faiss_index():
print("Índice FAISS não encontrado ou erro ao carregar. Processando PDF e
criando novo índice...")
# Processamento do PDF
print("\n--- Processando o PDF ---")
pdf_processor = PDFProcessor()
processed_data = pdf_processor.preprocess_pdf(pdf_file_path)
if not processed_data["text"]:
print("Erro: Não foi possível extrair texto do PDF. Verifique o caminho
do arquivo ou o conteúdo do PDF.")
else:
print(f"Texto extraído e limpo (primeiros 500
caracteres):\\n{processed_data["text"][:500]}...")
# Chunking Inteligente
print("\\n--- Realizando o Chunking Inteligente ---")
chunker = IntelligentChunker(max_chunk_size=500, overlap=50)
chunks = chunker.chunk_text(processed_data["text"])
print(f"Total de chunks gerados: {len(chunks)}")
# Vetorizar os chunks e adicionar ao índice
embeddings = vector_manager.vectorize_texts(chunks)
if [Link] > 0:
embedding_dimension = [Link][1]
vector_manager.initialize_faiss_index(embedding_dimension)
vector_manager.add_embeddings(embeddings, chunks)
vector_manager.save_faiss_index()
else:
print("Não foi possível gerar embeddings. Verifique o modelo ou os
chunks.")
else:
print("Índice FAISS carregado com sucesso.")
# 3. Inicializar o Sistema de Recuperação
print("\n--- Inicializando Sistema de Recuperação ---")
retrieval_system = RetrievalSystem(vector_manager)
# 4. Exemplo de uso do Sistema de Recuperação
if vector_manager.index:
query = "Quais são os prazos para recursos em licitações?"
print(f"\n--- Buscando chunks relevantes para a query: \\\"{query}\\\" ---
")
relevant_chunks = retrieval_system.retrieve_relevant_chunks(query, k=3)
if relevant_chunks:
print("\\n--- Chunks Relevantes Encontrados ---")
for i, (chunk_text, score) in enumerate(relevant_chunks):
print(f"Chunk {i+1} (Score: {score:.4f}):\\n{chunk_text}\\n")
else:
print("Nenhum chunk relevante encontrado.")
else:
print("Não foi possível realizar a busca, índice FAISS não está
disponível.")
Para fazer este código funcionar:
1. Certifique-se de que todos os arquivos ( pdf_processor.py ,
intelligent_chunker.py , vector_manager.py , retrieval_system.py e o
pipeline_example.py atualizado) estejam no mesmo diretório.
2. Mantenha a pasta Data com seu PDF de teste e a pasta data (que conterá o
índice FAISS).
3. Instale as dependências necessárias manualmente (se ainda não o fez): bash
pip install PyMuPDF pandas numpy sentence-transformers faiss-cpu
4. Abra seu terminal, navegue até o diretório onde esses arquivos estão e execute:
bash python3 pipeline_example.py
Você verá o processo completo de carregamento/criação do índice e, em seguida, a
busca de chunks relevantes para a sua consulta. Os chunks retornados são as
informações que o LLM usará para formular uma resposta na próxima fase do pipeline.
Fase 6: Análise e Explicação do Arquivo response_generator.py e
Geração de Respostas
O arquivo response_generator.py contém a classe ResponseGenerator , que é a
etapa final do seu pipeline RAG. Ele é responsável por pegar a consulta original do
usuário e os chunks relevantes recuperados (pelo RetrievalSystem ) e, usando um
Large Language Model (LLM) da OpenAI, gerar uma resposta estruturada em formato
JSON.
Propósito:
Conforme descrito na seção "Etapa 4: Geração da Resposta (Generation)" do seu guia
em PDF, o ResponseGenerator tem como objetivo:
Interagir com a API da OpenAI.
Construir um prompt eficaz que inclua o contexto recuperado e a consulta do
usuário.
Garantir que a resposta do LLM siga um esquema JSON predefinido para
extração de informações específicas de editais.
Lidar com erros na comunicação com a API ou na decodificação da resposta.
Como funciona:
A classe ResponseGenerator é orientada a objetos e possui os seguintes métodos:
1. __init__(self, openai_api_key: str, model: str = "gpt-4o") :
Função: Inicializa o gerador de respostas. Ele requer sua chave da API da
OpenAI ( openai_api_key ) e o nome do modelo da OpenAI a ser utilizado
(padrão é gpt-4o ).
Ele tenta carregar um system_prompt de um arquivo chamado prompt-
[Link] . Este prompt define o papel do LLM e as instruções detalhadas
para a geração da resposta.
Define um json_schema detalhado. Este esquema é crucial, pois instrui o
LLM a formatar sua saída exatamente como você precisa, com campos
específicos para análise de editais (data da sessão, valor estimado,
requisitos de habilitação, itens detalhados, etc.).
Importância: Configura a conexão com a OpenAI e, mais importante, define
as "regras do jogo" para o LLM através do system_prompt e do
json_schema . O json_schema é uma forma poderosa de garantir que a
saída do LLM seja estruturada e fácil de ser processada por outras partes do
seu sistema.
2. generate_response(self, query: str, relevant_chunks: List[str]) ->
Dict[str, Any] :
Função: Este é o método principal para gerar a resposta. Ele recebe a
query original do usuário e a lista de relevant_chunks (os textos
recuperados pelo RetrievalSystem ).
Ele concatena os relevant_chunks para formar o context que será
fornecido ao LLM.
Constrói a mensagem do usuário para o LLM, incluindo o context e a
instrução para gerar o JSON.
Chama a API [Link] da OpenAI, passando o modelo, as
mensagens (system e user) e, crucialmente, response_format={"type":
"json_object"} . Esta opção garante que a OpenAI tente retornar um JSON
válido.
Decodifica a resposta JSON e a retorna. Inclui tratamento de erros para
problemas de API ou de decodificação JSON.
Importância: É onde a "Geração" do RAG acontece. O LLM utiliza o contexto
fornecido para "fundamentar" sua resposta, preenchendo o esquema JSON
com as informações extraídas dos chunks relevantes. O system_prompt e o
json_schema guiam o LLM para extrair informações específicas e
estruturadas, reduzindo "alucinações" e garantindo a consistência da saída.
Considerações sobre a implementação:
[Link] : A existência e o conteúdo deste arquivo são vitais. Ele deve
conter instruções claras e detalhadas para o LLM sobre como analisar o edital e
preencher o JSON. O script espera que este arquivo esteja no mesmo diretório do
response_generator.py .
json_schema : O esquema JSON é muito bem definido e específico para editais.
Isso é excelente para garantir a extração de dados estruturados. Certifique-se de
que o LLM seja capaz de entender e preencher todos esses campos com base no
contexto fornecido.
Tratamento de Erros: O script inclui blocos try-except para lidar com erros da
API da OpenAI e erros de decodificação JSON, o que é uma boa prática para
robustez.
Variável de Ambiente para API Key: O exemplo de uso ( if __name__ ==
"__main__" ) mostra como obter a chave da API de uma variável de ambiente
( OPENAI_API_KEY ). Esta é a forma recomendada de gerenciar chaves sensíveis,
em vez de codificá-las diretamente no script.
Como usar este módulo no seu projeto (integrando com PDFProcessor ,
IntelligentChunker , VectorManager e RetrievalSystem ):
Agora, vamos completar o pipeline_example.py adicionando a etapa de geração de
respostas. Para isso, você precisará ter sua chave da OpenAI configurada como uma
variável de ambiente ou diretamente no script (para testes).
# pipeline_example.py (final)
import os
from pdf_processor import PDFProcessor
from intelligent_chunker import IntelligentChunker
from vector_manager import VectorManager
from retrieval_system import RetrievalSystem
from response_generator import ResponseGenerator # Importar o novo módulo
import json # Para imprimir o JSON formatado
from dotenv import load_dotenv # Para carregar a chave da API do .env
# Carregar variáveis de ambiente do arquivo .env
load_dotenv()
# 1. Configuração
pdf_file_path = [Link]("Data", "EDITAL(1).pdf") # Substitua pelo nome do
seu PDF
vector_db_dir = "data" # Diretório para salvar o índice FAISS
vector_db_path = [Link](vector_db_dir, \'faiss_index.bin\')
# Chave da API da OpenAI (obtida da variável de ambiente)
openai_api_key = [Link]("OPENAI_API_KEY")
if not openai_api_key:
print("ERRO: A variável de ambiente OPENAI_API_KEY não está configurada.
Por favor, crie um arquivo .env ou defina-a.")
exit()
# Certifique-se de que o diretório \'data\' existe
[Link](vector_db_dir, exist_ok=True)
# 2. Inicializar VectorManager e carregar/criar índice
print("\n--- Inicializando Gerenciador de Vetores ---")
vector_manager = VectorManager(vector_db_path=vector_db_path)
if not vector_manager.load_faiss_index():
print("Índice FAISS não encontrado ou erro ao carregar. Processando PDF e
criando novo índice...")
# Processamento do PDF
print("\n--- Processando o PDF ---")
pdf_processor = PDFProcessor()
processed_data = pdf_processor.preprocess_pdf(pdf_file_path)
if not processed_data["text"]:
print("Erro: Não foi possível extrair texto do PDF. Verifique o caminho
do arquivo ou o conteúdo do PDF.")
else:
print(f"Texto extraído e limpo (primeiros 500
caracteres):\\n{processed_data[\'text\'][:500]}...")
# Chunking Inteligente
print("\\n--- Realizando o Chunking Inteligente ---")
chunker = IntelligentChunker(max_chunk_size=500, overlap=50)
chunks = chunker.chunk_text(processed_data["text"])
print(f"Total de chunks gerados: {len(chunks)}")
# Vetorizar os chunks e adicionar ao índice
embeddings = vector_manager.vectorize_texts(chunks)
if [Link] > 0:
embedding_dimension = [Link][1]
vector_manager.initialize_faiss_index(embedding_dimension)
vector_manager.add_embeddings(embeddings, chunks)
vector_manager.save_faiss_index()
else:
print("Não foi possível gerar embeddings. Verifique o modelo ou os
chunks.")
else:
print("Índice FAISS carregado com sucesso.")
# 3. Inicializar o Sistema de Recuperação
print("\n--- Inicializando Sistema de Recuperação ---")
retrieval_system = RetrievalSystem(vector_manager)
# 4. Inicializar o Gerador de Respostas
print("\n--- Inicializando Gerador de Respostas ---")
response_generator = ResponseGenerator(openai_api_key=openai_api_key)
# 5. Exemplo de uso completo do Pipeline RAG
if vector_manager.index:
user_query = "Quais são os principais pontos deste edital e os requisitos
de habilitação?"
print(f"\n--- Processando a query do usuário: \\\"{user_query}\\\" ---")
# Recuperar chunks relevantes
relevant_chunks = retrieval_system.retrieve_relevant_chunks(user_query,
k=5)
if relevant_chunks:
# Extrair apenas o texto dos chunks para passar ao gerador
chunks_text_only = [chunk[0] for chunk in relevant_chunks]
print(f"\n--- Gerando resposta para a query: \\\"{user_query}\\\" ---")
response_json = response_generator.generate_response(user_query,
chunks_text_only)
print("\n--- Resposta Gerada (JSON) ---")
print([Link](response_json, indent=2, ensure_ascii=False))
else:
print("Nenhum chunk relevante encontrado para a query. Não é possível
gerar resposta.")
else:
print("Não foi possível realizar a busca ou gerar resposta, índice FAISS
não está disponível.")
Para fazer este código funcionar:
1. Certifique-se de que todos os arquivos ( pdf_processor.py ,
intelligent_chunker.py , vector_manager.py , retrieval_system.py ,
response_generator.py e o pipeline_example.py atualizado) estejam no
mesmo diretório.
2. Mantenha a pasta Data com seu PDF de teste e a pasta data (que conterá o
índice FAISS).
3. Crie o arquivo [Link] no mesmo diretório do
response_generator.py com o prompt do sistema para o LLM. Um exemplo
básico pode ser: Você é um assistente especializado em análise de
editais de licitação. Sua tarefa é extrair informações chave do texto
fornecido e apresentá-las em um formato JSON específico. Seja preciso
e objetivo. (Você pode e deve refinar este prompt para atender às suas
necessidades exatas, como o exemplo mais detalhado que já está no
response_generator.py .)
4. Instale as dependências necessárias manualmente (se ainda não o fez): bash
pip install PyMuPDF pandas numpy sentence-transformers faiss-cpu
openai python-dotenv
5. Configure sua chave da API da OpenAI: Crie um arquivo chamado .env (com
um ponto na frente) no mesmo diretório do seu pipeline_example.py e
adicione sua chave da seguinte forma:
OPENAI_API_KEY=sua_chave_da_openai_aqui Substitua
sua_chave_da_openai_aqui pela sua chave real da OpenAI.
6. Abra seu terminal, navegue até o diretório onde esses arquivos estão e execute:
bash python3 pipeline_example.py
Ao executar, você verá o pipeline completo em ação: processamento do PDF, chunking,
vetorização (ou carregamento do índice existente), recuperação de chunks relevantes
e, finalmente, a geração de uma resposta JSON estruturada pelo LLM. Esta é a
culminação de todas as etapas do seu sistema RAG!
Fase 7: Análise e Explicação do Arquivo [Link] e Execução do
Pipeline Completo
O arquivo [Link] é o coração do seu projeto RAG. Ele atua como o orquestrador,
integrando todas as classes e funcionalidades que analisamos nas fases anteriores
( PDFProcessor , IntelligentChunker , VectorManager , RetrievalSystem ,
ResponseGenerator ) para formar um pipeline completo de Geração Aumentada por
Recuperação.
Propósito:
O [Link] tem como objetivo principal:
Configurar o ambiente (embora tenhamos decidido fazer isso manualmente, o
script original tenta automatizar).
Carregar a chave da API da OpenAI.
Instanciar todas as classes dos módulos do pipeline.
Definir e executar a sequência de operações do pipeline RAG: processamento de
PDF, chunking, vetorização, recuperação e geração de resposta.
Fornecer um ponto de entrada para a execução do sistema.
Como funciona:
Vamos analisar as seções principais do [Link] :
1. Configuração de Imports e Dependências (Seção Inicial): ```python
#!/usr/bin/env python3 import os import sys import json from pathlib import
Path from install_pen import criar_ambiente, instalar_dependencias,
verificar_dependencias
Configuração de imports
try: [Link](str(Path(file).parent)) from install_d import
verificar_dependencias, install_dependencies # <-- ATENÇÃO AQUI
if not verificar_dependencias():
print("Instalando dependências necessárias...")
if not install_dependencies():
print("Falha na instalação das dependências")
[Link](1)
except Exception as e: print(f"Erro ao configurar ambiente: {str(e)}") [Link](1) ``
* **Observação Importante:** O seu [Link] original tenta
importar install_d e usar suas funções para verificar e instalar
dependências. No entanto, o arquivo que você forneceu é install_pen.py ,
e não install_d.py . Além disso, decidimos que as dependências serão
instaladas *manualmente* para maior controle. Portanto, esta seção
precisaria ser ajustada ou removida se você não quiser que
o [Link] tente gerenciar instalações. Para o nosso tutorial, vamos
considerar que as dependências já foram instaladas manualmente, e
você pode simplificar esta parte ou garantir que install_d.py exista e
seja o correto. * **Recomendação:** Para seguir nossa abordagem de
instalação manual, você pode remover ou comentar a seção try-except que
tenta instalar dependências, mantendo apenas a importação de Path e os`.
2. Carregamento da Chave da API da OpenAI: ```python from dotenv import
load_dotenv load_dotenv("[Link]") # Carrega do arquivo [Link]
openai_api_key = [Link]("OPENAI_API_KEY")
if not openai_api_key: print("Erro: OPENAI_API_KEY não encontrada") [Link](1)
`` * **Função:** Esta seção é crucial. Ela utiliza a
biblioteca python-dotenv para carregar a sua chave da API da OpenAI do
arquivo [Link] . Se a chave não for encontrada, o programa é
encerrado. * **Importância:** Garante que o ResponseGenerator` tenha
acesso à chave necessária para interagir com a API da OpenAI. Reforça a boa
prática de não embutir chaves sensíveis diretamente no código.
3. Importações Locais: python from pdf_processor import PDFProcessor from
intelligent_chunker import IntelligentChunker from vector_manager
import VectorManager from retrieval_system import RetrievalSystem
from response_generator import ResponseGenerator
Função: Importa todas as classes dos módulos que compõem o pipeline
RAG. Isso permite que o [Link] instancie e utilize essas classes.
Importância: Demonstra a modularidade do projeto, onde cada
componente é desenvolvido separadamente e depois integrado no script
principal.
4. Classe RAGPipeline : ```python class RAGPipeline: def init(self,
openai_api_key: str): self.pdf_processor = PDFProcessor() [Link] =
IntelligentChunker(max_chunk_size=500, overlap=50) self.vector_manager =
VectorManager() self.retrieval_system = RetrievalSystem(self.vector_manager)
self.response_generator = ResponseGenerator(openai_api_key=openai_api_key)
def run_pipeline(self, pdf_path: str, query: str) -> dict:
# ... (implementação do pipeline)
* **`__init__(self, openai_api_key: str)`:** O construtor da classe
`RAGPipeline` inicializa instâncias de todas as classes dos módulos
do pipeline. Note que o `RetrievalSystem` recebe a instância do
`VectorManager`, e o `ResponseGenerator` recebe a chave da API. *
**`run_pipeline(self, pdf_path: str, query: str) -> dict`:** Este é o
método principal que executa o pipeline completo. Ele recebe o
caminho do PDF a ser processado e a consulta do usuário. Vamos
detalhar cada passo: * **1. Processamento do PDF:** `processed_data =
self.pdf_processor.preprocess_pdf(pdf_path)` * Chama o `PDFProcessor`
para extrair e limpar o texto do PDF, incluindo tabelas e
placeholders de imagens. Se a extração falhar, retorna um erro. *
**2. Chunking Inteligente:** `chunks =
[Link].chunk_text(processed_data["text"])` * Pega o texto
processado e o divide em chunks usando o `IntelligentChunker`.
Verifica se chunks foram gerados. * **3. Vetorização:** `embeddings =
self.vector_manager.vectorize_texts(chunks)` * Converte os chunks em
embeddings numéricos usando o `VectorManager`. Verifica se a
vetorização foi bem-sucedida. * **4. Armazenamento:** python if
self.vector_manager.index is None:
self.vector_manager.initialize_faiss_index([Link][1])
self.vector_manager.add_embeddings(embeddings, chunks) `` * Inicializa
o índice FAISS (se ainda não estiver inicializado) com a dimensão
correta dos embeddings e adiciona os novos embeddings e seus chunks
correspondentes. **Importante:** O [Link] atual não implementa a
lógica de *carregar* um índice FAISS existente antes de adicionar.
Ele sempre inicializa ou adiciona. Para um sistema mais robusto, você
precisaria adicionar a lógica
de self.vector_manager.load_faiss_index() aqui, como fizemos
no pipeline_example.py . * **5. Recuperação:** relevant_chunks =
self.retrieval_system.retrieve_relevant_chunks(query, k=5) * Usa
o RetrievalSystem para buscar os 5 chunks mais relevantes para a
consulta do usuário no banco de dados vetorial. Verifica se chunks
relevantes foram encontrados. * **6. Geração returnde Resposta:**
self.response_generator.generate_response(query, [chunk for chunk, _ in
relevant_chunks]) * Pega os chunks relevantes (apenas o texto) e a
consulta, e os passa para o ResponseGenerator` para que o LLM crie a
resposta JSON estruturada.
5. Execução Principal ( if __name__ == "__main__": ) ```python if name ==
"main": try: # Configuração de caminhos relativos base_path = Path(file).parent
pdf_path = base_path / "Data" / "[Link]" # Substitua pelo seu PDF
query = "Quais são os requisitos de habilitação jurídica e o valor estimado do
edital?"
# Execução do pipeline
pipeline = RAGPipeline(openai_api_key)
result = pipeline.run_pipeline(str(pdf_path), query)
print("\nResultado da análise:")
print([Link](result, indent=2, ensure_ascii=False))
except Exception as e:
print(f"\nErro durante execução: {str(e)}")
[Link](1)
`` * **Função:** Este bloco é executado quando o script [Link] é
rodado diretamente. Ele define o caminho do PDF de entrada e a
consulta de exemplo, instancia o RAGPipeline e chama o
método run_pipeline`. * Importância: É o ponto de entrada para testar e usar o
sistema RAG completo. Ele demonstra como todas as partes se encaixam para
processar um PDF e responder a uma pergunta.
Como fazer o código funcionar (ajustes e execução):
Para que o [Link] funcione corretamente, você precisará fazer alguns ajustes e
garantir as configurações:
1. Dependências: Certifique-se de que todas as dependências ( PyMuPDF , pandas ,
numpy , sentence-transformers , faiss-cpu , openai , python-dotenv )
estejam instaladas manualmente no seu ambiente Python.
2. [Link] : Crie um arquivo chamado [Link] no mesmo diretório do [Link] e
adicione sua chave da OpenAI nele:
OPENAI_API_KEY=sua_chave_da_openai_aqui .
3. [Link] : Crie este arquivo no mesmo diretório do
response_generator.py (ou ajuste o caminho no ResponseGenerator se
preferir outro local) e adicione o prompt do sistema para o LLM.
4. Estrutura de Pastas: Crie a pasta Data e coloque seu PDF de teste ( 661adb6-
[Link] ou o nome que você usar) dentro dela. Crie também a pasta data para o
índice FAISS.
5. Ajuste no [Link] (Opcional, mas Recomendado):
Remover Instalação Automática: Para evitar confusão e seguir nossa
abordagem de instalação manual, você pode comentar ou remover as
linhas relacionadas à importação e execução de install_d no início do
[Link] .
Carregamento do Índice FAISS: O [Link] atual sempre adiciona
embeddings ao índice, sem verificar se já existe um índice salvo. Para um
comportamento mais eficiente (carregar se existir, criar/adicionar se não),
você pode adaptar a lógica que usamos no pipeline_example.py para o
run_pipeline do [Link] .
Exemplo de ajuste para run_pipeline (apenas a parte de
vetorização/armazenamento): ```python
... dentro do método run_pipeline ...
3. Vetorização e Armazenamento
Tentar carregar o índice existente
primeiro
if not self.vector_manager.load_faiss_index(): print("Índice FAISS não encontrado
ou erro ao carregar. Criando novo índice...") embeddings =
self.vector_manager.vectorize_texts(chunks) if [Link] == 0: return
{"error": "Falha na vetorização"}
embedding_dimension = [Link][1]
self.vector_manager.initialize_faiss_index(embedding_dimension)
self.vector_manager.add_embeddings(embeddings, chunks)
self.vector_manager.save_faiss_index() # Salvar o índice após a
criação/adição
else: print("Índice FAISS carregado com sucesso. Adicionando novos chunks, se
houver.") # Se o índice foi carregado, ainda podemos adicionar novos chunks se
necessário # embeddings = self.vector_manager.vectorize_texts(chunks) #
Vetorize apenas se for adicionar novos chunks #
self.vector_manager.add_embeddings(embeddings, chunks) # Adicione os novos
chunks # self.vector_manager.save_faiss_index() # Salve novamente se adicionou
... (continuação do pipeline)
`` * **Nota:** A lógica acima é um pouco mais complexa porque
o run_pipeline é chamado para *cada* query. Se você pretende processar
o PDF *uma vez* para criar o índice e depois apenas *consultá-lo*, a
lógica de criação/carregamento do índice deveria estar fora
do run_pipeline , talvez no init ou em uma função separada de setup_index`.
6. Execução: Abra seu terminal, navegue até o diretório onde [Link] e os outros
arquivos estão e execute: bash python3 [Link]
Ao executar, você verá o pipeline RAG completo em ação, desde o processamento do
PDF até a geração da resposta JSON estruturada pela OpenAI. Este é o ponto onde
todo o trabalho dos módulos individuais se une para resolver o problema de análise
de editais!
Fase 8: Conclusão e Recomendações Finais
Parabéns! Você agora tem um entendimento aprofundado de cada componente do
seu pipeline RAG e de como eles se integram para processar documentos PDF, extrair
informações relevantes e gerar respostas estruturadas usando Large Language Models.
Recapitulação do Pipeline RAG:
1. pdf_processor.py : Extrai e limpa o texto de PDFs, lidando com texto, tabelas e
imagens.
2. intelligent_chunker.py : Divide o texto limpo em chunks menores,
preservando o contexto e adicionando sobreposição.
3. vector_manager.py : Transforma os chunks em embeddings vetoriais e os
armazena em um índice FAISS para busca eficiente.
4. retrieval_system.py : Recebe uma consulta do usuário, busca os chunks mais
relevantes no índice FAISS.
5. response_generator.py : Utiliza os chunks relevantes e a consulta para gerar
uma resposta estruturada (JSON) usando um LLM da OpenAI.
6. [Link] : Orquestra todas as etapas, desde o carregamento da API key até a
execução completa do pipeline.
Recomendações para o Desenvolvimento Contínuo:
Refinamento do Chunking: Experimente diferentes max_chunk_size e overlap
no IntelligentChunker para otimizar a recuperação. Considere o chunking
baseado em tokens em vez de caracteres para maior precisão, especialmente se
o modelo de embedding for sensível a isso.
Tratamento de Imagens e Tabelas: A funcionalidade de describe_images no
PDFProcessor é um placeholder. Para um sistema RAG verdadeiramente
multimodal, invista em modelos de Visão Computacional (OCR avançado ou VQA
- Visual Question Answering) para gerar descrições ricas para as imagens. Para
tabelas complexas, explore bibliotecas como camelot ou tabula-py para uma
extração mais robusta.
Reranking: Para melhorar a precisão da recuperação, adicione uma etapa de
reranking após o RetrievalSystem . Modelos de reranking (como cross-
encoders) podem reordenar os chunks recuperados, priorizando aqueles que são
mais contextualmente relevantes para a consulta.
Prompt Engineering: O system_prompt no ResponseGenerator é fundamental.
Continue iterando e refinando-o para guiar o LLM a produzir as respostas mais
precisas e no formato desejado. Explore técnicas como few-shot prompting ou
chain-of-thought para resultados mais complexos.
Gerenciamento de Erros: Implemente um tratamento de erros mais robusto em
todo o pipeline, com logging adequado, para facilitar a depuração e a
manutenção.
Otimização do FAISS: Para grandes volumes de dados, explore diferentes tipos
de índices FAISS (e.g., IndexIVFFlat , IndexHNSW ) que oferecem um trade-off
entre velocidade de busca e precisão, e considere a otimização de parâmetros.
Monitoramento e Avaliação: Estabeleça métricas para avaliar a qualidade do
seu sistema RAG, como precisão da recuperação (recall, precision) e qualidade da
geração (fluência, relevância, factualidade). Isso é crucial para identificar
gargalos e áreas de melhoria.
Interface do Usuário: Considere construir uma interface simples (usando Flask,
Streamlit, Gradio, etc.) para interagir com o seu pipeline, tornando-o mais
acessível e fácil de testar.
Este guia forneceu uma base sólida para o seu projeto. Lembre-se que o
desenvolvimento de sistemas RAG é um processo iterativo, e a experimentação
contínua é a chave para otimizar o desempenho e a precisão.
Boa sorte com seu projeto!