【今更聞けない!?】✨ Azure OpenAIとLangChainで始める！RAG入門!AIチャットボット構築ハンズオン 🚀

## はじめに

**最新情報に対応できる賢いAIチャットボットを、Azure OpenAIを使って作ってみませんか？**

この記事では、Azure OpenAIとLangChainを活用したRAG (Retrieval-Augmented Generation) の基本と、実践的なチャットボットの構築方法を、分かりやすく解説します。
LangChainは、LLMと外部データソースを統合するための強力なライブラリで、複雑なフローを簡単に構築できる点が魅力です。特にRAGの実装において、LangChainは重要な役割を果たします。
これからAIを活用したいと考えている方、Azure OpenAIとLangChainの基本的な使い方を**手を動かして**学びたい方、RAGに興味がある方に向けて、丁寧に解説していきます。

**✅ 対象読者**

* 生成AIやRAGに興味がある方
* 噂のAzure OpenAIとLangChainを使ってAIチャットボットを作ってみたい方
* AIチャットボットの最新技術を学びたい方

**この記事を読めば、RAGの基礎を理解し、実際に動くAIチャットボットを構築できるようになります！**

## この記事で作るAIチャットボットの概要とハンズオンの流れ

この記事では、**Azure OpenAIとLangChainを使って、Wikipediaのデータから質問に答えるAIチャットボットを構築するハンズオン**をご紹介します。

**完成イメージ**

最終的には、あなたが用意したテキストデータから学習したAIチャットボットが、その内容に関する質問に答えてくれるようになります。

例えば、Wikipediaの「葬送のフリーレン」のページを学習させた場合、以下のような質問に答えることができます。

* **質問:** フリーレンのアニメはいつからいつまで放送されたんですか?
* **回答:** フリーレンのアニメは、2023年9月から2024年3月まで放送されました。初回（第1話 - 第4話）は「初回2時間スペシャル〜旅立ちの章〜」として、2023年9月29日に『金曜ロードショー』枠にて2時間スペシャルで放送され、その後、第5話以降は同系列の新アニメ枠である『FRIDAY ANIME NIGHT』枠ほかにて10月から2024年3月まで放送されました。


**ハンズオンの流れ**

1. **Azure OpenAIのセットアップ:** Azure OpenAIを利用するための準備を行います。アカウントの作成、リソースの作成、モデルのデプロイなどを行います。

2. **RAGを実装:** 
    * 必要なライブラリをインストールします。
    * WikipediaのAPIを使って、特定のページのテキストデータを抽出し、`input.txt`というファイルに保存します。今回は「葬送のフリーレン」のページを例にしますが、自由に他のページに変更することも可能です。
    * テキストデータをベクターデータベースに変換し、AIが理解しやすい形にします。
    * LangChainを使って、AIチャットボットの処理の流れを定義します。

3. **プログラムを実行:** 作成したプログラムを実行し、実際にAIチャットボットと対話してみます。


**必要なもの**

* **Azureアカウント:** Azure OpenAIを利用するために必要です。まだアカウントをお持ちでない場合は、無料で作成できます。
* **Pythonの開発環境:** Pythonのコードを実行するために必要です。


**この記事を通して、RAGの基本的な仕組みを理解し、実際にAIチャットボットを構築する経験を積むことができます。ぜひ、最後まで読み進めて、あなただけのAIチャットボットを作り上げてください！**


---

## 1. なぜRAGが必要なの？ 🤔 従来のAIチャットボットとの違いとは？

### RAGとファインチューニングの比較

AIチャットボットは日々進化していますが、従来のチャットボットには大きな制約がありました。それは、**学習データが固定されており、新しい情報や特定の知識に対応できない**という点です。この制約を克服するためのアプローチとして、ファインチューニングとRAG（Retrieval-Augmented Generation）の2つがあります。

### ファインチューニングとは？

ファインチューニングは、既にトレーニングされた大規模言語モデル（LLM）を特定のデータセットで再トレーニングし、特定の分野に特化した能力を持たせる方法です。例えば、医療分野に特化したチャットボットを作成する際に、医療データでファインチューニングを行うことで、医療に関する質問に対して高精度な応答ができるようになります。

**ただし、このアプローチには限界があります。**  
ファインチューニングされたモデルは特定のドメインでのパフォーマンスは向上しますが、汎用性が損なわれる可能性があります。また、ファインチューニング後もモデルは依然としてトレーニングデータに依存しており、外部の最新情報を反映することが難しいのです。

### RAGとは？

一方、**RAG（Retrieval-Augmented Generation）** は、LLMに外部の知識ベースをリアルタイムで活用させるアプローチです。RAGでは、チャットボットが質問を受けるたびに、外部のデータベースやウェブサイトから最新の情報を取得し、それを基に応答を生成します。これにより、常に最新の情報を反映した回答が可能になります。以下は､RAGの動作機構の模式図です。

![](https://storage.googleapis.com/zenn-user-upload/5ad9ddf9fb7a-20240822.png)
*[^1]*

**イメージで例えると…**

従来のAIチャットボットは、百科事典しか持っていない図書館員のようなものです。この図書館員は百科事典に書かれた情報しか提供できません。一方、RAGを搭載したAIチャットボットは、インターネットに接続され、リアルタイムで情報を取得できる図書館員です。この図書館員は、常に最新の情報を取り入れた回答を提供できるのです。

### ファインチューニング vs. RAGの違い

| 項目 | ファインチューニング | RAG |
|---|---|---|
| **適用範囲** | 特定のドメインに特化 | 幅広いドメインに対応 |
| **最新情報の反映** | トレーニングデータの更新が必要 | 外部データからリアルタイムに反映 |
| **計算コスト** | 高い（大規模な再トレーニングが必要） | 比較的低い（リアルタイム検索のみ） |
| **実装の複雑さ** | データセットの選定が重要だが比較的簡単 | データベースの構築や検索の最適化が必要で複雑 |
| **応答の正確性** | 特定分野で高い精度を発揮 | リアルタイム情報の正確性に依存するが、常に最新 |
| **システムの拡張性** | 新しいドメインの追加には再トレーニングが必要 | 知識ベースを拡張するだけで対応可能 |

**注釈:**
- **適用範囲:** ファインチューニングは特定のドメインに特化した高精度な応答を提供する一方、RAGは幅広い質問に対応するための柔軟性を提供します。
- **最新情報の反映:** RAGはリアルタイムで外部の最新情報を取り入れることができ、常に更新された情報を提供できます。
- **計算コスト:** ファインチューニングは多くのリソース(主にGPUやVRAM)を必要とするため、実装には高いコストがかかる場合があります。
- **実装の複雑さ:** RAGは実装がやや複雑ですが、拡張性や情報の更新において優れています。



---




## 2. Azure OpenAIのセットアップ 🛠️

### Azure OpenAIのセットアップ

まず、Azure OpenAIを利用するために必要な設定を行います。以下はその手順です。
詳しくは以下をご参照ください｡
https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/create-resource?pivots=web-portal

1. **Azureポータルにサインイン**

   Azureポータル（[https://azure.microsoft.com/en-us/get-started/azure-portal](https://azure.microsoft.com/en-us/get-started/azure-portal)）にアクセスし、Microsoftアカウントでサインインします。まだアカウントをお持ちでない方は、無料アカウントを作成することも可能です。

2. **Azure OpenAIリソースの作成**

   ポータル内で「Azure OpenAI Service」を検索し、「Create」をクリックします。リソースグループや価格帯を選択し、リソースを設定します。以前(2024年7月頃)までは、Azure OpenAIの利用には承認が必要でしたが､現在は申請不要となり､特に個人での利用のハードルが非常に低くなりました｡

3. **デプロイの完了を待つ**

   設定が完了したら、Azureがデプロイを行います。完了後、ポータル内のAzure OpenAIリソースにアクセスします。

4. **モデルのデプロイ**

   Azure OpenAI Studio（[https://azure.microsoft.com/en-us/products/ai-services/openai-service](https://azure.microsoft.com/en-us/products/ai-services/openai-service)）にアクセスし、使用したいモデル（例: GPT-4o）をデプロイします。「Deployments」タブから「Create new deployment」を選択し、デプロイを開始します。

   今回のハンズオンでは､east-usリージョンにて､チャットモデルに『**GPT-4o**』(or GPT-4o mini)､埋め込みモデルに『**text-embedding-3-small**』を使ってみようと思います!最終的には､以下のようになっていればOKです｡このとき､モデルのエンドポイントとAPIキーを手元に控えておきましょう｡

![](https://storage.googleapis.com/zenn-user-upload/4b55957c1ff6-20240822.png)

---

## 3. RAGを実装してみよう！ 🛠️

ここからは、LangChainを使用してRAGを実装する方法について説明します。LangChainは、データの取り扱いやフローの設計を簡素化する強力なツールです。このツールを使うことで、Azure OpenAIと外部データソースを効果的に統合し、リアルタイムで最新の情報を提供するチャットボットを構築することができます。

### ステップ1: 環境の準備 🔧

まずは、必要なツールを準備しましょう。

1. **仮想環境の構築**

Pythonの仮想環境を構築することで、プロジェクトごとに依存関係を管理できます。これにより、異なるプロジェクトで異なるライブラリを使っても互いに影響を与えません。

```bash
# プロジェクトフォルダを作成し、その中に仮想環境を構築します
mkdir your-project-folder
cd your-project-folder
python3 -m venv venv
```

仮想環境をアクティベートします。

- **Windows**:
  ```bash
  .\venv\Scripts\activate
  ```
- **Mac/Linux**:
  ```bash
  source venv/bin/activate
  ```

2. **必要なライブラリのインストール**

仮想環境をアクティベートした状態で、以下のコマンドを実行して必要なライブラリをインストールします。

```bash
pip install langchain==0.2.14 openai==1.41.0 python-dotenv faiss-cpu
```

3. **フォルダ構造の準備**

以下のフォルダ構造を作成し、必要なファイルを配置します。

```
/your-project-folder
│
├── /venv                     # 仮想環境フォルダ
│
├── /.env                     # 環境変数を設定する.envファイル
│
├── /faiss-db                 # FAISSベクターデータベースを保存するフォルダ（プログラム実行時に生成されます）
│
├── /data                     # インプットとなるテキストファイルを格納するフォルダ
│   └── input.txt             # テキストデータを格納するファイル（例: input.txt）
│
├── 01_extract_wikidata.py    # wikiのデータからインプットデータを作成するPythonスクリプト
│
├── 02_create_vector_db.py    # ベクターデータベースを作成するPythonスクリプト
│
└── 03_main.py                # チャットボットを実行するメインのPythonスクリプト
```

4. **環境変数の設定**

`.env`ファイルに必要な環境変数を設定します。

```env
AZURE_OPENAI_API_KEY="your-api-key"
AZURE_OPENAI_ENDPOINT="your-endpoint"
OPENAI_API_VERSION="2024-07-01-preview"
AZURE_OPENAI_DEPLOYMENT="gpt-4o" 
AZURE_OPENAI_EMBEDDING_DEPLOYMENT="text-embedding-3-small"
```

**`your-api-key` と `your-endpoint` は、ご自身の Azure OpenAI の設定に合わせて変更してください。**


### ステップ2: Wikipediaデータを使ってRAGする用のインプットデータを作成しよう！ 📝

#### データ抽出の準備

RAGを実装する際、チャットボットに与えるデータが重要です。今回は、Wikipediaのページからテキストデータを抽出して、チャットボットのインプットとして利用します。この方法を使えば、興味のあるトピックや最新の情報をチャットボットに取り込むことができます。

以下は、Wikipediaから指定したページのテキストを抽出し、それをファイルに保存するPythonプログラムです。今回は､『葬送のフリーレン』のwikipediaを対象にしてみます｡

https://ja.m.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3

```python:01_extract_wikidata.py
import requests

def get_wikipedia_page(title):
    """
    Wikipediaから指定ページのテキストを抽出する関数

    Args:
        title (str): Wikipediaページのタイトル
    Returns:
        str: ページのテキスト（抽出に失敗した場合は空文字列）
    """
    url = "https://ja.wikipedia.org/w/api.php"
    params = {
        "action": "query",
        "format": "json",
        "titles": title,
        "prop": "extracts",
        "exlimit": 1,
        "explaintext": True,
        "redirects": 1,
    }

    try:
        response = requests.get(url, params=params)
        response.raise_for_status()  # リクエストが失敗した場合に例外を発生
        data = response.json()
        page = next(iter(data["query"]["pages"].values()))
        return page.get("extract", "")
    except requests.exceptions.RequestException as e:
        print(f"APIリクエストに失敗しました: {e}")
        return ""

# Wikipediaからページを取得し、テキストファイルに保存
# 「葬送のフリーレン」のページを取得
page_content = get_wikipedia_page("葬送のフリーレン")
file_path = "./data/input.txt"
with open(file_path, "w", encoding="utf-8") as file:
    file.write(page_content)

```

#### 解説

このコードは、`requests`ライブラリを使ってWikipediaのAPIにアクセスし、指定したタイトルのページからテキストを取得します。`get_wikipedia_page`関数は、ページのテキストを抽出して返します。その後、取得したテキストを`input.txt`というファイルに保存します。

**ポイント:**

- **APIの利用**: WikipediaのAPIは、簡単にデータを取得することができ、さまざまな用途に利用できます。ここでは、日本語のWikipediaページを例にしていますが、他の言語でも同様に利用可能です。
- **データの保存**: 抽出したデータを`input.txt`に保存することで、次のステップでRAGのベクターデータベースとして利用できます。


### ステップ3: ベクターデータベースの作成 🗄️

テキストデータをAIが理解できるように、ベクターデータベースに変換します。

```python:02_create_vector_db.py
import os

from dotenv import load_dotenv
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import AzureOpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 環境変数の読み込み
load_dotenv()


# ベクターデータベースの作成
def create_vector_database(txt_path):
    # テキストデータのロード
    loader = TextLoader(txt_path)
    docs = loader.load()

    # ドキュメントを分割してチャンクを作成
    splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    documents = splitter.split_documents(docs)

    # エンベディングを生成してベクターストアに保存
    embeddings = AzureOpenAIEmbeddings(
        model=os.environ.get("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
    )
    db = FAISS.from_documents(documents, embeddings)
    db.save_local("./faiss-db")


if __name__ == "__main__":
    create_vector_database("data/input.txt")
```

### 解説

このコードでは、`create_vector_database`関数を使って、テキストデータをベクターデータベースに変換しています。これにより、RAGが必要とする外部知識ベースが構築され、チャットボットが利用可能な情報源として機能します。

- **TextLoader**: テキストファイルからデータを読み込みます。
- **RecursiveCharacterTextSplitter**: 読み込んだテキストを小さなチャンクに分割します。これにより、ベクターデータベースが効率的に処理できるようになります。
- **FAISS**: Facebookが開発したベクターデータベースで、大量のテキストデータの中から類似性の高い情報を高速に検索します。

### ステップ4: AIチャットボットの実装 🚀

いよいよAIチャットボットを実装します！
LangChainのモジュールを使用して、テキストデータの分割やベクターデータベースの作成を行います。LangChainは、これらの操作をシンプルにし、RAGの構築プロセスを効率化します。

```python:03_main.py
import os
import sys  # コマンドライン引数を扱うために必要

from dotenv import load_dotenv
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings

# 環境変数の読み込み
load_dotenv()


# チャットボットのセットアップ
def setup_chatbot():
    """
    Azure OpenAIとFAISSベクターストアを使用してチャットボットをセットアップします。

    Returns:
        Callable: チャットボットの質問応答チェーンを実行するための関数。
    """
    embeddings = AzureOpenAIEmbeddings(
        azure_deployment=os.environ.get("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
    )

    vectorstore_faiss = FAISS.load_local(
        "./faiss-db", embeddings, allow_dangerous_deserialization=True
    )  # ベクターストアのロード

    llm = AzureChatOpenAI(
        azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT"),
        verbose=False,
        temperature=0.3,  # 応答の創造性と正確性のバランス
    )

    # PromptTemplateの説明
    # `PromptTemplate`は、LLMに対してどのように質問や文脈を提示するかを定義するテンプレートです。
    prompt_template = """あなたはAIアシスタントです。以下のコンテキストを考慮してください:
    {context}

    次の質問に答えてください:
    {question}

    アシスタント:"""

    prompt = PromptTemplate(template=prompt_template, input_variables=["context", "question"])

    qa_chain = (
        {
            "context": vectorstore_faiss.as_retriever(),
            "question": RunnablePassthrough(),
        }
        | prompt
        | llm
        | StrOutputParser()
    )
    return qa_chain


# チャットボットの実行
if __name__ == "__main__":
    # コマンドライン引数から質問を取得
    if len(sys.argv) > 1:
        question = sys.argv[1]
    else:
        print("質問を入力してください。")
        sys.exit(1)

    chatbot = setup_chatbot()
    response = chatbot.invoke(question)
    print(response)

```

### 解説

このコードでは、チャットボットをセットアップし、ユーザーからの質問に対してベクターデータベースを用いて応答を生成しています。

- **AzureChatOpenAI**: AzureのOpenAIモデルを使用して、ユーザーの質問に応答します。
- **PromptTemplate**: 質問や文脈をどのようにLLMに提示するかを定義するテンプレートです。
- **RunnablePassthrough**: プロンプトや応答の処理をチェーンの各段階で通過させるための実行可能なオブジェクトです。

---

## 4. ここまでで作ったプログラムを実行してみよう！

### 実行方法

それでは、実際にプログラムを実行してみましょう。

1. `01_extract_wikidata.py` を実行して、RAGする用のインプットデータを作成します｡

```bash
python 01_extract_wikidata.py
```

2. `02_create_vector_db.py` を実行して、ベクターデータベースを作成します。

```bash
python 02_create_vector_db.py
```

3. `03_main.py` を実行して、チャットボットを起動します。

```bash
python 03_main.py "フリーレンのアニメはいつからいつまで放送されたんですか?"
```

### 実行結果

`main.py` を実行すると、以下のような結果が出力されます。

> フリーレンのアニメは、2023年9月から2024年3月まで放送されました。初回（第1話 - 第4話）は「初回2時間スペシャル〜旅立ちの章〜」として、2023年9月29日に『金曜ロードショー』枠にて2時間スペシャルで放送され、その後、第5話以降は同系列の新アニメ枠である『FRIDAY ANIME NIGHT』枠ほかにて10月から2024年3月まで放送されました。


このように、`input.txt` に含まれる情報に基づいて、チャットボットが質問に答えてくれます。(合ってますね!)


---

## 5. さらに賢く！ 🧠 RAGの可能性を広げよう！

今回紹介したRAGは、ほんの一例です。RAGにはまだまだ多くの可能性が秘められています。

* **様々なデータソースとの連携:** PDF、Webサイト、データベースなど、様々なデータソースと連携することで、より幅広い情報をAIに提供できます。
* **高度な検索技術の導入:** より高度な検索技術を導入することで、より的確な情報をAIに提供できます。

**RAGを駆使して、あなただけの最強AIチャットボットを作り上げましょう！**

---

## まとめ：RAGでAIチャットボットは新たな時代へ！ 🚀

RAGは、AIチャットボットの可能性を大きく広げる革新的な技術です。RAGを活用することで、従来のチャットボットでは難しかった最新情報の反映が可能になり、より賢く信頼性の高い応答を生成できるようになります。ファインチューニングとRAG、それぞれの強みを理解し、目的に応じて適切な手法を選択することで、AIチャットボットの能力を最大限に引き出すことができます。この記事を参考に、あなたもRAGを活用して、より賢く、信頼性の高いAIチャットボットを開発してみましょう！

**ここまで読んでいただきありがとうございます!お疲れ様でした｡
もし少しでもお役に立てましたらいいね👍 とフォロー 🙏 よろしくお願いします！**

[^1]:[高度な取得拡張生成システムの構築](https://learn.microsoft.com/ja-jp/azure/developer/ai/advanced-retrieval-augmented-generation)