はじめに:プロンプト、どこで管理してますか?
LLM に渡すプロンプト、こんなふうに管理していませんか?
- Jupyter Notebook のセルにベタ書き
- 試行錯誤の履歴は残っておらず、バージョン管理は頭の中
- 気がついたら、なぜ今のプロンプトになったのか説明できない
もし一つでも当てはまるなら、プロンプトの管理と再利用を改善するタイミングかもしれません。
本記事では、YAML を使ってプロンプトを構造的に管理し、LangChain の ChatPromptTemplate に自動変換する仕組みについて紹介します。 プロンプトのバージョン履歴を明示的に残せるだけでなく、開発・運用の再現性も向上します。
なぜYAMLでプロンプトを管理するのか?
プロンプト開発は「試行錯誤」の連続です。 手元で調整 → 実行 → 修正 → 調整……という流れの中で、次第にプロンプトは形を変えていきます。
その変遷を記録せずにいると、
- 「なぜ今の形になったのか」がわからなくなる
- 「以前よかったプロンプト」が復元できない
- チームでの共有が困難になる
といった問題が生じがちです。
YAML を使えば、以下のような形でプロンプトの構成を構造化して記述できます:
input_variables:
- description
template: |
次の説明をもとに、タイプを分類してください。
説明: {description}
また、各バージョンの目的や課題、改善点などは index.yaml に残すことができます:
- version: v1:
updated: 2025-06-10
summary: "基本的な分類プロンプト。初期実装。"
issues:
- "分類精度が低く、スタイルが曖昧な場合に対応できない"
- version: v2:
updated: 2025-06-14
summary: "スタイル候補を複数返すよう改善"
issues:
- "出力形式に揺れがあり、パースが不安定"
こうすることで、プロンプトそのものをコードと同じようにバージョン管理しながら開発することが可能になります。
プロンプトローダーの実装:構造化されたYAML→ChatPromptTemplate
LangChain には prompt_loader という関数がありますが、対応する YAML の形式が不明瞭で、ドキュメントも見当たりませんでした。
そこで、自前でプロンプトローダーを実装しました。やることはシンプルです:
- YAML ファイルの書き方ルールを定める
- そのルールに従ってプロンプトを定義
- Python 側で読み取り、LangChain のテンプレートに変換する
YAMLファイルの構造 (例)
type: chat
input_variables:
- description
- hint
messages:
- role: system
content: |
あなたは XXX の分類器です。以下の説明からタイプを判断してください。
- role: user
content: |
説明: {description}
補足情報: {hint}
ローダーコード (抜粋)
from langchain.prompt import ChatPromptTemplate
import yaml
def load_prompt(path: str) -> ChatPromptTemplate:
# 入力変数を取得
input_variables = self.prompt_data.get("input_variables", [])
# メッセージの処理
messages = self.prompt_data.get("messages", [])
system_message = None
human_message = None
for message in messages:
if message.get("prompt", {}).get("role") == "system":
system_message = message["prompt"]["template"]
elif message.get("prompt", {}).get("role") == "human":
human_message = message["prompt"]["template"]
# ChatPromptTemplateの作成
chat_prompt = ChatPromptTemplate.from_messages([
("system", system_message),
("human", human_message)
])
chat_prompt.input_variables = input_variables
return chat_prompt
LangChain の他のテンプレート(例えば PromptTemplate や FewShotPromptTemplate)にも拡張可能な設計にしておけば、今後の柔軟性も担保できます。
実行例:YAML+LangChainで生成されるプロンプト
例えば次のような YAML を定義したとしましょう:
type: chat
input_variables:
- text
messages:
- role: system
content: テキストを分析して、ポジティブかネガティブかを判断してください。
- role: user
content: {text}
ローダーで読み込むと、LangChain の ChatPromptTemplate から以下のようなプロンプトが組み立てられます:
prompt.format_messages(text="これはとても素晴らしい製品です!")
[SystemMessage(content="テキストを分析して、ポジティブかネガティブかを判断してください。"),
HumanMessage(content="これはとても素晴らしい製品です!")]
これにより、プロンプトをコードから切り離して管理できるだけでなく、プロンプトの再利用・実験・バージョン管理すべてがスムーズになります。
まとめ:プロンプトは「コード」として育てよう
LLM のプロンプトは、もはや一時的なメモではありません。 プロダクトの挙動を決定づける重要なロジックの一部です。
- YAML による構造的な管理
- バージョンと課題の記録
- LangChain との自然連携
これらを整えることで、プロンプトは育ち、残り、再利用される「資産」になります。
「Jupyter のセルで上書きしてた時代」に別れを告げ、 再現性と保守性のあるプロンプト開発をはじめてみませんか?