エクサの生成AIチャレンジ日記

連載コラム:エクサの生成AIチャレンジ日記

プロンプトの開発をもっと効率的に!
AIアシスタント「たまちゃん」での取り組み

はじめに

生成AIを活用したアプリケーションにおいて、「プロンプトをいかに効率よく開発するか」は重要なテーマです。


プロンプトは一度作って終わりではなく、何度も試行錯誤を繰り返しながら改善していく必要があり、そのたびにコードや設計書が頻繁に更新されます。


また、プロンプトを過去のバージョンに戻したいケースや、1つのアプリケーション内で複数のプロンプトを組み合わせて使いたいケースがあり、それぞれのプロンプトをメンテナンスしやすい形式で管理しておくことが重要です。


AIアシスタント「たまちゃん」では、現時点で4種類のプロンプトを管理していますが、プロンプトを開発したり改修していく場合に、いくつかの課題がありました。


本記事では、「たまちゃん」で実践した工夫や改善策をご紹介します。生成AIを活用したアプリケーションを開発・運用されている方にとってのヒントになれば幸いです。

改善前

たまちゃんでは、プロンプトの開発や改修において、表1のような課題がありました。

表1. プロンプトの開発や改修における課題
課題詳細
メンテナンス性 プロンプトとアプリケーションのコードが混在していることで可読性が低く、以下の問題が発生
  • プロンプトの全体像が把握しづらい
  • 実装されたプロンプトが設計書と一致しているか確認しづらい
  • プロンプトを修正したい場合に該当箇所の特定が難しい
  • バージョン管理時にプロンプト部分の変更内容が把握しづらい
試行錯誤の容易性 プロンプトの動作確認を行うためには、実装元の設計書を探し出し、Azure AI Foundryにプロンプトやモデルのパラメータを手動で入力する手間がかかる
左右にスワイプすることで、表が見られます

以前のコラム(AIアシスタントが答えられない時、どうサポートする?AIアシスタント「たまちゃん」のUI/UX改善事例 vol.1)でご紹介した「質問に合ったSlackチャンネルを予測する」プロンプトを例に挙げると、改善前は、コード1のように、プロンプトの末尾に次々と文字列を結合していく形式で実装していました。

コード1.プロンプトを作成する
def create_prompt(rules, question, channels):  
  system_prompt = """
  あなたはユーザからの問い合わせに対して、適切なチャンネルに誘導するAIアシスタントです。
  """

  user_prompt = f"""
  #入力された質問 に対して、回答が得られそうなチャンネルを #チャンネル一覧 から選択​してください。
  また、​チャンネルを選択する時は #チャンネルを選択する時のルール に従ってください。​

  # チャンネルを選択する時のルール"""

  for rule in rules:
      user_prompt += f"\n・{rule}"

  user_prompt += """
  # 出力形式
  ## チャンネルを複数選択した場合
  [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}, 
{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},,,]
  ## チャンネルを1つ選択した場合
  [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}]
  ## チャンネルを1つも選択しなかった場合
  []

  # 入力された質問"""

  user_prompt += f"\n{question}"

  user_prompt += """
  # チャンネル一覧
  ["""

  for channel in channels:
      user_prompt += f'\n{"channel_name": {channel['id']},
"channel_description": {channel['description']} }}'

  user_prompt += "\n]"

  return system_prompt, user_prompt

この実装形式では、プロンプトの可読性が低く、プロンプトの全体像や実際に生成AIに渡されるプロンプトの内容が、把握しづらいことが分かります。


また、たまちゃんでは、生成AIの管理やプロンプトの動作確認にAzure AI Foundryを活用しています。しかし、プロンプトを見直す際に、Azure AI Foundry上で動作確認を行いたい場合、図1のような手順が必要でした。具体的には、まず実装元の設計書を探し出し、その後、Azure AI Foundryにプロンプトやモデルのパラメータを手動で入力しなければならず、多くの手間がかかっていました。

図1. プロンプトを動作確認するまでの流れ

図1. プロンプトを動作確認するまでの流れ

このように、改善前では、プロンプトのメンテナンスがしづらい課題や、試行錯誤が容易に行うことができない課題がありました。そこで、これらの課題を解決できるよう、改善に取り組むことにしました。

動的に値を書き換えたい項目はプレースホルダーとしておく

まず、プロンプトの可読性を向上させるには、動的に値を切り替えたい部分をプレースホルダー(変数)としてプロンプト内に記述し、後から文字列置換を用いて、その部分を置換する方法が有効だと考えられます。


実装例はコード2のようになります。

コード2.プレースホルダーを用いてプロンプトを作成する
def create_prompt(rules, question, channels):  
    system_prompt = """
    あなたはユーザからの問い合わせに対して、適切なチャンネルに誘導するAIアシスタントです。
    """
 
    user_prompt = """
    #入力された質問 に対して、回答が得られそうなチャンネルを #チャンネル一覧 から選択​してください。
    また、​チャンネルを選択する時は #チャンネルを選択する時のルール に従ってください。​
 
    # チャンネルを選択する時のルール
    {{rules_st}}

    # 出力形式
    ## チャンネルを複数選択した場合
    [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},
{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},,,]
    ## チャンネルを1つ選択した場合
    [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}]
    ## チャンネルを1つも選択しなかった場合
    []

    # 入力された質問
    {{question}}

    # チャンネル一覧
    [
    {{channels_st}}
    ]
    """

    rules_st = "\n".join([f"・{rule}" for rule in rules])
    user_prompt = user_prompt.replace("{{rules_st}}", rules_st)
    
    user_prompt = user_prompt.replace("{{question}}", question)

    channels_st = "\n".join([f'{{"channel_name":{channel["id"]},
"channel_description": {channel["description"]} }}' for channel in channels])
    user_prompt = user_prompt.replace("{{channels_st}}", channels_st)

    return system_prompt, user_prompt

改善前のコードと比較すると、最初にプロンプト全体をまとめて記述できるため、プロンプトの内容や構成がひと目で分かりやすくなります。

テンプレートエンジンのJinjaを活用する

さらにプロンプトの可読性を高める方法として、Jinjaを活用することが考えられます。


JinjaはPythonで使えるテンプレートエンジンで、テンプレート(文字列)内に変数や処理を記述しておくことで、動的にテキスト(HTMLやXML、プレーンテキストなど)を生成できます。また、Jinjaは、PythonのWebアプリケーションフレームワークであるDjangoのテンプレートエンジンの影響を受けており、テンプレート内でPythonに似た簡単な構文(加工処理、ループや条件分岐など)を書くことができます。


Jinjaを用いてプロンプトを作成する場合、コード3のような実装になります。

コード3.Jinjaを用いてプロンプトを作成する
from jinja2 import Template

def create_prompt(rules, question, channels):  
    system_prompt = """
    あなたはユーザからの問い合わせに対して、適切なチャンネルに誘導するAIアシスタントです。
    """
 
    user_prompt = """
    #入力された質問 に対して、回答が得られそうなチャンネルを #チャンネル一覧 から選択​してください。
    また、​チャンネルを選択する時は #チャンネルを選択する時のルール に従ってください。​
 
    # チャンネルを選択する時のルール
    {%- for rule in rules %}
    ・{{ rule }}
    {%- endfor %}

    # 出力形式
    ## チャンネルを複数選択した場合
    [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},
{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},,,]
    ## チャンネルを1つ選択した場合
    [{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}]
    ## チャンネルを1つも選択しなかった場合
    []

    # 入力された質問
    {{ question }}

    # チャンネル一覧
    [
    {%- for channel in channels %}
    {"channel_name":{{ channel.id }}, "channel_description": {{
channel.description }} }
    {%- endfor %}
    ]
    """

    user_prompt = Template(user_prompt).render(rules=rules,
question=question, channels=channels)

    return system_prompt, user_prompt

Jinjaを使わない場合と比べて、コードがよりシンプルになり、配列やオブジェクトの値がどのようにプロンプトに挿入されるかが分かりやすくなり、可読性がさらに向上します。

活用可能なPythonライブラリ

Jinjaを使ってプロンプトを作成する場合、いくつか活用可能なPythonライブラリがあります。主要なPythonライブラリを表2にまとめました。

表2. Jinjaを使ってプロンプトを作成する場合に活用可能なPythonライブラリ
#ライブラリ名作成元ライセンステンプレートで管理可能な項目備考
1 Prompty Microsoft MIT
  • プロンプト
  • モデルのパラメータ
  • LangChain, Semantic Kernel, Prompt flow (Experimental版)からも利用可能
  • OpenAI, Azure OpenAI Service, Azure AI Serverlessのモデル呼び出しに対応
  • Azure AI Foundry上でのテンプレートファイルのエクスポート/インポートに対応
  • Visual Studio Codeの拡張機能でGUI上での動作確認が可能
2 Prompt-Poet Character.AI MIT プロンプト
  • Googleが当該ライブラリを買収
  • トークン数に応じた文字列切り捨てが可能
左右にスワイプすることで、表が見られます

補足情報として、AWSには「Amazon Bedrock Prompt Management」というサービスがあります。このサービスでは、作成したプロンプトや、プロンプト作成時のモデルのパラメータなどをバージョン管理できます。また、バージョン管理したプロンプトは、Amazon BedrockのAPIから呼び出すことができます。Azure OpenAI ServiceではなくAmazon Bedrockを利用しているケースにおいては、このサービスが活用できると考えられます。

Promptyを導入する

先ほど挙げたPythonライブラリの内、たまちゃんでは、Azure OpenAI ServiceやAzure AI Foundryを利用しているため、Promptyというライブラリを導入することにしました。


Promptyでは、コード4のように「.prompty」という拡張子のテンプレートファイルでプロンプトを管理します。また、テンプレートファイルでは、プロンプトだけでなく、プロンプト実行時のモデルのパラメータや、プロンプトに関する補足情報(説明文や入出力例など)も管理することができます。

コード4.テンプレートファイル(.prompty)
---
name: PredictDestinationChannel
description: 質問に適した問い合わせ先のチャンネルを予測するプロンプト
model:
  api: chat
  configuration:
    type: azure_openai
    azure_endpoint: https://dummy
    api_version: 2024-12-01-preview
    azure_deployment: gpt-4o-mini
  parameters:
    temperature: 0
  response: full
sample:
  rules: ${file:./samples/rules.json}
  question: "PCの設定手順を教えてください。"
  channels: ${file:./samples/channels.json}
---

system:
あなたはユーザからの問い合わせに対して、適切なチャンネルに誘導するAIアシスタントです。

user:
#入力された質問 に対して、回答が得られそうなチャンネルを #チャンネル一覧 から選択​してください。
また、​チャンネルを選択する時は #チャンネルを選択する時のルール に従ってください。​

# チャンネルを選択する時のルール
{%- for rule in rules %}
・{{ rule }}
{%- endfor %}

# 出力形式
## チャンネルを複数選択した場合
[{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}, {"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"},,,]
## チャンネルを1つ選択した場合
[{"channel_name":"選択したチャンネル名", "score": "確信度(0~1の範囲)"}]
## チャンネルを1つも選択しなかった場合
[]

# 入力された質問
{{ question }}

# チャンネル一覧
[
{%- for channel in channels %}
{"channel_name":{{ channel.id }}, "channel_description": {{ channel.description }} }
{%- endfor %}
]

このテンプレートファイルをPythonのプログラムから利用する場合は、コード5のような実装になります。プロンプトの作成から生成AIへのリクエストまでを、シンプルに実装できることが分かります。

コード5.テンプレートファイル(.prompty)をPythonのプログラムから利用
import prompty
import prompty.azure

def chat(rules, question, channels):
    prompty_file_path = "PredictDestinationChannel.prompty"
    # 「.promtpyファイル」を使ってプロンプトの作成から生成AIへのチャットまで行う
    completion = prompty.execute(prompty_file_path,
                             inputs={
                                 "rules": rules,
                                 "question": question,
                                 "channels": channels
                             },
                             raw=True)

    return completion

また、テンプレートファイルはPythonのプログラムから利用できるだけでなく、Azure AI FoundryやVisual Studio CodeのGUI上で動作確認することもできます。これは、Azure AI Foundryがテンプレートファイルのインポートとエクスポートに対応していることや、PromptyがVisual Studio Code用の拡張機能を提供しているためです。


たまちゃんでは、Promptyの導入により、図2のような流れでプロンプトが開発できるようになりました。

図2. Prompty導入後におけるプロンプト開発の流れ

図2. Prompty導入後におけるプロンプト開発の流れ

Azure AI FoundryやVisual Studio CodeのGUI上で作成したプロンプトは、そのままテンプレートファイルとしてアプリケーションに簡単に組み込むことができます。また、アプリケーションに組み込まれたテンプレートファイルは、素早くAzure AI FoundryやVisual Studio CodeのGUI上で動作確認することもできます。これにより、プロンプトの開発や修正をスムーズに進められるようになりました。

改善後

Prompty導入後、改善前に抱えていた課題は表3のように解決されました。

表3. Prompty導入で解決した課題
課題詳細Prompty導入後
メンテナンス性 プロンプトとアプリケーションのコードが混在していることで可読性が低く、以下の問題が発生
  • プロンプトの全体像が把握しづらい
  • 実装されたプロンプトが設計書と一致しているか確認しづらい
  • プロンプトを修正したい場合に該当箇所の特定が難しい
  • バージョン管理時にプロンプト部分の変更内容が把握しづらい
  • プロンプト(モデルのパラメータも含む)をテンプレートファイルとして、アプリケーションのロジックから分離したことで、プロンプトの内容を簡単に把握・管理できるようになった
  • プロンプト内で動的に切り替わる部分は、どの値がどのように挿入されるかが明確になった
試行錯誤の容易性 プロンプトの動作確認を行うためには、実装元の設計書を探し出し、Azure AI Foundryにプロンプトやモデルのパラメータを手動で入力する手間がかかる
  • アプリケーションに組み込まれたプロンプトが、Azure AI FoundryやVisual Studio CodeのGUI上でスムーズに動作確認できるようになった
  • Azure AI FoundryやVisual Studio CodeのGUI上で作成したプロンプトが、アプリケーションにスムーズに組み込めるようになった
左右にスワイプすることで、表が見られます

さいごに

今回は、AIアシスタント「たまちゃん」で実践した、プロンプトの開発を効率化するための取り組みについてご紹介しました。


ご紹介した取り組みは、生成AIを活用した様々なアプリケーションでも応用できるものだと考えられます。これから生成AIを活用したアプリケーションの開発を始める方はもちろん、すでに運用されている方にも役立つ情報となれば嬉しいです。


本記事に記載されているロゴ、システム名称、企業名称、製品名称は各社の登録商標または商標です。

執筆者紹介

連載コラム:エクサの生成AIチャレンジ日記

本コラムでは、エクサ社内における生成AIの活用に向けた技術的な取り組みと、実際の業務適用事例をご紹介いたします。生成AIによる業務効率化や新たな価値創造のヒントとなれば幸いです。

関連コラム

関連ソリューション

関連事例

お問い合わせ

CONTACT

Webからのお問い合わせ
エクサの最新情報と
セミナー案内を
お届けします