POMLとJSONを使ってプロンプトの品質の維持を行う
プロンプトの品質維持の困難さ
LLMに指示を与える際に重要になってくるのは、指示となるプロンプトの品質です。
これをより良くするための知識または技術としてプロンプトエンジニアリングという分野が
生まれています。
その中で、
-
Few-Shotプロンプトのような記述形式の研究から得られた知見による質の向上 -
MCPといった新しい規格を開発することによる、LLMの新しい形式のプロンプトとレスポンスの拡張
様々な取り組みが行われてきました。
ただし、これらはあくまで、人とLLMの問題でした。
しかし、人とプロンプトの問題も考えられます。
「質の高いプロンプトを書く」ことを継続し続けられるか
「質の高さ」とはなにか
質の高いプロンプトの要件については、様々な要件がありますが、
総括すると、
「役割を定義し、適切な背景情報を提供し、タスクに対する詳細な説明と実装上のルールを指定し、適切なアウトプットの一例を与える。可能であれば、出力形式も指定する。また、メインタスクから分岐したサブタスクに対する対処方法についても与えるとよい。」
要件はわかりやすいですが、項目が多いですね。
本記事では、「質の高さ」を、いかにこの要件を遵守しているか否かとします。
毎回正しくフォーマットを指定する難しさと煩わしさ
例えば、私たちは特定の条件やフォーマットで延々とプロンプトを書き続けることに対して、
面倒だなと感じてしまう部分があるのではないでしょうか?それも当然です。
長い文を何回も書くことや繰り返しの作業はなるべくしたくない。
より短い時間で、高い成果を欲してしまうものなので、この工程をできるだけ最適化したいですよね。
それを解決するPOML
これを解決してくれるのが、今回ご紹介するPOMLです。
Microsoftが開発しました。LLMのプロンプトのための言語です。
XML的な構造でプロンプトを記述できる
名前からお察しの方もいらっしゃるかもしれませんが、XML的な言語です。
そのため、タグさえ覚えてしまえば、あとはサラサラと
構造的なプロンプトをわかりやすく作成することができます。
また、公式のライブラリとしてパーサーが提供されているので、
POML -> Markdownにパースして、プロンプトとして与えやすい形にできます。
現在はこの2つが公式から提供されています。
プロンプトを作るための豊富なタグ
XMLということは、様々タグで文書を記述するということが理解できると思います。
POMLはAIに対するプロンプトを作成することに特化しているため、
- 役割明示として
<role>、タスクの内容の明示として<task>というタグがある。 - 外部ファイルの情報の参照のタグとして
<Audio>や<Document>、<Image>などがある。 -
Few-Shotのためのタグとして<example>、<input>、<output>がある- 複数例示したい場合は、
<examples>で複数の<example>を囲む。
- 複数例示したい場合は、
- フォーマット指定のタグとして、
<output-format>がある。
他にも、チャットの履歴を示すためのタグやツール呼び出しのためのタグなど
品質の良いプロンプトを作成するためのタグが一通り揃っている。
JSONを読み込ませて変数展開
また、POMLには、JSONファイルのデータを読み込ませることができます。
JSONデータ内のプロパティを変数展開し、文字置換を行うことで、
POMLファイルをテンプレートプロンプトとして扱うことができます。
LLMを使ったAIワークフローのプロンプトを生成させる。
JSONデータを展開してプロンプトに活かせるということは、
- 特定のJSON形式のデータで変数展開する
POMLファイル - その形式
JSONデータを取得できるAPI -
POMLのパーサー - LLM
上記が揃っていれば、特定のタスクの自動化が可能です。
その例は、POMLの公式ドキュメントにも記載されています。
LLMによるワークフローのためのプロンプトのテンプレートを作成できるのは
大きな強みになるでしょう。
そのため、テンプレートとなるPOMLファイルさえあれば、
あとはJSONデータさえ用意しておけば、
プロンプトを書かなくても良い形のAgentic Codingを実行することも
可能になる可能性を秘めています。
条件分岐や配列展開で、出力するプロンプトの形式を変えられる
特定条件下でレンダリングするプロンプトを変えたい場合があるかもしれません。
例えば、優先度が高いもの、フロントエンド・バックエンドのように領域が異なるもの、
使っている技術スタックによってプロンプトを分岐させたいかもしれません。
その場合、POMLには条件分岐があるので、これを活かすと、
少ないファイルで様々なシチュエーションに対応できます。
また、多数のタスクリストをプロンプトとしたい場合は、
配列展開ができると助かりますね。そのようなシチュエーションにも対応しており、
配列のデータを展開して、その内容でリストを作成することができるようになっています。
実際にやってみよう
Pythonプログラム
import poml
import sys
def main():
poml.set_trace(trace_dir="poml_traces")
args = sys.argv
if len(args) <= 3:
print("Usage: python main.py <path_to_poml_file> <path_to_json_context_file>")
return
poml_file = args[2]
json_context_file = args[3]
if not (poml_file.endswith(".poml") and json_context_file.endswith(".json")):
print("Error: Invalid file extensions.")
return
params = poml.poml(
markup=poml_file,
context=json_context_file,
format="openai_chat"
)
print(params["messages"][0]["content"])
if __name__ == "__main__":
main()
POMLプロンプト
<poml>
<role>
あなたは優秀なAIアシスタントです。
ユーザの開発活動を支援するため、決められたフォーマットで出力してください。
</role>
<task>
あなたは、新機能を開発することになりました。
与えられた要件を満たすために必要なステップを洗い出し、
フォーマットに従ってまとめてください。
</task>
<OutputFormat caption="新機能開発のステップ">
<Bold>
{{ feature_name }}
</Bold>
<Section name="要件" syntax="markdown">
<h>要件</h>
<list>
<item for="item in requirements">
{{ item }}
</item>
</list>
</Section>
<Section name="開発ステップ" syntax="markdown">
<h>開発ステップ</h>
<list>
<item for="step in development_steps">
{{ step }}
</item>
</list>
</Section>
</OutputFormat>
</poml>
JSONデータ
{
"title": "新機能",
"fix_requirements": [
"要件1",
"要件2",
"要件3"
],
"fix_steps": [
"ステップ1",
"ステップ2",
"ステップ3"
]
}
ここまで作成できたら、
uv run main.py -- ./feat.poml ./feat.json
を実行してください。
出力結果
# Role
あなたは優秀なAIアシスタントです。 ユーザの開発活動を支援するため、決められたフォーマットで出力してください。
# Task
あなたは、新機能を開発することになりました。 与えられた要件を満たすために必要なステップを洗い出し、 フォーマットに従ってまとめてください。
# 新機能開発のステップ
**新機能**
### 要件
- 要件1
- 要件2
- 要件3
### 開発ステップ
- ステップ1
- ステップ2
- ステップ3
終わりに
プロンプトを書くための新しい言語としてPOMLが生まれたことにより、
プロンプトを書く手段がさらに広がりました。
また、JSONを読み込めることによって、JSONを作っておくだけで、
ある程度の品質のプロンプトを作成することができるようになりました。
これを活用すると、特定のタスクに対するプロンプトを
プログラムで生成しながら、その結果をプロンプトにすることで、
プロンプトの質を維持しながら、LLMからのレスポンスを
ある程度思い通りにすることができるため、
今、LLMへのプロンプトの品質に自信がない方は、
POMLをプロンプト作成に取り入れてみてはいかがでしょうか。
Discussion