你提出了一个好问题,这里没有细讲,partial主要是将部分变量在提示词中实例化,最常见的场景是对日期的渲染,比如你的提示词中希望提示词被触发时,自动渲染当前的时间,但是又不能硬编码时间,就需要用到它,类似:
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方法:
def format(self, **kwargs) -> str:
# Get the partial variables and update with kwargs
partial_kwargs = self.partial_variables.copy()
partial_kwargs.update(kwargs)
# Format the messages
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的值插入到提示字符串的适当位置。