PythonでRAGを実装:Ollama(llama3.1)+Chroma DBで“検索して答える”

AIテキスト

今回はPythonからRAGを実装します。

Chroma DBで検索した結果をプロンプトに差し込んで、OllamaのLLM(llama3.1)で文章を生成するまでを試してみます。

まず「ユーザー側検索」のRAGを試す

RAGには大きく分けて、アプリ側で検索して結果をLLMに渡す方法と、LLMに指示してツール呼び出しで検索をさせる方法と、2通りの構成があります。

最初に試すなら、構成が単純で原因切り分けもしやすいユーザー側検索がおすすめです。

Chroma DBでの検索結果を「追加コンテキスト」として渡すだけなので、原理としては基本的にどのLLMでも成立します。

なぜllama3.1を選ぶのか

Llama 3.1はMetaが公開したモデルファミリーで、8B/70B/405Bなどのサイズが提供されています。
Introducing Llama 3.1: Our most capable models to date

Llama 3.1はツール呼び出し(Function Calling)に対応しており、将来「LLM側検索」に拡張したいときの比較対象としても便利です。Llama3.2 も公開されていますが、Function Calling未対応のため、現時点でのRAG用途には3.1が適しています。
Llama 3.1 | Model Cards and Prompt formats

Ollamaでもllama3.1は提供されており、ローカル検証で扱いやすい軽量なllama3.1:8bが利用可能で、コマンドラインから簡単にモデルを取得できます。

ollama pull llama3.1:8b

OllamaとChroma DBの準備

Pythonは3.11系がバランスが良いでしょう。

Chroma DBはベクトルDBとして、Pythonからの作成・追加・検索が最小手数で進められます。

OllamaはローカルでLLMを動かす基盤で、API仕様も公開されておりPythonからの利用も簡単です。

PythonからOllamaを使う方法はいくつかありますが、公式のollama-pythonがシンプルです。
GitHub – ollama/ollama-python: Ollama Python library

pipでollamaとchromadbの両方をインストールしておきます。

pip install ollama chromadb

Chromaで検索してOllamaで回答する

「質問文で検索→検索結果をコンテキストとして渡す」というRAGを試します。

以下のコードは、Chroma DBから検索した結果をプロンプトに追加して回答を生成する例です。

import ollama
import chromadb
from chromadb.config import Settings

# Ollamaクライアントの初期化
ollama_client = ollama.Client()

# Chroma DB の初期化
chroma_client = chromadb.Client(Settings())
collection = chroma_client.create_collection(name="sample_texts")

# サンプルデータ投入は省略...

# 質問文に近い文章を検索
user_question = "吉はどんな内容でしたか?"
result = collection.query(
    query_texts=[user_question],
    n_results=2
)
docs = result.get("documents", [])
context = "\n".join(docs[0]) if docs and docs[0] else ""

# 検索結果を追加コンテキストとして渡す
prompt = (
    "以下の情報のみを使って質問に答えてください。"
    "情報にない場合は「わかりません」と答えてください。\n\n"
    f"参考情報:\n{context}\n\n"
    f"質問: {user_question}\n回答:"
)
print(prompt)
      
res = ollama_client.generate(model="llama3.1:8b", prompt=prompt)
print(res["response"])

Chromaへのデータ投入についてはこちらの記事も参照ください。

実行例

以下の情報のみを使って質問に答えてください。情報にない場合は「わかりません」と答えてください。

参考情報:
吉:派手さはありませんが、堅実な選択が後で効いてきます。
吉:安定した運気で、日常作業を丁寧に進めると評価が高まります。

質問: 吉はどんな内容でしたか?
回答:
派手さがありませんが、堅実な選択が後で効いてきます。安定した運気です。

知識ベースの参考情報がLLMに渡され、統合された内容が生成されました。

ユーザー側検索とプロンプト設計のポイント

本記事で扱うRAGの場合、関連する知識ベースの検索に、ユーザー側の発言がそのまま利用されます。

LLM側検索と異なり、検索クエリの最適化は不要ですが、プロンプト設計は重要です。 特に、LLMに対して、検索結果をどのように利用して回答すべきかを明示するのがポイントです。

チャットボットなど、正確な回答が必要である場合、LLMに知識ベースで得られた情報のみを使うように指示します。

プロンプト例: “以下の情報のみを使って質問に答えてください。情報にない場合は「わかりません」と答えてください。”

会話の補強など、創造性を重視する場合は、LLMの強みを活かし推測を行うように指示するのも有効です。

プロンプト例: “以下の情報を参考にして、質問に答えてください。ただし、情報にない場合は、自分の知識を使って推測してください。”

実用には知識ベース以外にも会話履歴などの情報をLLMに渡す必要があり、コンテキスト長の制約も加味したチューニングが重要です。

まとめ

今回は、OllamaのLLMとChroma DBを使って、RAGの基本的な構成を試しました。 ユーザー側で検索を行い、その結果をLLMに渡すシンプルなRAG構成を実装しました。 この方法は多くのLLMで利用可能であり、RAGの基本を理解するのに適しています。

次回は、LLM側でのRAGを試し、ユーザー側検索との違いや利点を比較してみます。

タイトルとURLをコピーしました