logo

YAMLで管理するLLMプロンプト開発と活用術

LLMLangChainプロンプトエンジニアリングプロンプト管理
メイン画像
目次を開く
はじめに:プロンプト、どこで管理してますか?
なぜYAMLでプロンプトを管理するのか?
プロンプトローダーの実装:構造化されたYAML→ChatPromptTemplate
YAMLファイルの構造 (例
ローダーコード (抜粋
実行例:YAML+LangChainで生成されるプロンプト
まとめ:プロンプトは「コード」として育てよう

はじめに:プロンプト、どこで管理してますか?

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 の形式が不明瞭で、ドキュメントも見当たりませんでした。

そこで、自前でプロンプトローダーを実装しました。やることはシンプルです:

  1. YAML ファイルの書き方ルールを定める
  2. そのルールに従ってプロンプトを定義
  3. 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 のセルで上書きしてた時代」に別れを告げ、 再現性と保守性のあるプロンプト開発をはじめてみませんか?

;