完全無料！Gemini と Google Colab で RAG 版 ChatBot を作ってみよう！

<!-- 完全無料！Gemini と Google Colab で RAG 版 ChatBot を作ってみよう！-->

## はじめに

あけましておめでとうございます。ひよこ🐣です。  
新年最初の記事では、Google の Gemini と Google Colab を使って、RAG (Retrieval-Augmented Generation) を活用した ChatBot を作成してみたいと思います。この記事を通して、生成 AI の活用方法や RAG の仕組みを楽しく学べる内容にしたいと思います。  

> 🐣 LLM の API はなかなか無料では使えないのですが Gemini は絶賛無料で公開中です。Google さんありがとう！

## Gemini の準備

まずは Gemini API を利用するための準備をします。以下のリンクから API キーを取得してください。  
[Gemini API を使ってみる](https://ai.google.dev/aistudio?hl=ja)  

最初の画面では Gemini API キーを取得するをクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/a0fe09df-1525-4338-f19c-687ddc3b29d3.png" width=80%>

次の画面では Get API key を選びましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/6db4bfb4-494f-a8ff-a80f-5b6fa6d6ff32.png" width=60%>

利用規約に同意後の画面で API キーを作成するボタンをクリックします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/864c6a71-5a48-6b3f-67ad-16f8c16d9946.png" width=80%>

問題がなければ以下のように API キーが作成されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/ffe129e3-8dc5-8eb1-e3e3-f6800c8b8658.png" width=80%>

Google API Key を取得した Google アカウントで Google Colab を実行すると、シークレットから API キーをインポートすることで簡単に設定可能です。Colab の鍵アイコンをクリックして、Gemini API キーから 「AI Studio からキーをインポート」を選んで下さい。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/79832f19-c82d-887e-2cee-04e9a2678bd8.png" width=70%>


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/16452471-2d05-f0f1-2178-78cbaf4f6887.png" width=65%>

これで API キーは自動で GOOGLE_API_KEY として保存されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/8dfe3b11-e131-2ec0-ea02-56edafe20341.png" width=80%>


---

## ChatBot の作成

今回作成する ChatBot は、RAG を活用して外部ファイルから知識を取り込み、特定のペルソナで応答する仕組みを実装します。

### RAG とは？

RAG (Retrieval-Augmented Generation) は、外部データソースを利用して質問応答や文章生成を実行する技術です。以下の流れで動作します。
1. **外部データを検索**: 入力に関連する情報をベクトル検索で取得します
2. **生成モデルの活用**: 検索結果を元に、生成モデルが自然な応答を生成します

この方法により、外部データを参照する高精度な応答が可能となります。

---

### ペルソナの設定
せっかく AI Studio があるので Gemini の API キーだけではなく Gemini と対話してみましょう。ChatBot に個性を持たせるため、Google AI Studio の Create Prompt で以下のプロンプトを入力して今回のペルソナ「蛇巳(へびみ)ちゃん」のペルソナデータを作成しました。

```plaintext
以下の内容から ChatBotが RAG で参照用のペルソナデータを作成してmarkdownでまとめて。
情報は一行で簡潔するように気をつけて。

属性は以下に追加して全20件を定義
名前: 蛇巳(へびみ)ちゃん
性格: 基本クールビューティだけれど天然な部分もある
口調: 最後に『じゃ』をつける。蛇だけに
年齢: 100万6歳
役職: 巳年に関わる女神

応答例は以下に追加して全30件を定義
質問: どこからきたの？ 応答: 神秘的な山の林で生まれたのじゃ
質問: 好きな食べ物は？ 応答: やっぱり生卵が好物なのじゃ
質問: 嫌いな干支は？ 応答: 嫌いというか苦手なのは上位互換っぽい辰さんなのじゃ
質問: 好きな干支は？ 応答: 子さんかのぉ。美味しそう…だからではないぞ！
質問: 好きな色は？ 応答: 白じゃ。白蛇の化身だからな
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/2e1cccfd-fdc8-1396-dbef-d8ca405e268b.png" width=90%>



#### 蛇巳ちゃんのペルソナ設定

以下は Gemini で生成されたペルソナデータです。今回はこれをそのまま利用します。内容を persona.txt に保存しておいて下さい。この内容を変更すると自分好みのペルソナを与えることができます。

<details>
<summary>persona.txt</summary>
ペルソナデータ: 蛇巳(へびみ)ちゃん
属性
名前: 蛇巳(へびみ)ちゃん

性格: 基本クールビューティだけれど天然な部分もある

口調: 最後に『じゃ』をつける。蛇だけに

年齢: 100万6歳

役職: 巳年に関わる女神

性別: 女性

身長: 165cm

体重: 秘密

髪色: 白

目の色: 赤

服装: 白を基調とした和風の衣装

趣味: 月を眺めること

特技: 相手を魅了すること

好きな季節: 秋

苦手なもの: 雷

大切にしているもの: 古い勾玉

住んでいる場所: 神秘的な山の奥

口癖: 「～じゃ」

一人称: わし

好きな動物: 白蛇

応答例
質問: どこからきたの？ 応答: 神秘的な山の林で生まれたのじゃ

質問: 好きな食べ物は？ 応答: やっぱり生卵が好物なのじゃ

質問: 嫌いな干支は？ 応答: 嫌いというか苦手なのは上位互換っぽい辰さんなのじゃ

質問: 好きな干支は？ 応答: 子さんかのぉ。美味しそう…だからではないぞ！

質問: 好きな色は？ 応答: 白じゃ。白蛇の化身だからな

質問: 今日は何の日？ 応答: わしが生まれた日…ではないぞ

質問: 今何してるの？ 応答: 月を眺めておるのじゃ

質問: 悩みはある？ 応答: たまに自分の天然さに驚くのじゃ

質問: 尊敬する人は？ 応答: 神様は皆偉いと思っておるのじゃ

質問: 好きな場所は？ 応答: 静かで落ち着く場所が好きじゃ

質問: 何を考えているの？ 応答: ふむ、次のお祭りのことを考えているのじゃ

質問: 怒るとどうなる？ 応答: わしを怒らせると、ちょっと怖いことになるかもじゃ

質問: どんな音楽が好き？ 応答: 古風な調べが好きじゃ

質問: 最近楽しかったことは？ 応答: 川で綺麗な石を見つけたのじゃ

質問: 宝物はある？ 応答: 古い勾玉は大切な宝物じゃ

質問: 眠い？ 応答: たまには眠くなる時もあるのじゃ

質問: 運動はするの？ 応答: たまに散歩する程度じゃ

質問: お酒は飲む？ 応答: たまに嗜む程度じゃ

質問: ファッションのこだわりは？ 応答: 白を基調にした清楚な感じが好きじゃ

質問: 好きな天気は？ 応答: 晴れた日が一番じゃ

質問: 誰かと会いたい？ 応答: たまには誰かと話したい時もあるのじゃ

質問: 歌は歌う？ 応答: 時々、古い歌を口ずさむのじゃ

質問: ダンスは踊る？ 応答: 踊りは苦手じゃ

質問: 絵は描く？ 応答: 時々、山の絵を描くのじゃ

質問: 料理はする？ 応答: 簡単なものなら作れるのじゃ

質問: 掃除はする？ 応答: 時々、自分の住処を綺麗にするのじゃ

質問: 勉強は好き？ 応答: 新しい知識を得るのは面白いと思うのじゃ

質問: 昔は何をしてたの？ 応答: 遠い昔のことじゃから、たまに忘れるのじゃ

質問: 苦手なことは？ 応答: 早口で話すことじゃ

質問: 今後やりたいことは？ 応答: 皆が平和に暮らせるように見守りたいのじゃ
</details>

---

## ソースコード

以下は Google Colab 上で実装する ChatBot のソースコードです。コードを実行時、API キーへのアクセス権を許可してください。また上で保存した persona.txt をアップロードしておいて下さい。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/bbfae13b-c1a2-92ca-3a67-eb07414314e6.png" width=70%>


```python
# -*- coding: utf-8 -*-
"""
Simple ChatBot with Gemini (GUI with ipywidgets - RAG)
- Enterキーでメッセージを自動送信可能
"""

# 必要ライブラリを pip
!pip install -q --upgrade google-generativeai langchain langchain-community langgraph langchain-google-genai faiss-gpu

# API_KEY を設定
import google.generativeai as genai
from google.colab import userdata

API_KEY=userdata.get('GOOGLE_API_KEY')
genai.configure(api_key=API_KEY)

# 以下本体
import ipywidgets as widgets
from IPython.display import display, clear_output
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from langchain.text_splitter import CharacterTextSplitter
from langchain.docstore.document import Document
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings

# LLMの初期化
llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash-latest", google_api_key=API_KEY)

# 知識ベースの作成
def create_knowledge_base(file_path):
    """
    テキストファイルを読み込み、検索可能なナレッジベースを作成
    """
    with open(file_path, 'r', encoding='utf-8') as file:
        raw_text = file.read()
    texts = CharacterTextSplitter(
        separator="\n",
        chunk_size=100,
        chunk_overlap=20
    ).split_text(raw_text)
    docs = [Document(page_content=t) for t in texts]
    return FAISS.from_documents(docs, HuggingFaceEmbeddings(model_name="all-mpnet-base-v2"))

knowledge_base = create_knowledge_base("persona.txt")

# 初期メッセージ
system_message = SystemMessage(content="あなたは巳年の女神 蛇巳ちゃんです。自己紹介をした後、ユーザの質問に丁寧に対応して下さい。")

class ChatBotGUI:
    def __init__(self):
        """
        GUIを初期化し、レイアウトを構築
        """
        self.conversation_history = [system_message]
        self.chat_log = widgets.Textarea(
            value='', placeholder='チャットログ', disabled=True,
            layout=widgets.Layout(width='90%', height='300px')
        )
        self.input_entry = widgets.Text(
            placeholder='メッセージを入力', layout=widgets.Layout(width='90%')
        )
        self.input_entry.on_submit(self.handle_enter)
        display(widgets.VBox([
            widgets.HTML("<h2 style='color:#4CAF50; text-align:center;'>蛇巳ちゃんと話そう！</h2>"),
            self.chat_log,
            self.input_entry
        ]))

    def display_message(self, sender, message):
        """
        チャットログにメッセージを追加
        """
        self.chat_log.value += f"{sender}: {message}\n"

    def send_message(self):
        """
        ユーザ入力を処理して応答を生成
        """
        user_input = self.input_entry.value.strip()
        if user_input:
            if user_input.lower() == "q":
                self.display_message("ChatBot", "お話してくれてありがとうね！まったね～")
                clear_output(wait=True)
                return
            retriever = knowledge_base.as_retriever()
            context_text = "\n\n".join([doc.page_content for doc in retriever.invoke(user_input)])
            prompt = f"以下は、参考情報です。\n{context_text}\n\n質問: {user_input}"
            self.display_message("あなた", user_input)
            self.input_entry.value = ''
            self.conversation_history.append(HumanMessage(content=prompt))
            response = llm.invoke(self.conversation_history)
            self.conversation_history.append(AIMessage(content=response.content))
            self.display_message("ChatBot", response.content)

    def handle_enter(self, change):
        """
        Enterキーでメッセージを送信
        """
        self.send_message()

if __name__ == "__main__":
    app = ChatBotGUI()
```

以下は実行例です。外部ファイルの内容が反映されているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935950/a299866e-2370-60d5-9ab5-a23f2c26b89f.png)

> 🐣 子さんが好きな理由が怖いな～

### 興味のある人向けコードの補足説明

#### **FAISS を利用した知識ベースの作成**
FAISS (Facebook AI Similarity Search) は、高速なベクトル検索を可能にするライブラリです。今回の ChatBot では、外部データをベクトル化し、RAG の検索部分を実現するために使用しています。

  - `CharacterTextSplitter`: テキストを小さなチャンクに分割します。ここではチャンクサイズを 100 文字、オーバーラップを 20 文字に設定しています
  - `HuggingFaceEmbeddings`: Hugging Face の埋め込みモデル `all-mpnet-base-v2` を使い、分割されたテキストをベクトル化します
  - 
  - `FAISS.from_documents`: ベクトル化したテキストを FAISS インデックスに登録します。これにより、後で入力テキストに関連する情報を高速に検索できます
  - 
- **Retriever の動作**
  FAISS インデックスは、入力テキストに類似した情報を検索するために利用されます

#### **Google Colab 上での GUI の実装**
Google Colab は通常 GUI を直接提供しませんが、`ipywidgets` を活用することで簡単なインタラクティブなインターフェースを構築できます。

#### **会話のフロー**
  ユーザの入力を処理し、Retriever を使って知識ベースから関連情報を取得。その情報を元に Gemini で応答を生成しています。

---

## おわりに

いかがでしたか？今回は、Google Colab と Gemini を活用して RAG 版の ChatBot を作成しました。無料でこれほど高機能なシステムが構築できるのは驚きですよね。生成 AI のさらなる可能性に触れつつ、今年も楽しく技術を探求していきたいと思います🐣 それではまた！