How to Create a RAG Agent with Reflection より
目次
Part 1: RAGとレレバンス問題の理解
RAG(Retrieval Augmented Generation)とは
RAG(Retrieval Augmented Generation)は、言語モデルに外部情報を供給することで性能を向上させる強力な技術です。この手法により、AIシステムは応答を生成する際に事前学習された知識だけでなく、外部知識ベースから最新の事実にアクセスできるようになります。
なぜRAGが重要なのでしょうか?言語モデルは強力ですが、以下のような制限があります:
- 知識が学習データに限定される
- 情報が古くなる可能性がある
- ハルシネーション(虚偽の情報生成)が発生する可能性がある
RAGはこれらの問題に対処するため、応答を生成する前に関連する外部情報を取得し、モデルに動的な知識ベースへのアクセスを提供します。
基本的なRAGパイプライン
標準的なRAGパイプラインは、次の2つの主要ステップで構成されています:
- 取得ステップ(Retrieval Step):システムが外部ソース(ベクトルデータベースやWeb検索など)からユーザークエリに関連するコンテキストを取得します
- 生成ステップ(Generation Step):言語モデルが取得したコンテキストと元のクエリを使用して、情報に基づいた応答を生成します
これは以下のように視覚化できます:
基本的なRAGプロセスは、ユーザークエリから外部知識の取得、そしてクエリと取得したコンテキストを組み合わせて応答を生成する言語モデルへと流れていきます。
セマンティック検索の限界
ほとんどのRAG実装は、取得ステップでセマンティック検索に依存しています。セマンティック検索は、クエリと知識ベース内のドキュメントの間の意味的類似性に基づいて結果を返します。効果的ですが、この手法には以下のような限界があります:
- 上位の結果はトピック的に類似していても、特定の質問に直接関連していない場合がある
- 意味的類似性が必ずしも質問に対する有用性に変換されるわけではない
- システムが関連性の薄い情報を大量に取得し、言語モデルを圧倒する可能性がある
例えば、ユーザーが「去年のWarriorsの成績は?」と尋ねた場合、セマンティック検索は前シーズンの勝敗記録に焦点を当てるのではなく、Warriorsチームの歴史、注目の試合、選手の統計など、一般的な情報を返す可能性があります。
RAGパイプラインにおける評価の必要性
これらの限界に対処するために、RAGパイプライン内に評価ステップを導入する必要があります。これらの評価は以下の役割を果たします:
- 品質フィルター - 真に関連性の高い情報のみが言語モデルに到達することを保証
- リフレクションメカニズム - 生成された回答が実際にユーザーの質問に対応しているかを確認
これらの評価ステップを導入することで、RAGベースのシステムからの応答の品質を大幅に向上させることができます。
Part 1のまとめ:RAGは外部知識を活用して言語モデルの応答を向上させる技術ですが、単純なセマンティック検索だけでは関連性の低い情報も取得してしまいます。この問題を解決するために、評価ステップを導入して情報の品質をフィルタリングする必要があります。
Part 2: Open Evalsを活用したIn-the-loop評価
Open Evalsの紹介
Open Evalsは、RAGシステムを含む言語モデルアプリケーション向けに設計された、すぐに使用できる評価ツールを提供するオープンソースパッケージです。以下の特徴があります:
- LMパフォーマンスの異なる側面に対する事前構築された評価器
- ブラックボックスおよびホワイトボックス評価の両方のサポート
- 既存のパイプラインとの柔軟な統合
- 一貫した評価方法
Open Evalsを使用することで、開発者は複雑な評価ロジックをゼロから構築する必要がなく、アプリケーションの最適化に集中できます。
RAGに役立つ評価指標
Open Evalsは、RAGアプリケーションに特に役立ついくつかの評価器を提供しています:
- 正確性評価器(Correctness Evaluator):生成された回答が正解とどれだけ一致するかを測定
- 有用性評価器(Helpfulness Evaluator):回答がユーザーの質問に適切に対応しているかを評価
- 根拠評価器(Groundedness Evaluator):最終的な回答が取得されたコンテキストによってサポートされているかをチェック
- 検索関連性評価器(Retrieval Relevance Evaluator):取得された各ドキュメントが元の質問にどれだけ関連しているかをスコアリング
強化されたRAGパイプラインでは、RAGシステムで一般的に発生する障害に直接対処する「検索関連性評価器」と「有用性評価器」に焦点を当てます。
強化されたアーキテクチャ概要
強化されたRAGアーキテクチャでは、従来のパイプラインに2つの重要なリフレクションステップを導入します:
- 生成前リフレクション:言語モデルに到達する前に、検索結果の関連性を評価・フィルタリング
- 生成後リフレクション:生成された回答がユーザーの質問に対して有用かどうかをチェック
強化されたアーキテクチャは以下のようになります:
このアーキテクチャにより、生成に使用される情報が関連性の高いものだけであり、応答が実際にユーザーの質問に対応していることが保証されます。
リフレクションステップの設定
このアーキテクチャを実装するには、以下が必要です:
- 関連性フィルターがどのように取得されたドキュメントを評価・フィルタリングするかを定義する
- 生成された応答をチェックするための有用性評価器をセットアップする
- 必要な場合に応答の再構成を要求するためのフィードバックループを作成する
これらのリフレクションステップでは、言語モデルを判断者として使用し、関連性と有用性を評価するための理解能力を活用します。
Part 2のまとめ:Open Evalsは、RAGパイプラインに評価ステップを簡単に組み込むためのツールセットを提供します。検索関連性と回答の有用性をチェックする2つのリフレクションステップを使用して、RAGアーキテクチャを強化できます。
Part 3: 強化されたRAGパイプラインの構築
レレバンスフィルタリングの実装
レレバンスフィルタリングステップでは、取得された各ドキュメントを個別に評価し、ユーザーのクエリに本当に関連しているかどうかを判断します。実装は以下のようになります:
def relevance_filter(state):
# ステートから最後のメッセージを抽出(検索結果であるはず)
last_message = state["messages"][-1]
# メッセージが検索ツールからのものか確認
if last_message["role"] == "tool" and last_message["name"] == "search":
# 検索結果を抽出
search_results = last_message["content"]
filtered_results = []
# 評価関数を定義
async def evaluate(result):
# Open Evalsから関連性評価器を作成
evaluator = RelevanceEvaluator()
# ステートから元のクエリを取得
query = state["original_query"]
# 関連性を評価
eval_result = await evaluator.evaluate(query=query, context=result)
return result, eval_result
# 各ドキュメントのタスクを作成
tasks = [evaluate(result) for result in search_results]
# 結果を処理
for task in asyncio.as_completed(tasks):
result, eval_output = await task
# 関連性があれば、結果を保持
if eval_output["score"] == True:
filtered_results.append(result)
# フィルタリングされた結果を返す
return {"role": "tool", "name": "search", "content": filtered_results}
# 検索結果でなければ、変更せずに通過させる
return last_message
この実装は:
- 検索結果が返されたときを識別する
- 各結果に対して評価器を作成する
- 評価を並列で実行する
- 関連性の低い結果をフィルタリングする
- 次のステップのために関連性の高いドキュメントのみを返す
レレバンスフィルタリングの仕組み
レレバンスフィルタリングプロセスは以下のように視覚化できます:
関連性評価器は、言語モデルを使用して、各ドキュメントが特定のユーザークエリに答えるのに役立つ情報を含んでいるかどうかを評価します。これによりノイズが減少し、言語モデルが関連性の低い情報に圧倒されることを防ぎます。
有用性評価の実装
有用性評価ステップでは、生成された応答が適切にユーザーの元の質問に対応していることを確認します:
def reflect_on_helpfulness(state):
# 最後のメッセージ(生成された応答)を抽出
last_message = state["messages"][-1]
# アシスタントのメッセージの場合のみ評価
if last_message["role"] == "assistant":
# 有用性評価器を作成
evaluator = HelpfulnessEvaluator()
# 元のクエリを取得
original_query = state["original_query"]
# 生成された回答
answer = last_message["content"]
# 有用性を評価
eval_result = evaluator.evaluate(query=original_query, response=answer)
# 有用でない場合、再試行をトリガー
if eval_result["score"] < 0.7: # 有用性のしきい値
reflection_message = {
"role": "user",
"content": f"""あなたの前の回答は私の質問に直接対応していませんでした: "{original_query}"
評価結果: {eval_result["reasoning"]}
もう一度試して、私の元の質問に具体的に焦点を当ててください。
"""
}
# リフレクションメッセージを挿入して再試行をトリガー
return reflection_message
# 有用であるか、アシスタントメッセージでない場合は通過させる
return last_message
この実装は:
- 応答が生成されたときを識別する
- 有用性評価器を作成する
- 応答を元のクエリと比較する
- 有用でない場合、フィードバックを提供し再構成を要求する
- 有用な場合、応答を進行させる
リトライメカニズム
応答が有用でないと判断された場合、リフレクションステップはフィードバックを生成し、会話に挿入します。これにより、再試行ループが作成されます:
このリトライメカニズムにより、初期生成が的外れであっても、ユーザーに配信される最終応答が実際に質問に対応していることが保証されます。
Part 3のまとめ:レレバンスフィルタリングと有用性評価の2つのリフレクションステップを実装することで、RAGパイプラインを大幅に改善できます。レレバンスフィルタリングは関連性の低いコンテキストを除去し、有用性評価は回答がユーザーの質問に適切に対応していることを確認します。
Part 4: 実証と結果
基本エージェントと強化エージェントの比較
基本エージェントと強化エージェント(リフレクションステップ付き)が同じクエリに対してどのように機能するかを比較してみましょう:「去年のWarriorsの成績は?」
基本エージェントの応答:
基本エージェントは10件の検索結果を取得し、Warriorsの歴史、注目の試合、業績に関する長い回答を生成しましたが、前シーズンの成績を明確に述べませんでした。その応答はトピック的には関連していましたが、特定の質問に直接答えるものではありませんでした。
強化エージェントの応答:
強化エージェントは:
- 同じ10件の検索結果を取得
- Warriorsの成績に特定に言及しているもののみにフィルタリング
- 簡潔な回答を生成:「Golden State Warriorsは2022-2023 NBAシーズンを44勝38敗(44-38)の成績で終えました。」
- この応答がユーザーの質問に直接答えていることを確認
強化エージェントは、クエリに対応するために必要な情報のみに焦点を当てることで、より正確で関連性の高い回答を提供しました。
トレース分析
強化エージェントのトレースを調査することで、リフレクションステップの動作を確認できます:
- ユーザークエリを受信:「去年のWarriorsの成績は?」
- エージェントが検索クエリを生成:「Golden State Warriors record last year」
- Webサーチツールから10件の検索結果が取得される
- 各結果は個別に関連性が評価される:
- 結果1:Warriorsのスコアと統計が含まれているが、成績が記載されていない → フィルタリング
- 結果2:前シーズンのWarriorsの成績が含まれている → 保持
- 結果3-10:Warriorsの成績に特定していない様々な情報 → フィルタリング
- エージェントは関連性のある結果のみを使用して応答を生成
- 有用性評価器が、応答が元の質問に直接答えていると判断
- 最終応答がユーザーに提供される
このトレースは、リフレクションステップがノイズをフィルタリングし、品質を確保することで、より正確な応答につながることを示しています。
In-the-loop評価の適用タイミング
In-the-loop評価は、特に以下の場合に価値があります:
- 精度が重要な場合:一般的な情報ではなく、正確な回答が必要な場合
- ノイズの多いデータソースを使用する場合:Webなどの広範なソースから情報を取得する場合
- 小規模な言語モデルを使用する場合:関連性の低いコンテキストをフィルタリングすることで、小規模モデルが関連情報に集中できる
- 複数ステップの推論チェーンを構築する場合:評価はエラーの伝播を防止する
ただし、これらの評価は計算オーバーヘッドを追加するため、すべてのアプリケーションで必要とは限りません。
RAGパイプラインの最適化
強化されたRAGパイプラインを最大限に活用するには:
- 評価のしきい値を調整する:特定のアプリケーションに基づいて、関連性と有用性の評価の厳密さを調整する
- 精度と再現率のバランスを取る:フィルタリングが厳しすぎると、有用な情報を見逃す可能性がある
- 評価結果のキャッシュを検討する:同じクエリが頻繁に表示される場合、結果をキャッシュして計算負荷を減らす
- 評価パターンをモニタリングして分析する:一般的な障害モードを特定し、システムを最適化する
- 他のRAG強化と組み合わせる:クエリの再構成、ドキュメントの再ランキング、回答の合成は評価ステップを補完できる
これらのベストプラクティスを実装することで、ユーザークエリに対して高品質で関連性の高い応答を提供する堅牢なRAGシステムを構築できます。
Part 4のまとめ:In-the-loop評価を実装することで、RAGシステムの応答品質が大幅に向上します。適切な設定とベストプラクティスの実施により、システムを最適化して最高の結果を得ることができます。
まとめ
RAG(Retrieval Augmented Generation)は外部知識を活用して言語モデルの応答を強化する強力な技術ですが、単純な実装では関連性の低い情報も取得してしまう可能性があります。In-the-loop評価を導入することで、以下の利点が得られます:
- 関連性フィルタリング:言語モデルに渡す前に検索結果を評価し、関連性の高い情報のみを選別
- 有用性評価:生成された応答がユーザーの質問に適切に対応しているかを確認し、必要に応じて回答の再構成を要求
Langchainが提供する「Open Evals」などのツールを使用することで、これらの評価ステップを簡単に実装でき、RAGシステムの全体的な品質と精度を大幅に向上させることができます。
最終的に、In-the-loop評価を備えたRAGシステムは、より正確で、関連性が高く、ユーザーの意図に沿った応答を生成し、ユーザーエクスペリエンスを向上させることができます。