LangChain 记忆组件深度解析:Chain 组件与 Runnable 深入学习

在构建复杂的 AI 应用时,有效管理对话历史和上下文信息至关重要。LangChain 框架提供了多种记忆组件,使得开发者能够轻松实现具有记忆功能的聊天机器人。本文将深入探讨 LangChain 中的记忆组件、Chain 组件以及 Runnable 接口,帮助开发者更好地理解和使用这些强大的工具。

LangChain 缓冲记忆组件的使用与解析

缓冲记忆组件的类型

LangChain 提供了多种缓冲记忆组件,每种组件都有其特定的用途和优势:

  1. ConversationBufferMemory:最简单的缓冲记忆,将所有对话信息全部存储作为记忆。

  2. ConversationBufferWindowMemory:通过设定 k 值,只保留一定数量(2*k)的对话信息作为历史。

  3. ConversationTokenBufferMemory:通过设置最大标记数量(max_token_limits)来决定何时清除交互信息,当对话信息超过 max_token_limits 时,抛弃旧对话信息。

  4. ConversationStringBufferMemory:等同于缓冲记忆,固定返回字符串(这是早期 LangChain 封装的记忆组件)。

缓冲窗口记忆示例

以下是一个使用 ConversationBufferWindowMemory 实现 2 轮对话记忆的示例:

复制代码
from operator import itemgetter
import dotenv
from langchain.memory import ConversationBufferWindowMemory
from langchain_community.chat_message_histories import FileChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

memory = ConversationBufferWindowMemory(
    input_key="query",
    return_messages=True,
    k=2,
)

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是OpenAI开发的聊天机器人,请帮助用户解决问题"),
    MessagesPlaceholder("history"),
    ("human", "{query}")
])

llm = ChatOpenAI(model="gpt-3.5-turbo-16k")

chain = RunnablePassthrough.assign(
    history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
) | prompt | llm | StrOutputParser()

while True:
    query = input("Human: ")
    if query == "q":
        exit(0)
    chain_input = {"query": query}
    print("AI: ", flush=True, end="")
    response = chain.stream(chain_input)
    output = ""
    for chunk in response:
        output += chunk
        print(chunk, flush=True, end="")
    print("\nhistory:", memory.load_memory_variables({}))
    memory.save_context(chain_input, {"output": output})
复制代码

LangChain 摘要记忆组件的使用与解析

摘要记忆组件的类型

LangChain 提供了两种主要的摘要记忆组件:

  1. ConversationSummaryMemory:将传递的历史对话记录总结成摘要进行保存,使用时填充的记忆为摘要,而非对话数据。

  2. ConversationSummaryBufferMemory:在不超过 max_token_limit 的限制下保存对话历史数据,对于超过的部分进行信息的提取与总结。

摘要缓冲混合记忆示例

以下是一个使用 ConversationSummaryBufferMemory 的示例,限制 max_token_limit 为 300:

复制代码
from operator import itemgetter
import dotenv
from langchain.memory import ConversationSummaryBufferMemory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个强大的聊天机器人,请根据对应的上下文回复用户问题"),
    MessagesPlaceholder("history"),
    ("human", "{query}"),
])
memory = ConversationSummaryBufferMemory(
    return_messages=True,
    input_key="query",
    llm=ChatOpenAI(model="gpt-3.5-turbo-16k"),
    max_token_limit=300,
)

llm = ChatOpenAI(model="gpt-3.5-turbo-16k")

chain = RunnablePassthrough.assign(
    history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
) | prompt | llm | StrOutputParser()

while True:
    query = input("Human: ")
    if query == "q":
        exit(0)
    chain_input = {"query": query, "language": "中文"}
    response = chain.stream(chain_input)
    print("AI: ", flush=True, end="")
    output = ""
    for chunk in response:
        output += chunk
        print(chunk, flush=True, end="")
    memory.save_context(chain_input, {"output": output})
    print("")
print("history: ", memory.load_memory_variables({}))
复制代码

使用摘要记忆组件时,需要注意一些潜在的问题,如多个 System 角色消息的处理和某些聊天模型对消息格式的特殊要求。

LangChain 实体记忆组件的使用与解析

实体记忆组件用于跟踪对话中提到的实体,并记住关于特定实体的既定事实。LangChain 提供了 ConversationEntityMemory 类来实现这一功能。

以下是一个使用 ConversationEntityMemory 的示例:

复制代码
import dotenv
from langchain.chains.conversation.base import ConversationChain
from langchain.memory import ConversationEntityMemory
from langchain.memory.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()
llm = ChatOpenAI(model="gpt-4o", temperature=0)
chain = ConversationChain(
    llm=llm,
    prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,
    memory=ConversationEntityMemory(llm=llm),
)
print(chain.invoke({"input": "你好,我最近正在学习LangChain。"}))
print(chain.invoke({"input": "我最喜欢的编程语言是 Python。"}))
print(chain.invoke({"input": "我住在广州"}))
res = chain.memory.entity_store.store
print(res)
复制代码

记忆组件的持久化与第三方集成

LangChain 的记忆组件本身没有持久化功能,但可以通过 chat_memory 来将对话信息历史持久化。LangChain 集成了近 50 多个第三方对话消息历史存储方案,包括 Postgres、Redis、Kafka、MongoDB、SQLite 等。

内置 Chain 组件的使用与解读

Chain 简介与使用

在 LangChain 中,Chain 用于将多个组件(如 LLM、提示词模板、向量存储、记忆、输出解析器等)串联起来一起使用。LangChain 支持两种类型的链:

  1. 使用 LCEL(LangChain Expression Language)构建的链
  2. 通过 Chain 类子类构建的链(遗产链)

以下是使用 LLMChain 的基础示例:

复制代码
import dotenv
from langchain.chains.llm import LLMChain
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

llm = ChatOpenAI(model="gpt-3.5-turbo-16k")
prompt = ChatPromptTemplate.from_template("请讲一个关于{subject}的冷笑话")

chain = LLMChain(
    llm=llm,
    prompt=prompt,
)

print(chain("程序员"))
print(chain.run("程序员"))
print(chain.apply([{"subject": "程序员"}]))
print(chain.generate([{"subject": "程序员"}]))
print(chain.predict(subject="程序员"))
print(chain.invoke({"subject": "程序员"}))
复制代码

内置的 Chain

LangChain 提供了多种内置的 Chain,包括 LCEL Chain 和遗产 Chain。例如,create_stuff_documents_chain 函数可以创建一个文档对话链:

复制代码
import dotenv
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个强大的聊天机器人,能根据对应的上下文信息回复用户问题。\n\n<context>{context}</context>"),
    ("human", "{query}"),
])

llm = ChatOpenAI(model="gpt-3.5-turbo-16k")

chain = create_stuff_documents_chain(llm=llm, prompt=prompt)

documents = [
    Document(page_content="小明喜欢绿色,但不喜欢黄色"),
    Document(page_content="小王喜欢粉色,也有一点喜欢红色"),
    Document(page_content="小泽喜欢蓝色,但更喜欢青色")
]

resp = chain.invoke({"query": "大家都喜欢什么颜色", "context": documents})

print(resp)
复制代码

RunnableWithMessageHistory 简化代码与使用

RunnableWithMessageHistory 是一个包装器,可以让链自动处理历史消息的填充和存储过程。

以下是一个使用 RunnableWithMessageHistory 的示例:

复制代码
import dotenv
from langchain_community.chat_message_histories import FileChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = FileChatMessageHistory(f"chat_history_{session_id}.txt")
    return store[session_id]

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个强大的聊天机器人,请根据用户的需求回复问题。"),
    MessagesPlaceholder("history"),
    ("human", "{query}"),
])
llm = ChatOpenAI(model="gpt-3.5-turbo-16k")

chain = prompt | llm | StrOutputParser()

with_message_chain = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="query",
    history_messages_key="history",
)

while True:
    query = input("Human: ")
    if query == "q":
        exit(0)
    response = with_message_chain.stream(
        {"query": query},
        config={"configurable": {"session_id": "muxiaoke"}}
    )
    print("AI: ", flush=True, end="")
    for chunk in response:
        print(chunk, flush=True, end="")
print("")
复制代码

通过使用 RunnableWithMessageHistory,我们可以更方便地管理多个用户的对话历史,并在链中自动处理历史消息的加载和存储。

结论:

LangChain 提供了丰富的记忆组件和 Chain 组件,使得开发者能够轻松构建具有上下文感知能力的 AI 应用。通过合理使用这些组件,我们可以创建更智能、更个性化的对话系统。随着 LangChain 的不断发展,LCEL 表达式和 Runnable 接口的引入进一步简化了应用的构建过程。开发者应该根据具体需求选择合适的记忆组件和 Chain 类型,以实现最佳的应用性能和用户体验。

posted @   muzinan110  阅读(268)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略
点击右上角即可分享
微信分享提示