Milvus、LangChain、OpenAI LLMによる多言語RAGの構築

過去2年間、Retrieval Augmented Generation (RAG)は、大規模言語モデル (LLMs)によって駆動されるGenAIアプリケーションを構築するための最も人気のあるテクニックの1つに急速になった。その核となるRAGは、モデルが事前に訓練されていない文脈情報を提供することで、LLMの出力を強化する。多言語RAGは、多言語のテキストデータを扱うために拡張されたRAGである。
OSS4AIのCEOであるYujian Tangは最近、Zilliz主催のUnstructured Data Meetupで講演した。彼は、RAGとその基本的なコンポーネントについて議論し、実世界の多様な言語の課題に対処するための多言語RAGの構築方法を実演した。
この投稿では、Yujian氏のプレゼンテーションから重要な洞察を要約し、多言語RAGを実装する方法をご案内します。Yujianの講演についてもっと知りたい方は、YouTubeで彼のプレゼンテーションを見ることをお勧めします。
RAGとは何ですか?LLMを使ったアプリケーションの核となる限界の1つは、学習させたデータに依存していることです。もしLLMが事前トレーニング中に特定の情報や知識領域全体に触れていなければ、正確な回答を生成するために必要な言語的関係を理解することはできない。このデータ不足は、LLMが答えを知らないと認めるか、もっと悪いことに「幻覚」と間違った情報を提供することにつながる。
RAGは、追加的な文脈情報をLLMに提供することで、LLMの幻覚の問題に対処する一般的な技術である。また、開発者や企業は、セキュリティの問題を心配することなく、個人データや専有データを利用することができる。
図1- RAGの仕組み](https://assets.zilliz.com/Figure_1_How_RAG_works_246044aacf.png)
RAGは埋め込みモデルから始まり、テキストデータをベクトル埋め込み、つまりテキストの意味的な意味を捉える数値表現に変換する。RAGシステムは、これらのベクトルをMilvusやZilliz Cloudのようなベクトルデータベースに格納し、類似検索のためのインデックスを作成する。
ユーザがクエリを送信すると、埋め込みモデルも入力をベクトルに変換する。そして、RAGシステムは、高次元ベクトル空間における距離を計算することによって、このクエリベクトルとベクトルデータベースのベクトルの類似性を比較する。関連するデータが見つかった場合、RAGシステムはこの情報を検索し、元のクエリに追加してLLMのための新しいプロンプトを形成する。LLMはこの追加情報を使って、より正確で文脈に関連した応答を生成し、学習データのみに基づいて生成できる応答を上回る。
多言語RAGとは?
多言語RAGは従来のRAGの機能を拡張し、多言語をサポートします。様々な言語で訓練されたエンベッディングモデルを統合することで、システムが異なる言語間の応答を処理し、生成することを可能にします。この多言語アプローチを使用することで、RAGシステムはあらゆる言語のクエリを処理し、元の言語に関係なく関連する情報を取得し、ユーザーの希望する言語で正確で文脈に関連した回答を提供することができます。
多言語RAGアプリケーションの構築方法:ステップバイステップガイド
RAGのコアコンセプトとコンポーネントを学んだところで、多言語RAGアプリケーションをステップバイステップで実装してみましょう。
このサンプルアプリケーションは、ウェブスクレーパーとメインアプリケーションの2つの部分を含んでいます。
ウェブスクレーパー**はインターネットから必要なデータセットをスクレイピングします。
メイン・アプリケーション** は、ベクトル埋め込みを作成し、ベクトルの類似性検索を実行し、答えを生成します。
ウェブ・スクレーパー
まず、Wikipediaからデータをスクレイピングし、このRAGの例の文脈情報として使う。
タイトルの定義:** まず、都市のリストを含む
wiki_titles
というリストを定義する。各都市はウェブスクレーパーが対応するウィキペディアのエントリーの内容を入力するテキストファイルを表している。例えば、"Atlanta.txt" はウィキペディアのアトランタのページからスクレイピングされたテキストを含む。wiki_titles`の各都市を繰り返し、Wikipedia APIにGETリクエストを行い、JSONレスポンスからページの内容を抽出する。そして、各都市に対応するテキストファイルにテキストを保存する。
from pathlib import Path
インポートリクエスト
wiki_titles = [
「アトランタ
「ベルリン
「ボストン
「カイロ
「シカゴ
「コペンハーゲン
「ヒューストン
「カラチ
「リスボン
「ロンドン
「モスクワ
「ミュンヘン
パリ
"Pékin"、#フランス語で北京の意
「サンフランシスコ
「シアトル
上海
東京
「トロント
]
data_path = Path("./french_city_data")
data_path.mkdir(exist_ok=True) # ディレクトリが存在することを確認する
for title in wiki_titles:
response = requests.get(
"https://fr.wikipedia.org/w/api.php"、
params={
"action":"query"、
"format":"json"、
"titles": タイトル、
"prop":"extracts": 抽出、
"explaintext":真、
},
).json()
page = next(iter(response["query"]["pages"].values()))
wiki_text = page.get("extract", "") # KeyErrorを避けるために.get()を使う
if wiki_text: # 抽出が空でないかチェックする
with open(data_path / f"{title}.txt", "w") as fp:
fp.write(wiki_text)
else:
print(f "No extract found for {title}")
環境の準備
まず、Milvus vector database, LangChain, OpenAI, sentence transformers という必要なライブラリをインストールして、開発環境を整えます。
さらに、OpenAIのようなAPIを通じてLLMに接続する場合は、APIキーを含める必要があります。このキーは別の .env
ファイルに保存することができ、 load_dotenv()
と os
を使ってアクセスすることができます。
以下はライブラリをインストールし、APIキーをロードするコードです:
pip install -qU pymilvus langchain sentence-transformers tiktoken openai
from dotenv import load_dotenv
インポート os
load_dotenv() # .env ファイルから環境変数を読み込む
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") # APIキーの設定
ライブラリのインストール:**
pip
を使ってpymilvus
,langchain
,sentence-transformers
,tiktoken
,openai
をインストールする。.env
ファイルから環境変数をロードするには
dotenv` を使用する。APIキーの設定:** 環境変数からOpenAIのAPIキーを取得し、設定する。
.env` ファイルに以下の形式で OpenAI API キーが含まれていることを確認してください:
OPENAI_API_KEY=your_api_key_here
LLMの初期化
環境がセットアップされたら、次のステップはアプリケーション内で使うLLMを定義することです。以下のコードでは、OpenAI ライブラリをインポートし、OpenAI のコンストラクタで LLM を定義しています。
from langchain.llms import OpenAI
llm = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
OpenAI API呼び出しに関連するコストを避けるために、オープンソースのLLMを選ぶことができます。Hugging Faceは何十万ものディープラーニングモデルを提供しており、実験することができます。HuggingFaceのオープンソースLLMを使用するには、Transformers libraryをインポートする必要があります。
from transformers import pipeline
llm = pipeline('text-generation', model='gpt2') # 'gpt2' を任意のモデルに置き換える
インポートや初期化のコードを変更することで、OpenAIとオープンソースのモデルを切り替えることができます。
適切な埋め込みモデルの選択
多言語RAGシステムを構築するとき、埋め込みモデルの選択は、LLMの選択と同じくらい重要です。埋め込みモデルは、あなたが作業している言語と互換性がなければならないからです。言語がフランス語であるこの例では、デフォルトのHuggingFace埋め込みで十分です。しかし、他の言語に対しては、最適な埋め込みモデルを特定し、使用する必要があります。
HuggingFaceのMTEBリーダーボードは、埋め込みモデルを見つけるための貴重なリソースです。このリーダーボードには、Yujianによって特定された中国語やポーランド語の埋め込みモデルのように、様々な言語に対する埋め込みモデルのトップパフォーマンスがリストアップされています。埋め込みモデルを選択する際には、パラメータとしてモデル名を指定する必要があります。
ここでは、エンベッディングモデルの設定方法を説明します:
from langchain_community.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings()
# 別の方法として、中国語の埋め込みでは、モデルがパラメータとして # 渡されます、
# HuggingFaceEmbeddings(model_name="TownsWu/PEG")
データのロードとチャンクへの分割
次に、ウィキペディアからスクレイピングした都市データファイルをロードし、セグメント(チャンク)に分割する。テキストをチャンク化することで、クエリを文書全体と比較することを避け、情報検索の効率を高めることができる。チャンクは chunk_size
パラメータで決定されるように、小さければ小さいほど精度は上がるが、より多くの検索操作が必要になる。chunk_overlap`で定義されるように、チャンク間の重複が多ければ多いほど、文脈が失われる可能性は低くなるが、その代償として冗長性が増す。
from langchain.text_splitter import CharacterTextSplitter
from langchain.schema import ドキュメント
files = os.listdir("./french_city_data")
file_texts = [].
for file in files:
with open(f"./french_city_data/{file}") as f:
file_text = f.read()
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=512, chunk_overlap=64、
)
text = text_splitter.split_text(file_text)
for i, chunked_text in enumerate(texts):
file_texts.append(Document(page_content=chunked_text、
メタデータ={"doc_title": file.split(".")[0], "chunk_num":i})
Milvusへのドキュメントのロード
都市データファイルをチャンキングし、ドキュメントのリストとして保存した後、それらをベクターストアにロードする必要があります。以下のコードでは、都市データがMilvusに格納されたときの初期ロードと更新を処理します。
from langchain_community.vectorstores import Milvus
# 最初の実行
vector_store = Milvus.from_documents(
file_texts、
embedding=embeddings、
connection_args={"host":「localhost", "port":19530},
コレクション名="french_cities"
)
# データがすでにMilvusに保存されている場合
vector_store = Milvus(
embedding_function=embeddings、
connection_args={"host":「localhost", "port":19530},
コレクション名="フランスの都市"
)
レトリバーの作成
次に、与えられたクエリに基づいて特定のソースからドキュメントを返すインターフェースであるレトリバーを初期化します。以下のコードでは、最後のステップで作成したベクター・ストアをリトリーバーとして使用し、変数に代入しています。
retriever = vector_store.as_retriever()
LangChainを使ったプロンプトテンプレートの作成
プロンプトテンプレートを使用すると、アプリケーション内で LLM への入力を正確にフォーマットすることができます。プロンプトテンプレートは、同じプロンプトのアウトラインを再利用する場合に特に便利です。
プロンプトテンプレートを使用すると、動的な入力、たとえばユーザー入力やベクターストアから取得したデータからプロンプトを作成することもできます。私たちのアプリケーションでは、直接チェーンに渡される質問と、ベクターストアから取得したコンテキストを動的に含めます。
from langchain.prompts import ChatPromptTemplate
テンプレート=""
あなたは質問応答タスクのアシスタントです。質問に答えるために、取得したコンテキストの以下の部分を使用してください。答えがわからない場合は、わからないと答えてください。
回答は3文以内で簡潔に。
フランス語で答えなさい。
質問質問
文脈{文脈}
答え:""
prompt = ChatPromptTemplate.from_template(template)
コンポーネントを連結して RAG アプリケーションを作成する
連鎖とは、コンポーネントをつなげてエンドツーエンドのAIアプリケーションを作成するプロセスで、LangChainの重要な機能のひとつです。
以下のコードは次の要素を含むチェーンを構築する方法を示している:レトリーバーからのコンテキスト、runnablepassthrough()
関数によって処理される入力プロンプト、プロンプトテンプレート、LLM、そしてチェーン呼び出しからの応答を出力するstroutparser()
。
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
chain = (
{"context": retriever, "question":RunnablePassthrough()} {"context": retriever
| プロンプト
| プロンプト
| StrOutputParser()
)
チェーンを使ったクエリーの作成
チェーンが構築されたら、様々なクエリーでチェーンを呼び出すことができる。例えば
response = chain.invoke("カラチの歴史的事実を教えてください。")
このクエリはフランス語で次のようなレスポンスを返す!
「カラチはテオフラステの植物史(Histoire des plantes de Théophraste au IIIe siècle av.J.-C.19世紀初頭にイギリスに占領され、1839年にシンドの首都となった。1876年、後にパキスタンの創設者となるムハンマド・アリー・ジンナーがカラチで生まれ、入国した。"
多言語能力を証明するために、別のクエリ-今度はフランス語だ:
response_2 = chain.invoke("Racontez-moi un fait historique sur Karachi.")
同じ質問であるにもかかわらず、異なる言語(英語とフランス語)によりエンベッディングは異なり、結果として異なる出力が得られます:
「カラチは19世紀初頭にイギリス人によって建設され、シンドの首都となった町である。重要な経済中心地であり、港を中心に急速な発展を遂げた。1980年以降、この町は民族・宗教紛争の舞台となり、2012年には歴史上最も大きな産業火災の現場となった。"
おめでとう!あなたは多言語RAGアプリケーションの構築に成功しました。エンベッディングはLLMがどのように言語を解釈するかの中心であることに留意してください。多言語をサポートするために最も適したエンベッディングを選択し、アプリケーションに統合してください。
まとめ
うわぁ!これはかなり長い記事だ。要点をいくつかまとめてみよう。
Retrieval augmented generation](https://zilliz.com/learn/Retrieval-Augmented-Generation) (RAG)は、入力プロンプトに追加データを挿入することで、LLMの出力を増強するフレームワークである。RAGは厄介なLLMの幻覚の問題を解決することができる。
多言語RAGは、多言語文書を扱うために拡張されたRAGである。
埋め込みモデル、ベクトルデータベース、LLMはRAGアプリケーションの3つのコアコンポーネントである。
多言語RAGアプリケーションの開発において重要なことは、埋め込みモデルの選択である。HuggingFaceのMTEB Leaderboardは、あなたのアプリケーションに適したモデルを見つけるための優れたリソースです。
その他のリソース
ユイジャン・タンのYouTubeプレゼンテーション](https://www.youtube.com/watch?v=UhRD_ALzAnU&list=PLPg7_faNDlT5F_6J8jjFSMw-Ars_ogtZk&index=28)
あなたのGenAIアプリのためのトップパフォーマンスエンベッディングモデル|Zilliz](https://zilliz.com/ai-models)
RAGの強化テクニック
HyDE - Hypothetical Document EmbeddingsによるRAGの改善](https://zilliz.com/learn/improve-rag-and-information-retrieval-with-hyde-hypothetical-document-embeddings)
WhyHowを使った知識グラフによるRAGの強化](https://zilliz.com/blog/enhance-rag-with-knowledge-graphs)
RAGパイプラインのパフォーマンスを向上させる方法](https://zilliz.com/learn/how-to-enhance-the-performance-of-your-rag-pipeline)
リランカーによるRAGの最適化:役割とトレードオフ](https://zilliz.com/learn/optimize-rag-with-rerankers-the-role-and-tradeoffs)
RAGアプリケーションを構築する開発者のための実践的なヒントとコツ](https://zilliz.com/blog/praticial-tips-and-tricks-for-developers-building-rag-applications)
カスタムAIモデルによるRAGのスケーリングにおけるインフラの課題](https://zilliz.com/blog/infrastructure-challenges-in-scaling-rag-with-custom-ai-models)
読み続けて

What is the K-Nearest Neighbors (KNN) Algorithm in Machine Learning?
KNN is a supervised machine learning technique and algorithm for classification and regression. This post is the ultimate guide to KNN.

Long List of Awesome DeepSeek Integrations You Should Know
Discover how DeepSeek's affordable AI ecosystem challenges Silicon Valley giants with powerful integrations for developers and businesses—from RAG systems to productivity tools, all at 90% lower cost.

Empowering Innovation: Highlights from the Women in AI RAG Hackathon
Over the course of the day, teams built working RAG-powered applications using the Milvus vector database—many of them solving real-world problems in healthcare, legal access, sustainability, and more—all within just a few hours.