百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

【AI大模型框架—Langchain】构建简单的LLM的聊天机器人

ccwgpt 2024-11-20 13:15 55 浏览 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的深入了解,你可以不断扩展和优化你的机器人,实现更多复杂功能。

相关推荐

VUE3前端开发入门系列教程二:使用iView框架辅助开发

1、安装iView新框架,支持VUE3npminstallview-ui-plus2、编辑src/main.js,添加以下内容,导入js和css到项目importViewUIPlusfrom...

万能前端框架uni app初探03:底部导航开发

前言本节我们使用uniapp的底部导航功能,点击不同tab会显示不同页面,这个功能在实际项目开发中几乎是必备的。一、基础知识1.tabBar如果应用是一个多tab应用,可以通过tabBar配...

Rust Web 开发框架,前端你可以选择哪个?

Rust构建一切。在如今流行的语言中,Rust可谓是将构建和高效作为自己优美的身姿在大众视野中脱颖而出。它是一门赋予每个人构建可靠且高效软件能力的语言。它有什么特性呢?高性能。Rust速度惊人且内...

连载:前端开发中纠结的Javascript框架(上)

如今,前端开发有着许许多多的框架和库。其中一些好用,一些却不尽人意。通常我们会习惯性运用某一概念,模块或句法。事实上,并没有什么万能工具。这篇文章是关于未来框架的发展趋势——那就是没有框架!我从以下几...

前端开发框架的演进架构:提升用户体验和开发效率

前端开发框架是现代Web应用开发的重要工具,它不仅可以帮助开发者构建复杂的用户界面,还能够提升用户体验和开发效率。随着Web技术的不断发展,前端开发框架也在不断演进,为开发者提供了更丰富、更高效的工具...

Google应用Mesh-TensorFlow框架,让CNN也能处理超高分辨率图像

为了要处理超高分辨率医疗图像数据,Google开发了一种空间数据分区(SpatialPartition)技术,在不牺牲图像分辨率的条件下,分析超高分辨率图像。Google使用Mesh-TensorF...

大模型安全挑战加剧:框架层漏洞成新靶心

近日,360数字安全集团发布了一份关于大模型安全漏洞的报告,揭示了当前大模型及围绕其构建的框架和应用中存在的严重安全问题。报告显示,360近期研究发现了近40个大模型相关的安全漏洞,其中既包括二进制内...

Keras 3.0正式发布:可用于TensorFlow、JAX和PyTorch

机器之心报道编辑:陈萍经过5个月的更新迭代,Keras3.0终于来了。「大新闻:我们刚刚发布了Keras3.0版本!」Keras之父FrancoisChollet在X上激动的...

TensorFlow和Keras入门必读教程(tensorflow与keras版本对应)

导读:本文对TensorFlow的框架和基本示例进行简要介绍。作者:本杰明·普朗什(BenjaminPlanche)艾略特·安德烈斯(EliotAndres)来源:华章科技01TensorFlo...

谷歌官方回应“TensorFlow遭弃”:还在投资开发,将与JAX并肩作战

鱼羊发自凹非寺量子位|公众号QbitAI终于,谷歌出面回应“TensorFlow遭弃”传闻:我们将继续致力于将TensorFlow打造为一流机器学习平台,与JAX并肩推动机器学习研究。这段时...

2025 年的PHP :现代 Web 开发的强大引擎

程序员还在吐槽PHP过时?2025年的PHP8.4直接封神了。看看最近更新的属性钩子、强类型系统,加上Laravel这些框架,老语言早就脱胎换骨。十年前说PHP弱类型容易崩代码的,现在脸疼不?联合类...

前端内卷终结者?htmx如何让开发者告别200行JS只做一个按钮

当你用React写一个点赞按钮需要引入3个状态管理库、编写80行JSX和120行钩子函数时,htmx只需要一行HTML:<buttonhx-post="/like"hx-sw...

NativePHP桌面版V1.0正式发布(元气桌面电脑版下载)

导读:各位小伙伴,使用PHP构建桌面级系统的利器,NativePHP来了。概述NativePHP是一个用于使用PHP构建桌面应用的框架。它允许PHP开发人员使用熟悉的工具和技术创建跨平台的原生应用...

PHP Laravel框架底层机制(php基本框架)

当然可以,Laravel是最受欢迎的PHP框架之一,以优雅的语法和丰富的生态而闻名。尽管开发体验非常“高端”,它的底层其实是由一系列结构清晰、职责分明的组件构成的。下面我从整体架构、核心流程、...

PHP框架之Laravel框架教程:2. 控制器、路由、视图简单介绍

2.控制器、路由、视图简单介绍我们先建立控制器,目录是:app/Http/Controllers,新建控制器Ding.php,代码如下:Ding.php:<?phpnamespaceA...

取消回复欢迎 发表评论: