Chat Towards Data Science|如何用个人数据知识库构建 RAG 聊天机器人?

news2024/11/15 7:11:16

生成式人工智能时代,开发者可以借助大语言模型(LLM)开发更智能的应用程序。然而,由于有限的知识,LLM 非常容易出现幻觉。检索增强生成(RAG)https://zilliz.com/use-cases/llm-retrieval-augmented-generation 通过为 LLM 补充外部知识,有效地解决了这一问题。

在 Chat Towards Data Science 博客系列中,我们将详细介绍如何使用个人的数据知识库构建 RAG 聊天机器人。本文是该系列的第一部分,将为大家介绍如何创建一个用于 Towards Data Science https://towardsdatascience.com/ 网站的聊天机器人,如何利用网页抓取数据、创建存储在 Zilliz Cloud https://zilliz.com.cn/ 上的知识库。

01.使用 BeautifulSoup4 抓取网页数据

所有机器学习(ML)项目的第一步都是收集所需的数据。本项目中,我们使用网页抓取技术来收集知识库数据。用 requests 库获取网页并使用 BeautifulSoup4.从网页中提取信息、解析 HTML 信息并提取段落。

导入 BeautifulSoup4 和 Requests 库进行网页抓取

运行 pip install beautifulsoup4 sentence-transformers安装 BeautifulSoup 和 Sentence Transformers。在数据抓取部分只需要导入requests和 BeautifulSoup。接下来,创建一个 dictionary,其中包含我们要抓取的 URL 格式。在本示例中,我们只从 Towards Data Science 抓取内容,同理也可以从其他网站抓取。

现在,用以下代码所示的格式从每个存档页面获取数据:

import requests
from bs4 import BeautifulSoup
urls = {
    'Towards Data Science''<https://towardsdatascience.com/archive/{0}/{1:02d}/{2:02d}>'
    }

此外,我们还需要两个辅助函数来进行网页抓取。第一个函数将一年中的天数转换为月份和日期格式。第二个函数从一篇文章中获取点赞数。

天数转换函数相对简单。写死每个月的天数,并使用该列表进行转换。由于本项目仅抓取 2023 年数据,因此我们不需要考虑闰年。如果您愿意,可以根据不同的年份进行修改每个月天数。

点赞计数函数统计 Medium 上文章的点赞数,单位为 “K” (1K=1000)。因此,在函数中需要考虑点赞数中的单位“K”。

def convert_day(day):
    month_list = [312831303130313130313031]
    m = 0
    d = 0
    while day > 0:
        m += 1
        d = day
        day -= month_list[m-1]
    return (m, d)

def get_claps(claps_str):
    if (claps_str is Noneor (claps_str == ''or (claps_str.split is None):
        return 0
    split = claps_str.split('K')
    claps = float(split[0])
    return int(claps*1000if len(split) == 2 else int(claps)

解析 BeautifulSoup4 的网页抓取响应

现在已经设置好必要的组件,可以进行网页抓取。为了避免在过程中遇到 429 错误(请求过多),我们使用 time 库,在发送请求之间引入延迟。此外,用 sentence transformers 库从 Hugging Face 获取 embedding 模型—— MiniLM 模型。

如前所述,我们只抓取了 2023 年的数据,所以将年份设置为 2023。此外,只需要从第 1 天(1 月 1 日)到第 244 天(8 月 31 日)的数据。根据设定的天数进行循环,每个循环在第一次调用time.sleep()之前会首先设置必要的组件。我们会把天数转换成月份和日期,并转成字符串,然后根据 urls 字典组成完整的 URL,最后发送请求获取 HTML 响应。

获取 HTML 响应之后,使用 BeautifulSoup 进行解析,并搜索具有特定类名(在代码中指示)的div元素,该类名表示它是一篇文章。我们从中解析标题、副标题、文章 URL、点赞数、阅读时长和回应数。随后,再次使用requests来获取文章的内容。每次通过请求获取文章内容后,都会再次调用time.sleep()。此时,我们已经获取了大部分所需的文章元数据。提取文章的每个段落,并使用我们的 HuggingFace 模型获得对应的向量。接着,创建一个字典包含该文章段落的所有元信息。

import time
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("sentence-transformers/all-MiniLM-L12-v2")
data_batch = []
year = 2023
for i in range(1243):
    month, day = convert_day(i)
    date = '{0}-{1:02d}-{2:02d}'.format(year, month, day)
    for publication, url in urls.items():
        response = requests.get(url.format(year, month, day), allow_redirects=True)
        if not response.url.startswith(url.format(year, month, day)):
            continue
        time.sleep(8)
        soup = BeautifulSoup(response.content, 'html.parser')
        articles = soup.find_all("div","postArticle postArticle--short js-postArticle js-trackPostPresentation js-trackPostScrolls")
        for article in articles:
            title = article.find("h3", class_="graf--title")
            if title is None:
                continue
            title = str(title.contents[0]).replace(u'\\\\xA0'u' ').replace(u'\\\\u200a'u' ')
            subtitle = article.find("h4", class_="graf--subtitle")
            subtitle = str(subtitle.contents[0]).replace(u'\\\\xA0'u' ').replace(u'\\\\u200a'u' 'if subtitle is not None else ''
            article_url = article.find_all("a")[3]['href'].split('?')[0]
            claps = get_claps(article.find_all("button")[1].contents[0])
            reading_time = article.find("span", class_="readingTime")
            reading_time = int(reading_time['title'].split(' ')[0]) if reading_time is not None else 0
            responses = article.find_all("a", class_="button")
            responses = int(responses[6].contents[0].split(' ')[0]) if len(responses) == 7 else (0 if len(responses) == 0 else int(responses[0].contents[0].split(' ')[0]))
            article_res = requests.get(article_url)
            time.sleep(8)
            paragraphs = BeautifulSoup(article_res.content, 'html.parser').find_all("[class*=\\\\"pw-post-body-paragraph\\\\"]")
            for i, paragraph in enumerate(paragraphs):
                embedding = model.encode([paragraph.text])[0].tolist()
                data_batch.append({
                    "_id"f"{article_url}+{i}",
                    "article_url": article_url,
                    "title": title,
                    "subtitle": subtitle,
                    "claps": claps,
                    "responses": responses,
                    "reading_time": reading_time,
                    "publication": publication,
                    "date": date,
                    "paragraph": paragraph.text,
                    "embedding": embedding
                })

最后一步是使用 pickle 处理文件。

filename = "TDS_8_30_2023"
with open(f'{filename}.pkl''wb'as f:
    pickle.dump(data_batch, f)

数据呈现

数据可视化十分有用。下面是在 Zilliz Cloud 中数据的样子。请注意其中的 embedding,这些数据表示了文档向量,也就是我们根据文章段落生成的向量。

alt

02.将 TDS 数据导入到向量数据库中

获取数据后,下一步是将其导入到向量数据库中。在本项目中,我们使用了一个单独的 notebook 将数据导入到 Zilliz Cloud,而不是从 Towards Data Science 进行网页抓取。

要将数据插入 Zilliz Cloud,需按照以下步骤进行操作:

  • 连接到 Zilliz Cloud

  • 定义 Collection 的参数

  • 将数据插入 Zilliz Cloud

设置 Jupyter Notebook

运行 pip install pymilvus python-dotenv 来设置 Jupyter Notebook 并启动数据导入过程。用 dotenv 库来管理环境变量。对于pymilvus包,需要导入以下模块:

  • utility 用于检查集合的状态

  • connections 用于连接到 Milvus 实例

  • FieldSchema 用于定义字段的 schema

  • CollectionSchema 用于定义 collection schema

  • DataType 字段中存储的数据类型

  • Collection 我们访问 collection 的方式

然后,打开之前 pickle 的数据,获取环境变量,并连接到 Zilliz Cloud。

import pickle
import os
from dotenv import load_dotenv
from pymilvus import utility, connections, FieldSchema, CollectionSchema, DataType, Collection


filename="TDS_8_30_2023"
with open(f'{filename}.pkl''rb'as f:
    data_batch = pickle.load(f)

zilliz_uri = "your_zilliz_uri"
zilliz_token = "your_zilliz_token"
connections.connect(
    uri= zilliz_uri,
    token= zilliz_token
)

设置 Zilliz Cloud 向量数据库并导入数据

接下来,需要设置 Zilliz Cloud。我们必须创建一个 Collection 来存储和组织从 TDS 网站抓取的数据。需要两个常量:dimension(维度)和 collection name(集合名称),dimension 是指我们的向量具有的维度数。在本项目中,我们使用 384 维的 MiniLM 模型。

Milvus 的全新 Dynamic schema https://milvus.io/docs/dynamic_schema.md#Dynamic-Schema 功能允许我们仅为 Collection 设置 ID 和向量字段,无需考虑其他字段数量和数据类型。注意,需要记住保存的特定字段名称,因为这对于正确检索字段至关重要。

DIMENSION=384
COLLECTION_NAME="tds_articles"
fields = [
    FieldSchema(name='id', dtype=DataType.VARCHAR, max_length=200, is_primary=True),
    FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, dim=DIMENSION)
]
schema = CollectionSchema(fields=fields, enable_dynamic_field=True)
collection = Collection(name=COLLECTION_NAME, schema=schema)
index_params = {
    "index_type""AUTO_INDEX",
    "metric_type""L2",
    "params": {"nlist"128},
}
collection.create_index(field_name="embedding", index_params=index_params)

Collection 有两种插入数据的选项:

  • 遍历数据并逐个插入每个数据

  • 批量插入数据

在插入所有数据之后,重要的是刷新集合以进行索引并确保一致性,导入大量数据可能需要一些时间。

for data in data_batch:
    collection.insert([data])
collection.flush()

03.查询 TDS 文章片段

一切准备就绪后,就可以进行查询了。

获取 HuggingFace 模型并设置 Zilliz Cloud 查询

注意,必须获取 embedding 模型并设置向量数据库以查询 Towards Data Science 知识库。这一步使用了一个单独的笔记本。我们将使用dotenv库来管理环境变量。此外,还需要使用 Sentence Transformers 中的 MiniLM 模型。这一步中,可以重用 Web Scraping 部分提供的代码。

import os
from dotenv import load_dotenv
from pymilvus import connections, Collection


zilliz_uri = "your_zilliz_uri"
zilliz_token = "your_zilliz_token"


from sentence_transformers import SentenceTransformer


model = SentenceTransformer("sentence-transformers/all-MiniLM-L12-v2")

执行向量搜索查询

连接到向量数据库并执行搜索。在本项目中,我们将连接到一个 Zilliz Cloud 实例,并检索之前创建的集合 tds_articles,用户要先输入他们的查询问题。

接下来,使用 Hugging Face 的 embedding 模型对查询进行编码。这个过程将用户的问题转换为一个 384 维的向量。然后,使用这个编码后的查询向量来搜索向量数据库。在搜索过程中,需要指定进行 ANN 查询字段(anns_field)、索引参数、期望的搜索结果数量限制以及我们想要的输出字段(output fields)。

之前,我们用了 Milvus 的 Dynamic Schema 特性来简化字段 Schema 定义流程。搜索向量数据库时,包括所需的动态字段在搜索结果中是必要的。这个特定的场景涉及请求paragraph字段,其中包含文章中每个段落的文本。

connections.connect(uri=zilliz_uri, token=zilliz_token)
collection = Collection(name="tds_articles")
query = input("What would you like to ask Towards Data Science's 2023 publications up to September? ")
embedding = model.encode(query)
closest = collection.search([embedding],
    anns_field='embedding',
    param={"metric_type""L2",
        "params": {"nprobe"16}},
    limit=2,
    output_fields=["paragraph"])
print(closest[0][0])
print(closest[0][1])

比如,我在应用中查询大语言模型相关的信息,返回了以下两个回答。尽管这些回答提到了“语言模型”并包含一些相关信息,但它们没有提供关于大型语言模型的详细解释。第二个回答在语义上相似,但是不足够接近我们想要的内容。

alt

04.给向量数据库知识库添加内容

到目前为止,我们使用 Zilliz Cloud 作为向量数据库在 TDS 文章上创建了一个知识库。虽然能够轻松地检索语义上相似的搜索结果,但还没有达到我们的期望。下一步是通过加入新的框架和技术来增强我们的结果。

05.总结

本教程介绍了如何基于 Towards Data Science 文章构建聊天机器人。我们演示了网页爬取的过程,创建了知识库,包括将文本转换成向量存储在 Zilliz Cloud 中。然后,我们演示了如何提示用户进行查询,将查询转化为向量,并查询向量数据库。

不过,虽然结果在语义上相似,但并不完全符合我们的期望。在本系列的下一篇中,我们将探讨使用 LlamaIndex 来优化查询。除了这里讨论的步骤之外,大家也可以结合 Zilliz Cloud 尝试替换模型、合并文本或使用其他数据集。

本文由 mdnice 多平台发布

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

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

相关文章

TS 入门指南

TS 类型基本用法 TS简介 TypeScript&#xff0c;简称 TS&#xff0c; 是一种由微软开发的编程语言&#xff0c;它是对 JavaScript 的一个增强让我们更加方便地进行类型检查和代码重构&#xff0c;提高代码的可靠性和可维护性同时&#xff0c;TypeScript 还支持 ECMAScript 的…

对长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,该算法删除线性表中的所有值为x的数据元素

对长度为n的顺序表L&#xff0c;编写一个时间复杂度为O(n)&#xff0c;空间复杂度为O(1)的算法&#xff0c;该算法删除线性表中的所有值为x的数据元素 算法思路&#xff1a; 用count标记遇到x的次数&#xff0c;每次遇到x&#xff0c;count 遇到非x的元素&#xff0c;把它前移…

探索企业基本信息查询API:数据访问的便捷方式

前言 当涉及到获取企业的基本信息时&#xff0c;传统的方法往往需要大量的时间和人力资源&#xff0c;以收集、整理和验证数据。然而&#xff0c;现在有一种便捷的方式可以解决这个问题&#xff0c;那就是通过企业基本信息查询API。本文将探讨这种API是如何成为数据访问的便捷…

【Hive SQL】字符串操作函数你真的会用吗?

文章目录 ININSTRSUBSTRLOCATELIKE 前言&#xff1a; 今天在做一个需求的时候&#xff0c;需要判断字符串中是否包含一个子串&#xff0c;然后我发现了我平常没注意到的一个点&#xff0c;通过这篇博文来记录一下。 IN IN 函数用于判断一个元素是否存在于所给的元素组中&…

【基础架构设计】仿12306系统公共组件设计深度解析

仿12306系统学习 学习路线 12306 铁路购票系统学习总体分为三块&#xff1a;组件库开发、业务梳理以及业务系统开发。 组件库开发 组件库的产出源于对公共功能的封装&#xff0c;避免了在不同项目之间相互复制代码的情况。当然&#xff0c;如果这种复制代码的方式出现问题&a…

红酒种类及更多的红酒基本知识

从法国不拘一格的绿色牧场到北加州的金山&#xff0c;各种不同类型的红葡萄酒从淡色到豪放&#xff0c;从各种不同的种植地区走向世界各地的餐桌。来自云仓酒庄品牌雷盛红酒分享红葡萄酒在味道、酒体、颜色、香味以及它们提供的整体体验方面可以有很大的不同。 为合适的场合选…

amr文件苹果手机怎么打开?四个方法教会你!

Amr格式文件因其资源占用率低、传输方便&#xff0c;通常用作各大手机厂商广泛使用的一种保存录音文件的格式&#xff0c;非常适合制作来电铃声。但是amr音频格式的适用范围有限&#xff0c;很多时候就需要把amr转换成兼容性更好的mp3格式。如何将AMR文件转换为mp3然后在苹果手…

Linux 内核文件系统dentry_path_raw函数

文章目录 一、简介1.1 __dentry_path1.2 prepend_name1.3 d_path 二、dmeo参考资料 一、简介 // linux-5.4.18/fs/d_path.cchar *dentry_path_raw(struct dentry *dentry, char *buf, int buflen) {return __dentry_path(dentry, buf, buflen); } EXPORT_SYMBOL(dentry_path_r…

语雀停服8小时,P0级事故,故障原因和补偿来了。

昨天互联网圈子里发生了一件大事&#xff0c;那就是语雀的 P0 级事故&#xff0c;前后足足停服了 7 个多小时&#xff0c;放眼整个互联网的发展史&#xff0c;都是相当炸裂的表现。 语雀是技术大牛玉伯在蚂蚁金服内部孵化出来的一个云端知识库&#xff0c;整体的界面非常清爽&…

[SQL开发笔记]IN操作符: 在WHERE子句中规定多个值

上一实例我们在where子句使用(year2022 or year2020)&#xff0c;如果我们需要在WHERE子句中规定多个值呢&#xff1f;这时我们将学习IN操作符 一、功能描述&#xff1a; 在WHERE子句中规定多个值。 二、IN操作符语法详解&#xff1a; IN操作符语法&#xff1a; SELECT col…

【Linux】MAC帧协议 + ARP协议

文章目录 &#x1f4d6; 前言1. 数据链路层2. MAC帧格式3. 再谈局域网4. ARP协议4.1 路由器的转发过程&#xff1a;4.2 ARP协议格式&#xff1a; 5. 如何获得目的MAC地址 &#x1f4d6; 前言 在学完网络层IP协议之后&#xff0c;本章我们将继续向下沉一层&#xff0c;进入到数…

STM32-通用定时器

通用定时器 通用定时器由一个可编程预分频器驱动的16位自动重新加载计数器组成。应用&#xff1a;测量输入的脉冲长度信号&#xff08;输入捕获&#xff09;、产生输出波形&#xff08;输出比较和PWM&#xff09;。 脉冲长度和波形周期可以从几微秒调制到几毫秒&#xff0c;使用…

记录隐藏挖矿木马rcu_tasked的查杀

记录一次项目中挖矿病毒的经历 这是黑客使用的批量蔓延病毒的工具&#xff0c;通过如下脚本 [rootServer .cfg]# cat /home/pischi/.bash_history cd /root/ nvidia-smi;ls -a;cd .cfg;ls -a;wc -l ip ./key 20 -f ip pass 22 "nproc;nvidia-smi;rm -rf .cfg;mkdir .cfg…

怎么做好网络软文推广?媒介盒子为你揭秘

不管是初创公司还是成熟公司&#xff0c;都需要打响品牌知名度&#xff0c;而有些公司在网络推广中的预算不是很高&#xff0c;这个时候就可以利用软文进行推广&#xff0c;今天媒介盒子就来告诉大家&#xff0c;如何写好网络推广软文。 一、 明确推广目标 确定推广目标有助于…

【备考网络工程师】如何备考2023年网络工程师之常见考点篇(1)

文章目录 写在前面涉及知识点1、NSLOOKUP命令设置的几个类型&#xff08;DNS服务器资源记录类型&#xff09;2、结构化综合布线系统的组成3、xDSL及相关概念4、私有地址及A-E类地址4.1 、私有地址4.2 、A-E类地址 总结 写在前面 其实做模拟或真题时候&#xff0c;总是会在关键…

建联合作1000+达人,如何高效管理?

随着社交媒体的发展&#xff0c;达人营销已成为品牌营销重要的方式之一&#xff0c;甚至可以说是必选项。 对于很多品牌商家来说&#xff0c;一次合作几百个不同类型、不同社媒平台的达人&#xff0c;已屡见不鲜。在电商大促前、主推单品爆品时&#xff0c;同时合作上千个达人&…

通过js来实现用身份证号来判断性别和出生年月

html: <input type"text" id"shenfenzhenghao" oninput"hao()" placeholder"证件号"><input type"text" id"xingbie" disabled"disabled" placeholder"性别"><input type&qu…

CVPR 2024 延期!

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 点击进入—>【计算机视觉和Transformer】交流群 扫码加入CVer知识星球&#xff0c;可以最快学习到最新顶会顶刊上的论文idea和CV从入门到精通资料&#xff0c;以及最前沿项目和应用&…

『第五章』二见痴心:初识小雨燕(中)

在本篇博文中,您将学到如下内容: 7. 值类型与引用类型8. OOP与POP9. 协议与扩展10. 函数与闭包11. 泛型和宏总结相逢情便深,恨不相逢早 玲珑骰子安红豆,入骨相思知不知。 7. 值类型与引用类型 在 Swift 中我们可以将之前介绍的那些数据类型分为两大类:值类型和引用类型。 …

做好微信私域,一定要知道的5大触点

越来越多人意识到私域的重要性&#xff0c;也有越来越多人在私域中获益。 把用户私有化&#xff0c;只是第一步。 我们还要和用户建立联系&#xff0c;要一直互动。 也就是说&#xff0c;我们必须高频地和用户互动&#xff0c;要不断去触达他们。而触达&#xff0c;就需要触点。…