0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【0から目指すAIエンジニア】Day7:RAGの基礎

Posted at

はじめに

こんにちは、慶應義塾大学理工学部機械工学科3年の金賢佑です!
私は東大発AIベンチャーの株式会社2WINSの元でインターンをしています!

これからの記事では自分がインターンを通して最強のAIエンジニアを目指していきます!
第七回はRAGの基礎を記録しました!

RAGとは

RAGとは簡単にいうとLLMに答えさせる前に、知識を検索してくれる仕組みのこと!

LLMはあくまで「学習済みの知識」しか知りません!
なので例えば、
👨「会社のマニュアルをもとに質問に答えてほしいな....」と思っても
🤖「何そのマニュアル...知らないんだけど...」
となってしまいます!

RAGでは何ができるの?

今回はRAGでは主要なコンポーネントとして5つ紹介します!

Document loader:PDFなどの文書を読み込む

Document transformer:読み込んだ文書を使いやすいサイズに分割!例えば一万字のPDFを500文字ごとに分ける!(この単位をチャンクって言うよ)
チャンクに直すことによって
①大量のテキストデータを小分けにして処理することが可能になり、検索効率が向上する
Embeddingのトークン制限を回避する
などの利点が挙げられます。

なお、適切なチャンクサイズは200~500トークンと言われていて、小さすぎると意味のなくなりがなくなり、大きすぎると検索をかける際に無関係な文もヒットするなどのデメリットがあります!

Embedding Model:チャンクをベクトルに変換する!
例えば、「この製品は高い耐久性と防水性を備えており、アウトドアでも安心して使えます。」みたいな文章があった時、
①["この", "製品", "は", ......]のようにテキストがトークン化される
②損失関数などを用いた事前学習済みの埋め込み行列から、それぞれにベクトルが渡される(ベクトルの数値が似ているものほど、似た意味を持っている)
③各トークンの平均or特定のトークンでまとめて一つのベクトルに集約される
④文全体の意味のベクトルが完成する

このことについてはday3でも紹介したこちらの動画をご覧ください!(chapter7くらいまであります)
https://youtu.be/tc8RTtwvd5U?si=ynBpv-bFHHjfwOCz

Vector store:ベクトル化したチャンクを保存する!
こうしてできたベクトルのデータベースは普通のデータベースと違い、似た文を探す、いわゆる「曖昧な検索」が可能になります。
とっても便利!

Retriever:ユーザーの質問に応じてVector storeから情報を検索する!
仕組みとしては例えば
①ユーザーが質問する👦「地球の直径はどれくらい?」
②質問文をベクトルに変換!これはさっきやったのと同じ!
③あらかじめEmbedding済みのデータベースに保存されているベクトル群の中で、上記のベクトルと似ているものを抽出!距離が近ければ意味も似ているので、ユークリッド距離を使ったり、ドット積を使います!

ドット積の結果の見方は以下を参考にしてください!

alt text

ちなみに補足ですが、Retrieverだけだと精度に問題があることがあります。間違った情報を渡してしまうことをハルシネーションと言います。
こうしたリスクを回避する方法として、Retrieverが意味的に近いだろうと持ってきたチャンクを再評価してくれるRerankerを間に挟むこともあります
Rerankerは例えば、Retrieverが持ってきた10個のチャンクをスコア付けし、最も高いものを選んでくれます!

では実際に一つずつ使ってみましょう!

Document loader

ではまず初めにDocument loaderを使ってみよう!
以下のコードを打ってください。

!pip install langchain-community==0.3.0 GitPython==3.1.43

from langchain_community.document_loaders import GitLoader

def file_filter(file_path: str) -> bool:
  return file_path.endswith('.mdx')

loader = GitLoader(
    clone_url='https://github.com/langchain-ai/langchain',
    repo_path='./langchain',
    branch='master',
    file_filter=file_filter,
)

raw_docs = loader.load()
print(len(raw_docs))

こちらのコードではLangChainの公式GitHubリポジトリから.mdxファイルだけを抽出して読み込んでいます!
最後にデータ件数を表示してみましたが現在では414件あるみたいですね。
Document loaderのコードは複雑ですね....
一応解読すると、

def file_filter(file_path: str) -> bool:

def file_filterで関数名を定義。
file_pathと言う名前の引数を受け取るよ言う意味。strなので引数は文字列。
-> boolこの関数は真偽を返す(True or False)と言う意味!

clone_url='https://github.com/langchain-ai/langchain',
repo_path='./langchain',
branch='master',
file_filter=file_filter,

clone_url='https://github.com/langchain-ai/langchain'でGitHubからのリポジトリをクローン
repo_path='./langchain'でローカルの保存先を指定
branch='master'でブランチを指定
file_filter=file_filterで上で定義したオブジェクトを引数に渡している!

Document transformer

続いてはドキュメントをチャンクで分割してみましょう!

!pip install langchain-text-splitters==0.3.0

まずは必要なものをインポートしてください!
その後テキストをチャンクに分割していきます!

from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)

docs = text_splitter.split_documents(raw_docs)
print(len(docs))

chunk_sizeっていうのは一つの塊であるチャンクに含める最大文字数(またはトークンの数)のこと!
出力でWARNING:langchain_text_splitters.base:Created a chunk of size 1281, which is longer than the specified 1000っていう警告が出ているのはchunk_size=1000では分割しきれなかったよ!っていうことです。
かといってchunk_sizeをあげすぎても分割できる量が少なくなってしまうから難しい...

Embedding model

次はベクトル化を行ってみます。

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model='text-embedding-3-small')

query = 'LangChainでPDFを読み込むにはどうしたらいいですか?'

vector = embeddings.embed_query(query)
print(len(vector))
print(vector[:3])

これを実行すると、下のように出力されます。
今回は長いので3要素しか出力していませんが、実際は1536次元のベクトルが与えられています!(気になった人は[:3]を消してみてください!)

1536
[-0.011487526819109917, -0.0013641082914546132, 0.013325303792953491]

Vector store & Retriever

続いてベクトル化したドキュメントの保存を行ってみます。
最初にGithubからコピーしてきたデータを処理しています!

!pip install langchain-chroma==0.1.4

続いてChromaをインポートしてみます!

from langchain_chroma import Chroma

ob = Chroma.from_documents(docs, embeddings)

ChromaはLangChainで使える「ベクトルデータベース」の一つ!
デフォルトではローカル(自分のパソコン)に保存されるよ!

.from_documents()はテキストを1つずつ取り出してembeddingを使ってベクトル化したのちにChromaに保存してくれるショートカット関数!
「ショートカット関数」とは一連の処理を一行でやってくれる便利な関数のこと!

Retriever

最後にユーザーの質問に対して関連する情報を取得するRetrieverを使ってみましょう!

query = 'LangChainでPDFを読み込むにはどうしたらいいですか?'

context_docs = retriever.invoke(query)
print(len(context_docs))

first_doc = context_docs[0]
print(first_doc.metadata)
print(first_doc.page_content)

first_doc.metadataにはファイル情報が含まれていて、出典に該当します。
first_doc.page_contentには実際の文章の中身が入っています。これがLLMに渡す情報になります。

まとめ

今回はRAGの主要なコンポーネントについて紹介しました!
なかなか複雑な文法もあったと思いますが、流れだけでも理解できたら十分だと思います!

お疲れ様でした!

参考文献

LangChainとLangGraphによるRAG・AIエージェント〈実践〉入門/西見公宏/吉田真吾/大嶋勇樹

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?