简介
在之前的教程中,你学习了如何通过语义搜索来教 ChatGPT 新知识(搜索与用户问题含义相似的问题)。
这种聊天机器人的性能主要取决于我们提供给模型的知识数据的质量。这个过程通常非常耗时,涉及收集、清理和格式化数据。
在本教程中,你将学习如何为一个新的聊天机器人准备知识数据,该机器人将回答有关 VISIONS 组织 的问题。基本思路是从其网站下载数据并使用该数据生成问题/答案。这是一个常见的用例:大多数企业和组织已经拥有网站,但需要构建他们的聊天机器人以提供更好的用户体验。
步骤 1 - 启动项目
你首先需要完成此教程:ChatGPT AI: QA Bot Using Semantic Search (RAG) (Difficulty: 4)
保存该项目的副本并将其重命名为“Chatbot Using Web Data”。
步骤 2 - 对 VISIONS 组织的基准测试
作为基准,我们必须测试 ChatGPT 对 VISIONS 组织的了解程度。如果它可以在没有帮助的情况下回答大多数问题,则无需注入额外的知识。
要运行测试,我们可以使用此项目中的普通 ChatGPT 助手:
https://play.creaticode.com/projects/6531b7e60fdce080a4481c1d
例如,我们可以看到 ChatGPT 已经了解 VISIONS 组织:
10ec4215-e013-4cfd-bcb0-dc1daa7f8086-image.png
然而,如果我们尝试获取更多具体信息,它会失败:
e4e998cc-69b8-4372-b021-8d66ca5b5775-image.png
这证明了 ChatGPT 需要我们的帮助来回答有关 VISIONS 组织的更具体问题,即使这些信息在其网站上很容易获得。
[高级] 为什么 ChatGPT 不知道答案?
ChatGPT 不会记住任何句子。相反,它会记住下一个单词的概率。 如果某些单词在训练数据中经常一起出现,则该模式将存储在模型中。
例如,如果许多网站包含类似“VISIONS 的电话号码是 1.888.245.8333”的句子,那么下次 ChatGPT 看到“VISIONS 的电话号码是”时,它将预测正确的电话号码作为下一个单词。
但是,由于该句子在训练数据中不常见,因此具有最高概率的下一个单词可能是“sorry”或“I”,而实际电话号码的概率要低得多。
步骤 3 - 从网站获取数据
现在,让我们看看 VISIONS 组织的网站。在新标签页中打开此 URL https://visionsvcb.org,你应该会看到以下内容:
e.gif
此网页包含大量信息和指向其他网页的链接。要下载信息,我们可以运行以下代码块(单击左下角的绿色“添加扩展”块并选择“云”类别):
e.gif
请注意,此代码块为你执行两件事:
下载页面的完整内容;
将内容转换为
Markdown 格式。
Markdown 格式非常简单。它几乎与你在网页上看到的文本相同,但包括了其他信息,例如网页上链接的 URL。这在下一步中将非常有用。
请注意,URL 的内容会被缓存,因此如果你在同一天重复从同一 URL 获取内容,则在第一次之后速度会非常快。
此外,网站的内容将经过审核过程,因此如果发现任何不适当的内容,此代码块将拒绝获取请求。
步骤 4 - 了解网页和链接
与大多数网站一样,我们下载的 VISIONS 页面包含许多链接,例如:
...
[首页](https://visionsvcb.org)
[关于我们](#)
[年度报告和财务](https://visionsvcb.org/about/annual-report)
[董事会](https://visionsvcb.org/about/board-of-directors)
[管理团队](https://visionsvcb.org/about/management-team)
[使命宣言](https://visionsvcb.org/about/mission-statement)
[VISIONS 历史](https://visionsvcb.org/about/visions-history)
...
每个链接都指向一个新页面,该页面可能链接到其他页面。 其中一些链接也可能是重复的。例如,页面 1 可能包含指向页面 2 的链接,而页面 2 可能包含指向页面 1 和页面 3 的链接。随着页面数量的增加,它们将形成一个具有许多链接之间链接的网络:
2c117e90-d904-4243-b82a-0b5d87801d48-image.png
在接下来的几个步骤中,我们将编写代码来解析每个页面上的链接,并将这些链接放入一个没有重复的队列中。我们将访问此队列中的每个链接以获取更多内容并提取更多链接。
步骤 5 - URLs 列表
要存储我们将访问的所有链接,请创建一个名为“URLs”的新列表。第一个 URL 将是该站点的主 URL:“https://visionsvcb.org”。请注意,我们首先删除列表中的所有项目,这将确保我们始终从主 URL 开始。
25317d16-f2a8-49b4-8b40-4c8fc1fe0ee0-image.png
步骤 6 - 遍历每个 URL
接下来,我们使用 for 循环访问列表中的每个 URL。由于列表会随着我们在访问的页面上发现更多链接而增长,因此我们不知道会有多少个 URL。我们现在将使用 1 来确保我们的代码适用于 1 个 URL。
我们还将添加一个保护措施,以确保 URL 索引永远不会大于列表的长度,这样我们将始终获得有效的 URL。
88c6edc8-f534-4b30-bff3-7e09126711ec-image.png
步骤 7 - 获取一个 URL 的内容
接下来,我们将从当前索引处的 URL 获取内容并将其存储在“result”变量中:
7c2f1c19-330a-4776-8e8a-0ecb53d22e03-image.png
步骤 8 - 定义“extract links”块
由于从页面内容中提取所有链接的逻辑相当独立,因此最好定义一个专用的新块:“extract links”。它将获取内容的结果并将该页面上的所有 URL 添加到“URLs”列表中。
31ac4877-141f-4e73-bb57-95ae38308c96-image.png
步骤 9 - 查找所有链接
要查找页面内容中的所有链接,我们需要查找特定的模式。在 markdown 格式中,所有链接都包含在以“https://”开头的一对 ( ) 中。 因此,我们可以使用正则表达式来查找与此模式匹配的所有文本,并将它们存储在一个名为“links”的新列表中。
你可以从此处复制确切的正则表达式:\(https?:\/\/[^\)]+\)
b73f85ef-1e31-4913-b0c6-936c3c4e8c0b-image.png
现在,如果我们运行程序,它将从主站点获取内容并将该页面上的所有 60 个链接提取到“links”列表中:
a015537e-c809-42e7-a8fe-75637aaa1465-image.png
步骤 10 - 遍历链接列表
要清理此链接列表,我们需要另一个 for 循环来处理每个链接。我们将每个链接存储在“link”变量中:
f7860de2-fce8-4e27-8bc6-8627bf2254cd-image.png
步骤 11 - 删除括号
每个链接都包含一对括号。要删除它们,我们需要提取从链接文本的第二个字母到倒数第二个字母的子字符串。结果将存储在一个名为“URL”的变量中。
e96d987c-ba6f-4335-9d75-408140442104-image.png
步骤 12 - 存储 URL 而不重复
现在,我们可以将新的 URL 添加到 URL 列表中,但我们需要确保该列表不包含此新的 URL。
708fe245-9bd1-4883-90cc-dbf1b7d1701b-image.png
步骤 13 - 限制为主站点
还有一个小问题。页面上的某些链接不是来自同一域,例如“(https://accessibility-helper.co.il)”。请注意,我们应该只从同一主站点下载数据。否则,当我们访问越来越多的网站时,URL 列表可能会呈指数级增长。因此,我们需要添加另一个条件:如果 URL 包含“visionsvcb.org”,我们才将其添加到列表中。(请注意,当你将此项目用于其他网站时,也需要更改此主 URL。)
15e87c61-c8fd-4107-864a-297cf5cc111d-image.png
在此之后,再次运行程序,“URLs”列表将增长到 42 个项目:
339a1833-4238-4a34-a8f6-73ad82a9e106-image.png
步骤 14 - 测试:从前 3 个 URL 获取
为了进行测试,让我们尝试从列表中的前 3 个 URL 获取:
184aefa0-fa01-446d-b716-4133447292a8-image.png
在我们再次运行此程序后,我们发现“URLs”列表增长到 61 个项目:
e.gif
我们还发现了一个新问题。很多 URL 是 PDF 文件。如果我们正在创建一个文档检索应用程序,这可能很有用,但对于此项目,我们应该排除它们,因为我们只需要 Web 内容。我们可以在“extract links”块中添加一个附加条件,如下所示:
93d87cdc-1cd0-4225-8a11-6f828c1ead3e-image.png
现在,如果我们重新运行程序,URLs 列表总共只有 42 个项目。这意味着当我们访问第二个和第三个 URL 时,没有发现新的链接。
步骤 15 - 添加“Generate QA”块
现在我们可以遍历网站中的所有页面,下一步是从每个页面生成问题和答案。让我们专注于使用第一页生成它们。请定义一个名为“generate QA”的新块并在重复循环中调用它。我们将传入“result”变量,它是当前页面的文本。
12fc11e4-2c47-4053-800d-8bfac5122500-image.png
步骤 16 - 将页面内容切分成块
接下来,我们将把页面内容提供给 ChatGPT 以生成问题和答案对。请注意,我们不能简单地在一个请求中将所有内容提供给 ChatGPT,因为这可能会超过 ChatGPT 对请求长度的限制。相反,我们将不得不将内容切分成块。
例如,假设我们将每个块限制为最多 5000 个字符。如果内容总共有 12000 个字符,我们将向 ChatGPT 发送 3 个请求:字符 1 到 5000,字符 5001 到 10000,以及字符 10001 到 12000。
这个想法可以使用如下所示的 for 循环来实现:
21a2ac51-53c7-4f82-b9d6-8810d32b3aed-image.png
“start index”是每个块的第一个字符的位置,最后一个字符的位置将是“start index + 4999”。因此,“chunk”变量将包含每个块的页面内容。
步骤 17 - 让 ChatGPT 生成问题和答案
让 ChatGPT 使用每个块生成一些问题和答案相当简单。但是,为了更容易解析 ChatGPT 的响应,我们还需要指定输出格式。例如,我们可以使用如下所示的提示:
你将根据网页内容生成问题和答案。每个问题以“--QUESTION:”开头,每个答案以“--ANSWER:”开头。以下是网页内容:
以下是组成和发送请求的代码:
rq.gif
请注意,每个请求都是一个新的聊天,这样 ChatGPT 就不需要担心以前的消息。否则,ChatGPt 可能不会专注于它正在处理的当前块。
步骤 18 - 将响应拆分成列表
我们从 ChatGPT 获得的响应将如下所示:
59bc00ae-320c-4e1e-a584-8b1286ca65ab-image.png
我们的下一个任务是将问题和答案放入表格格式,以便我们以后可以使用它们来构建语义数据库。首先,我们需要按特殊符号“--”拆分响应并将各个部分放入名为“qa”的列表中:
8f6ca4a5-cdc7-44af-9949-049cb0c94d13-image.png
该列表将如下所示,问题和答案作为单独的项目:
e681a5d7-78d1-417f-9c0f-25f24ff80470-image.png
步骤 19 - 清空数据表
由于我们将累积问题和答案并将它们存储在“data”表中,因此我们需要在开始时清空表的内容。
a3d53427-8976-461e-a9ab-c0722f5edd36-image.png
步骤 20 - 遍历“QA”列表
要将“qa”列表中的所有问题和答案添加到“data”表中,我们可以使用 for 循环遍历“qa”列表中的每个项目。我们已经知道列表的第一项始终为空,因此我们应该从第二项开始。此外,我们将一次使用 2 个项目,一个用于问题,一个用于答案,因此我们应该每次将索引“i”增加 2:
3d42078d-35ee-4a24-8736-d46e214c1a1c-image.png
步骤 21 - 添加一对问题和答案
现在我们可以读取索引“i”处的项目的问题,以及索引“i+1”处的项目的答案。然后我们将它们都作为新行添加到“data”表中:
8fd0b045-3713-4b1d-842e-02825eb59683-image.png
例如,如果有 3 对问题和答案,我们将在“data”表中获得 3 行:
c1e029a4-671e-4aa0-8cc4-6aef69f3c5f6-image.png
步骤 22 - 删除前缀
有一个小问题:问题包含前缀“QUESTION:”,答案包含前缀“ANSWER:”。我们可以使用“replace”运算符删除它们:
c14aa852-383f-4ff0-8dd5-aaf589a66b4c-image.png
现在如果我们清空数据表(手动删除现有项目)并再次单独运行 for 循环,我们将获得干净的问题和答案:
92c5f25e-6362-409f-bee1-b834e725f9df-image.png
步骤 23 - 测试运行
现在我们的程序已准备就绪。让我们用前 3 个 URL 测试它:
4ba63f5c-d54b-4246-9255-f9f99b0fec09-image.png
这将需要一些时间来运行,因为我们需要使用 ChatGPT 从每个页面生成问题和答案。运行完成后,我们将在“data”表中获得一些问题。当你运行它时,确切的问题数量可能会有所不同。
7611ce4a-f9dc-4247-920f-92edc6b71092-image.png
其余过程与之前相同:我们可以使用“data”表创建语义数据库(如果数据保持不变,则无需重复执行此操作),然后我们可以在用户提出新问题时查询此数据库,并将查询结果作为参考提供给 ChatGPT。
下一步
你现在可以尝试更改程序以从任何其他网站获取数据,然后使用该数据发布聊天机器人。请注意,你需要在 2 个位置指定新网站:
在开始时,当你指定初始 URL 时:
7325524f-a056-44ef-b641-7396b9a3be12-image.png
在“extract links”块的定义中,你删除与目标网站无关的 URL 的位置:
16583fbb-13e1-46cc-9e6e-193ef8c025bc-image.png