🤖

GPT-3.5とLangchain.jsで記憶を保存できるように

2023/04/02に公開

DiscordからGPT-3.5を呼び出せるようにしてなんか役立てることできないかなぁとなっていたときに、「チャット内容記憶できるようにしておけば色々便利じゃない?!」とふと思いました。

ネット上調べてもよくわからんし~ってことでなんとなくで作ったのが以下のコードです。動作確認まではできました。

おそらくもっと効率的な方法もあります。超簡易的なのでなんか不備とか欠陥があればお手柔らかにコメントお願いします。

main.ts
import { ConversationChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models";
import {
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    SystemMessagePromptTemplate,
    MessagesPlaceholder,
} from "langchain/prompts";
import { BufferMemory, ChatMessageHistory } from "langchain/memory";
import { AIChatMessage, BaseChatMessage, HumanChatMessage, MessageType, SystemChatMessage } from "langchain/schema"
import fs from "node:fs"

export const run = async (input: string, history?: ChatMessageHistory) => {
    const chat = new ChatOpenAI({ temperature: 0, modelName: "gpt-3.5-turbo" });

    const chatPrompt = ChatPromptTemplate.fromPromptMessages([
        SystemMessagePromptTemplate.fromTemplate(
            "省略"
        ),
        new MessagesPlaceholder("history"),
        HumanMessagePromptTemplate.fromTemplate("{input}"),
    ]);
    const memory = new BufferMemory({ returnMessages: true, memoryKey: "history" })

    if (history) {
        memory.chatHistory = history
    }

    const chain = new ConversationChain({
        memory: memory,
        prompt: chatPrompt,
        llm: chat,
    });

    const message = await chain.call({
        input
    });
    console.log(message.response);
    const arr: {
        type: MessageType,
        text: string
    }[] = []
    for (let message of (chain.memory as BufferMemory).chatHistory.messages) {
        arr.push({
            type: message._getType(),
            text: message.text
        })
    }

    return arr
};
const chatMessages: BaseChatMessage[] = []

if (fs.existsSync("memory.json")) {
    const roadHistory = JSON.parse(fs.readFileSync("memory.json", "utf-8"))

    for (let message of roadHistory) {
        if (message.type === "human") {
            chatMessages.push(new HumanChatMessage(message.text))
        } else if (message.type === "ai") {
            chatMessages.push(new AIChatMessage(message.text))
        } else if (message.type === "system") {
            chatMessages.push(new SystemChatMessage(message.text))
        }
    }
}

const message = "こんにちは!"
fs.writeFileSync("memory.json", JSON.stringify(await run(message, new ChatMessageHistory(chatMessages))))

中身としては至ってシンプル。メッセージタイプを持った状態でJSONで保存して読み込んだときにそれぞれのclassに変換して配列に詰め込んでそれをChatHistoryに持たせるって感じです。

コード見たら分かる通りクソ雑だしやり取りの数が多くなったら処理重くなるのが目に見えて分かるので実用的ではない。

以下動作例

Q1. こんにちは
Q2. 私の名前はひさめです!名前は?
Q3. おすすめの和食を1つ教えて
Q4. そのレシピを教えて


↑記憶ないバージョン


↑記憶あるバージョン

Discussion