自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

LangChain 讓 LLM 帶上記憶

人工智能
本文介紹了 LLM 缺乏記憶功能的固有缺陷,以及記憶組件的原理,還討論了如何利用 LangChain 給 LLM 裝上記憶組件,讓 LLM 能夠在對話中更好地保持上下文。

最近兩年,我們見識(shí)了“百模大戰(zhàn)”,領(lǐng)略到了大型語言模型(LLM)的風(fēng)采,但它們也存在一個(gè)顯著的缺陷:沒有記憶。

在對話中,無法記住上下文的 LLM 常常會(huì)讓用戶感到困擾。本文探討如何利用 LangChain,快速為 LLM 添加記憶能力,提升對話體驗(yàn)。

LangChain 是 LLM 應(yīng)用開發(fā)領(lǐng)域的最大社區(qū)和最重要的框架。

一、LLM 固有缺陷,沒有記憶

當(dāng)前的 LLM 非常智能,在理解和生成自然語言方面表現(xiàn)優(yōu)異,但是有一個(gè)顯著的缺陷:沒有記憶。

LLM 的本質(zhì)是基于統(tǒng)計(jì)和概率來生成文本,對于每次請求,它們都將上下文視為獨(dú)立事件。這意味著當(dāng)你與 LLM 進(jìn)行對話時(shí),它不會(huì)記住你之前說過的話,這就導(dǎo)致了 LLM 有時(shí)表現(xiàn)得不夠智能。

這種“無記憶”屬性使得 LLM 無法在長期對話中有效跟蹤上下文,也無法積累歷史信息。比如,當(dāng)你在聊天過程中提到一個(gè)人名,后續(xù)再次提及該人時(shí),LLM 可能會(huì)忘記你之前的描述。

本著發(fā)現(xiàn)問題解決問題的原則,既然沒有記憶,那就給 LLM 裝上記憶吧。

二、記憶組件的原理

1.沒有記憶的煩惱

當(dāng)我們與 LLM 聊天時(shí),它們無法記住上下文信息,比如下圖的示例:

2.原理

如果將已有信息放入到 memory 中,每次跟 LLM 對話時(shí),把已有的信息丟給 LLM,那么 LLM 就能夠正確回答,見如下示例:

目前業(yè)內(nèi)解決 LLM 記憶問題就是采用了類似上圖的方案,即:將每次的對話記錄再次丟入到 Prompt 里,這樣 LLM 每次對話時(shí),就擁有了之前的歷史對話信息。

但如果每次對話,都需要自己手動(dòng)將本次對話信息繼續(xù)加入到history信息中,那未免太繁瑣。有沒有輕松一些的方式呢?有,LangChain!LangChain 對記憶組件做了高度封裝,開箱即用。

3.長期記憶和短期記憶

在解決 LLM 的記憶問題時(shí),有兩種記憶方案,長期記憶和短期記憶。

  • 短期記憶:基于內(nèi)存的存儲(chǔ),容量有限,用于存儲(chǔ)臨時(shí)對話內(nèi)容。
  • 長期記憶:基于硬盤或者外部數(shù)據(jù)庫等方式,容量較大,用于存儲(chǔ)需要持久的信息。

三、LangChain 讓 LLM 記住上下文

LangChain 提供了靈活的內(nèi)存組件工具來幫助開發(fā)者為 LLM 添加記憶能力。

1.單獨(dú)用 ConversationBufferMemory 做短期記憶

Langchain 提供了 ConversationBufferMemory 類,可以用來存儲(chǔ)和管理對話。

ConversationBufferMemory 包含input變量和output變量,input代表人類輸入,output代表 AI 輸出。

每次往ConversationBufferMemory組件里存入對話信息時(shí),都會(huì)存儲(chǔ)到history的變量里。

2.利用 MessagesPlaceholder 手動(dòng)添加 history

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(return_messages=True)
memory.load_memory_variables({})

memory.save_context({"input": "我的名字叫張三"}, {"output": "你好,張三"})
memory.load_memory_variables({})

memory.save_context({"input": "我是一名 IT 程序員"}, {"output": "好的,我知道了"})
memory.load_memory_variables({})

from langchain.prompts import ChatPromptTemplate
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一個(gè)樂于助人的助手。"),
        MessagesPlaceholder(variable_name="history"),
        ("human", "{user_input}"),
    ]
)
chain = prompt | model

user_input = "你知道我的名字嗎?"
history = memory.load_memory_variables({})["history"]


chain.invoke({"user_input": user_input, "history": history})

user_input = "中國最高的山是什么山?"
res = chain.invoke({"user_input": user_input, "history": history})
memory.save_context({"input": user_input}, {"output": res.content})


res = chain.invoke({"user_input": "我們聊得最后一個(gè)問題是什么?", "history": history})

執(zhí)行結(jié)果如下:

3.利用 ConversationChain 自動(dòng)添加 history

我們利用 LangChain 的ConversationChain對話鏈,自動(dòng)添加history的方式添加臨時(shí)記憶,無需手動(dòng)添加。一個(gè)鏈實(shí)際上就是將一部分繁瑣的小功能做了高度封裝,這樣多個(gè)鏈就可以組合形成易用的強(qiáng)大功能。這里鏈的優(yōu)勢一下子就體現(xiàn)出來了:

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

memory = ConversationBufferMemory(return_messages=True)
chain = ConversationChain(llm=model, memory=memory)
res = chain.invoke({"input": "你好,我的名字是張三,我是一名程序員。"})
res['response']

res = chain.invoke({"input":"南京是哪個(gè)?。?})
res['response']

res = chain.invoke({"input":"我告訴過你我的名字,是什么?,我的職業(yè)是什么?"})
res['response']

執(zhí)行結(jié)果如下,可以看到利用ConversationChain對話鏈,可以讓 LLM 快速擁有記憶:

4. 對話鏈結(jié)合 PromptTemplate 和 MessagesPlaceholder

在 Langchain 中,MessagesPlaceholder是一個(gè)占位符,用于在對話模板中動(dòng)態(tài)插入上下文信息。它可以幫助我們靈活地管理對話內(nèi)容,確保 LLM 能夠使用最上下文來生成響應(yīng)。

采用ConversationChain對話鏈結(jié)合PromptTemplate和MessagesPlaceholder,幾行代碼就可以輕松讓 LLM 擁有短時(shí)記憶。

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一個(gè)愛撒嬌的女助手,喜歡用可愛的語氣回答問題。"),
        MessagesPlaceholder(variable_name="history"),
        ("human", "{input}"),
    ]
)
memory = ConversationBufferMemory(return_messages=True)
chain = ConversationChain(llm=model, memory=memory, prompt=prompt)

res = chain.invoke({"input": "今天你好,我的名字是張三,我是你的老板"})
res['response']

res = chain.invoke({"input": "幫我安排一場今天晚上的高規(guī)格的晚飯"})
res['response']

res = chain.invoke({"input": "你還記得我叫什么名字嗎?"})
res['response']

四、使用長期記憶

短期記憶在會(huì)話關(guān)閉或者服務(wù)器重啟后,就會(huì)丟失。如果想長期記住對話信息,只能采用長期記憶組件。

LangChain 支持多種長期記憶組件,比如Elasticsearch、MongoDB、Redis等,下面以Redis為例,演示如何使用長期記憶。

from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="gpt-3.5-turbo",
    openai_api_key="sk-xxxxxxxxxxxxxxxxxxx",
    openai_api_base="https://api.aigc369.com/v1",
)

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一個(gè)擅長{ability}的助手"),
        MessagesPlaceholder(variable_name="history"),
        ("human", "{question}"),
    ]
)

chain = prompt | model

chain_with_history = RunnableWithMessageHistory(
    chain,
    # 使用redis存儲(chǔ)聊天記錄
    lambda session_id: RedisChatMessageHistory(
        session_id, url="redis://10.20.1.10:6379/3"
    ),
    input_messages_key="question",
    history_messages_key="history",
)

# 每次調(diào)用都會(huì)保存聊天記錄,需要有對應(yīng)的session_id
chain_with_history.invoke(
    {"ability": "物理", "question": "地球到月球的距離是多少?"},
    config={"configurable": {"session_id": "baily_question"}},
)

chain_with_history.invoke(
    {"ability": "物理", "question": "地球到太陽的距離是多少?"},
    config={"configurable": {"session_id": "baily_question"}},
)

chain_with_history.invoke(
    {"ability": "物理", "question": "地球到他倆之間誰更近"},
    config={"configurable": {"session_id": "baily_question"}},
)

LLM 的回答如下,同時(shí)關(guān)閉 session 后,直接再次提問最后一個(gè)問題,LLM 仍然能給出正確答案。

只要configurable配置的session_id能對應(yīng)上,LLM 就能給出正確答案。

然后,繼續(xù)查看redis存儲(chǔ)的數(shù)據(jù),可以看到數(shù)據(jù)在 redis 中是以 list的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)的。

五、總結(jié)

本文介紹了 LLM 缺乏記憶功能的固有缺陷,以及記憶組件的原理,還討論了如何利用 LangChain 給 LLM 裝上記憶組件,讓 LLM 能夠在對話中更好地保持上下文。希望對你有幫助!

責(zé)任編輯:趙寧寧 來源: 程序員半支煙
相關(guān)推薦

2024-07-12 14:53:42

2024-07-03 09:38:35

LLM人工智能

2024-03-07 09:15:57

2024-06-25 15:35:53

LangChain轉(zhuǎn)換鏈

2024-06-19 08:14:51

大型語言模型LLMRAG

2023-09-28 08:41:11

OpenAILLMLangChain

2023-08-03 09:02:32

LangChain開發(fā)GLM

2024-05-14 09:57:10

人工智能QuarkusLLM

2024-06-03 07:45:00

2023-06-29 08:00:00

人工智能LLMGPT-4

2023-12-13 13:36:40

模型算力

2011-10-08 16:06:52

打印機(jī)推薦

2024-07-01 08:55:00

2023-08-07 18:55:19

2024-01-05 07:41:34

OpenLLM大語言模型LLM

2023-09-20 08:00:00

大語言模型代碼庫

2023-06-02 07:37:12

LLM?大語言模型

2024-05-20 02:00:00

LangChain人工智能

2024-11-21 15:56:37

2024-05-20 08:31:33

檢索增強(qiáng)生成LLM大型語言模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號