ちょっと前にChatGPTの話をしました。
あくまでも動いているものを試して見るだけで、これをどういう風に作るのか?ということまでは踏み込んでいませんでした。
ということでOpenAIのQuick Startをやってみたいと思います。
目次
GPT-3とは
ここがわかりやすい気がします。
ChatGPTは、その名からも分かる通り、GPT-3をベースとして、対話に特化した形で実装されているようです。
Quick Startをやってみる
Quick Startはここです。
https://beta.openai.com/docs/quickstart/start-with-an-instruction
ドキュメントの中でもいくつか試せるようになっていますが、実際にアプリを作って試すのは「Build your application」のところです。今回はNode.jsでやってみることにします。
サンプルのレポジトリをクローンします。
$ git clone https://github.com/openai/openai-quickstart-node.git
$ cd openai-quickstart-node
OpenAIのAPIキーを.envファイルに記載します。
$ cp .env.example .env
OPENAI_API_KEY=XXXXXXXXXXXXXXX
パッケージをインストールします。
$ npm install
アプリケーションを起動します。http://localhost:3000 で立ち上がります。
$ npm run dev > openai-quickstart-node@0.1.0 dev > next dev ready - started server on 0.0.0.0:3000, url: http://localhost:3000 (snip)
ブラウザでアクセスするとこういうのが立ち上がります。
動物を入れるとその名前を生成してくれるようですね。Quick Startの最初で紹介されていた通りに試してみましょう。
"horse"を入力します。
結果はこうなります。
もう一度同じく"horse"を入力するとこうなります。
1回めと違いますね。"Temperature"により意図的に精度を下げて結果としてバリエーションが生まれるということですね。
https://beta.openai.com/docs/quickstart/adjust-your-settings
少し絞り込んでみましょう。"black horse"で。
"black"に関連しそうなキーワードが選ばれていますね。
コードを読んで見る
デモアプリはNext.jsを使っています。で、GPT-3へのAPI処理はpages/api/generate.js
になります。
import { Configuration, OpenAIApi } from "openai"; const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); export default async function (req, res) { if (!configuration.apiKey) { res.status(500).json({ error: { message: "OpenAI API key not configured, please follow instructions in README.md", } }); return; } const animal = req.body.animal || ''; if (animal.trim().length === 0) { res.status(400).json({ error: { message: "Please enter a valid animal", } }); return; } try { const completion = await openai.createCompletion({ model: "text-davinci-003", prompt: generatePrompt(animal), temperature: 0.6, }); res.status(200).json({ result: completion.data.choices[0].text }); } catch(error) { // Consider adjusting the error handling logic for your use case if (error.response) { console.error(error.response.status, error.response.data); res.status(error.response.status).json(error.response.data); } else { console.error(`Error with OpenAI API request: ${error.message}`); res.status(500).json({ error: { message: 'An error occurred during your request.', } }); } } } function generatePrompt(animal) { const capitalizedAnimal = animal[0].toUpperCase() + animal.slice(1).toLowerCase(); return `Suggest three names for an animal that is a superhero. Animal: Cat Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline Animal: Dog Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot Animal: ${capitalizedAnimal} Names:`; }
順番に見ていきましょう。
createCompletionでテキスト補完の初期化を行っています。
try { const completion = await openai.createCompletion({ model: "text-davinci-003", prompt: generatePrompt(animal), temperature: 0.6, });
GPT-3は、用途に応じて4つのモデルを提供しています。これをmodel
で指定します。精度やレイテンシー、費用などが異なるようです。
https://beta.openai.com/docs/models/gpt-3
temperature
は上で紹介したとおりですね。
prompt
でAPIに渡す文字列を指定します。ここでgeneratePrompt
が呼ばれていますね。
function generatePrompt(animal) { const capitalizedAnimal = animal[0].toUpperCase() + animal.slice(1).toLowerCase(); return `Suggest three names for an animal that is a superhero. Animal: Cat Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline Animal: Dog Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot Animal: ${capitalizedAnimal} Names:`; }
Quick Startにもあったように、いくつかの例をヒントとしてモデルに渡すことで、より自分たちが期待する方向に寄せるような感じになります。
https://beta.openai.com/docs/quickstart/add-some-examples
日本語について
GPT-3は日本語にも対応しています。
ということで少し修正してみましょう。以下の関数を追加します。
function generatePromptJa(animal) { return `動物の日本っぽいクラシカルな名前を3つ挙げて。 動物名: 猫 名前: シロ, タマ, ミケ 動物名: 犬 名前: ポチ, ラッシー, ハチ 動物名: ${animal} 名前:`; }
呼び出し元で関数名を上記に変えます。
const completion = await openai.createCompletion({ model: "text-davinci-003", prompt: generatePromptJa(animal), temperature: 0.6, });
試してみましょう。
どうでしょうか。そう言われてみれば、って感じかなと思います。
まとめ
とてもシンプルに使えていい感じですね。パラメータやヒントなどを色々変えて試してみると良いかと思いますし、プロンプトの例もあります。
https://beta.openai.com/examples
また、ビジネスのユースケースで使うには、コンテキストをあわせるような工夫も必要になるかなと思いますが、そのあたりも考えられているようです。ここはキーになるかなと思っているのでもう少し調べてみます。