2
3

LangChain(Python)のPrompt基本使い方

Posted at

いつも適当に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)
print(response.content)
Hello! How can I assist you today?

たまにhumanではなく以下のようにuserと書いてあるのも見たことがあります。時間ないので細かく調べていませんが、動作はhumanと同じ。
image.png

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クラスの使用

基本と同じことをクラスSystemMessageHumanMessageを使って実装。書き方が違うだけで特に機能に変化なしです。ただ、こちらの書き方の方が、リテラルよりも保守性が高そうに思います。

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)
print(prompt.text)
Call me 太郎

PromptpTemplateだけを使って、LLMにPromptを投げます。そのときに変数に辞書形式で値を渡します。この方式だと勝手にプロンプトのRoleがhumanになってくれるみたいです(詳細未確認)。

chain = prompt_template | llm
response = chain.invoke({"name": "太郎"})
print(response.content)
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)
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)
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)
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()
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)

履歴を踏まえた回答が返ってきていますね。

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()
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:")]
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3