[Dify]RagasライブラリをつかってDifyのナレッジから合成テストセットを作成する。


## はじめに

RAGを評価する時に手動でQAサンプルを作成するのは時間と労力がかかり大変ですよね。
しっかりとした評価をしようと思った時に一問一答みたいなQAセットを作るだけではせっかくRAGのチューニングをしても正しく評価できないことがあります。

Ragasのライブラリでは、推論、条件付け、マルチコンテキストといった異なる特性を持つQAセットを自動で作成できるみたいです。
今回はRagasライブラリでDifyのナレッジから自動でテストセットを作成してみようと思います。
最後にはLangfuseに格納していつでも使えるようにしましょう。


## ナレッジから合成テストセットを作成する
基本は以下を改造してDifyのナレッジから合成テストセットを作成します。

https://docs.ragas.io/en/stable/getstarted/testset_generation.html

まずは必要なライブラリをインストールしましょう。
```
pip install ragas langfuse datasets langchain-openai
```

次に環境変数を設定してください。
```python
import os
 
os.environ["LANGFUSE_SECRET_KEY"] = "LANGFUSE_SECRET_KEY"
os.environ["LANGFUSE_PUBLIC_KEY"] = "LANGFUSE_PUBLIC_KEY"
os.environ["LANGFUSE_HOST"] ="LANGFUSE_HOST"
os.environ["OPENAI_API_KEY"] = "OPENAI_API_KEY"
```


ではDifyからナレッジを取得しましょう。
基本はナレッジに入っているドキュメントを取得する形になります。
データセットIDとドキュメントIDで取得することがきます。
私はローカルのDify使ってるので、ホストがlocalhostですが適宜変更してください。

```python
import requests

dataset_id = "dataset_id"
api_key = "api_key"
document_id = "document_id"
url = f"http://localhost/v1/datasets/{dataset_id}/documents/{document_id}/segments"
headers = {
    "Authorization": f"Bearer {api_key}"
}

response = requests.get(url, headers=headers)

```

取得したナレッジをRagasライブラリが扱えるようにLangchainのDocumentオブジェクトに変換します。

```python
from langchain_core.documents import Document

# レスポンスデータからすべてのセグメントデータを取得
segments_data = response.json()['data']

# すべてのセグメントデータをDocumentオブジェクトに変換
documents = []
for segment_data in segments_data:
    document = Document(
        page_content=segment_data['content'],
        metadata={
            "id": segment_data['id'],
            "position": segment_data['position'],
            "document_id": segment_data['document_id'],
            "word_count": segment_data['word_count'],
            "tokens": segment_data['tokens'],
            "keywords": segment_data['keywords']
        }
    )
    documents.append(document)

```


そしてRagasライブラリを使用して、合成テストセット作成します。
```python
from ragas.testset.generator import TestsetGenerator
from ragas.testset.evolutions import simple, reasoning, multi_context
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# generator with openai models
generator_llm = ChatOpenAI(model="gpt-3.5-turbo-16k")
critic_llm = ChatOpenAI(model="gpt-4")
embeddings = OpenAIEmbeddings()

generator = TestsetGenerator.from_langchain(
    generator_llm,
    critic_llm,
    embeddings
)

# generate testset
testset = generator.generate_with_langchain_docs(documents, test_size=10, distributions={simple: 0.5, reasoning: 0.25, multi_context: 0.25})
```

そうすると以下のように合成テストセットが作成されます。簡単に作れますね。
![スクリーンショット 2024-07-08 1.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/accb4404-c0e9-022e-92d4-f74951b2a204.png)


## Langfuseに格納

最後にいつでも使えるようにLangfuseに格納しておきましょう。
空のデータセットを作成してください。
```python
from langfuse import Langfuse
# init
langfuse = Langfuse()
langfuse.create_dataset(name="synthetic_testset");

```


そして以下のような作成したデータセットを格納しましょう。

```python
import json

for item in testset:
    input_data = {
        "question": item.question,
        "contexts": item.contexts
    }
    
    langfuse.create_dataset_item(
        dataset_name="synthetic_testset",
        input=json.dumps(input_data),
        expected_output=item.ground_truth
    )
```

これで以下のように格納できました。
![スクリーンショット 2024-07-08 1.30.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/003ca093-d651-2e79-be79-313b157ce59d.png)

## 最後に

結構簡単にできるので今後はこれ使おうと思います。

Xをやっているので気になる方はフォローお願いします。

https://x.com/hudebakonosoto