【AI大模型框架—Langchain】构建简单的LLM的聊天机器人
ccwgpt 2024-11-20 13:15 46 浏览 0 评论
在本文中,我们将带你一步步设计并实现一个基于大语言模型(LLM)的聊天机器人。这个机器人不仅可以与用户进行对话,还能够记住之前的互动记录。
先决条件
在开始之前,建议你熟悉以下概念:
- 聊天模型(Chat Models)
- 提示模板(Prompt Templates)
- 聊天记录(Chat History)
概述
我们将通过一个示例来展示如何设计和实现一个LLM驱动的聊天机器人。需要注意的是,这个机器人只使用语言模型进行对话。你可能还需要了解以下相关概念:
- Conversational RAG:在外部数据源上启用聊天机器人体验
- Agents:构建可以执行操作的聊天机器人
本教程将介绍一些基础知识,这些知识对上述更高级的主题也会有所帮助。
环境搭建
安装 LangChain
要安装LangChain,请运行以下命令:
pip install langchain
有关更多详细信息,请参阅我们的安装指南。
快速入门
使用语言模型
LangChain支持许多不同的语言模型,你可以根据需要选择使用。这里以OpenAI的gpt-4o-mini为例:
pip install -qU langchain-openai
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o-mini").bind(logprobs=True)
直接使用模型与之交互:
from langchain_core.messages import HumanMessage
response = model.invoke([HumanMessage(content="Hi! I'm Bob")])
print(response)
响应的结果:
content='Hi Bob! How can I assist you today?' response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 11, 'total_tokens': 21}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_ba606877f9', 'finish_reason': 'stop', 'logprobs': {'content': [{'token': 'Hi', 'bytes': [72, 105], 'logprob': -0.023249088, 'top_logprobs': []}, {'token': ' Bob', 'bytes': [32, 66, 111, 98], 'logprob': -0.01416727, 'top_logprobs': []}, {'token': '!', 'bytes': [33], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' How', 'bytes': [32, 72, 111, 119], 'logprob': -0.00035596156, 'top_logprobs': []}, {'token': ' can', 'bytes': [32, 99, 97, 110], 'logprob': -0.00011450992, 'top_logprobs': []}, {'token': ' I', 'bytes': [32, 73], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' assist', 'bytes': [32, 97, 115, 115, 105, 115, 116], 'logprob': -0.03804183, 'top_logprobs': []}, {'token': ' you', 'bytes': [32, 121, 111, 117], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' today', 'bytes': [32, 116, 111, 100, 97, 121], 'logprob': 0.0, 'top_logprobs': []}, {'token': '?', 'bytes': [63], 'logprob': 0.0, 'top_logprobs': []}]}} id='run-c623dce5-1b6a-45ee-ad27-84ddbee0ebad-0' usage_metadata={'input_tokens': 11, 'output_tokens': 10, 'total_tokens': 21}
如果问后续问题,模型默认没有状态概念:
response = model.invoke([HumanMessage(content="What's my name?")])
print(response)
响应结果:
content="I'm sorry, but I don't have access to personal information about users unless it has been shared in the conversation. If you'd like, you can tell me your name!" response_metadata={'token_usage': {'completion_tokens': 33, 'prompt_tokens': 11, 'total_tokens': 44}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_ba606877f9', 'finish_reason': 'stop', 'logprobs': {'content': [{'token': "I'm", 'bytes': [73, 39, 109], 'logprob': -0.47415686, 'top_logprobs': []}, {'token': ' sorry', 'bytes': [32, 115, 111, 114, 114, 121], 'logprob': -0.0006115251, 'top_logprobs': []}, {'token': ',', 'bytes': [44], 'logprob': -4.3202e-07, 'top_logprobs': []}, {'token': ' but', 'bytes': [32, 98, 117, 116], 'logprob': -0.00012356207, 'top_logprobs': []}, {'token': ' I', 'bytes': [32, 73], 'logprob': -7.703444e-06, 'top_logprobs': []}, {'token': " don't", 'bytes': [32, 100, 111, 110, 39, 116], 'logprob': -0.019258404, 'top_logprobs': []}, {'token': ' have', 'bytes': [32, 104, 97, 118, 101], 'logprob': -0.47407743, 'top_logprobs': []}, {'token': ' access', 'bytes': [32, 97, 99, 99, 101, 115, 115], 'logprob': -0.017442156, 'top_logprobs': []}, {'token': ' to', 'bytes': [32, 116, 111], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' personal', 'bytes': [32, 112, 101, 114, 115, 111, 110, 97, 108], 'logprob': -0.047323395, 'top_logprobs': []}, {'token': ' information', 'bytes': [32, 105, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110], 'logprob': -0.20144111, 'top_logprobs': []}, {'token': ' about', 'bytes': [32, 97, 98, 111, 117, 116], 'logprob': -0.19552712, 'top_logprobs': []}, {'token': ' users', 'bytes': [32, 117, 115, 101, 114, 115], 'logprob': -0.9391852, 'top_logprobs': []}, {'token': ' unless', 'bytes': [32, 117, 110, 108, 101, 115, 115], 'logprob': -0.1827523, 'top_logprobs': []}, {'token': ' it', 'bytes': [32, 105, 116], 'logprob': -1.0404304, 'top_logprobs': []}, {'token': ' has', 'bytes': [32, 104, 97, 115], 'logprob': -0.0007059985, 'top_logprobs': []}, {'token': ' been', 'bytes': [32, 98, 101, 101, 110], 'logprob': -5.5577775e-06, 'top_logprobs': []}, {'token': ' shared', 'bytes': [32, 115, 104, 97, 114, 101, 100], 'logprob': -0.007847821, 'top_logprobs': []}, {'token': ' in', 'bytes': [32, 105, 110], 'logprob': -1.5318099, 'top_logprobs': []}, {'token': ' the', 'bytes': [32, 116, 104, 101], 'logprob': -0.15039976, 'top_logprobs': []}, {'token': ' conversation', 'bytes': [32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105, 111, 110], 'logprob': -1.3203849, 'top_logprobs': []}, {'token': '.', 'bytes': [46], 'logprob': -2.2961513e-05, 'top_logprobs': []}, {'token': ' If', 'bytes': [32, 73, 102], 'logprob': -0.82898766, 'top_logprobs': []}, {'token': " you'd", 'bytes': [32, 121, 111, 117, 39, 100], 'logprob': -0.252001, 'top_logprobs': []}, {'token': ' like', 'bytes': [32, 108, 105, 107, 101], 'logprob': -1.504853e-06, 'top_logprobs': []}, {'token': ',', 'bytes': [44], 'logprob': -1.0768048, 'top_logprobs': []}, {'token': ' you', 'bytes': [32, 121, 111, 117], 'logprob': -0.014669579, 'top_logprobs': []}, {'token': ' can', 'bytes': [32, 99, 97, 110], 'logprob': -0.00018411019, 'top_logprobs': []}, {'token': ' tell', 'bytes': [32, 116, 101, 108, 108], 'logprob': -0.00955621, 'top_logprobs': []}, {'token': ' me', 'bytes': [32, 109, 101], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' your', 'bytes': [32, 121, 111, 117, 114], 'logprob': -5.5122365e-07, 'top_logprobs': []}, {'token': ' name', 'bytes': [32, 110, 97, 109, 101], 'logprob': 0.0, 'top_logprobs': []}, {'token': '!', 'bytes': [33], 'logprob': -0.00811096, 'top_logprobs': []}]}} id='run-ec33c381-a4db-4bb9-9ccb-d1720a8214a6-0' usage_metadata={'input_tokens': 11, 'output_tokens': 33, 'total_tokens': 44}
模型无法回答,体验不佳。为解决这个问题,我们需要传递整个对话历史:
response = model.invoke(
[
HumanMessage(content="Hi! I'm Bob"),
AIMessage(content="Hello Bob! How can I assist you today?"),
HumanMessage(content="What's my name?"),
]
)
print(response)
此时响应的结果可以看出,LLM已经能够识别到我是谁了?
content='Your name is Bob! How can I help you today?' response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 33, 'total_tokens': 45}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_ba606877f9', 'finish_reason': 'stop', 'logprobs': {'content': [{'token': 'Your', 'bytes': [89, 111, 117, 114], 'logprob': -0.003211819, 'top_logprobs': []}, {'token': ' name', 'bytes': [32, 110, 97, 109, 101], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' is', 'bytes': [32, 105, 115], 'logprob': -4.3202e-07, 'top_logprobs': []}, {'token': ' Bob', 'bytes': [32, 66, 111, 98], 'logprob': 0.0, 'top_logprobs': []}, {'token': '!', 'bytes': [33], 'logprob': -0.25192946, 'top_logprobs': []}, {'token': ' How', 'bytes': [32, 72, 111, 119], 'logprob': -0.015417111, 'top_logprobs': []}, {'token': ' can', 'bytes': [32, 99, 97, 110], 'logprob': -0.00081379723, 'top_logprobs': []}, {'token': ' I', 'bytes': [32, 73], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' help', 'bytes': [32, 104, 101, 108, 112], 'logprob': -0.023248974, 'top_logprobs': []}, {'token': ' you', 'bytes': [32, 121, 111, 117], 'logprob': 0.0, 'top_logprobs': []}, {'token': ' today', 'bytes': [32, 116, 111, 100, 97, 121], 'logprob': -0.01769961, 'top_logprobs': []}, {'token': '?', 'bytes': [63], 'logprob': -0.6931476, 'top_logprobs': []}]}} id='run-122d5e43-1c05-4bb2-a3cd-1507f7167f4d-0' usage_metadata={'input_tokens': 33, 'output_tokens': 12, 'total_tokens': 45}
管理对话历史
我们可以使用Message History类来记录对话,使模型具有状态。安装必要依赖:
pip install langchain_community
然后设置会话历史记录存储:
def get_session_history(session_id: str) -> BaseChatMessageHistory:
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": "abc2"}}
response = with_message_history.invoke([HumanMessage(content="Hi! I'm Bob")], config=config)
print(response.content)
response = with_message_history.invoke([HumanMessage(content="What's my name?")], config=config)
print(response.content)
运行结果:
Hi Bob! How can I assist you today?
Your name is Bob! How can I help you today?
使用提示模板
提示模板帮助将用户输入转换为LLM可以处理的格式。首先,我们添加系统消息来定制指令:
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)
响应结果为:
Hi Bob! How can I assist you today?
将其包装在Message History对象中:
# 包装在Message History对象
with_message_history = RunnableWithMessageHistory(chain, get_session_history)
config = {"configurable": {"session_id": "abc5"}}
response = with_message_history.invoke([HumanMessage(content="Hi! I'm Jim")], config=config)
print(response.content)
response = with_message_history.invoke([HumanMessage(content="What's my name?")], config=config)
print(response.content)
Hi Jim! How can I assist you today?
Your name is Jim! How can I help you today, Jim?
管理对话历史的大小
为了防止对话历史过长,我们可以使用LangChain的消息修剪功能:
from langchain_core.messages import trim_messages, AIMessage, BaseMessage, HumanMessage, SystemMessage
messages = [
HumanMessage(content="hi! I'm bob"),
SystemMessage(content="you're a good assistant"),
AIMessage(content="hi!"),
HumanMessage(content="I like vanilla ice cream"),
AIMessage(content="nice"),
HumanMessage(content="whats 2 + 2"),
AIMessage(content="4"),
HumanMessage(content="thanks"),
AIMessage(content="no problem!"),
HumanMessage(content="having fun?"),
AIMessage(content="yes!"),
]
trimmer = trim_messages(
# messages,
max_tokens=65,
strategy="last",
token_counter=model,
include_system=True,
allow_partial=False,
start_on="human",
)
print(trimmer)
response = trimmer.invoke(messages)
print(response)
在我们的链中使用修剪功能:
# 在langchain的链中使用
from operator import itemgetter
from langchain_core.runnables import RunnablePassthrough
chain = (
RunnablePassthrough.assign(messages=itemgetter("messages") | trimmer)
| prompt
| model
)
response = chain.invoke(
{
"messages": messages + [HumanMessage(content="what's my name?")],
"language": "English",
}
)
print(response.content)
将其包装在Message History中:
# 包装在Message History
with_message_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="messages",
)
config = {"configurable": {"session_id": "abc20"}}
response = with_message_history.invoke(
{
"messages": messages + [HumanMessage(content="whats my name?")],
"language": "English",
},
config=config,
)
print(response.content)
流式响应
为了改善用户体验,我们可以使用流式响应:
config = {"configurable": {"session_id": "abc15"}}
for r in with_message_history.stream(
{
"messages": [HumanMessage(content="hi! I'm todd. tell me a joke")],
"language": "English",
},
config=config,
):
print(r.content, end="|")
通过本文的讲解,你应该能够构建一个简单但功能强大的LLM聊天机器人。随着对LangChain的深入了解,你可以不断扩展和优化你的机器人,实现更多复杂功能。
相关推荐
- Spring WebFlux vs. Spring MVC(springboot是什么)
-
背景随着异步I/O和Netty等框架的流行,响应式编程逐渐走入大众的视野。但是,响应式编程本身并不是太新的概念,这个术语最早出现在1985年DavidHarel和AmirPnue...
- 深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理
-
适配主流框架如果不借助Sentinel提供的适配主流框架的模块,则在使用Sentinel时需要借助try-catchfinally将要保护的资源(方法或代码块)包起来,在目标方法或代码块执行之前,调...
- Spring MVC 底层原理深度解析:从请求到响应的全链路拆解
-
一、Servlet容器与DispatcherServlet的启动博弈1.Tomcat初始化阶段java//Tomcat初始化流程StandardContext#startInterna...
- 改造总结之传统SpringMVC架构转换为SpringBoot再到集群
-
改造出发点,是基于现在服务都在向上云的目标前进,传统SpringMVC难以满足项目持续构建、服务节点任意扩展的需求,所以开始了历史项目的改造。项目改造考虑的主要是兼容以前的业务代码,以及session...
- SpringBoot3 整合 Spring MVC 全解析:开启高效 Web 开发之旅
-
在当今的JavaWeb开发领域,Spring框架家族无疑占据着重要的地位。其中,SpringBoot3和SpringMVC更是开发者们构建强大、高效Web应用的得力工具。今天,...
- 一文读懂SpringMVC(一文读懂!残疾人低保边缘家庭能领的超实用福利政策)
-
1.SpringMVC定义1.1.MVC定义Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据View(视图):是应用程序中处理数据显示的部分。通常...
- 69 个Spring mvc 全部注解:真实业务使用案例说明(必须收藏)
-
SpringMVC框架的注解为Web开发提供了一种简洁而强大的声明式方法。从控制器的定义、请求映射、参数绑定到异常处理和响应构建,这些注解涵盖了Web应用程序开发的各个方面。它们不仅简化了编码工作,...
- Spring MVC工作原理:像拼积木一样构建Web应用
-
SpringMVC工作原理:像拼积木一样构建Web应用在Java的Web开发领域,SpringMVC无疑是一个让人又爱又恨的存在。它像一位神通广大的积木搭建大师,将一个个分散的功能模块巧妙地拼接在...
- 5千字的SpringMVC总结,我觉得你会需要
-
思维导图文章已收录到我的Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary概述SpringMVC再熟悉不过的框架了,因为现在最火的...
- SpringMVC工作原理与优化指南(springmvc工作原理和工作流程)
-
SpringMVC工作原理与优化指南在现代Java开发中,SpringMVC无疑是构建Web应用程序的首选框架之一。它以其优雅的设计和强大的功能吸引了无数开发者。那么,SpringMVC究竟是如何工作...
- Spring MVC框架源码深度剖析:从入门到精通
-
SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...
- 3000字搞明白SpringMVC工作流程、DispatcherServlet类、拦截器!
-
SpringMVC基础虽然SpringBoot近几年发展迅猛,但是SpringMVC在Web开发领域仍然占有重要的地位。本章主要讲解SpringMVC的核心:DispatcherServlet类...
- 多年经验大佬用2000字透彻解析SpringMVC的常用注解及相关示例
-
SpringMVC注解SpringMVC框架提供了大量的注解,如请求注解、参数注解、响应注解及跨域注解等。这些注解提供了解决HTTP请求的方案。本节主要讲解SpringMVC的常用注解及相关示例...
- 知乎热议:如何成为前端架构师,赚百万年薪?
-
作者|慕课网精英讲师双越最近有一条知乎热议:从一个前端工程师,如何根据目标,制定计划,才能快速进阶成为前端架构师?不久之前我参与了一次直播,讲到了自己对于Web前端架构师的理解。架构师这个角色...
- 学习笔记-前端开发架构设计(前端架构设计方案)
-
前端开发的技术选项主要包含以下几点,下面对一些名词概念的解释做了笔记:1、分层架构:把功能相似,抽象级别相近的实现进行分层隔离优势:松散耦合(易维护,易复用,易扩展)常见分层方式:MVC,MVVM2、...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Spring WebFlux vs. Spring MVC(springboot是什么)
- 深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理
- Spring MVC 底层原理深度解析:从请求到响应的全链路拆解
- 改造总结之传统SpringMVC架构转换为SpringBoot再到集群
- SpringBoot3 整合 Spring MVC 全解析:开启高效 Web 开发之旅
- 一文读懂SpringMVC(一文读懂!残疾人低保边缘家庭能领的超实用福利政策)
- 69 个Spring mvc 全部注解:真实业务使用案例说明(必须收藏)
- Spring MVC工作原理:像拼积木一样构建Web应用
- 5千字的SpringMVC总结,我觉得你会需要
- SpringMVC工作原理与优化指南(springmvc工作原理和工作流程)
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- scrapy框架 (52)
- beego框架 (42)
- java框架spring (43)
- grpc框架 (55)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)