Open7
Nextjs + Neon

Next.js + Vercel AI SDKを使ったLLMアプリケーションのデータ永続化にNeonのPostgresを使ってみる

日本リージョンはない

.envとapp/sctions.tsを設定
// app/actions.ts
"use server";
import { neon } from "@neondatabase/serverless";
export async function getData() {
const sql = neon(process.env.DATABASE_URL);
const data = await sql`...`;
return data;
}

テーブルの初期化はNeonの管理画面上のSQLエディターからSQLを実行。
開いた時にサンプルがあるので、とりあえずそれを実行。
結果タブが見やすい。

チャットの履歴を保存したいので、テーブルを作る。今回はアプリ画面で出す用ではなくて管理目的のみなので簡易的になりそう。
- sender ... AIかユーザーか
- value ... チャットの内容
- system_prompt_version ... システムプロンプトのバージョンコード (運用上管理されている)
- thread_id ... フロントから発行する
- create_at ... タイムスタンプ
CREATE TABLE IF NOT EXISTS chat_history(
id SERIAL PRIMARY KEY,
sender TEXT NOT NULL,
value TEXT NOT NULL,
thread_id TEXT NOT NULL,
system_prompt_version TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

actions.tsに関数を追加
export async function saveHistyroy(props: {
sender: string;
value: string;
thread_id: string;
}) {
if (!process.env.DATABASE_URL) {
throw new Error("DATABASE_URL is not set");
}
const sql = neon(process.env.DATABASE_URL);
const data =
await sql`INSERT INTO chat_history (sender, value, thread_id, system_prompt_version)
VALUES (${props.sender}, ${props.value}, ${props.thread_id}, '2');`;
return data;
}
ページからコールする。
export default function Home() {
...
const {
messages,
setMessages,
input,
setInput,
handleInputChange,
handleSubmit,
isLoading,
} = useChat({
onFinish: (message) => handleFinishMessage(message),
});
const handleFinishMessage = (latestMessage: Message) => {
saveHistyroy({
sender: latestMessage.role,
value: latestMessage.content,
thread_id: threadId.current,
});
};
...
}

今回のはユーザー識別やスレッド表示を考慮してないが、綱領した上であるあるテーブルは用意しておけそう。