これは何?
コミュニティ勉強会「Langfuse Night #2」で実施するハンズオンセッションの手順書です。
イベントに参加されていない方も、本手順をそのまま実施することでLangfuseに入門できますのでご活用ください。
実施にあたり、AWSアカウントへの課金(Bedrockの推論コスト=数十円以内が目安)の発生が予想されます。金額含め、自己責任のうえ実施をお願いします。
Langfuseとは?
LLMアプリケーションの監視やデバッグに役立つ統合ツールです。無料で自分の環境にデプロイできるセルフホスト版と、SaaS型で使えるCloud版があります。
本ハンズオンではお手軽なCloud版を利用します。個人利用なら無料で使い始められます。
事前準備
Langfuseアカウントの作成
公式サイト右上の「Sign Up」からCloud版にサインアップしましょう。
GoogleやGitHubのアカウントと連携すると楽ですね。
リージョンの選択がありますが、EU/USいずれでもOKです。
AWSアカウントの作成
以下を参考にサインアップしましょう。クレジットカードが必要です。
1. 元となるLLMアプリを作成しよう
Bedrockモデルの有効化
- AWSマネジメントコンソールにサインイン( https://console.aws.amazon.com/ )し、ホーム画面右上からリージョンを「オレゴン」に切り替えます。
- 検索ボックスから「Bedrock」を検索し、Bedrockのコンソールに移動します。
- 左サイドバー下部の「モデルアクセス」より、「すべてのモデルを有効にする」を選択してウィザードを進めます。
- 「ユースケースの詳細」では自分の会社名などをざっくり入力します。対象ユーザーは「社内の従業員」、ユースケースの説明は「ハンズオン」と記載して進めましょう。
- リクエストを送信すると、数分で生成AIモデルへアクセスできるようになります。待っている間に次の手順へ進みましょう。
- リクエスト送信直後、一部の古いモデルについてエラーが出ますが、今回利用しないため無視して問題ありません。
本ハンズオンでは、AWSのオレゴンリージョンのみを利用します。Bedrockのモデル呼び出しレートリミットが緩いためです。
LLMアプリの実行
- 検索ボックスから「CloudShell」を検索し、CloudShellを全画面で開きます。「ようこそ」ポップアップは閉じてください。
- 作業PCのローカルでテキストエディタ(メモ帳など)を開き、以下のコードをコピペして「1_bedrock.py」という名前で保存します。
import boto3
# Bedrockの推論APIを実行する関数
def invoke_bedrock(prompt):
bedrock = boto3.client("bedrock-runtime")
response = bedrock.converse(
modelId="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
messages=[
{
"role": "user",
"content": [{"text": prompt}]
}
]
)
output = response["output"]["message"]["content"][0]["text"]
return output
# 上記の関数を呼び出し、結果を画面出力するメイン関数
def main(input):
output = invoke_bedrock(input)
print(output)
return output
# メイン関数に入力を与えて呼び出す
main("Langfuseって何?")
最近のOSであれば大丈夫だと思いますが、テキストの保存フォーマットはShift_JISではなくUTF-8になるようにしてください。
- CloudShell画面右上の「アクション > ファイルアップロード」から、上記ファイルをアップロードします。
- CloudShellのターミナルで
python 1_bedrock.py
というコマンドを実行して、アプリの出力結果が表示されることを確認しましょう。
もしアップロード後に内容を修正したい場合は、CloudShellで rm 1_bedrock.py
を実行して当該ファイルを一度削除し、修正版のファイルを再度アップロードしてください。
2. トレースを記録しよう
Langfuse Cloudのセットアップ
- Langfuseの管理画面にアクセス( https://cloud.langfuse.com )し、サインインします。
- 「New Organization」をクリックして、好きな名前でOrganizationを作成します。(例:自分のニックネームなど)
- 「Organization Members」はデフォルトのまま「Next」を押して進みます。
- 「New Project」画面で、今回のハンズオン用のプロジェクトを
langfuse-night
という名前で作成します。 - 「Create API Key」ボタンを押して認証情報を表示させます。
- 作業PCでメモ帳などのテキストエディタを開き、以下のコマンドをコピペします。各行イコールの右辺に自分のLangfuse認証情報を上書きして、このメモは後でまた使えるように開いておきましょう。(機密情報のため、保存せずにハンズオン後削除することをお勧めします)
export LANGFUSE_SECRET_KEY=sk-XXXXXXXXXXXXXXXXXXXXXX
export LANGFUSE_PUBLIC_KEY=pk-XXXXXXXXXXXXXXXXXXXXXX
export LANGFUSE_HOST=https://XXXXXXX.langfuse.com
- 自分のLangfuse認証情報で上書きした上記コマンドを、CloudShellにコピペして実行します。(「複数行テキストの貼り付け」警告が出ますが、問題ないので貼り付け実行します。)すると環境変数が設定されて、そのターミナルのタブを閉じるまではLangfuseへの接続設定が記憶されます。
自分のアプリにトレースの計装を行う
- 作業PCのローカルでテキストエディタ(メモ帳など)を開き、以下のコードをコピペして「2_trace.py」という名前で保存します。
import boto3
from langfuse.decorators import observe # 追加
@observe() # 追加
def invoke_bedrock(prompt):
bedrock = boto3.client("bedrock-runtime")
response = bedrock.converse(
modelId="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
messages=[
{
"role": "user",
"content": [{"text": prompt}]
}
]
)
output = response["output"]["message"]["content"][0]["text"]
return output
@observe() # 追加
def main(input):
output = invoke_bedrock(input)
print(output)
return output
main("Langfuseって何?")
元のコードに対して、Langfuseのモジュールをインポートして @observe()
のデコレーションを追加しているだけです。簡単ですね!
- CloudShell画面右上の「アクション > ファイルアップロード」から、上記ファイルをアップロードします。
- CloudShellで
pip install langfuse
を実行して、Python用のLangfuseライブラリをインストールします。 - CloudShellのターミナルで
python 2_trace.py
を実行して、アプリの出力結果が表示されることを確認しましょう。 - Langfuseのダッシュボードに移動し、左サイドバーの「Tracing > Traces」から実行結果のトレースを確認してみましょう。
3. プロンプトを管理しよう
Langfuseにプロンプトテンプレートを登録する
- Langfuseの左サイドバー「Prompts」をクリックし、「Create Prompt」を実行して以下のプロンプトを作成しましょう。
- Name:
what-is
- Prompt:
{{name}} って何?
- 他はデフォルトのままでOK
- Name:
自分のアプリからLangfuseのプロンプトを呼び出す
- 作業PCのローカルでテキストエディタ(メモ帳など)を開き、以下のコードをコピペして「3_prompt.py」という名前で保存します。
import boto3
from langfuse.decorators import observe
from langfuse import Langfuse # 追加
# 追加:Langfuseからプロンプトを取得する関数
def get_prompt(word):
langfuse = Langfuse()
prompt = langfuse.get_prompt("what-is")
compiled_prompt = prompt.compile(name=word)
return compiled_prompt
@observe()
def invoke_bedrock(prompt):
bedrock = boto3.client("bedrock-runtime")
response = bedrock.converse(
modelId="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
messages=[
{
"role": "user",
"content": [{"text": prompt}]
}
]
)
output = response["output"]["message"]["content"][0]["text"]
return output
@observe()
def main(input):
prompt = get_prompt(input) # 追加
output = invoke_bedrock(prompt)
print(output)
return output
main("Langfuse") # 引数を変更
元のコードに対して、「プロンプト取得関数」を追加しています。内容は、Langfuseインスタンスを作成して get_prompt
メソッドを実行しているだけです。
受け取ったキーワードをプロンプトテンプレート内の変数に代入していることが分かると思います。
- CloudShell画面右上の「アクション > ファイルアップロード」から、上記ファイルをアップロードします。
- CloudShellのターミナルで
python 3_prompt.py
を実行して、アプリの出力結果が表示されることを確認しましょう。 - ちゃんとプロンプトテンプレートが使われているか、Langfuseトレース内の
invoke_bedrock
関数の入力を確認してみましょう。
4. LLMアプリの生成結果を評価しよう
IAMユーザーを作成し、アクセスキーを取得する
- AWSマネコンで「IAM」と検索し、IAMコンソールにアクセスします。
- 左サイドバーの「ユーザー」より、「ユーザーの作成」をクリックして以下のように設定します。(記載ないものはデフォルトでOK)
- ユーザー名:
langfuse
- 許可のオプション:ポリシーを直接アタッチする
- 許可ポリシー:「AmazonBedrockFullAccess」を検索してチェック
- ユーザー名:
- 作成後、ユーザー名「langfuse」をクリックして「アクセスキーを作成」をクリックします。(記載ないものはデフォルトでOK)
- ユースケース:サードパーティーサービス
- 「上記のレコメンデーションを理解し、アクセスキーを作成します。」にチェック
- 表示されたアクセスキーとシークレットアクセスキーを、このあとすぐ使います。この画面は一度閉じると再度開けないので、触らずに置いておいてください。
Langfuseに評価器を設定する
- Langfuse左サイドバーから「Evaluation > LLM-as-a-Judge」を開き、「Create Evaluator」をクリックします。
- 「Select a template」から「Create new template」を選び、以下のように設定します。(記載ないものはデフォルトでOK)
- Select a Langfuse managed template: Correctness
- Model > 「+ Add new LLM API key」をクリック
- Provider name:
Claude 3.5 Sonnet v2
- LLM adapter: bedrock
- AWS Region:
us-west-2
- AWS Access Key ID: 前述のIAM画面からコピペ
- AWS Secret Access Key: 前述のIAM画面からコピペ
- Custom models:
us.anthropic.claude-3-5-sonnet-20241022-v2:0
(「+ Add custom model name」より追加)
- Provider name:
Claudeモデルの初期クォータが厳しめのため、レートリミットに抵触しないようにアプリ本体が利用するモデルと微妙に変えています。
- 上記すべて保存後、「Create evaluator」画面で「correctness」を選択します。
- 「Variable mapping」セクション右側で以下のように設定して、Evaluatorを保存します。
- {{query}}
- Object: Span
- Object Name:
invoke_bedrock
- Object Variable: Input
- {{generation}}
- Object: Trace
- Object Variable: Output
- {{ground_truth}}
- Object: Span
- Object Name:
get_truth
- Object Variable: Output
- {{query}}
自分のアプリの出力を評価する
- 作業PCのローカルでテキストエディタ(メモ帳など)を開き、以下のコードをコピペして「4_eval.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):
truth = ""
if word == "かぐたん":
truth = "かぐたんは、KAG社が開発したSlackチャットボットです。"
return truth
@observe()
def invoke_bedrock(prompt):
bedrock = boto3.client("bedrock-runtime")
response = bedrock.converse(
modelId="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
messages=[
{
"role": "user",
"content": [{"text": prompt}]
}
]
)
output = response["output"]["message"]["content"][0]["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のターミナルで
python 4_eval.py
を実行して、アプリの出力結果が表示されることを確認しましょう。 - Langfuse側で先ほど設定した評価器が、この生成結果を数秒遅れで評価してくれます。EvaluatorsのIDをクリックして、評価結果の点数とコメントを確認してみましょう。(コメントは見切れやすいので、ツールバーアイコンから行の幅を広げましょう)
RAGなしで「かぐたん」の正しい説明ができるLLMは少ないはずなので、おそらくCorrectnessの点数は0点になったと思います。
分かりづらいのですが、get_truth
関数は評価のカンペ用に正解データを取得しているだけで、(RAGのように)アプリ本体に正解を教えてあげているわけではありません。だからハルシネーションが発生しているのですね。
5. データセットを管理しよう
前項では関数内に正解データをベタ書きしましたが、これをデータセットとしてLangfuseに登録して使ってみましょう。
- Langfuseの左側サイドバー「Datasets」より、「New Dataset」をクリックして以下のように設定します。(記載ないものはデフォルトでOK)
- Name:
truth
- Name:
- 「New Item」より、以下のように設定します。(記載ないものはデフォルトでOK)
- Input:
{"text": "かぐたん"}
- Expected output:
{"text": "かぐたんは、KAG社が開発したSlackチャットボットです。"}
- Input:
自分のアプリからデータセットを利用する
- 作業PCのローカルでテキストエディタ(メモ帳など)を開き、以下のコードをコピペして「5_dataset.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
# 更新:Langfuseから正解データを取得する関数
@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
@observe()
def invoke_bedrock(prompt):
bedrock = boto3.client("bedrock-runtime")
response = bedrock.converse(
modelId="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
messages=[
{
"role": "user",
"content": [{"text": prompt}]
}
]
)
output = response["output"]["message"]["content"][0]["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のターミナルで
python 5_dataset.py
を実行して、アプリの出力結果が表示されることを確認しましょう。 - 正解データを正しくLangfuseから取得できているか、トレースから確認してみましょう。
お片付け
- AWSアカウントはしばらく使わない場合、解約してしまいましょう。そのとき、登録したメールアドレスもAWSで二度と使えなくなってしまうため、捨てアドレスなどに設定変更してから解約することをお勧めします