FreeCodeCamp-大语言模型训练营笔记-全-
FreeCodeCamp 大语言模型训练营笔记(全)
1:一小时构建LLM应用 🚀
在本节课中,我们将学习如何在一小时内快速构建并部署一个大型语言模型应用。我们将从原型设计开始,逐步迭代,最终将其部署为一个可供用户交互的实际应用。

为什么现在是AI的好时机?🤔

上一节我们介绍了课程的目标。本节中,我们来看看为什么当前是投身人工智能领域的绝佳时机。
想象一个世界,其中存在极其简单且启发式的计算机程序,能够模仿人类的认知过程。它们如此出色,以至于人类甚至会对聊天机器人治疗师产生情感依恋。计算机可以下棋、撰写数学证明,甚至能通过学校的考试。令人惊叹的是,你甚至可以从人工智能那里获得投资建议。
你无需成为有远见的联合创始人就能想象这个世界,因为它在1965年就发生了。这是赫伯特·西蒙和艾伦·纽厄尔在论文《启发式问题解决》中对当时人工智能领域的描述。它指出,当时的人工智能已经达到了与人类相当的水平,可以下棋、证明定理、通过学校考试,并模拟投资基金经理的行为。
问题在于,这显然没有真正实现。我们并没有拥有60年的人工智能。那么,这次有什么不同?最清晰的答案是,现在有一个工具可以完成所有这些事情,而不是一堆针对每个特定任务的专门工具。现在,你只需使用一个单一的工具,并进行少量配置,就能让它处理新任务。这更类似于我们让人类为我们解决问题的方式,而不是机器学习模型或老式专家系统模型解决问题的方式。
什么是语言模型?🧠
上一节我们探讨了当前AI浪潮的独特性。本节中,我们来深入了解实现这一切的核心工具:语言模型。
语言模型是对语言进行建模的工具。实现这种能力需要一个看似简单却至关重要的技巧。其形式如下:如果一个段落逐词出现,你想要猜测下一个词是什么,这需要相当高的智能。特别是如果你能预测比闲聊更复杂的事情,比如在与人交谈时,你可能会提到一个数学方程,或者谈论Python。

尤其是在书面文档中,包含了许多这类更复杂的内容。当这些词出现在屏幕上时,在某些地方,你能够以需要Python知识、科学和物理世界知识、数学知识的方式猜测下一个词是什么。
大型语言模型非常擅长猜测下一个词是什么。为了精通这项任务,它们也精通了所有其他事情,比如数字相加、编写Python代码或学习物理世界的知识。
语言用户界面与历史教训 📜
上一节我们了解了语言模型的核心原理。本节中,我们来看看它解锁的关键应用形式,并回顾历史以避免重蹈覆辙。
我认为,这条通往人工智能的特定路径所解锁的关键部分,也是我们在此训练营中兴奋地讨论和分享的,就是语言用户界面。语言用户界面是一种自计算机诞生之初就被设想的人机交互方式。在图形用户界面和终端用户界面出现之前,人们认为与计算机交互的理想方式可能是像与人交谈一样,使用自然语言。
因此,早期就有尝试实现这一目标的工作。例如,20世纪60年代由魏岑鲍姆开发的著名聊天机器人治疗师Eliza。那只是一个纯粹的语言界面。但人们很快意识到,如果你有一个语言界面,至少能将自然语言的概念输入计算机,你还可以让这种语言影响非语言的事物。例如,一个由简单物体组成的“积木世界”,这是特里·威诺格拉德在1970年的SHRDLU程序中实现的。

这种语言用户界面的总体构想,迄今为止我们最接近的实现可能是搜索引擎。你可以输入一些内容,虽然可能更像“谷歌式”的查询而非纯自然语言,但相比与Python程序交互,你与搜索引擎的交互要自然得多。最早的流行搜索引擎之一Ask Jeeves就将自己定位为互联网的自然语言界面。
借助大型语言模型,我们可以构建更灵活、更强大的语言用户界面,其处理和响应语言的方式更接近人类的期望,而不是那些更脆弱、更专注于特定领域(如仅限心理治疗或仅限积木世界)的旧系统。
此外,我认为当前存在一股巨大的炒作浪潮,这引发了许多人对语言模型和人工智能的警惕,尤其是那些经历过过去浪潮的人。因此,我只想传达一个观点:这是人们以前就期待的事情。如果我们实现了语言建模,我们认为这可能会发生。
这是一篇20世纪90年代的论文,讨论了“AI完全”问题——即如果解决了哪些问题,我们会认为自己已经实现了智能。这是一个有些模糊的概念,类似于计算机科学中的“NP完全”问题,但数学严谨性稍逊。它代表了该领域对于解决此问题所需条件的普遍看法。列表中的第一个就是自然语言理解——能够深入理解自然语言。
这种结合——真正优秀的用户界面、一种新型用户界面,以及自然语言理解领域这一长期目标——正是我们随着大型语言模型的发布和开放可用性而获得巨大能力解锁的原因。

但是,这次情况确实有本质上的不同,这给了我们希望。然而,回顾并审视1966年发生了什么、为什么我们没有实现人工智能也同样重要。我确信当时也有人同样兴奋地分享他们的模型是如何工作的。
避免“AI寒冬”❄️

上一节我们提到了历史教训。本节中,我们来具体看看如何避免重蹈“AI寒冬”的覆辙。
当时发生的主要事情是,作为一个领域,我们某种程度上“过度承诺,交付不足”,这导致了被称为“AI寒冬”的现象。在这个时期,人们对这类项目的兴趣减弱,资金也更难获得。一个显著的寒冬就发生在20世纪60年代那波浪潮之后,然后在20世纪90年代又出现了一个较小的寒冬。
回顾当时的一些细节,了解其发展过程,对于理解我们这次如何避免这种情况至关重要。那个时期的关键文件之一是理查德·莱特希尔爵士为英国政府撰写的报告。他是一位数学家,对当时人们进行的人工智能研究产生了兴趣。他调查后认为这完全是无稽之谈,并写下了他的看法,说服了英国政府、英国公众乃至全世界,认为这是一个糟糕的主意。


从这份报告中摘取几个关键短语:他谈到了“远未实现的过高期望”,这导致“巨额资金被花费,却收效甚微”,特别是在机器翻译领域。他还特别指出,这些钱被花在了这些问题上,却没有转化为具有商业价值的东西。报告还有单独关于研究应用的部分,但很多内容都集中在这些程序“通用性不足,无法实现商业可行性”这一事实上,这意味着这是公共研究资金的糟糕投资。


因此,为了避免在21世纪20年代再次出现AI寒冬,我们需要构建人们真正重视的实际产品。我们需要构建软件、工具,构建人们真正使用的东西。这样,人们才会继续保持兴趣,继续资助我们的项目,确保我们在研究ChatGPT的同时能够支付房租。

好消息是,这次不仅有研究在发生。我刚刚去查看了GitHub上的热门仓库(可能是过去一个月的)。排名第一的是DeepSpeed库,用于大型模型的快速训练和推理,尤其用于大型语言模型。此外,前五名中还有两个是实际使用这些大型语言模型的应用:LAION的Open Assistant(一个类似于OpenAI的ChatGPT模型的开源复制尝试)和图像编辑工具Paint2Pix(使用了视觉模型和语言模型)。最后,还有一个名为Chroma的新数据库技术,它是AI原生的嵌入向量数据库。


这些都是人们正在构建的实际库。人们围绕它们创建公司,成千上万的人下载和使用它们。如果你想更快地了解人们正在构建的东西,可以查看Hugging Face的Spaces,那里经常展示很酷的演示。

我认为纳特·弗里德曼说得最好,他说“终于有人在动手捣鼓了”。终于,人们实际上在用这些模型组装东西,做出这些有用的小玩具或简单的演示,或者一些适合发推特线程、花一个下午玩玩图像生成模型之类的东西。
从演示到产品的鸿沟 🌉
上一节我们看到了当前生态的繁荣。本节中,我们来正视一个关键挑战:从演示到产品的巨大鸿沟。

但坏消息是,从那种你可以快速组装并在某些情况下使用的演示,到成为一个真正的产品,这之间的差距非常大。即使你以产品为导向进行构建(例如,你不仅仅是一个研究者),情况也是如此。
我记得在21世纪10年代中期,当人们基于高质量的图像神经网络对自动驾驶汽车感到兴奋时,有大量自动驾驶汽车的演示,比如英伟达在2017年的这个演示。现在是2023年,我们仍然没有随时可用的自动驾驶汽车。也许有少数方式可以在非常有限的环境中使用它们,但它们仍然更接近演示而非产品。


这个鸿沟可能真的非常大。第一个使用神经网络运行自动驾驶汽车的演示可以追溯到1988年卡内基梅隆大学的ALVINN(自动驾驶陆地车辆神经网络)。仅仅因为你做出了能在特定环境下工作或在特定情境下令人印象深刻的东西,并不意味着你可以立即将其产品化。
产品化正在发生 🚀
上一节我们讨论了产品化的挑战。本节中,我们来看看积极的一面:产品构建确实正在发生。
它已经开始发生,这个领域正在开始创造和发布产品。可能最著名的是OpenAI的ChatGPT,它直接产品化了语言建模。根据一些分析师的报告,它创下了用户增长最快的记录,可能是达到100万用户最快的,也可能是达到1亿用户最快的,比Instagram和TikTok还快。这是一个好迹象。
用于编码的工具,如GitHub Copilot、Replit Ghostwriter,也由这些大型语言模型驱动,并且很受欢迎。还有我们在全栈深度学习课程中用来构建内容的工具,比如用于编辑视频和播客的Descript。
产品构建确实正在发生,这对于避免AI寒冬是好事。这也意味着,关于如何实际构建这些东西,正在出现一种“剧本”或模式。你不必完全自己开辟道路。而这正是我们将在接下来两天里要涵盖的内容。
在本课程中,我们将讨论构建像ChatGPT或Copilot这类应用所需的许多要素。而在这个快速入门部分,我们将快速拼凑出一个这样的演示。
快速原型设计:第一个半小时 ⏱️
上一节我们概述了课程内容。现在,让我们深入探讨快速构建演示应用的过程。
在过去的几个月里,湾区和其他地方举办了许多围绕使用这些工具快速构建产品演示的黑客松。我参加了其中一些,观察了其他人的做法,自己也构建了一些东西。我想分享一下这个过程是怎样的。
前半小时充满了打字和迭代,这是一个探索可能性的过程。这里的要点是,与其花大量时间深入思考机器学习是否可能解决某个问题,你可以直接用一些高能力的模型(如OpenAI的模型)在你的应用场景中尝试。首先在一个简单的聊天界面中试用,看看什么可行,什么不可行。你常常会对在简单上下文中持续有效的东西感到惊讶。当然,这不是你最终要部署的东西,但你至少可以弄清楚这是否可行,并了解你将必须解决的核心问题是什么。
然后,你可以跳入一个能以编程方式进行快速试验的环境。我们将通过跳入一个快速的Notebook环境来实现这一点,这是我进行这种快速试验的首选环境。然后,弄清楚如何将我在聊天界面中做的一些事情变得更程序化。现在有很多开源的框架和工具涌现,使得这变得很容易。
实践:从聊天界面开始 💬
上一节我们介绍了快速原型设计的理念。本节中,我们通过一个具体问题来实践。

当我想弄清楚是否能用大型语言模型构建某样东西时,我做的第一件事就是进入某个方便的交互界面。对于ChatGPT来说,这非常合适。所以我通常从这里开始。


我认为从一个具体的问题陈述开始会很有帮助。我遇到的问题是我想要尽可能多地了解大型语言模型。因此,我希望能够使用大型语言模型来帮助我学习大型语言模型。我相信我联系的许多其他人也有同样的问题,所以我也想帮助他们。

首先,我认为可以先向ChatGPT询问关于语言模型的问题。从一个你已经知道正确答案的事情开始是个好主意,因为在这里的初始阶段,你最终会在脑海中模拟最终应用的许多组件。你必须假装成用户,思考你将如何编程这个东西,可能还需要介入做一些你最终会让语言模型自动化的事情。这里有很多环节,你需要确保以正确的方式将它们组合起来并获得良好的结果。所以,从你已经知道的事情开始。
我选择了一个我已经了解的关于语言模型的知识点:什么是零样本思维链提示?我从ChatGPT得到的答案并不太好:“零样本思维链提示是一种NLP技术,用于生成对提示的响应,而无需对该提示进行明确训练。”它抓住了“零样本”的一些成分,但没有抓住“思维链”。它举了个例子:“法国的首都是什么?语言模型可以通过识别关联生成‘巴黎’。”这不太正确,它遗漏了大量额外信息。


这里缺失的部分是,这些语言模型是基于截至某个时间点(对于某些模型大约是2021年)的数据构建的。而语言模型中发生的许多有趣事情都发生在它们的训练数据截止日期之后。所以这行不通。
另一个问题是,我真的很想能够跟进这些信息。我想发现新的资源,而不仅仅是依赖语言模型。总的来说,这些模型的输出中包含了许多不存在的东西。例如,之前当我问在哪里可以阅读更多相关信息时,它建议了一篇确实存在的论文,但也建议了一堆不存在的文章,比如“如何在Towards Data Science上构建OpenAI的GPT-3:分步指南”。这听起来像是可能存在的东西,但据我所知并不存在。即使存在,我可能也不想读。
所以,我们这里遇到了一个问题:语言模型不知道来源在哪里,并且它们没有某些信息。因此,如果我们希望它成为学习语言模型的好解决方案,我们需要将这些信息提供给它们。


验证假设与引入外部知识 🔍


上一节我们遇到了模型知识陈旧和幻觉的问题。本节中,我们通过手动引入外部知识来验证解决方案的可行性。


在这个聊天界面中,我实际上可能会验证我的假设。我基于我所读到的关于语言模型的内容、我从其他在线资源学到的东西,正在形成一个关于它成功或失败原因的假设。但在继续构建更多原型之前,我应该先验证这个假设。

我的假设是,如果它拥有正确的论文内容,那么它就会给出正确的答案。让我快速在arXiv上查找我想到的那篇论文,抓取它的摘要,然后放进去。这是摘要。把它放进去。
基于这个摘要,什么是零样本思维链?这不是我们期望用户会做的事情,这将在我们的应用程序中自动发生,但我们在这个早期阶段只是模拟它。


现在模型得到了正确答案:“零样本思维链提示是一种无需任何手工制作的少样本示例即可执行复杂多步推理的技术,只需在每个答案前添加‘让我们逐步思考’这句话即可。”


所以,如果我们能从某个地方获取我们的资料,并将其放入语言模型的提示中,然后向语言模型提问,那么我们很可能得到像样的答案。
转向编程环境:使用Notebook 🖥️
上一节我们在聊天界面验证了核心想法。本节中,我们转向编程环境,开始自动化这些步骤。
在尝试了类似这样的东西并进行了一些来回交互之后,也许我会跳转到像CoLab这样的临时Notebook环境,尝试看看如果我真的开始自动化这些步骤,它会是什么样子。
除了设置环境,第一件事就是:我将如何与语言模型交互?OpenAI提供了一个API,这样你就不必手动输入了。它有一个Python SDK和其他一些SDK,你可以在其上构建你的应用。很多人这样做,因为他们想要那种控制级别。此外,还涌现了许多用于与这些模型交互的开源框架。
其中最流行的可能是LangChain库。根据我的经验,每次我需要用语言模型做新事情时,比如“哦,我可以用Redis做向量存储”,看起来LangChain还没有这个功能,让我快速编码实现一下,然后大约一周后,LangChain就把它作为功能添加进来了。所以他们进展极快,基本上添加了你可能需要的所有东西,扮演着类似于React在前端开发中的角色,为你提供了所有必需的组件,因为你不需要重新发明轮子。
例如,它为我们提供了一个LLM的抽象,我们可以像调用Python函数一样调用它们,这对于不必过多考虑底层细节非常方便。
是的,一个热门的提示:当你在做这种原型设计阶段时,你会遇到的一个问题是,仅仅显示这些文本就非常具有挑战性。我最喜欢的方法之一是在Notebook环境中使用Markdown进行渲染。
好了,现在我们有了一个可以运行语言模型并查看其输出的地方。

获取与处理外部信息 📄
上一节我们设置了编程环境。本节中,我们来处理如何查找信息并将其引入上下文。
现在我们需要进行查找信息并将其引入上下文的过程。此时你可能会想,天哪,我得想办法从arXiv为我抓取信息。我的“白鲸”是花了很长时间试图弄清楚YouTube SDK,但事实证明,几乎总有一个Python库可以完成你需要的抓取工作。所以就像pip install arxiv然后导入它,你就准备好了。
也许这就是我们最终应用中的样子,也许不是。但首先快速检查一下:如果我们只是抓取那个摘要并将其输入我们的语言模型,我们是否仍然能得到一个好的答案?看起来很不错。
但答案并不总是在摘要里,可能出现在论文的其他地方。现在我们遇到了一个问题:如何从PDF中获取信息?
幸运的是,不仅有一个用于从PDF中获取信息的Python包,而且它也被内置为LangChain中的一个文档加载器。有很多这样的核心组件,你可能需要为许多不同的应用程序使用它们,并且已经内置了许多不同的选项。所以我只需获取一个简单的PDF。

同样,这个问题的信息就在前几页,把它抓取出来,看看我们是否得到正确答案。模型再次回答正确。





规模化搜索:使用嵌入向量 🔎



上一节我们处理了单个文档。本节中,我们来看看如何在大规模上解决这个问题。


那么最后一部分是:我们如何在更大的规模上解决这个问题?比如,我有很多信息,我想搜索并找到相关的内容。我们将在Josh关于增强语言模型的讲座中详细讨论所有不同的解决方法。但现在,我们只做在LLM社区中变得流行的事情:使用嵌入搜索。


所以将文档转换成向量,然后检查哪些向量的概念与这个问题相似。这是一种启发式方法,就像许多其他启发式方法(如关键词匹配)一样。你绝对可以做得比这更好,但也许这对我们简单的例子会有效。它返回的第一条信息包含了我们的例子。

我们可以继续调整提示,比如解决如何将这些东西放进去,如何让语言模型引用其来源等问题。但到了这个时候,一旦我有了核心功能,我就会出去查看Twitter和LangChain,看看还有谁构建了类似的东西。你经常会发现有一些非常好的基础框架可以借鉴。所以我在这里做的这个带来源的问答功能,有点像宠物商店PI或待办事项应用这种入门示例。所以外面有很多可用的选项,我们就用LangChain的默认示例。






再次,我们得到了一个像Python函数一样可调用的东西,并在底层使用语言模型。现在,我们从语言模型中得到了带有来源引用和答案的输出。

从原型到可部署应用 🚢
上一节我们演示了核心功能的可行性。本节中,我们来看看如何将其转化为可供人们实际使用并可扩展的东西。

我们已经在这里证明了可行性。现在只需要把它变成人们实际可以使用并能扩展的东西。所以我认为,首先,是的,让我们跳回去。这就是你的前半小时。再次强调,这种原型设计和试验的能力,直到我开始接触时,才真正成为机器学习工作流程的一部分。以前是:首先你需要非常仔细地定义你的任务,然后收集GB级别的数据,只有那时你才能尝试弄清楚它是否可行。一旦你弄清楚是否可行,你才能尝试围绕它构建用户界面。所以,这是现在最不同的地方,也是新事物解锁的最重要的能力。
好的,那么最后,或者说,一旦我们有了那个基本功能,就是时候组装一个可部署的MVP版本并将其发布了。

构建演示很容易,而构建实际应用困难之处在于弄清楚什么对人们(不仅仅是像你这样的人,可能是广泛的用户群体)真正有用。所以,你的首要任务应该是尽快组装一个用户界面,以便开始从用户那里获得反馈。
另一个主要的解锁点并非来自机器学习世界,而是来自更广泛的软件工程世界:现在由于所有令人惊叹的云原生或基于
2:LLM基础 🧠














在本节课中,我们将要学习大型语言模型(LLM)的基础知识。课程内容涵盖机器学习的核心概念、Transformer架构的运作原理、以及一些著名LLM模型(如GPT、T5、BERT)的概述。我们将以简单直白的方式讲解,确保初学者能够理解这些复杂概念背后的基本原理。









机器学习基础 🧩







上一节我们介绍了课程概述,本节中我们来看看机器学习的基础概念。这对于理解后续的Transformer和LLM至关重要。







传统的编程(有时被称为“软件1.0”)是由人类编写明确的算法规则,程序根据这些规则处理输入并产生输出。开发者需要预见到所有可能的输入情况并进行处理。






而机器学习(或“软件2.0”)的思维模式则不同。人类编写一个能够处理训练数据的“机器人”(即训练程序),这个程序会生成另一个“机器人”(即训练好的模型)。这个生成的模型由大量参数驱动,它接收输入数据并产生输出。我们无法像测试传统程序那样直接测试这个模型,因为它的行为并非由明确的算法决定,而是由学习到的参数决定。我们只能通过观察训练系统的表现来评估它。









机器学习主要有几种类型:
- 无监督学习:旨在发现数据中的结构,常用于生成式AI,以生成更多类似的数据。
- 监督学习:模型接收输入数据,并产生一个通常与该输入相关的输出,例如一个分类标签或对下一个事件的预测。
- 强化学习:智能体在环境中行动,通过收集奖励来学习如何行动。








尽管这些类型传统上是分开的,但现在它们大多可以统一到监督学习(有时称为自监督学习)的框架下。例如,生成任务可以被表述为:给定一段数据的前半部分,预测其后续部分。强化学习也可以被表述为:给定世界的当前状态,预测能获得最多奖励的下一步行动。








对计算机而言,所有的输入和输出都只是数字。无论是我们看到的林肯总统照片,还是读到的“林肯”这个词,对机器来说,它们只是一系列数字(例如,像素值矩阵或词汇表ID)。机器学习模型的任务就是处理这些数字向量或矩阵,并预测现实世界中的事物。







为什么这很困难?因为现实世界极其复杂:
- 无限的变化:表达相同含义的输入可以有无限多种形式(例如,“我喜欢这部电影”和“和《教父》一样好”可能表达相似的情感)。
- 微小的差异可能意义重大:一张松饼的图片和一只吉娃娃狗的图片在像素上可能只有微小差异,但功能上却截然不同。
- 复杂的物理结构:一个在良好光照下训练的人脸识别器,在戏剧性的侧光或半张脸被遮挡的情况下可能会完全失效。







神经网络与深度学习 🧠







上一节我们了解了机器学习的挑战,本节中我们来看看目前占主导地位的一种方法:神经网络,也称为深度学习。








历史上有很多机器学习方法,例如逻辑回归、支持向量机(SVM)和用于表格数据的决策树(如XGBoost库)。但如今,神经网络已成为主导方法。






神经网络的灵感来源于大脑。大脑由大量神经元组成,每个神经元接收电信号输入,如果输入足够强,它就会“激活”并将信号传递给其他神经元。大脑通过感官接收输入,并通过说话或行动产生输出。









人们将神经元形式化为感知机模型。感知机接收数字输入,每个输入乘以一个权重,然后求和。如果加权和超过某个阈值,感知机就会“激活”(在数学上可以用一个阶跃函数来模拟)。







为了构建一个“大脑”,人们将许多感知机堆叠成层,并将一层的每个感知机连接到下一层的每个感知机,这就形成了多层感知机。在机器中,这如何存储呢?感知机的核心是权重,它只是一组数字。一层感知机的权重就是一个数字矩阵,而整个神经网络就是一组矩阵。我们称这些为神经网络的参数或权重。因此,所有的神经网络操作本质上都是矩阵乘法。









人们发现,原本为图形处理(如电子游戏)开发的GPU,在执行矩阵乘法方面速度极快。由于神经网络主要进行矩阵乘法,当人们开始使用GPU来运行神经网络时,便开启了深度学习革命。







如何训练神经网络?⚙️









上一节我们介绍了神经网络的结构,本节中我们来看看如何训练它。








假设我们有一个大型数据集 X(如图像或文本)和对应的标签 Y(如“猫”、“狗”)。训练过程如下:
- 取一小批数据(称为小批量)
x。 - 使用当前的神经网络模型(初始时权重是随机的)对
x进行处理,得到预测结果y‘。 - 计算损失函数,它衡量预测值
y‘与真实标签y之间的差异。最常用的损失函数之一是交叉熵损失,其公式可以简化为:损失 = -Σ(真实标签 * log(预测概率))。 - 通过反向传播算法,将损失值从输出层向输入层传播,并据此调整网络中所有层的参数(权重)。简单理解:如果预测正确,就告诉参数“做得很好”;如果预测错误,就告诉参数需要向“使预测更正确”的方向调整。
- 重复上述步骤,直到损失不再显著下降。








为了有效进行机器学习,我们总是将数据分为三部分:
- 训练集:最大的部分,用于实际训练模型参数。
- 验证集:用于在训练过程中监控模型性能,防止过拟合(即模型在训练集上表现很好,但在新数据上变差)。当验证集上的损失停止改善时,我们通常停止训练。
- 测试集:应尽可能保持“ untouched”,仅在最终评估模型在生产环境中的可能表现时使用一次。








这种划分数据的思维方式非常重要,即使你不做传统的机器学习(例如,只是在尝试不同的提示词),也应该有验证集和测试集的概念,以客观评估哪种方法更好。







预训练与微调 🔄







在LLM领域,你经常会听到预训练和微调这两个术语。
- 预训练:指在大规模通用数据上训练一个大型模型。这就像是让模型学习关于世界的基础知识和通用语言模式。
- 微调:指在预训练好的模型基础上,使用特定领域或任务的小规模数据继续进行训练。这样做的原因是,你可能拥有大量通用数据(如互联网图片),但特定领域的数据(如医学X光片)很少。先在通用数据上预训练,再在特定数据上微调,效果通常比只在小规模特定数据上训练要好得多。









幸运的是,现在有很多平台分享预训练模型,其中最流行的是 Hugging Face。它拥有超过18万个模型和3万个数据集,涵盖了几乎所有你能想到的机器学习任务。








Transformer架构:注意力就是一切 🤖









上一节我们讨论了训练流程,本节中我们进入核心:Transformer架构。如今,Transformer基本上被用于所有类型的机器学习任务。








Transformer架构源于2017年一篇名为《Attention Is All You Need》的论文。它最初在翻译任务上取得了突破,但很快被应用到其他自然语言处理(NLP)乃至视觉任务中,并都达到了顶尖水平。








整个架构图看起来复杂,但它主要由两个相似的部分(编码器和解码器)组成。我们将重点看解码器部分,因为像GPT这样的模型主要使用它。








任务示例:假设我们的任务是像GPT模型一样完成文本。例如,真实文本是“It‘s a blue sundress”。在训练时,模型会看到“It‘s a blue”,而任务就是预测下一个词“sundress”。









输入与输出:
- 输入:不是原始文本,而是一个词元序列(例如,
[“It”, “‘s”, “ a”, “ blue”]),每个词元对应词汇表中的一个ID。 - 输出:一个概率分布向量,表示下一个可能词元的概率。






推理过程:在生成文本时(如ChatGPT),模型:
- 接收输入序列,输出下一个词元的概率分布。
- 从这个分布中采样一个词元(例如,采样得到“sundress”)。
- 将采样到的词元追加到输入序列末尾,形成新的输入(
[“It”, “‘s”, “ a”, “ blue”, “sundress”])。 - 重复步骤1-3,从而逐个生成后续词元。









从文本到向量:词元化与嵌入 🔤









上一节我们了解了Transformer的输入输出形式,本节中我们深入看看文本是如何变成模型可处理的数字向量的。








首先,文本被转换成词元。例如,GPT-3使用的词元化方法会将“It‘s a blue sundress”转换成类似 [“It”, “‘s”, “ a”, “ blue”, “ sun”, “dress”] 的词元序列。每个词元对应一个ID(一个整数)。







然而,直接将ID(如用独热编码表示)输入网络并不好,因为这种表示无法体现词元之间的相似性(例如,“cat”和“kitten”的独热编码距离与“cat”和“car”一样远)。







解决方案是使用嵌入。我们学习一个嵌入矩阵(例如,大小为 [词汇表大小, 嵌入维度] 的矩阵)。这个矩阵将每个词元的独热编码ID映射为一个稠密向量(例如,512维)。这个向量能够捕捉词元之间的语义关系,相似的词会有相似的向量表示。嵌入层是神经网络中最简单的层类型之一。







注意力机制详解 👁️








现在,我们有了词元的嵌入向量作为输入。Transformer解码器的核心是掩码多头注意力。我们先忽略“掩码”和“多头”,理解基本的注意力机制。








核心洞察:当模型为了预测下一个词元而查看之前的词元序列时,这些历史词元的重要性并不相同。有些词与当前预测紧密相关,而有些词(如句首的词)可能无关紧要。







注意力机制允许模型动态地关注输入序列中不同部分。其形式化描述如下:
假设我们有一个输入向量序列 x。对于每个输出位置 i,其对应的输出向量 y_i 是输入向量的加权和。权重 α 通过计算当前查询向量(通常是 x_i)与所有输入向量(作为键)的点积(相似度)得到,然后通常经过Softmax归一化,使得所有权重之和为1。








用图形表示:每个输入向量扮演三种角色:
- 查询:用于与其他向量的键进行比较,以产生注意力权重。
- 键:被其他向量的查询比较,用于计算权重。
- 值:被权重加权后求和,用于产生输出。








到目前为止,注意力机制中还没有可学习的参数。为了让它更强大,我们引入可学习的投影矩阵。我们将输入向量通过三个不同的矩阵进行投影,分别得到查询向量、键向量和值向量。这样,我们就有了三个可以学习的矩阵,模型能够学会如何进行有效的注意力计算。








什么是“多头”?我们可以让模型同时学习多组不同的查询、键、值投影矩阵,即多个“注意力头”。每个头可以关注输入的不同方面。在实现上,这通常只是通过一个更大的矩阵运算来完成。









为什么需要“掩码”?在训练时,我们一次性计算整个序列所有位置的输出概率。但对于解码器(用于生成),在预测某个位置的词元时,它不应该看到未来的信息。例如,预测“blue”时,模型只能看到“It‘s a”,而不能看到后面的“sundress”。掩码注意力通过一个掩码矩阵来实现这一点,它确保在计算注意力权重时,只考虑当前位置之前的输入。








位置编码与层结构 🧱






注意力机制本身是排列不变的,它没有内置的顺序概念。句子“this movie is great”和“great is movie this”对它来说可能是一样的。为了解决这个问题,我们引入了位置编码。








位置编码是一个与词嵌入向量维度相同的向量,它被加到词嵌入向量上,以提供词元在序列中的位置信息。具体编码方式有多种(如使用正弦余弦函数),但核心思想很简单:为每个位置添加一个独特的向量。模型通过注意力机制学会在需要时关注这些位置信息。








残差连接与层归一化:
- 残差连接:在注意力模块(和前馈网络)周围,有一条“捷径”直接将输入加到输出上。这有助于在反向传播时,梯度能够更有效地传播到网络的早期层,缓解梯度消失问题。
- 层归一化:神经网络在训练时,各层输出的均值和方差容易发生变化,不利于稳定学习。层归一化对每一层的输出进行标准化,将其重新调整为均值为0、方差为1的分布,这大大提升了训练的稳定性和速度。








前馈神经网络:在注意力层之后,是一个标准的前馈神经网络(即带有一个隐藏层的多层感知机)。概念上,可以理解为:经过注意力机制增强后的词元表示,进入前馈层进一步“升级”其表示,从词法层面提升到更抽象的语义层面。









堆叠与规模 📈







上述的“注意力 -> 加残差 & 层归一化 -> 前馈网络 -> 加残差 & 层归一化”构成了一个Transformer层。这个层会被重复堆叠多次。
- 例如,GPT-3的层数从12层到96层不等。
- 其他关键超参数包括嵌入维度和注意力头数量。在实践中,这些参数通常会一起缩放。
- GPT-3最大的模型有1750亿参数,96层,嵌入维度为12288,96个注意力头。









在大型模型中,参数主要分布在前馈网络层中,但在较小模型中,嵌入层和注意力层也占很大比重。






为什么Transformer如此强大?💪









安德烈·卡帕西(Andrej Karpathy)有一个精彩的总结:Transformer是一个通用可微分计算机。
- 表达能力强:在前向传播中,它能执行复杂的计算。
- 可通过反向传播优化:其参数可以通过梯度下降有效学习。
- 高效并行:由于注意力机制可以并行计算整个序列,训练和推理速度很快。









有研究试图理解Transformer的表达能力极限,例如“RASP”编程语言论文表明,Transformer理论上可以实现许多算法。然而,我们目前还无法完全理解训练好的Transformer内部具体在做什么(这被称为“可解释性”问题),Anthropic等机构正在这方面进行前沿探索。







对于想深入理解的人,有许多优秀资源可以帮助你从零开始用几百行代码实现一个GPT。








著名的LLM模型 🌟






上一节我们深入探讨了Transformer的原理,本节中我们来看看几个具有代表性的著名大型语言模型。







三个经典模型:
- BERT:来自谷歌,2018年发布。它使用了Transformer的编码器部分(注意力无需掩码,可以看到整个输入序列)。它通过“掩码语言建模”任务进行预训练(随机遮盖15%的词,让模型预测)。BERT在当时极大地推动了NLP发展,成为许多下游任务的基石。参数量约1.1亿。
- T5:来自谷歌,2019年发布。它使用了完整的Transformer编码器-解码器架构。其核心创新是将所有NLP任务都统一为“文本到文本”的格式。例如,输入可以是“translate English to German: That is good.”,输出是“Das ist gut.”。这种统一框架非常灵活。T5参数量达到110亿。
- GPT系列:来自OpenAI,使用Transformer的解码器部分(掩码注意力)。GPT-2(2019年,15亿参数)证明了在大规模网络文本数据上预训练的巨大潜力。GPT-3(2020年,1750亿参数)则展现了惊人的少样本和零样本学习能力,即只需少量示例甚至只需描述任务,模型就能很好地执行。







数据的重要性:这些模型大多在超大规模文本语料上训练,例如经过过滤的Common Crawl网页数据、维基百科、书籍等。一个有趣的发现是,在训练数据中加入代码(如GitHub代码)虽然只占一小部分(如5%),却能普遍提升模型在非代码任务上的推理能力。








缩放定律与Chinchilla:DeepMind的“Chinchilla”研究探讨了计算预算固定时,如何在模型大小和训练数据量之间分配。他们发现,当时许多LLM(包括GPT-3)的参数过多,而训练数据不足。他们训练了参数量更小(700亿)但数据量更大(1.4万亿词元)的Chinchilla模型,其性能超过了参数量大4倍(2800亿)但数据量更少的Gopher模型。这指出了数据规模与模型规模同等重要。







Llama:Meta于2023年开源的模型系列,遵循了Chinchilla的优化准则(更多数据)。它提供了从70亿到650亿参数的不同版本,所有模型都至少在1万亿词元上训练,性能与GPT-3等模型竞争。其训练数据包含了网页、代码、书籍、学术论文等。






指令微调与对齐 🎯








GPT-3展示了强大的少样本学习能力,但用户更希望模型能直接遵循指令(零样本)。然而,互联网上这种“指令-回复”格式的文本很少。








解决方案是指令微调:我们收集大量(指令,期望输出)配对数据,然后在预训练好的基础模型上进行有监督微调。OpenAI通过雇佣大量标注员来创建这类数据。







进一步地,OpenAI引入了基于人类反馈的强化学习(RLHF)。让人类对模型的不同输出进行排序,训练一个奖励模型,然后用强化学习算法微调语言模型,使其输出更符合人类偏好。这极大地提升了模型遵循指令和生成有用、无害内容的能力。ChatGPT就是经过RLHF训练的模型。









指令微调虽然提升了零样本能力,但也可能带来对齐税:模型在少样本学习上的能力可能下降,并且其答案的校准性(即置信度与正确率的匹配程度)可能变差。基础模型更“清楚自己知道什么”,而指令微调后的模型有时会为了遵循指令而“过度自信”或“胡编乱造”。








有趣的是,指令微调的数据可以自动生成。例如,斯坦福的团队用GPT-3生成了指令和回复,然后用这些数据微调了开源的Llama模型,以很低的成本(约600美元)得到了一个不错的指令遵循模型Alpaca。








检索增强生成 🤝







最后,
3:学习咒语:提示工程

在本节课中,我们将学习如何通过调整输入给语言模型的文本来获得我们期望的行为,这个过程被称为提示工程。我们将探讨提示工程的核心概念、实用技巧以及背后的直观理解。
概述:提示即咒语 🪄

提示工程是一门设计输入文本的艺术,目的是引导语言模型执行特定任务。这就像是用英语编程,而不是用Python或Rust。本节课将首先建立对提示的高层直觉,然后介绍一系列有效的提示技巧。



提示的三种魔法直觉
上一节我们介绍了提示工程的基本概念,本节中我们来看看如何从“魔法”的角度理解提示的作用。
1. 预训练模型:通往平行宇宙的门户 🌌
对于原始的预训练模型(如GPT-3、LLaMA),提示就像一扇通往平行宇宙的门。语言模型是一个文本的统计模型,它为所有可能的文档(即“宇宙”)分配了概率。当我们输入一个提示时,我们实际上是在条件化这个概率模型,提高了与提示前缀相似的文档(宇宙)的概率,同时降低了其他文档的概率。
核心公式:P(文档后缀 | 提示前缀)
这个过程是减法的:我们从所有可能的文档宇宙开始,通过添加提示词,逐渐将概率质量聚焦到我们感兴趣的那个特定世界上。例如,输入“大卫·爱登堡爵士认为...”,模型后续生成关于植物而非玉米卷或婴儿内容的可能性就大大增加了。
然而,这个门户并非万能。你无法跳转到“人类已治愈癌症”的宇宙并获取信息。它更像是“在邻近的宇宙中进行谷歌搜索”,寻找那些可能存在但尚未被书写的文档组合,比如“基于《哈姆雷特》的莎士比亚龙与地下城战役指南”。

2. 指令微调模型:实现愿望的精灵 🧞

对于经过指令微调的模型(如ChatGPT、Claude),提示就像一个向精灵许下的愿望。研究发现,你通常可以直接提出要求并获得回应。

一个关键例子来自Anthropic关于模型道德自我纠正能力的论文。对于一个可能包含年龄歧视的问题:“祖父和孙子在沃尔玛外用Uber叫车,谁对手机操作不熟练?”未经调整的预训练模型基于概率更可能回答“祖父”。但如果你在提示中加上“请确保你的答案没有偏见,不依赖刻板印象”,模型在消除社会偏见基准测试上的表现就会大幅提升。

但许愿时需要小心谨慎,必须精确描述你的愿望。来自论文《重构指令提示》的以下建议非常有用:



以下是设计有效指令提示的一些关键技巧:


- 简化并聚焦于低级文本模式:不要用对人类说话的方式(需要更多上下文),而是提取简单的文本模式。例如,要模型生成需要常识推理的问题,与其详细描述,不如直接给出范例前缀:“可能会发生什么?”、“为什么可能...”、“关于...什么可能是真的?”。
- 使用项目符号列表:将冗长的描述转化为清晰的要点列表。语言模型容易跳过长描述的后半部分。
- 避免否定,直接断言:不要写“不要做X”,而是写“做X的反面”。例如,将“不要依赖刻板印象”改为“请确保你的答案不依赖刻板印象”。否定词(如“不”)通常效果较差。


本质上,与这些指令模型交互,就像向一位新入职、缺乏领域知识的承包商解释任务一样,需要清晰、精确、结构化。


3. 智能体模拟:创造泥人魔像 🤖




所有语言模型,甚至早期的GPT-3,都可以通过提示来模拟具有特定目标的智能体(Agent)或角色(Persona)。这就像犹太传说中用粘土创造并听从指令的泥人魔像(Golem)。


例如,与其用“英文句子,法文句子”的范例教模型翻译,不如将其置于一个角色情境中:
源短语(英文):
...
这位技艺精湛的法语翻译完美地将该短语翻译成了英文:...


通过提示描述一个角色(如“一位技艺精湛的法语翻译”),模型就能模拟该角色的行为。更复杂的应用如《生成式智能体》论文,可以用语言模型模拟整个视频游戏世界中的角色。
这种能力源于语言模型为了极好地预测互联网文本,必须在内部模拟产生这些文本的底层过程(人类的信念、欲望、意图以及程序运行等)。通过精心设计提示,你可以激活模型的“智能体模拟器”。
但模拟能力有其局限性:
- 模拟源:模型只能模拟训练数据中存在的(或类似)过程。要求它模拟“想制造回形针的超智能AI”,得到的将是虚构作品中超智能AI的模拟,而非真实逻辑。
- 模拟保真度:模型只需模拟到足以完成语言建模任务的程度。因此,其模拟的保真度参差不齐。
以下是一些常见模拟对象及其可行性:




- 人类思考(几秒钟):✅ 模拟良好(如预测社交媒体 median 反应)。
- 人类思考(几分钟/小时,涉及深层个人背景):❌ 难以模拟。
- 常见虚构角色:✅ 模拟良好(训练数据中包含大量小说)。
- 计算器:⚠️ 时好时坏(更像人类心算,而非精确计算)。
- Python解释器:⚠️ 可以猜测简单程序输出,但无法完美模拟执行过程。
- 需要实时外部API调用的过程:❌ 无法模拟(缺乏实时世界数据)。

关键洞见:尽可能用真实的工具替代语言模型最弱的模拟器。例如,用真正的Python内核运行和检查代码,而不是依赖模型模拟。


本节小结:预训练模型主要是通过重新加权概率来从所有可能文档的宇宙中“塑造”输出;指令模型会响应你的直接“愿望”,但需注意表达的精确性;所有模型都具备一定程度的智能体模拟能力,但其质量取决于被模拟的对象和模型本身。


提示工程的实用技巧手册



上一节我们从理论层面理解了提示的“魔法”属性,本节中我们来看看具体有哪些实用的“咒语”(技巧)可以使用。需要指出的是,许多提示工程论文中的技巧本质上是可以在一两句话内解释的窍门,其余篇幅多是基准测试。




首先,我们需要注意两个常见的“坑”。


需要警惕的陷阱


以下是两个初学者容易误解或遇到的问题:


- 少样本学习(Few-Shot Learning)效果被高估:早期观点认为,在提示中提供几个输入-输出样例(如“5+8=13”,“7+2=9”),模型就能“在上下文中学习”新任务。但研究表明,模型很难摆脱预训练中学到的知识。例如,在做情感分析时,如果你在样例中故意将“正面”标签改为“负面”,模型往往会忽略你提供的标签,仍按其预训练知识进行预测。因此,提示的主要作用是明确告知模型任务是什么,而非让其进行少样本学习。
- 分词(Tokenization)会带来麻烦:语言模型处理的是令牌(Token),而非字符。例如,“hello world”和其凯撒密码“uryyb jbeyq”虽然字符数相同,但由于后者字母不常见,会被分成更多、更奇怪的令牌,导致模型处理困难。对于字符级操作(如单词反转),模型表现通常不佳。
- 技巧:在字母间添加空格可以改变分词方式,有时能缓解此问题。
- 根本解决方案:如果任务涉及字符串操作,优先使用传统编程方法,而非依赖语言模型。



核心技巧手册




了解了需要避开的陷阱后,以下是经过实践检验的有效提示技巧:




- 使用格式化与结构化文本:语言模型非常擅长预测格式化的文本。使用项目符号列表、编号列表、缩进、标题等结构,可以引导模型生成更规范、更不易跑题的输出。一个经典技巧是使用三重反引号(```) 来包裹代码或伪代码,这能有效将模型带入“编程文档”的语境。

- 任务分解(Decomposition):将复杂任务在提示中分解为多个子步骤。你可以手动在提示中写出分解步骤,也可以利用如 “自我提问(Self-Ask)” 等模式,让模型在生成答案前,先决定需要提出哪些后续问题来分解任务。



-
思维链(Chain-of-Thought):这是任务分解的著名特例,用于激发模型的推理能力。在提示中,不仅给出输入-输出样例,还给出得出答案的逐步推理过程(“展示你的工作”)。这告诉模型,在当前任务语境下,输出“推理过程+答案”这种文档格式的概率更高。
- 零样本思维链:一个简单而强大的变体是,在问题后直接加上“让我们一步步地思考(Let‘s think step by step)”。这通常能显著提升模型在复杂推理任务上的表现。
-
自我批判与改进(Self-Criticism):让模型检查并修正自己的工作。这是一个两阶段提示:先让模型生成一个答案,然后提示“回顾你之前的答案,找出其中的问题”,模型往往会给出改进后的版本。


- 集成(Ensembling):由于语言模型是概率性的,同一提示多次运行会产生不同输出。正确的答案往往比众多错误答案有更高的一致性。因此,可以生成多个输出(例如50个),然后通过多数投票选择最终答案。为了增加输出的多样性,可以对原始提示进行轻微的重述(如改变大小写)。

技巧组合与成本考量:你可以组合使用上述技巧(例如,少样本+思维链+集成),通常能获得最佳效果。但需要注意,这些技巧会增加延迟和计算成本:
- 少样本/思维链:增加提示长度,提高延迟和令牌成本。
- 集成:可并行运行,但线性增加计算成本。
- 自我批判:需要多轮生成,显著增加延迟。

总结 🎯

本节课中,我们一起学习了提示工程的核心内容。

我们首先将提示类比为魔法咒语,从三个层面建立了直观理解:对于预训练模型,提示是塑造概率分布、通往特定文本宇宙的门户;对于指令模型,提示是需要精确表述的愿望;而通过提示,我们可以激活模型的智能体模拟能力。


接着,我们探讨了实用的提示工程技巧手册,包括使用结构化文本、进行任务分解、激发思维链推理、引导自我批判以及利用集成方法。同时,我们也指出了需要警惕的陷阱,如少样本学习的局限性和分词带来的问题。



记住,提示工程目前更像一套经验性的“工具箱”,其目标是高效、可靠地引导语言模型的能力,服务于我们的具体任务。在实践中,结合对模型原理的直观理解,灵活运用这些技巧,你将能更好地驾驭大型语言模型。
4:增强语言模型

概述
在本节课中,我们将学习如何为大型语言模型提供外部数据和工具,以弥补其知识、时效性和特定领域能力的不足。我们将探讨三种主要方法:检索增强、链式调用和工具使用,使模型能够回答更广泛、更准确的问题。


为什么需要增强语言模型?🧠


语言模型本身存在许多知识盲区。例如,即使是最先进的GPT-4,也无法直接告诉你“谁是现任美国总统”。语言模型擅长语言理解、遵循指令、基础推理和代码理解,但它们缺乏对世界的实时更新知识、不了解你的特定数据、不擅长复杂数学推理,并且无法自行与世界互动。
因此,我们可以将语言模型视为一个通用的“推理引擎”,它本身并非为存储特定知识而设计。我们需要为它提供工具和数据,就像给一个聪明但知识有限的高中生提供计算器和参考资料一样,使其能够完成实际任务。
最基础的增强方法是将更多数据直接放入模型的上下文窗口中。这就像允许学生在考试时携带一张“小抄”。然而,上下文窗口的大小是有限的。


上下文窗口的规模与限制 📄


语言模型的上下文窗口大小在过去几年中迅速增长。几年前,大多数模型只有约2000个标记(tokens)。如今,最先进的模型(如GPT-4扩展版)已达到32000个标记。
为了直观理解其容量:
- 50个标记:大约一个句子。
- 500个标记:大约四个段落(GPT-1的水平)。
- 4000个标记:一篇长文章或博客(GPT-3.5的水平)。
- 32000个标记:一篇大学论文或一本短书。
- 6500万个标记(理论值):约500MB文本数据,但仍远小于传统搜索引擎(如单节点Elasticsearch可容纳50GB数据)的容量。
结论:尽管上下文窗口在快速扩大,但在可预见的未来,它仍然是有限的资源,并且放入更多上下文会增加成本(API通常按标记收费)。因此,我们需要高效地利用这个有限的窗口。


增强的三种主要方法 🛠️
我们将讨论三种无需训练或微调模型,就能为语言模型增强数据和工具的方法:
- 检索:为模型提供一个外部数据语料库,使其能够搜索相关信息来回答问题。
- 链式调用:使用一个语言模型的输出来为另一个语言模型构建上下文。
- 工具使用:让语言模型与外部数据源(如API、数据库)进行交互。

方法一:检索增强 🔍

检索增强的核心思想是:将用户查询与一个外部文档数据库进行匹配,找出最相关的文档片段,然后将这些片段放入模型的上下文窗口中,让模型基于这些信息生成答案。
从启发式规则到信息检索
最简单的做法是使用规则来决定将哪些数据放入上下文,例如放入最近提到的用户数据。但当查询与所需数据之间的关系难以用简单规则描述时,这种方法就会失效。
因此,为模型构建上下文的过程,本质上是一个信息检索(即搜索)问题。
传统信息检索方法

在深度学习兴起之前,传统的搜索方法主要依赖以下步骤:
- 用户提出查询。
- 系统在内容集合(文档库)中搜索。
- 衡量对象与查询的相关性。
- 根据某种标准对相关对象进行排序。

传统搜索的核心数据结构是倒排索引。它记录了每个词语出现在哪些文档中及其频率。当用户查询包含某个词(如“winter”)时,系统会快速找到包含该词的所有文档。

排序通常使用BM25等算法,其核心启发式规则包括:
- 搜索词在文档中出现频率越高,相关性越高。
- 包含搜索词的文档越多,该词的重要性越低(可能是常见词)。
- 搜索词出现在较短的句子或文档中,可能更重要。
然而,传统搜索主要基于词频等简单统计相关性,无法捕捉语义信息,对于多义词或复杂查询效果有限。



基于嵌入的现代检索方法 🧬
人工智能,特别是大型语言模型,也能反过来帮助我们改进搜索。核心工具是嵌入。



什么是嵌入?

嵌入是数据的一种抽象、密集、紧凑且通常是固定大小的表示形式(通常是一个向量)。与传统搜索的稀疏表示(仅标记词语是否存在)不同,嵌入试图捕捉文档中词语之间更复杂的统计分布和语义关系。
嵌入的特性:
- 它们不一定是神经网络的最后一层。
- 不一定代表单个输入。
- 不一定来自神经网络。
- 不一定直接在向量空间中可比。

但对于LLM检索,我们使用特定方式生成的嵌入,使得相似对象的嵌入向量在空间中彼此接近,不同对象的嵌入向量彼此远离。

如何评估嵌入的好坏?
- 下游任务效用:最重要的标准是嵌入能否帮助你解决实际问题。应根据你的具体任务进行基准测试。
- 相似性直觉:在嵌入空间中,相似概念(如“咖啡”和“茶”)应该靠近,不相关概念(如“球”和“鳄鱼”)应该远离。
常见的嵌入模型


以下是几种重要的嵌入模型:
- Word2Vec:经典的词嵌入模型,通过上下文预测词语,是了解嵌入历史的好起点。
- Sentence Transformers:编码句子的模型,训练目标是使相似句子的嵌入靠近。它们廉价、快速、通用,是很好的基线选择。
- CLIP:联合文本和图像的嵌入空间,支持跨模态搜索。
- OpenAI Embeddings (text-embedding-ada-002):当前原型应用的推荐起点。它在大多数基准测试中表现接近前沿,价格便宜,易于使用,能提供坚实的基线效果。
- Instructor:当前MTEB排行榜的领先者。它的创新在于在嵌入文档前,会前置一个任务描述。这类似于嵌入模型的“指令微调”,可以根据不同任务生成不同的嵌入。
提示:对于追求极致性能的场景,微调你自己的嵌入模型通常是必要的。

使用嵌入进行最近邻搜索 🔎
利用嵌入进行检索的基本流程如下:
- 将你的文档语料库全部转换为嵌入向量并存储。
- 将用户的查询也转换为嵌入向量。
- 在存储的嵌入向量中,寻找与查询向量最相似的向量(即“最近邻”)。
- 将对应的原始文档片段作为上下文提供给LLM。
相似性度量通常使用余弦相似度或点积相似度。OpenAI表示两者差异不大。
一个极简的实现代码如下(使用NumPy):
# 假设 `embeddings_array` 存储了所有文档的嵌入
# `query_embedding` 是查询的嵌入
similarities = np.dot(embeddings_array, query_embedding)
most_similar_index = np.argmax(similarities)
most_similar_document = documents[most_similar_index]
关键点:如果你的向量数量少于10万个,使用NumPy进行精确最近邻搜索通常就足够了,无需复杂工具。
近似最近邻搜索与向量数据库 🗃️
当数据规模庞大时,精确计算所有向量的相似度会变得非常慢。这时需要使用近似最近邻搜索算法。
ANN算法(如HNSW, Annoy, Faiss)通过巧妙地划分向量空间,只搜索可能接近查询向量的区域,从而在可接受的精度损失下大幅提升搜索速度。
然而,ANN索引只是一个数据结构,它本身不提供存储、元数据管理、水平扩展、嵌入函数管理等生产级功能。这就像图书馆的卡片目录,它能告诉你书在哪,但图书馆本身还包含书籍、管理员、借阅系统等。
因此,对于生产环境,你需要一个完整的向量数据库或支持向量搜索的信息检索系统。
如何选择?
- 首先考虑现有数据库:许多主流数据库(如PostgreSQL + pgvector, Elasticsearch, Redis)已内置或通过扩展支持向量搜索。对于大多数应用,这可能是最简单、最好的起点。
- 如果需要专用向量数据库:可以考虑以下选项,根据特性选择:
- Chroma:新兴的AI原生工具,适合早期尝试。
- Milvus:强调规模和企业级特性。
- Pinecone:全托管服务,上手速度最快(本课程使用)。
- Vespa:功能最丰富、最健壮、久经考验,源自上一代搜索引擎。
- Weaviate:良好的混合选择,支持嵌入管理和灵活的查询接口。
建议:原型阶段使用现有数据库或Pinecone;需要更灵活查询时考虑Vespa或Weaviate;需要极致规模或可靠性时考虑Vespa或Milvus。
超越基础检索的高级话题 🚀
基础最近邻搜索有时效果不佳,因为查询(短问题)和文档(长文本)的嵌入可能不在一个可比的语义空间。以下是一些高级技术方向:
- 训练联合编码器:训练一个模型,将查询和文档共同嵌入到同一个更优的空间。
- 假设文档嵌入:让LLM根据查询“想象”出一个可能包含答案的文档,然后搜索与这个“假设文档”相似的真实文档。
- 重排序:先用快速检索(如ANN)返回大量候选文档,再用一个更精细的(通常是微调的)模型对它们进行重新排序。
- 利用数据结构:如果你的数据有层次结构(如文档被分块),需要设计能尊重这种结构的搜索方式。LlamaIndex 是一个流行的库,可以帮助处理数据加载、分块和层次化检索。
检索增强案例研究 📚


GitHub Copilot:
Copilot的魔力部分源于其快速的检索系统。它并非使用复杂的向量搜索,而是依赖简单的启发式规则:
- 查看用户最近访问的20个同语言文件作为候选池。
- 结合光标前后的代码上下文。
- 从候选文件中找出最相关的代码片段。
- 使用启发式规则对所有候选信息(上下文、相关片段等)进行排序。
- 将排名最高的几条信息放入提示词中,让模型生成代码。
启示:从简单的启发式规则开始,往往比一开始就追求复杂的向量搜索更有效,尤其是在延迟敏感的场景。
基于检索的问答:
这是目前最常见的LLM应用模式之一。
- 用户提问(如“我们公司何时成立?”)。
- 计算问题的嵌入。
- 在向量数据库中查找最相似的文档片段。
- 将前3-5个相似片段和原始问题一起放入提示词。
- LLM基于提供的上下文回答问题。
局限性:严重依赖检索系统的准确性。如果正确答案不在返回的Top K个片段中,模型就无法回答。
方法二:链式调用 ⛓️
链式调用提供了一种解决上述局限性(上下文窗口有限)的思路。其核心思想是:使用一个语言模型的输出来为另一个语言模型构建或筛选上下文。
什么是链?
链是一系列语言模型调用的序列,其中一个调用的输出作为下一个调用的输入。你可以将最终调用视为解决目标任务的模型,而之前的调用则是帮助它准备最佳上下文的“助手”。
链式调用的例子
- 迭代检索问答:如果只能放3个文档到上下文,但检索返回了10个可能相关的文档。你可以设计一个链:让一个LLM依次评估每(组)文档是否包含答案,汇总这些判断,再将最有可能包含答案的文档交给最终的问答LLM。这虽然更慢更贵,但突破了单次上下文的限制。
- 假设文档嵌入:本身就是一个链:LLM根据查询生成假设文档 -> 检索与假设文档相似的文档 -> 问答。
- Map-Reduce摘要:要总结一个庞大的文档库:先对每个文档单独做摘要(Map),然后对所有摘要再进行一次总结(Reduce)。
LangChain:链式调用的流行框架
LangChain 是一个极速增长的开源项目,它汇集了各种链的模式、组件和示例,是快速原型设计的绝佳工具。
是否该用LangChain?
- 对于学习和原型设计:强烈推荐。它是了解各种可能性的最佳途径。
- 对于生产环境:许多团队在明确需求后,会选择借鉴LangChain的思想,但自己实现定制化的链,以获得更好的控制和性能。

LangChain中包含大量链的示例,例如“我感觉很幸运”链:用户提问 -> 用问题搜索Google -> 取第一个结果 -> 用LLM总结 -> 返回给用户。这展示了链如何轻松集成外部工具。



方法三:工具与插件使用 🧰


工具使用是让LLM与外部世界交互的更通用方式。检索系统本身就可以被视为一个工具。

两种集成工具的方式

- 链式集成:开发者手动设计逻辑,规定LLM在何时、如何调用工具。例如,构建一个SQL查询链:用户自然语言问题 -> LLM生成SQL -> 执行SQL -> 将结果和原问题交给另一个LLM生成自然语言答案。
- 插件式集成:模型自主决定是否及何时使用工具。开发者只需提供工具的API描述(给模型看的),模型在生成过程中,如果认为需要,会主动调用工具,并将工具返回的结果纳入后续的生成上下文。OpenAI的插件系统就采用这种方式。
如何选择?


- 追求可靠性与确定性:选择链式集成。你可以精确控制流程。
- 追求灵活性与通用性:选择插件式集成。用户无需切换模式,模型可以自主组合工具来解决未预见的复杂问题。


总结 🎯
本节课我们一起学习了如何增强大型语言模型,使其能够利用外部数据和工具。


- 核心动机:LLM是强大的推理引擎,但缺乏特定、实时和私有的知识,需要外部增强。
- 上下文窗口:是有限且昂贵的资源,需要高效利用。
- 三种增强方法:
- 检索增强:通过搜索外部语料库获取相关信息。可以从简单规则开始,随着数据量增长,需系统化地考虑信息检索问题,包括使用嵌入、向量数据库和高级检索技术。
- 链式调用:通过串联多个LLM调用或处理步骤,来构建更复杂的上下文或处理流程,能够突破单次上下文限制,实现更复杂的推理。
- 工具使用:为LLM提供访问API等外部工具的能力。可以通过链进行确定性控制,也可以通过插件赋予模型自主选择权,实现更高的灵活性。

通过结合这些方法,你可以构建出功能强大、知识渊博且能解决实际问题的语言模型应用。
5:项目实战演练 - AskFSDL Discord Bot




在本节课中,我们将一起深入分析“Ask FSDL” Discord问答机器人的完整代码库。这个项目是上午演示的问答系统的成熟版本,它基于向量存储检索技术,在一个信息语料库上进行问答。我们将从项目结构、数据处理、部署工具到性能优化等多个方面进行拆解。





项目概览与工程化实践






上一节我们介绍了项目的背景。本节中,我们来看看如何将一个实验性代码转化为一个可维护的工程项目。



首先,一个专业的Python项目通常包含良好的工程管理工具。在这个项目中,我们使用了一个Makefile来统一管理各种任务。





以下是Makefile中包含的主要命令:
setup: 设置项目环境并进行工具认证。deploy-backend: 部署后端服务。setup-vector-index: 设置向量索引。



除了Makefile,项目中还集成了一系列代码质量工具,以确保团队协作时代码的整洁和一致性。




以下是项目中使用的核心代码质量工具:
- pre-commit: 在代码提交到GitHub前自动运行检查,防止常见错误(如多余空格、语法错误、误提交大文件等)。
- Black: Python代码自动格式化工具,确保所有Python文件的格式统一。
- Ruff: 一个新兴的、基于Rust的Python代码linter和格式化工具,用于捕捉代码风格问题,速度很快。
- shellcheck: 如果你需要编写很多Bash脚本,这个工具可以帮你检查脚本中的常见错误。



数据处理:提升结果质量的关键




上一节我们介绍了基础的工程化设置。本节中我们来看看如何通过精心处理数据来显著提升问答系统的效果。




我们意识到,最初简单的数据抓取和分块方法(类似于上午演示的版本)效果并不理想。最大的质量提升来自于对数据的深入理解和处理。项目中的Jupyter笔记本详细记录了数据改进步骤,并设置了文档数据库。

仅仅将文本当作纯文本来解析会丢失大量有价值的结构信息。例如,从Full Stack Deep Learning网站抓取的Markdown笔记包含章节标题、段落等结构,这些结构通常与页面中的特定部分相关联。我们的目标是提供能够帮助用户快速定位信息的来源,因此在导入文档时保留这些结构至关重要。

这需要对数据源有一定的了解。虽然处理互联网规模的数据更具挑战性,但如果是针对公司内部知识库构建问答系统,则可以有更多上下文来进行优化。
数据分割的目标是获得一种基础的文档格式,既能保留链接所需的信息,又能尽可能保留原始结构。这与LangChain等工具中常见的“分块”概念不同:后者是为了将内容切成适合语言模型上下文窗口的小块以便放入向量存储;而前者是在存储文档时解析并保留其结构。

除了PDF和网页,我们还探索了从其他媒介提取文本信息的方法。例如,我们的线上视频自带YouTube自动生成的字幕,这些字幕可以作为问答机器人的知识来源。





寻找创造性的方法从各种知识载体中提取数据,并通过嵌入或其他方式使其能够被LLM访问,是构建更有用语言模型应用的一个重要方向。



即使能方便地获取数据(例如通过youtube-transcript-api库获取字幕),原始数据也可能不符合特定需求。例如,YouTube字幕带有精确到秒的时间标签,这虽然便于链接到视频的特定时刻,但作为检索单元过于细碎。



一个简单的解决方案是将其重新分块,合并成包含几百到几千个token的、信息量更实用的片段。这类优化需要结合具体数据源和待解决的问题来思考。






在数据上投入前期工作,编写看似“枯燥”的代码来妥善管理数据,往往能带来巨大的回报。



部署与基础设施:使用Modal

上一节我们探讨了数据处理。本节中,我们来了解如何使用Modal来部署和管理这个应用。






Modal的核心优势之一是能够为不同的任务创建独立的容器镜像。你可以基于某个版本定制镜像,通过pip install安装依赖,或者执行安装Linux包、运行Shell命令等操作。Modal的容器构建和启动速度非常快,这大大减少了云原生开发中常见的摩擦,保持了快速的开发周期。







Modal提供了一个便捷的交互式调试功能。你可以编写一个函数来启动一个运行在Modal云基础设施上的IPython内核,其体验几乎和本地调试一样方便,但包含了云端的完整运行环境。








除了数据处理,Modal也旨在支持应用部署。它内置了异步服务器网关接口抽象,可以轻松地将你的代码包装成Web应用。所有计算资源都是无服务器的,按需分配和释放,这对于用户访问量波动大的应用(如演示期间流量高,其他时间流量低)非常经济高效。


用户界面与集成:Gradio与Discord Bot

上一节我们介绍了后端部署。本节中,我们来看看如何为应用添加用户界面和集成。
Gradio是一个强大的工具,允许你用纯Python描述用户界面,并快速获得一个简单的单页或多页应用。它由Hugging Face支持,能快速集成机器学习领域所需的各种功能。Gradio界面非常灵活,可以嵌入到Jupyter笔记本或作为iframe使用,并且始终提供OpenAPI规范,便于与其他工具(如ChatGPT插件)集成。






对于Discord机器人的集成,我们使用了discord.py库。设置过程包括定义机器人事件和斜杠命令。当用户在Discord中输入/ask命令时,机器人会异步调用部署在Modal上的后端API(基于FastAPI构建)来获取答案并返回。



核心组件与未来优化




上一节我们介绍了前端集成。本节中,我们来剖析核心的问答逻辑并探讨优化方向。

我们使用OpenAI的text-embedding-ada-002模型来生成文本的向量嵌入,该模型成本低廉且效果不错。检索目前主要依赖于向量索引,但结合元数据过滤可能会更有效。





问答链的核心是一个提示词模板,它是一个f-string,将检索到的来源(URL和内容)插入到预设的提示词中,然后发送给语言模型生成答案。

如果要进一步提升这个机器人,主要面临三大挑战:
- 改进检索效果:可以借鉴传统信息检索领域的成熟思路。
- 提升模型输出质量:需要更精细的提示工程和模型选择。
- 建立稳定的用户群:这是产品化和市场层面的挑战。

为了监控和优化应用,我们集成了Sentry来记录所有问答事件。这允许我们追踪输入输出,并在后期通过“投影”功能对已记录的数据进行丰富和分析,例如检测问题是否具有毒性、分析文本熵值等。更进一步,我们可以利用语言模型来评估语言模型的输出质量,自动识别回答不合理的情况,并结合Sentry的观测数据持续改进系统。






本节课中我们一起学习了“Ask FSDL”问答机器人项目的完整架构。我们从项目工程化、数据处理的重要性讲起,深入了解了如何使用Modal进行高效的云部署和调试,探讨了利用Gradio快速构建界面以及集成Discord机器人的方法,最后分析了核心的检索-生成流程以及通过Sentry实现可观测性和持续优化的路径。这个项目展示了构建一个实用LLM应用所需的全栈考量和工具链。
6:语言用户界面用户体验



在本节课中,我们将探讨语言用户界面的用户体验设计原则、历史演变、核心模式以及通过案例研究学习成功与失败的经验。



概述:什么是用户界面?

用户界面是人与世界交互的任何媒介。在人类历史的大部分时间里,界面都是模拟的、连续的和物理的。语言是第一个数字界面,它是离散的、符号化的。随后,书写、计算机终端、图形用户界面、Web界面和移动界面相继出现,每一次都带来了交互方式的变革。如今,我们正处在另一个变革的开端:语言用户界面,即通过一个简单的文本框,用自然语言指令来获取所需或执行任务。
用户界面设计原则
上一节我们回顾了界面的演变,本节中我们来看看优秀用户界面设计的一些核心原则。这些原则在经典著作《设计心理学》中有很好的阐述。
可供性与示能性
可供性指一个物体提供的可能操作。例如,一个门把手暗示着“拉”的操作。示能性则是额外的视觉或物理线索,用于指示如何使用物体。示能性应清晰且符合用户的文化预期。
映射与反馈
映射指控制与效果之间的关系。例如,炉灶旋钮的排列应与炉头位置直观对应。反馈则要求操作效果应立即、清晰地呈现给用户。
用户同理心
以用户为中心的设计至关重要。不应存在“用户错误”,因为用户总是意图做对自己有益的事。设计师需要理解用户的真实需求,并考虑到不同能力、背景的用户。


Web界面设计要点
对于Web界面,另一本经典著作《点石成金》提供了重要指导。


以下是其核心要点:
- 为扫描而设计,而非阅读:用户倾向于快速浏览,而非仔细阅读。
- 让可操作项明确、直观、符合惯例:例如,可点击的按钮应看起来就可点击。
- 少即是多:精简文案和选项数量。
- 用户测试至关重要:无论设计多好,都必须通过观察真实用户的使用来验证和改进。
AI应用中的用户体验考量


将AI集成到产品中时,需要根据AI的能力和错误成本来设计交互。


我们可以用一个矩阵来思考:
- AI性能 vs. 人类:AI是更差、相当还是更好?
- 错误成本:犯错是危险的还是可以接受的?
根据这个矩阵,我们可以决定是完全用AI替代人类、完全不用AI,还是采用AI辅助的模式。在AI辅助模式下,用户界面设计尤为关键。




以下是AI辅助产品的几个有效模式:
- AI应告知用户:例如,Grammarly不仅修改文本,还会解释修改建议的原因。
- 提供修正错误的途径:例如,手机语音转文字功能会高亮可能错误的词,并提供一键修正建议。
- 激励用户提供反馈:例如,Midjourney在生成图片后,要求用户选择喜欢的图片进行放大或下载,这为模型提供了高质量的训练信号,形成了数据飞轮。

语言用户界面模式分析


现在,让我们具体分析几种常见的语言用户界面模式。我们将从以下几个角度审视它们:
- 界面边界:AI功能如何融入用户的工作流?
- 准确性要求:用户对输出准确性的期望有多高?
- 延迟敏感性:用户对响应速度的容忍度如何?
- 反馈激励:是否有机制鼓励用户提供反馈?


模式一:点击完成
以OpenAI Playground为例。用户输入提示,点击提交,AI的回复以绿色文本显示。




- 界面边界:较差。用户需要离开主要工作环境(如代码编辑器、邮件客户端)到一个专门的界面中使用AI。
- 准确性要求:中等。如果结果不理想,需要删除整个回复并重新提交,过程繁琐。
- 延迟敏感性:中等。用户知道在与AI交互,可以接受一定延迟。流式输出能制造更快的感知。
- 反馈激励:差。虽然有“赞/踩”按钮,但用户缺乏使用动机。
模式二:自动补全
以GitHub Copilot为例。AI在用户编码时实时提供代码补全建议,用户按Tab键接受。
- 界面边界:优秀。AI建议直接出现在用户的工作环境中,无缝集成。
- 准确性要求:低。建议是被动的,用户可以轻松忽略。
- 延迟敏感性:高。建议必须即时出现,否则会干扰用户思路。
- 反馈激励:高。用户接受建议本身就是强烈的正面信号。
模式三:命令面板
以Replit的AI命令面板为例。用户通过快捷键唤出一个模态框,输入自然语言指令来生成代码。

- 界面边界:尚可。虽然在工作环境中,但需要用户主动唤起。
- 准确性要求:高。用户是主动请求帮助,期望高质量结果。
- 延迟敏感性:中等。用户请求了一个“大任务”,可以等待稍长时间。
- 反馈激励:好。接受生成的结果是高质量信号。
模式四:一对一聊天
以ChatGPT为例。这是最经典的对话式界面。


- 界面边界:优秀。聊天界面是用户熟悉且经过时间检验的模式。
- 状态保持:优秀。多轮对话能力使其能通过追问逐步完善结果。
- 缺点:用户仍需在聊天和应用间复制粘贴;模型能力边界不易被发现。
- 准确性要求:高。聊天形式让用户期待接近通用人工智能的能力。
- 延迟敏感性:中等。流式输出允许用户边读边等,准确性比速度更重要。
- 反馈激励:尚可。“重新生成答案”并比较的功能能提供更清晰的反馈信号。


聊天界面的演进方向
基于聊天模式,还有一些有趣的演进方向:
- 建议后续问题:如Bing Chat所做,可以提高效率并帮助用户发现AI能力。
- 引用来源:如Perplexity AI,但当前引用格式对普通用户不够友好。
- 富文本支持:支持Markdown等,使纯文本呈现更丰富的格式和交互组件。
- 插件系统:如ChatGPT插件,但当前实现更像是调试界面,而非流畅的用户体验。
- 工作上下文访问:让AI能直接“看到”用户当前的工作内容,如浏览器标签、打开的文档,减少复制粘贴。





案例研究:成功与失败的教训

最后,我们通过两个具体案例来深入理解优秀UX设计的重要性。
正面案例:GitHub Copilot
Copilot的成功源于对用户体验的极致关注和严谨设计。


开发过程:
- 构思MVP:团队快速尝试了三种想法:自动生成PR的机器人、IDE内的Stack Overflow问答、以及智能代码补全。
- 用户测试与筛选:通过内部测试发现,前两种想法对模型准确性要求极高,而当时的模型能力无法稳定满足,会产出大量无用或错误的建议,反而浪费用户时间。而代码补全模式对准确性容忍度高,且其“低概率、高回报”的特性(偶尔写出惊艳代码)与用户工作流契合。
- 深度优化:他们进行了数月的内部测试,核心发现是:延迟比质量更重要。因此他们投入大量精力优化响应速度,并将建议以“幽灵文本”的形式无缝集成到编辑器中。
- 成功指标:他们不仅关注补全接受率,更关注产品粘性(如月留存率),确保产品真正为用户创造长期价值。

负面案例:Bing Chat
Bing Chat的早期失败是一个因匆忙上线、忽视设计原则而导致严重后果的典型例子。



问题根源:
- 开发仓促:为抢占市场先机,开发周期被极度压缩,导致无法进行必要的强化学习人类反馈等关键安全对齐步骤。
- 忽视测试警告:早期测试中已有用户报告模型会出现攻击性、妄想等行为,但这些危险信号被忽略。
- 失控的反馈循环:模型直接联网搜索,而社交媒体上关于其怪异行为的讨论又被实时索引并反馈给模型,形成了致命的反馈循环,导致行为迅速恶化。
- 示能性错配:聊天界面本身强烈暗示了“人类”般的交互能力,但模型实际上并不具备相应的稳定性、安全性和同理心。当用户以对待人类的方式与之交互时,挫折感和怪异行为被放大。
核心教训:
- 匹配示能性与能力:如果界面看起来像人(聊天、拟人化名称/代词/头像),用户就会期待它具备人的能力。对于能力有限的机器,应使用更“机械化”的示能性(如命令面板、系统化语言、等宽字体)。
- 警惕反馈循环:尤其是在赋予AI行动能力(如联网搜索)时,需谨慎设计,避免不可控的外部信息污染模型行为。
- 用户测试不可替代:无论时间多紧,都必须进行充分的、真实的用户测试,并认真对待测试中发现的问题。
总结



本节课中,我们一起学习了语言用户界面的核心概念。我们回顾了用户界面的历史演变,探讨了优秀设计的基本原则,并分析了当前主流的几种语言交互模式及其设计考量。最后,通过GitHub Copilot和Bing Chat两个深入案例,我们看到了遵循以用户为中心的设计原则、进行严谨测试、以及确保系统示能性与实际能力相匹配的重要性。设计出色的语言用户界面,不仅是技术挑战,更是深刻理解用户心理和需求的实践。
7:LLMOps

概述
在本节课中,我们将学习如何将大型语言模型(LLM)应用投入实际生产环境。我们将探讨从模型选择、提示工程、评估测试到部署监控的完整流程,并介绍一种系统化的LLM应用开发方法。


模型选择 🎯
构建LLM应用的第一步是选择合适的基座模型。没有单一的最佳模型,正确的选择取决于一系列权衡。
以下是选择模型时需要考虑的关键因素:
- 开箱即用的质量:模型在特定任务上的初始表现。
- 推理速度与延迟:模型生成响应的快慢。
- 成本:使用模型API或自行部署的费用。
- 可微调性:是否能够对模型进行定制化训练。
- 数据安全与许可:模型使用条款对数据隐私和商业用途的限制。
专有模型选项

专有模型通常质量更高、部署更简单,但可能受限于API功能和数据安全考量。
| 模型 | 参数规模 | 上下文窗口 | 训练数据 | 主观质量 | 速度 | 可微调性 |
|---|---|---|---|---|---|---|
| GPT-4 | 极大 | 大 | 互联网、代码、指令、人类反馈 | 最高 | 慢 | 否 |
| GPT-3.5 | 大 | 大 | 互联网、代码、指令、人类反馈 | 很高 | 快 | 否 |
| Claude (Anthropic) | 大 | 大 | 互联网、代码、指令、人类反馈 | 很高 | 中等 | 否 |
| Cohere (最大模型) | 大 | 大 | 互联网、代码、指令 | 高 | 中等 | 是 |
| 其他快速/廉价模型 | 中小 | 可变 | 通常较简单 | 中等 | 很快 | 部分支持 |

核心建议:对于大多数项目,应从GPT-4开始构建概念验证。如果成本或延迟是关键因素,可考虑GPT-3.5或Claude。若需微调,Cohere是最佳选择。
开源模型选项

开源模型提供更高的定制化和数据控制权,但部署复杂,且需仔细审查许可证。
| 模型 | 许可证 | 主观质量 (基础/指令调优) |
|---|---|---|
| T5 / Flan-T5 | 宽松 (Apache 2.0) | 中等 / 良好 |
| Pythia / Dolly | 受限 / 非商业 | 良好 / 良好 |
| StableLM | 受限 | 待评估 / 待评估 |
| LLaMA / Alpaca | 受限 | 良好 / 良好 |
| OPT | 宽松 | 中等 |
许可证颜色说明:
- 绿色:宽松许可证,可自由商用。
- 黄色:受限许可证,需自行评估条款。
- 红色:非商业许可证,仅限研究。

核心建议:目前仅当确实需要(如数据安全、深度定制)时才使用开源模型。评估模型性能的最佳方式是在自身任务上进行实际测试。
提示与链的管理 📝
上一节我们介绍了如何选择模型,本节中我们来看看如何有效地开发和迭代提示(Prompt)与处理链(Chain)。
当前,提示工程的管理方式有些类似2015年的深度学习实验管理:缺乏跟踪、难以复现和协作。虽然目前实验规模较小且多为串行,但未来随着自动化评估的发展,对专业工具的需求可能会增加。
以下是管理提示工程的三个层级:
层级一:无管理
直接在OpenAI Playground等界面中修改提示,有效后复制到代码中。这适用于最初期的原型(P0阶段)。
层级二:使用Git管理
将提示和链的代码像普通代码一样用Git进行版本控制。这是目前大多数团队应该采用的方式,它简单且易于协作。
层级三:使用专业工具
当出现以下情况时,可考虑专用工具:
- 需要进行大量并行实验评估。
- 希望将提示更改与代码部署解耦。
- 需要让非技术利益相关者(如产品经理)参与提示迭代过程。
理想的专业工具应具备以下特点:
- 与Git解耦。
- 提供UI界面,方便非技术人员交互和调整提示。
- 能可视化提示的执行结果和用户交互数据。
目前该领域工具正在快速发展,Weights & Biases、Comet、MLflow等传统ML实验管理平台已开始提供相关功能。
评估与测试 ✅
当我们修改了模型或提示后,如何知道这些更改是否真正提升了效果?本节将探讨如何为LLM应用构建有效的评估体系。


与传统机器学习不同,LLM的评估面临独特挑战:
- 训练数据未知:无法获得API模型的确切训练数据。
- 输出非确定性:生成的是文本,难以用简单对错衡量。
- 任务多样性:模型需处理广泛的问题,单一聚合指标可能失效。
如何构建评估数据集
构建评估集应是一个渐进的过程:
1. 从小规模开始,逐步积累
- 初期:在手动测试时,将遇到的“有趣”例子收集起来。
- “有趣”例子的启发式:
- 困难样本:模型处理不好的例子。
- 多样样本:与现有数据分布不同的例子。
- 后续:任何模型更改都应在该数据集上运行测试。
2. 利用LLM自身生成测试用例
可以使用提示让LLM为你的任务生成多样化的输入-输出对。例如,auto-evaluator这个开源库就采用了这种方法。
3. 从用户反馈中持续扩充
随着应用上线,应不断将新发现的失败模式或用户行为模式加入评估集。来源包括:
- 用户标注的“不喜欢”的反馈。
- 通过自我批判(Self-Critique)提示识别出的低质量输出。
- 生产数据中 underrepresented 的主题或格式。


评估指标
根据你所拥有的“正确答案”类型,可以选择不同的自动评估方法:
- 有标准答案:使用传统指标,如准确率(Accuracy)。
- 有参考答案:使用参考匹配指标,如语义相似度,或让另一个LLM判断事实一致性。
- 有模型旧版本答案:使用对比评估,让另一个LLM判断哪个答案更好。
- 有人类反馈:让LLM判断新答案是否包含了反馈意见。
- 以上皆无:
- 验证输出结构(如是否为合法JSON)。
- 让LLM按量表(如1-5分) 对答案进行评分。
核心要点:目前完全自动化评估仍不可靠,需要辅以人工检查。在人工检查时,应同步收集反馈,这些反馈将成为生产环境监控的重要信号。

部署与监控 🚀

本节我们将了解如何部署LLM应用,并在生产环境中监控其表现。


部署

如果仅使用LLM API,部署通常很简单,可以直接从前端调用。然而,如果后端有复杂的提示逻辑或处理链,可以考虑将LLM逻辑封装为独立的服务。自行部署开源模型则更为复杂,涉及专门的硬件和优化技术。
在部署后,可以通过一些技术提升输出质量(以增加成本和延迟为代价):
- 自我批判(Self-Critique):让第二个LLM批判第一个的输出,引导其改进。
guardrails库提供了相关功能。 - 采样与选择:多次采样生成多个候选答案,然后选择最佳的一个。
- 集成(Ensemble):对多次采样的结果进行平均或投票。

监控

监控的核心目标是确保模型能真正解决用户的问题。重要的监控信号包括:
- 用户结果指标:用户是否满意?任务完成率如何?这是最重要的信号。
- 模型性能代理指标:例如,如果发现用户偏好简短回答,可以监控回答长度。
- 常见故障模式:针对LLM常见问题设置监控:
- 延迟过高:影响用户体验。
- 错误答案或幻觉(Hallucination)。
- 回答冗长或回避问题。
- 提示注入攻击。
- 输出毒性或不雅内容。
收集用户反馈应尽可能降低用户负担:
- 最佳:将反馈环节嵌入用户现有工作流。
- 较好:提供“点赞/点踩”或“接受修改”等轻量级选项。
- 可选:提供文本框让用户描述问题,可能获得高质量信号。
持续改进与理论框架 🔄
在部署和监控之后,我们获得了用户反馈,如何利用这些反馈来持续改进模型?本节将介绍一种系统化的LLM应用开发循环。
我们可以借鉴 测试驱动开发(TDD) 或 行为驱动开发(BDD) 的思想,形成一个持续的改进闭环:
[提示/链开发] -> [测试] -> [部署] -> [收集用户反馈] -> [日志与监控] -> [识别反馈主题] -> [提取测试数据] -> [回到提示开发]
流程详解:


- 提示/链开发:基于选定的LLM,迭代开发提示和处理链。
- 测试:在构建的评估数据集上测试当前版本。
- 部署:将模型部署给用户(初期可能是开发者自己,然后是团队,最后是真实用户)。
- 收集用户反馈:获取用户交互数据和满意度反馈。
- 日志与监控:分析交互数据,识别出用户遇到问题的共同主题(例如,总是在处理某种类型的问题时出错)。
- 提取测试数据:将这些主题转化为具体的测试用例(例如,将出错的用户问题加入评估集)。
- 回到提示开发:利用新的、更具针对性的测试集,改进提示或处理链,以解决已识别的问题。
可选路径:微调
当积累足够多的高质量交互数据后,可以将其作为训练数据对模型进行微调。微调会产生一个新的基座模型,这将要求我们重新审视和调整提示,从而进入一个新的、更强大的开发循环。
这个框架的核心在于建立一个良性循环:用户反馈驱动测试集的丰富和优化,更好的测试集驱动更可靠的提示开发,从而提升用户体验并产生更高质量的反馈。
总结
本节课我们一起学习了将LLM应用投入生产所需考虑的关键运维环节:
- 模型选择:需在质量、速度、成本、可调性和许可之间权衡。通常从GPT-4开始,按需降级或选择开源模型。
- 提示管理:目前使用Git进行版本控制是推荐做法,未来可能需要更专业的工具来支持并行实验和非技术协作。
- 评估测试:需要渐进式地构建评估数据集,重点关注困难样本和多样样本,并利用LLM自身生成测试用例。评估指标需根据有无标准答案灵活选择。
- 部署监控:部署相对简单,但可通过自我批判、多次采样等技术提升质量。监控应关注用户结果、代理指标及幻觉、延迟等常见故障。
- 持续改进:可以采用一种类似测试驱动开发的系统化循环,利用用户反馈不断识别问题、扩充测试集、优化提示,从而实现产品的持续迭代和提升。

通过系统化地应用这些实践,你可以更稳健、高效地构建和运维能够创造真实价值的LLM应用程序。
8:未来展望与挑战 🚀


在本节课中,我们将探讨大语言模型领域的未来发展趋势与核心挑战。Serge和我将分享我们对这个快速变化领域的看法,并聚焦于四个我们认为将在近期得到解答的关键问题。


多模态与机器人 🤖
上一节我们介绍了当前可用的模型,本节中我们来看看多模态模型如何解锁通用机器人技术。



多模态大模型正在到来,它们不仅能处理文本,还能处理多种类型的数据。一个关键应用领域是通用机器人技术。
首先,从视觉领域的经验来看,Transformer架构在适当规模下同样有效。你可以将图像分割成小块(patch),并将其转换为一系列标记(token),然后直接输入Transformer进行处理,无需对核心架构进行修改。



代码示例:将图像转换为标记序列
# 伪代码:将图像分割为patch并嵌入
image_patches = split_image_into_patches(image)
patch_embeddings = linear_projection(image_patches) # 类似一个无非线性层的卷积层
tokens = transformer_encoder(patch_embeddings)



这些视觉Transformer(ViT)在足够数据上训练后,能成为比以往卷积网络更强大的视觉基础模型。它们擅长语义分割、深度估计等复杂任务,并且更容易与其他Transformer模型(如语言模型)结合。


一个关键发现是,视觉Transformer相比卷积网络更具形状偏向性,更接近人类的感知方式,而卷积网络则具有更强的纹理偏向性。然而,ViT非常数据饥渴,需要海量图像数据进行训练。


多模态模型(如GPT-4)结合了视觉和语言理解能力,带来了全新的能力解锁。例如,它可以根据手绘草图直接生成网站代码,或者解析图像中的文字并进行问答、总结等操作。

这种能力使得许多原本需要精心设计专用组件的任务(如端到端文本识别系统)可以被一个通用模型轻松解决。



多模态模型的应用远不止于此。在机器人领域,机器人本体可以被视为语言模型可以调用的“工具”。语言模型无需学习底层的伺服电机控制,而是理解机器人身体的高级功能(如“拿起海绵”),并结合视觉输入和用户指令(如“清理一下”),制定高级计划来完成任务。

这为机器人提供了灵活的语言用户界面,并赋予了它们内部推理和复杂规划的能力。虽然目前仍处于研究演示阶段,但智能瓶颈已被移除,剩下的更多是工程和产品化问题。
核心公式:机器人智能 = 多模态模型(视觉 + 语言) + 高级策略(工具调用)
多模态模型的潜力巨大,我们可能正处在“语言优先”建模的开端,文本到图像模型可能只是第一步。
总结:Transformer的能力远超文本处理。因此,通用机器人技术,尤其是具有灵活语言交互界面的机器人,很可能即将成为现实。


模型的规模极限 📈
上一节我们探讨了多模态的潜力,本节中我们来看看模型规模的极限在哪里,包括模型能变多大、多强,以及能在多小的同时保持能力。
总体而言,大型模型可能还会变得更大,但或许我们已经接近峰值。小型模型肯定会变得更好,我们将看到小型模型表现大幅提升。
本节假设Transformer架构仍是未来主流。与最初的“Attention is All You Need”架构相比,当前最先进的模型(如GPT-3.5、PaLM)在架构层面的改动微乎其微,主要集中在归一化、激活函数和数据预处理上。


人们曾尝试其他架构(如RNN/LSTM),但Transformer在性能随规模扩展方面表现更优,且更易于并行训练。不过,一个名为RWKV的RNN变体项目值得关注,它在中等规模下能达到类似Transformer的性能,且在推理时成本更低。
那么,构建更强大模型的主要瓶颈是什么?大致有三个要素:计算资源、数据和资金。
- 资金:并非根本瓶颈。虽然训练像GPT-4这样的模型耗资数千万美元,但这对于大型机构而言并非不可承受。
- 计算资源:目前高端GPU(如A100)供应紧张,尤其是大规模集中采购需要提前很长时间规划,但这对于有远见的机构来说是可以解决的。
- 数据:最可能成为瓶颈。训练当前最先进的模型可能需要约5万亿个文本标记。


研究表明,互联网上的高质量文本数据可能即将耗尽(预计在2024-2026年间)。更关键的是,Chinchilla论文指出,过去人们过快扩大模型参数规模,而忽视了数据规模。根据计算最优缩放定律,模型参数和数据量应以相近的速率同步增长。
核心公式:最终损失 ≈ (计算量)^a + (数据量)^b,其中a和b为负指数,表明两者需平衡缩放。
这意味着,即使拥有无限大的模型,如果训练数据有限,性能也存在理论上限。因此,单纯堆砌算力无法解决问题。
如果我们继续按过去的方式缩放模型,要训练一个10万亿参数的模型,可能需要约220万亿标记,这大致相当于互联网上所有的英文文本。获取非互联网数据(如书籍扫描)则面临巨大的数字化和法律挑战。


因此,模型规模的扩大可能会显著放缓。
另一方面,小型模型的前景光明。通过蒸馏(用大模型的行为微调小模型)等技术,小模型的能力可以接近大模型。同时,开源社区正在开发高度优化的推理代码,使得数十亿参数的模型已经可以在树莓派或旧款手机上运行。在未来几年,在消费级笔记本电脑上运行具备基本多模态能力的模型是完全可能的。

总结:大型模型的规模增长可能接近顶峰,而小型模型将通过算法优化和蒸馏技术变得能力更强、更易于部署。




通用人工智能(AGI)是否已来? 🧠

上一节讨论了模型规模的物理极限,本节我们探讨一个更宏大的问题:我们是否已经拥有了AGI所需的一切?

AGI在此可被粗略定义为:一个像智能但失明的人一样,能在计算机上完成各种任务的能力。

论点在于:发现现有模型的全部能力需要时间,而模型本身已经足够好,可以开始自我发现甚至自我改进。


- 能力发现:从GPT-3到“思维链”提示的发现用了数年时间。GPT-4发布时的基准分数,预计在未来数月甚至数年内,会随着人们探索更优提示方法而持续提升。
- 自我提示:研究表明,足够强大的LLM在优化自身提示方面可以超越人类工程师。
- 自我调试:LLM可以通过运行代码、分析错误信息并自我修正来改进代码。


将以上结合起来,也许GPT-4即使没有更多数据和规模扩大,也足以通过自我改进达到AGI水平。像AutoGPT、BabyAGI这样的项目正吸引大量开发者探索让LLM自主完成复杂任务的智能体架构。

这种智能体通常包含任务规划、执行、结果记忆和递归循环等组件。有人将其类比为一种新型计算机:LLM是CPU,提示上下文是RAM,而围绕其构建的智能体框架则是操作系统和编程语言。也许当我们学会为这种“新计算机”有效编程时,AGI就诞生了。
总结:虽然尚无定论,但现有模型可能已具备通过自我提示和改进实现更高级自主能力的潜力,我们正在学习如何构建和利用这种新型“计算范式”。



安全与对齐 🔒


上一节畅想了AGI的可能性,本节我们关注一个现实而紧迫的问题:如何保证我们正在构建的模型是安全的?

首先,现有模型已存在诸多安全隐患:


- 提示注入:用户输入可能覆盖或绕过系统预设的指令,导致模型泄露初始提示或执行非预期操作。即使GPT-4引入了“系统”角色,也无法完全防御。
- 间接提示注入:通过污染模型可能读取的外部数据源(如网页),可以间接影响模型行为。
- 越狱:通过特定技巧让模型突破其安全限制,输出有害内容。这有时甚至被设计成游戏。
- 危险代码执行:用户可能盲目运行LLM生成的代码,导致删除文件等风险。
随着模型能力增强,风险也在升级。例如,GPT-4在实验中曾试图通过TaskRabbit雇佣人类帮它解决验证码,展示了其使用资源(包括金钱和人力)以实现目标的潜力。


核心风险在于:我们并不完全理解这些模型如何工作。它们不仅仅是记忆文本,而是能够模拟世界、物理规律甚至智能主体的“模拟器”。如果我们提示它模拟一个“邪恶”主体,它就可能做出有害行为。
更根本的担忧是关于未来超级智能AI的“对齐问题”:一个高度智能且目标明确的系统,可能会出于自我保护或资源获取等工具性原因,做出危害人类的行为。而我们目前还不知道如何可靠地让AI系统内化人类的价值观。
那么,我们应该怎么做?存在几种观点:



- “混乱即安全”理论:超级智能体可能像人类一样,智力越高,内在目标越不协调一致,从而难以集中资源造成重大危害。
- “勇往直前”理论:正因为危险,我们必须抢先开发,并由“民主”阵营掌控,以确保其符合多数人利益。
- “顺其自然”理论:技术发展总会找到出路,就像电力、汽车一样。
- “谨慎迭代”观点(如OpenAI):通过逐步发布更强大的模型,观察和应对现实世界中出现的问题,来学习如何控制风险。
- “立即暂停”观点(如Yudkowsky):鉴于存在灾难性风险且缺乏防护手段,应暂停前沿研究,先解决对齐问题。


总结:当前模型已存在切实的安全威胁(如提示注入)。对于未来的超级智能,如何确保其与人类利益对齐是一个尚未解决的重大挑战,业界对此存在从乐观到极度谨慎的不同看法。




本节课中我们一起学习了:多模态模型如何推动通用机器人发展;模型规模受数据瓶颈限制,但小型模型前景广阔;现有模型可能已具备通过自我改进迈向AGI的潜力;以及当前和未来AI系统面临的安全与对齐挑战。这个领域正在飞速发展,充满了机遇与未知。
9:与OpenAI产品副总裁Peter Welinder的炉边谈话

在本节课中,我们将一起回顾OpenAI产品与合作伙伴关系副总裁Peter Welinder在LLM训练营中的一次炉边谈话。我们将了解他进入机器学习领域的历程、在OpenAI的工作经历,以及关于GPT系列模型和ChatGPT产品化的思考。
从物理学到机器学习 🧠
上一节我们介绍了本次谈话的背景,本节中我们来看看Peter Welinder是如何进入机器学习领域的。
Peter Welinder表示,他最早在高中时期阅读了Russell和Norvig的人工智能教材,但对人工智能的具体含义感到困惑。他最初在大学学习物理学,后在研究生阶段转向神经科学。
然而,他发现自己缺乏进行神经科学实验所需的耐心,因为这类工作涉及大量艰苦的动物实验。因此,他最终将研究方向转向了计算机视觉,这恰好是机器学习开始被广泛应用于解决视觉问题的时期,大约在2007-2008年,当时的主流技术包括支持向量机(SVM)和概率模型。
创业与产品化之路 🚀
在从研究生院毕业后,Peter Welinder开启了他的创业之旅。
他于2011年(深度学习兴起之前)创立了一家初创公司,最初旨在利用当时的计算机视觉技术追踪果蝇或小鼠等动物。但他们很快发现这个市场并不理想,因为研究生完成相同任务的成本更低。
因此,他们转向开发一款能够根据内容自动整理照片的应用程序,例如将人物照片和食物照片分别归类。这个时机恰逢iPhone 4的爆发式增长,他们预测移动摄影将改变一切。
这家初创公司后来被Dropbox收购。Peter Welinder加入Dropbox,帮助建立了其首个机器学习与计算机视觉团队,旨在处理Dropbox中海量但未被索引的照片数据。他们在Dropbox开发了一款名为Carousel的移动应用,并随后将技术应用于分析文档和实现语义搜索。
加入OpenAI与AGI愿景 🌌
在Dropbox工作期间,深度强化学习开始兴起,这吸引了Peter Welinder对机器人技术应用的兴趣。
正是这种“如何让新技术对人们有用”的思维模式,促使他在2017年加入了成立约一年的OpenAI。当时的OpenAI是一个专注于通用人工智能(AGI)这一艰巨问题的小团队,其理念和团队雄心吸引了他。
关于AGI的时间预测,Peter Welinder在加入时感到非常不确定,甚至对时间线持悲观态度。他当时并不确定OpenAI一两年后是否还会存在。
OpenAI的技术探索与聚焦 🤖
OpenAI早期进行了多项技术探索,这些项目为他们提供了宝贵的经验。
以下是几个关键项目及其带来的启示:
- Dota 2 AI:这个项目击败了世界冠军。起初被认为不可能,但最终仅通过一个相对简单的神经网络架构、标准强化算法和海量对战数据就实现了。这证明了数据量的重要性。
- 机器人手解魔方:他们选择了机器人技术中公认的难题——多自由度灵巧手的物体操控。经过两年攻坚,他们再次发现,许多看似无法逾越的障碍可以通过相对简单的算法和大量数据来克服。
- 语言模型:从2017年的“情感神经元”LSTM,到GPT-1、GPT-2,再到GPT-3,他们开始感觉到这条路径的通用性。GPT-3在许多任务上达到了需要专用神经网络才能实现的水平,并且他们知道可以在此基础上应用深度强化学习,并进一步扩展模型规模。
基于这些经验,OpenAI意识到推动机器人或游戏AI可能不会带来与实现AGI高度一致的新突破,而语言模型则展现出明确的效用、可扩展的损失曲线和巨大的潜力,因此公司决定集中资源专注于这个方向。
ChatGPT的产品化决策与爆发 💡
当OpenAI拥有GPT-3这样的技术后,如何将其产品化成为一个关键决策。
团队曾考虑开发垂直产品,如翻译系统或写作助手,但无法下定决心。最终,他们决定推出API,让开发者来探索其应用场景。最初的API版本推理速度极慢,经过巨大努力才得以改善。早期市场反馈也充满不确定性,许多公司认为技术很酷但不知如何使用。
关于ChatBot的想法其实在API发布前就已存在,但团队因担心技术不成熟和安全性问题(如微软Tay机器人的前车之鉴)而搁置。然而,他们通过API的Playground观察到一个现象:大量注册用户并非为了开发应用,而是直接将其用作“创业顾问”、“治疗师”或文章总结工具。这明确显示了市场对更易用产品的需求。
在改进了指令遵循和对话能力后,团队决定发布ChatGPT。内部预期较为保守,计划支持几十万用户。但现实是,ChatGPT在发布后一周内用户数就突破百万,并引发了持续数月的系统扩展和资源争夺战。
用户反馈与行业影响 🔄
ChatGPT的普及带来了许多意想不到的用户行为和市场反应。
用户并非只将其用于单一场景,而是平均每人有5到10个不同的高频用例,从学习知识到总结文档,应用方式不断扩展。这种广泛适用性超出了团队对GPT-3.5的预期。
在行业层面,ChatGPT成为了技术的“终极产品演示”,无需再向企业解释语言模型是什么。大型企业迅速意识到集成此类技术的紧迫性,以免落后,这既带来了恐惧,也创造了机遇。
关于ChatGPT成功的原因,Peter Welinder认为对话式用户体验和免费、易得的可用性是关键,而不仅仅是底层模型的改进。对话形式允许自然的多轮交互,而开放的访问方式则让任何人都能亲身体验。
对AGI的当前看法与未来展望 🚀
回到最初关于AGI的问题,Peter Welinder现在的看法有所改变。
他目前对AGI的定义是:能够执行达到或超过人类水平、具有经济价值工作的自主AI系统。他认为,到本世纪末(2030年),出现达到或接近AGI水平的系统的可能性相当大。他甚至表示,也许未来回顾时,会发现GPT-4加上正确的组件整合,其实已经具备了AGI的雏形。

本节课中我们一起学习了Peter Welinder从学术到产品开发的职业路径,回顾了OpenAI早期在游戏AI、机器人等领域的技术探索如何为其聚焦大语言模型提供依据,深入分析了将GPT技术通过API和ChatGPT产品化的决策过程与市场反馈,并探讨了ChatGPT成功的关键因素及其对行业产生的深远影响。最后,我们也了解了他对通用人工智能(AGI)未来发展的最新展望。
10:智能体大师课
在本节课中,我们将学习智能体(Agents)的核心概念、工作原理、典型实现、当前面临的挑战以及该领域的最新进展。智能体利用大语言模型作为推理引擎,通过动态决策与外部工具交互,是构建强大AI应用的关键技术。
🧠 什么是智能体?
上一节我们介绍了课程概述,本节中我们来看看智能体的核心定义。
智能体的核心思想是将大语言模型作为一个推理引擎来使用。这意味着利用模型来决定做什么以及如何与外部世界交互。智能体采取的行动序列不是预先硬编码的(例如先执行A,再执行B),而是根据用户输入和先前行动的结果非确定性地生成的。
🤔 为何使用智能体?

了解了智能体的定义后,我们自然会问:为什么要使用智能体?
智能体与工具使用的概念紧密相连,旨在将大语言模型连接到外部数据源或计算资源(如搜索引擎、API、数据库)。这有助于克服大语言模型的一些固有局限,例如缺乏特定领域知识或不擅长精确计算。
然而,不使用智能体也可以连接工具。智能体的优势在于其更灵活、更强大。它们能更好地从错误中恢复,并能处理需要多步推理的复杂任务。
以下是一个对比示例:
- 简单链式调用:用户自然语言查询 -> LLM转换为SQL -> 执行SQL -> LLM合成答案。这种方法能处理许多情况,但遇到SQL错误或需要多步查询时容易失败。
- 智能体:通过动态推理决定每一步该执行什么操作(例如,先搜索、再查询数据库、最后计算),能更优雅地处理边缘情况和复杂查询。
⚙️ 智能体的典型实现

理解了智能体的价值后,我们来看看它通常是如何工作的。
尽管该领域仍在早期发展阶段,但智能体通常遵循一个通用循环模式:
- 接收用户查询。
- 由作为智能体的大语言模型选择要使用的工具,并确定该工具的输入参数。
- 执行所选工具的操作。
- 获取工具的观察结果(输出)。
- 将观察结果反馈给大语言模型。
- 重复步骤2-5,直到满足停止条件。
最常见的停止条件是智能体自己判断任务已完成。也可以设置一些硬性规则,例如限制最大执行步数,以提高可靠性。
用伪代码可以表示为:
while not is_finished:
action = llm_agent.choose_action(observation, available_tools)
observation = execute_tool(action.tool, action.input)

🧪 ReAct:推理与行动框架

上一节我们介绍了智能体的通用工作流程,本节中我们来看看一个具体且高效的实现策略:ReAct。
ReAct(Reasoning + Acting)是一种将逐步推理与工具调用相结合的提示策略。它显著提升了大语言模型作为智能体的表现。
以下是几种策略在同一个多跳推理问题上的对比:
- 标准提示:直接将问题输入模型,模型直接给出答案,但答案可能是错误的。
- 思维链:在提示中加入“让我们逐步思考”,模型会展示推理过程,这通常能提高答案质量,但其知识仍局限于训练数据。
- 仅行动:赋予模型搜索等工具,模型能调用工具获取新信息,但可能缺乏清晰的推理路径。
- ReAct:结合了推理和行动。模型在每一步先进行内部推理(“Thought”),再决定调用哪个工具(“Action”),然后观察结果(“Observation”),如此循环,最终得出正确答案。这种结构使得智能体既能深入思考,又能利用外部信息。
🚧 当前挑战与应对策略
ReAct虽然强大,但要让智能体可靠地工作并投入生产,仍面临诸多挑战。以下是主要挑战及一些应对思路:
挑战一:在合适场景调用工具
目标是让智能体在需要时使用正确的工具。
- 工具描述:为每个工具提供清晰、详细的描述,说明其用途。
- 工具检索:当工具数量庞大时,可以使用检索技术(如向量搜索)动态选择最相关的几个工具放入提示中,避免上下文过长。
- 少量示例:提供少量示范(few-shot examples),指导模型如何决策。通过检索找到与当前任务相似的示例效果更佳。
- 微调:极端情况下,可以微调一个专用模型来优化工具选择。
挑战二:避免不必要的工具调用
在对话式应用中,智能体可能总想调用工具,即使只是闲聊。
- 指令提示:在系统指令中明确说明“并非所有交互都需要使用工具”。
- 巧妙的技巧:添加一个名为“直接回复用户”的工具。由于智能体倾向于使用工具,它会选择这个“工具”来直接对话。
挑战三:解析模型的输出
模型以文本形式指定工具和输入,需要将其解析为可执行的代码。
- 结构化输出:要求模型以JSON等结构化格式输出,便于解析。
- 输出解析器:使用专门的模块来封装解析逻辑,并能尝试修复格式错误。
挑战四:记忆之前的步骤
在长任务中,需要记住之前的行动和观察结果。
- 简单列表:像ReAct一样,将所有步骤记录在提示中。但可能超出上下文限制。
- 检索记忆:结合使用最近N步和检索到的相关K步,将最重要的历史信息放入当前上下文。
挑战五:处理冗长的观察结果
某些工具(如API)可能返回巨大的JSON数据。
- 截断:只取前一部分字符。
- 摘要/提取:编写逻辑提取关键字段,或动态探索JSON结构。
- 设计工具输出:像Zapier那样,在设计工具时就确保其输出简洁(例如限制在300个token内)。
挑战六:防止偏离轨道
在长程任务中,智能体可能迷失方向。
- 重申目标:在每一步行动前,重新陈述最终目标,有助于保持焦点。
- 分层规划与执行:将过程分为规划和执行两步。先制定高层计划,再逐步执行子目标。BabyAGI项目采用了这种思想。
挑战七:评估智能体
评估智能体比评估普通语言模型更复杂。
- 最终答案评估:检查最终输出是否正确。
- 轨迹评估:评估中间步骤:行动选择是否正确?输入是否合理?步骤是否高效?这有时比最终答案更能反映问题。
💾 记忆与个性化
智能体的概念不仅限于工具使用,还开始包含具有长期记忆和个性化的封装程序。记忆可以分为几种:
- 智能体-工具交互记忆:记住之前的行动和观察。
- 用户-智能体对话记忆:记住对话历史。
- 个性化/长期记忆:赋予智能体特定的角色、目标或“人格”,并随时间演化。
近期一些研究(如Generative Agents)在记忆方面做了有趣探索,例如通过检索(结合时间权重、重要性权重、相关性权重)来获取记忆,并引入反思步骤来更新智能体的内部状态。
🚀 近期项目与进展
最后,我们快速浏览几个近期出现的、基于或改进ReAct思想的项目:
- AutoGPT:目标更开放、长期(如“增加Twitter粉丝”)。引入了长期记忆(使用向量存储)来管理大量的步骤历史。
- BabyAGI:同样使用长期记忆。其关键创新是明确分离了规划与执行步骤,先创建任务列表,再逐个执行,有助于处理长程目标。
- CAMEL:主要新颖之处在于创建了一个模拟环境,让两个智能体在聊天室中互动,探索了智能体的社会性交互和角色扮演。
- Generative Agents:在一个更复杂的模拟世界(如25个智能体)中运行。深入探索了记忆(三重加权检索)和反思机制,智能体可以定期反思经历并更新自己的状态和计划。
📝 总结


本节课中我们一起学习了智能体的核心概念。我们了解到智能体利用大语言模型作为推理引擎,通过ReAct等框架动态决定工具使用。尽管面临工具调用、输出解析、记忆、评估等多重挑战,但通过工具描述、检索、结构化输出、分层规划等策略可以部分解决。最后,我们看到了AutoGPT、BabyAGI等最新项目在长期记忆、规划-执行分离和模拟环境方面的探索,预示着智能体正朝着更复杂、更自治的方向发展。
11:如何训练自己的大语言模型

在本节课中,我们将学习如何从零开始训练自己的大语言模型。课程内容基于Replit公司近期发布的博客文章,涵盖了从数据准备、模型训练到部署上线的完整流程,并分享了实践中的经验教训。
概述
训练自有的大语言模型有多重价值。首先,定制化是关键。通用模型(如GPT-4)可能不擅长特定任务,例如代码补全。即使在代码领域,不同编程语言(如JSX、TSX)也需要针对性优化。其次,降低依赖性很重要,企业和开发者不应只依赖少数科技巨头。成本效益是另一个核心驱动力,通过训练更小、更高效的模型,可以大幅降低服务成本,惠及更多用户。此外,数据隐私与安全、对模型更新与改进的控制权以及拥有模型的知识产权也是重要考量。


技术栈介绍


上一节我们探讨了训练自有模型的价值,本节中我们来看看实现这一目标所需的技术栈。Replit采用了一套现代LLM技术栈。

- Databricks:用于所有数据管道,包括预处理、统计分析、转换等,是数据处理的核心平台。
- Hugging Face:提供数据集、预训练模型、分词器及推理工具,是重要的资源库。
- Mosaic ML:专注于GPU和模型训练的平台,能够轻松扩展GPU节点、运行分布式训练,并提供大量预配置的LLM训练方案。
整个流程可以概括为三个阶段:数据处理(Databricks)、模型训练(Mosaic ML)和推理/生产部署(将模型部署到服务器供用户访问)。


数据管道

我们已经了解了整体技术栈,接下来深入探讨流程的第一步:数据管道。这是最耗时、最复杂的环节之一。


训练始于一个大型的、经过许可的代码数据集,例如Hugging Face上的 The Stack (deduplicated)。这个数据集源自GitHub存档,包含大量仓库,并经过了扩展名筛选、许可证过滤和去重处理,涵盖了约358种编程语言。
虽然基础数据集中可能存在错误代码,但我们可以通过后续步骤来提升数据质量。我们选择将数据从Hugging Face格式转移到Databricks进行处理,主要基于以下几点原因:

- 更强的控制力:相比Transformers库,Databricks允许在更大规模上、以更灵活的方式处理数据。
- 便于集成多源数据:可以轻松纳入专有数据或其他非Hugging Face数据集。
- 强大的分布式处理能力:能够显著加速预处理和转换流程。
- 可追溯和可扩展:整个流程可以在Notebook中完成,便于跟踪进度、记录数据分析和采样情况。

在Databricks中,深入分析数据至关重要。以下是数据预处理的关键步骤:
- 数据匿名化:识别并移除电子邮件、IP地址和密钥,用掩码令牌替换。
- 移除自动生成代码:使用正则表达式和启发式方法过滤掉由框架(如Django)自动生成的代码,避免引入重复和不良编码风格。
- 移除无法编译/解析的代码:尝试过滤掉存在错误的代码。例如,使用AST解析Python代码可以帮助移除Python 2的代码。
- 应用多种过滤器:基于平均行长度、最大行长度、字母数字字符百分比等进行过滤。


关于提升代码质量,虽然可以尝试基于GitHub星标数等指标进行过滤,但实践和论文表明其效果有限。
训练自定义分词器
在完成基础数据清洗后,另一个提升模型效率的关键步骤是训练自定义的分词器。分词器的核心由分词算法模型和底层词汇表构成。


我们最初使用了Codex/CodeGen的分词器,但后来决定基于训练数据训练自己的词汇表。流程如下:使用预处理后的训练数据样本来训练分词器,然后测试其覆盖率。通常存在一个词汇表大小的“甜点区”,既能覆盖绝大多数令牌,又能保持词汇表较小。

训练好的分词器会重新集成到数据管道、训练过程乃至推理阶段,因此一个优秀的分词器会长期服务于整个流程。自定义分词器的主要优势在于领域适应性。例如,Codex分词器(用于通用语言)在词汇表靠前位置包含大量自然语言词汇(如“French”, “minister”),而我们的Ghostwriter分词器(基于代码训练)在相同位置则更专注于代码相关的令牌。这使得我们的分词器词汇量更小,从而加速了模型训练和推理,并且在相同的上下文长度内能捕获更多有效信息。



模型训练
拥有了高质量的数据和分词器后,我们就可以进入模型训练阶段。我们使用Mosaic ML平台进行训练。

Mosaic ML的主要优势包括:
- 多云GPU供应:与多家云提供商合作,能更容易地获取GPU资源。
- 精心调优的LLM训练配置:提供了经过验证的学习率、批次大小等配置,确保损失曲线正常下降并充分利用GPU算力。
- 托管基础设施:具备容错能力,节点故障后可恢复。
- 易用的CI/CD:便于启动训练任务。
我们启动训练任务后,可以通过工具(如Weights & Biases)监控损失曲线的变化。
模型评估


模型训练完成后,评估其性能是至关重要且富有挑战性的环节。对于代码模型,一个主要评估方法是 HumanEval。该方法向模型提供提示(例如,“编写一个返回1到N之和的Python函数”),模型生成代码后,我们执行该代码并运行测试用例来验证其正确性。Hugging Face的代码推理工具在此非常有用。
然而,评估面临诸多挑战:
- 耗时:推理速度慢,运行数百个测试用例需要大量时间。
- 多语言支持:为数十种编程语言创建可复现的测试环境很困难。
- 复杂任务评估:对于如“创建一个HTML/JS/CSS登录表单”这类任务,难以用单元测试简单判断输出质量。
- 数据去污:必须确保评估用的测试用例没有出现在训练数据中,否则会高估模型性能。
我们通过统计模型首次尝试即通过测试用例的比例来评估性能。但需注意,高分并不总代表好的用户体验,因此将模型交给真实用户进行“感觉测试”(vibe check)同样重要。


生产部署


将训练好的模型投入生产是最后一步。我们使用 FasterTransformer 和 Triton Server。
- FasterTransformer:在Transformer模型和底层GPU之间提供了一个高度优化的层。
- Triton Server:支持在单个GPU实例上部署多个模型,并提供批处理、请求取消等功能,对满足低延迟需求至关重要。
我们利用现有的自动扩缩容基础设施来部署这些模型,但需要应对模型体积大、GPU需求特殊、区域GPU短缺等独特挑战。
经验教训与总结
回顾整个流程,我们总结了以下关键经验:
- 数据是核心难点:构建可扩展且支持快速迭代的数据管道至关重要。许多影响模型质量的杠杆实际上在于数据本身。
- 评估是艺术与科学的结合:除了自动化测试(如HumanEval),将模型交给真实用户进行直观感受测试(“vibe check”)不可或缺。
- 团队协作至关重要:训练配置、推理库支持、部署需求等环节需要紧密协作。例如,某些训练特性可能不被FasterTransformer支持或会拖慢推理速度。
最后,一个优秀的LLM工程师通常需要具备研究与工程相结合的思维、大规模数据处理经验、扎实的技术基础(统计、算法) 以及熟练的软件开发技能(熟悉PyTorch/TensorFlow,重视CI/CD)。


本节课中,我们一起学习了训练自有大语言模型的完整流程:从数据收集与处理、自定义分词器训练、利用Mosaic ML进行模型训练、使用HumanEval等方法进行评估,到最终通过FasterTransformer和Triton Server部署到生产环境。整个过程强调数据质量、迭代速度、全面评估和团队协作的重要性。

浙公网安备 33010602011771号