初めてのRAG触ってみた

## はじめに
無知な私が超簡易的なRAGを実装してみました。（[参考](https://qiita.com/en2enzo2/items/ae7ac793199c85356055)）
かなり生暖かい目推奨です。
## 環境準備
今回使用したのは下記になります。
``langchain``：LLMベースのアプリケーション構築ライブラリ
``openai``：OpenAIのAPIクライアント
``faiss``：高速な類似検索用ライブラリ

必要なライブラリは以下のコマンドでインストールしてください。
```
pip install langchain openai faiss-cpu
```
また、OpenAIのAPIキーを環境変数に設定します。
```
os.environ["OPENAI_API_KEY"] = "your-key"
```
## コード
```python:rag.py
import os # osとの対話を行うためのモジュール
from langchain.llms import OpenAI # OpenAIの言語モデルを使うためのクラス
from langchain.embeddings.openai import OpenAIEmbeddings # テキストをベクトルに変換するクラス
from langchain.vectorstores import FAISS # ベクトルデータを効率的に検索するためのクラス
from langchain.text_splitter import CharacterTextSplitter # テキストを小さな部分に分割するクラス
from langchain.schema import Document # テキストデータを管理するためのクラス
from langchain.chains import ConversationalRetrievalChain #  会話型の質問応答システムを作るクラス

# OpenAI APIキーの設定
os.environ["OPENAI_API_KEY"] = "your-key"

# 1. 知識ベースの準備
content = """
12月18日、兵庫県神戸市の地下鉄三宮駅で、女性が刃物で刺される事件が発生しました。警察は現場で女を逮捕し、詳しい状況を調査しています。
また、北九州市で中学生が殺傷された事件に関連し、最寄り駅の防犯カメラには、犯人と特徴が似た人物は映っていなかったことが判明しました。捜査は難航しています。
さらに、ホンダと日産が経営統合に向けた協議を進めているとの報道がありました。自動車業界の再編が進む中、今後の動向が注目されています。
"""
documents = [Document(page_content=content)]

# 2. テキストを小さなチャンクに分割
splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = splitter.split_documents(documents)

# 3. 埋め込みの生成
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(texts, embeddings)

# 4. RAGチェーンの作成
llm = OpenAI()
retriever = vectorstore.as_retriever()
rag_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever)

# 5. 質問に対する応答を生成
question = "最近のニュースを一つ教えてください"
chat_history = []

response = rag_chain.run({"question": question, "chat_history": chat_history})
print(response)
```
## 各ステップの説明
### 1\. 知識ベースの準備
私の場合別のファイルを用意した際にエンコードがどうたらというエラーが出たので直書きしました。
contentのままだとstr型なのでオブジェクト型に変換します。
```python
content   = """...ニュース内容..."""
documents = [Document(page_content=content)]
```
### 2\. テキストのチャンク分割
現在の状態だと、正確な処理ができないそうなのでテキストを分割し埋め込みに適した形にする。
```python
splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts    = splitter.split_documents(documents)
```
### 3\. 埋め込みの生成
OpenAIの埋め込みを利用し、``FAISS``ベースのベクトルストア（数値化した塊）を作成します。
```python
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(texts, embeddings)
```
### 4\. RAGチェーンの作成
``ConversationalRetrievalChain``を利用して質問応答のパイプラインを構築します。
llm フィールドを OpenAI インスタンスとして明示的に設定してるけどエラーが出たからしているだけで出ないなら``llm=OpenAI()``でいいと思う。
```python
llm = OpenAI()
retriever = vectorstore.as_retriever()
rag_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever)
```
### 5\. 応答の生成
質問を入力し、関連するニュースを取得して回答を生成します。
```python
question = "最近のニュースを一つ教えてください"
chat_history = []
response = rag_chain.run({"question": question, "chat_history": chat_history})
print(response)
```
## 実行結果
実行すると、入力された質問に対してニュース内容に基づいた回答が得られます。
```
12月18日、兵庫県神戸市の地下鉄三宮駅で女性が刃物で刺される事件が発生しました。
```
## おまけ
質問文をめちゃくちゃギャルにすると結果はどう変わるか見てみた。
```python
question = "最近のニュースを一つギャル語で教えてください。""""
```
【結果】
ちょっと薄いですがギャルで帰ってきましたね！
```
ホンダと日産が経営統合するニュースがあったよ！自動車業界がどうなるか注目だね☆
```
## まとめ
LangChainとOpenAI APIを活用することで、簡単に動的な質問応答システムを構築できます。このプロジェクトでは、ニュースを基にした回答生成を実現しましたが、さまざまなドキュメントやデータに応用可能です。
初めて触ってみましたが、いろんなエラーが出て試行錯誤祭りでした。