LangChain 提供的記憶機制能有效提升對話式 AI 的效能,讓系統理解並回應連續提問,而非僅處理單獨的問答。文章以虛擬客服代理 Eva 為例,展示短期記憶如何使對話更自然流暢,並探討 LangChain 的記憶操作核心:讀取和儲存。文章詳細介紹了使用 MongoDB 儲存聊天記錄、使用 ConversationBufferMemory 進行記憶管理,以及如何在 LangChain Expression Language (LCEL) 中直接新增記憶到鏈,並提供程式碼範例。同時,文章也涵蓋了 LangChain 中各種記憶體型別,如 ConversationBufferWindowMemory、ConversationSummaryMemory、ConversationSummaryBufferMemory 和 ConversationTokenBufferMemory,比較它們的特性和適用場景,讓開發者能根據需求選擇合適的記憶體管理策略。
短期記憶在問答系統中的應用
在開發對話式人工智慧系統時,短期記憶(Short-Term Memory, STM)的應用能夠顯著提升系統的互動性和連貫性。想像一個名為Eva的虛擬客服代理,她能夠在與使用者的對話中,利用短期記憶來理解和回應連續的問題。
案例分析:Eva的對話流程
使用者查詢:使用者詢問電子產品的退貨政策。
- 使用者: “電子產品的退貨政策是多久?”
- Eva: “電子產品的退貨政策是30天。”
後續查詢:使用者接著詢問服裝類別商品的退貨政策。
- 使用者: “那服裝類別商品呢?”
- Eva(利用STM): “服裝類別商品的退貨政策是45天。您還想了解其他類別嗎?”
在這個例子中,Eva透過運用短期記憶,能夠無縫地繼續對話,預測使用者可能提出的後續問題。這種流暢性得益於短期記憶的有效佈署,使對話式代理能夠將對話視為一個連貫的互動過程,而非孤立的問答。
LangChain中的記憶機制
LangChain提供了簡便的方法來為大語言模型(LLMs)新增記憶功能。如圖所示,每個記憶系統在鏈中負責兩個基本操作:讀取和儲存。
記憶操作的核心
讀取記憶:在收集初始使用者資料後,但在執行之前,鏈會從其記憶中檢索資訊,並將其新增到使用者的輸入中。
儲存資訊:在鏈完成處理後,但在傳回答案之前,鏈會將當前執行的輸入和輸出寫入記憶,以便在未來的執行中參考。
建立記憶系統的關鍵選擇
狀態儲存方法:選擇適合的資料函式庫或儲存方案來儲存對話狀態。
查詢記憶狀態的方法:根據應用需求,設計查詢記憶內容的方式。
狀態儲存
生成式AI模型的基礎記憶本質上是結構化的聊天訊息序列。這些訊息可以儲存在臨時的記憶體列表中,或固定在更持久的資料函式庫中。對於長期儲存的需求,可以利用多種資料函式庫整合方案,以簡化流程,避免手動整合的麻煩。
使用MongoDB儲存聊天記錄
# 提供連線到MongoDB資料函式庫的連線字串
connection_string = "mongodb://mongo_user:password123@mongo:27017"
chat_message_history = MongoDBChatMessageHistory(
session_id="test_session",
connection_string=connection_string,
database_name="my_db",
collection_name="chat_histories",
)
# 新增使用者和AI的訊息
chat_message_history.add_user_message("我喜歡程式設計!")
chat_message_history.add_ai_message("你喜歡程式設計的哪個方面?")
# 檢視聊天記錄
print(chat_message_history.messages)
# [HumanMessage(content='我喜歡程式設計!'), AIMessage(content='你喜歡程式設計的哪個方面?')]
查詢狀態
不同的應用對記憶查詢有不同的需求。LangChain的記憶工具箱允許開發者建立簡單的記憶基礎設施,同時也能架構出自定義的系統,以滿足特定的需求。
ConversationBufferMemory的使用
from langchain.memory import ConversationBufferMemory
# 初始化ConversationBufferMemory
memory = ConversationBufferMemory()
# 儲存對話上下文
memory.save_context({"input": "你好"}, {"output": "最近怎麼樣"})
# 載入記憶變數
print(memory.load_memory_variables({}))
# {'history': 'Human: 你好\nAI: 最近怎麼樣'}
# 傳回LangChain架構的訊息
memory = ConversationBufferMemory(return_messages=True)
memory.save_context({"input": "你好"}, {"output": "最近怎麼樣"})
print(memory.load_memory_variables({}))
# {'history': [HumanMessage(content='你好'), AIMessage(content='最近怎麼樣')]}
在LCEL中直接新增記憶到鏈
from langchain.memory import ConversationBufferMemory
from langchain_openai.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableLambda
from operator import itemgetter
# 初始化記憶和模型
memory = ConversationBufferMemory(return_messages=True)
model = ChatOpenAI(temperature=0)
# 定義提示範本
prompt = ChatPromptTemplate.from_messages([
("system", "作為一個幫助使用者解決問題的聊天機器人。"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
# 構建鏈
chain = (
{
"input": lambda x: x["input"],
"history": RunnableLambda(memory.load_memory_variables) | itemgetter("history"),
}
| prompt
| model
| StrOutputParser()
)
# 呼叫鏈並儲存訊息到記憶變數
inputs = {"input": "嗨,我叫詹姆斯!"}
result = chain.invoke(inputs)
memory.save_context(inputs, {"output": result})
# 檢視記憶中的訊息
print(memory.load_memory_variables({}))
# {'history': [HumanMessage(content='嗨,我叫詹姆斯!'), AIMessage(content='你好,詹姆斯!今天我能怎麼幫你?')]}
測試鏈是否能夠使用之前的上下文回答新的問題
透過上述步驟,我們成功地在LangChain中實作了具有短期記憶功能的對話式AI系統。這種系統能夠根據之前的對話內容,提供更連貫和更具上下文相關性的回答,從而提升使用者經驗。
進一步最佳化與擴充套件
增強記憶管理:可以根據實際需求,選擇更適合的記憶儲存方案,如使用更高效的資料函式庫系統。
最佳化查詢機制:開發更智慧的查詢機制,以更精確地檢索相關資訊,提升系統回應的準確性。
擴充套件應用場景:將此技術應用於更多領域,如客戶服務、教育輔導等,以發揮其在不同場景下的價值。
#: 隨著AI技術的不斷發展,對話式AI系統將變得越來越智慧和人性化。結合短期記憶和其他先進技術,這些系統將能夠提供更加自然和流暢的互動體驗,進一步拓展其在各個領域的應用潛力。
圖表說明
此圖示展示了LangChain中記憶機制的運作流程,包括讀取和儲存兩個主要操作。這種架構使得對話式AI系統能夠有效地管理和利用對話歷史,從而提供更具上下文相關性的回應。
圖表翻譯: 此圖表呈現了LangChain內部的記憶機制,主要分為兩個部分:讀取和儲存。在每次對話過程中,系統首先從記憶中讀取相關資訊,然後根據新的輸入進行處理,最後將處理結果儲存回記憶中,以供未來參考使用。這種設計使得對話式AI能夠保持連貫性和上下文理解能力,從而提供更優質的服務。
LangChain 中的記憶體管理與應用
LangChain 提供多種記憶體型別以支援不同情境下的對話管理需求,從基本的對話緩衝區到更複雜的摘要與 Token 限制管理。本文將探討 LangChain 中的各種記憶體型別及其特性。
對話緩衝記憶體(ConversationBufferMemory)
此記憶體型別用於儲存完整的對話歷史,無論對話長度如何。它提供了基本的對話記憶功能,但缺乏對長度或 Token 數的限制。
程式碼範例:
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
memory.save_context({"input": "hi"}, {"output": "whats up"})
print(memory.load_memory_variables({}))
# 輸出:{'history': 'Human: hi\nAI: whats up'}
內容解密:
- 初始化
ConversationBufferMemory
物件。 - 使用
save_context
方法儲存對話上下文,包括輸入與輸出。 - 使用
load_memory_variables
方法載入儲存的對話歷史。
對話緩衝視窗記憶體(ConversationBufferWindowMemory)
此型別維護最近的 K 次互動,確保緩衝區不會過度增長。它適合用於需要限制對話歷史長度的場景。
程式碼範例:
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
print(memory.load_memory_variables({}))
# 輸出:{'history': 'Human: not much you\nAI: not much'}
內容解密:
- 設定
k=1
表示只保留最後一次互動。 - 儲存多輪對話上下文。
- 載入記憶體變數時,只傳回最近的一次互動。
對話摘要記憶體(ConversationSummaryMemory)
此記憶體型別會動態摘要對話內容,適合用於較長的對話場景,以減少 Token 使用量。
程式碼範例:
from langchain.memory import ConversationSummaryMemory
from langchain_openai import OpenAI
memory = ConversationSummaryMemory(llm=OpenAI(temperature=0))
memory.save_context({"input": "hi"}, {"output": "whats up"})
print(memory.load_memory_variables({}))
# 輸出:{'history': '\nThe human greets the AI, to which the AI responds.'}
內容解密:
- 使用 OpenAI 模型進行對話摘要。
- 儲存對話上下文並自動生成摘要。
- 載入記憶體變數時傳回生成的摘要。
對話摘要緩衝記憶體(ConversationSummaryBufferMemory)
結合了緩衝區與摘要功能,保留近期互動並將舊互動摘要化。
程式碼範例:
from langchain.memory import ConversationSummaryBufferMemory
from langchain_openai.chat_models import ChatOpenAI
memory = ConversationSummaryBufferMemory(llm=ChatOpenAI(), max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
print(memory.load_memory_variables({}))
# 輸出:包含最近互動及摘要的歷史記錄
內容解密:
- 設定
max_token_limit
以控制 Token 使用量。 - 結合近期互動與摘要內容傳回完整的對話歷史。
對話 Token 緩衝記憶體(ConversationTokenBufferMemory)
使用 Token 長度決定何時清除互動記錄,適合需要嚴格控制 Token 使用的場景。
程式碼範例:
from langchain.memory import ConversationTokenBufferMemory
from langchain_openai.chat_models import ChatOpenAI
memory = ConversationTokenBufferMemory(llm=ChatOpenAI(), max_token_limit=50)
memory.save_context({"input": "hi"}, {"output": "whats up"})
print(memory.load_memory_variables({}))
# 輸出:根據 Token 限制傳回對話歷史
內容解密:
- 設定
max_token_limit=50
以限制 Token 使用量。 - 根據設定的 Token 限制傳回適當的對話歷史。
各種記憶體型別的比較
記憶體型別 | 主要特點 | 適用場景 |
---|---|---|
ConversationBufferMemory | 完整儲存對話歷史,無長度限制 | 需要完整對話記錄的場景 |
ConversationBufferWindowMemory | 只保留最近 K 次互動 | 需要限制對話歷史長度的場景 |
ConversationSummaryMemory | 自動摘要對話內容 | 較長對話,需要減少 Token 使用 |
ConversationSummaryBufferMemory | 結合近期互動與摘要功能 | 需要平衡 Token 使用與對話完整性的場景 |
ConversationTokenBufferMemory | 根據 Token 長度管理對話歷史 | 需要嚴格控制 Token 使用量的場景 |