《使用 LangChain 进行大模型应用开发》学习笔记(三)

news2024/11/16 1:33:39

前言

本文是 Harrison Chase (LangChain 创建者)和吴恩达(Andrew Ng)的视频课程《LangChain for LLM Application Development》(使用 LangChain 进行大模型应用开发)的学习笔记。由于原课程为全英文视频课程,国内访问较慢,同时我整理和替换了部分内容以便于国内学习。阅读本文可快速学习课程内容。

课程介绍

本课程介绍了强大且易于扩展的 LangChain 框架,LangChain 框架是一款用于开发大语言模型(LLM)应用的开源框架,其使用提示词、记忆、链、代理等简化了大语言模型应用的开发工作。由于 LangChain 仍处于快速发展期,部分 API 还不稳定,课程中的部分代码已过时,我使用了目前最新的 v0.2 版本进行讲解,所有代码均可在 v0.2 版本下执行。另外,课程使用的 OpenAI 在国内难以访问,我替换为国内的 Kimi 大模型及开源自建的 Ollama,对于学习没有影响。

参考这篇文章来获取 Kimi 的 API 令牌。
参考这篇文章来用 Ollama 部署自己的大模型。

  • 第一部分
  • 第二部分
  • 第三部分

在这里插入图片描述

课程链接

第三部分

提问和回答

生成测试数据

我们先使用任意聊天机器人来生成测试的数据,提示词如下:

请随机生成30条商品介绍数据,以逗号分隔的csv格式输出,第一行是表头,输出:no,name,description,包含以下三列:
序号
商品名称
商品的详细描述

会生成类似下面这样的内容,我们保存为 product.csv 文件。

no,name,description
1,高清智能电视,"这款高清智能电视拥有4K超高清分辨率,内置智能系统,支持语音控制,提供丰富的娱乐体验。"
2,多功能料理机,"集搅拌、打蛋、榨汁等多种功能于一身,操作简便,是厨房里的得力助手。"
3,无线蓝牙耳机,"轻巧舒适,音质清晰,支持长时间续航,适合运动和日常使用。"
4,智能扫地机器人,"自动规划清扫路线,智能避障,解放双手,保持家中清洁。"
5,便携式榨汁机,"小巧便携,操作简便,快速榨汁,适合健康生活需求。"
...

问答链

然后我们通过下面的代码,让 LLM 从我们生成的测试数据中找出和总结我们需要的数据。下面使用了 Ollama 部署的 qwen2(千问2)模型,执行前请先部署服务。

请先安装依赖 pip install docarray

from langchain_community.llms import Ollama
from langchain.chains import RetrievalQA
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.document_loaders import CSVLoader
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain.indexes import VectorstoreIndexCreator

# 服务地址
base_url = 'http://localhost:11434'
# 模型名称
llm_model = 'qwen2'
# 数据文件路径
file_path = 'product.csv'

# 创建模型
llm = Ollama(base_url=base_url, model=llm_model)
# 创建数据载入器
loader = CSVLoader(file_path=file_path)
# 创建词嵌入
embeddings = OllamaEmbeddings(base_url=base_url, model=llm_model)
# 创建向量索引
index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch,
    embedding=embeddings
).from_loaders([loader])
# 提问
query = "请列出带有智能功能且节能环保的电器,以 Markdown 格式输出,总结它们的功能描述。"
response = index.query(query, llm=llm)
print(response)

可能会获得如下输出(由于生成的测试数据以及 LLM 每次回答不同,结果可能有较大差异)。

- **智能空调**:
  * 功能描述:智能温控,自动调节,节能省电,提供舒适环境。

- **空气净化器**:
  * 功能描述:高效过滤空气中的污染物,提供清新空气,适合家庭和办公室使用。

这里我们使用 LangChain 提供的问答链快速从我们自己的数据中获得了结果。这些数据是我们自己内部的数据,对于 LLM 是不具备的。

步骤分解

接下来让我们一步步分解来执行,看看上面的代码到底做了什么。

第一步是使用 CSVLoader 来载入外部数据。这些数据是不存在于 LLM 中,而是我们其他的内部数据库中,作为背景数据或内部知识库传递给 LLM。

loader = CSVLoader(file_path=file)
docs = loader.load()
print(docs[0])

可能会得到如下结果。

page_content='no: 1
name: 高清智能电视
description: 这款高清智能电视拥有4K超高清分辨率,内置智能系统,支持语音控制,提供丰富的娱乐体验。' metadata={'source': 'product.csv', 'row': 0}

这里使用了 CSVLoader,用来载入 csv 格式的数据。还有其他很多现成的 Loader,如 JSONLoader、HtmlLoader 等,也有很多其他的扩展,可以从 Office 文档、PDF、数据库、网盘中获取数据。

然后,用 Embeddings(嵌入)来处理字符串,这里我们使用 Ollama 的 embeddings 接口。我们初始化 OllamaEmbeddings 实例,调用其 embed_query 方法来创建词嵌入。

embeddings = OllamaEmbeddings(base_url=base_url, model=llm_model)
embed = embeddings.embed_query("你好,我的名字是火眼9988")
print(len(embed))
print(embed[:5])

我们可以看到词嵌入的结果是数千个数值的列表,我们可以保存这些向量数值,在后续使用。嵌入的过程就是将内容转换为向量数组。

3584
[0.46612900495529175, 3.102452516555786, -2.066977024078369, 0.17733854055404663, 1.7350211143493652]

在这里插入图片描述

  • 嵌入的向量数组能够“保存”原先的内容或意思。
  • 相似的文字也会获得相似的向量数组。

我们还可以使用向量数据库来保存这些向量数据。如果有一段比较长的文本,我们可以首先将它切割为数个短一点的片段,这样我们可以减少传递给 LLM 的内容大小。然后,我们对各个片段创建词嵌入,并将它们保存到向量数据库中。这就是我们创建索引的过程。

在这里插入图片描述

我们使用 from_documents 来创建向量存储。

db = DocArrayInMemorySearch.from_documents(
    docs,
    embeddings
)

然后,我们可以在运行时使用了。当新的请求进来时,先将请求进行嵌入处理,然后将向量和向量数据库中的所有数据进行比对,找出最相似的 n 条数据。我们就可以获得这些数据,并将它们添加到提示词中,提交给 LLM。

在这里插入图片描述

我们查询“智能家用电器”,让向量数据库查找最相似的数据。

query = "请选择智能家用电器"
docs = db.similarity_search(query)
print(len(docs))
print(docs[0])

会输出类似如下内容。我们看到获取了 4 条数据,第一条数据就是“智能热水器”。

4
page_content='no: 28
name: 智能热水器
description: 即开即热,智能恒温,节能环保。' metadata={'source': 'product.csv', 'row': 27}

那我们怎么使用 LLM 来查询我们自己的文档数据呢?首先,我们创建 LLM 模型,接着,将文档中的 page_content 拼接到一个字符串变量中,并将变量传递给提示词模板。最后,调用大语言模型来回答。


# 创建 Ollama LLM
llm = Ollama(base_url=base_url, model=llm_model)
# 拼接文档
qdocs = "".join([docs[i].page_content for i in range(len(docs))])
# 提问
response = llm.invoke(f"{qdocs} 问题:请找出最环保的电器?")
print(response)

可以得到类似下面的回答。

在给出的描述中,“智能热水器”因其“即开即热”和“节能环保”的特性被认为是最环保的电器。它可以在需要时快速提供热水服务,并且在设计上考虑到能源的有效利用和减少浪费,因此被评为最环保选项。

所有这些步骤都可以使用 LangChain 的链来处理。这里我们创建一条 Retrieval QA 链,我们使用下面几个参数来创建这条链。

  • llm:大语言模型,这里使用的是 Ollama 的 qwen2
  • chain_type:链类型,这里使用的是 stuff,是最简单的方式
  • retriever:是用来获取文档的接口,它接收查询并返回文档
# 创建 retriever
retriever = db.as_retriever()
# 创建问答链
qa_stuff = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    verbose=True
)
query = "请列出带有智能功能且节能环保的电器,以 Markdown 格式输出,总结它们的功能描述。"
response = qa_stuff.run(query)
print(response)

可得到类似下面的结果。

在这里插入图片描述

链的类型

上面我们在创建问答链的时候使用了 stuff 类型,具体这个有什么作用呢?又有其他哪些类型呢?

Stuff

stuff 非常简单,它将所有内容合并到一个提示词中发给 LLM,并获得一个回答。它非常简单和有效,但这里我们只有 4 个文档数据,如果我们要查询的文档数据非常庞大,我们就可以使用其他的类型。

在这里插入图片描述
优点:只有一次提问,LLM 可以一次获得所有的相关数据。
缺点:LLM 往往有长度限制,不适用于大批量的数据文档。

Map_reduce

Map_reduce 获取所有的文档片段,将它们和问题一起发送给 LLM,并获得回答。然后,发起另外的请求来总结之前的回答,并获得最终的回答。它可以处理任意数量的文档,并且可以并行处理所有的请求。但是,它需要发起多次请求,并且每个文档都认为是独立的,有时候可能并不会获得最佳的结果。
在这里插入图片描述

Refine

Refine 会逐个处理所有文档,下一个请求会基于上一个的回答。所以,它会结合多个文档之间的关联,但是它的回答会比较慢。
在这里插入图片描述

Map_rerank

Map_rerank 会给每个文档请求一次 LLM,并获得一个得分,然后选择最高的得分。类似于 map_reduce,每个文档也是独立的,因此它比较快速。但也会发起多个请求,会有较高的费用。
在这里插入图片描述

最常用的类型是 stuff,其次是 map_reduce,这个类型也可以用于其他类型的链,例如处理总结的链。

上面我们使用 LangChain 构建了一条问答链,并提供了 LLM 没有的我们自己的数据作为背景数据,这非常常用,特别是对于企业有自己的知识库的场景中。

(未完待续)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2130323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Keil MDK报错:Browse information of one or more files is not available----解决方法:

Keil MDK报错:Browse information of one or more files is not available----解决方法: 问题描述 最近在项目中遇到这样一个问题:拷贝过来添加到工程的.c文件在编译时报如下错误: 解决方案: 总结以下一些解决办法&…

PCL 读取和保存点云

目录 一、概述 1.1原理 1.2实现步骤 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更新) 一、概述 1.1原理 PCL (Point Cloud Library) 是…

开源免费的工贸一体行业ERP管理系统

引言 在当今数字化浪潮汹涌澎湃的时代,中小企业面临着前所未有的挑战与机遇。如何实现数字化转型发展,成为了众多中小企业主心头的大事。 据相关数据显示,目前我国中小企业数量已经超过了 4000 万户,然而成功实现数字化转型的比例…

单向链表之创建,插入,输出(下)

文章目录 🍊自我介绍🍊插入(下)尾插法有序插入:按照指定顺序插入 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞关注评论收藏(一键四连)哦~ 🍊自我介绍 H…

Arduino 2线串行 通信 驱动 LCD 12864

上效果图片 源代码 Arduino 328p /****************************************************************** 2线 LCD 12864 (屏幕主控芯片 ST7920)******************************************************************//***********************端口/引脚定义区域************…

Golang | Leetcode Golang题解之第401题二进制手表

题目&#xff1a; 题解&#xff1a; func readBinaryWatch(turnedOn int) (ans []string) {for i : 0; i < 1024; i {h, m : i>>6, i&63 // 用位运算取出高 4 位和低 6 位if h < 12 && m < 60 && bits.OnesCount(uint(i)) turnedOn {ans …

WPF创建不规则窗体时WebBrowser控件不显示的问题

最近有小伙伴需要在不规则窗体上放置WebBrowser控件&#xff0c;因为设置了WindowStyle"None" 和 AllowsTransparency"True"。 导致WebBrowser控件不显示。 界面代码如下所示&#xff1a; 1 <Window x:Class"WebBrowserDemo.MainWindow" …

【CTF Web】BUUCTF BUU UPLOAD COURSE 1 Writeup(文件上传+PHP+文件包含漏洞)

BUU UPLOAD COURSE 1 1 上课用~ 点击启动靶机。 解法 疑似存在文件包含漏洞。 http://15a5666e-1796-4f76-b892-0b69cf97df8e.node5.buuoj.cn:81/index.php?fileupload.php查看网页源代码。判断是后端检查。 <!DOCTYPE html> <html lang"zh-cn"> &…

区块链Dapp开发:质押挖矿的各模式开发详解

质押挖矿是区块链去中心化金融&#xff08;DeFi&#xff09;生态系统中的核心部分&#xff0c;吸引了大量用户参与。随着Dapp&#xff08;去中心化应用&#xff09;的普及&#xff0c;质押挖矿的模式多样化发展&#xff0c;不同模式各有其优点和风险。本文将介绍质押挖矿的基本…

SpringBoot快速接入OpenAI大模型(JDK8)

使用AI4J快速接入OpenAI大模型 本博文给大家介绍一下如何使用AI4J快速接入OpenAI大模型&#xff0c;并且如何实现流式与非流式的输出&#xff0c;以及对函数调用的使用。 介绍 由于SpringAI需要使用JDK17和Spring Boot3&#xff0c;但是目前很多应用依旧使用的JDK8版本&…

计算机毕业设计选题推荐-校园车辆管理系统-Java/Python项目实战(亮点:数据可视化分析、账号锁定)

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

最新版微服务项目搭建

一&#xff0c;项目总体介绍 在本项目中&#xff0c;我将使用alibabba的 nacos 作为项目的注册中心&#xff0c;使用 spring cloud gateway 做为项目的网关&#xff0c;用 openfeign 作为服务间的调用组件。 项目总体架构图如下&#xff1a; 注意&#xff1a;我的Java环境是17…

C语言-数据结构 弗洛伊德算法(Floyd)邻接矩阵存储

弗洛伊德算法相比迪杰斯特拉相似的地方都是遍历邻接矩阵不断调整最短路径的信息&#xff0c;并且两种算法面对多源最短路径的时间复杂度都是O(n^3)&#xff0c;Floyd采用的是动态规划而Dijkstra是采用贪心的思想。在Floyd中我们将创建两个数组进行辅助&#xff0c;一个path二维…

swift qwen2-vl推理及加载lora使用案例

参考: https://swift.readthedocs.io/zh-cn/latest/Instruction/LLM%E5%BE%AE%E8%B0%83%E6%96%87%E6%A1%A3.html#%E5%BE%AE%E8%B0%83%E5%90%8E%E6%A8%A1%E5%9E%8B https://blog.csdn.net/weixin_42357472/article/details/142150209 SWIFT支持300+ LLM和50+ MLLM(多模态大模型…

MySQL主从同步延时高问题排查

文章目录 背景数据库性能指标1、sysbench工具安装1.1、yum方式在线安装1.2、离线安装1.3、sysbench简介 2、主从延时过高问题排查流程2.1、登录从库查看从库状态、事务及相关进程2.2、查看服务器磁盘、cpu等信息2.3、使用fio命令压测数据盘性能2.3.1、安装fio工具2.3.2、执行磁…

element-plus组件问题汇总

element-plus组件问题汇总 一、el-select 1. 下拉选项实现添加全部 问题描述&#xff1a;value为空时&#xff0c;select框中不显示全部选项&#xff0c;但是下拉列表中全部显示是勾选状态 图片&#xff1a; 解决办法&#xff1a;添加 :empty-values“[null, undefined]” …

基于Java+Mysql实现(WEB)宿舍管理系统

数据库实践课程之宿舍管理系统 一、系统需求分析 1.1 系统描述 随着社会的发展以及教育水平的提高&#xff0c;当今社会在校生的数量越来越庞大&#xff0c;使用传统的方式对学生的信息进行管理效率非常低下。在互联网技术高度发达的今天&#xff0c;使用数据库技术对学生的…

Golang | Leetcode Golang题解之第400题第N位数字

题目&#xff1a; 题解&#xff1a; func findNthDigit(n int) int {d : 1for count : 9; n > d*count; count * 10 {n - d * countd}index : n - 1start : int(math.Pow10(d - 1))num : start index/ddigitIndex : index % dreturn num / int(math.Pow10(d-digitIndex-1)…

Redis高可用,Redis性能管理

文章目录 一&#xff0c;Redis高可用&#xff0c;Redis性能管理二&#xff0c;Redis持久化1.RDB持久化1.1触发条件&#xff08;1&#xff09;手动触发&#xff08;2&#xff09;自动触发 1.2 Redis 的 RDB 持久化配置1.3 RDB执行流程(1) 判断是否有其他持久化操作在执行(2) 父进…

Unity开发一个FPS游戏之五

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏&#xff0c;感兴趣的朋友可以回顾一下。这个系列的文章如下&#xff1a; Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…