Zenn
🪽

Arize Phoenix v8.0 新機能:プロンプトテンプレートの基本と LangChain アプリケーションへの応用

2025/02/26に公開

はじめに

Arize Phoenix は、LLM の実験、評価、トラブルシューティングのために設計された OSS オブザーバビリティプラットフォームです。2025 年 2 月にリリースされた Phoenix v8.0 より、プロンプトテンプレートの管理機能が新たに追加されました。
既にリリースされていた Playground 機能と組み合わせることで、より効率的にプロンプトエンジニアリングを推進することができるようになりました。

image

https://docs.arize.com/phoenix/prompt-engineering/overview-prompts/prompt-management

プロンプトテンプレート管理

プロンプトテンプレート管理は LangSmithLangFuse など他のサービス・OSS でも導入されている機能になります。コードにプロンプトをベタ書きする従来の方法と比較して、以下のような多くのメリットがあります:

  1. 再現性の確保:プロンプトとモデルパラメータを一緒に管理することで、LLM の出力結果の再現性を高め、バージョン管理されたプロンプトを使用すれば、いつでも同じ条件で実行することが可能

  2. メンテナンス性の向上:コードロジックとプロンプトを分離することで、プロンプトの更新がアプリケーションコードの変更が不要

  3. チーム間コラボレーションの促進:中央管理されたプロンプトライブラリにより、組織内での知識共有とコラボレーションが容易になり、異なるチームや部門間でのプロンプトの再利用も促進

  4. バージョン管理と変更履歴:プロンプトの変更履歴を追跡し、必要に応じて以前のバージョンに戻すことが可能となり、問題が発生した場合の原因特定も容易

  5. 環境ごとの管理:開発、テスト、本番環境など、異なる環境ごとに適切なプロンプトバージョンを使い分けが可能

プロンプトテンプレート管理を導入することで、LLM アプリケーション開発の効率性、品質、ガバナンスを向上させることができると想定されます。

Phoenix の Prompt Template Management を試してみる

以降の検証環境は以下のとおりです。

LLM プロバイダー設定

Playground で LLM を活用するために、各種 LLM プロバイダーの API キー等の認証情報を登録します。v8.0 の時点では、OpenAI、Azure OpenAI Service、Anthropic、Google AI Studio の 4 つのプロバイダーが対応しています。

API キー等の登録はダッシュボードの「settings」から直接入力することができます。

image

また Phoenix をセルフホスティングしている場合は、環境変数から指定することも可能です。

Provider Environment Variable Platform Link
OpenAI OPENAI_API_KEY https://platform.openai.com/
Azure OpenAI AZURE_OPENAI_API_KEY / AZURE_OPENAI_ENDPOINT / OPENAI_API_VERSION https://azure.microsoft.com/en-us/products/ai-services/openai-service/
Anthropic ANTHROPIC_API_KEY https://console.anthropic.com/
Gemini GEMINI_API_KEY or GOOGLE_API_KEY https://aistudio.google.com/

Playground

Playground では、プロンプトエンジニアリングを行うためのエディタ機能やプロンプトの実行が可能です。

image

  • Message:プロンプトテンプレートのメッセージ部分を定義します。基本的な使い方は LangSmith と同じで、rolemessageを定義します。

  • Response Format

    • Response Format を活用することで、任意の Json 形式のレスポンスを生成することができます。
    • OpenAI の Structured Outputsに従って Json Schema を定義します。
    • OpenAI のクライアントライブラリや Langchain など各種 LLM フレームワークでは Pydantic の BaseModel で定義したモデルでレスポンスを生成することができるなか、json 手書きはツライ。。
    {
      "type": "json_schema",
      "json_schema": {
        "name": "content_compliance",
        "description": "Determines if content is violating specific moderation rules",
        "schema": {
          "type": "object",
          "properties": {
            "is_violating": {
              "type": "boolean",
              "description": "Indicates if the content is violating guidelines"
            },
            "category": {
              "type": ["string", "null"],
              "description": "Type of violation, if the content is violating guidelines. Null otherwise.",
              "enum": ["violence", "sexual", "self_harm"]
            },
            "explanation_if_violating": {
              "type": ["string", "null"],
              "description": "Explanation of why the content is violating"
            }
          },
          "required": ["is_violating", "category", "explanation_if_violating"],
          "additionalProperties": false
        },
        "strict": true
      }
    }
    

    実行結果

  • Tool

    • Function Calling を定義することができます。
    • こちらもOpenAI の Function Callingのフォーマットに従って定義することができます。
    {
      "function": {
        "name": "get_weather",
        "description": "与えられた地点の現在の気温を取得",
        "parameters": {
          "type": "object",
          "required": ["location"],
          "properties": {
            "location": {
              "type": "string",
              "description": "地名や国名。例:ロンドン、大阪、カナダなど"
            }
          },
          "additionalProperties": false
        },
        "strict": true
      },
      "type": "function"
    }
    

    実行結果

モデルパラメータ定義

LLM の再現性を確保するためには、プロンプトテンプレートに加え、モデルパラメータもセットで管理する必要があります。Playground では、モデル名以外にも、temperaturetop_pmax_tokens などのプロバイダーに応じたパラメータを定義することができます。

image

プロンプト比較

プロンプトテンプレートを複数定義して、 playground 内で比較検証を行うことができます。

image

データセットによる評価

またPhoenix のデータセット管理機能と連携して、プロンプトを評価することも可能になります。事前に登録しておいたデータセットを指定して実行するだけで、データセット内のすべてのデータに対してプロンプトの実行結果を確認することができます。

image

プロンプト登録

Playground で作成したプロンプトは、プロンプトテンプレートとして登録することができます。プロンプトはバージョンごとに管理され、任意のタグも設定することができます。

image

プロンプトテンプレートの LLM アプリケーションでの利用

https://docs.arize.com/phoenix/prompt-engineering/how-to-prompts/using-a-prompt

作成したプロンプトテンプレートを実際の LLM アプリケーションで利用するためには、Phoenix のクライアントライブラリである[arize-phoenix-client](https://github.com/Arize-ai/phoenix/releases/tag/arize-phoenix-client-v1.0.0)をインストールします。

インストール方法
pip install arize-phoenix-client

あとはプロンプト名、もしくはバージョン ID、タグ名を指定することで、プロンプトテンプレート、およびモデルパラメータを取得することができます。

from phoenix.client import Client

client = Client(endpoint="http://localhost:6006", api_key="your_api_key")

prompt_name = "demo"
prompt = client.prompts.get(prompt_identifier=prompt_name)
print(prompt._dumps())
prompt._dumps()の出力結果
{
  "model_provider": "AZURE_OPENAI",
  "model_name": "gpt-4o-mini",
  "template": {
    "messages": [
      {
        "role": "system",
        "content": [{ "type": "text", "text": "You are a chatbot" }]
      },
      {
        "role": "user",
        "content": [{ "type": "text", "text": "{{question}}" }]
      }
    ],
    "type": "chat"
  },
  "template_type": "CHAT",
  "template_format": "MUSTACHE",
  "invocation_parameters": {
    "type": "azure_openai",
    "azure_openai": {
      "temperature": 0.0,
      "frequency_penalty": 0.0,
      "presence_penalty": 0.0,
      "top_p": 1.0,
      "seed": 1
    }
  },
  "description": ""
}

LangChain での利用

最後に取得したプロンプトテンプレートを LangChain で利用する方法を検証していきます。v8.0 の時点ではarize-phoenix-clientでは LangChain との連携は対応していないため、一部の機能を自力で実装する必要があります。

LLM モデル

LLM のモデルはprompt._model_providerに応じて、必要なプロバイダーのモデルを返す関数を作成しました。モデル名(prompt._model_name)やモデルパラメータ(prompt._invocation_parameters)もテンプレートから取得するようにしています。

from langchain_core.language_models import BaseChatModel
from langchain_openai import AzureChatOpenAI, ChatOpenAI


def get_chat_model_from_phoenix(prompt: PromptVersion) -> BaseChatModel:
    """Get a chat model from Phoenix prompt template

    Args:
        prompt (PromptVersion): prompt template

    Returns:
        BaseChatModel: chat model
    """
    if prompt._model_provider == "OPENAI":
        return ChatOpenAI(
            model=prompt._model_name,
            api_key=os.getenv("OPENAI_API_KEY"),
            **prompt._invocation_parameters["openai"],
        )
    elif prompt._model_provider == "AZURE_OPENAI":
        return AzureChatOpenAI(
            deployment_name=prompt._model_name,
            api_version=os.getenv("OPENAI_API_VERSION"),
            azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
            **prompt._invocation_parameters["azure_openai"],
        )
    elif prompt._model_provider == "ANTHROPIC":
        ...(省略)
    elif prompt._model_provider == "GOOGLE_AI_STUDIO":
        ...(省略)
    else:
        raise ValueError(f"Unsupported model provider: {prompt._model_provider}")

ここで課題となったのが Azure OpenAI を活用する際に、playground で指定したモデルの API バージョンがモデルパラメータとして取得できないという点です。再現性確保のためには API バージョンも playground と同一に揃えるべきであるため、このあたりは改修を待ちたいと思います。

プロンプトテンプレート

プロンプトテンプレートはprompt._templateに格納されています。prompt._template_formatに応じて、ChatPromptTemplateを返す関数を作成しました。

def get_langchain_template(prompt: PromptVersion) -> ChatPromptTemplate:
    """Get a langchain template from Phoenix prompt template

    Args:
        prompt (PromptVersion): prompt template

    Returns:
        ChatPromptTemplate: langchain template
    """
    if prompt._template_format == "MUSTACHE":
        template_format = "jinja2"
    else:
        template_format = "f-string"

    return ChatPromptTemplate(
        [
            (msg["role"], msg["content"])
            for msg in prompt._template["messages"]
        ],
        template_format=template_format,
    )

実行

モデルとプロンプトテンプレートが LangChain 形式に変換できれば、あとは chain をつくって通常通りに実行することで、プロンプトテンプレートを活用した実行が可能です。

llm = get_chat_model_from_phoenix(prompt)
template = get_langchain_template(prompt)

chain = template | llm

result = chain.invoke({"question": "月にうさぎはいるの?"})
print(result.content)
実行結果
月にうさぎがいるというのは、日本の伝説や民話に由来する表現です。特に「月にうさぎが餅をついている」という話が有名です。実際には、月にはうさぎはいませんが、月の表面に見える模様がうさぎの形に見えることから、このような言い伝えが生まれました。これは文化や神話の一部として楽しまれています。

Response Format

Response Format を定義した場合、bind_llmを活用してモデルをバインドすることで、任意の Json 形式のレスポンスを生成することができます。
また出力結果を Json 形式にパースするためには、JsonOutputParserを活用します。

bind_llm = llm.bind(response_format=prompt._response_format)
chain = temmplate | bind_llm | JsonOutputParser()

response = chain.invoke({"question": "あー殴りてー"})
print(response)
実行結果
{
  "category": "violence",
  "is_violating": true,
  "explanation_if_violating": "The phrase expresses a desire to hit or physically harm someone, which falls under violent content."
}

Tool

Tool を定義した場合、bind_toolsを活用してモデルをバインドすることで、Function Calling を実行することができます。
LangChain では Tool Calling でツールの実行までを行ってくれますが、この方法ではあくまで Function Calling の結果のみの取得となる点は注意が必要です。


llm_with_tool = llm.bind_tools(
    tools=weather_prompt._tools["tools"], tool_choice="auto"
)
chain = weather_template | llm_with_tool

result = chain.invoke({"question": "東京で晴れてる?"})
print(result.content)
実行結果
[{'id': 'call_igOIrnYiLRPGPanDQHRLW4ec', 'function': {'arguments': '{"location":"東京"}', 'name': 'get_weather'}, 'type': 'function'}]

まとめ

LangChain での利用はまだ試行錯誤中ですが、Phoenix のプロンプトテンプレートを活用することで、LangChain での利用も容易になりそうです。
一方で Azure OpenAI Service を活用する際に API バージョンが取得できない問題があり、再現性という観点では課題となりえます。このあたりは Phoenix の改善を待つ必要がありそうです。

参考

https://docs.arize.com/phoenix/prompt-engineering/overview-prompts

Discussion

ログインするとコメントできます