SmartHR Tech Blog

SmartHR 開発者ブログ

Prompt flowの良いところ、難しいところ ── 使ってみてわかった!

こんにちは!SmartHRでAIプロダクト開発をしている@nukosukeです。

近年、様々な企業でLLMを使ったアプリケーション開発を模索しています。 SmartHRもその1つで、AIプロダクト開発チームではLLMを使ったプロダクトを模索しています。

LLM関連のツールは枚挙にいとまがないほどありますが、AIプロダクト開発チームではPrompt flowというツールを使っていました。 今回は、AIプロダクト開発チームでのPrompt flowを使って、LLMにアプリケーションを評価させるLLM as a Judgeを使った経験を下記のラインナップで紹介します。

注意事項

  • 今回の記事の内容はAIプロダクト開発チームがPrompt flowを2024年の半ばくらいから数ヶ月ほど使った経験に基づきます。そのため、本記事の執筆時点(2025年1月)とはまた状況が違うかもしれません。
  • 一部、私が個人的にPrompt flowを使ってみた経験も含みます。

Prompt flowとは?

Prompt flowはLLMアプリケーションを開発しやすくするためのMicrosoft製のツールです。

github.com

Prompt flowを使えば、例えばチャットのようなアプリケーションを作成したり、LLM as a Judgeのように評価フローを組み立てることができます。 なお、Azure Machine LearningのPrompt flowと混同されることも多いですが、Prompt flow自体はオープンソースで公開されており、ローカルやセルフホスティング環境でも使うことができます。

Prompt flowには色々機能がありますが、平たく言ってしまえば ワークフローを作るためのツール と捉えています。 LLMを使った開発をする場合、ユーザーから受け取ったデータを加工したり、ベクトルDBにデータを格納/問い合わせしたり、ケースに応じて何度かLLMとやりとりするなどなど、処理が複雑になることもあると思います。 このような処理をワークフローとして実行しやすくしたのがPrompt flowです。

AIプロダクト開発チームでのPrompt flowの使い方

AIプロダクト開発チームでは LLM as a Judgeを使ったオフライン評価でPrompt flowを使っていました。 具体的には、インプットと期待値のセットを予め用意しておき、RAGやLLMへ問い合わせ、LLM as a Judgeといった一連の処理をPrompt flowを使って評価していく、といったイメージです。

LLM as a Judgeは色々なやり方や評価観点などあると思いますが、AIプロダクト開発チームではAzure Machine LearningのPrompt flowで事前に用意されている評価プロンプトを活用しました。 Azure Machine LearningではPrompt flowのテンプレートが用意されており、評価用のフローも用意されています。便利。

Azure Machine Learningでプロンプト作成画面
Azure Machine Learningでプロンプト作成画面

例えば「QnA Groundedness Evaluation」のテンプレートを使ってPrompt flowを作成すると、次のようなLLM as a Judgeの評価用プロンプトを得ることができます(2025/01/21時点)。 なお、例に挙げているものは、LLMの回答がどのくらいコンテキスト(例えばRAGで取得したテキスト)に準じているかをスコアリングするものです。

groundedness_scoreのプロンプト
groundedness_scoreのプロンプト

このようにAzure Machine LearningのPrompt flowでは様々な評価テンプレートが用意されています。これらのプロンプトを活用しながらAIプロダクト開発チームはPrompt flowによる評価フローを組み立てました。

Prompt flowの良いところ

AIプロダクト開発チームでPrompt flowを実際に使った経験の元に、「良かったな」と思うところをご紹介します。

タスクをYAMLで書くとよしなに色々してくれる

Prompt flowが良い点の1つは、YAML形式でタスクの処理を書くと、「よしなに色々してくれる」点です。

$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json
inputs:
  entities:
    type: list
    default:
    - software engineer
    - CEO
  ground_truth:
    type: string
    default: '"CEO, Software Engineer, Finance Manager"'
outputs:
  match_cnt:
    type: object
    reference: ${match.output}
nodes:
- name: cleansing
  type: python
  source:
    type: code
    path: cleansing.py
  inputs:
    entities_str: ${inputs.ground_truth}
- name: match
  type: python
  source:
    type: code
    path: match.py
  inputs:
    answer: ${inputs.entities}
    ground_truth: ${cleansing.output}
- name: log_metrics
  type: python
  source:
    type: code
    path: log_metrics.py
  inputs:
    match_counts: ${match.output}
  aggregation: true
environment:
  python_requirements_txt: requirements.txt

(promptflowのGitHubリポジトリより引用)

「よしなに色々してくれる」というのは、例えばタスクの依存関係を見て並行で実行したり、可視化したりすることができます。

ワークフローを作成するツールによっては、「AのタスクはBのタスクに依存関係があって、こことここは依存関係がないから並行で実行して...」みたいなことを考えながら手続き的なコードを書く場合もあります。 Prompt flowではYAMLで各タスクを記述し、タスクのインプットとアウトプットを解析してくれて、よしなに諸々やってくれます。

また、Visual Studio Codeの拡張機能であるPrompt flow for VS CodeやAzure Machine LearningのPrompt flowを使うことでタスクの依存関係も可視化することができます。

Prompt flow for VS Code
Prompt flow for VS Code

Prompt flowの公式サイトより引用)

YAMLの記述をPrompt flow for VS CodeのGUI上で編集することも可能です。またタスクのデバッグ実行なども同じくGUI上からできて便利です。

LLMの処理が簡潔に書ける

Prompt flowではOpenAIやAzure OpenAIを使ったLLMの処理を簡潔に書くことができます。 LLMへ渡すパラメータは、例えば次のようにYAMLで記述できます。

- name: question_to_llm
  type: llm
  source:
    type: code
    path: question_to_llm.jinja2
  inputs:
    deployment_name: gpt-4
    temperature: 1
    top_p: 1
    max_tokens: 1000
    presence_penalty: 0
    frequency_penalty: 0
    question: ${inputs.question}
  provider: AzureOpenAI
  api: chat

LLMへ渡すプロンプトは、jinja2(Pythonのテンプレートエンジン)のファイル形式で記述できます。

system:
You are a helpful assistant.

user:
{{question}}

このようにわざわざコードを書かなくともLLMへ渡すパラメータやプロンプトを記述することができます。 なお、LLMを例に挙げていますが、その他にも例えばベクトルDBへの検索も簡潔に書くことができます。 ただし、OpenAIやAzure OpenAI以外のLLMには基本的に対応していないので注意が必要です。

タスクの処理を追跡しやすい

Prompt flowではTrace Viewという機能が用意されており、各タスクでどのくらい時間がかかったか、LLMでどのくらいトークンを使ったかなどを確認することができます。

Trace View
Trace View

Prompt flowの公式サイトより引用)

先述したPrompt flow for VS Codeでも、どこの処理でエラーが出たのかを確認できますし、デバッガをアタッチするようなデバッグ実行もVS Code上のGUIからできます。

その他、Prompt flowでは、事前に用意したデータ分だけフローを実行する(例えば100個インプットとなるデータがある場合は100回分実行する)ようなBatch Runという機能がありますが、こちらもTrace Viewを使って確認することができます。

このようにワークフローの機能として追跡機能も充実しています。 ただし、こちらもトークンなどのLLMに関するメトリクス収集はOpenAIやAzure OpenAI以外には対応していないので注意が必要です。

Prompt flowの難しいところ

Prompt flowを実際に使って「良かったな」と思うところをご紹介しました。 一方で、「ここは難しいな」と思ったところもあったためご紹介します。

Azure Machine LearningとGit管理との相性が良くない

Azure Machine LearningにおけるPrompt flowでは、ブラウザ上からPythonのコードなどが編集できて便利です。

[Azure portalのPrompt flow
Azure portalのPrompt flow

一方で、誰でも自由にブラウザ上からフローを編集できてしまうので、できればGitでコードを管理したいところです。 が、私たちがPrompt flowを使っていた時点では、ローカルで開発したPrompt flowのコードをAzure Machine Learning上で実行するようなAPIはあったものの、同期をするようなAPIはありませんでした。

私たちの調べた限りでは、このあたりのベストプラクティスのような情報が見つけられませんでした。

オフライン評価における結果の一覧化がしづらい

オフライン評価において、例えば予め用意した100個のインプットと期待値を元に100回フローを実行&スコアリング結果を集計し、平均値といったメトリクスを含めて一覧で見たい場合があります。 Prompt flowにおいてはこれをダイレクトに実現する機能はありませんでした。

Prompt flowでは例えば100回フローを流し、最後100回流した後に処理を実行できるaggregationという機能があります。

@tool
def aggregate(groundedness_scores: List[float]):
    """
    This tool aggregates the processed result of all lines to the variant level and log metric for each variant.

    :param processed_results: List of the output of line_process node.
    :param variant_ids: List of variant ids that can be used to group the results by variant.
    :param line_numbers: List of line numbers of the variants. If provided, this can be used to
                        group the results by line number.
    """

    aggregated_results = {"groundedness": 0.0, "count": 0}

    # Calculate average groundedness score for each variant
    for i in range(len(groundedness_scores)):
        aggregated_results["groundedness"] += groundedness_scores[i]
        aggregated_results["count"] += 1

    aggregated_results["groundedness"] /= aggregated_results["count"]

    # Log metric for each variant
    from promptflow.core import log_metric

    log_metric(key="groundedness", value=aggregated_results["groundedness"])

    return aggregated_results

(promptflowのGithubリポジトリより引用)

上記はaggregation機能を使ったPythonのコード例です。 引数の groundedness_scores はすべてのフローの実行結果が格納されます。

集計結果を元にしたメトリクスも含めてフローの実行結果を一覧化して見たい場合は、例えばCSVに出力するような自前の処理が必要です。 Azure Machine LearningのPrompt flowを使えばもしかしたら実現可能かもしれませんが、少なくともOSSとして使う場合は難しく感じました。

オープンソースの運用として不安なところがある

手前味噌で恐縮ですが、Prompt flowのドキュメントに誤りを見つけた場合は修正のPull Requestを出したり、バグを見つけた場合はissueを出したりしていました。

業務内外問わず、OSSのPrompt flowを見ていて「おや?」と思うことがありました。 例えば外部のコミュニティからのPull RequestやissueをスルーはまぁOSSとして日常茶飯事かもしれませんが、催促を促したとしてもスルーされることが多々あった(私も経験有)ので「流石にスルーし過ぎでは...?」とは思いました。 外部からのPull Requestには external ラベルがつくのですが、ことごとく反応がなく、時限でクローズされて散っていく様子を見ることができます。

マージされているPull Requestもありますが、Microsoft社内の人からのPull Requestのようです。 これは一例ですが、他にもOSSの運用としては他にも思うところがあったりしたので、ちょっと使い続けるのに不安はありました。

AIプロダクト開発チームの今

LLMの周辺ツールは数も多く、またアップデートするスピードも速いです。 私たちAIプロダクト開発チームも立ち上がったばかりということも相まって、まだまだ試行錯誤中です。

殊更LLMアプリケーションの評価という部分には関して言えば、他にも私たちの要件をより満たすようなツールがあったため、別ツールに移行しました。 それはLangfuseです。

langfuse.com

また機会があればテックブログで紹介しようと思います。

Yes, we’re hiring!

いかがでしたでしょうか。SmartHRでは現在、AIに関連するエンジニアやプロダクトマネージャーを募集しております。まずはカジュアル面談からでも大歓迎です。ご応募お待ちしております!