Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Your AI SDK chat table breaks every six months

2026年09月14日に「Dev.to」が公開したITニュース「Your AI SDK chat table breaks every six months」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

AI SDKでチャット履歴をデータベースに保存するのは手間が多く、特にバージョンアップ時のテーブル変更や過去の回答・分岐履歴の管理が課題だった。新ライブラリ「ai-sdk-threads」は、これらの課題を解決し、既存のPostgresなどで会話履歴を効率的かつ堅牢に永続化できる。

ITニュース解説

AIチャットアプリケーションの開発では、ユーザーとの会話履歴を正確に、そして効率的に保存することが非常に重要な課題となる。しかし、この「永続化」と呼ばれる作業は、一見すると簡単そうに見えて、実は多くの落とし穴が潜んでおり、開発者が繰り返し同じような問題に直面することが少なくない。

例えば、人気のあるAIチャットボットのテンプレートを見ると、データベースのテーブル名にMessage_v2のようにバージョン番号が付いている場合がある。これは、過去にAI SDKというライブラリのメッセージ形式が変更された際、既存のテーブルを直接更新する「マイグレーション」を行うよりも、新しい形式に対応した_v2という名前のテーブルを新たに作成し、古いデータをそちらへ移行する方が簡単だったためだ。その結果、新しいプロジェクトを始めるたびに、このバージョン番号が付いたテーブル名がスキーマに残り、恒久的にバージョンアップの「傷跡」として引き継がれてしまう、というような状況が発生していた。開発者の中には、このような手動での移行作業を何度も経験し、その手間を省きたいと考える者もいる。

多くのプロジェクトで、AIチャットの会話履歴をデータベースに保存するために、ほぼ同じような約25行のコードが繰り返し書かれている。このコードは、外部から受け取ったチャットメッセージの中から新しいユーザーメッセージを識別し、既存の履歴と結合してAIモデルに渡し、返ってきたAIの応答メッセージをデータベースに保存するという一連の流れを処理する。しかし、この一連の処理の中には、特に見落としやすい四つの問題点が存在し、これらが原因でバグが発生することが頻繁にある。

第一に、メッセージのIDを生成する部分(generateMessageId)を適切に設定しないと、データベースに保存されるメッセージのIDが空になってしまい、後からメッセージを特定することが困難になる。第二に、すでに保存済みのメッセージを識別するためのセット(knownセット)を使わないと、ページをリロードするたびに同じユーザーメッセージが重複してデータベースに保存されてしまう。第三に、AIの応答メッセージが二重に保存されることを防ぐためのフラグ(persistedガード)を設定し忘れると、ストリームの終了イベントが複数回発生した場合に、AIからの返信がデータベースに二重に書き込まれる可能性がある。

そして第四に、特に厄介なのは、AI SDKのバージョンによって、会話の終了時にデータベースにメッセージを保存するための「コールバック関数」の名前が異なっていた点だ。例えば、バージョン6ではonFinishという名前だったが、バージョン7ではonEndに変わった。もし開発者がどちらか片方だけを指定してしまうと、新しいバージョンでは問題なく動作しても、古いバージョンでは何もエラーを表示せず、ただ単にメッセージがデータベースに保存されないという状況が起こり得る。この原因を特定するには、実際に古いバージョンでテストを実行するなどの手間が必要だった。

このような課題に対し、既存の解決策もいくつか存在するが、それぞれに限界があった。AI SDKの公式ガイドは永続化の「パターン」を示すものであり、各アプリケーションにそのコードをコピーしてメンテナンスする必要があるため、複数のアプリケーションで利用する場合には非効率だ。また、assistant-ui cloudConvexのような外部サービスは、永続化の仕組みを完全に提供してくれるが、会話データを彼らのシステム内で管理するため、すでに運用しているPostgresなどのデータベースに会話を保存したい場合や、データ管理に関する特定の要件がある場合には適さない。さらに、既存のテンプレートをフォークして使う方法は、永続化の仕組みだけでなく、認証スタックやファイルストレージなど、テンプレート全体のアーキテクチャを引き継ぐことになるため、必ずしも開発者が望む柔軟性を提供しない。

このような背景から、ai-sdk-threadsという新しいライブラリが登場した。これは、開発者がすでに使っているPostgresやSQLiteなどのデータベースで、チャットの「スレッド」(会話のまとまり)と「メッセージ」を効率的に管理できるように設計されている。このライブラリは、データベースのスキーマ(threadsmessagesという二つのテーブル)と、それらを操作するための型付けされたストア(createThreadStore)を提供する。開発者は、自身のDrizzle ORMインスタンスを使ってこのストアを一度作成すれば、あとはチャットのルートハンドラー内でそのストアを渡すだけで、前述の永続化における多くの問題を解決できる。

具体的には、ai-sdk-threadsは、受信したメッセージを一度だけデータベースに保存し、AIからの応答をストリームしながら保存する際も、AI SDKのバージョン6と7の両方に対応したコールバック名を内部で登録するため、メッセージの取りこぼしを防ぐ。また、メッセージの内容はAI SDKが生成したそのままの形式でデータベースに保存されるため、ツール呼び出しや推論の過程など、複雑なメッセージの「パーツ」も忠実に復元できる。これにより、データが途中で加工されて失われたり、深夜にデバッグが必要になったりするような事態を防ぐことができる。ただし、このライブラリは、どのユーザーがどの会話にアクセスできるかを制御する「認証」の仕組みは提供しないため、開発者は別途、認証ロジックを実装する必要がある。

さらに、ChatGPTのような高度なチャットアプリケーションでは、一度生成されたAIの回答を再生成しても、以前の回答が完全に消えるわけではなく、ユーザーが過去の回答に遡って確認できる機能や、途中の質問を編集しても元の会話の経緯が「ブランチ」(枝分かれ)として残る機能が提供されている。しかし、多くのAI SDKベースのアプリケーションでは、このような複雑な履歴管理機能は実装されておらず、単純に最新の会話のみを保存していることが多い。これは、会話の履歴を効率的にデータベースに保存し、それをUIで表現するためのデータ構造を設計することが非常に難しい問題だからだ。

ai-sdk-threadsは、この高度な履歴管理機能も解決する。そのデータモデルはシンプルで、すべてのメッセージはparentIdを持ち、すべてのスレッドは現在の「アクティブなリーフ」(最新の会話の終端)を指すactiveLeafIdを持つ。AIの回答が再生成された場合、それは既存の回答を上書きするのではなく、同じ親メッセージから派生した新しい子メッセージとして扱われる。これにより、ユーザーはsiblingsOfメソッドを使って兄弟メッセージを切り替えたり、setActiveLeafメソッドで会話のライブパス(現在表示されている会話の流れ)を変更したりできる。データは決して削除されず、getTreeを使えば会話の全体像をツリー構造で取得できる一方、loadMessagesuseChatコンポーネントが求めるようなライブパスのみを返す。

このライブラリの信頼性については、いくつかの技術的な配慮がなされている。ドキュメントサイトでは、PostgresをWebAssemblyでブラウザ内で動かし、実際のデータベースの変更やクエリログをリアルタイムで確認できるプレイグラウンドが提供されており、概念実証だけでなく実際の動作を体験できる。パフォーマンス面では、スレッドの読み込みはメッセージの数にかかわらず常に2クエリで処理され、ルートからリーフへのパスは効率的にメモリ上で処理される。また、スレッドの一覧表示も1ページあたり1クエリで完了する。N+1問題(データ取得時に無駄なクエリが大量に発生する問題)を防ぐため、すべての操作におけるクエリ数はテストによって厳密に管理され、CI(継続的インテグレーション)プロセスでチェックされる。

さらに、すべてのデータベース行にはsdk_versionという情報が付与される。これにより、将来AI SDKのメジャーバージョンが変更された際にも、どのデータが影響を受けるかをCLIツールで特定し、適切な移行パスを提示できるようになる。以前のVercelテンプレートから移行する場合のためのインポーターも用意されている。AI SDKのバージョン6と7の両方で、198ものテストを含むフルテストスイートが実行されることで、広範な互換性が保証されており、前述のonEnd/onFinishのバグもこのテストスイートによって発見された。

ただし、ai-sdk-threadsは会話の永続化と履歴管理に特化しており、それ以外の機能は意図的に対象外としている。例えば、会話内容に基づいたベクトル検索、自動要約、エージェントオーケストレーションといった機能は、異なる課題を解決するための別のライブラリが担当する範囲だ。また、チャットUIそのものも提供せず、ai-elementsassistant-uiのようなUIライブラリがレンダリングするデータを保存することに徹している。AI SDKのバージョンは、バージョン5のメジャーな書き直し以降のバージョン6および7をサポート対象とし、バージョン4以前はサポートしない。スループットのベンチマークは提供されていないが、永続化の目的は速度よりもデータの正確性と整合性にあるため、クエリ数やテストカバレッジといった側面で信頼性を示している。

このライブラリはMITライセンスで提供され、コア機能にはランタイム依存がなく、軽量だ。ドキュメントとプレイグラウンドが公開されているため、興味のある開発者は実際に試してみることができる。開発者は、10万スレッドや500メッセージのパスで測定しているが、さらに大規模な会話でこのストレージモデルが破綻するケースがあれば、ぜひフィードバックを求めている。

関連コンテンツ

関連IT用語