ジェネラティブエージェンツの大嶋です。
この記事では、LangChainのPrompt templateでループを使う方法を紹介します。
想定シーン
プロンプトのテンプレートを作成する際、ループ処理を入れたくなることがあります。
たとえば以下は、ユーザーの入力に応答するためのエージェントを選択する、というプロンプトの例です。
ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: - name: researcher description: リサーチャー - name: coder description: コーダー
上記のプロンプトのうち「Agents」の箇所のエージェント一覧は、プログラムで動的に埋めたい場合もあります。
つまり、プログラム中に以下のようにagentsというエージェントの一覧の変数があるとします。
from pydantic import BaseModel class Agent(BaseModel): name: str description: str agents = [ Agent(name="researcher", description="リサーチャー"), Agent(name="coder", description="コーダー"), ]
この「agents」という変数を使って、以下のようなプロンプトのテンプレートからプロンプトを組み立てたい、ということです。
ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: <ここをagents変数のループで組み立てたい>
このようなシーンでは、Prompt templateの中でループのような処理を記述したくなります。
LangChainのtemplate_format
実はLangChainのPromptTemplateやChatPromptTemplateには、「template_format」というパラメータがあります。
template_formatには「f-string」「mustache」「jinja2」の3種類を指定することができます。
デフォルト値は「f-string」ですが、「mustache」または「jinja2」を使えば、ループのような処理を記述できます。
mustacheを使う例
mustacheを使う場合、ChatPromptTemplateを以下のように記述します。
from langchain_core.prompts import ChatPromptTemplate system_prompt_template = """\ ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: {{#agents}} - name: {{name}} description: {{description}} {{/agents}} """ prompt = ChatPromptTemplate.from_messages( messages=[ ("system", system_prompt_template), ("human", "{{query}}"), ], template_format="mustache", )
template_format="mustache"
としていることと、mustacheの記法でプロンプトを記述していることがポイントです。
このプロンプトの穴埋めを実行します。
query = "今日のニュースは?" prompt_value = prompt.invoke({"agents": agents, "query": query}) print("=== system ===") print(prompt_value.messages[0].content) print("=== human ===") print(prompt_value.messages[1].content)
すると、以下のようにagents変数の値がループでプロンプトに埋め込まれます。
=== system === ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: - name: researcher description: リサーチャー - name: coder description: コーダー === human === 今日のニュースは?
jinja2を使う例
jinja2を使う場合、ChatPromptTemplateを以下のように記述します。
from langchain_core.prompts import ChatPromptTemplate system_prompt_template = """\ ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: {%- for agent in agents %} - name: {{agent.name}} description: {{agent.description}} {%- endfor %} """ prompt = ChatPromptTemplate.from_messages( messages=[ ("system", system_prompt_template), ("human", "{{query}}"), ], template_format="jinja2", )
template_format="jinja2"
としていることと、jinja2の記法でプロンプトを記述していることがポイントです。
このプロンプトの穴埋めを実行します。
query = "今日のニュースは?" prompt_value = prompt.invoke({"agents": agents, "query": query}) print("=== system ===") print(prompt_value.messages[0].content) print("=== human ===") print(prompt_value.messages[1].content)
すると、以下のようにagents変数の値がループでプロンプトに埋め込まれます。
=== system === ユーザーの入力に応答するために適切なエージェントを選択してください。 Agents: - name: researcher description: リサーチャー - name: coder description: コーダー === human === 今日のニュースは?
注意事項
注意事項として、PromptTemplateのAPIリファレンスには以下のセキュリティ上の警告が書かれています。
Security warning:
Prefer using template_format=”f-string” instead of template_format=”jinja2”, or make sure to NEVER accept jinja2 templates from untrusted sources as they may lead to arbitrary Python code execution.
As of LangChain 0.0.329, Jinja2 templates will be rendered using Jinja2’s SandboxedEnvironment by default. This sand-boxing should be treated as a best-effort approach rather than a guarantee of security, as it is an opt-out rather than opt-in approach.
Despite the sand-boxing, we recommend to never use jinja2 templates from untrusted sources.
信頼できないソースから取得したjinja2のテンプレートを使用すると、任意のPythonコード実行の可能性があるという内容であり、この点には注意が必要です。
まとめ
以上、LangChainのPrompt templateでループを使う方法を紹介しました。
LangChainのPromptTemplateやChatPromptTemplateには、「template_format」というパラメータがあり、「mustache」または「jinja2」を使えばループのような処理を記述できます。
なお、この記事のコードはGoogle Colab上のlangchain-core==0.3.25で動作確認しました。 最近はGoogle ColabにLangChainがプリインストールされているので、このようなちょっとした動作確認をしたいときは嬉しいですね。