AI應用必備:探索LangChain PromptTemplate 提示模板的入門與應用-2

Sean Yeh
Python Everywhere -from Beginner to Advanced
25 min readAug 2, 2024

--

Parque Forestal de Gibralfaro, Málaga, España, photo by Sean Yeh
目錄

角色物件(AIMessage, HumanMessage, SystemMessage)
什麼是角色物件?
模板進階用法
1. Partial 固定提示模板中部分的參數
2. 將函式加入模板內容
結論

上一篇我們提到了LangChain中的 PromptTemplate和ChatPromptTemplate,幫助開發者有效率的產出和管理提示文本。在這一篇文章中,我們要探討「對話提示模板( ChatPromptTemplate )」的三種角色物件( AIMessage, HumanMessage, SystemMessage )中尚未提及的部分,另外也會提到提示模板的其他使用方式。

角色物件(AIMessage, HumanMessage, SystemMessage)

# 什麼是角色物件?

角色物件是LangChain中用來構建對話提示模板的重要元素。這些角色物件包括「AIMessage」、「HumanMessage」和「SystemMessage」,每個角色都有其特定的功能和用途。

- AIMessage:代表AI生成的回應。通常用於模擬AI在對話中的回應內容。
- HumanMessage:代表使用者的輸入。這類訊息用於模擬人類在對話中的提問或陳述。
- SystemMessage:用來設定系統提示或背景信息。這些資訊可以用來設定對話的基礎調性。

使用「AIMessage」、「HumanMessage」與「SystemMessage」這三種角色物件,可以讓我們輕鬆地建立不同角色,也可以替換部分內容的訊息提示模板。

再組合成對話提示模板後,即可帶入參數替換內容以形成角色物件串列,傳遞給語言模型進行處理。

## 在PromptTemplate中的應用

在PromptTemplate中,這些角色物件可以被用來構建結構化的對話,幫助模型用更好的方式理解上下文的對話和各角色間的相互關係。

## 使用範例

以下範例顯示了如何使用AIMessage、HumanMessage和SystemMessage建立對話。首先,我們來看這個例子:


from langchain.prompts import PromptTemplate
from langchain.schema import AIMessage, HumanMessage, SystemMessage
# 建立對話提示模板
chat_template = ChatPromptTemplate(
messages=[
SystemMessage(content="You are an AI assistant."),
HumanMessage(content="Can you tell me a joke?"),
AIMessage(content="Sure! Why did the scarecrow win an award? Because he was outstanding in his field!")
]
)
# 輸出提示模板
pprint(chat_template)

輸出的提示模板會是下面這樣:


ChatPromptTemplate(
input_variables=[],
messages=[
SystemMessage(content='You are an AI assistant.'),
HumanMessage(content='Can you tell me a joke?'),
AIMessage(content='Sure! Why did the scarecrow win an award? Because he was outstanding in his field!')
]
)

從上面的結果我們可以觀察到messages是個list串列。這個串列由SystemMessage、HumanMessage與AIMessage等角色物件所組成。此外,你會發現有一個 input_variables,而且它的值是空的。這是因為我們尚未在模板中設定參數的關係。

以上的範例也可以簡化成使用加號運算符號「 + 」直接串接角色物件。


chat_template = (
SystemMessage(content="You are an AI assistant.")+
HumanMessage(content="Can you tell me a joke?")+
AIMessage(content="Sure! Why did the scarecrow win an award? Because he was outstanding in his field!")
)

執行後得到的結果會是一樣的。

## 角色物件與訊息提示模板搭配

角色物件可以與訊息提示模板進行搭配使用,舉下面的例子說明。


prompt = (
SystemMessage(content="You are a doctor.") +
HumanMessage(content="I do not feel good.") +
AIMessage(
content="I am sorry to hear that. Can you tell me more about your symptoms?"
) +
HumanMessagePromptTemplate.from_template("{input}")
)
pprint(prompt)

與前一個範例類似,我們使用符號「 +」直接串接 SystemMessage、HumanMessage 與 AIMessage 三個角色物件,並且在這三個物件之後再次使用符號「 + 」串接一個人類的訊息提示模板HumanMessagePromptTemplate。透過這個方式,我們可以將一個 `input` 參數設定在這個提示模板上。

設定好之後,印出來的話,會是下面這樣的提示模板:


ChatPromptTemplate(
input_variables=['input'],
messages=[
SystemMessage(content='You are a doctor.'),
HumanMessage(content='I do not feel good.'),
AIMessage(content='I am sorry to hear that. Can you tell me more about your symptoms?'),
HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}'))
]
)

這一次的提示模板裡面,我們可以清楚地看到input_variables不再是空值,而是具備了一個input的值。

然後,就可以透過format_messages 輸入input對話。


chats = chat_model.invoke(prompt.format_messages(input="I have a headache")).content
print(chats)

執行後,經過語言模型的解讀之後就會產生下面這樣的結果:

I'm sorry to hear that you're experiencing a headache. 
Have you tried taking any over-the-counter pain medications like
acetaminophen or ibuprofen? It's also important to make sure you
are staying hydrated and getting enough rest. If your headache
persists or gets worse, I recommend consulting with a healthcare
professional for further evaluation and treatment.

同樣的,上面的例子也有較為簡單的表示法:


prompt = (
SystemMessage(content="You are a doctor.") +
HumanMessage(content="I do not feel good.") +
AIMessage(
content="I am sorry to hear that. Can you tell me more about your symptoms?"
) +
"{input}"
)
pprint(prompt)

我們可以省略掉 HumanMessagePromptTemplate的部分,直接用「 + 」加號添加上 input參數。執行的結果應該會是一樣的。

總結來說,角色物件(AIMessage、HumanMessage、SystemMessage)在建立對話系統中有著至關重要的作用。開發者透過這些物件的彈性使用,可以建立出更加自然、流暢的對話體驗,進一步提升AI應用服務的整體性能。

以上介紹了提示模板的基本用法,我們介紹了兩種提示模板的差異與模板參數的使用方式,接下來我們要介紹提示模板的一些進階用法。

模板進階用法

進階用法中,開發者可以固定提示模板的部分參數,從而在不同場景中重用模板,減少重複設計的工作量。此外,LangChain還允許開發者透過函式動態加入新內容,使得模板更加靈活和強大。這種方式特別適用於需要根據上下文動態生成提示的應用場景。

1. Partial 固定提示模板中部分的參數

在某些情況下,將提示模板的部分參數固定起來可以提高使用的效率和一致性。這種方法允許開發者將一些常見的參數設置為固定值,而不需要在每次填寫模板時都提供這些參數值。

partial 是 LangChain 中用於建立部分提示模板的一個功能。它允許我們將一個提示模板傳入部分變數值固定起來,並生成一個新的提示模板。當使用這個新的提示模板時,我們只需要傳入剩下的變數值即可。

透過partial的使用,可以預先設定這些固定參數,減少每次填寫模板時需要提供的參數數量。這樣對於那些需要頻繁且重複的使用相同參數之應用情境非常有用。

# 使用範例

以下是示範如何在LangChain中固定提示模板部分參數的範例:

首先,我們有一個定義好的普通的模板,在模板裡面有兩個參數 variable1 與 variable2。

from langchain.prompts import PromptTemplate

# 定義模板並固定參數
template = PromptTemplate(
template="This is a template with {variable1} and {variable2}.",
input_variables=["variable1", "variable2"]
)
print(template)

直接輸出的話,結果會是。我們以此作為對照組:

PromptTemplate(
input_variables=['variable1', 'variable2'],
template='This is a template with {variable1} and {variable2}.'
)

這時候,我們可以對上面的PromptTemplate物件使用 partial 方法,將參數值直接代入模板中並建立一個新的模板。

template = PromptTemplate(
template="This is a template with {variable1} and {variable2}.",
input_variables=["variable1", "variable2"]
)

partial_template = template.partial(variable1="數值1")
print(partial_template)

輸出後會是下面結果:

PromptTemplate(
input_variables=['variable2'],
partial_variables={'variable1': '數值1'},
template='This is a template with {variable1} and {variable2}.'
)

與前面的對照組相比,這裏可以看到PromptTemplate物件中增加了partial_variables的屬性。這表示我們已經設定好需要被固定的參數。

## 另一種設定方式

除了前面這種設定固定參數的方式外,我們還可以透過下面方式來設定固定參數。

from langchain.prompts import PromptTemplate

# 定義模板並固定參數
template = PromptTemplate(
template="This is a template with {variable1} and {variable2}.",
input_variables=["variable1", "variable2"],
partial_variables={"variable1":"數值1"}
)

print(template)

輸出後的結果仍然是一樣的:

PromptTemplate(
input_variables=['variable2'],
partial_variables={'variable1': '數值1'},
template='This is a template with {variable1} and {variable2}.'
)

端看您喜歡哪一種方式。

接著,我們可以將它套入語言模型試試:

# 定義模板並固定參數
template = PromptTemplate(
template="Make an answer as a {variable1} for {variable2}.",
input_variables=["variable1", "variable2"],
partial_variables={"variable1":"doctor"}
)

# 進入模型
chats = chat_model.invoke(template.format(variable2="headache"))

# 顯示結果
print(chats)

執行的結果:

AIMessage(
content='I recommend taking a pain reliever such as ibuprofen or acetaminophen to help alleviate the headache. It is also important to stay hydrated,
get plenty of rest, and try to relax in a quiet and dark room. If the headache persists or is severe, please schedule an appointment with me for further
evaluation and treatment options.',
response_metadata={
'token_usage': {'completion_tokens': 68, 'prompt_tokens': 16, 'total_tokens': 84},
'model_name': 'gpt-3.5-turbo-0125',
'system_fingerprint': None,
'finish_reason': 'stop',
'logprobs': None
},
id='run-c3afc288-cee0-4ea3-91d7-48cfbdc1709a-0',
usage_metadata={'input_tokens': 16, 'output_tokens': 68, 'total_tokens': 84}
)

如果將variable2的值代換為covid-19的話,會得到下面的結果。

AIMessage(
content='As a doctor, it is important to stay informed about the latest guidelines and recommendations from health authorities regarding COVID-19. It
is crucial to follow proper hygiene practices, such as washing hands regularly, wearing masks in public spaces, and practicing physical distancing to
reduce the spread of the virus. If you are experiencing symptoms of COVID-19, such as fever, cough, or difficulty breathing, it is important to get
tested and follow the advice of healthcare professionals for treatment and isolation. Vaccination is also a key tool in preventing severe illness and
reducing the spread of the virus. It is important to stay informed and take proactive measures to protect yourself and others during this pandemic.',
response_metadata={
'token_usage': {'completion_tokens': 133, 'prompt_tokens': 18, 'total_tokens': 151},
'model_name': 'gpt-3.5-turbo-0125',
'system_fingerprint': None,
'finish_reason': 'stop',
'logprobs': None
},
id='run-c7fd6722-6ae8-44b7-b6ff-0aa9fb4f47f9-0',
usage_metadata={'input_tokens': 18, 'output_tokens': 133, 'total_tokens': 151}
)

partial 的用法可以幫助我們更靈活地使用 LangChain,它有助於提高提示模板的重複使用率和效率,並且可以簡化程式碼的結構,使得開發者能夠更靈活地應付各種使用情境。

2. 將函式加入模板內容

在某些應用場景中,動態生成模板內容是必要的。模板的參數不僅可以輸入固定的值以外,LangChain允許開發者輸入函式的返回值到模板裡面,生成模板的一部分內容,進而根據上下文或動態資料生成更靈活的提示。

# 使用範例與實踐

以下範例展示了如何使用函式動態生成模板內容:

程式碼是根依照使用者輸入的出生年月日計算出對應的季節,然後生成一個包含年份季節的對話提示,並且將這個提示傳給語言模型,最終產生出一個完整的對話內容並將結果印出來。

from datetime import datetime
from langchain.prompts import PromptTemplate

# 計算生日所屬的季節
def get_season(birthday):
month = datetime.strptime(birthday, "%Y-%m-%d").month
year = datetime.strptime(birthday, "%Y-%m-%d").year
if month in [12, 1, 2]:
return f"Winter of {year}"
elif month in [3, 4, 5]:
return f"Spring of {year}"
elif month in [6, 7, 8]:
return f"Summer of {year}"
else:
return f"Fall of {year}"

# 定義模板,將函式結果作為內容的一部分

template = PromptTemplate(
input_variables=["birthday"],
template="I was born in {birthday}, which is in " + "{season}. Could you tell us what happened during that time?"
)

# 使用模板填充數據
birthday = "1990–05–09"
season = get_season(birthday)
filled_template = template.format(birthday=birthday, season=season)

chats = chat_model.invoke(filled_template.format(birthday)).content

print(chats)

程式碼在一開始,就引入了所需的datetimePromptTemplate模組。datetime用於處理日期和時間,PromptTemplate用於生成對話提示模板。

接下來,設計一個計算生日所屬的季節的函式get_season。這個函式會接收一個日期字串作為參數,並返回該日期所對應的季節。然後再兩個變數birthdayseason帶入對話提示模板。
birthday由使用者輸入,而season則透過函式get_season得到值(season = get_season(birthday))。

最後,再使用對話模型生成對話內容。請注意,在此處`chat_model`是預先定義的對話模型物件,詳細內容可以參考上一篇文章,在此省略其定義的部分。

輸出結果為:

Certainly! Here are some significant events that happened in the Spring of 1990:
1. On May 2, 1990, the final episode of the popular TV show "ALF" aired, bringing an end to the series after four seasons.
2. On May 22, 1990, Microsoft released Windows 3.0, a major upgrade to its operating system that helped solidify the company's
dominance in the software industry.
3. In April 1990, the Hubble Space Telescope was launched into orbit by the Space Shuttle Discovery, revolutionizing our
understanding of the universe with its stunning images of distant galaxies and nebulae.
4. In March 1990, Lithuania became the first Soviet republic to declare independence from the USSR, marking the beginning of the
dissolution of the Soviet Union.
5. In April 1990, the Hubble Space Telescope was launched into orbit by the Space Shuttle Discovery, revolutionizing our
understanding of the universe with its stunning images of distant galaxies and nebulae.
These are just a few of the notable events that took place during the Spring of 1990.

透過這種方式,可以根據具體情況動態生成模板的一部分內容,這在需要靈活處理不同情境的應用中尤其有用。

# 也可搭配 Partial 使用

我們也可以將函式返回的值透過Partial固定在某一個參數上。讓該參數固定的從函式取回一定的值。以下舉例說明:

from datetime import datetime

def get_current_time():
now = datetime.now()
return now.strftime("%Y/%m/%d, %H:%M:%S")

# 定義模板,將函式結果作為內容的一部分
template = PromptTemplate( template="現在時間是 {current_time}.")
partial_template = template.partial(current_time=get_current_time())

print(partial_template)

結果會輸出:

PromptTemplate(
input_variables=[],
partial_variables={‘current_time’: ‘2024/08/02, 19:39:08’},
template=’現在時間是 {current_time}.’
)

當模板實際帶入current_time參數時,會執行指定的函式get_current_time,進而重新獲取目前即時的時間。這也可以說是固定部分參數的一種用法。我們可以在模板中隱藏一個「取得現在時間」的參數,這樣模板產出的結果更符合當時的需要。使用者不需要手動輸入這些資訊,模板會自動補足所需的內容,讓操作更方便。以下舉個例子。

下面這段程式碼的主要功能是產生一個包含當天日期的提示模板,並查詢歷史上在這一天曾經發生的事件。使用者不需要輸入今天的日期,模板會自動插入當天日期,使得生成的提示更符合實際需求。

from datetime import datetime, timedelta
from langchain.prompts import PromptTemplate

# 定義函式來獲取今天的日期
def get_today_date():
today = datetime.now()
return today.strftime("%m-%d")

# 定義模板,將函式結果作為內容的一部分
today_template = PromptTemplate(template="請列出歷史上今天 ({today_date}) 發生什麼事?")

# 使用模板填充數據
filled_today_template = today_template.partial(today_date=get_today_date())
chats = chat_model.invoke(filled_today_template.format()).content
pprint(chats)

程式碼中透過get_today_date函式來取得今天的日期,並將其格式化為”月-日”的形式。
然後在 PromptTemplate中定義了一個對話提示模板,包含一個變數{today_date},用來插入今天的日期。模板的格式為:”請列出歷史上今天 ({today_date}) 發生什麼事?”。然後再使用partial方法將函式返回的今天日期值填入模板中,形成最終的提示字串。最後,使用chat_model來生成對話內容,並且印出來。

綜上所述,LangChain提供了更進階的用法,使得PromptTemplate的功能更加的靈活和強大。

無論是透過固定模板的部分參數,或者是透過函式動態的產生模板內容,這些技巧都可以提高模板的使用效率與實用性。如果開發者可以暸解這些技巧並且實際的在專案中運用這些方式,就能夠更有效地應付各種複雜的使用需求,進一步提升AI模型的效能和使用者的體驗。

結論

在這系列文中,我們探討了LangChain PromptTemplate的基本概念和應用。我們從開始介紹 PromptTemplate 的定義及其在AI模型中的重要性,並透過具體範例示範了如何建立和使用這些模板。

此外,我們了解到字串提示模板(PromptTemplate)和對話提示模板(ChatPromptTemplate)個別的使用方式,並探討了角色物件( AIMessage, HumanMessage, SystemMessage )在建構複雜對話中的應用方式。

系列最後,我們也介紹了PromptTemplate的一些進階使用方法,包括固定模板參數和使用函式動態生成內容,這些技巧使得我們在使用PromptTemplate 時能夠更加的靈活與有效率。

LangChain PromptTemplate在AI的應用服務中扮演重要的角色。透過結構化的提示模板,讓開發者提高模型的準確性和效率。鼓勵大家可以深入了解並實際應用LangChain PromptTemplate模板,才能夠掌握這一強大的工具,減少重複的工作,並建立更自然和連貫的使用者體驗。

--

--

Sean Yeh
Python Everywhere -from Beginner to Advanced

# Taipei, Internet Digital Advertising,透過寫作讓我們回想過去、理解現在並思考未來。並樂於分享,這才是最大贏家。