いつも適当にLangChainのプロンプトを使っていたので、少し整理してみました。似たようなクラスも多いので頭の中がすっきりしました。
使用例
基本
一番基本的な使い方かと思います。system
にLLMの役割を記述して、human
にはLLMに投げかけるプロンプトを書きます。
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo-0125")
messages = [
("system", "You are a helpful assistant"),
("human", "Hi")
]
response = llm.invoke(messages)
print(response.content)
Hello! How can I assist you today?
たまにhuman
ではなく以下のようにuser
と書いてあるのも見たことがあります。時間ないので細かく調べていませんが、動作はhuman
と同じ。
LangChain公式の「Messages」には、それぞれ、以下のように書いています。
SystemMessage
This represents a system message, which tells the model how to behave. Not every model provider supports this.
HumanMessage
This represents a message from the user.
Messageクラスの使用
基本と同じことをクラスSystemMessage
とHumanMessage
を使って実装。書き方が違うだけで特に機能に変化なしです。ただ、こちらの書き方の方が、リテラルよりも保守性が高そうに思います。
from langchain_core.messages import HumanMessage, SystemMessage
messages = [
SystemMessage(content="You are a helpful assistant"),
HumanMessage(content="Hi")
]
response = llm.invoke(messages)
print(response.content)
Prompt Template(変数ありPrompt)
実際には変数に値を埋め込むような使い方が多いと思います。PromptpTemplate
を使います。
from langchain_core.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template("Call me {name}")
prompt = prompt_template.invoke({"name": "太郎"})
print(prompt.text)
Call me 太郎
PromptpTemplate
だけを使って、LLMにPromptを投げます。そのときに変数に辞書形式で値を渡します。この方式だと勝手にプロンプトのRoleがhuman
になってくれるみたいです(詳細未確認)。
chain = prompt_template | llm
response = chain.invoke({"name": "太郎"})
print(response.content)
Hello 太郎! How can I assist you today?
ChatPromptTemplates
ChatPromptTemplatesを使うと、複数メッセージを送れます。
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
prompt_template = ChatPromptTemplate.from_messages([
SystemMessage(content='You are a helpful assistant'),
HumanMessagePromptTemplate.from_template("Call me {name}")
])
prompt = prompt_template.invoke({"name": "太郎"})
print(prompt.messages)
[SystemMessage(content='You are a helpful assistant'),
HumanMessage(content='Call me 太郎')]
MessagesPlaceholder
MessagesPlaceholderを使うことでテキストとしての変数ではなく、メッセージそのものを変数化できます。
from langchain_core.prompts import MessagesPlaceholder
prompt_template = ChatPromptTemplate.from_messages([
SystemMessage(content='You are a helpful assistant'),
MessagesPlaceholder("msgs")
])
prompt = prompt_template.invoke({"msgs":
[HumanMessage(content="hi! my name is 太郎")]})
print(prompt.messages)
[SystemMessage(content='You are a helpful assistant'),
HumanMessage(content='hi! my name is 太郎')]
これは、会話履歴を渡すときによく使います。
from langchain_core.messages import AIMessage
from langchain_core.prompts.chat import HumanMessagePromptTemplate
prompt_template = ChatPromptTemplate.from_messages(
[
SystemMessage(content="You are a helpful assistant"),
MessagesPlaceholder("history"),
HumanMessagePromptTemplate.from_template("{question}")
]
)
history = [
HumanMessage(content="hi! my name is 太郎"),
AIMessage(content="hello 太郎"),
]
prompt = prompt_template.invoke(
{
"history": history,
"question": "Call me my name."
}
)
print(prompt.messages)
[SystemMessage(content='You are a helpful assistant'),
HumanMessage(content='hi! my name is 太郎'),
AIMessage(content='hello 太郎'),
HumanMessage(content='Call me my name.')]
長くなってくるとpretty_print
関数使うことで少し見やすい
prompt_template.pretty_print()
================================ System Message ================================
You are a helpful assistant
============================= Messages Placeholder =============================
{history}
================================ Human Message =================================
{question}
会話履歴がLLMに伝わっているか確認。
chain = prompt_template | llm
response = chain.invoke(
{
"history": history,
"question": "Call me my name."
})
print(response.content)
履歴を踏まえた回答が返ってきていますね。
Of course, 太郎. How can I assist you today?
使ったことはないですが、Example Selectors というFew-Shot Promptingの機能もあるようです。
LangChain Hub
LangChain HubというPromptのHubがあります。Function Callingする場合など、ここのPromptから取得/参考にして使っています。
Python上で呼び出す方法。
from langchain import hub
prompt_template = hub.pull("rlm/rag-prompt")
prompt_template.pretty_print()
================================ Human Message =================================
You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.
Question: {question}
Context: {context}
Answer:
invokeすることで変数埋め込むのは他と同じ。
prompt = prompt_template.invoke({"question": "What is my name?",
"context": "My name is 太郎"})
prompt.to_messages()
コードブロックだと横スクロールが見にくいと思い、表形式に。
prompt.to_messages() |
---|
[HumanMessage(content="You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\nQuestion: What is my name? \nContext: My name is 太郎 \nAnswer:")] |