[日本語訳] LlamaIndex を使用した RAG パイプラインでの Stripe Docs の使用


:::note
この記事は、[dev.to](https://dev.to/stripe)に公開されている[Anthony Morris氏](https://twitter.com/amorriscode)によって書かれた英語記事の日本語訳です。

![スクリーンショット 2024-02-16 16.56.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ea0b2080-b8b8-67c2-1d6b-48812e771751.png)
元記事: [Using Stripe Docs in your RAG pipeline with LlamaIndex](https://dev.to/stripe/using-stripe-docs-in-your-rag-pipeline-with-llamaindex-2j23)
:::

最新の、特定分野の、あるいはプライベートなデータを用いて生成型AI（Generative AI）のアプリケーションを強化すると、その能力は飛躍的に向上します。この手法は「Retrieval Augmented Generation（RAG）」と呼ばれています。

本記事では、[StripeDocs Reader](https://llamahub.ai/l/readers/llama-index-readers-stripe-docs)(Stripeドキュメンテーションを[Pinecone](https://www.pinecone.io/)でベクトル化する[LlamaIndex](https://www.llamaindex.ai/)上のローダー)を使用してPythonスクリプトを構築します。このスクリプトにより、ユーザは[OpenAI](https://openai.com/)（この場合はLLM）に対してStripe Docsについての質問を投げると、生成された応答を受け取ることができます。


## 必要要件
このサンプルでは、OpenAIとPineconeの両方のアカウントとAPIキーが必要です。OpenAIは、質問に基づいて出力を生成するためのLLMを提供します。そしてPineconeは、ベクトルデータベースを提供します。これを使ってLLMプロンプトへ注入する前に、関連するStripeドキュメンテーションを検索することができます。

## セットアップ
このプロジェクトではPythonを使用します。PythonはAI開発用に非常に人気のある言語です。

1. OpenAIのアカウントを作成し、[APIキーを取得](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key)します
2. Pineconeのアカウントを作成し、[APIキーを取得](https://docs.pinecone.io/docs/quickstart#2-get-your-api-key)します
3. APIキーを.envファイルに保存します  
```shell
PINECONE_API_KEY=abc_12345
OPENAI_API_KEY=abc_12345
```
4.次の依存関係を持つ`requirements.txt`ファイルを作成します：  
```shell
llama-hub==0.0.77
llama-index==0.9.40
pinecone-client==3.0.2
python-dotenv==1.0.1
```
5.依存関係をインストールします：
```shell
pip install -r requirements.txt
```

## ベクトルストアとインデックスの構築
ユーザーの質問に関連するStripe Docsを決定するためには、まずPinecone内でベクトルストアとインデックスを作成する必要があります。第一歩として、Stripeドキュメンテーション全体からEmbedding化したベクトルデータを作成しましょう。後半のステップで、ユーザーの質問に関連するドキュメントを取得するための検索に利用します。

Stripe Docs全体を解析し、それらをEmbedding化するのは決して容易な作業ではありません。しかし、[StripeDocsReader](https://llamahub.ai/l/readers/llama-index-readers-stripe-docs)を使用すればこの全プロセスを気にする必要はなくなります。

https://llamahub.ai/l/readers/llama-index-readers-stripe-docs

このローダーは[Stripeのサイトマップ](https://stripe.com/sitemap/sitemap.xml)を利用して、Stripeの全ドキュメンテーションを再帰的にロードします。ロードしたデータを処理することで、ドキュメンテーションからのEmbeddingを手軽に行えるようになります。

:::note warn
Pineconeのインデックスを作成するにはかなり時間がかかります。インデックス作成処理を実行する間、コーヒーブレイクを取って待ちましょう。

**訳者注:** Pineconeの無料で試せるプラン（スターター）を使った場合、40-50分程度かかりました。
:::

### 1. `build.py`ファイルを作成し、適切なパッケージと環境変数をロードします。
```python
import os
from pinecone import Pinecone, PodSpec
from llama_index import VectorStoreIndex, download_loader, StorageContext
from llama_index.vector_stores import PineconeVectorStore
from dotenv import load_dotenv

load_dotenv()

PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# APIキーが正確にロードされたことを確認します
if not OPENAI_API_KEY:
    raise Exception("OPENAI_API_KEY environment not set")
if not PINECONE_API_KEY:
    raise Exception("PINECONE_API_KEY environment not set")

# Open AI APIキーをセットします
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
```

### 2. LlamaIndexから[StripeDocsReader](https://llamahub.ai/l/readers/llama-index-readers-stripe-docs)ローダーをセットアップします。
```python
StripeDocsReader = download_loader("StripeDocsReader")
loader = StripeDocsReader()

# StripeDocsReaderを利用してStripe Docs全体を探索します
documents = loader.load_data()
```
`StripeDocsReader`に`filters`パラメータを渡すことで、コーパスをStripe Docsの一部のみに絞り込むことができます。使用例については[StripeDocsReaderドキュメンテーション](https://llamahub.ai/l/readers/llama-index-readers-stripe-docs)を参照してください。

https://llamahub.ai/l/readers/llama-index-readers-stripe-docs

### 3. 関連するStripeドキュメンテーションを検索するために使用されるPineconeインデックスを初期化します。
```python
# Pinecone indexを初期化します
# https://docs.llamaindex.ai/en/stable/examples/vector_stores/PineconeIndexDemo.html
pc = Pinecone(api_key=PINECONE_API_KEY)
if "stripe-docs" not in pc.list_indexes().names():
    pc.create_index(
        name="stripe-docs",
        dimension=1536,
        metric='euclidean',
        spec=PodSpec(
            pod_type='starter',
            environment='gcp-starter'
        )
    )

pinecone_index = pc.Index("stripe-docs")
```

### 4. 自身のPineconeインデックスとベクトルストアを作成し、Stripe Docsを追加します。
```python
# ベクトルストアとインデックスを作成します
# https://docs.llamaindex.ai/en/stable/understanding/indexing/indexing.html
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, show_progress=True, storage_context=storage_context)
```

### 5. buildスクリプトを実行します：
```shell
python build.py
```

## StripeドキュメンテーションとRAGの活用
Pinecone上にあるベクトルストアに対して、Stripeのドキュメンテーションからインデックスを作成したら、次にインデックスへクエリを投げる処理を作ります。LlamaIndexを使ってユーザーの質問に答える際、ライブラリは自動的に関連するStripe Docsを検索・処理し、それらをChatGPTへのプロンプトとともに送信します。

### 1. `query.py`ファイルを作成し、適切なパッケージと環境変数をロードします。
```python
import os
import pinecone
from llama_index import VectorStoreIndex, download_loader, StorageContext
from llama_index.vector_stores import PineconeVectorStore
from dotenv import load_dotenv

load_dotenv()

PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# APIキーが正確にロードされたことを確認します
if not OPENAI_API_KEY:
    raise Exception("OPENAI_API_KEY environment not set")
if not PINECONE_API_KEY:
    raise Exception("PINECONE_API_KEY environment not set")

# Open APIキーをセットします
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
```

### 2. 作成済みのPineconeインデックスを初期化します。
```python
# Pinecone indexを初期化します
pc = Pinecone(api_key=PINECONE_API_KEY)
pinecone_index = pc.Index("stripe-docs")
```

### 3. Pineconeのベクトルストアからクエリエンジンを初期化します。
```python
# ベクトルストアとインデックスを作成します
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_vector_store(vector_store, show_progress=True, storage_context=storage_context)

# クエリエンジンを作成します
query_engine = index.as_query_engine(response_mode="refine")
```
詳細なレスポンスを作成するために、`response_mode=”refine”`を使用します。

### 4. ユーザー入力を元に、クエリエンジンにクエリを投げます。
```python
print("今日は何をお手伝いしましょうか？")
q = input()

# クエリは以下のステップを含みます:
# 1. インデックスからドキュメントを検索
# 2. ドキュメントの後処理
# 3. プロンプト + ドキュメントをLLMに送信
# https://docs.llamaindex.ai/en/stable/understanding/querying/querying.html
res = query_engine.query(f"""
Stripeのインテグレーションに関する正真正銘のエキスパートです。あなたの仕事は、StripeユーザーがStripeと製品を統合するのを助けるための詳細な回答を提供することです。関連のあるStripeドキュメンテーションを提供しますので、あなたは質問に対して詳細な答えを提供します。

ドキュメンテーションを読んだり、Stripeのサポートに連絡したりするようにユーザーに伝えることは絶対にしないでください。いつでも直接答えを提供してください。

可能な場合は引用を使用します。

適用可能な場合は実際のコード例を使用します。

次の質問があなたに尋ねられました: {q}""")

print(f"{res}\n")
```

### 5. スクリプトを実行します：
```shell
python query.py
```

このコマンドを実行すると、入力した質問文に対する回答文を、[Stripe Docs](https://docs.stripe.com)にある情報に基づいて生成します。

https://docs.stripe.com

以下は元記事にある、英語のデモ動画です。

<iframe width="560" height="315" src="https://www.youtube.com/embed/O59MUpyUjK4?si=hizvQx3dhVB5v8Pi" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

:::note
**訳者注:** 日本語で質問したり、回答文を取得することも可能です。
以下はGoogle Colabを利用して動作させた例のキャプチャーです。

![スクリーンショット 2024-02-28 12.46.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/4e92cc2c-07d3-91af-7aa3-bcc1d96197e6.png)
:::

## 結論
この記事では、Stripeのドキュメンテーションを使用して生成型AIアプリケーションを強化する方法（RAG）について説明しました。RAGは複雑なプロセスではありますが、LlamaIndexやStripeDocsReaderローダーの使用によって始めやすくなっています。ドキュメントの切り出し、取得、クエリに対してデフォルト設定を使用しても、[Stripe Docs AI](https://docs.stripe.com/)に似たものを作成することができます。レスポンスの品質は、LlamaIndexが提供するパラメータを微調整することで大きく改善できます。

この[GitHubリポジトリ](https://github.com/amorriscode/stripe-docs-reader-demo)でのコードを参照してみてください。

https://github.com/amorriscode/stripe-docs-reader-demo