如何使用自己的数据创建私密的ChatGPT
学习使用ChatGPT/LLMs创建自己的问答引擎所需的架构和数据要求。
随着ChatGPT和GPT-4等大型语言模型(LLM)的崛起,许多人都在问:是否可以用公司数据训练一个私人ChatGPT呢?但这可行吗?这样的语言模型能提供这些功能吗?
在本文中,我将讨论用于创建“您私人的ChatGPT”的架构和数据要求,这将利用您自己的数据。我们将探讨这项技术的优势以及您如何克服目前的局限性。
免责声明:本文提供的是架构概念的概述,这些概念与Azure无关,但使用Azure服务进行举例,因为我是微软的解决方案架构师。
1. 用自己的数据进行微调 LLM 的缺点
通常人们将微调(训练)作为在预训练的语言模型之上添加自己的数据的解决方案。然而,这种方法存在缺点,比如在最近的GPT-4发布声明中提到的幻觉风险。此外,GPT-4仅使用了截至2021年9月的数据进行训练。
当您对LLM进行微调时,常见的缺点有以下几个:
- 事实正确性和可追踪性,答案来源于何处。
- 访问控制,无法将特定文件限制为特定用户或群组。
- 成本,新文件需要对模型进行再次训练和模型托管。
这将使细调来进行问答(QA)变得极其困难,几乎不可能。我们如何克服这些限制,并仍能从这些LLMs中受益?
2. 将你的知识与语言模型分开
为了确保用户获得准确的答案,我们需要将我们的语言模型与知识库分离。这样可以利用语言模型的语义理解能力,同时为用户提供最相关的信息。所有这些都是实时进行的,无需进行模型训练。
在运行时将所有文档输入模型可能看起来是个不错的主意,但由于一次只能处理的标记数量(以标记为单位所测量的字符限制),这是不可行的。例如,GPT-3支持最多4K个标记,GPT-4支持最多8K或32K个标记。由于按每1000个标记计费,使用更少的标记还可以帮助节省成本。
这个问题的方法如下所示:
- 用户提出一个问题
- 应用程序找到最相关的文本,其中(很可能)包含答案。
- 向LLM发送了简明的提示与相关的文档内容。
- 用户将会收到一个回答或者“未找到答案”的响应。
这种方法通常被称为模型基于事实(grounding the model)或检索增强生成(Retrieval Augmented Generation,RAG)。该应用程序会为语言模型提供额外的上下文,以便能够基于相关资源回答问题。
现在你已经理解了开始构建这样一个场景所需的高级架构,是时候深入技术细节了。
3. 检索最相关的数据
上下文是关键。为了确保语言模型具备足够的信息来工作,我们需要建立一个知识库,通过语义搜索来找到最相关的文档。这将使我们能够为语言模型提供正确的上下文,使其能够产生正确的答案。
3.1将数据分块和拆分
由于答题提示有一个令牌限制,我们需要确保将我们的文档切分成更小的块。根据您的块的大小,您也可以分享多个相关部分并在多个文档中生成答案。
我们可以通过将文档按页进行简单拆分,或者使用一个文本分割工具按预定的令牌长度进行拆分。当我们将文档转换为更易访问的格式后,就可以创建一个可通过提供用户问题进行查询的搜索索引了。
在这些块旁边,您应该为索引添加附加的元数据。存储原始来源和页面编号以将答案链接到您的原始文件。存储可用于访问控制和过滤的附加元数据。
选项1:使用搜索产品
构建语义搜索索引的最简单方式是利用现有的“搜索即服务”平台。在Azure上,例如可以使用认知搜索(Cognitive Search),该平台提供了一个托管的文档摄取流水线和利用Bing背后的语言模型的语义排名功能。
选项2:使用嵌入来构建自己的语义搜索系统
一个嵌入是由浮点数构成的向量(列表)。两个向量之间的距离用来衡量它们的相关性。小距离表示高相关性,大距离表示低相关性。 [1]
如果您想利用最新的语义模型,并对搜索索引拥有更多控制权,您可以使用OpenAI的文本嵌入模型。对于您的所有部分,您需要预先计算嵌入并存储它们。
在Azure上,您可以将这些嵌入存储在托管的矢量数据库中,例如具有矢量搜索(预览版)的认知搜索、Azure Redis缓存(RediSearch),或者在开源的矢量数据库中,如Weaviate或Pinecone。在应用程序运行时,您将首先将用户的问题转换为一个嵌入,以便我们可以将问题嵌入的余弦相似度与之前生成的文档嵌入进行比较。像认知搜索这样的高级搜索产品可以将关键字搜索和矢量搜索的优点结合起来进行混合搜索。
(有关嵌入的深入探讨可以在《走向数据科学》上找到)
3.2 使用不同的切块策略来提高相关性。
为了能够找到最相关的信息,重要的是您了解数据和潜在用户的查询。您需要什么样的数据来回答问题?这将决定您数据的最佳分割方式。
可能提高相关性的常见模式有:
- 使用滑动窗口;每页或每个标记进行分块可能会导致失去上下文的不良效果。使用滑动窗口在您的分块中创建重叠内容,以增加分块中包含最相关信息的机会。
- 提供更多的上下文;一个非常结构化的文档,其章节中可能有多层嵌套(例如1.3.3.7节),可以从章节标题和节标题等额外上下文中获益。您可以解析这些节并为每个块添加上下文信息。
- 概述,创建包含整个文档部分摘要的块。这将使我们能够捕捉到最重要的文本,并将其全部汇集到一个块中。
4. 编写一个简明扼要的提示,以避免幻觉。
设计您的提示是如何“编程”模型的方式,通常通过提供一些说明或几个例子。[2]
您的提示是ChatGPT实现的重要部分,用于预防不受欢迎的回应。如今,人们称之为提示工程是一项新技能,每周都会分享更多的样本。
在您的提示中,您希望清楚表明模型应简洁,并且只使用所提供的上下文数据。当模型无法回答问题时,应提供预定义的“无答案”回复。输出应包括一个脚注(引用),指向原始文档,以便用户可以通过查看来源验证其事实准确性。
这样一个提示的例子:
"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. " + \
"Use 'you' to refer to the individual asking the questions even if they ask with 'I'. " + \
"Answer the following question using only the data provided in the sources below. " + \
"For tabular information return it as an html table. Do not return markdown format. " + \
"Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. " + \
"If you cannot answer using the sources below, say you don't know. " + \
"""
###
Question: 'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'
Sources:
info1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family.
info2.pdf: Overlake is in-network for the employee plan.
info3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.
info4.pdf: In-network institutions include Overlake, Swedish and others in the region
Answer:
In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf].
###
Question: '{q}'?
Sources:
{retrieved}
Answer:
"""
源码:在 azure-search-openai-demo(MIT许可证)中使用的提示
一次性学习用于增强响应;我们提供了一个用户问题处理的示例,并提供了具有唯一标识符的来源以及由多个来源的文本组成的示例答案。在运行时,{q}将被用户问题填充,{retrieved}将被知识库中相关部分填充,以供最终提示使用。
不要忘记通过您的参数设置一个低温度,如果您想要更加重复和确定性的回应。增加温度会导致更多意外或创意的回应。
这个提示最终用于通过(Azure)OpenAI API生成响应。如果您使用gpt-35-turbo模型(ChatGPT),您可以在每个对话轮中传递对话历史以提出澄清问题或使用其他推理任务(如摘要)。了解有关提示工程的更多信息的一个很好的资源是GitHub上的dair-ai/Prompt-Engineering-Guide。
下一步
在本篇文章中,我讨论了构建实现所需的架构和设计模式,没有深入讨论代码的具体细节。这些模式在现今常被使用,以下的项目和笔记本可以作为启发,帮助您开始构建这样的解决方案。
- Azure OpenAI服务 — 基于您的数据,新功能可以让您以完全托管的方式结合OpenAI模型,如ChatGPT和GPT-4,并使用您自己的数据。无需复杂基础设施或代码。
- ChatGPT 检索插件,允许 ChatGPT 访问最新信息。目前,此功能仅支持公共 ChatGPT,但希望将来能够将插件能力添加到 ChatGPT API(OpenAI + Azure)中。
- LangChain,流行的库,用于结合LLMs和其他计算或知识来源。
- Azure认知搜索+ OpenAI加速器,让您在自己的数据上体验类似ChatGPT的体验,随时可部署。
- OpenAI烹饪书,使用OpenAI嵌入在Jupyter笔记本中进行问答的示例(无需基础设施)。
- 语义内核,一种将传统编程语言与LLMs(即语言模型)混合的新库(提供了提示模板、链接和规划能力)。
最终,您可以通过像LangChain或Semantic Kernel这样的工具将“您自己的ChatGPT”与更多系统和功能进行连接,从而扩展它。可能性是无限的。
结论
结论是,仅依靠语言模型生成事实文本是一个错误。对模型进行微调也无法帮助,因为它不会给该模型带来新知识,并且不提供验证其回答的方法。要在大型语言模型之上构建一个问答引擎,需要将知识库与语言模型分离,并且仅根据提供的上下文生成答案。
如果您喜欢这篇文章,欢迎在LinkedIn、GitHub或Twitter上与我联系。
参考资料
[1] 嵌入 — OpenAI API。2023年3月,https://platform.openai.com/docs/guides/embeddings
[2] 简介—OpenAI API。2023年3月,https://platform.openai.com/docs/introduction/prompts
[3] Bubeck, S., Chandrasekaran, V., Eldan, R., Gehrke, J., Horvitz, E., Kamar, E., Lee, P., Lee, Y. T., Li, Y., Lundberg, S., Nori, H., Palangi, H., Ribeiro, M. T., Zhang, Y. "人工通用智能的火花:GPT-4的初期实验"(2023年),arXiv:2303.12712
[4] 史丹尼斯·席克(Schick),尤迪维迪-于(Dwivedi-Yu),德西(Dessì),拉伊利亚努(Raileanu),洛梅利(Lomeli),泽特尔莫尔(Zettlemoyer),坎塞达(Cancedda),斯夏隆(Scialom)。《Toolformer:语言模型能够自教使用工具》(2023),arXiv:2302.04761。
[5] Mialon, G., Dessì, R., Lomeli, M., Nalmpantis, C., Pasunuru, R., Raileanu, R., Rozière, B., Schick, T., Dwivedi-Yu, J., Celikyilmaz, A., Grave, E., LeCun, Y., Scialom, T. "增强语言模型:一项调查"(2023),arXiv:2302.07842