Criando aplicativos RAG sem OpenAI - Parte Dois: Mixtral, Milvus e OctoAI
Este blog foi escrito por Yujian Tang e Thierry Moreau.
Geração Aumentada por Recuperação (RAG) é o caso de uso mais popular para LLMs a surgir em 2023. Embora a maioria dos exemplos mostre como você pode criar RAG com os LLMs GPT da OpenAI, esta série aborda como criar RAG sem a OpenAI. Veja Building RAG without OpenAI Part One aqui.
Este tutorial é a segunda parte desta série, cobrindo a criação de RAG com Milvus, Mixtral hospedado por meio da OctoAI e LangChain. Em particular, compartilhamos apenas a ponta do iceberg das inúmeras vantagens do Mixtral neste tutorial: suas capacidades multilíngues.
Neste blog, abordaremos:
- Stack de tecnologia RAG de código aberto MMO(L)
- Mixtral
- Milvus
- OctoAI
- LangChain
- A arquitetura do aplicativo RAG
- Configure suas ferramentas RAG
- Selecione e carregue seus dados
- Consulte seus dados com OctoAI e Mixtral
- Resumo
Encontre o notebook no GitHub.
Stack de tecnologia RAG de código aberto MMO(L)
Há muitas maneiras de criar aplicativos RAG e, na minha última pesquisa de mercado, encontrei mais de 50 ferramentas diferentes na stack de LLM. Neste exemplo, nos concentramos em quatro: Mixtral como o LLM, Milvus como o banco de dados vetorial, OctoAI para servir o LLM e o modelo de embeddings, e LangChain como nosso orquestrador. Antes de mergulharmos na arquitetura, vamos aprender um pouco sobre as ferramentas envolvidas.
Mixtral
Mixtral 8x7B, ou apenas “Mixtral” para abreviar, é o modelo mais recente lançado pela pioneira startup francesa de IA Mistral. Lançado em dezembro de 2023 (com o artigo saindo em janeiro de 2024), ele representa uma extensão significativa do modelo de linguagem grande fundacional anterior, Mistral 7B. Mixtral é um modelo de linguagem Sparse Mixture of Experts (SMoE) 8x7B com capacidades mais substanciais do que o Mistral 7B original. Ele é maior, usando 13B parâmetros ativos durante a inferência de um total de 47B parâmetros, e oferece suporte a vários idiomas, código e uma janela de contexto de 32k. No início de 2024, Mixtral é o modelo de código aberto com a maior pontuação nos rankings de LLM.
Milvus
O núcleo da memória do nosso aplicativo RAG é o banco de dados vetorial. Milvus é um banco de dados vetorial altamente escalável voltado para aplicações empresariais. Sua estrutura inerente de sistema distribuído permite escalonamento contínuo à medida que você se aproxima dos verdadeiros níveis de produção de vetores. Milvus também oferece outros recursos empresariais, como multilocação, controle de acesso baseado em funções e alta disponibilidade.
OctoAI
OctoAI fornece a infraestrutura para executar modelos LLM em escala de produção. OctoAI facilita para desenvolvedores de IA a integração dos modelos hospedados da OctoAI, que oferecem uma seleção de poderosos modelos de código aberto, incluindo Mixtral e ajustes finos da comunidade, como Nous Hermes. Cerca de 9 em cada 10 novos cadastros na OctoAI começam com Mixtral como seu modelo LLM de escolha, e hoje o Mixtral na OctoAI gera bilhões de tokens para clientes diariamente. Neste tutorial, substituiremos o GPT pelo modelo Mixtral altamente popular.
LangChain
LangChain é, sem dúvida, o framework de aplicativos LLM mais popular do mercado. LangChain inclui integrações com quase todas as ferramentas que você possa imaginar. Embora você possa usá-lo de muitas maneiras, neste exemplo, nós o usamos para conectar tudo. Carregamos o Milvus e o endpoint da OctoAI por meio do LangChain e, em seguida, o usamos para “encadear” tudo.
A arquitetura do aplicativo RAG
Cada aplicativo RAG tem quatro componentes críticos: o LLM, o banco de dados vetorial, o modelo de embedding e o orquestrador. Por baixo de tudo isso fica a camada de infraestrutura. Nesta configuração, estamos usando Mixtral como o LLM, Milvus como o banco de dados vetorial, GTE Large como o modelo de embedding, LangChain como o orquestrador e OctoAI como a camada de infraestrutura que fornece o GTE Large e o Mixtral.
Configure Suas Ferramentas RAG
Vamos começar configurando nossas ferramentas RAG. Nesta seção, configuramos nossos endpoints de inferência para o LLM e os embeddings e inicializamos nosso banco de dados vetorial. Vamos começar instalando os pré-requisitos. Precisamos de pymilvus e milvus para trabalhar com o Milvus. Precisamos de langchain, sentence-transformers e tiktoken para usar a funcionalidade do LangChain neste exemplo. Por fim, também precisamos de octoai-sdk para fazer interface com as APIs de embedding e conclusão de texto da OctoAI.
Usamos este primeiro bloco de código para carregar a maioria das nossas importações necessárias do LangChain, incluindo as importações do Milvus e da OctoAI. Também carregamos o módulo LLMChain, que nos permite encadear funções, e o módulo PromptTemplate, que usamos para passar prompts aos nossos LLMs. Também precisamos carregar nossas variáveis de ambiente na memória. Há muitas maneiras de fazer isso, mas, para este exemplo, usamos load_dotenv da biblioteca python-dotenv.
# ! pip install pymilvus milvus langchain sentence-transformers tiktoken octoai-sdk python-dotenv
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_community.llms.octoai_endpoint import OctoAIEndpoint
from langchain_community.embeddings import OctoAIEmbeddings
from langchain_community.vectorstores import Milvus
from dotenv import load_dotenv
import os
load_dotenv()
# the line below is just to show that you need to have your OCTOAI_API_TOKEN
os.environ["OCTOAI_API_TOKEN"] = os.getenv("OCTOAI_API_TOKEN")
O próximo passo é inicializar nosso acesso ao LLM. A OctoAI nos permite acessar facilmente modelos hospedados e personalizá-los para o nosso caso de uso. Usamos OctoAIEndpoint do LangChain e passamos o endpoint (mostrado no código) para acessar um modelo. Também passamos os parâmetros de LLM necessários. Para este exemplo, são o nome do modelo, o número máximo de tokens (o quão longo é o prompt de saída), bem como outros parâmetros para dizer ao modelo o que você precisa que ele faça (por exemplo, prompt do sistema) e quão criativo deve ser com a saída (“presence_penalty”, “temperature”, “top_p”). Para os embeddings, apenas passamos a URL do endpoint da OctoAI. Por padrão, ele usará o GTE Large. Com o tempo, mais modelos de embedding serão adicionados à OctoAI.
llm = OctoAIEndpoint(
endpoint_url="https://text.octoai.run/v1/chat/completions",
model_kwargs={
"model": "mixtral-8x7b-instruct-fp16",
"max_tokens": 128,
"presence_penalty": 0,
"temperature": 0.01,
"top_p": 0.9,
"messages": [
{
"role": "system",
"content": "You are a helpful assistant. Keep your responses limited to one short paragraph if possible.",
},
],
},
)
embeddings = OctoAIEmbeddings(endpoint_url="https://text.octoai.run/v1/embeddings")
A última parte disso é o banco de dados vetorial. Usamos Milvus Lite como nosso banco de dados vetorial. Importe default_server do Milvus e, em seguida, chame a função start() para iniciar o servidor.
from milvus import default_server
default_server.start()
Selecione e Carregue Seus Dados
Com tudo configurado, é hora de carregar nossos dados. Para este exemplo, você pode encontrar os dados no Repositório do GitHub. Se quiser obter os dados, eles foram simplesmente extraídos da Wikipédia. Depois que tivermos nossos dados, é hora de carregá-los em um banco de dados vetorial. Usamos LangChain e Milvus para essa tarefa.
As duas importações de que precisamos do LangChain para carregar esses documentos são um divisor de texto - CharacterTextSplitter neste caso - e Document. Agora, podemos carregar todo o diretório de dados como uma lista de “Documents”, uma abstração do LangChain. Para este exemplo, estamos carregando um diretório chamado “data”. Também criamos uma lista vazia para armazenar nossa lista de Documents.
Em seguida, percorremos cada um dos arquivos no diretório. Lemos o arquivo e usamos um divisor de texto para dividir o texto em chunks. Para este exemplo, usamos um tamanho de chunk de 512 e uma sobreposição de chunk de 64. Esses valores foram escolhidos simplesmente porque geralmente tendem a fazer sentido. Sinta-se à vontade para ajustá-los como quiser para ver como os resultados podem diferir.
Depois de dividirmos o texto em chunks, nós o armazenamos como um documento com alguns metadados. Os metadados que mantemos com o texto são o título do documento e o número do chunk para nos informar onde o chunk está no documento.
from langchain.text_splitter import CharacterTextSplitter
from langchain.schema import Document
files = os.listdir("./data")
file_texts = []
for file in files:
with open(f"./data/{file}") as f:
file_text = f.read()
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=512, chunk_overlap=64,
)
texts = text_splitter.split_text(file_text)
for i, chunked_text in enumerate(texts):
file_texts.append(Document(page_content=chunked_text,
metadata={"doc_title": file.split(".")[0], "chunk_num": i}))
Com os Documents prontos, é hora de inseri-los no banco de dados vetorial. Usamos a integração do Milvus com o LangChain e chamamos a função from_documents. Passe os documentos, o modelo de embeddings, os argumentos de conexão para a instância do Milvus Lite e um nome para as coleções. Simplesmente chamamos o método as_retriever() para colocar um LLM por cima e começar a trabalhar com o Milvus como nosso banco de dados vetorial para este exemplo básico de RAG.
vector_store = Milvus.from_documents(
file_texts,
embedding=embeddings,
connection_args={"host": "localhost", "port": default_server.listen_port},
collection_name="cities"
)
retriever = vector_store.as_retriever()
Consulte Seus Dados com OctoAI e Mixtral
Tudo está pronto. Agora podemos usar o LangChain para orquestrar a parte de recuperação do nosso quebra-cabeça. Começamos fornecendo um template ao LangChain. Devemos passar duas variáveis para o template de prompt - o contexto que recuperamos e a pergunta que queremos fazer. Podemos tratar a string do template como uma f-string e então passá-la para a função from_template de PromptTemplate.
Depois do template, configuramos a parte da “chain”. Precisamos do módulo RunnablePassthrough para passar o contexto adiante e do StrOutputParser para analisar a saída. Em seguida, configuramos a chain. Primeiro, dizemos ao LangChain onde obter o contexto e a pergunta, depois encaminhamos esses dados para o prompt, que é encaminhado para o LLM e, por fim, para o analisador de saída de string para fazer a análise. Para fazer uma pergunta, simplesmente damos invoke na chain.
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = PromptTemplate.from_template(template)
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain.invoke("How big is the city of Seattle?")
Para o exemplo de “Qual é o tamanho da cidade de Seattle”, podemos ver uma saída esperada abaixo. A resposta é precisa e respaldada pelas informações da Wikipedia que armazenamos no banco de dados vetorial.
Aproveitando os recursos multilíngues do Mixtral por meio da OctoAI
Como estamos usando o Mixtral, vamos aproveitar alguns recursos exclusivos, como a expertise multilíngue. O bom de usar a OctoAI é que podemos aproveitar o mesmo endpoint com uma instrução diferente para fazer coisas diferentes. Neste caso, diremos ao modelo para responder em francês e não em inglês.
# Let's make this a bit more fun and showcase the multilingual capabilities of Mixtal which really outshine other open source models
# Our Vector DB is populated with entries from english text - even the embedding model we're using here, GTE-Large
# works best on english text. However Mixtral has good mutlilingual capabilities in French, German, Spanish and Italian.
# So what we'll do is ask the assistant to only answer in french in the system and user prompt. RAG here is performed based on
# english text, but upon producing the user response, the Mixtral LLM will generate tokens in a different language here (french)
llm = OctoAIEndpoint(
endpoint_url="https://text.octoai.run/v1/chat/completions",
model_kwargs={
"model": "mixtral-8x7b-instruct-fp16",
"max_tokens": 128,
"presence_penalty": 0,
"temperature": 0.1,
"top_p": 0.9,
"messages": [
{
"role": "system",
"content": "You are a helpful assistant who responds in french and not in english.",
},
],
},
)
Também usamos um modelo ligeiramente modificado para pedir ao Mixtral que responda em francês. O prompt precisa ser refeito a partir do novo modelo, e a cadeia precisa ser refeita a partir do novo prompt, modelo e LLM. A cadeia pode ser invocada da mesma forma. Fazemos a mesma pergunta em inglês e esperamos uma resposta em francês.
template = """Answer the question in french based only on the following context:
{context}
Question: {question}
"""
prompt = PromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain.invoke("How big is the city of Seattle?")
A resposta deve se parecer com a imagem abaixo.
Resumo
Neste tutorial, exploramos outra maneira de criar RAG sem a OpenAI. Na parte 1, usamos a Symbl.AI como LLM; neste, usamos o Mixtral da Mistral hospedado pela OctoAI. As outras peças do framework RAG que usamos são o Milvus como banco de dados vetorial, o LangChain como orquestrador e o GTE-Large, também hospedado pela OctoAI, como modelo de embedding.
Configuramos nossas ferramentas de RAG e carregamos um pouco da Wikipedia como nossos dados de exemplo. Em seguida, usamos o LangChain para ler os dados no Milvus e adicionar o “le big model” por cima. No final, também dedicamos um tempo para explorar um dos recursos exclusivos do Mixtral: a capacidade de trabalhar em vários idiomas. Para este exemplo, usamos o francês. Da próxima vez, exploraremos também alguns outros idiomas!
Continue lendo

Data Deduplication at Trillion Scale: How to Solve the Biggest Bottleneck of LLM Training
Explore how MinHash LSH and Milvus handle data deduplication at the trillion-scale level, solving key bottlenecks in LLM training for improved AI model performance.

8 Latest RAG Advancements Every Developer Should Know
Explore eight advanced RAG variants that can solve real problems you might be facing: slow retrieval, poor context understanding, multimodal data handling, and resource optimization.

How to Use Anthropic MCP Server with Milvus
MCP + Milvus: Streamline AI agent development with standardized data access, eliminating integration hassles while enhancing context and flexibility.



