このチュートリアルでは、Platform for AI (PAI) の Elastic Algorithm Service (EAS) と、ベクトルデータベースとして ApsaraDB RDS for PostgreSQL を使用して、検索拡張生成 (RAG) ベースの大規模言語モデル (LLM) チャットボットを構築する方法を説明します。
このチュートリアルでは、以下の操作を行います。
-
ApsaraDB RDS for PostgreSQL インスタンスにベクトルデータベースをセットアップする
-
EAS コンソールを介して RAG ベースのチャットボットをデプロイする
-
取得、LLM、RAG の各クエリモードを使用して Web UI でチャットボットをテストする
-
cURL と Python からチャットボット API を呼び出す
仕組み
RAG は、取得と生成を組み合わせることで、スタンドアロンの LLM アプリケーションの精度の限界に対処します。クエリが到着すると、システムはベクトルデータベースから関連ドキュメントを取得し、それらをプロンプトに挿入して、強化されたプロンプトを LLM に送信します。これにより、モデルのトレーニングデータだけでなく、特定のナレッジベースに基づいた回答が生成されます。モデルの再トレーニングは不要です。
このアーキテクチャでは、ApsaraDB RDS for PostgreSQL がベクトルデータベースとして機能します。pg_jieba 拡張機能により、中国語テキストのキーワードベースの取得と再現率が可能になります。
前提条件
開始する前に、以下が準備できていることを確認してください。
-
Virtual Private Cloud (VPC)、vSwitch、およびセキュリティグループ。詳細については、「VPC の作成と管理」および「セキュリティグループの作成」をご参照ください。
-
(任意) カスタムファインチューニングモデルを使用する場合は、Object Storage Service (OSS) バケットまたは Apsara File Storage NAS (NAS) ファイルシステム。詳細については、「OSS コンソールの使用を開始する」または「ファイルシステムの作成」をご参照ください。
Faiss を使用してベクトルデータベースを構築する場合、OSS バケットが必須です。
制限事項
-
ApsaraDB RDS for PostgreSQL インスタンスと EAS は、同じリージョンに存在する必要があります。
-
チャットボットは、LLM サービスのトークン制限を受けます。長い対話ではこの制限に達する可能性があります。シングルターンのシナリオで制限に達する可能性を減らすには、Web UI で [チャット履歴] を無効にします。詳細については、「チャット履歴の無効化」をご参照ください。
手順 1: ベクトルデータベースのセットアップ
-
ApsaraDB RDS for PostgreSQL インスタンスを作成します。VPC 内部接続を有効にするために、計画している EAS デプロイメントと同じリージョンに配置します。詳細については、「インスタンスの作成」をご参照ください。
-
インスタンス用の特権アカウントとデータベースを作成します。詳細については、「データベースとアカウントの作成」をご参照ください。
-
[アカウントタイプ] を [特権アカウント] に設定します。
-
データベースを作成する際、[承認者] ドロップダウンリストから特権アカウントを選択します。
-
-
データベース接続の詳細を取得します。
-
[インスタンス] ページに移動します。上部のナビゲーションバーで、インスタンスが存在するリージョンを選択し、インスタンス ID をクリックします。
-
左側のナビゲーションウィンドウで、[データベース接続] をクリックします。
-
エンドポイントとポート番号をメモします。これらはチャットボットをデプロイする際に必要になります。
-
-
shared_preload_librariesパラメーターにpg_jiebaを追加します。インスタンスのパラメーターページでshared_preload_librariesを見つけ、[実行中のパラメーター値] にpg_jiebaを追加します。例:'pg_stat_statements,auto_explain,pg_cron'。詳細については、「ApsaraDB RDS for PostgreSQL インスタンスのパラメーターの変更」をご参照ください。pg_jieba 拡張機能は、キーワードベースの取得と再現率のために中国語テキストを分割します。詳細については、「pg_jieba 拡張機能の使用」をご参照ください。
手順 2: RAG ベースのチャットボットのデプロイ
-
Platform for AI (PAI) コンソールにログインします。
-
左側のナビゲーションウィンドウで、[ワークスペース] をクリックします。[ワークスペース] ページで、対象のワークスペースを見つけてその名前をクリックします。ワークスペースが存在しない場合は、作成してください。詳細については、「ワークスペースの作成」をご参照ください。
-
左側のナビゲーションウィンドウで、[モデルデプロイメント] > [Elastic Algorithm Service (EAS)] を選択します。
-
[Elastic Algorithm Service (EAS)] ページで、[サービスのデプロイ] をクリックします。[シナリオベースのモデルデプロイメント] セクションで、[RAG ベースのスマート対話デプロイメント] をクリックします。
-
[RAG ベースの LLM チャットボットデプロイメント] ページで、パラメーターを設定します。
基本情報
パラメーター 説明 [サービス名] サービス名。 [モデルソース] モデルソース。有効な値: [オープンソースモデル]、[カスタムファインチューニングモデル]。 [モデルタイプ] モデルのタイプ。要件に基づいて選択してください。[モデルソース] で [カスタムファインチューニングモデル] を選択した場合は、パラメーター数と精度も設定する必要があります。 [モデル設定] [モデルソース] で [カスタムファインチューニングモデル] を選択した場合に必須です。ファインチューニングされたモデルファイルの保存場所を指定します。モデルファイル形式は、Hugging Face Transformers と互換性がある必要があります。有効な値: [OSS のマウント] (OSS パスを選択)、および [NAS のマウント] (NAS ファイルシステムとソースパスを選択)。 リソース設定
パラメーター 説明 リソース設定 [モデルソース] が [オープンソースモデル] の場合、システムは自動的にインスタンスタイプを選択します。[モデルソース] が [カスタムファインチューニングモデル] の場合、モデルに一致するインスタンスタイプを選択します。詳細については、「EAS での LLM アプリケーションのデプロイ」をご参照ください。 推論アクセラレーション A10 または GU30 インスタンス上の Qwen、Llama2、ChatGLM、または Baichuan2 モデルで利用可能です。オプション:[BladeLLM 推論アクセラレーション] (高い同時実行性と低レイテンシー) と [オープンソース vLLM 推論アクセラレーション]。 ベクトルデータベース設定
パラメーター 説明 ベクトルデータベースタイプ [RDS PostgreSQL] を選択します。 ホストアドレス RDS インスタンスの内部またはパブリックエンドポイント。RAG アプリケーションとデータベースが同じリージョンにある場合は、内部エンドポイントを使用します。異なるリージョンにある場合は、パブリックエンドポイントを使用します。詳細については、「パブリックエンドポイントの申請またはリリース」をご参照ください。 ポート デフォルト:5432。 データベース 手順 1 で作成したデータベースの名前。 テーブル名 新規または既存のテーブル名。既存のテーブルを使用する場合、そのスキーマは RAG ベースの LLM チャットボットのフォーマットと互換性がある必要があります。 アカウント RDS インスタンスの特権アカウント。 パスワード 特権アカウントのパスワード。 VPC 設定
パラメーター 説明 VPC [ホストアドレス] が内部エンドポイントの場合、RDS インスタンスの VPC を選択します。[ホストアドレス] がパブリックエンドポイントの場合、VPC と vSwitch を設定し、インターネットアクセス用にインターネット NAT ゲートウェイと Elastic IP アドレス (EIP) を作成します。EIP を RDS インスタンスの IP アドレスホワイトリストに追加します。詳細については、「インターネット NAT ゲートウェイの SNAT 機能を使用したインターネットアクセス」および「IP アドレスホワイトリストの設定」をご参照ください。 vSwitch セキュリティグループ名 セキュリティグループ。 created_by_rdsという名前のセキュリティグループは使用しないでください。これはシステムアクセス制御用に予約されています。 -
[デプロイ] をクリックします。[サービスステータス] 列に [実行中] と表示されたら、チャットボットはデプロイされています。
手順 3: Web UI でのテスト
アプリケーションに統合する前に、組み込みの Web UI を使用してチャットボットのパフォーマンスを検証します。
チャットボットの設定
-
EAS ページで、[サービスタイプ] 列の [Web アプリケーションの表示] をクリックします。
-
埋め込みモデルを設定します。
-
[埋め込みモデル名]:4つのモデルが利用可能です。デフォルトで最適なモデルが選択されます。
-
埋め込み次元: [埋め込みモデル名] を選択すると、自動的に設定されます。
-
-
[PostgreSQL に接続] をクリックして、RDS ベクトルデータベースへの接続を確認します。接続設定はデプロイメント設定から取得され、ここでは変更できません。
ナレッジベースファイルのアップロード
[アップロード] タブで、ビジネスデータファイルをアップロードします。
サポートされているファイル形式:TXT、PDF、XLSX、XLS、CSV、DOCX、DOC、Markdown、HTML。
-
チャンキングパラメーターを設定して、ドキュメントの分割方法を制御します。
パラメーター 説明 デフォルト チャンクサイズ 各チャンクのサイズ (バイト単位)。 500 チャンクオーバーラップ 隣接するチャンク間の重複部分。 10 QA 抽出モデルで処理 [はい] に設定すると、システムはアップロードされたファイルから質問と回答のペアを抽出し、取得の精度を向上させます。 — -
[ファイル] タブでファイルをアップロードするか、[ディレクトリ] タブでディレクトリをアップロードします。
-
システムは、データを保存する前に、データクレンジング (テキスト抽出とハイパーリンクの置換) とセマンティックベースのチャンキングを実行します。
ファイルがアップロードされると、[アップロードステータス情報] テーブルの [ステータス] 列に
completedが、[アップロードステータス] セクションにUpload success.が表示されます。これは、ファイルのアップロードが成功したことを示します。
推論パラメーターの設定
[チャット] タブで、取得と生成のパラメーターを設定します。
取得ベースのクエリ設定
[チャット] タブの左側にある設定パネルの上部で、クエリモードとして [取得]、[LLM]、または [RAG (取得 + LLM)] を選択できます。
| パラメーター | 説明 |
|---|---|
| ストリーミング出力 | 結果をストリーミングモードで返します。 |
| 取得モデル | 取得方法。[埋め込みのみ]:ベクトルデータベースベースの取得。[キーワードのみ]:キーワードベースの取得。[ハイブリッド]:両方の方法を組み合わせます。ほとんどのシナリオでは、ベクトルベースの取得がより良い結果をもたらします。正確なキーワード一致が重要なコーパスでは、[キーワードのみ] または [ハイブリッド] の方がパフォーマンスが向上する場合があります。ApsaraDB RDS for PostgreSQL は、中国語のテキスト分割に pg_jieba を使用します。詳細については、「pg_jieba 拡張機能の使用」をご参照ください。 |
| リランカータイプ | セカンドパスランキングモデルを適用して、結果の精度を向上させます。[simple-weighted-reranker] または [model-based-reranker] を使用して、上位 K 件の結果に対してより高精度の再ランク付け操作を実行できます。 説明
初めてモデルを使用する場合、モデルがロードされるまでしばらく待つ必要がある場合があります。 |
| 上位 K 件 | ベクトルデータベースから取得する上位の結果の数。 |
| 類似度スコアのしきい値 | 結果が返されるための最小類似度スコア。値が高いほど、返される結果は少なくなりますが、より関連性が高くなります。 |
RAG クエリ設定 (取得 + LLM)
事前定義されたプロンプトテンプレートタイプには、[シンプル]、[一般]、[URL の抽出]、[正確なコンテンツ]、および [カスタム] が含まれます。
事前定義されたプロンプトテンプレートを選択するか、カスタムテンプレートを定義します。このモードでは、[ストリーミング出力]、[取得モデル]、および [リランカータイプ] も設定できます。利用可能なプロンプトポリシーの詳細については、「RAG ベースの LLM チャットボット」をご参照ください。
クエリの実行
チャットボットは 3 つのクエリモードをサポートしています。
取得 — ベクトルデータベースから上位 K 件の関連結果を返します。
[チャット] タブで、左側のパネルでクエリモードとして [取得] を選択し、入力ボックスに質問 (例:Machine Learning Platform for AI とは何ですか?) を入力し、[送信] をクリックします。
LLM — LLM アプリケーションのみを使用して回答を生成します。
[チャット] タブで、クエリモードとして [LLM] を選択し、下部の入力ボックスに質問 (例:Machine Learning Platform for AI とは何ですか?) を入力し、[送信] をクリックしてリクエストを送信します。
RAG (取得 + LLM) — 関連ドキュメントを取得し、選択したプロンプトテンプレートに挿入して、結合された入力を LLM に送信します。
[チャット] タブで、左側のパネルでクエリモードとして [RAG (取得 + LLM)] を選択し、[カスタム] などのプロンプトテンプレートタイプを選択し、下の入力ボックスに質問 (例:「Machine Learning Platform for AI とは何ですか?」) を入力し、[送信] をクリックします。
手順 4: API の呼び出し
エンドポイントとトークンの取得
-
チャットボットサービス名をクリックして、[サービス詳細] ページを開きます。
-
[基本情報] セクションで、[エンドポイント情報の表示] をクリックします。
-
[呼び出し方法] ダイアログの [パブリックエンドポイント] タブで、サービスエンドポイントとトークンをコピーします。
ナレッジベースファイルのアップロード
API を呼び出す前に、ベクトルデータベースに接続し、ナレッジベースファイルをアップロードします。または、PAI-RAG スキーマに準拠したテーブルを使用して、ベクトルデータベースに直接データを投入することもできます。
API の呼び出し
チャットボットは、各クエリモードに対応する 3 つのエンドポイントを公開します。
| モード | エンドポイント |
|---|---|
| 取得 | service/query/retrieval |
| LLM | service/query/llm |
| RAG (取得 + LLM) | service/query |
<service_url> と <service_token> を前の手順で取得した値に置き換えます。サービス URL から末尾のスラッシュ (/) を削除してください。
cURL
シングルターンのリクエスト
# 取得モード
curl -X 'POST' '<service_url>service/query/retrieval' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI とは何ですか?"}'
# LLM モード (temperature などのオプションパラメーターをサポート)
curl -X 'POST' '<service_url>service/query/llm' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI とは何ですか?", "temperature": 0.9}'
# RAG モード (取得 + LLM)
curl -X 'POST' '<service_url>service/query' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI とは何ですか?"}'
マルチターンのリクエスト
マルチターン対話は RAG および LLM モードでサポートされています。session_id を使用してリクエスト間で対話の状態を維持するか、chat_history を明示的に渡します。
# ラウンド 1: 最初の質問を送信し、レスポンスで session_id を取得します
curl -X 'POST' '<service_url>service/query' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI とは何ですか?"}'
# ラウンド 2: session_id を含めて対話を継続します
curl -X 'POST' '<service_url>service/query' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI の利点は何ですか?", "session_id": "ed7a80e2e20442eab****"}'
# 代替案: chat_history を {user, bot} のペアのリストとして直接渡します
curl -X 'POST' '<service_url>service/query' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI の特徴は何ですか?", "chat_history": [{"user": "PAI とは何ですか", "bot": "PAI は Alibaba Cloud が提供する AI プラットフォームです..."}]}'
# session_id と chat_history の両方が指定された場合、chat_history はセッションに追加されます
curl -X 'POST' '<service_url>service/query' \
-H 'Authorization: <service_token>' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"question": "PAI の特徴は何ですか?", "chat_history": [{"user": "PAI とは何ですか", "bot": "PAI は Alibaba Cloud が提供する AI プラットフォームです..."}], "session_id": "1702ffxxad3xxx6fxxx97daf7c"}'
Python
シングルターンのリクエスト
import requests
EAS_URL = 'http://xxxx.****.cn-beijing.pai-eas.aliyuncs.com' # 末尾のスラッシュ (/) を削除します
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'MDA5NmJkNzkyMGM1Zj****YzM4M2YwMDUzZTdiZmI5YzljYjZmNA==',
}
def test_post_api_query_llm():
url = EAS_URL + '/service/query/llm'
data = {"question": "PAI とは何ですか?"}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"======= 質問 =======\n {data['question']}")
print(f"======= 回答 =======\n {ans['answer']} \n\n")
def test_post_api_query_retrieval():
url = EAS_URL + '/service/query/retrieval'
data = {"question": "PAI とは何ですか?"}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"======= 質問 =======\n {data['question']}")
print(f"======= 回答 =======\n {ans['docs']}\n\n")
def test_post_api_query_rag():
url = EAS_URL + '/service/query'
data = {"question": "PAI とは何ですか?"}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"======= 質問 =======\n {data['question']}")
print(f"======= 回答 =======\n {ans['answer']}")
print(f"======= 取得されたドキュメント =======\n {ans['docs']}\n\n")
# LLM モード
test_post_api_query_llm()
# 取得モード
test_post_api_query_retrieval()
# RAG モード (取得 + LLM)
test_post_api_query_rag()
マルチターンのリクエスト
マルチターン対話は LLM および RAG モードでサポートされています。前のレスポンスから session_id を渡して対話を継続します。
import requests
EAS_URL = 'http://xxxx.****.cn-beijing.pai-eas.aliyuncs.com' # 末尾のスラッシュ (/) を削除します
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'MDA5NmJkN****jNlMDgzYzM4M2YwMDUzZTdiZmI5YzljYjZmNA==',
}
def test_post_api_query_llm_with_chat_history():
url = EAS_URL + '/service/query/llm'
# ラウンド 1
data = {"question": "PAI とは何ですか?"}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"=======ラウンド 1: 質問 =======\n {data['question']}")
print(f"=======ラウンド 1: 回答 =======\n {ans['answer']} session_id: {ans['session_id']} \n")
# ラウンド 2: ラウンド 1 の session_id を使用します
data_2 = {
"question": "PAI の利点は何ですか?",
"session_id": ans['session_id']
}
response_2 = requests.post(url, headers=headers, json=data_2)
if response_2.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response_2.status_code}')
ans_2 = dict(response_2.json())
print(f"=======ラウンド 2: 質問 =======\n {data_2['question']}")
print(f"=======ラウンド 2: 回答 =======\n {ans_2['answer']} session_id: {ans_2['session_id']} \n\n")
def test_post_api_query_rag_with_chat_history():
url = EAS_URL + '/service/query'
# ラウンド 1
data = {"question": "PAI とは何ですか?"}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"=======ラウンド 1: 質問 =======\n {data['question']}")
print(f"=======ラウンド 1: 回答 =======\n {ans['answer']} session_id: {ans['session_id']}")
print(f"=======ラウンド 1: 取得されたドキュメント =======\n {ans['docs']}\n")
# ラウンド 2: ラウンド 1 の session_id を使用します
data = {
"question": "PAI の特徴は何ですか?",
"session_id": ans['session_id']
}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
raise ValueError(f'Error post to {url}, code: {response.status_code}')
ans = dict(response.json())
print(f"=======ラウンド 2: 質問 =======\n {data['question']}")
print(f"=======ラウンド 2: 回答 =======\n {ans['answer']} session_id: {ans['session_id']}")
print(f"=======ラウンド 2: 取得されたドキュメント =======\n {ans['docs']}")
# チャット履歴付き LLM モード
test_post_api_query_llm_with_chat_history()
# チャット履歴付き RAG モード
test_post_api_query_rag_with_chat_history()
ナレッジベースのコンテンツの表示
チャットボットが実行中になったら、RDS PostgreSQL データベースに接続して、インポートされたナレッジベースのコンテンツを直接確認できます。接続手順については、ApsaraDB RDS for PostgreSQL インスタンスへの接続をご参照ください。
ベクトルデータベースのインデックステーブルには、id、text、metadata_、node_id の 4 つのカラムが含まれています。id カラムは自動増分整数で、node_id カラムは長いハッシュ文字列です。
よくある質問
チャット履歴の無効化
ウェブ UI でマルチターン対話履歴を無効にするには、[チャット履歴] チェックボックスの選択を解除します。
次のステップ
-
スタンドアロン LLM のデプロイ:Web UI または API 経由で呼び出し可能な LLM アプリケーションをデプロイし、LangChain フレームワークを使用してエンタープライズナレッジベースを統合します。詳細については、「EAS で LLM を迅速にデプロイする」をご参照ください。
-
AI 動画の生成:ComfyUI と Stable Video Diffusion を使用して AI 動画生成サービスをデプロイします。詳細については、「ComfyUI を使用して AI 動画生成モデルサービスをデプロイする」をご参照ください。