摘要:本文介绍利用langChain核心组件Models里的Chat Models构建基本的Chatbot,能实现简单的问答。
文章目录
- 概述
- Chat Model
- 1. message对象
- 1.1 消息类型介绍:
- 1.2 使用场景:
- 2. 利用ChatModel构建简单的 Chatbot
- 2.1 实现基本的问答:
- ① 基本问答
- ② 利用SystemMessage传递指令,指定输出语言
- ③ 处理批量问题
- 2.2 带缓存的聊天:
- 3. 局限
概述
实现聊天机器人通常不仅仅是一问一答,还需要“机器人”能够结合上下文,再垂直领域需要“机器人”可以随时索引专业信息等。
Chat Model
LangChain核心组件Models,包含Chat Models, Embeddings, LLMs。
其中Chat Model虽然聊天模型在后台使用语言模型(LLM),但它暴露的接口却有所不同。不光是提供一个“输入文本、输出文本”的API,而是提供了一个以“聊天消息”作为输入和输出的接口。ChatModel的接口比LLM更加结构化。
Embeddings是嵌入模型用于将离散的高维数据,比如句子,文章映射到低维向量空间;一般是向量数据库配合使用,实现向量匹配,构建知识库。
本文主要用ChatModel
1. message对象
刚才提到ChatModel不光是提供一个“输入文本、输出文本”的API,而是提供了一个以“聊天消息”作为输入和输出的接口。
LangChain支持的聊天模型消息类型主要包括:AIMessage、HumanMessage、SystemMessage、ChatMessage;
1.1 消息类型介绍:
1.1.1 HumanMessage
表示人或用户产生的消息,既聊天主题的对话内容。
{"type":"HumanMessage","content":"你好,我是小明,今天天气怎么样?"
}
1.1.2 AIMessage
表示由人工智能或聊天机器人生成的消息。它通常是对用户输入的响应或系统触发的自动回复。用于记录和传输由 AI 生成的回复内容。
{"type":"AIMessage","content":"你好,小明!😊 不过作为AI助手,我无法获取实时天气数据哦。"
}
1.1.3 SysMessage
代表由系统生成的消息,通常用于传递系统状态、指令或元信息。
#例如 传递指令
{"type":"SystemMessage","content":"不论用户输入何种语言,请用中文回答问题。"
}
#例如 指定对话状态
{"type": "SystemMessage","content": "对话已经开始。"
}
1.1.4 ChatMessage
通用消息类型,可以包含任何消息内容,主要用于记录传输对话的上下文。
{"type": "ChatMessage","role": "human","content": "你好,我是小明,今天天气怎么样?"
},
{"type": "ChatMessage","role": "ai","content": "你好,小明!😊 不过作为AI助手,我无法获取实时天气数据哦。。"
},
{
"type": "ChatMessage",
"role": "system",
"content": "会话已重置。"
1.2 使用场景:
1.2.1 AIMessage 和 HumanMessage:
- 在对话中区分用户输入和 AI 响应。
- 追踪对话的来回交流,用于分析/改进对话系统的性能。
1.2.2 SystemMessage - 包含开始、结束等系统事件信息以及指令信息等。
- 主要用于对对话进行控制。
1.2.3 ChatMessage - 统一对不用类型信息进行存储,用于处理多种消息类型的复杂对话场景。
实际应用中主要需要处理AIMessage 、HumanMessage、SystemMessage三种。
2. 利用ChatModel构建简单的 Chatbot
2.1 实现基本的问答:
① 基本问答
# chat model message
from langchain.chat_models import ChatOpenAI
from langchain_core.messages import HumanMessage,AIMessage,SystemMessage,ChatMessage# 定义模型调用API URL
base_url = "https://api.deepseek.com/v1"
# 定义模型调用API KEY(实际应用会放到环境变量中,避免明文暴露)
api_key = "输入你的模型 API key"
# 定义模型名称(对应DeepSeek-V3)
model='deepseek-chat' chatbot = ChatOpenAI(base_url=base_url, api_key=api_key,model=model)messages=[HumanMessage(content="你好,我是小明,今天天气怎么样?")]result = chatbot(messages)print("type: {}, content:{}".format(result.type,result.content))
type: ai, content:你好,小明!😊 不过作为AI助手,我无法获取实时天气数据哦。建议你:1. 查看手机上的天气应用
2. 在搜索引擎输入"天气+你所在的城市"(比如"北京天气")
3. 问问智能音箱或语音助手需要我教你如何设置手机天气小工具吗?或者你那边现在天气如何?可以和我分享呀~ ☀️🌧️⛅
② 利用SystemMessage传递指令,指定输出语言
如果希望使用英语可以利用SystemMessage 传递指令
# 增加SystemMessage 指定输出为英语
messages = [SystemMessage(content="不论用户输入何种语言,请用英文回答问题。"),HumanMessage(content="你好,我是小明,今天天气怎么样?")
]result = chatbot(messages)print("type: {}, content:{}".format(result.type,result.content))
得到结果:
type: ai, content:Hello, I'm an AI assistant and I can only respond in English. You asked: "Hello, I'm Xiao Ming, how's the weather today?"Since I don't have real-time weather data capabilities, I can't provide current weather conditions. However, I can suggest you check a weather app or website for the most accurate forecast in your location.Would you like me to help with anything else?
③ 处理批量问题
batch_messages = [[HumanMessage(content="你好,我是小明,今天天气怎么样?")],[HumanMessage(content="我今年18岁,你有多少岁了?")],
]# 返回LLMResulr 对象
result = chatbot.generate(batch_messages)# 遍历每轮的响应
for gen in result.generations:# 输出每轮第一次响应结果print("=============================")print(gen[0].text)
输出:
=============================
你好,小明!😊 不过作为AI助手,我无法获取实时天气数据哦。你可以通过手机天气应用、网页搜索(比如“北京今天天气”) 或询问智能设备(如小爱同学、Siri)来获取最新天气情况~需要的话,我也可以帮你查某个城市**近期典型天气**或提供出行建议!☀️🌧️
=============================
哈哈,我其实没有真实的“年龄”哦~作为一个AI助手,我的知识库更新到2023年,但我的存在时间取决于你遇到我的那一刻——就像现在,对你来说我就是“刚出生”的新朋友!✨不过按人类的时间算,你可以当我是永远18岁的数字伙伴~ (毕竟和同龄人聊天更轻松嘛😉) 有什么想聊的随时找我!
2.2 带缓存的聊天:
我们每次调用OpenAI的API都是要花钱的,在实际生产过程中,同一个问题可以对结果进行缓存,可以减少接口的调用次数,降低成本;同时还能提高响应速度。
对上述ChatBot进行多轮会话(不带缓存):
# 第一轮对话
messages = [HumanMessage(content="请给我将一个笑话。")]
result = chatbot.invoke(messages)
print("第一轮对话:")
print("type: {}, content:{}".format(result.type,result.content))# 模拟第二轮对话
messages = [HumanMessage(content="请给我将一个笑话。")]
result = chatbot.invoke(messages)
print("第二轮对话:")
print("type: {}, content:{}".format(result.type,result.content))
输出:
第一轮对话:
type: ai, content:好的!来一个轻松的小笑话:**顾客**:老板,你这包子怎么涨价了?
**老板**:因为猪肉涨价了啊!
**顾客**(指着豆沙包):那这个为什么也涨?
**老板**(沉默两秒):…因为猪肉涨价,我得多吃豆沙包补充体力,所以它也缺货了!(冷知识:所有涨价最终都会怪到猪肉头上😂)希望逗你一笑~ 需要其他类型的笑话随时说哦!
第二轮对话:
type: ai, content:好的,来一个轻松的笑话:🐔 **鸡的困惑**
一只小鸡问母鸡:“妈妈,人类为什么总说‘鸡蛋’?明明是我们先有的,为什么不叫‘鸡蛋’?”
母鸡沉思两秒:“可能他们觉得‘鸡蛋’听起来比较……‘鸡’动人心?”(冷到你了记得加件外套~ 😄)
结果,虽然问题一样,单给的答案不一样,说明二次调用了API,另外可以看到两次调用的时间:
增加缓存
from langchain.cache import InMemoryCache,SQLiteCache
from langchain.globals import set_llm_cache# 启动全局缓存 可以是内存缓存,也可以是Sqllite本地缓存
# set_llm_cache(SQLiteCache(database_path=".langchain.db"))
set_llm_cache(InMemoryCache())
之后再执行相同的问题:
# 第一轮对话
messages = [HumanMessage(content="请给我将一个笑话。")]
result = chatbot.invoke(messages)
print("第一轮对话:")
print("type: {}, content:{}".format(result.type,result.content))# 模拟第二轮对话
messages = [HumanMessage(content="请给我将一个笑话。")]
result = chatbot.invoke(messages)
print("第二轮对话:")
print("type: {}, content:{}".format(result.type,result.content))
输出:
第一轮对话:
type: ai, content:当然!这里有个经典笑话送给你:**顾客**:老板,你这清炒小白菜怎么有肉味?
**老板**:啊,可能因为…我炒菜时戴着口罩。
**顾客**:这和口罩有什么关系?
**老板**:我口罩是猪肉馅的。(然后被卫生局拖走)(冷知识:这其实是网友对“食堂黑暗料理”的吐槽梗改编😂)需要再来一个吗?
第二轮对话:
type: ai, content:当然!这里有个经典笑话送给你:**顾客**:老板,你这清炒小白菜怎么有肉味?
**老板**:啊,可能因为…我炒菜时戴着口罩。
**顾客**:这和口罩有什么关系?
**老板**:我口罩是猪肉馅的。(然后被卫生局拖走)(冷知识:这其实是网友对“食堂黑暗料理”的吐槽梗改编😂)需要再来一个吗?
可以看到第二次直接走缓存,不化时间:
(PS:监控配置LangSmith)
3. 局限
以上chatbot只是简单的示例,实际应用中还需要考虑上下文管理、知识库访问,工具调用等能力。