【Ragas】日本語テストセットの生成方法のご紹介【v0.2】

こんにちは、サイオステクノロジーの佐藤 陽です。
アドベントカレンダー登場2回目です。

今日はRagasのv0.2における日本語のテストセット生成方法についてご紹介します。
すぐに利用できるソースコードも載せてますので、「最新のRagas使ってテストセットを自動生成したい!」という方は是非最後までご覧ください。

はじめに

本日紹介するのは、現状最新バージョンであるv0.2のRagasを使ったテストセット生成方法です。

テストセットとは、Ragasの評価時に利用される質問と回答のペアのデータになります。
このRagasでは、与えた文章に基づいて質問(question)と回答(reference)のペアを自動で作成してくれます。

例えば「社内規約」の文章を与えた時には、その文章に基づき

  • 質問:有給休暇は何日取れますか?
  • 回答:繰越すことで最大で40日まで取得可能です

といったペアを生成します。

今回のケースであれば、「社内規約」をよく知る人間がテストセットを生成するのが一番間違いはないのですが
人力で膨大なテストセットを作成するのも大変なので、Ragasの機能で自動生成してもらうのも一つの手段かとは思います。

公式ドキュメントにテストセット生成に関するチュートリアルがあるのですが、
チュートリアルをそのまま行うと日本語のドキュメントを読み込んでも、英語の内容でテストセットが生成されてしまいます。
そのため本記事では、日本語でテストセットを紹介する方法をご紹介したいと思います。

なお、本記事はv0.2.6のバージョンにおける内容であり、今後変更の可能性があります。
最新の情報に関しては公式のドキュメントを参照してください。

現状の把握

v0.1の時からもテストセットの生成方法の機能は用意されていました。
ただ、v0.1から大きなリファクタリングが実施され、利用方法が異なっています。

とはいいつつ、丁寧なチュートリアルが提供されているのでその通りやれば問題なくテストセットが生成されます。

ただ、この通りに実施すると、日本語の文章を読み込ませたとしても質問と回答のペアが英語で出力されてしまいます。
この理由としては、テスト生成に利用するためのプロンプトが英語で書かれているためです。

これに対して、「多言語に対応どうやるの?」といった内容のIssueも挙がっていました。

Issueに対する実装としては既にマージ済みなのですが、ドキュメントには現状書かれていないようです。
こちらのIssueに、「TODOリストとしてドキュメントを作成する」というタスクは追記してあるので、順次対応予定のようです。

ただ、そこを一歩先取りして本ブログで紹介してしまおう!というのが本記事の目的です。

ということで、将来的には既に公式ドキュメントに記載されているかもしれませんし、もしかしたら実装方法が変更になっている可能性もあります。
まだまだRagasも変化も多い状況だと思うので、その点踏まえて読んでいただきたいと思います。

多言語対応の仕組み

まず初めに多言語対応の仕組みについて紹介します。
その方法はずばり、構築済みのプロンプトに日本語を適用するです。

そしてこの方法が「Adapting metrics to target language」として公式の記事にも紹介されています。

またこれはテストセット生成に限った話ではなく、
FaithfulnessやContextRecallの評価といった通常の評価フェーズの際にも利用できる仕組みです。

adapt_promptsというメソッドを利用し、既に用意されているプロンプトに対して指定した言語を適用させます。
そしてこのメソッドはPromptMixinというクラスで定義されており、このクラスは以下のように定義されています。

Mixin class for classes that have prompts.

つまり、これを継承する「プロンプトを扱うようなクラス」はadapt_promptsを利用できることになります。
この仕組みを利用し、テストセットを生成するプロンプトに対して日本語を適用し、日本語のテストセットを作成していきます。

実装

チュートリアルの確認

まずはチュートリアルにあるテストセット生成の流れを確認します。

なお今回はAzure OpenAI Serviceを利用してテストセット生成を行います。
ChatとEmbeddingsのモデルをそれぞれデプロイしておいてください。

チュートリアルの内容に沿って以下のソースコードを作成しました。
なお、エンドポイントやAPIキーなどは.envファイルに格納しているため、適宜作成してください。

import os
import asyncio
from dotenv import load_dotenv
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
from ragas.testset import TestsetGenerator
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings
from langchain_community.document_loaders import DirectoryLoader

#.envファイル変数読み込み
load_dotenv()
# 環境変数に値をセット
os.environ["AZURE_OPENAI_API_KEY"] = os.getenv("AZURE_OPENAI_API_KEY")
os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv("AZURE_OPENAI_ENDPOINT")
os.environ["OPENAI_API_VERSION"] = os.getenv("OPENAI_API_VERSION")

async def main():
    # ChatModel定義
    generator_llm = LangchainLLMWrapper(AzureChatOpenAI(
        azure_deployment="gpt-4o-mini-deploy",
        temperature=0.8,
    ))

    # EmbeddingsModel定義
    generator_embeddings = LangchainEmbeddingsWrapper(AzureOpenAIEmbeddings(
        azure_deployment="text-embedding-3-small-deploy"
    ))
    
    # Generatorの生成
    generator = TestsetGenerator(llm=generator_llm, embedding_model=generator_embeddings)

    # テストセット生成のベースとなる文章をロード
    path = "Sample_Docs_Markdown/"
    loader = DirectoryLoader(path, glob="**/*.md")
    docs = loader.load()

    # テストセット生成
    testset = generator.generate_with_langchain_docs(docs, testset_size=3)

    df = testset.to_pandas()
    # データフレームをCSVファイルとして保存
    csv_file_path = "generated_testset.csv"
    df.to_csv(csv_file_path, index=False)

asyncio.run(main())

今回は読み込むドキュメントとしては、サイオステクノロジーに関するWikipediaの内容をDocumentIntteligenceでmd化したものとします。
sios.mdというファイルでSample_Docs_Markdownの配下に保存します。
Smaple_Docs_Markdown/sios.md
では上記のプログラムを実行します。

すると以下のようなテストセットが出力されました。(一部省略)
なぜか、2つ目の質問だけは日本語で回答されましたが、他は見事に英語です。

 

user_input reference_contexts reference synthesizer_name
What historical developments have shaped our current understanding of the subject? [‘1 沿革\n\n’] The historical developments that have shaped our current understanding of the subject are not detailed in the provided context. AbstractQuerySynthesizer
How do the technological offerings and solutions of サイオステクノロジー compare with those of other companies in the fields of open source software, business continuity solutions, and cloud integration, particularly in relation to Linux and Gluegent Apps? [‘サイオステクノロジー株式会社は、オープンソースソフトウェアとJavaを基盤にしたシステムやソフトウェアの開発、販売、サポートを行う企業で、2017年に設立されました。主な製品には、事業継続ソリューションの「LifeKeeper」やデータ複製ソフト「DataKeeper」があります。また、Google Appsとの連携を提供するクラウドソリューションや、業務プロセスを簡素化するワークフローシステム「Gluegent Flow」なども展開しています。さらに、セキュリティソリューションやオープンソースに関するサポートも行っています。’] サイオステクノロジーは、オープンソースソフトウェアやJavaを基盤にしたシステムの開発、事業継続ソリューションの提供、Google Appsとの連携を含むクラウドソリューションを展開しており、特にLinuxやGluegent Appsに関連する技術的な提供やソリューションは、他社と比較して独自の製品群を持っています。 ComparativeAbstractQuerySynthesizer
What functionalities do Gluegent Apps provide for companies using Google Workspace or Microsoft 365? [‘7 外部リンク\n\n☐目次の表示・非表’] Gluegent Apps provide functionalities such as a shared address book for searching and selecting personnel within a company, a group scheduler for visualizing schedules by department or team, and gadgets that can be embedded in corporate portal sites, all designed for companies using Google Workspace or Microsoft 365. SpecificQuerySynthesizer

2つ目の回答が日本語だったことに関しては

  • 「サイオステクノロジー」が重要な単語であると推察され、質問文作成時に翻訳されなかった
  • 質問文に日本語が入っているため、回答としても日本語で返された

といったことではないかな、と考察しました。

ちなみに内容としてはそれなりにいい感じです。
なので、テストセット生成としては問題ないのですが、英語に精通していない人間が評価内容をチェックするのが大変です。

では、いよいよここから日本語対応していきます。

日本語化対応

先程述べた adapt_prompts を利用していきます。

こちらのプルリクエストにて以下のサンプルコードが書かれていたのですが
これだけだと全体が把握できなかったのでこれを踏まえて手探りでやっていきます。

synthesizer = AbstractQuerySynthesizer()
adapted_prompts = await synthesizer.adapt_prompts("dutch", llm)
synthesizer.set_prompts(**adapted_prompts)

どうやら、QuerySynthesizerというのが肝のようです。
これについては公式のドキュメントにも定義があり、シナリオを作成するための役割を持ちます。
「シナリオって何?」と思われるかと思うのですが、テストセット生成の仕組みに関しては別途記事にしたいと思うので、ここでは割愛させていただきます。

簡単に書くと、様々な質問文を生成するために必要な情報(質問の長さ、使用する情報)をまとめたものになります。
そしてこのシナリオを元に質問文(=question=Query)や回答のペアを生成します。

つまり、このQuerySynthesizerがテストセットを作成する親玉であり、ここに対して日本語を適用していきます。

なお、このQuerySynthesizerの元になっているBaseSynthesizerというクラスを見ると、PromptMixinクラスを継承していることも確認できます。
つまり adapt_prompts のメソッドも使えることが分かりますね。

そして、この日本語を適用したQuerySynthesizerをどこで反映させるかというと
テストセットを作成するgenerate_with_langchain_docsの引数として与えることができます。

なのでステップとしては

  1. QuerySynthesizerに対して日本語を適用(adapt_prompts)
  2. 日本語が適用されたQuerySynthesizerを利用してテストセット生成

といった感じです。
流れが分かったところで早速これらを反映したソースコードを見てみます。

import os
import asyncio
from dotenv import load_dotenv
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
from ragas.testset import TestsetGenerator
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings
from langchain_community.document_loaders import DirectoryLoader
from ragas.testset.synthesizers import AbstractQuerySynthesizer

load_dotenv()
os.environ["AZURE_OPENAI_API_KEY"] = os.getenv("AZURE_OPENAI_API_KEY")
os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv("AZURE_OPENAI_ENDPOINT")
os.environ["OPENAI_API_VERSION"] = os.getenv("OPENAI_API_VERSION")

async def main():
    generator_llm = LangchainLLMWrapper(AzureChatOpenAI(
        azure_deployment="gpt-4o-mini-deploy",
        temperature=0.8,
    ))

    generator_embeddings = LangchainEmbeddingsWrapper(AzureOpenAIEmbeddings(
        azure_deployment="text-embedding-3-small-deploy"
    ))

    generator = TestsetGenerator(llm=generator_llm, embedding_model=generator_embeddings)

    path = "Sample_Docs_Markdown/"
    loader = DirectoryLoader(path, glob="**/*.md")
    docs = loader.load()

    #Synthesizerのインスタンスを生成
    synthesizer = AbstractQuerySynthesizer(llm=generator_llm)
    #シンセサイザーのプロンプトに日本語を適用
    adapted_prompts = await synthesizer.adapt_prompts("japanese", generator_llm)
    #プロンプトをセット
    synthesizer.set_prompts(**adapted_prompts)

    #generate_with_langchain_docsに引き渡すためのデータ整備
    query_distribution = [
        (synthesizer, 1.0) #1.0は割合を表し、今回はこのSynthesizerを100%利用することを表す。他のSynthesizerと組み合わせる事も可能。
    ]
    # テストセット生成
    testaset = generator.generate_with_langchain_docs(docs, testset_size=3, query_distribution=query_distribution) #query_distributionを引数としてあたえる
    
    df = testset.to_pandas()

    # データフレームをCSVファイルとして保存
    csv_file_path = "generated_testset.csv"
    df.to_csv(csv_file_path, index=False)


asyncio.run(main())

このプログラムを実行すると以下の結果が得られました。
全ての質問および回答が日本語で生成されていることが分かります。

user_input reference_contexts reference synthesizer_name
沿革の重要性は何ですか? [‘1 沿革\n\n’] 沿革の重要性は、歴史的な背景や発展の過程を理解することで、現在の状況や未来の方向性を把握する手助けとなることです。 AbstractQuerySynthesizer
企業名の由来はどう企業のアイデンティティや価値反映するの? [‘2 社名の由来\n\n’] 企業名の由来は、企業のアイデンティティや価値を反映する重要な要素です。 AbstractQuerySynthesizer
主な製品・サービスはどのように相互に関連し、ビジネス戦略に寄与するのか? [‘3 主な製品・サービス\n\n’] 主な製品・サービスの相互関連性とビジネス戦略への寄与についての具体的な情報は提供されていません。 AbstractQuerySynthesizer

なお、今回はPRのusageを例にAbstractQuerySynthesizerを採用したため非常に抽象的なテストセットとなりました。
もちろん他のSynthesizerを利用しても問題ありません。
試しにComparativeAbstractQuerySynthesizerを使うため、以下の部分の書き換えを行います。

synthesizer = ComparativeAbstractQuerySynthesizer(llm=generator_llm) # 対象のSynthesizerを変更
adapted_prompts = await synthesizer.adapt_prompts("japanese", generator_llm)
synthesizer.set_prompts(**adapted_prompts)

すると以下のような結果が得られ、回答内容がガラッと変わることも分かります。

user_input reference_contexts reference synthesizer_name
サイオステクノロジー オープンソースソフトウェア 事業継続ソリューション Linux クラウドソリューション 技術 特性 機能 比較 評価 レポート [‘サイオステクノロジー株式会社は、オープンソースソフトウェアとJavaを基盤にしたシステムやソフトウェアの設計、開発、販売、サポートを行う企業で、2017年に設立されました。主な製品には、事業継続ソリューションの「LifeKeeper」やデータ複製ソフト「DataKeeper」があります。また、Google Appsとの連携を提供するクラウドソリューションや、業務プロセスを簡素化するワークフローシステム「Gluegent Flow」なども展開しています。さらに、オープンソースに関するサポートやトレーニングも行っており、セキュリティソリューションとして「i-FILTER」や「m-FILTER」も提供しています。’] サイオステクノロジー株式会社は、オープンソースソフトウェアを基盤にした事業継続ソリューションやクラウドソリューションを提供しており、主な製品には「LifeKeeper」や「DataKeeper」があります。 ComparativeAbstractQuerySynthesizer
サイオスのオープンソースソフトウェアと事業継続ソリューションはどう違うの? [‘サイオステクノロジー株式会社は、オープンソースソフトウェアとJavaを基盤にしたシステムやソフトウェアの設計、開発、販売、サポートを行う企業で、2017年に設立されました。主な製品には、事業継続ソリューションの「LifeKeeper」やデータ複製ソフト「DataKeeper」があります。また、Google Appsとの連携を提供するクラウドソリューションや、業務プロセスを簡素化するワークフローシステム「Gluegent Flow」なども展開しています。さらに、オープンソースに関するサポートやトレーニングも行っており、セキュリティソリューションとして「i-FILTER」や「m-FILTER」も提供しています。’] サイオスのオープンソースソフトウェアは、主にソフトウェアの設計、開発、販売、サポートを行うものであり、事業継続ソリューションは「LifeKeeper」などの特定の製品を指します。 ComparativeAbstractQuerySynthesizer
サイオステクノロジーの事業継続ソリューションオープンソースソフトウェアクラウドソリューション他のビジネスソリューション比較利点特長は? [‘サイオステクノロジー株式会社は、オープンソースソフトウェアとJavaを基盤にしたシステムやソフトウェアの設計、開発、販売、サポートを行う企業で、2017年に設立されました。主な製品には、事業継続ソリューションの「LifeKeeper」やデータ複製ソフト「DataKeeper」があります。また、Google Appsとの連携を提供するクラウドソリューションや、業務プロセスを簡素化するワークフローシステム「Gluegent Flow」なども展開しています。さらに、オープンソースに関するサポートやトレーニングも行っており、セキュリティソリューションとして「i-FILTER」や「m-FILTER」も提供しています。’] サイオステクノロジーの事業継続ソリューション「LifeKeeper」やデータ複製ソフト「DataKeeper」、クラウドソリューション、業務プロセスを簡素化するワークフローシステム「Gluegent Flow」などは、オープンソースソフトウェアを基盤にした利点や特長を持っています。 ComparativeAbstractQuerySynthesizer

ちなみにデフォルトだとquery_distributionの値としては

(AbstractQuerySynthesizer(llm=llm), 0.25), #25%
(ComparativeAbstractQuerySynthesizer(llm=llm), 0.25), #25%
(SpecificQuerySynthesizer(llm=llm), 0.5), #50%

という割合となっています。
このあたりも、どういった質問事項を作成したいかに合わせて設計していきたいところです。

まとめ

今回はRagas v0.2における日本語のデータセット生成の方法を紹介しました。
近いうちにドキュメントも整備されるとのことですが、一足お先に紹介してみました。
もしかしたら、公式のドキュメントでの起債が紹介した方法と全然違うかもしれませんが、その際は改めて修正したいと思います。

ではまた!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です