尼恩:LLM大模型学习圣经PDF的起源
惊天大逆袭:8年小伙20天时间提75W年薪offer,逆涨50%,秘诀在这
《LLM大模型学习圣经:从0到1吃透Transformer技术底座》 《LLM大模型学习圣经:从0到1精通RAG架构,基于LLM+RAG构建生产级企业知识库》 《LLM大模型学习圣经:从0到1吃透大模型的顶级架构》
本文目录
- 尼恩:LLM大模型学习圣经PDF的起源
- 1. 大语言模型简介
- 1.1 大语言模型简介:探索AI的新边疆
- 预训练语言模型(PLM):NLP的瑞士军刀
- 大语言模型(LLM):AI进化的里程碑
- LLM与PLM:大小之间的质变
- 大语言模型的涌现能力:AI的新技能
- 大语言模型的关键技术:构建AI的基石
- 1.2 大语言模型特点
- 1. 具备涌现能力
- 2. 训练数据大且难度大:
- 3. 模型参数量大
- 4. 生成的模型大
- 5. 训练需要算力规模
- 1.3 大型语言模型四要素
- 1. 算力:AI的心脏
- 2. 算法:AI的大脑
- 3. 数据:AI的养料
- 4. 场景:AI的舞台
- 1.4 大语言模型应用
- 1. 业务流程自动化
- 2. 促进个性化交互
- 3. 提升任务准确性
- 2. 检索增强生成(RAG)
- 2.2 RAG是什么?
- 2.2.1 RAG的诞生背景
- 2.3 RAG技术概述与原理
- RAG 概述
- 2.3 RAG系统的主要组件和工作流程
- 2.3.1 RAG系统的核心组件与工作流程
- 2.3.2 RAG工作流程的全景视图
- 2.3 RAG范式
- 2.3.1 第一阶段,朴素RAG
- 2.3.2 第二阶段,高级RAG
- 2.3.3 第三阶段,模块化RAG
- 2.3.1 预检索
- 2.3.2 检索
- 2.3.3 检索后
- 2.3.4 生成
- 3. 网络爬虫与数据采集
- 使用BeautifulSoup解析HTML
- 清理HTML
- 提取文本
- 去除多余的空白和换行
- 返回处理后的文本
- 4. 向量数据库与Embedding模型
- 4.1 为什么现在每个人都在谈论矢量数据库?
- 4.2 RAG 场景对向量数据库的需求
- 4.3 如何选择向量数据库
- 4.4 向量数据库对比
- 4.5 什么是Embedding?
- 4.6 向量之间的距离
- 1. 欧几里德距离度量(Euclidean Distance)
- 2. 曼哈顿距离度量(Manhattan Distance)
- 3. 余弦距离度量(Cosine Distance)
- 4. 切比雪夫距离度量(Chebyshev Distance)
- 4.7 如何选择嵌入模型
- 常见的类Embbedding模型
- Embbedding模型在RAG种的应用场景
- 在哪里找到合适Embbedding模型?
- Embbedding模型选型
- 4.8 嵌入是如何生成的?
- 方式一:模型托管方式生成 嵌入
- 开源的嵌入模型
- 5. 实战: 基于 Langchain+私有模型,构建一个生成级RAG 聊天机器人
- 5.1 设置环境和依赖
- 5.2 初始化LLM
- 5.3 增强生成
- 5.4 生成嵌入
- 5.5 生成并存储嵌入
- 5.6 查询嵌入
- 5.7 检索增强生成
- 6. 实战: 基于 Langchain+公有模型,构建一个生成级RAG 聊天机器人
- 6.1 准备工作
- 6.2 加载配置
- 6.3 索引:加载数据
- 6.4 索引:切分数据
- 6.5 索引:生成嵌入
- 6.6 索引:存储嵌入
- 6.7 查询检索
- 生成
- 总结
- 说在最后:有问题找老架构取经
1. 大语言模型简介
1.1 大语言模型简介:探索AI的新边疆
预训练语言模型(PLM):NLP的瑞士军刀
大语言模型(LLM):AI进化的里程碑
LLM与PLM:大小之间的质变
大语言模型的涌现能力:AI的新技能
大语言模型的关键技术:构建AI的基石
1.2 大语言模型特点
1. 具备涌现能力- GPT-3(175B):
由OpenAI开发,是一个具有1750亿参数的大型语言模型。 预训练数据集包含3000亿个token,来源包括CommonCrawl、WebText2、Books1、Books2和Wikipedia。 - PaLM(540B):
由Google Research提出,是一个具有5400亿参数的多任务、多模态大型语言模型。 预训练数据集包含7800亿个token,来源包括社交媒体对话、过滤后的网页、书籍、Github、多语言维基百科和新闻。 - LLaMA:
是Meta AI提出的一种大型语言模型系列,具有不同的大小变体,从6亿参数到65亿参数不等。 训练数据来源多样,包括CommonCrawl、C4、Github、Wikipedia、书籍、ArXiv和StackExchange。 LLaMA(6B)和LLaMA(13B)使用了1万亿个token进行训练,而更大的模型版本LLaMA(32B)和LLaMA(65B)则使用了1.4万亿个token。 产生臆想的答案(幻觉):在没有确切答案的情况下,LLM可能会产生误导性信息。 知识更新慢:当用户需要基于最新情况的具体响应时,LLM可能提供过时或不具体的信息。 知识来源缺乏引用:LLM可能引用非权威来源的信息,影响回答的准确性。 术语混淆:不同训练数据中相同的术语可能指向不同概念,导致LLM产生混淆。 领域专业知识不足: 尽管LLM拥有广泛的知识基础,但它们并不了解特定业务的细节,如公司的私有数据。 避免“幻觉”问题:RAG 通过检索外部信息作为输入,获取领域特定的知识,辅助大型模型回答问题,这种方法能显著减少生成信息不准确的问题,。 信息的实时性: RAG 允许从外部数据源实时检索信息,RAG允许LLM访问最新的客户记录、产品规格和实时库存信息,解决知识时效性问题。 解决黑匣子问题:RAG技术使GenAI应用程序能够提供其使用的数据来源,增加透明度,类似于学术论文中的引用,增加回答的可追溯性。 数据隐私和安全: RAG 可以将知识库作为外部附件管理企业或机构的私有数据,避免数据在模型学习后以不可控的方式泄露。 降低应用成本:RAG提供了一种经济高效的方法,使得组织能够在不重新训练模型的情况下,提升LLM的输出质量。 白盒模型的透明度和可解释性:RAG的工作流程相对透明,模块之间的关系清晰,这为模型的效果调优和可解释性提供了优势。在检索召回的内容质量不高或置信度不足时,RAG系统有能力避免生成误导性信息,选择不生成回答而非提供错误的信息。 成本效益和响应速度:与微调模型相比,RAG的训练周期更短,成本更低。与长文本处理相比,RAG能够提供更快速的响应和更低的推理成本。在工业界和产业应用中,成本是一个至关重要的因素,而RAG在这一点上具有明显的优势。 私有数据管理与安全性:RAG通过将知识库与大型模型分离,为私有数据的管理提供了一个安全的实践基础。这种方法有助于企业更好地控制和管理其知识资产,同时解决了知识依赖问题。此外,RAG底座数据库的访问权限控制和数据管理相对容易实现,而这对于大模型来说则较为困难。 灵活性和适应性:RAG能够适应不同的数据源和检索需求,为特定领域或任务提供定制化的解决方案。这种灵活性使RAG在多种应用场景中都能找到其适用之处。 模块化和可扩展性:RAG的模块化设计允许它轻松集成新模块或调整现有模块之间的交互流程,以适应不断变化的任务需求和数据环境。 第一部分: 索引 第二部分: 检索与生成 加载:根据不同的数据源选择合适的加载器,加载数据得到文档。 切分:使用文本切分器将文档切分成更小的片段,使用小片段一方面可以更好地匹配用户问题,同时也可以适应模型的有限上下文窗口。 存储:存储和索引切片,以便在检索时能够快速找到相关的数据,通常使用 Embeddings 模型和向量数据库(VectorStore)来完成。 检索:给定用户输入,使用检索器从存储中检索相关的切片。 生成:使用包括问题和检索到的数据的提示调用 LLM 来生成答案。
1.3 大型语言模型四要素
1.4 大语言模型应用
2. 检索增强生成(RAG)
2.2 RAG是什么?
2.2.1 RAG的诞生背景
2.2.3 RAG具备性价比
2.3 RAG技术概述与原理
RAG 概述
2.3 RAG系统的主要组件和工作流程
2.3.1 RAG系统的核心组件与工作流程
2.3.2 RAG工作流程的全景视图
2.3 RAG范式
2.3.1 第一阶段,朴素RAG
2.3.2 第二阶段,高级RAG
2.3.3 第三阶段,模块化RAG
2.3.1 预检索
2.3.2 检索
搜索与排名2.3.3 检索后
2.3.4 生成
3. 网络爬虫与数据采集
import re
from typing import List, Union
import requests
from bs4 import BeautifulSoup
def html_document_loader(url: Union[str, bytes]) -> str:
"""
Loads the HTML content of a document from a given URL and return it's content.
Args:
url: The URL of the document.
Returns:
The content of the document.
Raises:
Exception: If there is an error while making the HTTP request.
"""
try:
response = requests.get(url)
html_content = response.text
except Exception as e:
print(f"Failed to load {url} due to exception {e}")
return ""
try:
# Create a Beautiful Soup object to parse html
soup = BeautifulSoup(html_content, "html.parser")
# Remove script and style tags
for script in soup(["script", "style"]):
script.extract()
# Get the plain text from the HTML document
text = soup.get_text()
# Remove excess whitespace and newlines
text = re.sub("\s+", " ", text).strip()
return text
except Exception as e:
print(f"Exception {e} while loading document")
return ""
BeautifulSoup 对象,用于解析HTML文档。"html.parser" 是指定的解析器。使用 soup(["script", "style"])找到所有的<script>和<style>标签,并通过script.extract()移除它们,因为这些标签通常包含JavaScript代码或CSS样式,而不是文档的文本内容。
使用 soup.get_text()获取HTML文档的纯文本。
使用正则表达式 re.sub("\s+", " ", text).strip()替换一个或多个空白字符(包括空格、制表符、换行符等)为单个空格,并且移除字符串首尾的空白字符。
最终,处理后的文本通过 return text返回。
4. 向量数据库与Embedding模型
4.1 为什么现在每个人都在谈论矢量数据库?
4.2 RAG 场景对向量数据库的需求
高精度的召回:向量数据库需要能够准确召回与查询语义最相关的文档或信息片段。这要求数据库能够理解和处理高维向量空间中的复杂语义关系,确保召回内容与查询的高度相关性。这里的效果既包括向量检索的数学召回精度也包括嵌入模型的语义精度。 快速响应:为了不影响用户体验,召回操作需要在极短的时间内完成,通常是毫秒级别。这要求向量数据库具备高效的查询处理能力,以快速从大规模数据集中检索和召回信息。此外,随着数据量的增长和查询需求的变化,向量数据库需要能够灵活扩展,以支持更多的数据和更复杂的查询,同时保持召回效果的稳定性和可靠性。 处理多模态数据的能力:随着应用场景的多样化,向量数据库可能需要处理不仅仅是文本,还有图像、视频等多模态数据。这要求数据库能够支持不同种类数据的嵌入,并能根据不同模态的数据查询进行有效的召回。 可解释性和可调试性:在召回效果不理想时,能够提供足够的信息帮助开发者诊断和优化是非常有价值的。因此,向量数据库在设计时也应考虑到系统的可解释性和可调试性。
4.3 如何选择向量数据库
混合搜索还是关键字搜索? 关键字+矢量搜索的混合会产生最佳结果,每个矢量数据库供应商都意识到了这一点,提供了自己的定制混合搜索解决方案 本地部署还是云原生? 许多供应商都在推销“云原生”,好像基础设施是世界上最大的痛点,但从长远来看,本地部署可以更加经济,因此也更加有效 开源还是完全托管? 大多数供应商都建立在可用源代码或开源代码库的基础上,展示其底层方法,然后将管道的部署和基础设施部分商业化化(通过完全托管的 SaaS)。仍然可以自行托管大量此类服务,但这需要额外的人力和内部技能要求。
4.4 向量数据库对比
Pinecone
优点:非常容易启动和运行(没有托管负担,它完全是云原生的),用户不需要了解有关矢量化或矢量索引的任何信息。文档也写得不错。 缺点:完全专有,如果无法在 GitHub 上跟踪他们的进展,就不可能知道幕后发生了什么以及他们的路线图上有什么。此外,某些用户的体验凸显了依赖完全外部的第三方托管服务的危险,以及从开发人员的角度来看完全缺乏对数据库设置和运行方式的控制。考虑到现有开源、自托管替代方案的数量庞大,从长远来看,依赖完全托管、闭源解决方案的成本影响可能会很大。 评价:在 2020-21 年,当矢量数据库非常不受关注时,Pinecone 远远领先于潮流,并以其他供应商没有的方式为开发人员提供了便利的功能。快进到 2023 年,坦率地说,Pinecone 现在几乎没有其他供应商提供的功能,而且大多数其他供应商至少提供自托管、托管或嵌入式模式,更不用说他们的算法的源代码了它们的底层技术对最终用户是透明的。 官方页面:pinecone.io
Weaviate
优点:优秀的文档(最好的文档之一,包括技术细节和正在进行的实验)。 Weaviate 似乎确实专注于构建尽可能最佳的开发人员体验,并且通过 Docker 启动和运行非常容易。在查询方面,它可以生成快速、亚毫秒级的搜索结果,同时提供关键字和矢量搜索功能。 缺点:因为 Weaviate 是用 Golang 构建的,所以可扩展性是通过 Kubernetes 实现的,而且当数据变得非常大时,这种方法(与 Milvus 类似)需要相当数量的基础设施资源。从长远来看,Weaviate 的完全托管产品的成本影响尚不清楚,将其性能与其他基于 Rust 的替代方案(如 Qdrant 和 LanceDB)进行比较可能是有意义的(尽管时间会告诉我们哪种方法在最具成本效益的情况下可以更好地扩展)方式)。 评价:Weaviate 拥有庞大的用户社区,并且开发团队正在积极展示极端的可扩展性(数千亿个向量),因此看起来他们的目标市场确实是拥有海量数据的大型企业。进行矢量搜索。提供关键词搜索和矢量搜索,以及强大的混合搜索,使其能够推广到各种用例,直接与 Elasticsearch 等文档数据库竞争。 Weaviate 积极关注的另一个有趣领域涉及通过向量数据库进行数据科学和机器学习,将其带出传统搜索和检索应用程序的领域。 官方页面:weaviate.io
Qdrant
优点:虽然比 Weaviate 新,但 Qdrant 也有很好的文档,可以帮助开发人员轻松地通过 Docker 启动和运行。它完全用 Rust 构建,提供开发人员可以通过 Rust、Python 和 Golang 客户端使用的 API,这些是当今后端开发人员最流行的语言。由于 Rust 的潜在功能,它的资源利用率似乎低于 Golang 中构建的替代方案。目前可扩展性是通过分区和 Raft 共识协议来实现的,这是数据库领域的标准实践。 缺点:作为一个比竞争对手相对较新的工具,Qdrant 在查询用户界面等领域一直在追赶 Weaviate 和 Milvus 等替代品,随着每个新版本的发布,这种差距正在迅速缩小。 评价:我认为 Qdrant 有望成为许多公司的首选矢量搜索后端,这些公司希望最大限度地降低基础设施成本并利用现代编程语言 Rust 的强大功能。在撰写本文时,混合搜索尚不可用,但根据他们的路线图,它正在积极开发中。此外,Qdrant 不断发布有关如何优化内存中和磁盘上的 HNSW 实施的更新,这将极大地有助于其长期的搜索准确性和可扩展性目标。很明显,根据 Qdrant的 GitHub 星级历史记录,Qdrant 的用户社区正在快速增长(有趣的是,比 Weaviate 的速度更快)!。 官方页面:qdrant.tech
Milvus/Zilliz
优点:非常成熟的数据库,具有大量算法,因为它在矢量数据库生态系统中长期存在。提供了很多矢量索引选项,并在 Golang 中从头开始构建,具有极高的可扩展性。截至 2023 年,它是唯一一家提供有效 DiskANN 实现的主要供应商,据说这是最有效的磁盘向量索引。 缺点:在我看来,Milvus 似乎是一个解决可扩展性问题的解决方案——它通过代理、负载均衡器、消息代理、Kafka 和 Kubernetes的组合实现了高度的可扩展性,这使得整个系统变得非常复杂并且资源密集。客户端 API(例如 Python)也不像 Weaviate 和 Qdrant 等较新的数据库那样可读或直观,后者往往更注重开发人员体验。 评价:Milvus 的构建理念是实现将数据流式传输到向量索引的大规模可扩展性,并且在许多情况下,当数据大小不太大时,Milvus 似乎有些过大了。对于更静态和不频繁的大规模情况,Qdrant 或 Weaviate 等替代方案可能更便宜,并且在生产中启动和运行速度更快。 官方页面:milvus.io和zilliz.com
Chroma
优点:为开发人员提供方便的 Python/JavaScript 界面,以快速启动和运行矢量存储。它是市场上第一个默认提供嵌入式模式的矢量数据库,其中数据库和应用程序层紧密集成,允许开发人员快速构建、原型化并向世界展示他们的项目。 缺点:与其他专门构建的供应商不同,Chroma 主要是围绕现有 OLAP 数据库(Clickhouse)和现有开源矢量搜索实现(hnswlib)的 Python/TypeScript 包装器。目前(截至 2023 年 6 月),它尚未实现自己的存储层。 评价:矢量数据库市场正在迅速发展,Chroma似乎倾向于采取“等待和观望”的理念,并且是少数旨在提供多种托管选项的供应商之一:无服务器/嵌入式、自托管(客户端-服务器)和云原生分布式 SaaS 解决方案,可能同时具有嵌入式和客户端-服务器模式。根据路线图,Chroma 的服务器实施正在进行中。 Chroma 引入的另一个有趣的创新领域是量化“查询相关性”的方法,即返回的结果与输入用户查询的接近程度。可视化嵌入空间(也在他们的路线图中列出)是一个创新领域,可以让数据库用于除搜索之外的许多应用程序。然而,从长远来看,我们从未见过嵌入式数据库架构在矢量搜索领域成功商业化,因此它的演变(与 LanceDB 一起,如下所述)将会很有趣! 官方页面:trychroma.com
LanceDB
优点:旨在对多模式数据(图像、音频、文本)执行分布式索引和本地搜索,构建在Lance 数据格式之上,Lance 数据格式是一种用于 ML 的创新型柱状数据格式。就像 Chroma 一样,LanceDB 使用嵌入式、无服务器架构,并且是用 Rust 从头开始构建的,因此与 Qdrant 一起,这是唯一一家利用速度 、内存安全性和相对较低的资源利用率的其他主要矢量数据库供应商。 缺点:在 2023 年,LanceDB 是一个非常年轻的数据库,因此许多功能正在积极开发中,并且由于工程团队不断壮大,直到 2024 年功能的优先级将成为一个挑战。 评价:我认为在所有矢量数据库中,LanceDB与其他数据库的区别最大。这主要是因为它在存储层本身(使用 Lance,一种比 parquet 更快的新列格式,专为非常高效的扫描而设计)和基础设施层上进行了创新 - 通过在其云版本中使用无服务器架构。结果,大量基础设施的复杂性降低,大大增加了开发人员构建以分布式方式直接连接到数据湖的语义搜索应用程序的自由度和能力。 官方页面:lancedb.com
Vespa
优点:提供最“企业就绪”的混合搜索功能,结合了久经考验的关键字搜索功能和 HNSW 之上的自定义矢量搜索。尽管 Weaviate 等其他供应商也提供关键字和矢量搜索,但 Vespa 是最早推出此产品的供应商之一,这让他们有充足的时间来优化其产品,使其变得快速、准确和可扩展。 缺点:由于应用程序层是用 Java 编写的,因此开发人员的体验不如使用 Go 或 Rust 等面向性能的语言编写的更现代的替代方案那么顺畅。此外,直到最近,它还没有使设置和拆除开发实例变得非常简单,例如通过 Docker 和 Kubernetes。 评价:Vespa 确实提供了非常好的产品,但它的应用程序主要是用 Java 构建的,而后端和索引层是用 C++ 构建的。随着时间的推移,这使得维护变得更加困难,因此,与其他替代方案相比,它往往会给开发人员带来不太友好的感觉。如今,大多数新数据库完全是用一种语言编写的,通常是 Golang 或 Rust,而且 Weaviate、Qdrant 和 LanceDB 等数据库的算法和架构创新速度似乎要快得多。 官方页面:vespa.ai
Vald
优点:旨在通过高度分布式架构处理多模式数据存储,以及索引备份等有用功能。使用非常快的 ANN 搜索算法 NGT(邻域图和树),当与高度分布的向量索引结合使用时,该算法是最快的 ANN 算法之一。 缺点:似乎比其他供应商的整体吸引力和使用量要少得多,并且文档没有清楚地描述使用什么矢量索引(“分布式索引”相当模糊)。它似乎也完全由一个实体——雅虎!日本,关于其他主要用户的信息很少。 评价:我认为 Vald 是一个比其他供应商更小众的供应商,主要迎合 Yahoo!日本的搜索要求较高,并且总体上用户社区要小得多,至少从 GitHub 上的星数来看是这样。部分原因可能是它的总部位于日本,营销力度不如欧盟和湾区其他地位较高的供应商。 官方页面:vald.vdaas.org
Elasticsearch、Redis 和 pgvector
优点:如果您已经在使用 Elasticsearch、Redis 或 PostgreSQL 等现有数据存储,那么利用它们的矢量索引和搜索产品非常简单,而无需求助于新技术。 缺点:现有数据库不一定以最佳方式存储或索引数据,因为它们被设计为通用目的,因此,对于涉及百万级矢量搜索及以上的数据,性能会受到影响。 Redis VSS(矢量搜索存储)之所以快,主要是因为它纯粹在内存中,但当数据变得大于内存时,就有必要考虑替代解决方案。 评价:我认为专用矢量数据库将在需要语义搜索的领域慢慢超越现有数据库,这主要是因为它们在矢量搜索方面最关键的组件(存储层)上进行创新。像 HNSW 和 ANN 算法这样的索引方法在文献中有详细记录,大多数数据库供应商都可以推出自己的实现,但是专门构建的向量数据库具有针对手头任务进行优化的优点(更不用说它们是使用 Go 和 Rust 等现代编程语言编写),并且出于可扩展性和性能的原因,从长远来看,它很可能会在这个领域胜出。
4.5 什么是Embedding?
{
"word": "Valentine's Day",
"vector": [0.12, 0.75, -0.33, 0.85, 0.21, ...etc...]
}
Embedding的重要性何在呢?
4.6 向量之间的距离
欧几里德距离度量 曼哈顿距离度量 余弦距离度量 切比雪夫距离度量。
1. 欧几里德距离度量(Euclidean Distance)
2. 曼哈顿距离度量(Manhattan Distance)
3. 余弦距离度量(Cosine Distance)
4. 切比雪夫距离度量(Chebyshev Distance)
4.7 如何选择嵌入模型
常见的类Embbedding模型检索用Embbedding 重排序用Embbedding
知识库存入向量数据库之前,需要使用Embbedding模型 用户提问时的问题,需要使用使用Embbedding模型 检索完成之后重排序的时候,需要 Rank Embbedding模型
Retrieval Average: NDCG是衡量检索系统性能的常用指标。 NDCG 较高表示模型能够更好地在检索结果列表中将相关项目排名靠前。 模型大小:模型的大小(以 GB 为单位)。它给出了运行模型所需的计算资源的概念。虽然检索性能随模型大小而变化,但值得注意的是,模型大小也会对延迟产生直接影响。在生产设置中,延迟与性能的权衡变得尤为重要。 最大令牌数:可以压缩为单个嵌入的令牌数。您通常不想放置超过一个文本段落(~100 个代币) 到单个嵌入中。因此,即使模型的最大令牌数为 512,也应该绰绰有余。 Embbedding维度:嵌入向量的长度。较小的嵌入可提供更快的推理,并且存储效率更高,而更多的维度可以捕获数据中的细微细节和关系。最终,我们希望在捕获数据的复杂性和运营效率之间取得良好的权衡。 支持的语言 (Languages): 中文 (zh),英文 (en) 等
4.8 嵌入是如何生成的?
sentence-transformers,可通过Hugging Face 模型中心或直接从源代码库获取curl -X POST https://xxx -d '{ "input": ["推荐一些美食","给我讲个故事"]}'
输入文本以获取embeddings说明:
(1)文本数量不超过16
(2)每个文本token数不超过512且长度不超过2000个字符
(3)输入文本不能为空,如果为空会报错
[
{
"object": "embedding",
"embedding": [
0.018314670771360397,
0.00942440889775753,
...(共384个float64)
-0.36294862627983093
],
"index": 0
}
]
curl -X POST http://xxxx -d '{"query": "上海天气","documents":["上海气候", "北京美食"]}
开源的嵌入模型[
{
"document": "上海气候",
"relevance_score": 0.7059729695320129,
"index": 0
},
{
"document": "北京美食",
"relevance_score": 0.4241394102573395,
"index": 1
}
]
get_embeddings 的函数,它使用 OpenAI API 来生成文本的嵌入表示。
def get_embeddings(docs: List[str], model: str="text-embedding-3-large") -> List[List[float]]:
"""
使用 OpenAI API 生成嵌入。
参数:
docs (List[str]): 要生成嵌入的文本列表
model (str, optional): 模型名称。默认为 "text-embedding-3-large"。
返回:
List[float]: 嵌入的数组
"""
# 替换换行符,它们可能会对性能产生负面影响
docs = [doc.replace("\n", " ") for doc in docs]
# 调用 OpenAI API 来获取嵌入
response = openai_client.embeddings.create(input=docs, model=model)
# 提取响应中的嵌入数据
response = [r.embedding for r in response.data]
# 返回嵌入数据
return response
```
from typing import List
from transformers import AutoModel, AutoTokenizer
import torch
# 用户查询中要追加的指令,以改善检索结果
RETRIEVAL_INSTRUCT = "Represent this sentence for searching relevant passages:"
# 检查 CUDA(GPU 支持)是否可用,并相应地设置设备
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
# 从 Hugging Face 加载 UAE-Large-V1 模型
model = AutoModel.from_pretrained('WhereIsAI/UAE-Large-V1').to(device)
# 加载与 UAE-Large-V1 模型关联的分词器
tokenizer = AutoTokenizer.from_pretrained('WhereIsAI/UAE-Large-V1')
# 装饰器,用于禁用梯度计算
@torch.no_grad()
def get_embeddings(docs: List[str], input_type: str) -> List[List[float]]:
"""
使用 UAE-Large-V1 模型获取嵌入。
参数:
docs (List[str]): 要嵌入的文本列表
input_type (str): 要嵌入的输入类型。可以是 "document" 或 "query"。
返回:
List[List[float]]: 嵌入的数组
"""
# 如果是查询类型,则在查询前追加检索指令
if input_type == "query":
docs = ["{}{}".format(RETRIEVAL_INSTRUCT, q) for q in docs]
# 对输入文本进行分词
inputs = tokenizer(docs, padding=True, truncation=True, return_tensors='pt', max_length=512).to(device)
# 将分词后的输入传递给模型,并获取最后一个隐藏状态
last_hidden_state = model(**inputs, return_dict=True).last_hidden_state
# 从最后一个隐藏状态中提取嵌入
embeddings = last_hidden_state[:, 0]
# 返回嵌入,从 GPU 转移到 CPU 并转换为 NumPy 数组
return embeddings.cpu().numpy()
```
5. 实战: 基于 Langchain+私有模型,构建一个生成级RAG 聊天机器人
5.1 设置环境和依赖
use python 3.10
pip installfastembed==0.1.3 chromadb==0.4.22 langchain==0.1.8wikipedia==1.4.0 ollama
5.2 初始化LLM
from langchain_community.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
llm = Ollama(
model="llama3",
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
)
llm.invoke("英伟达公布2024二季度营收多少亿美元?")
According to my knowledge, InVite (英伟达) is a Chinese company that specializes in electric vehicles. As of now, I couldn't find any reliable sources confirming their 2024 Q2 revenue.
However, if you're interested in knowing the previous quarterly or annual revenues for InVite, I can try searching for those. ?
Please let me know what specific information you're looking for, and I'll do my best to help! ?
5.3 增强生成
context),并要求 LLM 使用该上下文来回答问题。from langchain.prompts import PromptTemplate
template = """你是一个机器人,使用提供的上下文来回答问题。如果你不知道答案,只需简单地说明你不知道。.
{context}
Question: {input}"""
prompt = PromptTemplate(
template=template, input_variables=["context", "input"]
)
prompt.format(
context="英伟达公布2024财年第二财季季报。二季度营收135.07亿美元",
input="英伟达公布2024二季度营收多少亿美元?"
)
'你是一个机器人,使用提供的上下文来回答问题。如果你不知道答案,只需简单地说明你不知道。.\n\n英伟达公布2024财年第二财季季报。二季度营收135.07亿美元\n\nQuestion: 英伟达公布2024二季度营收多少亿美元?'
llm.invoke(
prompt.format(
context="英伟达公布2024财年第二财季季报。二季度营收135.07亿美元",
input="英伟达公布2024二季度营收多少亿美元?"
)
)
根据上下文,英伟达公布的2024二季度营收是135.07亿美元。
5.4 生成嵌入
PyPDFLoader:from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("AIGC行业深度报告(11).pdf")
docs = loader.load()
print(len(docs))
print(docs[1].page_content)
Document包含整个页面的 LangChain。正如我们上面所讨论的,我们将把页面分成块。实现此目的的一种方法是使用RecursiveCharacterTextSplitter遍历文本并提取一定长度的块,每个块之间可以选择重叠:text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 1000,
chunk_overlap= 200,
length_function = len,
is_separator_regex = False,
)
data = text_splitter.split_documents(docs)
data[:3]
[Document(page_content='华西计算机团队\n2023年10月9日华为算力分拆 : 全球AI算力的第二极\n请仔细阅读在本报告尾部的重要法律声明\n仅供机构投资者使用\n证券研究报告 |行业深度研究报告\n分析师:刘泽晶\nSAC NO:S1120520020002\n邮箱: 行业深度报告 (11)', metadata={'source': 'AIGC行业深度报告(11).pdf', 'page': 0}),
Document(page_content='核心逻辑 :\n\uf075全面对标英伟达,华为开启国产自主可控新征程 。我们认为英伟达作为全球 AI算力芯片龙头坐拥三大法宝,分别是高性能芯片、其中 IC设计\n是重点, CUDA 架构、助力 AI加速计算生态, Nvlink 、NVSwitch 助力芯片快速互联互通与 InfiniBand 配合组网技术实现高效互联互通;而华\n为作为国产计算之光全面对标英伟达,在算力方面, 昇腾910芯片单卡算力已经可以与英伟达 A100 相媲美;统一达芬奇架构助力 AI计算引擎;\nHCCS 互联技术,实现卡间高速互联 。\n\uf075华为构筑世界 AI算力第二选择 : 全连接大会上,华为发布多款 AI产品,为世界 AI算力第二选择。 华为Atlas 900 SuperCluster 、全新的华为\n星河AI智算交换机亮相,打开国产算力集群想象空间,同时 发布“三力四总线”,打造智能世界数字基础大设施,此外发布星河 AI网络解决\n方案,以高运力释放 AI时代的高算力;软件方面,华为携手基础软硬件创新,开启国产 AI生态;华为鲲鹏、昇腾、 AI助力国产千行百业数字\n化升级,包括金融、智能制造、工业、教育、医疗等方面。\n\uf075为领衔演绎国产 AI计算产业崛起 : 我们认为华为 AI计算产业的核心在于芯片的自主可控,其中以鲲鹏和昇腾为主导的海思芯片尤为重要,因此\n与之相关的国产集成电路产业突围尤为重要,其中重中之重是 EDA 、光刻、代工产业; AI与信创双轮驱动,国产服务器需求火爆, AI 服务\n器中的主要元器件包括 CPU 、GPU 板组、内存、硬盘、网络接口卡组成,配合电源、主板、机箱、散热系统等基础硬件以提供信息服务,\n计算服务器基础硬件供应商和华为生态伙伴也将迎来发展机遇;算力组网方面,华为有望带动相关产品快速放量,其中包括国产 AI服务器、\n交换机、光模块等产品,此外,在算网的趋势下,网络可视化将迎来黄金发展周期。\n\uf075投资建议: 受益标的: EDA:华大九天、概伦电子、广立微 等;光刻: 福晶科技、奥普光电、苏大维格、美埃科技、腾景科技 等;PCB:沪\n电股份、胜宏科技 等;内存接口: 澜起科技、聚辰股份 等;连接器: 华丰科技、鼎通科技 等;BIOS :卓易信息 等;电源: 杰华特、欧陆通、', metadata={'source': 'AIGC行业深度报告(11).pdf', 'page': 1}),
Document(page_content='交换机、光模块等产品,此外,在算网的趋势下,网络可视化将迎来黄金发展周期。\n\uf075投资建议: 受益标的: EDA:华大九天、概伦电子、广立微 等;光刻: 福晶科技、奥普光电、苏大维格、美埃科技、腾景科技 等;PCB:沪\n电股份、胜宏科技 等;内存接口: 澜起科技、聚辰股份 等;连接器: 华丰科技、鼎通科技 等;BIOS :卓易信息 等;电源: 杰华特、欧陆通、\n中国长城 等;服务器: 拓维信息、神州数码、天源迪科、四川长虹、高新发展 等;光模块: 天孚通信,剑桥科技、太辰光、中际旭创 等;网\n络可视化: 恒为科技、浩瀚深度、中新赛克 等;操作系统: 润和软件、测绘股份、中国 软件、麒麟信安、诚迈科技 等;技术开发: 软通动力、\n常山北明 等;传统应用: 海量数据、超图软件、赛意信息 等;AI应用: 润达医疗、云鼎科技、梅安森、万达信息、龙软科技、金山办公、梦\n网科技 等。\n\uf075风险提示 : 核心技术水平升级不及预期的风险、 AI伦理风险、政策推进不及预期的风险、中美贸易摩擦升级的风险。2', metadata={'source': 'AIGC行业深度报告(11).pdf', 'page': 1})]
5.5 生成并存储嵌入
from langchain.vectorstores import Chroma
#from langchain.embeddings import OpenAIEmbeddings
from langchain_community.embeddings.fastembed import FastEmbedEmbeddings
embeddings = FastEmbedEmbeddings(model_name="BAAI/bge-base-en-v1.5")
store = Chroma.from_documents(
data,
embeddings,
ids = [f"{item.metadata['source']}-{index}" for index, item in enumerate(data)],
collection_name="AIGC-report-Embeddings",
persist_directory='db',
)
store.persist()
5.6 查询嵌入
k。result = store.similarity_search(
query="英伟达公布2024二季度营收多少亿美元?",
k=10
)
[doc.page_content for doc in result]
['1.1 全球龙头英伟达业绩持续高度景气,印证全球 AI产业趋势\n\uf075英伟达二季度业绩持续超预期 ,印证AI景气度: 美东时间 8月23日,英伟达公布 2024 财年第二财季季报 。二季度营收 135.07亿美元 ,同\n比增长 101%,远超市场预期的指引区间 107.8亿到112.2亿美元 ,相较于华尔街预期 水平 高22%-29%以上 。业绩指引方面 ,英伟达预计 ,\n本季度 、即2024 财年第三财季营业收入为 160亿美元 ,正负浮动 2%,相当于指引范围在 156.8亿到163.2亿美元之间 。以160亿美元计\n算,英伟达预期三季度营收将同比增长 170%,连续两个季度翻倍增长 ,高于市场预期 。\n\uf075AI芯片所在业务同环比均翻倍激增较市场预期高近 30%,游戏业务同比重回增长 :AI对英伟达业绩的贡献突出 。包括AI显卡在内的英伟\n达核心业务数据中心同样收入翻倍激增 ,二季度数据中心营业收入为 103.2亿美元 ,同比增长 171%,环比增长 141%;二季度游戏营收\n24.9亿美元 ,同比增长 22%,环比增长 11%,英伟达称 ,数据中心收入主要来自云服务商和大型消费类互联网公司 。基于Hopper 和A\nmpere 架构GPU 的英伟达 HGX 平台之所以强劲需求 ,主要源于开发生成式 AI和大语言模型的推动 。\n5 资料来源:techpowerup ,Bloomberg ,英伟达官网 ,英伟达2023财年年报, 新浪,华西证券 研究所产品实现云、边、端全面布局\n云端\n•GPU 加速云计算( 在云端完\n成计算 )\n•Omniverse Cloud :自部署云\n容器 、托管服务终端\n•游戏: 驱动器、 Reflex 、G-SYNC 显示器\n•可视化: 虚拟工作站 、NVIDIA RTXDI 光\n线追踪等\n•智能驾驶: 舱内智能服务软件、地图软件、\n辅助驾驶平台等边缘计算\n•Jetson 嵌入式系统: Orin 系列 、\nXavier 系列 、TX2系列 、Nano (在\n数据源或数据源附近完成计算 )',
'目录\n301 全面对标英伟达,开启国产自主可控新征程\n02 华为领衔演绎国产 AI计算产业崛起\n03投资建议 : 梳理AIGC 相关受益厂商\n04风险提示',
.....................
']
5.7 检索增强生成
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
retriever = store.as_retriever(search_kwargs={
'k': 10
})
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
chain = create_retrieval_chain(retriever, combine_docs_chain)
result = chain.invoke({
"input": "英伟达公布2024二季度营收多少亿美元?"
})
According to the text, NVIDIA announced its 2024 second quarter revenue as $135.07 billion, with a year-over-year growth of 101%.
6. 实战: 基于 Langchain+公有模型,构建一个生成级RAG 聊天机器人
6.1 准备工作
安装 Python:建议使用 Python 3.8 或更高版本,这是当前许多现代 Python 库和框架的通用要求。 安装依赖:使用 pip 安装 LangChain 及其相关依赖pip install --upgrade --quiet langchain langchain-community langchainhub langchain-openai 获取 OpenAI 密钥:这里选择使用 OpenAI 的 GPT 系列模型作为我们的 LLM。所以需要注册一个 OpenAI 账号,然后创建一个 API 密钥。 注册 LangSmith (可选):使用 LangSmith,可以对 LangChain 的调用进行跟踪和分析,强烈建议使用。
6.2 加载配置
.env 文件进行加载,同时记得在 .gitignore 中排除这个文件,避免将敏感信息泄霩。# .env
OPENAI_API_KEY="sk-xxx"
# OPENAI_API_BASE="https://api.openai.com/v1"
# LANGCHAIN_TRACING_V2=true
# LANGCHAIN_API_KEY=xxx
from dotenv import load_dotenv
dotenv.load_dotenv()
6.3 索引:加载数据
pip install pypdf
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("https://arxiv.org/pdf/2402.16480.pdf")
docs = loader.load()
print(len(docs))
print(docs[0].page_content)
PyPDFLoader 来加载一个 PDF 文件,然后打印出了文档的长度和第一页的内容。PyPDFLoader 默认不处理图片,如果需要提取图片,可以借助 rapidocr-onnxruntime 库:pip install rapidocr-onnxruntime
loader = PyPDFLoader("https://arxiv.org/pdf/2402.16480.pdf", extract_images=True)
PyPDFLoader,LangChain 还提供了其他针对不同类型 PDF 文件的加载器,比如 MathpixPDFLoader、UnstructuredPDFLoader等具体实现,可以根据实际情况选择,详细介绍可以参考官方文档。6.4 索引:切分数据
RecursiveCharacterTextSplitter 切分文档:from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
splits = text_splitter.split_documents(docs)
print(len(splits))
print(splits[0].page_content)
print(splits[0].metadata)
RecursiveCharacterTextSplitter 来切分文档,然后打印出了切分后的切片数量、第一个切片的内容和元数据。RecursiveCharacterTextSplitter 时,我们可以使用 chunk_size 来控制切分的粒度,chunk_overlap 来控制切片的重叠,重叠的部分可以保证切片之间的上下文连贯性。add_start_index 来控制是否在切片的元数据中添加起始索引。RecursiveCharacterTextSplitter 来切分代码,可以通过结合 Language 类来实现:from langchain_text_splitters import (
Language,
RecursiveCharacterTextSplitter,
)
python_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
RecursiveCharacterTextSplitter,LangChain 还提供了其他针对不同类型文档或者不同切分方式的切分器,比如:MarkdownHeaderTextSplitter用于通过指定标题切分 Markdown 文件RecursiveJsonSplitter用于切分 JSON 文件CharacterTextSplitter用于通过指定分隔符切分文本
6.5 索引:生成嵌入
OpenAIEmbeddings 嵌入文档切片:from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
embedded_query = embedding.embed_query("What was the name mentioned in the conversation?")
print(embedded_query[:5])
[0.005384807424727807, -0.0005522561790177147, 0.03896066510130955, -0.002939867294003909, -0.008987877434176603]
OpenAIEmbeddings 来嵌入查询,然后打印出了嵌入后的前 5 个元素。embed_query 和 embed_documents 两个方法,分别用于嵌入查询和文档切片。因为不同的嵌入器可能会针对文档和查询提供不同的实现。6.6 索引:存储嵌入
ChromaVectorStore 存储嵌入后的 embeddings:from langchainhub.vectorstores import ChromaVectorStore
vectorstore = Chroma.from_documents(documents=splits, embedding=embedding)
query = "如何在开源项目中使用 ChatGPT ?"
docs = vectorstore.similarity_search(query)
print(docs[0].page_content)
Chroma 来存储嵌入后的 embeddings,然后使用 similarity_search 方法通过查询文本检索数据。这里需要留意的是,虽然原始的 PDF 文档是英文,而代码中的查询是中文,但依然可以查询到相关文档,这就是语义搜索的魅力。除了 similarity_search,我们还可以使用 similarity_search_by_vector 直接通过向量检索数据。6.7 查询检索
| 名称 | 索引类型 | 使用LLM | 使用时机 | 描述 |
VectorStoreRetriever 检索数据:retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 6})
query = "如何在开源项目中使用 ChatGPT ?"
docs = retriever.invoke(query)
print(len(docs))
print(docs[0].page_content)
vectorstore 创建了一个检索器,并且指定 search_type="similarity" 表示使用相似度检索,,search_kwargs={"k": 6} 表示最多返回 6 个结果,然后调用 invoke 方法检索数据。生成
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 从 Hub 中加载 RAG Prompt
prompt = hub.pull("rlm/rag-prompt")
# 使用 OpenAI 的 gpt-3.5-turbo 模型
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
# 格式化文档
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 构建 chain
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# 以流的方式生成答案
for chunk in rag_chain.stream("What is Task Decomposition?"):
print(chunk, end="", flush=True)
ChatOpenAI 来加载 OpenAI 的 gpt-3.5-turbo 模型,然后构建了一个 chain,其中包含了检索、格式化、提示和生成等步骤。最后以流的方式生成答案。代码中涉及到的关键概念有:hub.pull:从 Hub 中加载 RAG Prompt,Hub 是 LangChain 提供的一个中心化的模型仓库,可以方便地获取和分享模型。|:管道操作符,用于连接多个 Runnable。基于 LangChain Expression Language (LCEL) 的语法,可以方便地构建复杂的 chain,类似于 Unix 管道。LCEL 提供了非常多的特性,包括异步、批量执行、并发执行、流式、重试和回退等,在我看来就是 LangChain 的精髓所在,详细介绍可以参考官方文档。RunnablePassthrough:一个简单的 Runnable,用于传递输入StrOutputParser:一个简单的 OutputParser,用于将输出转换成字符串stream:以流的方式生成答案
ChatModel 和 LLM。前者接收聊天消息列表返回单个聊天消息,比如我们上面代码中使用的 ChatOpenAI;后者接收一个字符串返回一个字符串。这两种抽象可以根据实际情况选择,详细对比和介绍可以参考官方文档。总结
说在最后:有问题找老架构取经
《LLM大模型学习圣经:从0到1吃透Transformer技术底座》 《LLM大模型学习圣经:从0到1精通RAG架构,基于LLM+RAG构建生产级企业知识库》 《LLM大模型学习圣经:从0到1吃透大模型的顶级架构》
Netty 学习圣经:穿透Netty的内存池和对象池(那个超级难,很多人穷其一生都搞不懂), DDD学习圣经: 穿透 DDD的建模和落地, Caffeine学习圣经:比如Caffeine的底层架构, 比如高性能葵花宝典 Thread Local 学习圣经 等等等等。
