去年まで作っていたRAGシステムの話 —— AIチャットを独自にカスタマイズ

ちょうど去年の5月頃まで、私はAIを使った社内向けチャットシステムを作っていた。

最近はAIの進化が早すぎて、少し離れるともう昔の話のように感じる。せっかくなので、忘れてしまう前に当時やっていた構成を記録として残しておこうと思う。

注:業務内容をそのまま書けないので、社内システムということにしている。実際は違う:)

今回は、いわゆる RAG(Retrieval-Augmented Generation) の一般的な構成について、実際に作っていたシステムをベースに書いてみる。


そもそもRAGとは何か?

RAGというのは簡単に言えば、

「AIに、事前に会社の資料を読ませてから回答させる仕組み」

である。

通常のLLM(ChatGPTのような大規模言語モデル)は、インターネット上の一般知識は持っているが、当然ながら会社固有の情報は知らない。

例えば:

こういったものは、学習されていない。

そこで必要になるのがRAGだ。


実際にやっていた構成

当時の構成は、かなりオーソドックスだった。

流れとしてはこんな感じ。

  1. 社内データを登録
  2. ドキュメントを分割(チャンク化)
  3. ベクトル化(Embedding)
  4. pgvectorへ保存
  5. ユーザー質問をEmbedding化
  6. 類似チャンク検索
  7. LLMへ渡して回答生成

今見ると「教科書通り」なのだが、実際この構成はかなり強力だった。


1. まずは社内データを集める

元データは主にPostgreSQLに入っていた。

例えば:

など。

ただ、ここで重要なのは、

「DBに入っている = AIが理解できる」

ではないということ。

人間向けのデータは、そのままだとAIには扱いづらい。


2. ドキュメントをチャンク化する

ここで登場するのがLangChain。

当時はかなり使われていた。

例えば長いマニュアルを、そのままLLMへ送ると:

という問題が起きる。

なので、文章を小さく分割する。

例えば:

製品Aについて
========

機能説明...

障害時対応...

注意事項...

これを:

チャンク1: 機能説明
チャンク2: 障害対応
チャンク3: 注意事項

みたいに切る。

この「どこで切るか」が意外と重要だった。

細かすぎると文脈が消えるし、大きすぎると検索精度が落ちる。

RAGは、実はこの辺の地味な調整がかなり効く。


3. Embedding(ベクトル化)

次に、文章をEmbeddingする。

Embeddingとは簡単に言えば、

「文章を数値ベクトルに変換すること」

である。

例えば:

"パスワードを変更したい"

みたいな文章が、数百〜数千次元の数値配列になる。

重要なのは、

意味が近い文章ほど、近いベクトルになる

という点。

つまり:

みたいな文は、数学的に近くなる。

これがRAGの核心部分。


4. pgvectorへ保存

Embeddingしたベクトルは、PostgreSQL + pgvectorへ保存していた。

これは非常に実務的だった。

理由は単純で、

から。

ただし、ここで一つ注意点がある。

チャンク化するとデータ量が一気に膨らむので、ベクトル用のDB自体は業務DBと分けた方がいい。

同じPostgresでも、インスタンスは別にする、というイメージ。

バックアップやモニタリングなど、運用の流儀はそのまま流用できる。

でも、本番DBとI/Oを取り合う構成だけは避けたかった。

世の中的には:

みたいな専用Vector DBもある。

ただ、業務システムでは「新しいDBを増やしたくない」という事情も強い。

なので、pgvectorはかなり現実解だった。


5. ユーザー質問をEmbedding化

ユーザーが質問する。

例えば:

経費精算の締め日は?

これを同じEmbeddingモデルでベクトル化する。

ここが重要で、

登録時と検索時で、同じEmbeddingモデルを使う

必要がある。

でないと空間の意味がズレる。


6. 類似チャンク検索

次にpgvectorで類似検索する。

つまり:

SELECT *
FROM documents
ORDER BY embedding <-> :question_vector
LIMIT 5;

みたいなことをやる。

すると:

など、意味的に近いチャンクが取得される。

ここが普通の全文検索と違う部分。

キーワード一致ではなく、

「意味が近い」

で引っ張れる。

なので:

に比較的強い。


7. 最後にLLMへ渡す

取得したチャンクを、LLMへ渡す。

イメージとしては:

以下の情報を参考に回答してください。

[関連資料]
- 経費精算は毎月25日締め
- 承認期限は月末

[質問]
経費精算の締め日は?

するとLLMが、

経費精算の締め日は毎月25日です。

のように自然文で返す。

これがRAG。


当時感じた「RAGの現実」

やってみて感じたのは、

RAGは「AI魔法」ではなく、かなり泥臭い検索システム

ということだった。

実際、精度を左右するのは:

みたいな地味な部分。

LLMそのものより、

「どう検索させるか」

の方が重要だったりする。


そして今

もう1年近く、AI自体を作る業務はやってないが、今では:

などのような手法があるようだ。

ただ、根本思想は当時から変わっていない。

「AI単体ではなく、外部知識を検索して補強する」

これがRAGの本質だと思う。


おわりに

AIチャットというと、つい「LLMが全部賢い」と思われがちだ。

でも実際の業務システムでは、

みたいな、かなり従来型の技術が土台になっている。

むしろ、

「検索エンジンの進化版」

として見る方が、実態に近いかもしれない。

そして、その泥臭い部分こそ、実は一番面白かったりする。

——なお、経験則として「AIを入れれば全部解決する」と言う人ほど、だいたい社内のドキュメントは10年前から更新されていない。

AIに賢くなってもらう前に、まずは自分たちの資料を整理する方が先だ。

魔法を待つより、棚卸しの方が早い。