Dieser Artikel konzentriert sich auf die Verwendung der Node.js- Bibliothek von OpenAI zum Erstellen einer CLI , die das Davinci-Modell in Mathematik trainiert.
cd ~/Dev/YourRootFolderForPersonalStuff/ mdkir davinci-is-bad-at-maths cd davinci-is-bad-at-maths npm i dotenv openai npm i prettier -D touch .env touch goodAtMathsDatasetBuilder.js touch openAI.js mkdir bin touch bin/cli.js
package.json
... kann einfach sein, so:
{ "description": "Experiments using OpenAI's API NodeJs v4 library", "name": "davinci-is-bad-at-maths", "private": true, "bin": "./bin/cli.js", "dependencies": { "dotenv": "^16.3.1", "openai": "^4.0.0" }, "devDependencies": { "prettier": "^3.0.2" }, "main": "openAI.js", "scripts": { "cli": "node bin/cli.js", "prettier": "prettier --list-different --write \"**/*.{css,html,js,json,md,mjs,scss,ts,yaml}\"" }, "type": "module" }
Der Eintrag „cli“ in Skripten bedeutet, dass wir npm run cli -- commandName [args]
aufrufen können. Wenn Sie dies anstelle von node bin/cli.js commandName [args]
verwenden, bedeutet dies, dass Sie den Verlauf Ihrer Shell beibehalten, auch wenn Sie später die App-Struktur oder den Namen von cli.js
ändern. Einfache Dinge gefallen einfachen Köpfen und ich habe einen einfachen Geist.
.env
... muss so aussehen, aber mit Ihrem eigenen API_KEY:
OPENAI_API_KEY="sk-d0ntY0uD4reUs3MyK3yG3tY0urOwnFr0mOp0n41W36s1t3Yo" OPENAI_MODEL="davinci"
Öffnen Sie openAI.js
und kopieren Sie dies in:
/** A not-robust OpenAI v4 CLI; a playground for OpenAI v4 API calls; a utility for working with a OpenAI model who is really really, like - I mean - really bad at maths. * @usage * >> import commandHub from "openAI.js" * >> const [, , command, ...args] = process.argv * >> const commandFunc = commandHub[command] * >> commandFunc(...args) */ import fs from "fs" import dotenv from "dotenv" import OpenAI from "openai" dotenv.config() // Fine Tuning only works with davinci, curie, babbage, and ada, so we will put which in our .env file so that we can call the same one consistently. const model = process.env.OPENAI_MODEL // Instantiate the API object. const apiKey = process.env.OPENAI_API_KEY const openai = new OpenAI({ apiKey }) /** openai.chat.completions.create * @usage * >> npm run cli -- chatCompletionsCreate "2+8=?" * @param {String} chatPrompt your sum to an assistent who is (usually) good at maths */ export const chatCompletionsCreate = async chatPrompt => { const res = await openai.chat.completions.create({ messages: [ { role: "system", content: "You are good at maths." }, { role: "user", content: chatPrompt }, ], model: model, }) console.log("chatCompletionsCreate", res.choices) } /** openai.completions.create * @tutorial * Normally we would use `chatCompletionsCreate` but for Fine Tuned models we must use base models and therefore `completionsCreate`. * @usage * >> npm run cli -- completionsCreate "2+8=?" * @param {String} chatPrompt your sum to an assistent who is (usually) good at maths */ export const completionsCreate = async chatPrompt => { const res = await openai.completions.create({ model: model, prompt: chatPrompt, temperature: 0, }) console.log("completionsCreate", res) } /** openai.files.create and output to `openai.files.create.json` * @usage * >> npm run cli -- filesCreate bad-at-maths-fine-tuning-dataset.jsonl * @param {String} filePath of JSONLD file to upload. */ export const filesCreate = async filePath => { const res = await openai.files.create({ file: fs.createReadStream(filePath), purpose: "fine-tune", }) console.log("filesCreate", res) fs.writeFileSync( "openai.files.create.json", JSON.stringify(res, null, 2), "utf-8", ) } // openai.files.del /** openai.files.list and output to `openai.files.list.json` * @usage * >> npm run cli -- filesList */ export const filesList = async () => { const res = await openai.files.list() console.log("filesList", res) fs.writeFileSync( "openai.files.list.json", JSON.stringify(res, null, 2), "utf-8", ) } // openai.files.retrieve // openai.files.retrieveContent /** openai.fineTunes.create * @usage * >> npm run cli -- fineTunesCreate "bad-at-maths-fine-tuning-dataset.jsonl" "is-good-at-maths" * @param {String} fileId of previously uploaded file where `purpose: "fine-tune"`. * @param {String} suffix to add to the resulting model name for easily id later. */ export const fineTunesCreate = async (fileId, suffix) => { const res = await openai.fineTunes.create({ training_file: fileId, suffix: suffix, model: model, }) console.log("fineTunesCreate", res) fs.writeFileSync( "openai.fineTunes.create.json", JSON.stringify(res, null, 2), "utf-8", ) } /** openai.fineTunes.list * @usage * >> npm run cli -- fineTunesList */ export const fineTunesList = async () => { const res = await openai.fineTunes.list() console.log("fineTunesList", res) fs.writeFileSync( "openai.fineTunes.list.json", JSON.stringify(res, null, 2), "utf-8", ) } // openai.fineTunes.cancel // openai.fineTunes.retrieve // openai.fineTunes.listEvents // openai.models.del // openai.models.list // openai.models.del // openai.images.generate // openai.images.edit // openai.images.createVariation // openai.audio.transcriptions.create // openai.audio.translations.create // openai.edits.create // openai.embeddings.create // openai.moderations.create // A command hub. const commandHub = { chatCompletionsCreate, completionsCreate, filesCreate, filesList, fineTunesCreate, fineTunesList, } export default commandHub
Sie werden feststellen, dass ich alle verfügbaren Endpunkte in der OpenAI -Bibliothek in dieser Datei belassen habe, die ich Ihnen als Übung zum Erstellen eines nützlichen Moduls hinzufügen kann.
Öffnen Sie bin/cli.js und fügen Sie Folgendes ein:
#!/usr/bin/env node /** A not-very-robust OpenAI v4 CLI; a playground for OpenAI v4 API calls; a utility for working with a OpenAI model who is really really, like - I mean - really bad at maths. * @usage with "cli" in "scripts" (don't forget the "--"). * >> npm cli -- commandName [arg1 arg2 ...arg(n)] */ import commandHub from "../openAI.js" const [, , command, ...args] = process.argv // Call the requested command. Not a robust CLI but it gets the job done! if (!commandHub.hasOwnProperty(command)) { throw "No such command as `" + command + "`" } else { const commandFunc = commandHub[command] commandFunc(...args) }
ChatGPT sollte keine Probleme haben, irgendwelche Summen zu beantworten, da ChatGPT (normalerweise) gut in Mathematik ist, was wir wie folgt beweisen (und unsere CLI testen) können:
OPENAI_API_KEY="sk-d0ntY0uD4reUs3MyK3yG3tY0urOwnFr0mOp0n41W36s1t3Yo" OPENAI_MODEL="gpt-3.5-turbo"
npm run cli -- chatCompletionsCreate "12+4`.
Sehen? Gut in Mathe.
Zu einem späteren Zeitpunkt, wenn es möglich wird, Chatbot-Modelle wie „gpt-3.5-turbo“ zu verfeinern, werden wir sie so verfeinern, dass sie schlecht in Mathematik sind.
Der Teil --
ist erforderlich, um sicherzustellen, dass die Parameter korrekt an NPM übergeben werden. Ich werde nicht näher darauf eingehen, weil ich nicht weiß, warum. Vielleicht. Das ist gut. Sag mir Bescheid, wenn du es weißt. Ich weiß nur, dass man es tun muss, damit es funktioniert, und das ist eine Tatsache.
NB: So würden Sie das Gleiche auch außerhalb unserer CLI tun:
import dotenv from "dotenv" import OpenAI from "openai" const apiKey = process.env.OPENAI_API_KEY const model = process.env.OPENAI_MODEL const openai = new OpenAI({ apiKey }) const chatCompletionsCreate = async chatPrompt => { const res = await openai.chat.completions.create({ messages: [ { role: "system", content: "You are good at maths." }, { role: "user", content: chatPrompt }, ], model: model, }) console.log("chatCompletionsCreate", res.choices) } chatCompletionsCreate("12+4")
OPENAI_API_KEY="sk-d0ntY0uD4reUs3MyK3yG3tY0urOwnFr0mOp0n41W36s1t3Yo" OPENAI_MODEL="davinci"
npm run cli -- completionsCreate "12+4`.
NB: So würden Sie das Gleiche auch außerhalb unserer CLI tun:
import fs from "fs" import dotenv from "dotenv" import OpenAI from "openai" const apiKey = process.env.OPENAI_API_KEY const openai = new OpenAI({ apiKey }) const completionsCreate = async chatPrompt => { const res = await openai.completions.create({ model: model, prompt: chatPrompt, temperature: 0, }) console.log("completionsCreate", res) } completionsCreate("12+4")
Gemäß der Dokumentation sind für die „Feinabstimmung“ von ChatGPT-Modellen große Datensätze erforderlich, mindestens 200. Der springende Punkt bei „davinci-is-bad-at-maths“ ist, zu lernen , wie man „Feinabstimmung“-Datensätze erstellt, hochlädt und verwendet und wie man diese verknüpft Arbeit tatsächlich daran, einen nützlichen und nicht albernen Datensatz aufzubauen.
Und da wir Programmierer sind, können wir eine Verknüpfung wie diese programmieren:
Öffnen Sie goodAtMathsDatasetBuilder.js
und fügen Sie Folgendes ein:
import fs from "fs" // Don't waste bandwidth with duplicates in the fine-training data. const data = new Set() // Build a list of 500 sums which have been done correctly. while (data.size < 500) { // Two random integers. let x = Math.round(Math.random() * 1000) let y = Math.round(Math.random() * 1000) let result = x + y data.add( JSON.stringify({ prompt: `${x}+${y}\n\n###\n\n`, completion: `${x}+${y}=${result} END`, }), ) } fs.writeFileSync( "good-at-maths-fine-tuning-dataset.jsonl", [...data].join("\n"), "utf-8", ) console.log("JSONL fine-tuning dataset has been created.")
Alles, was wir hier tun, ist, einen Datensatz zu erstellen, der ChatGPT-Modelle „verfeinert“, um gut in Mathematik zu sein, und alles, was wir brauchen, sind viele Summen mit „Vervollständigungen“, die korrekt sind.
Führen Sie dieses Skript wie folgt aus:
node goodAtMathsDatasetBuilder.js`
Öffnen Sie good-at-maths-fine-tuning-dataset.jsonl
und es sollte so aussehen:
{"prompt":"487+63\n\n###\n\n","completion":"487+63=550 END"} {"prompt":"842+624\n\n###\n\n","completion":"842+624=1466 END"} {"prompt":"58+783\n\n###\n\n","completion":"58+783=841 END"} {"prompt":"96+478\n\n###\n\n","completion":"96+478=574 END"} {"prompt":"69+401\n\n###\n\n","completion":"69+401=470 END"}
... mit mehr Summen, die stimmen.
Um den Datensatz hochzuladen, führen Sie Folgendes aus:
npm run cli -- filesCreate good-at-maths-fine-tuning-dataset.jsonl
NB: So würden Sie das Gleiche auch außerhalb unserer CLI tun:
import fs from "fs" import dotenv from "dotenv" import OpenAI from "openai" const apiKey = process.env.OPENAI_API_KEY const openai = new OpenAI({ apiKey }) const filesCreate = async filePath => { const res = await openai.files.create({ file: fs.createReadStream(filePath), purpose: "fine-tune", }) console.log("filesCreate", res) fs.writeFileSync( "openai.files.create.json", JSON.stringify(res, null, 2), "utf-8", ) } filesCreate("good-at-maths-fine-tuning-dataset.jsonl")
Notieren Sie sich die Datei- id
, z. B. „file-th15IsM1ne3G3tY0urOwn1Yo“.
So erstellen Sie ein „fein abgestimmtes“ Modell mit diesem Datensatzaufruf:
npm run cli -- fineTunesCreate "file-th15IsM1ne3G3tY0urOwn1Yo"`"is-good-at-maths"
NB: So würden Sie das Gleiche auch außerhalb unserer CLI tun:
import fs from "fs" import dotenv from "dotenv" import OpenAI from "openai" const apiKey = process.env.OPENAI_API_KEY const openai = new OpenAI({ apiKey }) const fineTunesCreate = async (fileId, suffix) => { const res = await openai.fineTunes.create({ training_file: fileId, suffix: suffix, model: model, }) console.log("fineTunesCreate", res) fs.writeFileSync( "openai.fineTunes.create.json", JSON.stringify(res, null, 2), "utf-8", ) } fineTunesCreate("file-th15IsM1ne3G3tY0urOwn1Yo")
Es dauert eine Weile, DaVinci Mathematik beizubringen, denn ehrlich gesagt ist DaVinci wirklich schlecht in Mathematik!
Du kannst rennen:
npm run cli -- fineTunesList
Warten Sie, bis sich status: 'pending'
in den status: 'suceeded'
ändert.
Wenn status: 'suceeded'
lautet, suchen Sie den Namen fine_tuned_model
.
OPENAI_API_KEY="sk-d0ntY0uD4reUs3MyK3yG3tY0urOwnFr0mOp0n41W36s1t3Yo" OPENAI_MODEL="<fine_tuned_model name>"
npm run cli -- completionsCreate "12+4`.
Es ist eine kitschige Antwort, aber Sie sollten sehen, dass Davinci besser in Mathe ist.
Dieses Projekt finden Sie hier:
https://gitlab.com/timitee/davinci-is-bad-at-maths/edit#js-general-project-settings