🎃

LLMアプリケーションの実験管理の運用をまとめてみた〜PromptLayerを使った本番運用〜

2024/04/03に公開

こんにちは。PharmaX共同創業者の上野(@ueeeeniki)です!

LLMアプリケーションの実験管理サービスであるPromptLayerの使い方をご紹介したところ、非常に多くの方にお読みいただき、LLMの実験管理で検索してもかなり上位に出てくる記事になりました。

https://zenn.dev/pharmax/articles/27915681d4ba57

そこで今回は、発展編としてPromptLayerの使い方だけではなく、PharmaXでの実験管理のリアルなプラクティスを徹底解説したいと思います。
PharmaXで行っている実験管理のプラクティスは下記のように何度か発表しているのですが、記事の形できちんとまとめるのは初めてなので、改めてガッツリご紹介します!

https://speakerdeck.com/pharma_x_tech/llmapurikesiyonno-gai-shan-purosesunogou-zhu

https://speakerdeck.com/pharma_x_tech/llmapurikesiyonnoshi-yan-guan-li-ping-jia-nogong-fu-woshao-jie

PharmaXでのリアルな実験管理のノウハウが、LLMアプリケーションを運用されている方々の参考になれば嬉しいです。

PromptLayerはマネージドなSaaSサービスにはなるので、セキュリティの問題などは各社の規定などに従い十分注意してご利用ください。今回は個人情報の扱いなどについては、あえて詳しく触れないこととします。

実験管理とはなにか

実験管理とは、AIに与えるプロンプトやパラメータの変更履歴と、どのようなプロンプトやパラメータのときにどのような出力だったかを管理することです。

特にLLMでは、プロンプトエンジニアリングやRAGと呼ばれる手法など、LLM特有の最適化手法が出てきたため、これまでのAIアプリケーション開発とは少し違った実験管理が求められます。
GPT-4などのモデルを使っている場合、利用者側がモデルの事前学習を実験管理することはないので、Fine-tuningや利用時のプロンプトエンジニアリングなどを実験管理するということになります。

PromptLayer以前の実験管理とPromptLayerの導入のモチベーション

LLMアプリケーションの開発当初、PromptLayerの導入に手が回っていなかったときは、メンバーが手動で出力結果を記録して、FBを集めていました。

例えば、薬剤師がチャットする内容をサジェストするアプリケーションでは下記のようにLLMがサジェストした出力結果とそれに対する薬剤師メンバーからのFBを記載してもらっていました。

これでは、すべての出力を記録するのには無理があります。
また、出力はなんとか手動で記録することはできますが、どのような入力を与えたときにどのような出力だったのかを記録することはできません。

そこで、自動で入出力を記録管理できる実験管理用のサービスであるPromptLayerを導入しました。
https://promptlayer.com/

PromptLayerを選択した理由とPromptLayerの特長

PromptLayerを選択した一番の理由は、テンプレート機能の使い勝手がいいことです。

ブラウザの管理画面からプロンプトのテンプレートを登録して編集可能です。登録したテンプレートはコード上で呼び出して使用することができます。
また、入出力をテンプレートに紐づけることができるので、どのテンプレートのどのバージョンを使っている時にどんな出力結果が出たのかを後から確認することができます。

そのため、開発者以外のメンバーもプロンプトを確認・修正することが可能です。
そして、すべてのプロンプトのテンプレートをPromptLayerに一元管理することで、一箇所に知識を集約することが可能になります。

各機能を簡単にご紹介します。

テンプレート機能

テンプレート管理

プロンプトのテンプレートを作成することができ、バージョン管理を行うこともできます。

テンプレートを登録し、バージョン管理可能

プロンプトのテンプレートにはパラメータなども設定することが可能です。
パラメータを登録しておけば、テンプレートの呼び出し元でパラメータを統一することができます。

モデル名や各種パラメータを設定可能

テンプレートを変更した際にはコミットメッセージを残してバージョン管理することもできます。

バージョンを更新する際にはコミットメッセージが求められる

テンプレートに紐づく入出力結果一覧

各テンプレートを使用した入出力結果の一覧を見ることができます。
これによって、どのテンプレートのどのバージョンでどのような出力結果だったのかを後から振り返ることが可能になります。

各テンプレートの各バージョンごとに紐づく入出力一覧をみることができる

各入出力の詳細

各入出力の詳細ページを見ることもできます(各入出力の詳細ページからもどのテンプレートを使用していたのかが分かります)。

左にどのような入力を与えたか、右にLLMがどのような出力を返したかが記録される

metadataやscoreの紐づけ

各出力結果にはメタデータや評価のscoreを紐づけることも可能です。
メタデータには後からあると嬉しい情報を紐づけます。scoreを紐づけることが可能になることで、定量的な評価も可能になります。

メタデータを確認できる


scoreは複数紐づけることができる

出力履歴確認

入出力結果一覧

テンプレートごとではなく、全入出力結果の一覧も見ることができます。

すべての入出力結果一覧をみることができる

メタデータ・scoreでの検索

一覧からメタデータやscoreで詳細検索することも可能です。

複数の条件で検索可能

PromptLayerの運用プラクティス

主力結果の記録

すべての入出力結果はテンプレートに紐づけるようにします。
下記のように書けば簡単に出力結果をPromptLayerに
(今後記載のコードはすべて公式ドキュメントから引用します)

# Make sure to `pip install promptlayer`
import promptlayer

# Swap out your 'from openai import OpenAI'
OpenAI = promptlayer.openai.OpenAI
client = OpenAI()

# Do something fun 🚀
response, pl_request_id = client.chat.completions.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "system", "content": "You are an AI."},
    {"role": "user", "content": "Compose a poem please."}
  ],
  pl_tags=["getting-started"]
)

テンプレートへの紐づけ

PharmaXでは、LLM用のすべてのプロンプトのテンプレートをPromptLayerで一元管理しており、すべてのLLMの入出力結果が何かしらのテンプレートに紐づくようになっています。

PromptLayerのSDK(もちろんREST APIでも可能です)を使えば下記のように簡単に入出力結果をテンプレートに紐づけることができます。

promptlayer.track.prompt(
    request_id=pl_request_id,
    prompt_name='recipe_template',
    prompt_input_variables=variables
)

metadataの紐づけ

入出力結果にはmetadataを紐づけることもできます。
PharmaXでは、使用された環境(local, staging, prod)やどの薬剤師が使ったのか?など、後からみて役に立つ情報をmetadataとして記載しています。

promptlayer.track.metadata(
  request_id=pl_request_id,
  metadata={
     "user_id": "abc123",
     "session_id": "xyz456",
     "is_vegetarian": "false",
  }
)

評価(score)の紐づけ

出力結果を評価したタイミングでscoreを入出力履歴に紐づけます。
紐づけ方はmetadataとほぼ同じで非常に簡単です。

promptlayer.track.score(
   request_id=pl_request_id,
   score=(100 if food in response.choices[0].message.content else 0)
)

複数のscoreを紐づけることが可能なので、PharmaXでは出力結果がマニュアルに沿っているかや、医学的に間違っていないかという評価をスコアリングして
評価の詳しいプラクティスはまた別の記事でもご紹介します。

PharmaXのLLMアプリケーションのアーキテクチャ

PharmaXでは、バックエンド、フロントエンドから直接LLMやプロンプトレイヤーを呼び出す構成を取っています。
(LLMはOpenAIでも、Azure OpenAI Serviceでも、Amazon Bedrockでも、各社の使用するLLMリソースに置き換えて考えていただいて問題ありません。)

つまり、LLMの処理をまとめるアプリケーション層(Pythonで書かれるのが一般的でしょう)を追加するようなことはしていません。


LLM APIとPromptLayerを呼び出すアーキテクチャ

この構成のデメリットは、同じようなLLMへのリクエストやPromptLayerへの入出力処理をバックエンド、フロントエンドの両方に記述しなければならなくなることです。

しかし、LLMの処理にはかなりの時間がかかるため、余分な層を中間に置かずにレイテンシーを小さくすることを優先するという選択しています。
プロンプトのテンプレートをPromptLayerに集めることができているので、プロンプトをバックエンドとフロントエンドの両方で管理する必要はありません。
複数の呼び出し箇所から使われるプロンプトのテンプレートをPromptLayerに一元管理できることが、PromptLayerを使うメリットの1つです。

本番環境での実験管理

PharmaXでは本番環境でも、プロンプトの複数バージョンを(ABテストのようなイメージで)実験できるような環境を整えています。
たとえば、薬剤師が患者さんとチャットする内容をサジェストするアプリケーションでは、薬剤師が実際に使うプロンプトと、PdMやリーダー陣が実験・検証するためのプロンプトを両方本番用環境で利用できるようになっています。

実験プロンプト管理画面
管理画面から実験用プロンプトが読み込める様子

薬剤師がチャットする内容をサジェストするアプリケーションでは、本番でプロンプトのテンプレートを安易に変更して、薬剤師チーム全体に変更が適用されてしまうと生産性に悪影響を及ぼす可能性があります。
そこで、PdMやリーダー陣など一部のメンバーが実験用のプロンプトを使って入念に実験し、結果がよかったテンプレートを全体のプロンプトに適用させるようにしています。

このように本番環境から実験用テンプレートを使ってプロンプトの実験をできるようにしたことで、エンジニア以外のメンバーもプロンプトやパラメータを変更できるようになり改善速度が劇的に上がりました。

本番環境で実験を行うためのテンプレートの運用方法

PromptLayer上で、下記の写真のようにテンプレートを実験用と実際に使用されているものに分けて管理し、実験して結果がよかったものを実際に使用されるテンプレートに反映させます。

PromptLayerでは、プロンプトのテンプレートをフォルダに入れることができるので、実験用フォルダと実際に使用される用のフォルダを分けて運用しています。


テンプレートを実験用と実際に使用されているものに分けて管理する

このように、まだ実験・検証段階のテンプレートもPromptLayer上で管理することで、今どのテンプレートが実験・検証されているのかが誰が見ても分かるようになっています。

まとめ

今回はPharmaXが実際に運用している実験管理のプラクティスをご紹介しました。
特に、プロンプトのテンプレートを作成し、そのテンプレートにLLMの入出力結果を紐づけることで管理するという手法を中心に、実験管理の仕方をご紹介しました。

また、特にPharmaXで行って効果の大きかったプラクティスとして、まだ実験・検証段階のプロンプトを本番環境から呼び出せるようにするというプラクティスについても解説しました。
この記事では特に触れませんでしたが、もちろん新しい機能を作るときは開発者がローカルで実験してからリリースします。ローカル環境で使用するプロンプトも当然PromptLayer上で管理しています。
一方、ローカル環境では、本番さながらのデータ、状況でプロンプトの検証・改善をすることができません。
今回ご紹介したような方法で本番環境でプロンプトを検証・改善することができればPDCAが爆速で周り、LLMアプリケーション開発が進むのではないしょうか。

PharmaXテックブログ

Discussion