前回の記事ではChatGPTのAPIを呼ぶ処理を書きました。
ここでは1つの話しかけに対して1つの応答が返ってくる、という例を書きました。 実際はユーザーとAI間で何回かやりとりをしたいというケースが多いと思います。
ドキュメントのmessagesをみてみると
A list of messages describing the conversation so far.
とあります。
つまり過去の会話の配列を送る必要があるわけで、やりとりが多くなれば多くなるほど必要なトークン数が増えていくということになりますね。
前回の記事で書いたCloudFunctionsからChatGPTのAPIを呼ぶ箇所を変更していきます。
chat.ts
import superagent = require("superagent"); import functions from "firebase-functions"; import {defineSecret} from "firebase-functions/params"; import {Response, Request} from "express"; const apiKey = defineSecret('API_KEY'); export async function postChatCompletionApi(req:Request, res:Response) { try { const apiRequest = JSON.parse(req.body) as ChatCallApiRequest; const url = "https://api.openai.com/v1/chat/completions"; let messages:Message[] = []; if (apiRequest.system_prompt !== undefined) { const systemPrompt:Message = { role: "system", content: apiRequest.system_prompt, }; messages.push(systemPrompt); } if (apiRequest.user_prompt !== undefined) { const userPrompt:Message = { role: "user", content: apiRequest.user_prompt, }; messages.push(userPrompt); } // 追加した部分 if (apiRequest.messages != undefined) { messages = messages.concat(apiRequest.messages); } const request: ChatCompletionRequest = { model: apiRequest.model, messages: messages, temperature: 0.7, //適当 max_tokens: 1200, //適当 }; const response = await superagent .post(url) .send(request) .set('Authorization', `Bearer ${apiKey.value()}`); console.log(response.body); res.status(200).send(response.body); } catch (e) { console.log(e); } } type ChatCallApiRequest = { system_prompt?:string, user_prompt?:string, messages?: Message[] model:string, } type ChatCompletionRequest = { model:string, messages:Message[], temperature:number, max_tokens?:number, } type Message = { role:string, // system,user,assistant content:string, // the contents of the message. name?:string, // Author }
index.ts
import chat = require("./chat"); import {defineSecret} from "firebase-functions/params"; const apiKey = defineSecret('API_KEY'); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true, })); app.post("/chat/call", async (req, res) => { await chat.postChatCompletionApi(req, res); }); const api = functions .runWith({secrets: [apiKey]}) .region("asia-northeast1").https.onRequest(app); module.exports = { api, };
これで、過去のやりとりを反映させた形で送ることができます。
{ "model": "gpt-3.5-turbo-0301", "messages": [ { "role": "system", "content": "語尾に必ず「ニャ」をつけて返信する" }, { "role": "user", "content": "こんにちは" }, { "role": "assistant", "content": "こんにちはニャ!" }, { "role": "user", "content": "私が言ったことを繰り返してくださいね。おはよう!" }, { "role": "assistant", "content": "おはようニャ!と言われましたニャ!" }, { "role": "user", "content": "あなたが最初に言ったことをもう一度言ってください。" } ] }
このようなリクエストを送ると、次のようなレスポンスが返ってきました。
{ "usage": { "prompt_tokens": 118, "completion_tokens": 12, "total_tokens": 130 }, "choices": [ { "message": { "role": "assistant", "content": "「こんにちはニャ!」と言いましたニャ!" }, "finish_reason": "stop", "index": 0 } ] }
語尾に必ず「ニャ」をつけて返信する
こんにちは
こんにちはニャ!
私が言ったことを繰り返してくださいね。おはよう!
おはようニャ!と言われましたニャ!
あなたが最初に言ったことをもう一度言ってください。
ここまでが送った内容です。返信は
「こんにちはニャ!」と言いましたニャ!
ということで、ちゃんと認識してくれています。
一旦以上です。