基于Langchain + DeepSeek 构建聊天机器人
前言
本文主要介绍如何基于 DeepSeek 来创建一个聊天机器人。首先介绍 PromptTemplate 提示模版,它作为设计对话流的基础,能够极大提升用户体验。接着,深入 DeepSeek 环境准备及模型创建过程,包括获取 API、创建和配置 API Key、设置 base_url 以及选择合适的模型等步骤。基于 Langchain 框架,将介绍如何通过 MessagesPlaceholder 处理复杂的多轮对话,构建 Chain 保存对话历史,并了解 RunnableWithMessageHistory 对象的实现流式输出,并通过示例代码演示整个流程的实际运行效果。
备注:本系列文章基于 B 站课程:马士兵-AI 大模型全套教程(学习路线+LLM 大语言模型+RAG 实战+Langchain+ChatGLM-4+Transformer+DeepSeek)学习整理得到。
1. 使用 PromptTemplate 提示模板
Langchain 提供了一个提示词模板 ChatPromptTemplate
,它用来帮助我们构建提示词。可以简单理解为 Python 的字符串拼接模板。
定义提示模版
from langchain_core.prompts import ChatPromptTemplate
prompt_template = ChatPromptTemplate.from_messages(
[("system", '请将以下的内容翻译成{language}'), ("user", "{text}")]
)
完整使用代码及运行结果
import os
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
os.environ["OPENAI_API_KEY"] = "DEEPSEEK_API_KEY"
# 1. 创建模型
model = ChatOpenAI(
model='deepseek-chat',
base_url="https://api.deepseek.com/v1"
)
# 2. 定义提示模版
prompt_template = ChatPromptTemplate.from_messages(
[("system", '请将以下的内容翻译成{language}'), ("user", "{text}")]
)
# 3. 创建返回的数据解析器
parser = StrOutputParser()
# 4. 创建链 chain
chain = prompt_template | model | parser
# 5. 直接使用 chain 进行调用
result = chain.invoke({"language": "English", "text": '我下午还有一节课,不能去打球了'})
print(result)
2. DeepSeek 环境准备及模型创建
2.1 获取 API
访问 DeepSeek 开放平台。
2.2 创建 API Key
在左侧点击 API Keys,然后创建 API Key。
2.3 配置 API KEY
os.environ["OPENAI_API_KEY"] = "your_key"
将上一步中创建的 Key 配置到环境变量中。
2.4 配置 base_url
model = ChatOpenAI(
base_url="https://api.deepseek.com"
)
代理地址或中转地址填写 "https://api.deepseek.com"
。
注意:出于与 OpenAI 兼容考虑,也可以将 base_url
设置为 "https://api.deepseek.com/v1"
。
2.5 配置 model
model = ChatOpenAI(
model='deepseek-reasoner',
base_url="https://api.deepseek.com/v1"
)
deepseek-reasoner
是 DeepSeek 最新推出的推理模型 DeepSeek-R1。- 通过指定
model='deepseek-reasoner'
,即可调用 DeepSeek-R1。 - 注意:通过指定
model='deepseek-chat'
,即可调用 DeepSeek-V3。
3. Langchain 构建聊天机器人
这个聊天机器人能够进行对话并记住之前的互动。
3.1 引入 MessagesPlaceholder 来处理多轮对话
MessagesPlaceholder
用于在 Prompt 中插入历史消息,支持多轮对话。动态的系统消息可以通过 {}
进行参数化。
# 定义提示模版
prompt_template = ChatPromptTemplate.from_messages([
('system', '你是一个乐于助人的助手。用{language}尽你所能回答所有问题。'),
MessagesPlaceholder(variable_name='my_msg')
])
3.2 构建 Chain 和保存对话历史
LangChain 提供了 RunnableWithMessageHistory
和 ChatMessageHistory
来支持多轮对话,并保存对话的历史记录。
store = {} # 所有用户的聊天记录都保存到 store。key: session_id, value: 历史聊天记录
# 此函数预期将接受一个 session_id,并返回与该 session_id 对应的聊天记录
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
do_message = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key='my_msg' # 每次聊天时发送 msg 的 key
)
3.3 调用 RunnableWithMessageHistory 对象的 invoke() 方法
每次调用 do_message.invoke()
时,都会根据当前会话的 sessionId
获取或创建对应的对话历史。
config = {'configurable': {'session_id': 'ls1234'}} # 给当前会话定义一个 sessionId
# 第一轮对话
resp1 = do_message.invoke(
{
'my_msg': [HumanMessage(content='你好啊! 我是孙悟空')],
'language': '中文'
},
config=config
)
print(resp1.content)
# 第二轮对话
resp2 = do_message.invoke(
{
'my_msg': [HumanMessage(content='请问:我有其它的昵称吗')],
'language': '中文'
},
config=config
)
print(resp2.content)
3.4 流式输出
LangChain 支持流式响应,这对于处理长文本或实时交互非常有用。
# 第三轮对话 返回的数据是流式的
config = {'configurable': {'session_id': 'lishi987'}} # 给当前会话定义一个 sessionId
for resp in do_message.stream(
{'my_msg': [HumanMessage(content='81难后,我该成仙还是成佛? 或者入魔?')],
'language': '中文'},
config=config):
# 每一次 resp 都是一个 token
print(resp.content, end='-')
3.5 示例代码及运行效果
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
import os
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
# 1. 创建模型
model = ChatOpenAI(
model='deepseek-chat',
base_url="https://api.deepseek.com/v1"
)
# 2. 定义提示模版,引入 MessagesPlaceholder 来处理多轮对话
prompt_template = ChatPromptTemplate.from_messages([
('system', '你是一个乐于助人的助手。用{language}尽你所能回答所有问题。'),
MessagesPlaceholder(variable_name='my_msg')
])
# 3. 创建链 chain
chain = prompt_template | model
# 4. 定义函数保存和管理对话历史
store = {}
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
# 5. 将 Chain 和对话历史管理器对象结合
do_message = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key='my_msg'
)
config = {'configurable': {'session_id': 'ls1234'}}
# 6. 调用对话历史管理器对象的 invoke() 及 stream() 方法,进行对话
# 第一轮对话
resp1 = do_message.invoke(
{
'my_msg': [HumanMessage(content='你好啊! 我是孙悟空')],
'language': '中文'
},
config=config
)
print(resp1.content)
# 第二轮对话
resp2 = do_message.invoke(
{
'my_msg': [HumanMessage(content='请问:我有其它的昵称吗')],
'language': '中文'
},
config=config
)
print(resp2.content)
# 第三轮对话 返回的数据是流式的
config = {'configurable': {'session_id': 'lishi987'}}
for resp in do_message.stream(
{'my_msg': [HumanMessage(content='81难后,我该成仙还是成佛? 或者入魔?')],
'language': '中文'},
config=config):
print(resp.content, end='-')