langchain更新再体验:加入一个prompt
前言
在上一篇文章中,利用更新的langchain
制作了一个基本的demo
。那么,现在,我们尝试增加难度,再往里面塞一个prompt
。
目前源码已更新到了我的GitHub上,本文对应的是functions
目录下的prompt.py
文件。
配置
这部分相对于上篇文章没有变化,不再赘述。
获得大模型对象
也不再赘述,仅给出代码:
1 | class TongyiFactory(BaseLLMFactory): |
PromptTemplate
这一点还是和以前一样,用的提示词模板,所以先定义一个字符串,并在字符串中定义占位符,使得字符串可以被植入一些我们所需的内容:
1 | template = """ |
然后,用PromptTemplate
类来创建一个模板对象:
1 | prompt_template = PromptTemplate( |
需要注意的是,prompt_tempate
中传入的input_variables
与template
中的占位符需要在数量上、名称上保持一致。
chat_history
为了更方便地体现对话历史,这个也和以前一样:
1 | memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input") |
在这里,memory_key
需要与prompt_template
的input_variables
中的名称对应,input_key
也需要与input_values
中的名称对应。
管道链接
这里就是LLMChain
删除后的写法了。
1 | chain = prompt_template | llm |
管道是什么?他有什么作用?
其实也不需要追着这个【管道】的定义到处问,只需要关注代码的逻辑就够了。chain
无非就是prompt_template
与llm
求或的结果。
所以,我们直接将问题拆开:
invoke
把当我们调用chain.invoke
的时候,首先访问的是chain
对象,这一点毋庸置疑。
非短路或
在访问chain
对象时,由于非短路的或运算符|
的存在,会按照从左到右的顺序依次访问,并且不会因为某一个对象非None
而直接返回。也就是先访问prompt_template
,再访问llm
,直到所有的对象全部被访问到。
于是,问题就很明显了。
管道的存在实际上就是利用非短路的或运算符,将多个Runnable
子类对象组合成一个Runnable
对象,并且从左到右的顺序正好就是期望大模型执行的顺序。在上面这个案例中,顺序就是优先构建PromptTemplate
对象,再构建LLM
对象。
管道操作
说是管道操作,实际上就是访问顺序构建的llm
对象。
1 | result = chain.invoke({"chat_history": memory, "human_input": "What is the capital of France?"}) |
P.S.:并不是写错了
hunman_input
,而是就这么皮,偏要写一个跟prompt
没半点关系的东西。
这样,我们也就会获得到大模型的回答:
1 | It seems there's been a mix-up in your query, |
同样的,这里换行完全是为了好看,不是代表原始输出就是会换行。
总结
其实与以前的版本相比,除了LLMChain
等类似的Chain
需要注意弃用警告以外,包括PromptTemplate
在内的多种类其实都没有太大的变化,在使用上还是保持了老版本的用法。
最大的改动其实是将所有可执行的类统一为了Runnable
,从而可以利用管道顺序执行。