841 Views
February 15, 25
スライド概要
自己紹介 株式会社ACES ACESは、アルゴリズムを用いて事業開発を行うAI事業会社です。 青山 広大(Aoyama Kodai) エンジニアリング領域 WEBフロントエンド/バックエンド(React.js, Next.js, Node.js, Python) モダンデータスタック(特にSnowflake) AI(特にOpenAI, Azure) 音声認識 #テックリード #Certified ScrumMaster® 1
2
第7章 LangSmithを使ったRAGアプリケーションの評価 3
7.1. 第7章で取り組む評価の概要 オフライン評価 事前に用意したテストデータセットを用いて評価 回答の正確性や検索の妥当性を安定的に検証できる オンライン評価 実際のユーザー利用状況をモニタリングし継続評価 ユーザーフィードバックを活用し動的に性能改善が可能 ポイント: LLM応答には非決定性があるため、オフライン/オンライン両面での評 価が推奨される 4
7.2. LangSmithの概要 LangSmithの料金プラン(2025/02/13 時点) プラン 料金 (月額) Free 無料 Pro $39/ユーザー Starter 要問い合わせ Enterprise 要問い合わせ 主な特徴 - 1ユーザー限定 - 5,000トレース/月 - 14日間データ保持 - コミュニティサポート - 複数ユーザー(~10名) - 10,000トレース/月 - 14日間データ保持 - メールサポート - Pro相当の機能を割安提供 - スタートアップや教育機関向け特 別プラン - 上限カスタマイズ(トレース数・ 保持期間など) - シングルサインオン(SSO) - VPCセルフホスト対応 - SLA保障 & 専任サポート 対象 個人開発者・趣味レベルの利用 小~中規模チーム(本格的な運用 向け) 初期資金の少ない企業・教育機関 大規模企業・厳格な運用要件があ る組織 5
LangSmithの機能の全体像 1. Tracing(トレース収集・可視化) 2. Prompts(プロンプト管理) 3. Evaluation(モデル出力の評価) 6
1. Tracing(トレース収集・可視化) チェーン実行の履歴を自動記録 LLM呼び出しやエージェントの各ステップをログとして保存 詳細な可視化とデバッグ 入出力、処理時間、トークン使用量などをUIで簡単に把握 チーム共有・監視 URL共有で簡単にメンバーへトレースを公開 閾値超過など異常を検知してアラートを出す 7
2. Prompts(プロンプト管理) プロンプトの集中管理・共有 Web UI上でテンプレート編集し、チーム全員で利用 バージョン管理 変更履歴を追跡し、過去版へのロールバックも容易 比較・実験 複数のプロンプト案をABテストし、最適案を選定 8
3. Evaluation(モデル出力の評価) テストデータセットの作成・運用 質問・期待回答をセット化して一括テスト 多様な評価指標 回答の正確性や関連度を自動採点 (LLMやRagasなど) カスタムEvaluator ドメイン特有の評価ロジックを自由に実装 オンライン評価 & フィードバック 実際のユーザー回答をモニタリングし、失敗事例を継続学習 9
(発表者コラム)LangSmithとLangFuse・MLflowの比較 10
提供元 LangSmith LangChainコミュニティ (一部SaaS/Ent版あり) OSS(MIT) +有償Enterprise版 主用途 LLMアプリの開発・評価を包括的 に管理 LLMアプリの監視・分析に特化 Tracing チェーン全ステップを 自動収集・可視化 専用UIで集中管理, バージョン管理・A/Bテスト 自動評価(LLM-as-judge), 人手ラベル付け, RAG特化スコア対応 EntプランでSSO/SLA, オンプレ導入サポート, 手厚いサポート LLMコール詳細ログ & ダッシュボード表示 バージョン切替可, OSSで自由に拡張 LLM Autolog (OTel互換) 同様に自動 & 人手評価可, RAG指標もカスタム可 従来ML指標+LLM評価拡張, 人手UIは限定的 OSSセルフホスト+ 有償版で追加機能 & サポート LLM中心の本格的開発 (プロンプト管理や評価を クラウドUIで完結したい) OSSでLLMログ管理を内製したい (自由度が高くエコシステム構築 が可能) Databricks上のManaged MLflow (商用サポート), OSS版はコミュニティ中心 LLM以外も含め一括管理 (全社的にMLflowを導入済 or 他のMLワークフローと統合した い) Prompts Evaluation エンタープライズ おすすめ LangFuse MLflow Databricks社(OSS版もあり) 機械学習全般 実験管理・モデル追跡+LLM評価 機能 実験ログとして管理, LLM専用Hubは限定的 11
7.3. LangSmithとRagasを使ったオフライン評価の構成例 Ragasとは RAGアプリケーション向けに最適化された評価フレームワーク 検索精度・回答精度をスコアリングし、RAGの品質を数値で把握可能 12
この章で構築するオフライン評価の構成 1. Ragasでテストデータ(QAペア)生成 2. LangSmithにデータセットとしてインポート 3. オフライン評価実行 → 各質問に対する回答をRagas評価器でスコア付け 4. LangSmithで集計・可視化 13
7.4. Ragasによる合成テストデータの生成 Ragasの合成テストデータ生成機能の概要 既存ドキュメントの文脈をもとに疑似的なQ&Aを生成可能 質問と期待回答をセットで作成することで、検証作業を効率化 14
Google Colabでの実行例 パッケージのインストール: !pip install torch==2.5.1+cu124 --extra-index-url https://download.pytorch.org/whl/cu124 !pip install langchain-core==0.3.35 langchain-openai==0.3.5 \ langchain-community==0.3.17 ragas==0.2.13 nest-asyncio==1.6.0 \ langchain_chroma==0.2.2 \ fsspec==2024.10.0 rapidfuzz==3.12.1 15
検索対象ドキュメントのロード: from langchain_community.document_loaders import GitLoader def file_filter(fite_path: str) -> bool: return fite_path.endswith(".mdx") loader = GitLoader( clone_url="https://github.com/langchain-ai/langchain", repo_path="./langchain", branch="master", file_filter=file_filter, ) documents = loader.load() print(len(documents)) # 394 16
Ragasによる合成テストデータ生成の実装(1/3) documents = documents[:10] # 目安:10件で2分の処理時間 import nest_asyncio nest_asyncio.apply() import os import asyncio from ragas.llms import LangchainLLMWrapper from ragas.embeddings import LangchainEmbeddingsWrapper from ragas.testset import TestsetGenerator from ragas.testset.persona import Persona from ragas.testset.synthesizers import default_query_distribution from langchain_openai import ChatOpenAI, OpenAIEmbeddings 17
Ragasによる合成テストデータ生成の実装(2/3) async def main(): os.environ["OPENAI_API_KEY"] = "あなたのAPIキー" generator_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o")) generator_embeddings = LangchainEmbeddingsWrapper(OpenAIEmbeddings()) personas = [ Persona( name="Japanese Engineer studying LangChain", role_description="私はLangChainに興味を持つ日本人エンジニアで、 AIの基礎的な知識はあるものの、LangChainを活用した実践的な事例はまだ把握しきれていません。 より深く理解し、自社システムやプロジェクトに応用するため、LangChainの詳細やユースケースを学習しています。 コード以外は全て日本語での回答を期待します。", ), ] 18
Ragasによる合成テストデータ生成の実装(3/3) async def main(): ...省略(2/3からの続き) generator = TestsetGenerator( llm=generator_llm, embedding_model=generator_embeddings, persona_list=personas ) distribution = default_query_distribution(generator_llm) for query, _ in distribution: prompts = await query.adapt_prompts("japanese", llm=generator_llm) query.set_prompts(**prompts) testset = generator.generate_with_langchain_docs( documents, testset_size=4, query_distribution=distribution ) df = testset.to_pandas() display(df) return testset testset = asyncio.run(main()) 19
実行中にドキュメント内に見出しがないとエラーが出るが気にしない♬: ERROR:ragas.testset.transforms.engine:unable to apply transformation: 'headlines' property not found in this node 20
出力された合成テストデータ 21
LangSmithのDatasetの作成 from langsmith import Client os.environ["LANGSMITH_API_KEY"] = "あなたのAPIキー" dataset_name = "agent-book" client = Client() if client.has_dataset(dataset_name=dataset_name): client.delete_dataset(dataset_name=dataset_name) dataset = client.create_dataset(dataset_name=dataset_name) 22
LangSmithに合成テストデータを入れるDatasetが作成される 23
生成したQ&AをLangSmithにアップロードして評価用Datasetを構築
inputs, outputs, metadatas = [], [], []
for testset_record in testset:
inputs.append(
{
"question": testset_record.eval_sample.user_input,
}
)
outputs.append(
{
"contexts": testset_record.eval_sample.reference_contexts,
"ground_truth": testset_record.eval_sample.reference,
}
)
metadatas.append(
{
"source": '',
"evolution_type": testset_record.synthesizer_name,
}
)
client.create_examples(
inputs=inputs,
outputs=outputs,
medatada=metadatas,
dataset_id=dataset.id
)
24
アップロードされた合成テストデータ 25
7.5. LangSmithとRagasを使ったオフライン評価の実装 LangSmithのオフライン評価の概要 **テストデータセット(Q&A)**を元に一括実行 各回答を評価器(Evaluator)で採点し、スコアリング結果をLangSmithに保存 26
利用可能なEvaluator(評価器) LLM系 Evaluator LLMそのものに回答の正確度を評価させる Ragas Evaluator RAG特有の指標で回答精度を定量化 27
Ragasの評価メトリクス Precision/Recallで文書検索の正確性を測定 回答がどの程度正しい根拠ドキュメントを参照しているか数値化 (コラム)Ragas以外の検索の評価メトリクス TF-IDF/BM25などベースライン比較の指標も併用することで総合的に評価 28
Evaluatorの実装(1/3) from typing import Any from langchain_core.embeddings import Embeddings from langchain_core.language_models import BaseChatModel from langsmith.schemas import Example, Run from ragas.embeddings import LangchainEmbeddingsWrapper from ragas.llms import LangchainLLMWrapper from ragas.metrics.base import Metric, MetricWithEmbeddings, MetricWithLLM 29
Evaluatorの実装(2/3)
class RagasMetricEvaluator:
def __init__(self, metric: Metric, llm: BaseChatModel, embeddings: Embeddings):
self.metric = metric
if isinstance(self.metric, MetricWithLLM):
self.metric.llm = LangchainLLMWrapper(llm)
if isinstance(self.metric, MetricWithEmbeddings):
self.metric.embeddings = LangchainEmbeddingsWrapper(embeddings)
def evaluate(self, run: Run, example: Example) -> dict[str, Any]:
context_strs = [doc.page_content for doc in run.outputs["contexts"]]
score = self.metric.score(
{
"user_input": example.inputs["question"],
"response": run.outputs["answer"],
"retrieved_contexts": context_strs,
"reference": example.outputs["ground_truth"],
},
)
return {"key": self.metric.name, "score": score}
30
Evaluatorの実装(3/3) from langchain_openai import ChatOpenAI, OpenAIEmbeddings from ragas.metrics import answer_relevancy, context_precision metrics = [context_precision, answer_relevancy] llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) embeddings = OpenAIEmbeddings(model="text-embedding-3-small") evaluators = [ RagasMetricEvaluator(metric, llm, embeddings).evaluate for metric in metrics ] 31
推論の関数の実装(1/3) from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings(model="text-embedding-3-small") db = Chroma.from_documents(documents, embeddings) 32
推論の関数の実装(2/3)
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template('''\
以下の文脈だけを踏まえて質問に回答してください。
文脈: """
{context}
"""
質問: {question}
''')
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
retriever = db.as_retriever()
chain = RunnableParallel(
{
"question": RunnablePassthrough(),
"context": retriever,
}
).assign(answer=prompt | model | StrOutputParser())
33
推論の関数の実装(3/3)
def predict(inputs: dict[str, Any]) -> dict[str, Any]:
question = inputs["question"]
output = chain.invoke(question)
return {
"contexts": output["context"],
"answer": output["answer"] ,
}
34
オフライン評価の実装・実行 from langsmith.evaluation import evaluate evaluate( predict, data="agent-book", evaluators=evaluators, ) 35
LangSmith上のオフライン評価の実行結果 36
7.6. LangSmithを使ったフィードバックの収集 この節で実装するフィードバック機能の概要 実際のユーザーやテスターによるGood/Badなどの評価を集め、LangSmithに送信 オフライン評価と組み合わせることで、運用中の失敗ケースも継続的に学習へ還 元 37
フィードバックを送る関数の実装
import requests
headers = {
"x-api-key": "あなたのAPIキー",
}
good = 1
bad = 0
requests.post(
"https://api.smith.langchain.com/feedback",
headers=headers,
json={
"run_id": "your_llm_run_id",
"key": "feedback-key",
"score": bad,
"comment": "comment",
},
)
38
フィードバックボタンを表示 回答と一緒にHTMLパーツに埋め込むことで、ワンクリック評価が可能 コラム:Online Evaluator(LLM-as-judge evaluator) フィードバック内容をLangSmithに連携し、本番環境でのユーザー評価をスコアに 即時反映 閾値下回りが多いケースを自動通報など、高度な運用フローも構築できる 39
LangSmith上のLLMの実行結果 40
7.7. フィードバックの活用のための自動処理 Automation ruleによる処理 LangSmithでAutomation ruleを設定 例:フィードバック「Bad」が一定数以上ならSlack通知やチケット発行 41
良い評価のトレースを自動でDatasetに追加する 高評価のログを定期的にオフライン評価Datasetへ追加 再学習や再評価に活用し、継続的にモデル精度向上を図る 42
43
7.8. まとめ オフライン評価 & オンライン評価 Ragasで合成データを生成 → オフラインテスト → LangSmithで採点 実運用からのフィードバックをLangSmithに集め、再評価サイクルを回す LangSmithの機能とRagasの重要性 LangSmith:LLM評価のモニタリング & チェーントレース Ragas:RAG特有の評価指標で検索/回答精度を定量化 フィードバックの自動処理 Automation ruleで評価の高/低事例をスムーズに仕分け データセットを拡張し、将来の精度を持続的に向上 44