【Langfuse入門ハンズオンの後に】RAGを利用して生成AIアプリの評価を向上させよう【非公式続編】

## はじめに

本記事では、みのるんさん（ [@minorun365](https://x.com/minorun365?s=21)） のLangfuse入門ハンズオンの「データセットを管理しよう」章まで終えたことを前提としています。
まだ終えていない方やクリーンアップしてしまった方は、先に以下のハンズオンを実施ください。

https://qiita.com/minorun365/items/9d0d11f0ecb4c29924d5

続編と言っても、Langfuse要素の追加ではなく生成結果の評価をRAG（Amazon Bedrock Knowledge Bases）を使って向上させることを目的にしています。

ハンズオンの「LLMアプリの生成結果を評価しよう」章ではLLMが「かぐたん」の正しい説明ができずにハルシネーションを起こしてました。
RAGを利用することでLLMに正しく説明してもらい、生成結果の評価を向上させていきます。

なお、手順は全体的に以下のハンズオンを参考にしています。

https://qiita.com/minorun365/items/24dfb0ea3afde6ed0a56

## 6. ナレッジベースを準備する

### 6-1. 「かぐたん」の文章を用意する

アプリの生成結果を評価したときのプロンプトは「かぐたんって何？」でした。

かぐたんについての情報をRAGで利用するために、以下のWebページを`kagutan.pdf`という名前でデスクトップ等にPDFとして保存します。

https://prtimes.jp/main/html/rd/p/000000010.000115171.html

PDFファイルを直接ダウンロードしたい場合は、次のページの`2-1. 「社内文書」を準備`を参考にしてください。

https://qiita.com/minorun365/items/24dfb0ea3afde6ed0a56#2-1-%E7%A4%BE%E5%86%85%E6%96%87%E6%9B%B8%E3%82%92%E6%BA%96%E5%82%99

### 6-2. S3バケットを作成する

- AWSマネジメントコンソール（ https://console.aws.amazon.com/ ）を開き、右上のリージョンをオレゴンに変更する
- 検索窓から「S3」を検索し、S3コンソールを開く
- S3コンソールトップから「バケットの作成」をクリック
- 次の設定で「バケットを作成」をクリック
  - リージョン：オレゴン（us-west-2）
  - バケット名：handson-YYYYMMDD（年月日）-xxx（あなたのニックネームなど）

S3バケット名は全世界で一意である必要があるので、誰かが作成したバケットと名前が被らないようにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/78317f8e-9063-4d6d-818d-3d988e2ccc95.png)

作成したバケットに「かぐたん」の文章をアップロードします。

- 汎用バケットの一覧から、作成したバケットをクリックしてアクセス
- 「アップロード」をクリックしてアップロード画面にアクセス
- `kagutan.pdf`を指定してアップロードをクリック

「アップロードが成功しました」と出ることを確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/a9e167b6-5442-4256-b800-1e502b3a292e.png)

### 6-3. ナレッジベースを作成する

- マネジメントコンソールから「Bedrock」を検索し、Bedrockコンソールへ移動
- 左側のメニューバーから「ナレッジベース」を選択
- 作成ボタンをクリックし、「ベクトルストアを含むナレッジベース」を選択
- ステップ1. 「ナレッジベースの詳細を指定」はそのままの設定で次へ
- ステップ2. 「データソースを設定」ではS3 URIに「6-2. S3バケットを作成する」で作成したバケットを指定して次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/39a4759e-fc8d-4cc8-a284-35bd329a3629.png)
- ステップ3. 「Configure data storage and processing」では次の設定をして次へ
  - 埋め込みモデル：Cohere Embed Mulutilingual V3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/92b67aff-5f34-4392-b5bc-88635e3352b6.png)

  - ベクトルデータベース：新しいベクトルストアをクイック作成 > Amazon Aurora PostgreSQL Serverless
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/0e3278e1-f148-435a-829c-0d4d1aea28b2.png)

ステップ4. 「確認して作成」では、そのまま「ナレッジデータベースを作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/1cfcf8f3-ebf1-4230-aa04-6d4d6bbdc3bd.png)

Aurora ServerlessのDBクラスター作成に10分程度かかります。

また、CloudFormationコンソールよりデプロイの進行状況を確認できます
- 検索窓から「CloudFormation」を検索し、CloudFormationコンソールを開く
- スタック一覧からステータスが`CREATE_IN_PROGRESS`となっているスタックを選択
- イベントタブを開きタイムラインビューを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/cb40b993-a4ff-4386-9a06-200a849b9e29.png) 

### 6-4. ナレッジベースをマネコンから呼び出してみる

ナレッジベースが作成できたらデータソースを同期します。

- マネジメントコンソールから「Bedrock」を検索し、Bedrockコンソールへ移動
- 左側のメニューバーから「ナレッジベース」を選択
- ナレッジベースの一覧から、作成したナレッジベースにアクセス
- 作成したデータソースを選択し、「同期」をクリック

数秒でステータスが「利用可能」になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/d9958095-8b8f-4841-80fa-2a90b50ddeea.png)

ナレッジベースをテストします。

- 「テスト」をクリックすると「ナレッジベースをテスト」の枠が開くので次を設定
    - モデル：Anthoropic Claude3.5 Sonnet V2
    - 推論プロファイル：US Anthropic Claude 3.5 Sonnet v2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/999b745a-270e-4bb4-a5cc-845345e3dc06.png)
- 下の方へスクロールすると入力エリアが現れるので、「かぐたんって何？」を入力して実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/33982ad4-b2ec-458d-97e2-d3ae46a48f04.png)

「かぐたん」についてしっかり回答できています！

> かぐたんはSlackから利用できる生成AIチャットボットです。KAG（カグ）という社名愛称をもとにネーミングされ、親しみやすさを意図して作られました。
> ユーザーは「@かぐたん」にメンションすることで、一般的な知識の質問や文書作成、アイディア出しなどの業務効率化に活用できます。
> このチャットボットの特徴として、Webブラウザを起動する必要がなく、Slack上で直接利用できる点があります。
> スレッド内での会話履歴を記憶し継続的なやり取りが可能で、ダイレクトメッセージでの個別利用や、チャンネルでのチーム活用にも対応しています。
> 技術面では、Amazon Bedrockを活用し、フルAWSでセキュアに構築されています。

## 7. RAGを利用した上でLLMアプリの生成結果を評価しよう

### 7-1. 自分のアプリの出力を評価する

作業PCのローカルでテキストエディタ（メモ帳など）を開き、以下のコードをコピペして「6_dataset.py」という名前で保存します。

```python:6_use_rag.py
import boto3
from langfuse.decorators import observe
from langfuse import Langfuse

def get_prompt(word):
    langfuse = Langfuse()
    prompt = langfuse.get_prompt("what-is")
    compiled_prompt = prompt.compile(name=word)
    return compiled_prompt

@observe()
def get_truth(word):
    langfuse = Langfuse()
    dataset = langfuse.get_dataset("truth")
    truth = ""
    for item in dataset.items:
        if item.input["text"] == word:
            truth = item.expected_output
    return truth

# 更新：ナレッジベースをクエリし、取得された結果をもとにLLMが回答する関数
@observe()
def invoke_bedrock(prompt):
    bedrock = boto3.client("bedrock-agent-runtime")
    response = bedrock.retrieve_and_generate(
        input={'text': prompt},
        retrieveAndGenerateConfiguration={
            'type': 'KNOWLEDGE_BASE',
            'knowledgeBaseConfiguration': {
                'knowledgeBaseId': "ナレッジベースID" # 作成したナレッジベースIDに置き換えてください
                'modelArn': 'us.anthropic.claude-3-7-sonnet-20250219-v1:0'
            }
        }
    )
    output = response["output"]["text"]
    return output

@observe()
def main(input):
    prompt = get_prompt(input)
    get_truth(input)
    output = invoke_bedrock(prompt)
    print(output)
    return output

main("かぐたん")
```

- 検索ボックスから「CloudShell」を検索し、CloudShellを全画面で開く。「ようこそ」ポップアップは閉じる
- CloudShell画面右上の「アクション > ファイルアップロード」から、上記ファイルをアップロード
- CloudShellのターミナルで `python 6_use_rag.py` を実行して、アプリの出力結果が表示されることを確認
- LangfuseのEvaluatorsIDをクリックして、評価結果の点数とコメントを確認する

`0.0000`だったScore Valueが`0.4000`に向上しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/32f419cd-19b9-4c39-bdf7-ab4c6dcb8c7d.png)


:::note info
関数を実行したときに次のようなエラーが出た場合
`Langfuse client is disabled since no public_key was provided as a parameter or environment variable 'LANGFUSE_PUBLIC_KEY'.`
CloudShellの環境情報からLangfuseのAPIキーが設定されていない状態です。
必要であればAPIキーの再発行し、次のコマンドでCloudShellの環境情報に設定してください。
```
export LANGFUSE_SECRET_KEY=sk-XXXXXXXXXXXXXXXXXXXXXX
export LANGFUSE_PUBLIC_KEY=pk-XXXXXXXXXXXXXXXXXXXXXX
export LANGFUSE_HOST=https://XXXXXXX.langfuse.com
```
:::

## 8. 生成結果の評価を改善しよう

RAGを使うことでかぐたんについて回答することができ、評価スコアも向上しました。
ただ、1が最大なのに0.4000ではまだまだ精度が低いです。

評価結果のScore Comment（翻訳）を確認すると、正解ラベルより回答の方が詳しかったようです。

> 生成では、かぐたんが KAG によって開発されたSlackチャットボットであると正しく識別されますが、単純なGround Truthステートメントではサポートされていない、機能、命名の由来、技術的な実装に関する多くの追加の詳細が含まれています。

トレースから回答を確認すると、回答内容に問題はなさそうです。

> かぐたんはSlackから呼び出せるチャットボットです。「@かぐたん」にメンションすることで生成AIへ一般的な知識を質問したり、文書作成やアイディア出しなどの業務効率化に役立てることができます。KDDIアジャイル開発センター株式会社（KAG）が開発し、KDDI Digital Divergence Holdings（KDH）グループ内で展開されています。
> 社名愛称「KAG（カグ）」をもとに、皆から親しまれるようにとの思いを込めてネーミングされています。 かぐたんの特徴として、Webブラウザを起動することなく普段のコミュニケーションツールの延長でシームレスに生成AIを活用できます。Slackのスレッドで会話を継続でき、スレッド内の会話履歴を記憶したうえでやり取りを継続できるため、効率よく追加質問を続けることができます。
> 技術的には、AWSの生成AIサービス「Amazon Bedrock」を活用してフルAWSでセキュアに構築されており、テキスト生成用の言語モデルにはAnthropic社のClaude 2.1を利用しています。

この場合以下の課題が考えられます。
- 回答が期待していた値と異なっている
- 正解ラベルの精度が低い

それぞれの課題を解決して評価を改善していきます。

### 8-1. Langfuseのプロンプトテンプレートを更新して評価を改善

回答が期待していた値と異なっている場合、回答が期待通りになるようにプロンプトを変更します。
LLMの回答に合わせてプロンプトを変更するのではなく、目的に合うようにプロンプトを更新することに注意してください。

プロンプトテンプレートを更新してアプリの出力を再度評価します。

- Langfuseの左サイドバー「Prompts」をクリックし、一覧から「what-is」を選択
- 「Versions」の「+ New」をクリック
- 次のように設定
    - 「Set the "production" label」をチェック
    - Promptに次の内容を入力
```markdown:Prompt
以下の例のように、提供元・開発元とそれが何であるかについて1文で簡潔に答えて

AWSって何？
A: AWSは、Amazon Web Service（AWS）社が提供しているクラウドサービスです。
Claudeって何？
A: Claudeは、Anthropic社が開発したLLMです。
{{name}} って何？
A:
```
- 「Save new prompt version」をクリック
- CloudShellで`python 6_rag.py`を実行

生成結果は次の通りでした。
> かぐたんは、KDDIアジャイル開発センター株式会社（KAG）が開発したSlackから利用できる生成AIチャットボットです。

EvaluationのLLM as a Judgeから、EvaluatorsのIDをクリックして、評価結果を見ます。
Score Valueが0.9000になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/a0ce8895-00b9-497b-9f41-07f5010678e5.png)

Score Comment（翻訳）を確認すると、正しく評価できています。
> この生成では、Kagutan が KAG によって開発された Slack チャットボットであるという重要な事実を正確に捉えており、KAG のフルネームと AI 機能に関する追加の詳細を提供するという点でわずかな違いがあるだけです。

### 8-2. Langfuseのデータセットを更新して評価を改善

正解ラベルの精度が低い場合、正解ラベルを期待する出力となるようにします。
今回は簡単のため「6-4. ナレッジベースをマネコンから呼び出してみる」で出力された回答を利用します。

> かぐたんはSlackから利用できる生成AIチャットボットです。KAG（カグ）という社名愛称をもとにネーミングされ、親しみやすさを意図して作られました。
> ユーザーは「@かぐたん」にメンションすることで、一般的な知識の質問や文書作成、アイディア出しなどの業務効率化に活用できます。
> このチャットボットの特徴として、Webブラウザを起動する必要がなく、Slack上で直接利用できる点があります。
> スレッド内での会話履歴を記憶し継続的なやり取りが可能で、ダイレクトメッセージでの個別利用や、チャンネルでのチーム活用にも対応しています。
> 技術面では、Amazon Bedrockを活用し、フルAWSでセキュアに構築されています。

まずは「8-1. Langfuseのプロンプトテンプレートを更新して評価を改善」で変更したプロンプトを元に戻します。

- Langfuseの左サイドバー「Prompts」をクリックし、一覧から「what-is」を選択
- #1（Prompt: {{name}} って何？）の「↑」をクリック
- 「production」にチェックを入れ、「Save and promote to production」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/355e85de-ec63-4449-8f26-b80d711829b3.png)

Version#1のプロンプトに「production」タグがつきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/6642d21f-6153-4317-867b-14cda957d28a.png)

データセットを更新してアプリの出力を再度評価します。

- Langfuseの左サイドバー「Datasets」をクリックし、一覧から「truth」を選択
- Itemsからハンズオンで登録したItem idを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/3ee3898d-764c-45c7-aa8a-c5f0b286abae.png)
- Expected outputを次の内容で更新
```json:Expected output
{
  "text": "かぐたんはSlackから利用できる生成AIチャットボットです。KAG（カグ）という社名愛称をもとにネーミングされ、親しみやすさを意図して作られました。ユーザーは「@かぐたん」にメンションすることで、一般的な知識の質問や文書作成、アイディア出しなどの業務効率化に活用できます。このチャットボットの特徴として、Webブラウザを起動する必要がなく、Slack上で直接利用できる点があります。スレッド内での会話履歴を記憶し継続的なやり取りが可能で、ダイレクトメッセージでの個別利用や、チャンネルでのチーム活用にも対応しています。技術面では、Amazon Bedrockを活用し、フルAWSでセキュアに構築されています。"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/16c393e3-914d-4974-b2f1-8e27a75a98dc.png)
- CloudShellで`python 6_rag.py`を実行

生成結果は次の通りでした。
> かぐたんはSlackから呼び出せるチャットボットです。「@かぐたん」にメンションすることで生成AIへ一般的な知識を質問したり、文書作成やアイディア出しなどの業務効率化に役立てることができます。KDDIアジャイル開発センター株式会社（KAG）が開発し、KDDI Digital Divergence Holdings（KDH）グループ内で展開されています。
>
> 社名愛称「KAG（カグ）」をもとに、皆から親しまれるようにとの思いを込めてネーミングされています。 かぐたんの特徴として、一般的な生成AIのWebアプリケーションと異なり、Slackから直接利用できるため、Webブラウザを起動せずに普段のコミュニケーションツールの延長でシームレスに生成AIを活用できます。Slackのスレッドで会話を継続でき、スレッド内の会話履歴を記憶した上でやり取りを継続できるため、効率よく追加質問を続けることができます。
>
> 技術的には、AWSの生成AIサービス「Amazon Bedrock」を活用し、テキスト生成用の言語モデルにはAnthropic社のClaude 2.1を利用しています。アプリケーションはPython言語で開発され、Slack用の開発フレーム ワーク「Bolt for Python」を活用し、Amazon ECS上のFargate基盤でサーバーレスに稼働しています。

EvaluationのLLM as a Judgeから、EvaluatorsのIDをクリックして、評価結果を見ます。
こちらもScore Valueが0.9000になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703623/31f1331f-38a7-4cb5-bb64-34a597a73a50.png)

Score Comment（翻訳）を確認すると、正しく評価できています。

> この生成では、かぐたんのコア機能、目的、技術的実装が正確に記述されており、Ground Truthには存在しないものの、事実上正確で文脈上関連性のあるわずかな追加詳細のみが記述されています。

## おわりに

これでハンズオンは終わりです。

今回作成したリソースは全てサーバーレスのため放置してもほとんど料金がかかることはないはずですが、しばらく使わないのであればAWSアカウントは解約してしまいましょう。

また、解約時に使われていたメールアドレスはAWSアカウントの登録に使えなくなってしまうため、捨てアドレスに置き換えた上でアカウントの解約することをおすすめします。