?
如果您還沒有看過我之前寫的兩篇博客,請(qǐng)先看一下,這樣有助于對(duì)本文的理解:
LangChain與大型語言模型(LLMs)應(yīng)用基礎(chǔ)教程:Prompt模板
LangChain與大型語言模型(LLMs)應(yīng)用基礎(chǔ)教程:信息抽取
LangChain與大型語言模型(LLMs)應(yīng)用基礎(chǔ)教程:角色定義?
在默認(rèn)情況下Chain和LLM都是無狀態(tài)的,這意味著它們獨(dú)立地處理每個(gè)傳入的prompt(底層 LLM 和聊天模型也是如此),因此它們不具有記住上下文的能力,但是在很多應(yīng)用場(chǎng)景中我們需要LLM具有記住上下文的能力,這樣會(huì)使我們的機(jī)器人看起來更加“聰明”,從而給用戶帶來更好的用戶體驗(yàn)。今天我們來介紹幾種在LangChain中常用的記憶力組件。
首先我們需要安裝如下的python包:
pip -q install openai langchain huggingface_hub transformers
1. ConversationBufferMemory
這是最簡(jiǎn)單的內(nèi)存記憶力組件,它的功能是直接將用戶和機(jī)器人之間的聊天內(nèi)容記錄在內(nèi)存中。下面我們看一個(gè)例子:
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain import OpenAI
from langchain.chains import ConversationChain
import os
#你申請(qǐng)的openai的api_key
os.environ['OPENAI_API_KEY'] = 'xxxxxx'
#定義llm
llm = OpenAI(model_name='text-davinci-003',
temperature=0,
max_tokens = 256)
#定義記憶力組件
memory = ConversationBufferMemory()
#定義chain
conversation = ConversationChain(
llm=llm,
verbose=True,
memory=memory
)
這里我們首先定義了一個(gè)openai的語言模型llm, 一個(gè)記憶力組件ConversationBufferMemory,和一個(gè)chain, Chain是Langchain中的核心組件,llm必須和Chain結(jié)合在一起才能正常工作。接下來就開始我們和openai語言模型的聊天:
print(conversation.predict(input='你好,我是王老六'))
?這里我們看到在內(nèi)存中存放了兩部分信息,首先是一個(gè)前綴信息:The following is ....,然后是機(jī)器人和用戶之間的聊天內(nèi)容。這里的前綴信息有助于讓機(jī)器人明確自己的角色定義,從而限制機(jī)器人不能隨心所欲的回答用戶提出的問題。
print(conversation.predict(input='你叫什么名字啊?'))
print(conversation.predict(input="那就叫你大聰明吧,怎么樣?"))
?
print(conversation.predict(input="你還記得我叫什么名字嗎?"))
?
這里我們注意到我們和機(jī)器人之間的多輪的對(duì)話內(nèi)容全部被自動(dòng)保存在了內(nèi)存中。這樣機(jī)器人就有了記憶力,它能記住我之前說過的話。
?2. ConversationBufferWindowMemory
ConversationBufferWindowMemory組件與之前的ConversationBufferMemory組件的差別是它增加了一個(gè)窗口參數(shù),它的作用是可以指定保存多輪對(duì)話的數(shù)量:
#定義openai的語言模型
llm = OpenAI(model_name='text-davinci-003',
temperature=0,
max_tokens = 256)
#定義內(nèi)存組件,k=2表示只保存最近的兩輪對(duì)話內(nèi)容
window_memory = ConversationBufferWindowMemory(k=2)
#定義chain
conversation = ConversationChain(
llm=llm,
verbose=True,
memory=window_memory
)
這里ConversationBufferWindowMemory的參數(shù)k=2表示在內(nèi)存中只保存最近的2輪對(duì)話內(nèi)容,因此更早的對(duì)話內(nèi)容將被拋棄掉。
print(conversation.predict(input='你好,我是王老六'))
print(conversation.predict(input='你叫什么名字?。?))
?
print(conversation.predict(input='那就叫你大聰明吧,怎么樣?'))
?
print(conversation.predict(input='你還記得我叫什么嗎?'))
?
?這里我們觀察到,在內(nèi)存中只保留了Human-AI,Human-AI兩輪對(duì)話內(nèi)容再加當(dāng)前用戶提出的問題。更早之前的Human-AI的對(duì)話內(nèi)容會(huì)被拋棄掉,所以最后機(jī)器人不記得我叫什么名字了。
3. ConversationSummaryMemory
與ConversationBufferMemory不同,ConversationSummaryMemory它不會(huì)將用戶和機(jī)器人之前的所有對(duì)話都存儲(chǔ)在內(nèi)存中。它只會(huì)存儲(chǔ)一個(gè)用戶和機(jī)器人之間的聊天內(nèi)容的摘要,這樣做的目的可能是為了節(jié)省內(nèi)存開銷和token的數(shù)量,因?yàn)橄駉penai這樣的語言模型是按token數(shù)量來收費(fèi)的,所以能省則省。
#定義openai的語言模型
llm = OpenAI(model_name='text-davinci-003',
temperature=0,
max_tokens = 256)
#定義內(nèi)存組件
summary_memory = ConversationSummaryMemory(llm=OpenAI())
#定義Chain
conversation = ConversationChain(
llm=llm,
verbose=True,
memory=summary_memory
)
這里我們將內(nèi)存組件換成了ConversationSummaryMemory,它會(huì)在內(nèi)存中產(chǎn)生聊天內(nèi)容的摘要信息。
print(conversation.predict(input='你好,我是王老六'))
?
print(conversation.predict(input='你叫什么名字???'))
?這里我們看到在內(nèi)存中會(huì)保留前綴信息,之前多輪對(duì)話的摘要信息,以及用戶當(dāng)前提出的問題這三部分內(nèi)容。
print(conversation.predict(input='那就叫你大聰明吧,怎么樣?'))
?
print(conversation.predict(input='你還記得我叫什么嗎?'))
4.?ConversationSummaryBufferMemory
ConversationSummaryBufferMemory結(jié)合了前面的ConversationBufferWindowMemory,ConversationSummaryMemory兩種工作方式,即在內(nèi)存中保留一部分聊天內(nèi)容的摘要,和一部分的多輪聊天內(nèi)容,但是要在內(nèi)存中保留多少輪聊天內(nèi)容,這取決于參數(shù)max_token_limit,如果將max_token_limit設(shè)置為較小的值時(shí),那么大部分之前的聊天內(nèi)容都被轉(zhuǎn)換成了摘要,少部分的聊天內(nèi)容被保存下來,相反當(dāng)max_token_limit設(shè)置為較大的值時(shí),小部分的之前聊天內(nèi)容被轉(zhuǎn)換成摘要,而大部分聊天內(nèi)容被保留下來。
from langchain.chains.conversation.memory import ConversationSummaryBufferMemory
from langchain import OpenAI
from langchain.chains import ConversationChain
import os
os.environ['OPENAI_API_KEY'] = 'xxxxx'
llm = OpenAI(model_name='text-davinci-003',
temperature=0,
max_tokens = 256)
memory = ConversationSummaryBufferMemory(llm=OpenAI(), max_token_limit=256)
conversation = ConversationChain(
llm=llm,
memory=memory,
verbose=True
)
這里我們將max_token_limit設(shè)置為256,表示當(dāng)我們多輪聊天內(nèi)容的prompt長(zhǎng)度超過256時(shí),較早的聊天內(nèi)容將會(huì)被轉(zhuǎn)換成摘要,同時(shí)小于256個(gè)token的聊天內(nèi)容會(huì)被保留下來。
print(conversation.predict(input='你好,我是王老六'))
print(conversation.predict(input='你叫什么名字?。?))
?
print(conversation.predict(input='我給你取個(gè)名字叫大聰明吧,怎么樣?'))
print(conversation.predict(input='你還記得我叫什么嗎?'))
print(conversation.predict(input='你還記得我給你起的名字嗎?'))
print(conversation.predict(input='我生病了,肚子疼,還嘔吐發(fā)燒,你說我是自己吃點(diǎn)藥對(duì)付一下呢還是去醫(yī)院看一下比較好?'))
?從上述多倫聊天內(nèi)容中我們可以發(fā)現(xiàn),隨著聊天輪次的增加,內(nèi)存中的摘要信息量也在增加,而內(nèi)存中的多輪聊天內(nèi)容的長(zhǎng)度被限制在256個(gè)token,當(dāng)有新的聊天內(nèi)容進(jìn)到內(nèi)存中后,較早的聊天內(nèi)容將會(huì)被轉(zhuǎn)換成摘要從而被踢出內(nèi)存中的多倫聊天記錄。
5.ConversationKGMemory
我們知道像ChatGPT這樣的LLM最大的問題是會(huì)“產(chǎn)生幻覺(hallucinate)”,也就是當(dāng)llm不知道正確答案的情況下,往往會(huì)天馬行空自由發(fā)揮從而導(dǎo)致llm給出了完全不正確的答案,為了避免llm產(chǎn)生幻覺,Langchain提供了ConversationKGMemory組件即“對(duì)話知識(shí)圖譜記憶”組件,該組件可以從和用戶的對(duì)話中提取出知識(shí)圖譜信息,即一些核心的關(guān)鍵信息,這些信息比之前的ConversationSummaryMemory組件所保存的信息更為精簡(jiǎn)。llm將會(huì)嚴(yán)格依據(jù)知識(shí)圖譜的中的相關(guān)內(nèi)容來回答用戶的問題,從而避免產(chǎn)生幻覺。
from langchain import OpenAI
from langchain.prompts.prompt import PromptTemplate
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationKGMemory
llm = OpenAI(temperature=0)
template = """下面是一段人與AI的友好對(duì)話。 人工智能很健談,并根據(jù)其上下文提供了許多具體細(xì)節(jié)。
如果 AI 不知道問題的答案,它會(huì)如實(shí)說它不知道。 AI 僅使用“相關(guān)信息”部分中包含的信息,不會(huì)產(chǎn)生幻覺。
相關(guān)信息:
{history}
對(duì)話內(nèi)容:
Human: {input}
AI:"""
prompt = PromptTemplate(
input_variables=["history", "input"], template=template
)
conversation_with_kg = ConversationChain(
llm=llm,
verbose=True,
prompt=prompt,
memory=ConversationKGMemory(llm=llm)
)
這里我們創(chuàng)建了一個(gè)prompt模板,模板中有三部分信息:前綴信息, 相關(guān)信息,對(duì)話內(nèi)容。前綴信息之前已經(jīng)介紹過,這里不再說明,相關(guān)信息指的是從之前的多輪對(duì)話中提取出來的知識(shí)圖譜信息,即精簡(jiǎn)的核心關(guān)鍵信息,對(duì)話內(nèi)容則只保留用戶當(dāng)前所提出的問題。
conversation_with_kg.predict(input="你好")
conversation_with_kg.predict(input="我叫大神,我有一位朋友叫小明,他是一位寵物醫(yī)院的醫(yī)生。")
?
conversation_with_kg.predict(input="小明是做什么的?")
?
conversation_with_kg.predict(input="小明的爸爸也是一位寵物醫(yī)生")
conversation_with_kg.predict(input="不過你小明的媽媽是位老師")
conversation_with_kg.predict(input="小明的哥哥是個(gè)老板")
conversation_with_kg.predict(input="小明的媽媽是做什么的?")
6.Entity?Memory
在自然語言處理(NLP)技術(shù)中一項(xiàng)基本的功能就是:命名實(shí)體識(shí)別(Named Entity Recognition,簡(jiǎn)稱NER)又稱作專名識(shí)別、命名實(shí)體,是指識(shí)別文本中具有特定意義的實(shí)體,主要包括人名、地名、機(jī)構(gòu)名、專有名詞等,以及時(shí)間、數(shù)量、貨幣、比例數(shù)值等文字。Langchain提供的實(shí)體記憶(Entity?Memory)組件能自動(dòng)提取AI與人類交互過程中的實(shí)體信息,并將其以字典的形式保存在內(nèi)存中。實(shí)體的正確識(shí)別能幫助AI能更準(zhǔn)確的回答人類提出的關(guān)于實(shí)體的相關(guān)問題。下面我們來看一個(gè)例子:
from langchain import OpenAI, ConversationChain
from langchain.chains.conversation.memory import ConversationEntityMemory
from langchain.chains.conversation.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE
from pydantic import BaseModel
from typing import List, Dict, Any
這里我們會(huì)使用一個(gè)ENTITY_MEMORY_CONVERSATION_TEMPLATE的模板,該模板為內(nèi)存記憶的固定格式,下面我們看一下該模板的主要內(nèi)容:
## The propmpt
print(ENTITY_MEMORY_CONVERSATION_TEMPLATE.template)
?我們將其翻譯成中文:
?該模板基本上也是由3部分組成:前綴信息, 上下文,歷史聊天信息,其中,“上下文”中記錄的是歷史聊天信息中提取出來的實(shí)體信息。
conversation.predict(input="你好,我家的小狗生病了怎么辦?")
?
conversation.predict(input="我突然想起來我有一個(gè)朋友叫小明,他是一位寵物醫(yī)生。")
conversation.predict(input="可我聽說他只會(huì)給小貓看病,不會(huì)給小狗看病,怎么辦?")
conversation.predict(input="我還是去找小王吧,他是一個(gè)更專業(yè)的獸醫(yī)。")
?
conversation.predict(input="請(qǐng)問小明會(huì)給小狗看病嗎?")
?通過上述簡(jiǎn)單的幾輪對(duì)話,我們看到聊天記錄中的實(shí)體信息被提取出來,并且AI能夠根據(jù)實(shí)體信息來準(zhǔn)確回答我的問題。下面我們看一下實(shí)體信息中的完整內(nèi)容:
from pprint import pprint
pprint(conversation.memory.entity_store.store)
?總結(jié)
今天我們學(xué)習(xí)了Langchain提供的6種記憶力組件它們分別是:
- ConversationBufferMemory
- ConversationBufferWindowMemory
- ConversationSummaryMemory
- ConversationSummaryBufferMemory
- ConversationKGMemory
- Entity?Memory
它們有著各自不能的功能和特點(diǎn),根據(jù)不同的應(yīng)用場(chǎng)景我們可以選擇不同的記憶力組件,當(dāng)我們開發(fā)一個(gè)與AI交互的應(yīng)用程序時(shí)選擇正確的記憶力組件能夠成倍的提高AI的工作效率,同時(shí)讓AI在回答人類的問題時(shí)更加準(zhǔn)確,自然,而不會(huì)產(chǎn)生幻覺。文章來源:http://www.zghlxwxcb.cn/news/detail-422391.html
參考資料
LangChain官方文檔文章來源地址http://www.zghlxwxcb.cn/news/detail-422391.html
到了這里,關(guān)于LangChain與大型語言模型(LLMs)應(yīng)用基礎(chǔ)教程:記憶力組件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!