🔥
コンテキストアウェアリフレクティブ方式QAデータセット生成システムの実装
はじめに
このノートブックでは、LLMを使用して高品質なQAデータセットを生成するシステムを実装します。特徴は以下の通りです:
- コンテキストアウェアな質問生成
- リフレクティブな品質評価・改善
- 自動的なデータセットのアップロード
環境セットアップ
!pip install -q litellm tqdm loguru wikipedia transformers
!pip install -q datasets huggingface-hub
必要なライブラリをインストールします。主な依存関係:
- litellm: LLMとの対話用
- tqdm: プログレスバー表示
- loguru: ロギング
- wikipedia: Wikipedia APIクライアント
- transformers & datasets: Hugging Face関連
基本設定とインポート
import wikipedia
import json
from typing import List, Dict, Any
from loguru import logger
import re
from tqdm import tqdm
from datetime import datetime
from pathlib import Path
# 基本パラメータ
MODEL_NAME = "ollama/llama3.1:8b-instruct-fp16"
DEFAULT_CHUNK_SIZE = 200
DEFAULT_OVERLAP_SIZE = 500
DEFAULT_QA_PAIRS_PER_CHUNK = 5
API_BASE = "http://localhost:11434"
主な設定項目の説明:
- MODEL_NAME: 使用するLLMモデル
- DEFAULT_CHUNK_SIZE: テキスト分割サイズ
- DEFAULT_OVERLAP_SIZE: チャンク間のオーバーラップ
- DEFAULT_QA_PAIRS_PER_CHUNK: 1チャンクあたりのQA生成数
WikiTextProcessor クラスの実装
class WikiTextProcessor:
"""Wikipediaテキストの処理とチャンク分割を行うクラス"""
@staticmethod
def get_wiki_text(topic: str, lang: str = "ja") -> str:
"""指定されたトピックのWikipedia記事を取得"""
wikipedia.set_lang(lang)
try:
page = wikipedia.page(topic)
return page.content
except Exception as e:
logger.error(f"Error fetching {topic}: {e}")
return ""
@staticmethod
def clean_text(text: str) -> str:
"""テキストのクリーニング"""
text = re.sub(r'\[\d+\]', '', text) # 参照記号の削除
text = re.sub(r'\n\s*\n', '\n', text) # 余分な改行の削除
return text.strip()
WikiTextProcessorの機能:
- Wikipedia記事の取得
- テキストのクリーニング
- チャンク分割とコンテキスト付与
QAGenerator クラス
class QAGenerator:
"""Q&Aペアの生成を担当するクラス"""
@staticmethod
def generate_qa_pairs_with_context(
chunk_data: Dict[str, str],
num_pairs: int = DEFAULT_QA_PAIRS_PER_CHUNK,
max_retries: int = 3
) -> List[Dict[str, str]]:
# プロンプトの構築
prompt = f"""
以下のテキストから質問と回答のペアを{num_pairs}つ生成してください。
## 全体の文脈:
{chunk_data['summary']}
## テキストの位置:
テキスト全体の{int(chunk_data['position'] * 100)}%付近
## メインテキスト:
{chunk_data['chunk_text']}
出力形式:
{{
"qa_pairs": [
{{"question": "具体的な質問1?", "answer": "回答1"}},
{{"question": "具体的な質問2?", "answer": "回答2"}}
]
}}
"""
# LLMを使用してQAペアを生成
QAGeneratorの主な特徴:
- コンテキストを考慮したQA生成
- 固有名詞の明示的な使用
- 質問の独立性確保
リフレクティブな評価と改善
@dataclass
class QAEvaluation:
"""Q&Aペアの評価結果を保持するデータクラス"""
score: float
feedback: str
improvement_suggestions: List[str]
factuality_score: float
question_quality_score: float
answer_completeness_score: float
def evaluate_qa_pair(self, qa_pair: Dict[str, str], context: Dict[str, str]) -> QAEvaluation:
"""Q&Aペアを評価し、詳細なフィードバックを生成"""
evaluation_prompt = f"""
質問: {qa_pair['question']}
回答: {qa_pair['answer']}
以下の基準で評価してください:
1. 事実性 (0-1)
2. 質問の質 (0-1)
3. 回答の完全性 (0-1)
"""
# LLMを使用して評価を実行
評価システムのポイント:
- 複数の評価基準
- 具体的な改善提案
- 反復的な品質向上
データセット生成とアップロード
def create_dataset(self, topics: List[str], output_file: str = "qa_dataset.json") -> None:
"""データセット生成のメインプロセス"""
all_qa_pairs = []
for topic in topics:
# Wikipedia記事の取得と処理
text = self.wiki_processor.get_wiki_text(topic)
text = self.wiki_processor.clean_text(text)
# チャンク分割とQA生成
chunks = self.wiki_processor.split_into_chunks_with_context(text)
for chunk in chunks:
qa_pairs = self.qa_generator.generate_qa_pairs_with_reflection(chunk)
all_qa_pairs.extend(qa_pairs)
# 結果の保存
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(all_qa_pairs, f, ensure_ascii=False, indent=2)
最後に、生成したデータセットをHugging Faceにアップロードする機能も実装されています。
パラメータチューニングのヒント
効果的なデータセット生成のためのパラメータ調整のコツ:
-
チャンクサイズ(chunk_size)
- 推奨: 200-300文字
- 長すぎると文脈が散漫に
- 短すぎると文脈が失われる
-
オーバーラップサイズ(overlap_size)
- 推奨: チャンクサイズの40-60%
- 文脈の連続性維持が重要
-
品質閾値(quality_threshold)
- 推奨: 0.8以上
- 厳しすぎると生成数が減少
- 緩すぎると品質が低下
使用例
# データセット生成の実行
creator = DatasetCreator(config={
"chunk_size": 200,
"overlap_size": 500,
"qa_pairs_per_chunk": 5,
"quality_threshold": 0.8,
"max_improvement_attempts": 2
})
topics = ["霊烏路空", "物部布都"]
creator.create_dataset(topics=topics, output_file="touhou_qa.json")
このシステムの特長は、単なるQA生成だけでなく、生成された各QAペアに対して品質評価と改善を行う点です。これにより、より高品質なデータセットの作成が可能になります。
📒ノートブック
Discussion