問題
テスト用のGCPインスタンスで動いていたはずのDockerイメージが、本番用のインスタンスでは動かなくなった。
原因
Qdrant(ベクトルデータベース)のバージョンを明示的に指定していなかったためであった。
今回までのあらすじ
布川シーランド公爵である。
だが俺はいち労働者であり、公爵よりエラい人が無数にいる。
チャットボット(のようなもの)を開発している。
「今週末に試用のものをリリースしますね」とヘラヘラしていたらあっという間に今週末がやってきた。
もうとっくに準備は終わっているので大丈夫だろう、と思ったらリリース前につよつよエンジニアによる怒涛のコードレビューが行われ、リファクタリングがなされてしまった。
なんでそんな数日前にレビューするの?
ちょっと泣きそうだったがコードが完璧であるため俺は何も言えない。俺のアホは水際で食い止められ、いくつかのやらかしは顧客の目に触れることはなくなった。
完璧に生まれ変わったはずのコイツを、満を持してリリースしようとしている。
なぜか本番環境で動かない。
ソースコードには、ドメイン名などの環境変数以外の差異はない。ビルドもしっかり通る。しかし、いざ、APIを呼び出すとエラーが返ってくる。
システムの概要
今回の問題の本質とはあまり関係ないが、俺の作っているシステムについてもちょっと話しておこう。
おおざっぱには……。
- 客がマイクで何か尋ねる。
- Qdrantでベクトル検索を行って、類似する資料を見つけてくる
- GPTが答える
というようなものだ。
Qdrantというのはオープンソースのベクトルデータベースである。
ベクトルデータベースというのは、画像とか、テキストとかをベクトル化して(Embeddingという)、近いベクトルのものを引っ張ってくる仕組みを備えたデータベースである。
これの良いところは、まったく文の形が違うものでもベクトルが似ていれば「似たものである」と判定してくれるところだ。
ベクトルにしてしまえば何でもかんでも検索できるだろうというすっごい仕組みである。
これを俺が何に使うかというと、類似検索のために使用する。
ChatGPTでおなじみのOpenAIもEmbeddingモデルを出している。
text-embedding-3-largeで、コサイン類似度で判断すると、「やわらかい」と、「ポメラニアン」は0.2242……略……くらいらしい。へえ!
例えば、お客さんが「飲み放題の梅プランで飲めるドリンクは?」といった場合と、「梅で飲めるドリンクは?」といった場合、どっちもあらかじめこちらにご用意しておいたメニュー表を参照するようにしたい。
「梅プランのドリンクは?」というような質問に、類似度が高いドキュメントを結び付けておいて、出したい。そん時に使うのだ。
(この例だと、「キーワード検索でもいいだろ」という気はするが、できれば、もし可能であったら「あーっ、なんだっけあの、梅とかなんとかのプランのドリンクって何?」といったような揺れを吸収してくれる可能性があるわけだ……)
これをRAGというのだ。
Retrieval-Augmented Generation(RAG)である。
これで得られたカンニングペーパーっていうか、内部情報をLLMに渡してやることで、LLMは「知ったこっちゃねえよお前の店がどういうプランだしてっかなんていちいち覚えてねえからよぉ~」という状態から「はい!かしこまりました!こちらメニュー表になります。いかがでしたか?」というふうになる。やったね。
RAGがない状態
プロンプト:客に対応してください。
[質問]梅プランってなんだっけ?何飲めるの?
何も知らないGPTくん:梅プランですね!梅プランについての情報を教えていただけますか?
RAGが存在する場合
プロンプト:客に対応してください。
質問ー梅プランってなんだっけ?何飲めるの?
[コンテキスト]リストはこれです。
- ビール
- 各種ソフトドリンク
麦茶
ウーロン茶
ジャスミン茶
GPTくん:(カンニングペーパーをチラ見)ハイ!梅プランは~
デバッグ
つよつよエンジニアの助けを借りてデバッグすると、例外が起きているのはQdrantのsearch呼び出し部であることが分かった。
俺が原因を自分自身の素行に求め、最近やらかした悪いことを(カップヌードルを2つ食べるなど)振り返り懺悔しているあいだ、つよつよエンジニアは少し考えた後、docker-compose.yaml
を見る。
「Qdrantのimageのバージョンが指定されていないね」
なにそれ?
VisualStudioCodeの拡張機能で、Qdrantのバージョンを確認する。
「latest(最新版)」のみがあった。
(*今はもう少したくさん映っている)
ということでリリース前の俺が連れてこられたのはdockerhubである。
ここで、問題ないほうで動いているバージョンのQdrantを更新日付から探し当て、タグを指定し、動いている部分のimageを動かす。
するとなんということだろう。
バグは解消されたのだ。
原因
requirements.txtではqdrant-client
でQdrantのバージョンを指定していたが、docker-compose-yamlでは指定しておらず、バージョンに不整合があったのだった。
今はいったんバージョン指定を外し、最新版を指定しなおしたので最新のものになっている。
テスト用環境はずっとテストしていたが、本番用環境はさいきん新しく建てたインスタンスであり、新しく環境を作るときは新しいものになるため、バージョンが不整合を起こしていたようだ。
総括
俺は数々のやらかしをしてきた結果、だいぶ謙虚になっていて、こういう時はパニックになりがちで「GCPのインスタンスを作成するとき、設定を間違えたかもしれない」「どこかにミスがあったのかもしれない」と原因を己に求める。だいたい俺が悪いからだ。
というか実際、バージョン指定をしていなかったせいであり、完璧に俺のやらかしなのだが、Qdrantがエラーを起こして落ちていることを把握すれば気が付けたかもしれない。
これからは外部ライブラリの関数を呼び出して落ちている場合、バージョンの不整合を疑ってみることにする。
さいわい、本番環境といっても、試作段階のAPIを提供するものだったので、何万人の顧客に影響が~ということはなかった。ちょっとどころではなく冷や汗をかいたけど……。