Pular para o conteúdo principal

DeepSeek R1 RAG Chatbot com Chroma, Ollama e Gradio

Saiba como criar um chatbot RAG local usando o DeepSeek-R1 com Ollama, LangChain e Chroma.
Actualizado 11 de fev. de 2025  · 12 min de leitura

A geração aumentada por recuperação (RAG) surgiu como uma abordagem poderosa para a criação de aplicativos de IA que geram respostas precisas, fundamentadas e contextualmente relevantes, recuperando e sintetizando o conhecimento de fontes externas.

Neste tutorial, explicarei passo a passo como criar um chatbot baseado em RAG usando o DeepSeek-R1 e um livro sobre os fundamentos dos LLMs como base de conhecimento. Ao final deste tutorial, você será capaz de criar um aplicativo RAG local capaz de responder a perguntas do livro e interagir com os usuários por meio de uma interface Gradio.

Por que usar o DeepSeek-R1 com o RAG?

DeepSeek-R1 é ideal para sistemas baseados em RAG devido ao seu desempenho otimizado, recursos avançados de pesquisa vetorial e flexibilidade em diferentes ambientes, desde configurações locais até implementações dimensionáveis. Aqui estão alguns motivos pelos quais ele é eficaz:

  1. Recuperação de alto desempenho: O DeepSeek-R1 lida com grandes coleções de documentos com baixa latência.
  2. Classificação de relevância refinada: Ele garante a recuperação precisa de passagens por meio da computação da similaridade semântica.
  3. Benefícios de custo e privacidade: Você pode executar o DeepSeek-R1 localmente para evitar taxas de API e manter dados confidenciais seguros.
  4. Fácil integração: Ele se integra facilmente a bancos de dados vetoriais, como o Chroma.
  5. Recursos off-line: Com o DeepSeek-R1, você pode criar sistemas de recuperação que funcionam mesmo sem acesso à Internet depois que o modelo é baixado.

Visão geral: Criando um chatbot RAG com o DeepSeek-R1

Nosso projeto de demonstração se concentra na criação de um chatbot RAG usando o DeepSeek-R1 e o Gradio.

Pipeline do RAG Chatbot

O processo começa com o carregamento e a divisão de um PDF em partes de texto, seguido pela geração de incorporações para esses blocos. Essas incorporações são armazenadas em um banco de dados Chroma para uma recuperação eficiente. Quando um usuário envia uma consulta, o sistema recupera os trechos de texto mais relevantes e usa o DeepSeek-R1 para gerar uma resposta com base no contexto recuperado.

Etapa 1: Pré-requisitos

Antes de começarmos, vamos garantir que você tenha as seguintes ferramentas e bibliotecas instaladas:

  • Python 3.8+
  • Langchain
  • Chromadb
  • Gradio

Execute os seguintes comandos para instalar as dependências necessárias:

!pip install langchain chromadb gradio ollama pymypdf
!pip install -U langchain-community

Quando as dependências acima estiverem instaladas, execute os seguintes comandos de importação:

import ollama
import re
import gradio as gr
from concurrent.futures import ThreadPoolExecutor
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_community.embeddings import OllamaEmbeddings
from chromadb.config import Settings
from chromadb import Client
from langchain.vectorstores import Chroma

Etapa 2: Carregar o PDF usando o PyMuPDFLoader

Usaremos o PyMuPDFLoader da LangChain para extrair o texto da versão em PDF do livro Foundations of LLMs (Fundamentos dos LLMs) de Tong Xiao e Jingbo Zhu - esse é um livro com muita matemática, o que significa que nosso chatbot deve ser capaz de explicar bem a matemática por trás dos LLMs. Você pode encontrar o livro no arXiv

# Load the document using PyMuPDFLoader
loader = PyMuPDFLoader("/path/to/Foundations_of_llms.pdf")

documents = loader.load()

Depois que o documento é carregado, podemos começar a dividir o texto em partes para processamento posterior.

Etapa 3: Dividir o documento em partes menores

Dividiremos o texto extraído em pedaços menores e sobrepostos para melhorar a recuperação do contexto. Você pode variar o tamanho do bloco e a sobreposição do bloco de acordo com seu sistema na função RecursiveCharacterTextSpilitter().

# Split the document into smaller chunks
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)

chunks = text_splitter.split_documents(documents)

Agora, temos os blocos de texto extraídos que estão prontos para serem convertidos em embeddings.

Etapa 4: Gerar embeddings usando o DeepSeek-R1

Usaremos o Ollama Embeddings baseado no DeepSeek-R1 para gerar os embeddings de documentos. Dependendo do tamanho do documento, a geração de incorporação pode ser demorada, portanto, é preferível que você a paralelize para obter um processamento mais rápido.

Observação: por padrão, o site model="deepseek-r1" considera o modelo de parâmetro 7B. Você pode alterá-lo conforme necessário para 8B, 14B, 32B, 70B ou 671B. Substitua o X no nome do modelo a seguir pelo tamanho do modelo: model="deepseek-r1:X"

# Initialize Ollama embeddings using DeepSeek-R1
embedding_function = OllamaEmbeddings(model="deepseek-r1")
# Parallelize embedding generation
def generate_embedding(chunk):
    return embedding_function.embed_query(chunk.page_content)
with ThreadPoolExecutor() as executor:
    embeddings = list(executor.map(generate_embedding, chunks))

A função acima inicializa o DeepSeek-R1 via Ollama para gerar embeddings semânticos de alta dimensão, que serão usados posteriormente para recuperação de documentos com base em similaridade.

A função generate_embedding() pega o texto de um bloco de documento e gera sua incorporação. Por fim, o site ThreadPoolExecutor() aplica o generate_embedding() a cada bloco simultaneamente, coletando embeddings em uma lista para um processamento mais rápido em comparação com a execução sequencial.

Etapa 5: Armazenar Embeddings no Chroma Vector Store

Armazenaremos os embeddings e os pedaços de texto correspondentes em um banco de dados vetorial de alto desempenho, o Chroma.

# Initialize Chroma client and create/reset the collection
client = Client(Settings())
client.delete_collection(name="foundations_of_llms")  # Delete existing collection (if any)
collection = client.create_collection(name="foundations_of_llms")
# Add documents and embeddings to Chroma
for idx, chunk in enumerate(chunks):
    collection.add(
        documents=[chunk.page_content], 
        metadatas=[{'id': idx}], 
        embeddings=[embeddings[idx]], 
        ids=[str(idx)]  # Ensure IDs are strings
    )

Começamos seguindo estas etapas para armazenar embeddings:

1. Inicializar o cliente Chroma e redefinir a coleção:

  • O site Client(Settings()) inicializa o cliente Chroma para gerenciar o armazenamento de vetores. 
  • Exclua qualquer coleção existente semelhante ao nome da sua coleção usando client.delete_collection() para evitar erros. Por fim, use client.create_collection() para criar uma nova coleção para armazenar os blocos de documentos e suas incorporações.

2. Iterar por partes do documento:

  • Itere sobre cada bloco de documento e sua incorporação correspondente usando seu ID de cadeia de caracteres exclusivo.

3. Adicione pedaços e incorporações ao Chroma:

  • Para cada bloco, o site collection.add() armazena:
    • O conteúdo conteúdo do documento (chunk.page_content)
    • Metadados ({'id': idx}) para fazer referência ao bloco
    • Seu correspondente vetor de incorporação para recuperação
    • A único ID para identificar a entrada

Essa configuração garante que cada bloco de documento seja indexado corretamente para uma recuperação eficiente baseada em vetores.

Etapa 6: Inicializar o recuperador

Inicializaremos o Chroma retriever, garantindo que ele use os mesmos embeddings do DeepSeek-R1 para consultas.

# Initialize retriever using Ollama embeddings for queries
retriever = Chroma(collection_name="foundations_of_llms", client=client, embedding_function=embedding_function).as_retriever()

O recuperador Chroma se conecta à coleção "foundations_of_llms" e usa os embeddings do DeepSeek-R1 via Ollama para incorporar as consultas do usuário. Ele recupera os blocos de documentos mais relevantes com base na similaridade de vetores para respostas com reconhecimento de contexto.

Etapa 7: Definir o pipeline do RAG

Em seguida, recuperaremos os trechos de texto mais relevantes e os formataremos para que o DeepSeek-R1 gere respostas.

def retrieve_context(question):
    # Retrieve relevant documents
    results = retriever.invoke(question)
    # Combine the retrieved content
    context = "\n\n".join([doc.page_content for doc in results])
    return context

A função retrieve_context incorpora a consulta do usuário usando o DeepSeek-R1 e recupera os principais blocos de documentos relevantes por meio do recuperador Chroma. Em seguida, ele combina o conteúdo dos blocos recuperados em uma única string de contexto para processamento posterior.

Etapa 8: Consultar o DeepSeek-R1 para obter respostas contextuais

Agora, temos a pergunta e o contexto recuperado. Em seguida, envie-o para o DeepSeek-R1 via Ollama para obter a resposta final.

def query_deepseek(question, context):
    # Format the input prompt
    formatted_prompt = f"Question: {question}\n\nContext: {context}"
    # Query DeepSeek-R1 using Ollama
    response = embedding_function.chat(
        model="deepseek-r1",
        messages=[{'role': 'user', 'content': formatted_prompt}]
    )
    # Clean and return the response
    response_content = response['message']['content']
    final_answer = re.sub(r'<think>.*?</think>', '', response_content, flags=re.DOTALL).strip()
    return final_answer

Para obter a resposta final, começamos combinando a pergunta do usuário e o contexto recuperado em um prompt estruturado. Em seguida, envie esse prompt para o modelo DeepSeek-R1 via Ollama para receber uma resposta. Para tornar o resultado final apresentável, removemos as tags desnecessárias e retornamos a resposta final.

Etapa 9: Criar a interface do Gradio

Temos nosso pipeline RAG em funcionamento. Agora, usaremos o Gradio para criar uma interface interativa para que os usuários façam perguntas relacionadas à sua base de conhecimento (Foundations of LLMs, neste caso).

def ask_question(question):
    # Retrieve context and generate an answer using RAG
    context = retrieve_context(question)
    answer = query_deepseek(question, context)
    return answer
# Set up the Gradio interface
interface = gr.Interface(
    fn=ask_question,
    inputs="text",
    outputs="text",
    title="RAG Chatbot: Foundations of LLMs",
    description="Ask any question about the Foundations of LLMs book. Powered by DeepSeek-R1."
)
interface.launch()

A função ask_question() recupera o contexto relevante usando o Chroma retriever e gera a resposta final por meio do DeepSeek-R1. A interface do Gradio, desenvolvida com o site gr.Interface(), permite que os usuários façam perguntas de forma interativa e recebam respostas contextualmente precisas e fundamentadas.

Parabéns! Agora você tem um chatbot em execução no local, pronto para discutir qualquer coisa relacionada a LLMs.

Aplicativo RAG com DeekSeek-R1 e Gradio

Otimizações

A demonstração acima abrange uma implementação muito básica do RAG, que pode ser otimizada ainda mais para aumentar a eficiência. Aqui estão algumas coisas que você pode experimentar:

  • Ajuste do tamanho do pedaço: Ajuste os parâmetros chunk_size e chunk_overlap para equilibrar o desempenho e a qualidade da recuperação.
  • Versões de modelos menores: Se o DeepSeek-R1 exigir muitos recursos, você poderá usar versões diferentes (deepseek-r1:7b ou deepseek-r1:8b ou deepseek-r1:14b) por meio do Ollama.
  • Escala usando Faiss: Para documentos maiores, considere integrar o Faiss para uma recuperação mais rápida.
  • Processamento em lote: Se a geração de incorporação for lenta, agrupe os blocos para aumentar a eficiência.

Conclusão

Neste tutorial, criamos um chatbot local baseado em RAG usando o DeepSeek-R1 e o Chroma para recuperação, o que garante respostas precisas e contextualmente ricas para perguntas baseadas em uma grande base de conhecimento.

Para saber mais sobre o DeepSeek, recomendo estes blogs:


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Sou Google Developers Expert em ML (Gen AI), Kaggle 3x Expert e Women Techmakers Ambassador com mais de 3 anos de experiência em tecnologia. Fui cofundador de uma startup de tecnologia de saúde em 2020 e estou fazendo mestrado em ciência da computação na Georgia Tech, com especialização em machine learning.

Temas

Aprenda IA com estes cursos!

curso

Retrieval Augmented Generation (RAG) with LangChain

3 hr
2.9K
Learn cutting-edge methods for integrating external data with LLMs using Retrieval Augmented Generation (RAG) with LangChain.
Ver DetalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado

blog

ChatGPT vs Google Bard: Um guia comparativo para chatbots de IA

Uma introdução amigável para iniciantes aos dois chatbots com tecnologia de IA sobre os quais todos estão falando.
Javier Canales Luna's photo

Javier Canales Luna

17 min

tutorial

RAG With Llama 3.1 8B, Ollama e Langchain: Tutorial

Aprenda a criar um aplicativo RAG com o Llama 3.1 8B usando Ollama e Langchain, configurando o ambiente, processando documentos, criando embeddings e integrando um retriever.
Ryan Ong's photo

Ryan Ong

12 min

tutorial

DeepSeek-Coder-V2 Tutorial: Exemplos, instalação, padrões de referência

O DeepSeek-Coder-V2 é um modelo de linguagem de código de código aberto que rivaliza com o desempenho do GPT-4, Gemini 1.5 Pro, Claude 3 Opus, Llama 3 70B ou Codestral.
Dimitri Didmanidze's photo

Dimitri Didmanidze

8 min

tutorial

Como criar aplicativos LLM com o tutorial LangChain

Explore o potencial inexplorado dos modelos de linguagem grandes com o LangChain, uma estrutura Python de código aberto para criar aplicativos avançados de IA.
Moez Ali's photo

Moez Ali

12 min

tutorial

Criando agentes LangChain para automatizar tarefas em Python

Um tutorial abrangente sobre a criação de agentes LangChain com várias ferramentas para automatizar tarefas em Python usando LLMs e modelos de bate-papo usando OpenAI.
Bex Tuychiev's photo

Bex Tuychiev

14 min

tutorial

Ajuste fino do Llama 3.1 para classificação de textos

Comece a usar os novos modelos Llama e personalize o Llama-3.1-8B-It para prever vários distúrbios de saúde mental a partir do texto.
Abid Ali Awan's photo

Abid Ali Awan

13 min

Ver maisVer mais