Como criar uma solução end-to-end de IA Generativa?
Neste artigo, daremos uma olhada na construção de uma solução completa de IA generativa e utilizaremos algumas ferramentas diferentes para operacionalizar esse fluxo de trabalho:
NOTA : Este artigo pressupõe um conhecimento intermediário de Python e um conhecimento básico de LangChain em específico. Eu sugeriria seguir este artigo para entender melhor o LangChain e construir melhor aplicativos de IA generativa.
Visão geral do problema
Os Large Language Models (LLMs) por si só são incrivelmente poderosos e muitas vezes podem responder a muitas perguntas sem ajuda de ajuste fino ou conhecimento/contexto adicional.
No entanto, isso pode se tornar um gargalo quando você precisar acessar outras fontes específicas de dados e, especialmente, dados recentes. Por exemplo, embora a OpenAI tenha sido treinada em um grande corpus de dados, ela não tem conhecimento dos artigos recentes.
Os modelos da OpenAI já possuem algum conhecimento do Amazon SageMaker a partir do corpus em que foram treinados. O que queremos ver é quanto desempenho podemos ganhar fornecendo a esses LLMs acesso aos artigos do Medium. Eles podem servir quase como uma espécie de folha de dicas para LLMs que já possuem um grande banco de conhecimento.
Como fornecemos a esses LLMs acesso a esse conhecimento e informações adicionais? 🤔
Por que precisamos do RAG
É aqui que entra em jogo a Geração Aumentada de Recuperação (RAG). Com o RAG fornecemos um sistema de recuperação de informação que nos dá acesso aos dados adicionais de que necessitamos. Isso nos ajudará a responder perguntas mais avançadas sobre o SageMaker e a aumentar nossa base de conhecimento de LLMs. Para implementar um sistema RAG básico precisamos de alguns componentes:
Essencialmente, você pode pensar no RAG como um melhorador de desempenho dos LLMs, fornecendo conhecimento extra que o LLM básico talvez ainda não tenha. Na próxima seção, veremos como podemos implementar esses conceitos utilizando LangChain e OpenAI.
Aplicação de IA generativa e inferência de amostra
Para começar, você precisa de uma chave de API OpenAI, que pode ser encontrada e instalada no link a seguir. Observe as cobranças por taxa/limite de API para que você entenda a estrutura de preços. Para desenvolvimento trabalhamos em uma SageMaker Classic Notebook Instance, mas qualquer ambiente com OpenAI e LangChain instalados deve ser suficiente.
import os
os.environ['OPENAI_API_KEY'] = 'Enter your API Key here'
# necessary langchain imports
import langchain
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.embeddings.cache import CacheBackedEmbeddings
from langchain.vectorstores import FAISS
from langchain.storage import LocalFileStore
from langchain.document_loaders import PyPDFDirectoryLoader
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
Depois de configurar o LangChain e o OpenAI, criamos um diretório local com dez artigos populares do Medium armazenados como PDFs. Estes serão os dados/informações adicionais que disponibilizaremos para meu LLM.
Como próximos passos, precisamos ser capazes de carregar esses dados e também criar um diretório onde possamos armazenar os embeddings que geramos. LangChain tem muitos utilitários que carregam automaticamente e também dividem/separam seus dados para você. A fragmentação é especificamente importante porque não queremos conjuntos maiores de dados para os embeddings que geramos. Quanto maiores os dados, maior o ruído potencial que pode ser introduzido.
Neste caso, usamos o carregador de PDF fornecido pelo LangChain para carregar e dividir nossos dados.
Recomendados pelo LinkedIn
# onde nossos embeddings serão armazenados
store = LocalFileStore("./cache/")
# instancia um carregador: isso carrega nossos dados, use PDF neste caso
loader = PyPDFDirectoryLoader("sagemaker-articles/")
# por padrão o carregador de PDF carrega e divide os documentos para nós
pages = loader.load_and_split()
print(len(pages))
Em seguida, instanciamos nosso modelo de embeddings OpenAI. Usamos o modelo Embeddings para criar nossos embeddings e preencher o diretório de cache local que criamos.
# instancia o modelo de incorporação
embeddings_model = OpenAIEmbeddings()
embedder = CacheBackedEmbeddings.from_bytes_store(
embeddings_model,
store
)
Em seguida, criamos nossa FAISS Vector Store e enviamos nossos documentos incorporados.
# criamos armazenamento de vetores, usamos FAISS neste caso
vector_store = FAISS.from_documents(pages, embedder)
Em seguida, usamos uma cadeia RetrievalQA para reunir todas essas partes móveis. Especificamos nosso armazenamento de vetores que criamos acima e também passamos o LLM padrão do ChatOpenAI como nosso modelo que receberá a entrada e os documentos relevantes para o contexto.
# este é todo o sistema de recuperação
medium_qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(),
retriever=vector_store.as_retriever(),
return_source_documents=True,
verbose=True
)
Podemos então comparar o desempenho do modelo sem RAG em oposição à nossa cadeia baseada em RAG, passando os mesmos prompts e observando os resultados. Vamos executar um loop de exemplos de prompts de dificuldades variadas.
sample_prompts = [ "Sobre o que Ram Vegiraju escreve?" ,
"O que é Amazon SageMaker?" ,
"O que é inferência do Amazon SageMaker?" ,
"Quais são as diferentes opções de hospedagem para Amazon SageMaker?" ,
"O que é inferência sem servidor com Amazon SageMaker?" ,
"Qual é a diferença entre endpoints multimodelos e endpoints multicontêineres?" ,
"Quais SDKs posso usar para trabalhar com o Amazon SageMaker?" ]
para prompt em sample_prompts:
#vanilla OpenAI Response
response = openai.Completion.create(
engine= "text-davinci-003" ,
prompt=prompt,
max_tokens = 500 )
# RAG Augmented Response
response_rag = middle_qa_chain({ "query" :prompt })
Vemos que a primeira pergunta em si é muito específica para minha escrita. Sabemos que o modelo OpenAI não tem nenhum acesso ou conhecimento dos artigos, por isso produz uma descrição bastante aleatória e imprecisa.
Alternativamente, nossa rede RAG teve acesso a alguns de meus artigos no Medium e produz um resumo um tanto preciso de minha escrita.
Podemos então testar ambas as abordagens fazendo algumas perguntas específicas ao SageMaker. Começamos com uma pergunta muito básica: O que é Amazon SageMaker? Como o OpenAI LLM tem conhecimento deste assunto, ele responde com uma resposta bastante precisa e comparável à nossa abordagem baseada em RAG.
Começamos a ver os benefícios reais do RAG à medida que as questões começam a ficar mais específicas e difíceis. Um exemplo disso é o prompt comparando as duas opções de hospedagem avançada: Multi-Model Endpoints (MME) e Multi-Container Endpoints (MCE).
Aqui vemos que a resposta do Vanilla OpenAI dá uma resposta completamente imprecisa, pois não tem conhecimento desses dois recursos recentes. Artigo específico do Medium sobre MCE vs MME, no entanto, fornece o contexto do modelo em torno dessas ofertas e, portanto, é capaz de responder à consulta com precisão.
Com o RAG podemos aumentar o conhecimento básico que nosso LLM já possui sobre o SageMaker. Na próxima seção podemos examinar diferentes métodos para melhorar este protótipo que construímos.
Como podemos melhorar o desempenho?
Embora esta seja uma solução interessante, ainda há muito espaço para melhorias. Alguns métodos potenciais que você pode usar para melhorar o desempenho baseado em RAG incluem o seguinte:
Obrigado por ler, fique à vontade para deixar qualquer comentário e fique com Deus! 🙏