Colocando o RAG em produção com o chatbot de IA da documentação do MongoDB
Avalie esse Artigo
No MongoDB, temos um slogan: "Ame seus desenvolvedores". Uma forma de demonstrarmos amor aos nossos desenvolvedores é oferecendo uma excelente documentação técnica para nossos produtos. Dado o surgimento de tecnologias de IA generativa, como o ChatGPT, queríamos usar a IA generativa para ajudar os desenvolvedores a aprender sobre nossos produtos usando linguagem natural. Isso nos levou a criar um chatbot de IA que permite que os usuários conversem diretamente com nossa documentação. Com o chatbot de IA sobre a documentação, os usuários podem fazer perguntas e obter respostas e conteúdo relacionado de forma mais eficiente e intuitiva do que era possível anteriormente.
Esta publicação fornece uma visão geral técnica de como construímos o chatbot de IA para a documentação. Ele abrange:
- Arquitetura de geração aumentada de recuperação (RAG) do chatbot.
- Os desafios na criação de um chatbot RAG para a documentação do MongoDB.
- Como criamos o chatbot para superar esses desafios.
- Como usamos o MongoDB Atlas no aplicativo.
- Próximas etapas para criar seu próprio aplicativo RAG de produção usando o MongoDB Atlas.
Construímos nosso chatbot usando a arquitetura de geração aumentada de recuperação (RAG). A RAG aumenta o conhecimento de grandes modelos de linguagem (LLMs) recuperando informações relevantes para as queries dos usuários e usando essas informações na resposta gerada pelo LLM. Usamos a documentação pública do MongoDB como fonte de informações para as respostas geradas pelo nosso chatbot.
Para recuperar informações relevantes com base nas consultas dos usuários, usamos o MongoDB Atlas Vector Search. Usamos a API Azure OpenAI do ChatGPT para gerar respostas às perguntas dos usuários com base nas informações retornadas do Atlas Vector Search. Usamos a API de incorporações do Azure OpenAI para converter a documentação do MongoDB e as queries de usuário em incorporações vetoriais, o que nos ajuda a encontrar o conteúdo mais relevante para queries usando o Atlas Vector Search.
Este é um diagrama de alto nível da arquitetura RAG do chatbot:
Para obter uma explicação mais detalhada do RAG, acesse nossa visão geral do uso do MongoDB para RAG.
Ao longo dos últimos meses, muitas ferramentas e arquiteturas de referência foram lançadas para a criação de aplicativos RAG. Decidimos que faria mais sentido começar simples e, em seguida, iterar com nosso design assim que tivéssemos um produto mínimo viável (MVP) funcional.
Nossa primeira iteração foi o que Gerry Liu, criador do framework RAG LlamaIndex, chama de "RAG ingênuo". Esta é a forma mais simples de RAG. Nossa implementação ingênua de RAG tinha o seguinte fluxo:
- Ingestão de dados: ingestão de dados de origem no MongoDB Atlas, divisão de documentos em partes menores e armazenamento de cada parte com sua incorporação vetorial. Indexar as incorporações vetoriais usando o MongoDB Atlas Vector Search.
- Chat: gerar uma resposta criando uma incorporação para a pergunta do usuário, encontrando partes correspondentes com o MongoDB Atlas Vector Search e, em seguida, resumindo uma resposta usando essas partes.
Colocamos um protótipo de RAG naive razoavelmente funcional em operação com uma equipe pequena em menos de dois meses. Para avaliar a qualidade das respostas e links gerados, os funcionários do MongoDB se ofereceram para testar o chatbot em um exercício de red teaming.
Para saber mais sobre a abordagem que adotamos para o red teaming, consulte a documentação da Microsoft.
O exercício de red teaming revelou que o chatbot RAG naive forneceu respostas satisfatórias em aproximadamente 60% das vezes.
Para 40% das respostas que foram insatisfatórias, notamos alguns temas comuns:
- O chatbot não estava ciente das mensagens anteriores na conversa.
Por exemplo, a conversa pode ser assim:
1 User: how to create a cluster atlas 2 Chatbot: To create a MongoDB Atlas cluster using the CLI, you can use the `mongocli atlas quickstart` command... 3 User: how to with UI 4 Chatbot: I'm sorry, I don't know what you mean...
- O chatbot às vezes fornecia soluções muito específicas quando uma resposta mais geral teria sido útil. O MongoDB tem muitos produtos com funcionalidades sobrepostas (drivers de banco de dados em várias linguagens, MongoDB no Atlas e auto-hospedado, etc.) e sem uma prioridade clara, ele poderia escolher um aleatoriamente.
Por exemplo, a conversa pode ser assim:
1 User: how to connect to mongodb 2 Chatbot: To connect to MongoDB you can use the Java Driver...
- Os links de leitura adicional do chatbot não eram consistentemente relevantes.
Por exemplo, a conversa pode ser assim:
1 User: write data to mongodb node.js 2 Chatbot: /* Reasonable generated answer */ 3 4 Further reading: 5 - https://www.mongodb.com/pt-br/docs/drivers/node/current/usage-examples/insertOne/ (👍) 6 - https://www.mongodb.com/developer/languages/javascript/node-connect-mongodb/ (👍) 7 - https://www.mongodb.com/developer/products/realm/realm-meetup-javascript-react-native/ (🤷)
Para levar o chatbot a um lugar onde nos sentíssemos confortáveis em colocá-lo no mundo, precisávamos lidar com essas limitações.
Esta seção aborda como criamos a documentação do chatbot da IA para abordar as limitações mencionadas anteriormente do RAG ingênuo para criar um chatbot não tão ingênuo que responda melhor às perguntas dos usuários.
Usando a abordagem descrita nesta seção, obtivemos o chatbot para mais de 80% de respostas satisfatórias em um exercício de avaliação de vulnerabilidades.
Configuramos um CLI para ingestão de dados, extraindo conteúdo da documentação do MongoDB e do Centro de desenvolvedores. Uma tarefa cron noturna garante que as informações do chatbot permaneçam atuais.
Nosso pipeline de ingestão envolve dois estágios principais:
Criamos um comando CLI
pages
que extrai conteúdo bruto de fontes de dados para o Markdown para o chatbot usar. Este estágio lida com formatos de conteúdo variados, incluindo árvores de sintaxe abstrata, HTML e Markdown. Armazenamos esses dados brutos em uma coleção pages
no MongoDB.Exemplo de comando
pages
:1 ingest pages --source docs-atlas
Um comando
embed
CLI pega os dados da coleção pages
e os transforma em um formulário que o chatbot pode usar, além de gerar incorporações vetoriais para o conteúdo. Armazenamos o conteúdo transformado na coleção embedded_content
, indexada usando o Atlas Vector Search do MongoDB.Exemplo de comando
embed
:1 ingest embed --source docs-atlas \ 2 --since 2023-11-07 # only update documentation changed since this time
Para transformar nossos documentos
pages
em documentos embedded_content
, usamos a seguinte estratégia: divida cada página em uma ou mais partes usando o LangChain RecursiveCharacterTextSplitter. Usamos o RecursiveCharacterTextSplitter para dividir o texto em partes lógicas, como manter as seções da página (conforme indicado pelos cabeçalhos) e os exemplos de código juntos. Permita o tamanho máximo da parte de 650 tokens. Isso levou a um tamanho médio de 450 tokens, que se alinha com as melhores práticas emergentes. Remova todas as partes com menos de 15 tokens de comprimento. Às vezes, eles apareciam nos resultados da pesquisa vetorial porque correspondiam à query do usuário, embora fornecessem pouco valor para informar a resposta gerada pela API ChatGPT. Adicione metadados ao início de cada parte antes de criar a incorporação. Isso dá ao pedaço um significado semântico maior para criar a incorporação. Consulte a seção a seguir para obter mais informações sobre como a adição de metadados melhorou muito a qualidade de nossos resultados de pesquisa vetorial.O aprimoramento mais importante que fizemos no chunking e na incorporação foi anexar partes com metadados. Por exemplo, digamos que você tenha este trecho de texto sobre como usar o MongoDB Atlas Vector Search:
1 ### Procedure 2 3 <Tabs> 4 5 <Tab name="MongoDB Atlas"> 6 7 #### Go to the Search Tester. 8 9 - Click the cluster name to view the cluster details. 10 11 - Click the Search tab. 12 13 - Click the Query button to the right of the index to query. 14 15 #### View and edit the query syntax. 16 17 Click Edit $search Query to view a default query syntax sample in JSON (Javascript Object Notation) format.
Essa parte em si tem informações relevantes sobre como realizar uma pesquisa semântica nos dados do Atlas, mas faltam dados de contexto que o tornem mais provável de ser encontrado nos resultados da pesquisa.
Antes de criar a incorporação vetorial para o conteúdo, adicionamos metadados ao topo da parte para alterá-la para:
1 --- 2 tags: 3 - atlas 4 - docs 5 productName: MongoDB Atlas 6 version: null 7 pageTitle: How to Perform Semantic Search Against Data in Your Atlas Cluster 8 hasCodeBlock: false 9 --- 10 11 ### Procedure 12 13 <Tabs> 14 15 <Tab name="MongoDB Atlas"> 16 17 #### Go to the Search Tester. 18 19 - Click the cluster name to view the cluster details. 20 21 - Click the Search tab. 22 23 - Click the Query button to the right of the index to query. 24 25 #### View and edit the query syntax. 26 27 Click Edit $search Query to view a default query syntax sample in JSON (Javascript Object Notation) format.
Adicionar esses metadados à parte melhorou muito a qualidade de nossos resultados de pesquisa, principalmente quando combinado com a adição de metadados à query do usuário no servidor antes de usá-los na pesquisa vetorial, conforme discutido na seção “Chat Server”.
Este é um documento de exemplo da coleção
embedded_content
. O campo embedding
é indexado com o MongoDB Atlas Vector Search.1 { 2 _id: new ObjectId("65448eb04ef194092777bcf6") 3 chunkIndex: 4, 4 sourceName: "docs-atlas", 5 url: "https://mongodb.com/pt-br/docs/atlas/atlas-vector-search/vector-search-tutorial/", 6 text: '---\ntags:\n - atlas\n - docs\nproductName: MongoDB Atlas\nversion: null\npageTitle: How to Perform Semantic Search Against Data in Your Atlas Cluster\nhasCodeBlock: false\n---\n\n### Procedure\n\n<Tabs>\n\n<Tab name="MongoDB Atlas">\n\n#### Go to the Search Tester.\n\n- Click the cluster name to view the cluster details.\n\n- Click the Search tab.\n\n- Click the Query button to the right of the index to query.\n\n#### View and edit the query syntax.\n\nClick Edit $search Query to view a default query syntax sample in JSON (Javascript Object Notation) format.', 7 tokenCount: 151, 8 metadata: { 9 tags: ["atlas", "docs"], 10 productName: "MongoDB Atlas", 11 version: null, 12 pageTitle: "How to Perform Semantic Search Against Data in Your Atlas Cluster", 13 hasCodeBlock: false, 14 }, 15 embedding: [0.002525234, 0.038020607, 0.021626275 /* ... */], 16 updated: new Date() 17 };
Construímos um servidor Express.js para coordenar o RAG entre o usuário, a documentação do MongoDB e a API do ChatGPT. Usamos o Atlas Vector Search do MongoDB para realizar uma pesquisa vetorial no conteúdo ingerido na coleção
embedded_content
. Persistimos as informações da conversa, incluindo mensagens de usuário e chatbot, para uma coleção conversations
no mesmo MongoDB database.O servidor Express.js é uma API RESTful bastante direta com três rotas:
POST /conversations
: cria uma nova conversa.POST /conversations/:conversationId/messages
: adicione uma mensagem de usuário a uma conversa e obtenha de volta uma resposta RAG à mensagem de usuário. Esta rota tem o parâmetro opcionalstream
para transmitir de volta uma resposta ou enviá-la como um objeto JSON.POST /conversations/:conversationId/messages/:messageId/rating
: avalia uma mensagem.
A maior parte da complexidade do servidor estava na rota
POST /conversations/:conversationId/messages
, pois ela lida com todo o fluxo de RAG.Conseguimos fazer melhorias significativas em relação à nossa implementação inicial do RAG básico adicionando o que chamamos de pré-processador de query.
Um pré-processador de query transforma a query original do usuário em algo que seja mais relevante para uma conversa e obtenha melhores resultados de pesquisa vetorial.
Por exemplo, digamos que o usuário insira a seguinte query no chatbot:
1 $filter
Por si só, essa query tem pouco significado semântico inerente e não apresenta uma pergunta clara para a API do chatGPT responder.
No entanto, usando um pré-processador de query, transformamos essa query em:
1 --- 2 programmingLanguages: 3 - shell 4 mongoDbProducts: 5 - MongoDB Server 6 - Aggregation Framework 7 --- 8 What is the syntax for filtering data in MongoDB?
Em seguida, o servidor de aplicativos envia essa query transformada no MongoDB Atlas Vector Search. Ela produz resultados de pesquisa muito melhores do que a query original. A query de pesquisa tem mais significado semântico e também se alinha com os metadados que anexamos durante a ingestão de conteúdo para criar um grau mais alto de similaridade semântica para a pesquisa vetorial.
Adicionar as informações
programmingLanguage
e mongoDbProducts
à query concentra a pesquisa vetorial para criar uma resposta baseada em um subconjunto específico da área de superfície total do conjunto de produtos do MongoDB. Por exemplo, aqui não queremos que o chatbot retorne resultados para usar o driver PHP para realizar agregações$filter
, mas a pesquisa vetorial teria mais probabilidade de retornar isso se não especificássemos que estamos procurando exemplos que usam o shell.Além disso, instruir a API do ChatGPT a responder à pergunta "Qual é a sintaxe para filtrar dados no MongoDB?" fornece uma resposta mais clara do que dizer para responder ao "$filter" original.
Para criar um pré-processador que transforma a query como esta, usamos a biblioteca TypeChat. TypeChat pega uma entrada de string e a transforma em um objeto JSON usando a API ChatGPT. TypeChat usa tipos TypeScript para descrever a forma dos dados de saída.
O tipo TypeScript que usamos em nosso aplicativo é o seguinte:
1 /** 2 You are an AI-powered API that helps developers find answers to their MongoDB 3 questions. You are a MongoDB expert. Process the user query in the context of 4 the conversation into the following data type. 5 */ 6 export interface MongoDbUserQueryPreprocessorResponse { 7 /** 8 One or more programming languages present in the content ordered by 9 relevancy. If no programming language is present and the user is asking for 10 a code example, include "shell". 11 @example ["shell", "javascript", "typescript", "python", "java", "csharp", 12 "cpp", "ruby", "kotlin", "c", "dart", "php", "rust", "scala", "swift" 13 ...other popular programming languages ] 14 */ 15 programmingLanguages: string[]; 16 17 /** 18 One or more MongoDB products present in the content. Which MongoDB products 19 is the user interested in? Order by relevancy. Include "Driver" if the user 20 is asking about a programming language with a MongoDB driver. 21 @example ["MongoDB Atlas", "Atlas Charts", "Atlas Search", "Aggregation 22 Framework", "MongoDB Server", "Compass", "MongoDB Connector for BI", "Realm 23 SDK", "Driver", "Atlas App Services", ...other MongoDB products] 24 */ 25 mongoDbProducts: string[]; 26 27 /** 28 Using your knowledge of MongoDB and the conversational context, rephrase the 29 latest user query to make it more meaningful. Rephrase the query into a 30 question if it's not already one. The query generated here is passed to 31 semantic search. If you do not know how to rephrase the query, leave this 32 field undefined. 33 */ 34 query?: string; 35 36 /** 37 Set to true if and only if the query is hostile, offensive, or disparages 38 MongoDB or its products. 39 */ 40 rejectQuery: boolean; 41 }
Em nosso aplicativo, o TypeChat usa o esquema
MongoDbUserQueryPreprocessorResponse
e a descrição para criar um objeto estruturado nesse esquema.Em seguida, usando uma função JavaScript simples, transformamos o objeto
MongoDbUserQueryPreprocessorResponse
em uma query para enviar para incorporar e depois enviar para o MongoDB Atlas Vector Search.Também temos o campo
rejectQuery
para sinalizar se uma query for inadequada. Quando o rejectQuery: true
, o servidor retorna uma resposta estática ao usuário, solicitando que tente uma query diferente.Nosso frontend é um componente React criado com o LeafyGreen Design System. O componente regula a interação com a API RESTful do servidor de chat.
Atualmente, o componente está apenas na página inicial de documentos do MongoDB, mas o construímos de forma que ele possa ser estendido para ser usado em outras propriedades do MongoDB.
Veja aqui como é o chatbot em ação:
A criação do chatbot no MongoDB Atlas foi um grande acelerador para a produtividade de nossos desenvolvedores e nos ajudou a simplificar nossa infraestrutura.
A configuração do MongoDB Atlas Vector Search em nosso cluster levou apenas alguns cliques na IU e a adição do seguinte índice do Atlas Vector Search ao campo
embedding
da coleção embedded_content
:1 { 2 "type": "vectorSearch, 3 "fields": [{ 4 "path": "embedding", 5 "dimensions": 1536, 6 "similarity": "cosine", 7 "type": "vector" 8 }] 9 }
Executar queries usando o índice do MongoDB Atlas Vector Search é uma operação de agregação simples com o operador
$vectorSearch
usando o Node.js driver: 1 export async function getVectorSearchResults( 2 collection: Collection, 3 vectorEmbedding: number[], 4 filterQuery: Filter<any> 5 ) { 6 return collection 7 .aggregate<WithScore<EmbeddedContents>>([ 8 { 9 $vectorSearch: { 10 index: "default", 11 vector: vectorEmbedding, 12 path: "embedding", 13 filter: filterQuery, 14 limit: 3, 15 numCandidates: 30 16 }, 17 }, 18 { 19 $addFields: { 20 score: { 21 $meta: "vectorSearchScore", 22 }, 23 }, 24 }, 25 { $match: { score: { $gte: 0.8 } } }, 26 ]) 27 .toArray(); 28 }
O uso do MongoDB para armazenar os dados de
conversations
simplificou a experiência de desenvolvimento, pois não tivemos que pensar em usar um armazenamento de dados para as incorporações separado do restante dos dados do aplicativo.O uso do MongoDB Atlas para pesquisa vetorial e como nosso armazenamento de dados de aplicativos simplificou nosso processo de desenvolvimento de aplicativos para que pudéssemos nos concentrar na lógica principal do aplicativo RAG e não ter que pensar muito em gerenciar infraestrutura adicional ou aprender novas linguagens de query específicas de domínio.
O chatbot de AI de documentação do MongoDB já está no ar há mais de um mês e funciona muito bem (experimente!). Ele ainda está em desenvolvimento e vamos distribuí-lo a outros locais no conjunto de produtos do MongoDB nos próximos meses.
Aqui estão alguns de nossos principais aprendizados ao levar o chatbot para a produção:
- O RAG básico não é suficiente. No entanto, começar com um protótipo RAG básico é uma ótima maneira de descobrir como você precisa estender o RAG para atender às necessidades do seu caso de uso.
- O red teaming é incrivelmente útil para identificar problemas. Faça isso no início do processo de desenvolvimento do aplicativo RAG, e com frequência.
- Adicione metadados ao conteúdo antes de criar incorporações para melhorar a qualidade das pesquisas.
- Pré-processe as queries do usuário com um LLM (como a API do ChatGPT e o TypeChat) antes de enviá-las para a pesquisa vetorial e fazer com que o LLM responda ao usuário. O pré-processador deve:
- Tornar a query mais relevante em termos de conversa e semântica.
- Incluir metadados para usar na pesquisa vetorial.
- Capture todos os cenários, como queries inadequadas, que você deseja tratar fora do fluxo normal do RAG.
- O MongoDB Atlas é um ótimo banco de dados para criar aplicativos RAG de produção.
Deseja criar seu próprio aplicativo RAG? Disponibilizamos nosso código-fonte publicamente como uma arquitetura de referência. Dê uma olhada no GitHub.
Também estamos trabalhando no lançamento de um framework de código aberto para simplificar a criação de aplicativos RAG usando o MongoDB. Fique atento para mais atualizações sobre esse framework RAG.
Principais comentários nos fóruns
Leo_CrownLeo Crownúltimo trimestre
St_Coleman St.Colemanúltimo trimestre
Artigo incrível.
Eu gostaria de saber como você lida com a atualização de incorporações? Você as substitui totalmente quando o conteúdo muda e, se for o caso, como lida com o impacto do custo?
Além disso, quais são alguns critérios que você conseguiu identificar que fariam com que uma atualização fosse feita? (por exemplo: se um erro de digitação foi cometido, talvez não valha a pena atualizar)
Agradecemos por compartilhar sua opinião conosco.
Hi,
Estou curioso para saber como você lida com a atualização de incorporações. Você as substitui completamente quando o conteúdo muda? Se sim, como faz para gerenciar o impacto de custo?
Além disso, quais critérios você usa para determinar quando uma atualização é necessária? Por exemplo, um pequeno erro de digitação justificaria uma atualização ou há mudanças mais significativas que acionam esse processo?
Agradecemos por compartilhar sua opinião conosco!
Isto parece bom para você?