Gerando comandos de shell MQL usando OpenAI e o novo shell mongosh
Avalie esse Artigo
OpenAI é uma plataforma de AI fascturante e em crescimento hospedada pela Microsoft, permitindo a você digerir texto de forma habilidosa para produzir conteúdo de AI com resultados surpreendentes, considerando o tamanho do "learning data set " que você realmente fornece.
A Query Language (MQL) do MongoDB é uma linguagem intuitiva para os desenvolvedores interagirem com documentos do MongoDB. Por esse motivo, eu queria colocar a OpenAI no teste de aprender rapidamente a linguagem MongoDB e usar seu conhecimento geral para construir queries a partir de frases simples. Os resultados foram mais do que satisfeitos para me. O Github já está trabalhando em um projeto chamado Github copilot que usa o mesmo mecanismo OpenAI para codificar.
Neste artigo, mostrarei meu experimento, incluindo os recursos de mudança de jogo do novo MongoDB Shell (
mongosh
), que pode estender a script com integrações de módulos npm.OpenAI é um projeto único com o objetivo de fornecer uma API para muitas tarefas de AI construídas principalmente no Processamento de Linguagem Natural atualmente. Você pode ler mais sobre seus projetos neste blog.
Se você quiser usar o OpenAI, precisará obter uma chave de API de teste primeiro, juntando-se à lista deespera na páginaprincipal. Depois de ser aprovado para obter uma chave de API, você receberá cerca de US$18 por três meses de testes. Cada chamada no OpenAI é cobrada e isso é algo a considerar ao usar em produção. Para nossos fins, US$18 é mais que suficiente para testar o mecanismo mais caro chamado “davinci.”
Depois de obter a API key, você pode usar vários clientes para executar a AI API a partir do seu script/aplicativo.
Primeiro, precisamos instalar o novo shell, caso não o tenha feito até agora. No meu laptop Mac, acabou de emitir:
1 brew install mongosh
Os usuários do Windows devem baixar o instalador MSI de nossa página de download e seguir as instruções do Windows.
Quando meu mongosh estiver pronto, posso começar a usá-lo, mas antes de fazer isso, vamos instalar o OpenAI JS, que importaremos no shell mais tarde:
1 $ mkdir openai-test 2 $ cd openai-test 3 Openai-test $ npm i openai-api
Decidi usar o padrão Perguntas e Respostas, na forma de
Q: <Question>
e A: <Answer>
, fornecido ao texto para APIde comandopara fornecer o material de aprendizado sobre MongoDB para o AI. Para melhor atualizá-lo, coloque as perguntas e respostas do treinamento em um arquivo chamado AI-input.txt
e seu conteúdo:1 Q: What is the query syntax? 2 A: db.collection.find(<filter>, <projection> , <options>) 3 Q: Query users collection for username with value "boy" 4 A: db.users.find({"username" : "boy"}) 5 Q: Query users collection for username with value "girl"A: db.users.find({"username" : "girl"}) 6 Q: Query users collection for username with age bigger than 16 7 A: db.users.find({"age" : {$gt : 16}})n; 8 Q: Query author collection for username with value "boy" 9 A: db.authors.find({"username" : "boy"}) 10 Q:Query author collection for age lower than 7 11 A: db.authors.find({"age" : {$lt : 7}}); 12 13 Q:insert a json document into collection authors with username equal to "girl" 14 A: db.authors.insert({"username" : "girl"}, {"age" : 10, "gender" : "female"}) 15 Q: insert many documents into users collections 16 A: db.users.insertMany([{username : "john doe"}, {username : "joe doe"}]); 17 Q: The following aggregation uses $geoNear to find documents with a location at most 2 meters from the center [ -73.99279 , 40.719296 ] and a category equal to Parks. 18 A: db.places.aggregate([{ $geoNear: {near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },distanceField: "dist.calculated",maxDistance: 2, query: { category: "Parks" },includeLocs: "dist.location", spherical: true}}]) 19 Q: How to build atlas $search text query? 20 A: db.collection.aggregate({$search: {"index": <index name> "text": {"query": "<search-string>","path": "<field-to-search>", "fuzzy": <options>,"score": <options> } }}) 21 22 Q: What is the aggregate syntax? 23 A: db.collection.aggregate([<stage1>,<stage2>,<stage3>], <projection> , <options>); 24 Q: aggregate users collection to calculate salary sum per user 25 A: db.users.aggregate([{$group : { _id : "$username" , salary_sum : { $sum : "$salary" }}}]); 26 Q: aggregate person collection to calculate salary sum per person 27 A: db.persons.aggregate([{$group : { _id : "$person" , salary_sum : { $sum : "$salary" }}}]); 28 Q: Lookup users and orders collection 29 A: db.users.aggregate([{$lookup : {from: 'orders', localField : "_id", foreignField : "userId", as : "result" }} ]); 30 31 Q: What is the update syntax? 32 A:db.collection.update(query, update, options) 33 Q: How to edit collection sports where sportname is 'football' and match is 'england vs portugal' to score of '3-3' and date to current date? 34 A: db.sports.update({ sportname: "football", match: "england vs portugal"} , {$set : {score: "3-3" , date : new Date()}} }) 35 Q: Query and atomically update collection zoo where animal is "bear" with a counter increment on eat field, if the data does not exist user upsert 36 A: db.zoo.findOneAndUpdate({animal : "bear"}, {$inc: { eat : 1 }} , {upsert : true})
Usaremos este arquivo mais tarde em nosso código.
Dessa forma, a conclusão será baseada em um padrão semelhante.
O MongoDB Atlas, o serviço de banco de dados como plataforma, é uma ótima maneira de ter um cluster em execução em segundos com um conjunto de dados de amostra já lá para nosso teste. Para prepará-lo, use as seguintes etapas:
- Crie uma conta Atlas (se ainda não tiver uma) e use/inicie um cluster. Para obter etapas detalhadas, siga esta documentação.
Use a connection string copiada, fornecendo-a ao binário
mongosh
para se conectar ao Atlas cluster pré-preenchido com dados de amostra. Em seguida, mude para o banco de dados dosample_restaurants
.1 mongosh "mongodb+srv://<u>:<p>@<atlas-uri>/sample_restaurants" 2 Using Mongosh : X.X.X 3 Using MongoDB: X.X.X 4 5 For mongosh info see: https://docs.mongodb.com/mongodb-shell/ 6 7 ATLAS atlas-ugld61-shard-0 [primary]> use sample_restaurants;
Agora, podemos construir nossa função
textToMql
colando-a no mongosh
. A função receberá uma frase de texto, usará nossa chave API OpenAI gerada e tentará retornar o melhor comando MQL para ela:1 async function textToMql(query){ 2 3 const OpenAI = require('openai-api'); 4 const openai-client = new OpenAI("<YOUR-OPENAI-API-KEY>"); 5 6 const fs = require('fs'); 7 8 var data = await fs.promises.readFile('AI-input.txt', 'utf8'); 9 10 const learningPath = data; 11 12 var aiInput = learningPath + "Q:" + query + "\nA:"; 13 14 const gptResponse = await openai-client.complete({ 15 engine: 'davinci', 16 prompt: aiInput, 17 "temperature": 0.3, 18 "max_tokens": 400, 19 "top_p": 1, 20 "frequency_penalty": 0.2, 21 "presence_penalty": 0, 22 "stop": ["\n"] 23 }); 24 25 console.log(gptResponse.data.choices[0].text); 26 }
Na função acima, primeiro carregamos o módulo npm do OpenAI e iniciamos um cliente com a chave de API relevante do OpenAI.
1 const OpenAI = require('openai-api'); 2 const openai-client = new OpenAI("<YOUR-OPENAI-API-KEY>"); 3 4 const fs = require('fs');
O novo shell nos permite importar módulosintegrados e externos para produzir uma flexibilidade ilimitada com nossos scripts.
Em seguida, lemos os dados de aprendizado do nosso arquivo
AI-input.txt
. Por fim, adicionamos nossa entradaQ: <query>
ao final, seguida pelo valorA:
, que informa ao mecanismo que esperamos uma resposta com base no learningPath fornecido e em nossa consulta.Esses dados irão Go para uma chamada de API OpenAI:
1 const gptResponse = await openai.complete({ 2 engine: 'davinci', 3 prompt: aiInput, 4 "temperature": 0.3, 5 "max_tokens": 400, 6 "top_p": 1, 7 "frequency_penalty": 0.2, 8 "presence_penalty": 0, 9 "stop": ["\n"] 10 });
A chamada executa uma API de conclusão e obtém todo o texto inicial como
prompt
e recebe alguns parâmetros adicionais, que detalharei:engine
: O OpenAI suporta alguns mecanismos de AI que diferem em qualidade e finalidade em troca de preços. O motor "davinci" é o mais sofisticado, de acordo com a OpenAI, e, portanto, é o mais caro em termos de consumo de faturamento.temperature
: quão criadora será o AI em comparação com as informações que demos a ele? Pode ser entre 0e1. 0.3 parece um valor simples, mas você pode jogar com ele.Max_tokens
: descreve a quantidade de dados que serão retornados.Stop
: Lista de personagens que impedirão o motor de produzir mais conteúdo. Como precisamos produzir declarações MQL, ela será baseada em uma linha e "\n " será um caractere de parada.
Depois que o conteúdo for retornado, analisamos o JSON retornado e o imprimimos com
console.log
.Assim que tivermos nossa função em vigor, podemos tentar produzir uma consulta simples para testá-la:
1 Atlas atlas-ugld61-shard-0 [primary] sample_restaurants> textToMql("query all restaurants where cuisine is American and name starts with 'Ri'") 2 db.restaurants.find({cuisine : "American", name : /^Ri/}) 3 4 Atlas atlas-ugld61-shard-0 [primary] sample_restaurants> db.restaurants.find({cuisine : "American", name : /^Ri/}) 5 [ 6 { 7 _id: ObjectId("5eb3d668b31de5d588f4292a"), 8 address: { 9 building: '2780', 10 coord: [ -73.98241999999999, 40.579505 ], 11 street: 'Stillwell Avenue', 12 zipcode: '11224' 13 }, 14 borough: 'Brooklyn', 15 cuisine: 'American', 16 grades: [ 17 { 18 date: ISODate("2014-06-10T00:00:00.000Z"), 19 grade: 'A', 20 score: 5 21 }, 22 { 23 date: ISODate("2013-06-05T00:00:00.000Z"), 24 grade: 'A', 25 score: 7 26 }, 27 { 28 date: ISODate("2012-04-13T00:00:00.000Z"), 29 grade: 'A', 30 score: 12 31 }, 32 { 33 date: ISODate("2011-10-12T00:00:00.000Z"), 34 grade: 'A', 35 score: 12 36 } 37 ], 38 name: 'Riviera Caterer', 39 restaurant_id: '40356018' 40 } 41 ...
Que legal! Nunca ensinamos ao mecanismo sobre a collection
restaurants
ou como filtrar com operadoresregex, mas ele ainda tomava as decisões corretas de AI.Vamos fazer algo mais Criativo.
1 Atlas atlas-ugld61-shard-0 [primary] sample_restaurants> textToMql("Generate an insert many command with random fruit names and their weight") 2 db.fruits.insertMany([{name: "apple", weight: 10}, {name: "banana", weight: 5}, {name: "grapes", weight: 15}]) 3 Atlas atlas-ugld61-shard-0 [primary]sample_restaurants> db.fruits.insertMany([{name: "apple", weight: 10}, {name: "banana", weight: 5}, {name: "grapes", weight: 15}]) 4 { 5 acknowledged: true, 6 insertedIds: { 7 '0': ObjectId("60e55621dc4197f07a26f5e1"), 8 '1': ObjectId("60e55621dc4197f07a26f5e2"), 9 '2': ObjectId("60e55621dc4197f07a26f5e3") 10 } 11 }
1 Atlas atlas-ugld61-shard-0 [primary] sample_restaurants> use sample_mflix; 2 Atlas atlas-ugld61-shard-0 [primary] sample_mflix> textToMql("Aggregate the count of movies per year (sum : 1) on collection movies") 3 db.movies.aggregate([{$group : { _id : "$year", count : { $sum : 1 }}}]); 4 5 Atlas atlas-ugld61-shard-0 [primary] sample_mflix> db.movies.aggregate([{$group : { _id : "$year", count : { $sum : 1 }}}]); 6 [ 7 { _id: 1967, count: 107 }, 8 { _id: 1986, count: 206 }, 9 { _id: '2006è2012', count: 2 }, 10 { _id: 2004, count: 741 }, 11 { _id: 1918, count: 1 }, 12 { _id: 1991, count: 252 }, 13 { _id: 1968, count: 112 }, 14 { _id: 1990, count: 244 }, 15 { _id: 1933, count: 27 }, 16 { _id: 1997, count: 458 }, 17 { _id: 1957, count: 89 }, 18 { _id: 1931, count: 24 }, 19 { _id: 1925, count: 13 }, 20 { _id: 1948, count: 70 }, 21 { _id: 1922, count: 7 }, 22 { _id: '2005è', count: 2 }, 23 { _id: 1975, count: 112 }, 24 { _id: 1999, count: 542 }, 25 { _id: 2002, count: 655 }, 26 { _id: 2015, count: 484 } 27 ]
Esse éo poder de AI dos pipelines MongoDB !
O novo shell do MongoDB nos permite criar scripts com um poder enorme como nunca antes, utilizando pacotes externos npm. Junto com o poder dos sofisticados padrões de AI do OpenAI, pudemos ensinar o shell a solicitar texto a comandos complexos e precisos do MongoDB e, com mais aprendizado e ajustes, provavelmente poderemos obter resultados muito melhores.
Experimente isso hoje mesmo usando o novo shell MongoDB.