此情可待成追憶,只是當(dāng)時已惘然。我們?nèi)祟悤泻芏嗷蛎篮没蛲纯嗟幕貞?,有的回憶會漸漸模糊,有的回憶午夜夢醒,會浮上心頭。
然而現(xiàn)在的大語言模型都是沒有記憶的,都是無狀態(tài)的,大語言模型自身不會記住和你對話之間的歷史消息。根本用不著“時時勤拂拭”,天然就是“本來無一物”。每一次的請求交互、api調(diào)用都是獨立的,完全沒有關(guān)聯(lián)。那些聊天機器人看起來有記憶,是因為借助代碼的幫助,提供歷史消息作為和LLM對話的上下文。嗯,就跟我們大腦不太夠用了,要拿小本本或者打開Obsidian/Notion/語雀……來查找一樣。(你去拜訪某些單位,還可以看到前臺拿著一本已經(jīng)翻到包漿的小本子來查電話。)
所以,現(xiàn)在的大語言模型,就跟福爾摩斯一樣,可能作為推理引擎更加好用:只要提供足夠的上下文信息,那么即使坐在家中,也比愚蠢的蘇格蘭警探更清楚案情。(可以考慮打造一個叫“夏洛克”的大語言模型? )運籌帷幄之中,決勝千里之外。
本節(jié)我們就來看一下LangChain提供的4種Memory(記憶)組件(Vector data memory和Entity memory不展開),每種組件都有其適用場景。
主要的記憶組件
- ConversationBufferMemory
這個記憶組件允許儲存對話的消息,并且可以把消息抽取到一個變量。
- ConversationBufferWindowMemory
這個記憶會保持K輪對話的列表。只保存最近的K輪對話。舊對話會清除。
- ConversationTokenBufferMemory
這個記憶組件跟ConversationBufferWindowMemory差不多,同樣把舊對話清除,只是是按Token的長度限制。
- ConversationSummaryMemory
這個記憶組件會調(diào)用大語言模型,對舊的會話進行總結(jié)。
- Vector data memory
這個組件把文本(來自會話或者其他地方的)保存到向量數(shù)據(jù)庫,檢索最相關(guān)的文本塊。
- Entity memories
調(diào)用LLM,記住關(guān)于特定實體的細節(jié)信息。
可以同時使用多個記憶組件,如調(diào)用會話記憶+實體記憶來檢索個人信息。還可以將會話內(nèi)容保存到傳統(tǒng)數(shù)據(jù)庫(如鍵值存儲Redis或者關(guān)系數(shù)據(jù)庫mysql等等),應(yīng)用要落地這個是必不可少的。
下面來具體看每個組件的例子。
同樣是先通過.env文件初始化環(huán)境,具體操作參考上一篇。
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
import warnings
warnings.filterwarnings('ignore')
deployment = "gpt-35-turbo"
model = "gpt-3.5-turbo"
ConversationBufferMemory
# from langchain.chat_models import ChatOpenAI
from langchain.chat_models import AzureChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
llm = AzureChatOpenAI(temperature=0.0, model_name=model, deployment_name=deployment)
memory = ConversationBufferMemory()
conversation = ConversationChain(
llm=llm,
memory = memory,
verbose=True #設(shè)置為True,可以看到對話的詳細過程
)
conversation.predict(input="你好,我是西濱。")
conversation.predict(input="1+1等于多少?")
conversation.predict(input="你還記得我的名字?")
這里會創(chuàng)建ConversationChain,Chain是LangChain的核心概念,后面會詳細講述,這里先不管。memory = ConversationBufferMemory() 創(chuàng)建一個ConversationBufferMemory傳給ConversationChain,我們打開verbose,看一下具體的輸出。
一開始LangChain自動發(fā)送一段提示(***The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.)***過去開始對話,后面我們可以看到,每次對話的信息都會自動發(fā)過去,經(jīng)過一輪對話之后,再問Ai“你還記得我的名字?”,Ai毫不猶豫的回答:“當(dāng)然記得!你是西濱。”
上面我們用memory這個變量來保存記憶,如果輸出memory.buffer,可以看到對話的所有消息:
Human: 你好,我是西濱。
AI: 你好,西濱!很高興認識你。我是一個AI助手,可以回答你的問題和提供幫助。有什么我可以幫你的嗎?
Human: 1+1等于多少?
AI: 1+1等于2。
Human: 你還記得我的名字?
AI: 當(dāng)然記得!你是西濱。
可以手工調(diào)用save_context方法來把上下文信息傳進去:
memory = ConversationBufferMemory()
memory.save_context({"input": "Hi"},
{"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
{"output": "Cool"})
memory.load_memory_variables({})
調(diào)用load_memory_variables({})來查看對應(yīng)的記憶內(nèi)容。(load_memory_variables中的花括號{}是一個空詞典,可以在這里傳遞額外的參數(shù)進行高級定制)
ConversationBufferMemory可以存儲到目前為止的對話消息,看起來很完美,但是隨著對話越來越長,所需的記憶存儲量也變得非常大,而向LLM發(fā)送大量Token的成本也會增加(現(xiàn)在大模型一般按照Token的數(shù)量收費,而且還是雙向收費,你懂的)。
解決這個問題,LangChain有三個不同的記憶組件來處理。
ConversationBufferWindowMemory
ConversationBufferWindowMemory 只保留一個窗口的記憶,也就是只保留最后若干輪對話消息。注意,這個跟微軟的Bing Chat不太一樣,微軟是每個話題保留30輪,30輪對話一到,自動轉(zhuǎn)向新話題;ConversationBufferWindowMemory的策略就是計算機算法典型的“滑動窗口”,永遠都是保留最新的若干輪對話。
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "Hi"},
{"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
{"output": "Cool"})
memory.load_memory_variables({})
上面的k設(shè)為了1,那只保留最后1輪對話,對話信息就只剩下:
{'history': 'Human: Not much, just hanging\nAI: Cool'}
前面的”Human:Hi?\nAI: What’s up“ 已經(jīng)去掉了。
實際應(yīng)用,我們會更多的采用ConversationBufferWindowMemory(K通常會設(shè)得比較大,需要根據(jù)具體情景調(diào)整),而不是ConversationBufferMemory,可以防止記憶存儲量隨著對話的進行而無限增長,同時也有比較好的效果。。
ConversationTokenBufferMemory
ConversationTokenBufferMemory通過另一種方式來解決記憶存儲量增長的問題:限制保存在記憶的令牌數(shù)量。
要先安裝tiktoken,底層用于計算Token數(shù)目:
!pip install tiktoken
from langchain.memory import ConversationTokenBufferMemory
llm = AzureChatOpenAI(temperature=0.0, model_name=model, deployment_name=deployment)
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)
memory.save_context({"input": "AI is what?!"},
{"output": "Amazing!"})
memory.save_context({"input": "Backpropagation is what?"},
{"output": "Beautiful!"})
memory.save_context({"input": "Chatbots are what?"},
{"output": "Charming!"})
memory.load_memory_variables({})
注意上面token的限制設(shè)為了30,則最終保留下來的消息只有這些,保證總的消息內(nèi)容長度不超過設(shè)置的令牌限制值max_token_limit。(這里涉及到計算Token的算法,不能按字符數(shù)計算。每種LLM計算Token的算法都不一樣,所以調(diào)用ConversationTokenBufferMemory要把llm傳進去。):
顯然,沒有保留最近兩輪完整的對話消息,所以這個組件的效果可能沒有ConversationBufferWindowMemory好,但是調(diào)用Api的性價比高一點。
ConversationSummaryMemory
ConversationSummaryMemory可以算是ConversationTokenBufferMemory的變體,同樣是按令牌數(shù)限制,但是當(dāng)它發(fā)現(xiàn)令牌數(shù)超了,不是把舊的消息丟掉,而是把當(dāng)前所有的消息進行摘要,直到摘要的文本令牌數(shù)不超過設(shè)置的限制。
from langchain.memory import ConversationSummaryBufferMemory
# create a long string
schedule = """There is a meeting at 8am with your product team.
You will need your powerpoint presentation prepared.
9am-12pm have time to work on your LangChain
project which will go quickly because Langchain is such a powerful tool.
At Noon, lunch at the italian resturant with a customer who is driving
from over an hour away to meet you to understand the latest in AI.
Be sure to bring your laptop to show the latest LLM demo."""
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=400)
memory.save_context({"input": "Hello"}, {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
{"output": "Cool"})
memory.save_context({"input": "What is on the schedule today?"},
{"output": f"{schedule}"})
memory.load_memory_variables({})
如果max_token_limit設(shè)置為400,因為400個令牌足以存儲所有的文本,可以看到ConversationSummaryMemory沒有做任何的動作,把所有的消息都原樣保存:
但是如果把max_token_limit設(shè)置為100,ConversationSummaryMemory會調(diào)用LLM,把消息保存為下面的摘要:
{'history': 'System: The human and AI exchange greetings. The human mentions that they are not doing much and the AI responds with a casual remark. The human then asks about their schedule for the day. The AI provides a detailed schedule, including a meeting with the product team, working on the LangChain project, and a lunch meeting with a customer interested in AI. The AI emphasizes the importance of bringing a laptop to showcase the latest LLM demo during the lunch meeting.'}
如果是問沒那么精確的問題,LLM仍然可以回答:
conversation = ConversationChain(
llm=llm,
memory = memory,
verbose=False
)
conversation.predict(input="What would be a good demo to show?")
'A good demo to show would be the latest Language Learning Model (LLM) demo. It showcases real-time translations, pronunciation feedback, grammar suggestions, interactive exercises, and quizzes. These features make it an ideal way to highlight the capabilities of our AI technology in the education and language learning industry.’
但是再問具體的信息,由于摘要已經(jīng)丟失了詳細信息,所以LLM開始胡說八道。
conversation.predict(**input="When will the meeting hold today?"**)
'The meeting with the product team is scheduled for 10:00 AM today.’
展望
雖然LangChain提供了不同的記憶組件,但是真正用起來還是有點麻煩,好消息是根據(jù)路透社報道,11月6日在OpenAI的開發(fā)者大會上,ChatGPT將推出帶有記憶能力的大模型,也就是有狀態(tài)的API接口。[3]
和大模型一次對話的內(nèi)容量稱之為Context,是一個很重要的指標。Context越大,意味著你可以和大模型對話的次數(shù)越多,傳遞的信息越多,那么大模型反饋給你的結(jié)果才會更加準確。如果Context不夠大,那么你只能拋棄一些信息,自然拿到的結(jié)果就會產(chǎn)生偏差。
現(xiàn)在GPT-4默認的Context是8K,如果要支持32K的Context,則價格直接翻倍。Claude大模型支持的Context更大,可以支持100K的Context,所以Claude對于很多PDF文檔閱讀支持得很好。還有國產(chǎn)的Kimi Chat,據(jù)說支持約 20 萬漢字的上下文,2.5 倍于 Anthropic 公司的 Claude-100k(實測約 8 萬字),8 倍于 OpenAI 公司的 GPT-4-32k(實測約 2.5 萬字)??梢哉fContext容量大小,也是大模型的核心競爭力之一。
但這一切即將成為過去,GPT即將支持記憶能力。也就是GPT會通過緩存的方式記錄之前和用戶的對話。你不需要那么大的Context容量了,多次對話的性能和單次對話都是一樣的。而且在大模型端,通過緩存的方式,可以極大降低應(yīng)用的開銷,讓成本直接節(jié)省到二十分之一。文章來源:http://www.zghlxwxcb.cn/news/detail-711412.html
期待……文章來源地址http://www.zghlxwxcb.cn/news/detail-711412.html
參考
- 短課程:https://learn.deeplearning.ai/langchain/lesson/3/memory
- 文檔:https://python.langchain.com/docs/modules/memory/
- Report: OpenAI to Introduce Updates to Make AI Models More Affordable: https://www.pymnts.com/news/artificial-intelligence/2023/openai-introduce-updates-make-ai-models-more-affordable/
到了這里,關(guān)于基于LangChain的LLM應(yīng)用開發(fā)3——記憶的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!