你提出了一个好问题,这里没有细讲,partial主要是将部分变量在提示词中实例化,最常见的场景是对日期的渲染,比如你的提示词中希望提示词被触发时,自动渲染当前的时间,但是又不能硬编码时间,就需要用到它,类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from datetime import datetime
def _get_datetime():
now = datetime.now()
return now.strftime( "%m/%d/%Y, %H:%M:%S" )
prompt = PromptTemplate(
template = "Tell me a {adjective} joke about the day {date}" ,
input_variables = [ "adjective" , "date" ],
)
partial_prompt = prompt.partial(date = _get_datetime)
print (partial_prompt. format (adjective = "funny" ))
|
那么在课程这个例子里比较特殊的地方是,format_instructions并没有显式的传入到prompt中,但是实际上这个过程langchain是在内部处理了。我们使用了ChatPromptTemplate,阅读源码可以看到,它有一个format方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def format ( self , * * kwargs) - > str :
partial_kwargs = self .partial_variables.copy()
partial_kwargs.update(kwargs)
formatted_messages = []
for message in self .messages:
if isinstance (message, BaseMessagePromptTemplate):
formatted_messages.append(message. format ( * * partial_kwargs))
elif isinstance (message, BaseMessage):
formatted_messages.append(message.content)
else :
raise ValueError(f "Unexpected message type: {type(message)}" )
return self .output_parser. format (formatted_messages)
|
它主要做的几件事:
1.复制partial_variables字典,并使用kwargs参数更新它。这样可以确保kwargs中提供的任何变量都会覆盖partial_variables中的对应变量。
2.遍历messages列表,对于每个消息,根据其类型进行格式化:
. 如果消息是BaseMessagePromptTemplate的实例,则调用其format方法,并传入更新后的partial_kwargs。
如果消息是BaseMessage的实例,则直接使用其content属性。
如果消息类型不是以上两种,则抛出ValueError异常。
3.将格式化后的消息列表传递给output_parser的format方法进行最终的格式化。
当我们调用prompt.partial(format_instructions=parser.get_format_instructions())时,实际上是在修改ChatPromptTemplate对象的partial_variables属性。在这种情况下,format_instructions被添加到partial_variables字典中,其值为parser.get_format_instructions()返回的格式化指令。当我们最终调用chain.invoke方法时,Langchain库会在内部调用prompt.format方法来格式化提示模板。在format方法内部,它会检查partial_variables字典,并将其中的变量替换到提示模板中对应的占位符上。所以,即使在提示模板中没有显式地包含{format_instructions}占位符,Langchain库也会在内部将format_instructions的值插入到提示字符串的适当位置。