杜克大学大语言模型实践笔记-全-

杜克大学大语言模型实践笔记(全)

大型语言模型实践:1.1:认识课程讲师阿尔弗雷德·德萨 👨‍🏫

在本节课中,我们将认识本课程的讲师阿尔弗雷德·德萨,并了解他的专业背景与教学理念。

大家好,我是阿尔弗雷德·德萨。我很高兴为大家带来这门关于生成式人工智能的入门课程。本课程将涵盖生成式人工智能的方方面面,包括它的工作原理,以及拥有或与生成式人工智能应用互动究竟意味着什么。

我的背景是编程。我曾担任多年的软件工程师。

我最初是一名系统管理员,之后转型从事了一些开发运维的工作。

我将软件工程应用于开发运维和运营的原则与概念。

我曾担任发布经理,并在多种不同类型的工程团队中工作过。

在我的整个职业生涯中,我对教学充满热情。我不仅热爱教学,也乐于分享我的知识。我希望你能发现这些关于生成式人工智能的基础知识,以及我作为一名软件工程师、运营人员,乃至如今作为杜克大学兼职教授的教学经验,都能以一种易于消化和理解的方式呈现给你。

我认为这门课程包含了众多不同的方面和概念。希望你能发现这些基础知识很有用,从而能在你的学习旅程中迈出下一步,并在你发现更多可以运用生成式人工智能的潜在方式时,尝试应用其中的一些概念。

本节课中,我们一起认识了讲师阿尔弗雷德·德萨,了解了他从软件工程到开发运维的丰富技术背景,以及他致力于以清晰易懂的方式分享生成式人工智能基础知识的教学热情。这为后续课程内容的学习奠定了良好的基础。

大型语言模型实践:02:认识你的课程讲师德里克·威尔士

在本节课中,我们将认识本课程的讲师德里克·威尔士,并了解他将在后续课程中带领我们学习的内容。

大家好,我是德里克。我毕业于杜克大学数据科学项目,目前在一家大型科技公司担任产品经理。

今天,我将向大家展示如何使用 OpenAI 的 DALL·E 模型,根据文本生成图像。请注意,这项技术发展非常迅速,从录制本课程到您学习时,部分模型可能已经更新。因此,请务必查阅课程资料中提供的最新文档。

我知道大家在前面的课程中已经接触过 OpenAI API。但在接下来的章节开始前,我将首先演示如何设置 GitHub Codespaces 作为开发环境。我认为这是一种极佳的云端开发方式,无需担心本地机器的任何依赖问题,并且能让你使用 Copilot 等工具,我们将在课程后续部分进一步讨论。

好的,感谢大家。让我们开始吧。😊


本节课中,我们一起认识了讲师德里克·威尔士,并初步了解了课程将涵盖使用 DALL·E 模型生成图像以及设置云端开发环境等内容。

大型语言模型实践:P3:03_01_04:关于本课程 📚

在本节课中,我们将概述整个课程将要探讨的核心概念与主题。课程旨在为您提供生成式AI的坚实基础,涵盖从基础理论到实际应用部署的完整流程。

我们将从生成式AI的基础知识开始,了解其基本构成。接着,我们会深入探讨大型语言模型及其在当前生成式AI领域中的现状。

上一节我们介绍了课程的整体框架,本节中我们来看看具体的课程模块。

以下是本课程将涵盖的主要主题:

  • 生成式AI基础与大型语言模型:学习生成式AI的基本原理,并了解当前主流的大型语言模型。
  • 提示工程:掌握与大型语言模型有效沟通的技巧,以获得更优质的响应。缺乏良好的提示技巧可能导致响应质量不佳。
  • 构建健壮的生成式AI系统:例如,学习如何扩展或增强大型语言模型应用中的响应能力。
  • 检索增强生成:探索一种称为RAG的技术。其核心概念是:RAG = 大型语言模型 + 外部知识检索。该技术能扩展模型的能力,使其能够利用训练时未掌握的新信息。
  • 实践应用与部署:学习如何将构建的应用部署到云端,了解结合了RAG、云端服务和大型语言模型的API如何工作,以及这些组件如何协同运作。
  • 动手实践:包括使用OpenAI等API构建应用、生成图像,以及进行微调。微调是指基于新信息,让大型语言模型获得额外特定能力的技术。

所有这些内容旨在为您打下坚实的知识基础。这些概念和知识将引导您迈出正确的第一步,帮助您更好地理解生成式AI,了解各个组件如何协同工作,并为您规划明确的后续学习路径,以便您在未来探索如何将这些概念应用于构建生成式AI应用。

本节课中我们一起学习了本课程的整体结构和核心模块,从理论基础到动手实践,为后续深入学习做好了准备。

大型语言模型实践:P4:引言与基础

概述

在本节课中,我们将学习生成式人工智能的基础知识。课程将涵盖人工智能的简要历史与演变、大型语言模型的工作原理及其应用,以及构建这些模型所需的关键步骤。目标是为你提供一个清晰、坚实的理解基础。

人工智能的简要历史与演变

上一节我们概述了课程内容,本节中我们来看看人工智能的发展历程。人工智能并非一夜之间出现,其发展跨越了数十年。

人工智能的概念和研究始于20世纪50年代。早期的AI专注于基于规则的系统,这些系统依赖于人类编写的明确指令来执行任务。

随着时间的推移,计算能力的提升和数据量的增长推动了机器学习的发展。机器学习使计算机能够从数据中学习模式,而无需为每个任务进行显式编程。

近年来,深度学习的突破,特别是神经网络技术的进步,引领了当前生成式AI的浪潮。我们现在所处的阶段,模型能够生成全新的、类似人类创作的内容。

大型语言模型的工作原理与应用

了解了AI的演变后,本节我们来看看当前的核心——大型语言模型是如何工作并应用于实践的。

大型语言模型是一种基于深度学习的模型,通过在大量文本数据上进行训练,学习预测序列中下一个词的概率。其核心是一个称为“Transformer”的神经网络架构。

一个简化的下一个词预测公式可以表示为:
P(下一个词 | 上下文词序列)

在应用中,这些模型通过接收用户的输入(提示),然后根据其训练所学,生成最有可能的后续文本序列来工作。

以下是LLMs常见的几种应用方式:

  • 文本生成:如撰写文章、故事或邮件。
  • 问答系统:基于给定文档或知识回答问题。
  • 代码生成与解释:辅助编写或理解编程代码。
  • 语言翻译:在不同语言之间进行转换。

大型语言模型的创建过程

我们已经了解了LLMs如何工作,最后,我们来探讨构建一个大型语言模型需要经历哪些步骤。这个过程虽然复杂,但可以分解为几个关键阶段。

创建大型语言模型主要涉及三个核心阶段:预训练、微调和部署。

以下是每个阶段的简要说明:

  1. 预训练:这是最耗资源的阶段。模型在超大规模的文本数据集(如整个互联网的公开文本)上进行训练,学习语言的基本规律、事实和推理能力。这相当于让模型“博览群书”。
  2. 微调:预训练后的模型是“通才”。为了使它擅长特定任务(如客服对话或法律文书分析),需要在更小、更专业的标注数据集上对其进行额外训练,以调整其行为。
  3. 部署与优化:将训练好的模型集成到应用程序中,并提供给用户使用。此阶段还需持续监控模型性能,并进行优化以确保其效率、安全性和可靠性。

总结

本节课中,我们一起学习了生成式人工智能的基础。我们回顾了人工智能从早期规则系统到现代深度学习的发展历程,剖析了大型语言模型基于Transformer架构的工作原理及其广泛的应用场景,最后梳理了构建一个LLM所需经历的预训练、微调和部署等关键步骤。这些知识为我们后续深入探索大型语言模型的运营与实践奠定了坚实的基础。

大型语言模型实践:1.1:什么是生成式人工智能 🤖

在本节课中,我们将要学习生成式人工智能的核心概念,理解其工作原理,并明确其作为“概率机器”的本质,而非事实数据库。

概述

生成式人工智能是指我们能够向人工智能提供一个输入,并得到一个响应或输出的能力。这个输出是由人工智能生成和创造的。基于我们的输入,人工智能现在能够生成文本、图像、声音或视频。

生成式AI的核心概念

上一节我们概述了生成式AI的定义,本节中我们来看看其核心运作机制。

生成式AI是一种概率机器。它并非基于事实的机器,尤其是在处理文本时。有些人可能会因为AI给出的答案听起来非常可信,而误以为这些答案就是事实或真理。然而,即使答案看起来正确或与事实相符,也并非总是如此。用户有责任去验证这些响应、生成的文本或输出,确保其准确、正确且可用。

因此,理解我们应如何与这种“概率机器”互动,是至关重要的基础。我们很容易习惯于得到的响应,并假设所有返回的内容都是事实。但我们已经看到许多案例,例如新闻报道中,人们盲目信任从大型语言模型或聊天界面输出的内容,并将其当作事实使用。

核心要点:生成式AI 不是 数据库。它并非基于可验证的真实事实。

当然,这其中存在一些细微差别。我们可以通过一些方法让这些大型语言模型变得更“聪明”,我们将在课程中探讨这些内容。然而,最重要的是理解:生成式人工智能是人工智能基于概率来产生、生成输出的能力。在大多数情况下,这涉及自然语言处理,生成基于文本的响应,但也可以生成类似视频、图像甚至声音的内容。

与AI互动的正确心态

以下是使用生成式AI时需要牢记的几个关键点:

  • 保持验证意识:始终对AI生成的内容保持批判性思维,并自行核实重要信息。
  • 理解概率本质:认识到输出是基于训练数据中的模式和概率计算得出的,不保证绝对正确。
  • 明确适用范围:将其视为强大的创意辅助或信息处理工具,而非终极事实权威。

总结

本节课中我们一起学习了生成式人工智能的基本定义,明确了其作为“概率机器”而非事实数据库的核心本质。我们强调了用户验证信息的重要性,并建立了与AI工具互动的正确基础认知。记住这一点,是安全、有效利用生成式AI力量的第一步。

大型语言模型实践:1.1:人工智能简史与演进 🧠

在本节课中,我们将一起回顾人工智能(AI)的发展历程,了解从最初的构想到如今生成式AI的关键里程碑。这段历史将帮助我们理解当前大型语言模型(LLM)兴起的背景。

概述

人工智能的研究始于20世纪中叶。我们将从1956年的达特茅斯会议开始,这是AI领域公认的诞生标志。随后,我们将看到AI如何经历了几十年的发展与沉淀,并在近些年,特别是随着Transformer架构GPT-3等大型语言模型的出现,迎来了爆发式的增长。

人工智能的演进历程

上一节我们概述了课程目标,本节中我们来看看人工智能发展史上的几个决定性时刻。

以下是人工智能发展过程中的关键节点:

  • 1956年:AI的诞生

    • 艾伦·图灵等人在达特茅斯会议上提出了“人工智能”的概念,标志着该研究领域的正式诞生。图灵也被誉为人工智能之父之一。他提出的核心思想是:让机器学会思考。
    • 著名的图灵测试也在这一时期被提出,用于判断回答问题的主体是机器还是人类。
  • 1997年:机器在复杂决策中的突破

    • IBM开发了超级计算机“深蓝”。它在国际象棋比赛中击败了世界冠军加里·卡斯帕罗夫。
    • 这一胜利具有里程碑意义。虽然当时的机器学习技术已能让机器从结构化数据中学习,但国际象棋每一步都存在海量可能性。深蓝的胜利证明了AI系统有能力在特定复杂领域超越顶尖人类。

  • 2017年:新架构与新的挑战
    • 谷歌推出了AI系统“AlphaGo”,它在更复杂的围棋游戏中击败了人类冠军。围棋的可能性数量远超国际象棋。
    • 与此同时,Transformer架构被引入。这是一种高效的自然语言处理机制。
      • 核心机制:Transformer能够处理文本、口语、翻译等自然语言,并理解其内在特征。其核心是自注意力机制,公式可简化为 Attention(Q, K, V) = softmax(QK^T/√d_k)V,它允许模型在处理一个词时关注输入序列中的所有相关词。
    • 这项突破为后来的生成式AI大发展奠定了基础。

  • 2021年:生成式AI的兴起
    • GPT-3 等大型语言模型达到了足够的性能水平,开始被广泛用作生成式AI。
    • GPT-3的参数量非常庞大,使得人们可以与之进行交互。这彻底改变了我们与AI模型的互动方式,并催生了像ChatGPT这样如今无处不在的服务。

总结

本节课中,我们一起学习了人工智能从1956年诞生到2021年后生成式AI爆发的简要历史。可以看到,AI的发展在近年来显著加速,特别是在大型语言模型领域。不仅ChatGPT,许多其他开源和商业模型都在快速推进。我们可以预见,未来AI不仅会有更多突破,而且变革的步伐会越来越快。

大型语言模型实践:P7:大型语言模型在应用中的工作原理 🧠

在本节课中,我们将要学习大型语言模型(LLM)在面向用户的应用中是如何工作的。我们将从用户界面开始,逐步深入到数据中心、应用代码、GPU处理等环节,了解一个完整的生成式AI应用的工作流程。


用户界面与互联网连接 💻

当我们谈论生成式AI时,主要指的是面向用户的应用。这些应用如何工作呢?让我们从最左边的用户界面开始。你可能已经体验过,即使你不是软件工程师或机器学习专家,也可以通过电脑连接互联网,访问像ChatGPT这样的网站来使用这些服务。互联网使我们能够连接到这些服务。

数据中心与云端服务 ☁️

这些服务通常运行在一种数据中心里。当我们谈论数据中心或“云端”时,指的是那些在多个地点拥有数据中心的大型公司,他们的应用程序就托管在这些数据中心的某个服务器上。其中一台服务器会负责处理你的请求并提供答案和功能。

本质上,大多数互联网应用的工作方式非常广泛:通过互联网连接到某个数据中心的计算机,然后该计算机产生某种输出,输出再通过互联网传回给用户界面。

应用代码与可扩展性 ⚙️

上一节我们介绍了基本的连接流程,本节中我们来看看应用内部的复杂性。应用通常比这更复杂一些。我们从最开始的用户提示(Prompt)开始。在生成式AI或AI应用中,我们总是讨论某种输入。

这个输入会进入应用代码。应用代码可能运行在一台或多台服务器上,这取决于输入量的可扩展性需求。通常,大多数系统都会接入某种云环境。

云环境允许应用程序自动扩展,并具有弹性。如果你不熟悉“云”,它基本上允许应用程序根据需求增长或收缩。想象一下,用户突然从一个人变成一百万人,这个应用如何工作?云的工作方式是创建同一应用的多个副本,进行复制和扩展。

GPU:人工智能的专用硬件 🎮

那个应用可能会被分成不同的部分或区段。一部分肯定是应用本身,另一部分是实际的数据,或者对于大多数人工智能工作负载来说,是一个计算更密集的系统。

我们谈论的是使用一种称为GPU的特定硬件。GPU代表图形处理单元。在个人电脑起步时,GPU基本上使计算机能够处理图形,处理那些让计算机具有交互性的东西。例如,电子游戏之所以可能,就是因为GPU。

这些图形处理单元允许人工智能进行海量计算,使我们能够实现生成式AI等功能。因此,一个应用程序可能不仅执行第二步这里的代码,还会尝试使用数据中心、云端某处部署的某个机器上的GPU来进行密集计算工作。

完整工作流程与决策 🔄

现在有不同类型的应用程序,我们稍后会介绍其中几种。但本质上,这就是我们所看到的情况:处理过程会返回给应用程序。

应用程序将根据生成的数据做出一些决定,然后最终返回给用户。有一点我需要确保你理解:用户输入在第一步直接进入机器学习模型或大型语言模型的情况很少见,甚至根本不会发生。

它通常会经过一个应用层,以及许多其他潜在层,到达GPU进行处理,然后返回应用程序。正如我在第四步提到的,应用程序会做出一些决定,然后返回给用户。


本节课中我们一起学习了大型语言模型应用的基本架构。我们了解了从用户提示开始,经过互联网、云端服务器、应用代码处理,到利用GPU进行密集型计算,最后再将结果经过应用决策返回给用户的完整流程。关键在于理解,用户输入并非直接与模型交互,而是通过一个多层级的应用架构来协调处理。

大型语言模型实践:1.1:大型语言模型的创建方式 🏗️

在本节课中,我们将要学习大型语言模型是如何被创建出来的。这是一个非常基础和概览性的介绍,旨在帮助初学者理解其背后的核心概念和基本流程。

概述

创建大型语言模型是一个复杂的过程,通常涉及海量数据的收集、清洗和训练。本节将首先通过不同来源的定义来理解其概念,然后通过一个云平台示例来直观展示机器学习模型的训练设置,从而类比理解大语言模型的创建步骤。

理解大型语言模型

首先,我们来看看如何定义大型语言模型。如果你从未接触过机器学习相关内容,可能会感到有些困惑,但我们将从基础开始。

我们以维基百科的定义作为起点。选择维基百科的原因是,它通常提供广泛而概括的答案,这有助于我们获得一个宏观的认识。

根据维基百科,大型语言模型是一种因其强大能力而著称的语言模型。然而,它并没有详细说明如何具体创建一个这样的模型。这引出了一个关键点:通常,个人或普通团队并不会从头开始构建一个大型语言模型,这是不常见的。

本质上,创建过程涉及获取数据,然后利用这些数据来训练模型,最终使其能够生成输出。维基百科的描述虽然宽泛,但指出了核心:你需要处理作为数据源的数据集。

数据准备的核心

数据准备是创建模型的起点。这个初始阶段至关重要。

以下是数据准备过程中需要考虑的几个关键方面:

  • 数据来源与规模:例如,想象一下抓取互联网上所有可用的文本,你可能会得到大量无用的或有毒信息。
  • 数据清洗:因此,你需要进行数据清洗,确保数据符合你的要求。例如,如果你在医疗领域,只想收集与医疗相关的数据,那么确保数据是匿名且不包含个人可识别信息就非常重要。
  • 领域针对性:数据相关工作涉及许多方面,需要根据目标进行精心处理。

模型的训练过程

接下来是训练阶段以及其具体工作原理。你将使用不同类型的训练方法。

这些方法将使你最终得到一个真正的大型语言模型。现在,我想转向另一个描述,这次是基于微软学习平台的定义。

一个大型语言模型是一种能够处理和生成自然语言文本的人工智能。它通过从海量数据(如书籍、文章、网页,在生成式AI中还包括图像)中学习,来发现语言的模式和规则。

这正是我想强调的部分:它是如何具体实现的。基于海量文本(这就是为什么列出书籍、文章和网页),在某些涉及图像的生成式AI中还包括图像数据,模型通过训练来发现这些语言的模式和规则。

实践窥探:云平台训练示例

我不会去实际创建一个大型语言模型,但我想使用一项云服务来展示这个过程。这里我们将使用 Azure AI 机器学习工作室,这是 Azure 提供的一项云服务,允许你进行一些训练。

我只是展示一下实际尝试训练机器学习模型时,这个过程看起来是什么样的。我们将从这里开始,使用“自动化 ML 作业”。我知道我还没有具体介绍平台是什么、我们在那里做什么以及如何到达这里,但让我们先专注于一些概念。

你基本上需要理解训练方法,设置一些参数、任务类型和数据。

然后,你需要某种计算系统,接着就可以启动作业开始训练。让我们看看这里有什么:我们将进行自动化训练,创建一个自动化机器学习作业。这意味着我们将让机器来决定何时训练得足够好,可以停止。

我们进入基本设置。在这里,我们需要设置作业的名称。然后,在“任务类型和数据”部分,这是我想重点关注的,我们必须始终理解你要进行什么类型的训练。

如果我点击这个下拉菜单,你会看到有不同类型的训练:分类、回归、时间序列预测。

例如,分类允许你预测是或否、蓝色/红色/绿色、开或关。想象一下,如果你想创建一个机器学习模型,使其能够根据特定文本来理解一个故事是否开放,那么你将需要多种不同类型的数据来定义开放和关闭的状态,并基于这些数据进行训练。

对于基于或创建大型语言模型的机器学习模型,你会进行自然语言处理(NLP)。它基于纯文本数据类型,使用多类或多标签分类进行预测。这些是大词和术语,本质上意味着你将使用大量纯文本来训练你的模型,使其能够基于特定语言来理解如何处理语言。

训练任务设置

一旦你决定了任务类型,接下来就需要选择具体的分类方式。

以下是几种主要的 NLP 分类任务:

  • 多类分类:预测每个样本的正确类别。
  • 多标签分类:预测每个样本的所有类别。
  • 命名实体识别:从结构化文本中提取特定领域的实体。

这里涉及很多内容,但归根结底,这就是你如何设置一个能够创建类似大型语言模型的东西的方式。请注意,我只是在举例说明如何创建一个机器学习模型。

创建真正大语言模型的挑战

对于一个真正的大型语言模型,过程会复杂得多。它肯定从数据开始,但我没有海量的文本数据来训练,所以这实际上不是一个好的用例。

正确的方式是组建一个完整的数据科学家团队,他们理解深度学习概念(如神经网络及其工作原理),懂得如何以能够实际创建模型的方式处理数据,并且拥有使用多个 GPU 和基础设施进行训练的能力。但这应该能让你很好地了解这个过程可能是什么样子,以及可能涉及哪些步骤。

再次强调,随着课程的深入,你会听到我多次提到数据。我们需要海量的数据,而且这些数据不仅要量大,还必须像之前描述中看到的那样,是干净的。

总结

本节课中,我们一起学习了大型语言模型创建的基本框架。我们了解到,创建过程始于海量、高质量的数据准备,包括收集、清洗和领域聚焦。接着,通过特定的训练方法(如自然语言处理中的分类任务)让模型从数据中学习语言的模式。虽然实际创建一个大语言模型需要专业的团队和巨大的计算资源,但通过云平台(如 Azure)的示例,我们直观地看到了训练一个机器学习模型的核心设置步骤,从而类比理解了构建大语言模型的复杂性与核心流程。记住,高质量的数据正确的训练任务是其中的关键。

大型语言模型实践:1.1:人工智能简史与现状 📜

在本节课中,我们将回顾人工智能的发展历程,了解其当前所处的阶段,并初步探讨大型语言模型的创建与应用基础。

我们得以窥见人工智能历史的一角,了解我们今日所处的位置。我们看到了那些引领我们走到今天的关键事件。正如你所见,整个人工智能领域的创新正在加速,这不仅仅局限于我们当前所处的生成式AI阶段。我们可以预见,事物将继续以极快的速度演进,发展将持续保持极高的速度。

上一节我们回顾了AI的发展脉络,本节中我们来看看大型语言模型是如何被创建的。

我们还简要了解了大型语言模型的创建过程及其所需条件。我们现在知道,这需要海量的数据。这个过程有些复杂,我们将在后续课程中深入探讨这些模型的本质。但凭借目前关于模型工作原理及其在不同应用中表现的基础知识,以及对生成式AI一些应用场景的了解,你将为进一步理解大型语言模型背后的细节做好准备。

以下是生成式AI的一些主要应用方向:

  • 内容创作与文本生成
  • 代码编写与辅助
  • 语言翻译
  • 问答与知识检索
  • 对话与聊天机器人

本节课中我们一起学习了人工智能的简要发展历程、当前创新的加速趋势,以及构建大型语言模型所需的海量数据基础。这些知识为我们后续深入理解大型语言模型的细节奠定了基石。

大型语言模型实践:P10:引言_2

在本节课中,我们将要学习大型语言模型的具体定义、工作原理、以及相关的优势、风险与挑战。我们还将探讨基础模型的概念及其重要性。理解这些核心知识,将为后续构建生成式AI应用打下坚实的基础。

大型语言模型的定义与工作原理 🔍

上一节我们简要介绍了机器学习模型。本节中,我们来看看什么是大型语言模型,以及它们是如何工作的。

大型语言模型是一种特殊的机器学习模型。理解其幕后的工作原理,是掌握生成式AI如何实现今天所见各种功能的关键。这种理解也是未来利用这些模型进行创造的重要基础步骤。

大型语言模型的优势、风险与挑战 ⚖️

在深入了解工作原理后,我们还需要快速审视使用大型语言模型时的一些方面。

以下是大型语言模型的主要优势、风险与挑战:

  • 优势:模型能够执行多种复杂的语言任务。
  • 风险:在使用这些模型时,某些操作可能带来潜在风险。
  • 挑战:我们需要确保某些方面是正确的,因为实施大型语言模型时方法必须非常扎实,否则可能陷入问题。我们也将探讨其中一些具体问题。

基础模型概述 🏗️

最后,我们来了解一下基础模型。

基础模型是经过海量数据预训练的大型模型,可以作为多种下游任务的起点。理解什么是基础模型、它们为何重要,以及我们如何利用这些模型,对于未来在应用程序中使用它们至关重要。

本节课中,我们一起学习了大型语言模型的核心概念、其背后的工作机制、以及应用时需权衡的优势与风险。同时,我们也介绍了作为多种AI应用基石的基础模型。这些知识构成了深入探索和实践生成式AI的坚实基础。

大型语言模型实践:1.3:什么是大型语言模型及其工作原理 🧠

在本节课中,我们将要学习大型语言模型(LLM)的基本概念及其核心工作原理。我们将从理解文本如何被模型处理开始,逐步揭示其作为“概率机器”的本质。

概述

要理解大型语言模型及其确切的工作原理,我们首先需要从“词元”开始,了解什么是“词元化器”。大型语言模型以文本作为输入,并生成文本作为输出。但这个过程具体是如何发生的呢?它通过将输入的文本分解成更小的片段,并将这些片段转换为数值来实现。

从文本到数字:词元化

上一节我们提到了模型处理文本的起点。本节中我们来看看文本是如何被转换成机器可以理解的格式的。

一段文本,例如“what is a tokenizer”,会通过一个称为“词元化”的过程被转换成数字。这个过程将文本分割成更小的块,我们称之为“词元”。每个词元随后会被转换成一个数值。

例如,词元“what”可能被转换为数值 318。所有词元最终都会被转换成数字,并放入一个数组中。这种方式使得机器能够处理它们,并尝试更好地理解这些由数值表示的片段。

我们实际上是在创建一个索引。这个索引是对原始文本块的编码。我们称之为“块”或“片段”,是因为划分方式并不总是以单词为单位。

以下是词元化可能产生的一些片段示例:

  • 单词本身,如“what”。
  • 可能包含一些空格。
  • 一个单词可能被拆分成两部分。
  • 标点符号,如问号,也可能单独成为一个词元。

所有这些表示方法都旨在让机器学习模型更容易理解文本。这是目前让机器理解文本的最佳方法。这个过程就是文本的分析、分解或分割,将其转化为数值。

核心机制:概率机器

在了解了文本如何被转换为数字之后,我们现在可以探讨模型的核心工作机制。我喜欢将大型语言模型称为一个“概率机器”。

为什么是概率机器?模型试图理解所有这些小的文本块(词元),并尝试预测从一个词元到下一个词元的概率。简而言之,给定一个词元序列,模型会计算下一个最可能出现的词元是什么。

这是一个极度简化的解释:它本质上就是一个基于海量文本训练得出的概率计算器。机器学习模型会尝试根据给定的文本片段,确定所有可能的后续词元的概率。

这一点非常重要,需要强调:大型语言模型本质上就是一个概率机器。这样思考这些模型会更容易理解,因为有时它们表现得非常出色,像一个能吐出事实的机器。

即使某些生成的文本看起来准确、正确且符合现实,我们也不应将其视为事实生成机。它所做的一切,都只是基于给定特定输入和大量训练文本,计算下一个词元可能是什么的概率。

实例解析:理解概率预测

为了更具体地理解概率预测,让我们看一个例子。

假设我们有一个短语:“今天天气晴朗,并且……”。这个短语是理解“……”部分可能是哪个特定词的完美例子。

在这种情况下,“今天天气晴朗,并且”后面很可能是“一天”。这意味着什么?基于大量的训练文本、对这些文本进行词元化处理后生成的索引,机器理解到,在这里你很可能想要的是“天”这个词,甚至前面可能还有一些空格,以确保生成的文本格式正确。

总结

本节课中,我们一起学习了大型语言模型的基本工作原理。

首先,模型通过词元化过程将输入文本分解并创建索引,转换为数值数组。这是机器理解文本的基础。

随后,模型作为一个概率机器运行。它基于从海量文本中学到的模式,计算给定词元序列后下一个词元出现的概率,并以此生成文本。

记住,LLM的本质是概率预测,而非事实检索。理解这一点是有效使用和评估大型语言模型输出的关键。

大型语言模型实践:P12:使用大型语言模型的优势与风险 🧠

在本节课中,我们将通过一个具体的例子,探讨使用大型语言模型(LLMs)的优势与潜在风险。我们将看到,虽然LLMs功能强大,但其输出结果需要谨慎对待。

概述

大型语言模型能够根据输入生成连贯、看似合理的文本。这使其在内容创作、信息总结等方面非常有用。然而,其输出可能包含不准确或虚构的信息。本节我们将通过实际操作,直观地理解这些优点和缺点。

探索LLMs的优势与风险

为了理解LLMs的优缺点,最好的方式是通过实际案例。我们将以我本人(Alfredo)为例,使用不同的提示词与模型进行交互,观察其输出结果。

尝试获取个人总结

首先,我们请求OpenAI的ChatGPT为我生成一个个人总结。

提示词示例:

give me a summary of myself Al Farodesa

模型输出:

该模型指出我为Python打包相关项目做出了重大贡献,并积极参与了开源社区。同时,它提醒道,个人信息可能发生变化,建议查阅最新资料以获取最准确信息。

这个总结看起来大体合理。然而,实际上我并未专门从事过Python打包工作。这说明,虽然LLMs的输出很有用,可以作为内容创作的起点,但其中可能包含不准确的信息。因此,用户需要具备辨别能力,仅采纳可信的部分。

测试模型的隐私边界与准确性

接下来,我们尝试以第三人称视角请求生成个人简介,以测试模型对隐私的处理和信息的准确性。

提示词示例:

Please create me a short bio about Alfredo, a Peruvian who knows technology.

模型响应:

模型拒绝了此请求,指出未经本人同意为个人创建传记信息涉及隐私问题。如果对象是公众人物,建议查阅其官方资料。

这体现了LLMs设计中对隐私保护的考量。随后,我们调整策略,以第一人称视角请求为项目创建简介。

提示词示例:

I am Alfredo, and I need a quick bio for a README in a Rust project.

模型输出:

生成了一段简短的自我介绍,内容包括:来自秘鲁、对开源和Rust充满热情、拥有软件工程和系统管理背景、乐于贡献项目以推动技术边界。

这段简介大部分内容准确有用,例如我的国籍和技术兴趣。但其中“出生于11月14日”等信息则是完全错误的。这清晰地展示了LLMs的“双刃剑”特性:既能生成有价值的文本,也可能掺杂不实信息。

对比不同模型的输出

为了进一步说明风险,我们查看另一个模型(Claude AI)生成的关于我的简介。其输出中声称我是一名数学家,并熟练使用Java和Ruby on Rails,这些都与事实严重不符。

这个例子强化了核心观点:LLMs的输出是混合体,部分正确,部分可能完全错误。在使用时,我们必须仔细甄别。

LLMs的核心应用与原理

上一节我们通过实例看到了LLMs的优缺点。本节中我们来看看它的另一个核心应用场景——文本总结,并理解其底层工作原理。

除了问答,LLMs在文本总结方面非常高效。我们可以要求模型对一段文字进行概括,甚至指定概括的详细程度。

提示词示例:

I need a summarization of the following paragraph... (后接待总结的文本)

或者

Reduce the above summary to two sentences.

模型能够生成简洁、准确的总结,这与其在开放性问题中表现出的不确定性形成对比。这种针对具体文本的处理任务,通常是LLMs更可靠的应用方向。

理解模型的工作机制

关键在于理解,大型语言模型本质上是一个概率机器。其核心工作原理可以概括为:

公式/原理:

给定一系列输入文本(Token),模型基于其从海量数据中学到的模式,计算并预测下一个最可能出现的词或句子序列。

因此,模型的输出是“听起来非常合理”的文本,但不保证事实准确性。它反映的是训练数据中的统计规律,而非确凿的事实数据库。

总结

本节课中我们一起学习了使用大型语言模型的优势与风险。

优势在于:

  • 能够快速生成文本、总结信息,极大提升效率。
  • 可作为头脑风暴和内容创作的强大起点。
  • 在特定结构化任务(如总结给定文本)中表现相对可靠。

风险与注意事项包括:

  • 可能产生“幻觉”:生成看似合理但实则错误或虚构的信息。
  • 需要事实核查:绝不能将LLMs的输出直接当作事实来源,必须进行验证。
  • 理解其本质:牢记LLMs是概率模型,其目标是生成“合理”的文本,而非“正确”的答案。

最终,成功使用大型语言模型的关键在于保持审慎:利用其强大的生成能力,同时以批判性思维仔细评估其输出的每一个细节。

大型语言模型实践:13:缓解大型语言模型的风险 🛡️

在本节课中,我们将学习如何理解和缓解大型语言模型(LLMs)可能带来的风险。我们将介绍四种主要的风险缓解策略,并分析它们在实施难度、成本和输出质量方面的权衡。

为了有效缓解并深入理解如何降低大型语言模型的风险,下面这张图表非常有用。

1. 提示工程 💬

我们从最顶层的“提示工程”开始。提示工程是我们向专门从事语言生成的机器学习模型提供输入、准确描述问题或需求的方式。当我们精心设计一个高质量的提示时,我们通常会得到更好的结果。

在图表顶部,这代表了最容易实施的方法。它的难度最低,是您在这个层面上最容易做的事情。随着我们向下深入,难度和成本都会增加。提示工程的成本几乎为零,难度也非常低。这意味着我们的主要任务是为机器学习模型提供一个良好的输入描述。

然而,在质量方面,我们得到的结果质量可能较低。即使我们有一个非常好的提示,如果模型本身不擅长手头的任务,效果也会有限。例如,如果您试图获取与特定国家法律程序或法律问题相关的准确回答,而模型没有接受过相关训练或不具备相关知识,那么仅靠提示工程可能帮助不大。

2. 检索增强生成(RAG)🔍

接下来,我们讨论检索或搜索,即检索增强生成。这意味着我们可以将搜索与提示工程结合起来。

具体做法是,您可以先根据提示内容进行搜索,然后将搜索结果作为提示的一部分输入给模型。这种方法本质上比单纯的提示工程要复杂一些,也会涉及更高的成本。可以说,它比提示工程的成本更高。

为了实现检索增强生成,您需要某种存储系统和搜索引擎。质量方面,相比单纯的提示工程,其输出质量会有所提升。例如,某些模型是基于过去事件训练的,可能存在信息过时的问题。通过检索增强生成,您可以不断用更新、更相关的数据来更新搜索内容,从而缓解这个问题。

3. 微调 🎯

继续深入,我们将进入“微调”环节。微调要复杂得多,您需要海量的数据,并且需要一个持续的过程来用这些额外数据训练模型。

微调的难度远高于检索增强生成或提示工程,当然成本也更高。为了快速完成微调,您可能需要使用一些GPU。然而,如果微调执行得当,您将获得更高的输出质量。就个人偏好而言,我仍然更倾向于使用检索增强生成和提示工程,因为微调的难度较大。

4. 从头训练模型 🏗️

最后一项,我在这里标为第四点,就是“从头训练模型”。这正是大多数大型语言模型必须做的事情,因为它们需要生成一个全新的模型。

这将是难度最高成本最昂贵的操作。至于质量,根据您的目标,它有可能达到最高、最好的水平。

总结与综合应用 📝

理解如何缓解风险,意味着您需要清楚了解所有可用的不同步骤和选项,并明白从提示工程到从头训练模型意味着什么。

这关系到成本、难度,当然也关系到质量。有些方法在缓解特定风险时可能更有效,但您通常需要结合使用一些防护措施。

需要强调的是,这些部分——例如提示工程——并不是孤立的。即使您在训练一个模型,您也100%可以同时使用提示工程,同样也可以结合微调、检索增强生成或搜索,将这些工具全部有效地利用起来。

因此,您对这些策略的理解越深入,您手中可用的工具和方法就越多,也就越能有效应对在处理大型语言模型时可能遇到的各种问题。

本节课中,我们一起学习了四种缓解大型语言模型风险的核心策略:提示工程、检索增强生成、微调和从头训练模型。我们分析了它们在实施难度、成本和输出质量上的权衡,并理解了这些方法可以综合运用,以构建更强大、更可靠的AI应用系统。

大型语言模型实践:1.1:什么是基础模型 🧱

在本节课中,我们将要学习基础模型的核心概念。基础模型是现代生成式AI应用的基石,理解它对于后续学习如何使用和定制大型语言模型至关重要。

基础模型是经过大规模训练的大型深度学习模型,它们具备很强的适应性。

这些模型在设计之初就考虑了自然语言处理,因此可以被应用于其他类型的任务。它们为构建基于AI的应用程序提供了一个坚实而优秀的起点。这里的关键点在于,这些模型建立在海量数据之上。这些数据主要是文本,正是这些文本使得大型语言模型的创建和存在成为可能。这些数据量极其庞大,并且是必要的,因为数据越多,模型的质量就越好。在这种情况下,一个非常大的语言模型就是起点。

那么,为什么说它是一个起点呢?一旦模型具备了处理自然语言多个方面的能力,就有可能将这个模型重新用于其他类型的任务。

接下来,我们来看看这些任务具体是什么。这里我们以GPT模型为例。

GPT模型可以被重新用于更具体的任务。一个常见的例子就是代码助手。代码助手现在变得非常普遍,开发者、软件工程师、机器学习工程师、数据科学家都在他们的开发环境中使用代码助手。这使他们能够基于大型语言模型的文本生成功能,更轻松、更快速地开发代码。在这种情况下,像GPT这样的大型语言模型提供了一个基础起点,以便可以在此基础上添加特定任务,并将其整合起来,创建一个单一用途或更具体的应用,而不是像基础模型那样通用。

另一个很好的例子是客户支持。你可能遇到过这样的聊天机器人:当你访问一个网站并说“嘿,我遇到问题了”,它会回应你。它会询问你遇到了什么样的问题,并根据你的描述,为你创建一张支持工单。这就是一个客户支持聊天机器人。类似地,销售机器人也能实现类似的功能。

然而,这些应用并非直接基于基础模型。不好的聊天机器人实现例子,就是那些没有任何过滤就直接与基础模型对话的应用程序。为了让这些应用成为可能,需要进行过滤和提供特定指令,在某些情况下,还需要对模型进行微调,使其适应特定任务,比如代码助手或客户支持。

以下是实现这一过程的关键步骤:

  • 过滤与处理:在基础模型和具体任务之间,需要有一层过滤和处理机制。
  • 指令引导:通过指令使模型的行为更具体。
  • 数据微调:对于像代码助手这样的任务,需要让模型学习大量已有的代码数据,在理解自然语言的基础模型之上进行额外的训练。

正是这些特点使得基础模型与众不同。因此,每当你听到“基础模型”这个词时,它指的就是那些允许其他更具体任务(如代码助手、客户支持和销售机器人)得以实现的基础模型

本节课中,我们一起学习了基础模型的定义与核心作用。我们了解到,基础模型是经过海量文本数据训练的大型语言模型,它为各种AI应用提供了通用起点。通过过滤指令引导微调等技术,我们可以将通用的基础模型转化为解决特定任务(如代码生成、客户服务)的专用工具。理解基础模型是理解整个生成式AI应用生态的第一步。

大型语言模型实践:2:总结

在本节课中,我们将回顾并总结关于大型语言模型工作原理、核心组件、局限性以及基础模型应用的关键知识。

大型语言模型的工作原理与组件

上一节我们介绍了大型语言模型的基本概念,本节中我们来看看其内部工作机制。我们能够初步了解大型语言模型如何运作。这些模型背后有一些关键要素和逻辑组件。当它们工作以生成文本、图像、音频或应用程序时,会执行特定的逻辑。

以下是其核心工作流程的组成部分:

  • 输入处理:模型接收并理解用户的提示或指令。
  • 上下文理解:模型分析输入中的信息与关联。
  • 内容生成:基于其训练数据和理解,模型逐词或逐元素生成输出。

大型语言模型的局限性与挑战

我们探讨了这些大型语言模型存在哪些局限性与挑战。我们甚至尝试突破其边界,使其陷入困境,达到模型响应开始崩溃、无法准确提供我们最初所要求内容的程度。

以下是其主要局限性:

  • 上下文长度限制:当输入信息过多、上下文过长时,大型语言模型便无法再生成任何有用的内容。
  • 事实性与一致性:模型可能生成看似合理但不准确或自相矛盾的信息。
  • 对提示的敏感性:输出的质量高度依赖于输入提示的措辞方式。

基础模型的价值与应用

最后,我们了解了基础模型。正如你现在所知道的,基础模型为你提供了一个良好的起点,大量的基础工作已经为你完成。

你可以通过以下方式利用它:

  • 微调:在特定数据集上对基础模型进行额外训练,使其适应特定任务。公式可表示为:最终模型 = 基础模型 + 特定任务数据微调
  • 改造用途:将这个大型语言模型重新用于其他领域,从而充分利用已经完成的所有训练成果。

本节课中我们一起学习了大型语言模型的核心工作机制、面临的主要挑战以及如何利用基础模型作为起点来构建特定应用。理解这些内容是有效使用和开发大语言模型应用的基础。

大型语言模型实践:1:生成式AI生态概览与模型获取途径

在本节课中,我们将要学习生成式人工智能的当前生态格局,并了解获取和使用大型语言模型的几种主要途径。我们将从OpenAI和ChatGPT开始,进而探索开源模型及其社区,接着学习如何在本地运行模型,最后简要了解基于云的解决方案。

生成式AI的当前格局

当今的生成式人工智能领域非常有趣。我们将看到这些技术不断发展,并随着时间的推移持续演进。越来越多不同的应用将会出现,并变得普及。

上一节我们介绍了生成式AI的宏观发展趋势,本节中我们来看看一些具体的模型与平台。

探索OpenAI与ChatGPT

在本课程中,我想稍微探讨一下OpenAI和ChatGPT。

开源模型与Hugging Face平台

我们也会看看一些开源模型,以及我们可以找到它们的一些地方,例如Hugging Face。

我们将了解Hugging Face是什么,它为何重要,以及为什么你应该了解它。

以下是Hugging Face平台的核心价值点:

  • 模型仓库:它是一个托管大量预训练机器学习模型(尤其是Transformer架构模型)的中心。
  • 社区与协作:研究人员和开发者可以在此分享模型、数据集和代码。
  • 工具库:提供了如transformersdatasets等强大的Python库,极大简化了模型的使用和部署流程。

本地运行大型语言模型

接下来,我们还将看看如何使用本地模型。我们会选取一些大型语言模型,并尝试在本地使用它们。

这会是怎样的情形?我们如何实现这一点?当你尝试对大型语言模型进行更多探索时,需要考虑哪些因素?

以下是本地运行模型时需要考虑的关键点:

  • 硬件要求:模型运行需要强大的计算资源,主要是GPU内存(VRAM)。模型参数数量直接决定了所需内存大小,近似公式为:所需内存 ≈ 参数数量 × 精度字节数(例如,70亿参数模型在FP16精度下约需14GB VRAM)。
  • 软件环境:需要配置Python环境、深度学习框架(如PyTorch)以及模型加载库。
  • 量化与优化:为了在资源有限的设备上运行,常需对模型进行量化(如GGUF格式),以牺牲少量精度换取更低的内存占用和更快的推理速度。

基于云的解决方案

最后,我们也将快速浏览一些基于云的解决方案。

如果你想与这些大型语言模型交互,当我们谈论基于云的解决方案时,会是什么样子?例如,来自微软的Azure云。


本节课中我们一起学习了生成式AI的多样生态。我们从知名的OpenAI和ChatGPT出发,认识了汇聚开源模型的Hugging Face平台,探讨了在本地部署模型所需的资源与考量,并初步了解了将模型部署在云端的便捷方案。这些途径为不同需求和资源水平的开发者提供了接触和利用大型语言模型的可能性。

大型语言模型实践:1:生成式AI概览与OpenAI ChatGPT

概述

在本节课中,我们将学习生成式AI的概况,并重点了解OpenAI与ChatGPT。我们将从ChatGPT的起源开始,解释其基本工作原理,并澄清一些容易混淆的术语。同时,我们也会介绍其他提供类似服务的平台,例如Anthropic和微软Azure,帮助你理解整个生态系统的构成。

生成式AI的现状

当前生成式AI的格局可能令人有些眼花缭乱。让我们从一切的起点开始,即ChatGPT和OpenAI。

你会看到一些容易混淆的术语,以及一些被广泛使用但可能造成误解的词汇。市场上存在许多AI和AI生成公司及服务,它们有时会重复使用某些词语,这可能会带来一些困惑。

起点:ChatGPT与OpenAI

我们从ChatGPT开始,它是最早推出的生成式AI之一,可以说是这场变革的先驱。

在左上角,我们实际交互的是一个大型语言模型,在本例中是ChatGPT 3.5。当你开始探索这些模型时,你会发现其他选项,例如GPT-4。但目前免费版本允许使用的是GPT-3.5。这就是一切的起点,可以说是生成式AI的开端。

在这里,你可以直接通过聊天框进行交互。需要注意的一点是,你会在大多数此类服务的底部看到这样的警告:“ChatGPT可能会犯错,请考虑核实重要信息。”这一点至关重要,并且我会在整个课程中反复强调:它不是一个事实机器

它不会处理或提供来自数据库的数据。它会基于概率生成内容。

例如,我们可以输入这样的提示:

我正在写一个README文件或一个新项目,想扩展一些关于我自己的信息。我的名字是Ferdesa,请为我提供一个简短的描述。

你会发现,生成的内容不一定完全准确,需要你自己去核实事实。我们不会深入探讨这是什么以及它是如何工作的,但会探索整个格局。

其他服务提供商:Anthropic

尽管ChatGPT和OpenAI是最早开始这项服务的,但还有其他提供商。例如,我将向你展示Anthropic,它向我们表明还有其他选择。

这是它的欢迎界面,有一些细节说明。它再次强调了与ChatGPT相同的事情:它可能显示不正确或有害的信息,因为它同样不是一个事实机器。公开测试版不旨在提供专业建议(法律、金融、医疗),你完全不能依赖它。

接受所有条款后,你可以完成设置,并看到一个与开始聊天非常相似的界面。

云服务集成:以Azure为例

就像OpenAI和ChatGPT一样,你会发现许多服务与最初的ChatGPT非常相似。此外,云服务(例如接下来要展示的Azure)能够直接与这些模型交互,而无需通过第三方服务。

尽管这看起来可能非常复杂,但我将集中精力向你展示一些模型。我将直接转到模型目录。

在这里,你会看到一项名为“Azure OpenAI语言模型”的服务,它仅在Azure上可用。我之所以在概览中提及这一点,是因为你可能会感到困惑:为什么既有OpenAI语言模型,又有Azure OpenAI?它们之间是什么关系?

事实是,你可以在Azure内通过页面订阅与OpenAI的大型语言模型进行交互。当你在Azure上拥有某种部署和账户时,你就可以使用这些模型。

当你浏览这些模型时,你会看到GPT-4以及许多其他模型,就像我们之前看到的GPT-3.5一样。你在这里拥有这些能力,并且可以创建自己的环境来与这些模型交互。正如你所见,这些并不是唯一的模型,我们还有许多其他模型可用。其中一些功能将在我们的云服务提供商处可用。

核心概念澄清

理解这一点很有用:并非一切都是ChatGPT。OpenAI是一个独立的实体,还有其他类似的服务提供商。在像微软Azure这样的云提供商中,Azure云将允许你与其中一些模型进行特定的交互。

总结

本节课中,我们一起学习了生成式AI的概况,重点了解了OpenAI的ChatGPT作为该领域的起点。我们明确了ChatGPT是一个基于概率生成内容的大型语言模型,不是一个事实机器,使用时需要自行核实信息。我们还介绍了其他服务如Anthropic,以及云平台(如Azure)如何集成这些模型,帮助你理解了生成式AI服务多样化的生态系统。记住,关键是要区分不同的服务提供商和访问方式。

大型语言模型实践:1.4:Hugging Face与开源模型 🤗

在本节课中,我们将要学习Hugging Face平台及其与开源大型语言模型的关系。我们将了解Hugging Face是什么,它提供哪些核心功能,以及如何在该平台上探索和使用模型。


什么是Hugging Face?

当我们谈论开源模型时,无疑会提到Hugging Face这家公司。

Hugging Face是一家专注于……的公司,但更准确地说,Hugging Face就像一个代码仓库,一个我们可以托管和分享模型的地方。许多公司,包括许多云服务提供商,都允许将他们的模型托管在这个平台上。

因此,Hugging Face不仅是一家公司,也是一个平台,许多开源模型都托管在这里。


Hugging Face平台的核心功能

那么,这具体意味着什么呢?在平台顶部,你会看到许多不同的选项:模型、数据集、空间。这些分别是什么?让我们快速了解一下。

以下是Hugging Face平台的主要功能模块:

  • 模型:托管和分享机器学习模型的地方。
  • 数据集:存储和共享用于训练模型的数据集。
  • 空间:部署和演示模型应用的交互式环境。

探索模型库

上一节我们介绍了Hugging Face的核心功能,本节中我们来看看如何在其模型库中进行探索。

点击“模型”,你会看到即使是像微软这样的公司,实际上也在那里放置了模型。需要注意的一点是,其中一些模型非常具体。例如,这里的“Microsoft Phi-2”是一个专门用于文本生成的模型。

这意味着这个模型的主要任务和目的就是文本生成,其功能类似于我们之前看到的提供聊天服务的系统,如ChatGPT和其他服务提供商。这并非唯一,你还可以看到Mistral AI的“Mistral”模型,它也进行文本生成。

那么Hugging Face在这里扮演什么角色?它与所有这些模型是什么关系?它是一个流行且优秀的托管和存放这些模型的服务。


深入了解一个模型

如果我们想深入了解一个模型,例如“Phi-2”,可以点击进入。

点击后,你会获得关于这个模型是什么以及它如何工作的一些信息。你会看到一些描述,例如如何使用它,以及一些关于如何实现它的说明。

这非常棒,但我们还可以看到更多不同的内容。我们可以看到如何使用Python代码来调用这个模型的示例。你可以浏览构成这个模型的实际文件,例如一些配置文件以及分词器所需的一些文件(我们尚未深入探讨分词器)。所有这些文件共同构成了这个模型的功能。

你可以在这里看到模型的大小是564 MB,这看起来是一个大文件。你实际上可以下载这些文件,甚至……


模型的许可与多样性

……如果你已登录,可以立即尝试文本生成。不过,此模型的API试用功能已被关闭,我们暂时不会尝试。我将返回到模型列表。

你可以看到还有其他功能的模型,所有这些模型都关联着不同类型的任务:计算机视觉、自然语言处理、音频处理等等。模型种类繁多。

并非所有模型都是完全开源的。有些模型可能是闭源的。例如,我们来看看Mistral AI的模型,并尝试了解其许可证。你可以看到这里的许可证是Apache 2.0,这是一个非常宽松的许可证。但这些许可证会有所不同,并非所有模型都具有相同的许可证。

其中一些许可证允许你做更多事情,另一些则限制更多,例如仅允许用于研究。


总结

本节课中我们一起学习了Hugging Face平台。

每当你听到Hugging Face和开源模型时,请确保你理解:Hugging Face只是一个你可以分享、上传、托管模型的地方,其中包含了大多数开源模型。许多公司和个人也在那里托管他们的模型。

大型语言模型实践:P19:19_01_06_使用本地模型 🖥️

在本节课中,我们将学习如何在本地计算机环境中运行大型语言模型。我们将重点介绍由Mozilla Ocho团队开发的LlamaFile项目,它使得下载和运行多种模型文件变得简单直接。

概述

上一节我们探讨了云端LLM服务,本节中我们来看看如何在本地运行大型语言模型。使用本地模型是完全可行的,并且正变得越来越普遍。LlamaFile项目作为一个框架,允许用户轻松下载和运行多种类型的模型文件。

为什么选择LlamaFile?

以下是LlamaFile项目的几个关键优势:

  • 易于上手:项目的快速入门指南非常清晰,只需几个简单步骤即可在您的操作系统上运行模型。
  • 跨平台兼容:它可以在macOS、Linux或Windows系统上运行,没有障碍。
  • 硬件灵活性:运行速度取决于您本地系统的配置,例如RAM大小和GPU类型。
  • 交互方式:运行后,它会打开浏览器并加载一个本地主机地址,您可以通过网页界面与模型进行交互。

实践步骤:下载与运行

接下来,我们通过一个具体例子来演示如何操作。我将以Mixtral 8x7B模型为例,该模型文件大小约为30GB,采用Apache 2.0许可证。

我已经提前在系统上下载了该模型文件。我使用的是macOS系统,因此将切换到终端进行操作。

在我的终端临时目录中,存放着已下载的mixtral-8x7b模型文件。运行它非常简单,基本不需要额外配置。

您可以直接执行该文件。虽然可以通过参数(如--threads)进行一些配置,但运行--help命令可以查看所有可用选项和详细说明。该工具甚至支持跨多个GPU进行分割计算,不过我们暂不深入这些细节。

我们将直接运行它,看看效果如何。我打算使用2个线程来运行。

执行命令后,终端会输出大量信息。模型加载完成后,它将自动在浏览器中打开交互界面。让我们等待它完成,然后回到浏览器查看。

与本地模型交互

模型界面加载速度很快。界面上会显示一些系统要求和配置信息。您可以进行对话,查看聊天历史记录。

如果您只是想尝试一下,无需更改任何设置,可以直接滚动到页面底部开始使用。

例如,我们可以输入一个简单的请求:“请为我简要总结一下Mozilla的LlamaFile项目是什么,请分三段说明。”

模型需要一点时间处理。很快,我们就能看到一些输出结果。

需要注意的是,这个输出内容可能不完全准确,它似乎在描述文件存储和管理。这是因为该模型对于近期事件的准确性可能不高。不过,我们可以尝试其他类型的请求。

我们可以继续交互,例如说:“这听起来不错,能否请你改用项目符号列表的形式重新总结?”

您可以像与其他AI系统对话一样与它互动,效果通常不错。

总结

本节课中我们一起学习了如何通过下载并执行模型文件,在本地运行大型语言模型。我们利用Mozilla出色的LlamaFile项目,实现了在本地计算机上运行(而非基于云端的)大型语言模型,这完全是可行的。

大型语言模型实践:P20:基于云的解决方案 ☁️

在本节课中,我们将学习如何使用基于云的解决方案来部署和管理大型语言模型。我们将以微软Azure平台为例,演示如何快速创建模型部署、通过API或交互式界面使用模型,并理解云服务带来的便利性。


上一节我们介绍了本地部署模型的基础知识,本节中我们来看看如何利用云服务来简化这一过程。基于云的系统,例如我们即将使用的Azure,提供了部署和管理大型语言模型的能力。不仅如此,它还提供了交互式API接口。

现在,我将向你展示Azure AI Studio。请注意,当你观看此视频时,相关功能可能已正式发布,不再处于预览阶段。我将点击进入,它会打开并欢迎你使用Azure AI Studio。由于我已经提前创建并打开了它,我将跳过初始设置步骤。这里列出了多个不同的项目,我将点击其中一个。具体是哪一个项目并不重要,我的目的是向你展示其核心功能。

首先,我需要创建一个部署。实际上,我已经完成了一个部署。我将点击“部署”选项,你可以看到我已经部署了一个名为“GPT-35 Turbo”的模型,这只是众多可用模型中的一个。创建部署的过程非常简单直接。部署本质上就是从一长串可用模型列表中选择一个模型。你甚至可以看到Hugging Face上的模型也在此列,所有这些模型都可以被部署,并准备好通过API调用。

如果我点击已部署的“GPT-3 Turbo”模型,我不仅可以通过一个暴露在互联网上的开放API与之交互(这意味着我可以从任何地方使用我的专属密钥访问它,出于安全考虑,密钥在此隐藏),还可以在“游乐场”中使用它。如果我点击“在游乐场中打开”按钮。

这将带我进入一个新页面。在这里,我可以设置系统消息、调整特定参数,并开始实际对话。我甚至可以语音输入(虽然现在不想这么做),然后关闭语音功能,输入一个查询。

例如,我想了解葡萄牙里斯本二月份的天气情况。我计划去那里,但不知道该穿什么衣服。那么,什么着装是合适的呢?让我们看看能否得到一些信息。

我立刻得到了回复。我正在使用那个部署到网络上的模型。回复非常完美:气温大约是61华氏度,即16摄氏度。这听起来非常温和宜人。我再次获得了多种操作选项,甚至有能力在VS Code桌面版或网页版中打开项目。

那么,为什么这种方式具有吸引力?为什么它很有趣?原因在于,当你不想在本地运行模型时,可以将它们放在云端。你可以看到,整个过程只需几次点击。当然,我提前完成了部署,所以我们才能看到已经部署好的模型。但这并非难事,过程相当直接。

以下是云平台提供的主要功能:

  • 游乐场:一个交互式环境,用于测试和与模型对话。
  • 评估:工具用于评估模型性能和输出。
  • 提示流:用于管理和优化你给模型的提示(指令)的工作流。
  • 多样化操作:你可以通过拖拽等多种方式与你的大型语言模型进行交互。

这是一个非常快速、直观的演示,展示了像Azure这样的云系统和云提供商如何让你能够运行这些模型。通过一个可以从互联网任何地方访问的部署,你可以实际运行模型、创建自己的应用程序,并以一种非常快速、便捷的方式与这些大型语言模型进行交互。


本节课中,我们一起学习了利用云平台(如Azure)部署和使用大型语言模型的基本流程。我们了解到,云服务通过简化的部署管理、灵活的API访问和交互式测试环境,大大降低了使用LLM的技术门槛和操作复杂度,使得开发者能够更专注于应用开发本身。

大型语言模型实践:1:课程总结

在本节课中,我们将对之前学习的内容进行回顾与总结,梳理在本地运行大型语言模型、探索开源资源以及未来向云端迁移的关键要点。

课程回顾

上一节我们介绍了在云端探索解决方案的可能性,本节中我们来总结整个模块的核心收获。

正如你所看到的,探索基于云的解决方案非常有趣,尤其当你身处一家公司时。如果你有一个想要实践的想法,云端无疑是你应该考虑的方向。

但在转向云端之前,你现在已经理解了如何在本地运行这些大型语言模型,并进行了一些探索和实验。这无疑具有成本优势,因为你可以通过在本地运行来推进一个大型语言模型应用的开发。当你的应用准备就绪时,再进入下一步,例如转向像微软Azure云这样的基于云的解决方案。

不仅如此,我们还探索了Hugging Face和一些开源模型。我们了解了什么是Hugging Face,如何找到其中的一些模型,以及如何探索Hugging Face空间中提供的模型集合里其他可用的模型。这是一个很好的方式,可以探索有哪些资源可供你使用,以及如何在本地使用它们,然后在准备就绪时或许再迁移到云端。

核心要点总结

以下是本阶段学习的关键收获:

  • 本地开发的成本优势:在将想法付诸云端实践前,于本地运行和测试大型语言模型是控制成本、进行初步探索的有效方式。
  • 云端的战略位置:对于企业级应用或成熟的项目,基于云的解决方案(如 Microsoft Azure)提供了强大的扩展性、管理工具和服务集成。
  • 开源资源的价值:利用如 Hugging Face 这样的平台,可以广泛接触和评估各种开源模型,其核心价值在于提供了一个庞大的模型库(Model Hub)和便捷的集成工具。

学习路径建议

基于以上内容,一个可行的学习与实践路径是:

  1. 本地探索:利用Hugging Face等资源,在本地环境尝试不同的开源模型。
  2. 应用开发:在本地完成应用的原型开发和初步测试。
  3. 云端迁移:当应用稳定并需要扩展时,考虑部署到云平台。

本节课中我们一起学习了大型语言模型实践的基础路径:从利用开源资源在本地进行低成本探索和开发,到认识到云端解决方案对于成熟项目的重要性。这条路径帮助你在拥有实践想法的同时,能兼顾成本与灵活性,并为未来的规模化应用做好准备。

大型语言模型实践:P22:引言_4

在本节课中,我们将要学习提示工程的基础知识。虽然在与大型语言模型进行基于聊天的交互时,我们可能不会过多思考它,但确实存在一些技巧和方法,可以让交互更有效、获得更好的回答,并使整个过程对您更有用。

什么是提示工程?🤔

上一节我们介绍了课程的整体目标,本节中我们来看看提示工程的核心概念。提示工程是指通过设计和优化输入给大型语言模型的文本(即“提示”),来引导模型生成更准确、更相关、更高质量输出的过程。

其核心公式可以理解为:
高质量输出 = 优化后的提示 + 模型能力

提示工程的关键技术 🛠️

我们将深入探讨几种基础的提示工程技术,而不仅仅是更好的提问方式。

以下是几种重要的提示方法:

  • 零样本提示:直接向模型提出一个问题或请求,不提供任何示例。例如,直接提问“法国的首都是哪里?”
  • 少样本提示:在提出主要问题前,先提供少量示例来引导模型。这有助于模型理解任务格式和期望的输出类型。

如何优化提示? ✨

为了获得更好的回答,我们需要改进提示本身。这主要涉及两个方面。

以下是优化提示的两个关键点:

  1. 提供更好的上下文:在提示中清晰地说明背景、角色和任务目标,帮助模型更准确地理解意图。
  2. 提出更简洁直接的问题:避免模糊或冗长的表述,使问题焦点明确,减少模型产生歧义的可能性。

评估模型响应 📊

最后,我们还需要学会评估模型返回的响应。检查回答是否准确、完整、相关,并符合提示的要求,是提示工程中不可或缺的一环。

本节课中我们一起学习了提示工程的基本概念,包括零样本提示和少样本提示等关键技术,以及如何通过优化上下文和提问方式来提升交互效果。同时,我们也认识到评估模型响应的重要性。掌握这些基础知识,将帮助您更有效地与大型语言模型进行交互。

大型语言模型实践:P23:什么是提示工程 🧠

在本节课中,我们将要学习提示工程的基本概念。提示工程是有效与大型语言模型(如ChatGPT)进行沟通的关键技能。我们将通过具体示例,理解如何通过提供清晰的上下文来获得准确、有用的回答。

什么是提示工程?

提示工程听起来可能像是一个营销噱头或一堆没有实际意义的流行词汇。实际上,当人们提到“提示工程师”或“提示”时,其核心含义是如何成为一个有效的沟通者

我们以ChatGPT为例。用户输入文本框中的内容就是“提示”,这是我们与AI应用程序或大型语言模型互动的方式。

理解提示的构成

以下是几个提示的例子:

  • Plan itinerary for a fashion-focused exploration of Paris.

请注意,“Plan itinerary for a fashion-focused exploration of Paris”这部分被加粗显示,它只是整个提示的一部分。提示工程的能力,就在于让这个提示为你提供一个有效的回应。

实现这一点的唯一方法,是提供大型语言模型能够理解并据此行动的上下文。如果我们说的话缺乏上下文,得到的回应就会不尽如人意。

从无效提示到有效提示

上一节我们介绍了提示需要上下文,本节中我们来看看一个缺乏上下文的例子。

假设我对购买一辆自行车感兴趣。我知道我想要什么类型的车,确切知道自己的尺寸,也清楚我将用于山地骑行。但AI,也就是这里的大型语言模型,对这些一无所知。

那么,一个不那么有效、不那么好的提示会是什么样的呢?我们可以这样说:

代码示例:一个无效的提示

I want to buy a bike.

输入这个提示后,大型语言模型会立刻识别出信息缺失。它不知道具体规格,不知道你是想要推荐,还是购买指导。它一无所知。

而提示工程,就是我能够以一种大型语言模型可以理解的方式提供更多上下文的能力,从而让它能为我提供准确、有用且可操作的信息。

构建一个有效的提示

让我们稍微修改一下这个提示。我们还没有深入探讨具体什么样的提示是有用的,但可以先让它变得好一些。

我可以这样说:

代码示例:一个改进后的提示

I am six feet four inches tall. I need a mountain bike for easy trail riding. I need recommendations of brands that I can investigate and look at some of their characteristics. List the brands and models.

现在,我们得到了一些更有意义的内容。通过这种方式与大型语言模型互动,我们提供的信息对于寻找特定物品的人来说是立即有用的

这就像去超市问别人“我需要做些吃的”,却不提供任何细节一样,那不会奏效。AI应用程序不会神奇地理解你想要什么。而在这个案例中,我们能够提供一些输入,并获得非常好的输出,它准确地总结了我需要的信息。

这里的信息是可操作的,对我有用。我可以开始查看每一个选项,并可能从这些有趣的自行车品牌和型号中做出选择,以满足我的使用需求。

课程总结 🎯

本节课中,我们一起学习了提示工程的基础。我们了解到,提示工程的核心是通过提供清晰、具体的上下文,与大型语言模型进行有效沟通。从一个简单的“我想买辆自行车”到包含身高、用途和具体需求的详细描述,我们看到了上下文如何将模糊的请求转化为 actionable 的实用建议。记住,与AI沟通就像与一个知识渊博但需要明确指令的助手对话,你说得越清楚,它回答得就越有用。

大型语言模型实践:P24:零样本、单样本与少样本提示 🎯

在本节课中,我们将要学习大型语言模型提示工程中的三个核心概念:零样本提示、单样本提示和少样本提示。理解这些概念是掌握有效提示技巧的基础。

概述

零样本、单样本与少样本提示是你在尝试优化提示时可能会听到的术语。它们描述了不同类型提示的良好特性。

零样本提示

让我们从零样本提示开始。我将给你一个例子。

这个例子是:“写一个关于狗的有趣笑话”。我没有提供任何示例。我实际上只是给大型语言模型一个单一的指令。我将得到一个非常直接的单一响应,没有其他内容。

这具体是关于什么呢?它不需要任何示例,因此我不需要提供任何额外的上下文。助手(大型语言模型)仅根据我给出的指令生成足够好的响应。

核心概念:零样本提示意味着仅提供任务指令,不提供任何示例。

# 零样本提示示例
prompt = "写一个关于狗的有趣笑话"

单样本提示

那么什么是单样本提示呢?那就是提供一个示例。

例如,我需要说:“这里有一篇关于《Python测试》的书评,这是我之前写的一本书。这是一本扎实的Python测试入门书,特别适合软件工程。按句子来,我认为这很不错。”

现在我可以接着说:“现在用同样的语气和语言,为《炼金术士》写一篇书评。”《炼金术士》是一本非常受欢迎的书。我们来看看它是否能做到。

看,它生成了:“《炼金术士》是一段迷人的旅程……”这实际上并没有完全使用我的示例。但我们给了它一个示例,这就是我们得到的结果。

例如,如果我们改变我们实际所说的内容,并给它一些更具体的指示:“这是一本书,我会给它打9.9分(满分10分)。用同样的语气和语言,使用格式。为《炼金术士》写一篇书评。确保遵循我的示例。”

也许我们会看到它包含了一点《Python测试》的内容,这有点意思。虽然不完全是我想要的,但它确实做到了。这实际上很有趣,因为它说《炼金术士》的叙事是9.9分(满分10分)。它确实在评分中使用了9.9分。它还说“就像Python语法中发现的清晰度一样”,这非常有趣。

核心概念:单样本提示意味着提供一个任务示例,然后要求模型执行类似任务。

# 单样本提示示例
prompt = """
示例:这是一篇关于《Python测试》的书评。这是一本扎实的Python测试入门书,特别适合软件工程。我会给它打9.9分(满分10分)。
任务:用同样的语气、语言和格式,为《炼金术士》写一篇书评。
"""

少样本提示

那么什么是少样本提示呢?我提供几个示例。

以下是关于本地餐厅的一些评论。😊

我说:“评论一:这里的食物很扎实,服务一般般。”我们可以做一个第一条评论。然后说:“评论二:真的很喜欢菜单。有不同的选择。服务很棒且友好。”

现在我能说的是:“现在为我写一篇遵循同样语气和字符数(或字数)的评论,但它是关于一家餐厅的略微负面的评论,比如说,一家供应汉堡的餐厅。”某种比较通用的东西。

我在这里做的是少样本提示。这意味着我提供了两个以上的示例。这就是为什么叫“少样本”。我要这么做,然后我会得到结果:“这个地方的汉堡还不错,不算特别惊艳。菜单缺乏多样性。”

你能看到我在谈论食物、菜单和服务。这与我之前提供的内容类似。这是一个关于如何交互和提供上下文的好例子。

核心概念:少样本提示意味着提供多个(通常大于一)任务示例,然后要求模型执行类似任务。

# 少样本提示示例
prompt = """
示例1:这里的食物很扎实,服务一般般。
示例2:真的很喜欢菜单。有不同的选择。服务很棒且友好。
任务:用类似的语气和长度,写一篇关于一家汉堡店的略微负面的评论。
"""

总结

本节课中我们一起学习了零样本、单样本与少样本提示的区别。这些概念足够好,能让你理解单样本、单次提示或少样本之间的差异。这里是非常基础的例子,但它们将为你打下良好的基础,以便你能继续学习更好的提示技巧。

大型语言模型实践:P25:基于上下文的基础提示 📝

在本节课中,我们将学习如何在与大型语言模型(如ChatGPT)交互时,通过提供基础上下文来获得更优质、更准确的回答。这是有效利用大语言模型的关键第一步。

概述

与大型语言模型互动时,仅仅给出指令往往不够。为了让模型生成符合我们具体需求的输出,我们需要为其提供相关的背景信息。本节课将通过一个编写README文件的实例,演示如何构建包含有效上下文的提示词。

基础提示示例

上一节我们概述了提供上下文的重要性,本节中我们来看看一个具体的例子。假设我们需要为项目编写一个README文件。

首先,我们向模型提供一个包含基本上下文的提示。这个提示不仅包含指令,还说明了项目的关键信息。

我需要为一个用Python编写的项目写一个README文件。请为我提供一个能引起开发者共鸣的基本结构。不需要为各个部分虚构内容,提供一个标题框架,以便我填充项目细节。

在这个提示中,我们提供了几个关键信息点:

  1. 任务目标:编写README文件。
  2. 项目语言:使用Python。
  3. 目标受众:开发者。
  4. 具体指令:提供结构框架,而非虚构内容。

模型根据这个提示,生成了一个通用的README结构,通常包含以下部分:

  • 项目标题
  • 描述
  • 安装
  • 使用
  • 贡献
  • 许可证

优化上下文以获得更佳结果

虽然第一个回答不错,但我们注意到,尽管提到了“Python”,生成的结构却并非Python项目特有的。这说明初始的上下文信息可能不够精确。

因此,我们需要进一步优化提示,提供更具体的上下文。

以下是优化后的提示,它更明确地指出了对Python相关内容的期望:

我需要为一个用Python编写的项目写一个README文件。请为我提供一个能引起Python开发者共鸣的基本结构。建议几个专门与Python相关的部分。不需要为各个部分虚构内容,提供一个标题框架,以便我填充项目细节。

这个新提示将“开发者受众”具体化为“Python开发者”,并明确要求“建议几个专门与Python相关的部分”。这为模型提供了更清晰的上下文。

上下文优化后的效果

基于更精确的上下文,模型现在生成的README结构包含了更多Python项目特有的部分。以下是可能新增或强化的部分:

以下是模型可能建议的Python相关章节:

  • 环境要求:明确列出所需的Python版本。
  • 虚拟环境设置:指导如何使用venvconda创建隔离环境。
  • 依赖安装:通过pip install -r requirements.txt安装依赖。
  • 运行测试:说明如何执行项目的测试套件(如使用pytest)。

通过提供“Python开发者”和“Python相关部分”这两个关键上下文,我们成功引导模型输出了更具针对性和实用性的结果。所有建议的部分对于一个Python项目来说都是高度相关的。

总结

本节课中我们一起学习了基于上下文的基础提示方法。关键在于,有效的提示应结合清晰的指令和具体的背景信息。通过示例我们看到,即使是很小的上下文补充(如从“开发者”细化到“Python开发者”),也能显著提升模型输出的相关性和质量。记住,你提供的上下文越精确,大型语言模型就越能理解你的真实意图,从而提供更有价值的帮助。

大型语言模型实践:P26:在提示中使用示例

概述

在本节课中,我们将学习如何在向大型语言模型(LLM)提问时,通过提供具体的示例来引导模型生成更符合我们期望的输出。这种方法被称为“少样本提示”,它能显著提升模型输出的准确性和格式规范性。

示例提示的作用

上一节我们介绍了提示的基本概念。本节中,我们来看看如何通过提供示例来具体指导模型。在之前的课程中,我们简要提到过可以使用“单样本”或“少样本”提示。这意味着我们可以在提示中直接包含我们希望模型模仿的格式或内容示例。

一个具体的应用案例

为了更清晰地说明,我将展示一个过去实际使用过的提示示例。在这个案例中,我尝试使用JSON格式来构建一个API。API和JSON这些术语对于非开发者可能有些陌生,但不用担心,我们会一步步解释。

以下是我当时使用的完整提示内容:

I'm building an example API that's basically an HTTP service, a programming API that's going to live on the web somewhere and uses JSON. JSON is a type of data formatting.
Uses a JSON file to load historical data on different temperature values for cities and countries.
I want to use the same but for different cities only in Portugal.
Please generate the JSON contents for me with as many major cities in Portugal as you can.
Here's the example JSON format:
{
  "England": {
    "London": {
      "January": {"high": 64, "low": 45},
      "February": {"high": 65, "low": 45}
    }
  }
}

提示的组成部分解析

让我们来分析一下这个提示的各个部分,理解它们如何共同作用来指导模型。

以下是这个提示包含的关键指令和信息:

  1. 任务描述:明确告知模型我正在构建一个使用JSON的HTTP API服务。
  2. 数据用途:说明JSON文件将用于加载城市和国家的历史温度数据。
  3. 具体范围:将数据范围限定在葡萄牙的主要城市。
  4. 输出要求:要求模型生成尽可能多的葡萄牙主要城市数据。
  5. 格式示例:提供了一个以英格兰和伦敦为例的JSON结构示例,明确了国家、城市、月份以及高低温数据的嵌套关系。

模型输出结果分析

基于以上提示,模型生成了以下输出:

{
  "Portugal": {
    "Lisbon": {
      "January": {"high": 14, "low": 8},
      "February": {"high": 15, "low": 8}
    },
    "Porto": {
      "January": {"high": 13, "low": 5},
      "February": {"high": 14, "low": 6}
    }
  }
}

可以看到,因为我提供了一个清晰的示例,模型准确地输出了我所需要的内容。生成的JSON格式规范,并且包含了里斯本和波尔图这两个葡萄牙的主要城市。

注意:一个有趣的细节是,示例中英格兰的温度单位是华氏度(64°F),但模型为葡萄牙生成的数据似乎是摄氏度(14°C)。这提醒我们,示例中的每一个细节都可能被模型捕捉和学习。

使用示例提示的优势

这个案例很好地展示了在提示中添加示例的强大作用。通过提供一个具体的格式范例,我们可以:

  • 获得精确的输出格式:确保模型返回的数据结构(如JSON的嵌套层级)完全符合我们的要求。
  • 引导内容生成:模型能理解示例中的数据关系(国家-城市-月份-温度),并据此为新主题(葡萄牙)生成类似内容。
  • 加速开发流程:生成的规范JSON数据可以直接被应用程序读取和使用,省去了手动整理数据的时间。

总结

本节课中,我们一起学习了如何在大型语言模型的提示中有效地使用示例。通过提供一个清晰、具体的格式范例,我们可以极大地提高模型输出结果的相关性格式规范性。这是一种简单而强大的技巧,能够帮助你将LLM的输出更精准地应用到实际项目中去,例如生成特定结构的数据、转换文本格式或模仿某种写作风格。

大型语言模型实践:2.8:总结 🎯

在本节课中,我们将回顾并总结如何与大型语言模型进行交互,以及提升模型响应质量的关键技术。

我们探讨了如何在基于聊天的界面中与大型语言模型进行交互,分析了所获得响应的类型,并学习了如何通过特定方法来改进这些响应。

提升响应质量的方法

以下是几种提升大型语言模型响应质量的核心技术。

1. 少量示例提示

当我们提供少量示例时,可以显著改善模型的输出。这种方法通过展示具体的例子,引导模型理解并遵循期望的格式或风格。

2. 提供更优的上下文

通过提供更丰富、更精确的上下文信息,可以帮助模型生成更相关、更准确的回答。这包括明确任务背景、约束条件或相关细节。

3. 使用示例增强效果

一种非常有效的方法是直接提供示例。无论是展示“这是我之前做过的”,还是呈现“这是类似的情况”,使用示例都能显著增强模型的响应,获得比仅使用简单提示(不含任何示例)更好的结果。

总结

本节课中,我们一起学习了与大型语言模型交互的基础,并重点掌握了通过少量示例提示提供更优上下文以及直接使用示例这三种关键技术来提升模型响应质量的方法。提供更多上下文信息,正如我们在最后几课中所见,是获得更佳结果的有效解决方案。

大型语言模型实践:1.2:提示工程进阶技巧与局限性

在本节课中,我们将学习如何通过设定语气和角色等进阶技巧来改进提示词,并探索如何通过与大型语言模型的迭代交互来优化其回答。我们还将了解如何通过提供反馈来获得更佳的输出,并认识提示工程中的一些局限性。

设定语气与角色 🎭

上一节我们介绍了提示工程的基础概念,本节中我们来看看两种进阶技巧:设定语气和设定角色。这些技巧虽然稍显复杂,但一旦熟练掌握,它们将变得非常自然。

以下是两种具体的应用方法:

  • 设定语气:通过明确指示模型采用特定的口吻(如正式、随意、热情、简洁)来塑造回答的风格。
  • 设定角色:通过指示模型扮演特定角色(如专家、教师、助手)来调整回答的视角和深度。

迭代优化回答 🔄

除了初始的提示设计,我们还可以在获得模型的初步回答后,进行迭代式的优化和精炼。这种方法基于模型的响应进行构建。

以下是迭代优化的基本步骤:

  1. 获取初始响应:向模型提出第一个问题或指令。
  2. 提出细化请求:基于初始回答,要求模型进行更深入的解释、提供示例或调整重点。
  3. 持续改进:可以多次重复这一过程,逐步引导模型产出更符合需求的答案。

通过反馈提升质量 💬

我们还可以通过向模型提供明确的反馈,来引导其后续的回答,从而进一步提升输出质量。

核心方法是:在对话中明确指出回答的优缺点或需要调整的方向,并要求模型据此生成新的、改进后的回答。代码层面的交互逻辑可以抽象为:

# 伪代码示例:基于反馈的交互循环
initial_response = llm_query(initial_prompt)
feedback = “请更详细地解释第二步,并补充一个实际案例。”
improved_response = llm_query(f“基于以下反馈改进你的回答:{feedback}\n你的原回答是:{initial_response}”)

理解提示工程的局限性 ⚠️

然而,提示工程并非万能,它也存在局限性。了解这些边界对于有效使用模型至关重要。

一个关键的局限性是:当提供的上下文信息过多或指令过于复杂时,可能会影响模型回答的质量。模型可能无法有效处理所有信息,导致回答偏离核心问题、遗漏关键点或产生混淆。

本节课中我们一起学习了如何通过设定语气和角色来优化提示词,掌握了通过迭代交互和提供反馈来精炼模型回答的方法,并认识了提示工程在处理过量信息时的局限性。掌握这些技巧将帮助你更有效地与大型语言模型协作。

大型语言模型实践:P29:设定语气与角色

在本节课中,我们将学习如何在与大型语言模型交互时,通过设定语气和角色来引导其输出,以确保获得符合特定需求的结果。

设定语气和角色是与大型语言模型交互时一项非常可靠的策略。当你需要确保模型输出的信息在表达方式和风格上完全符合你的要求时,这项技术尤其有用。

上一节我们介绍了策略的重要性,本节中我们来看看具体的操作方法。我将通过一个简单的总结任务来演示。

首先,我将在ChatGPT中执行一个基础任务,不提供任何额外的上下文或指示。我会输入:“请总结以下文本”。这段文本是我之前在LinkedIn上发布的一篇关于个人学习经历和重要观点的博客文章。

以下是基础指令下的输出结果:

  • 作者回忆了祖父的教诲,并对当前大规模裁员的现象表达了担忧。文章整体上是在陈述一种个人观点。

这个总结看起来不错,但我们可以通过添加角色和语气指令来改变它。

“角色”是指令大型语言模型扮演某个特定身份。例如,我们可以让模型扮演一位“高级高管教练”。

“语气”则是指定输出内容所使用的语言风格和正式程度。我们可以要求总结使用“高管级别的语言和语气”,甚至说明这份总结是“可以发送给董事会高管们的邮件”。

当我们同时应用了新的角色和语气指令后,输出发生了显著变化。开头变成了“我相信您一切安好。我写这封信是为了提请关注一篇近期富有洞察力的博客文章……”,整体语言变得非常正式和专业。

我们还可以尝试完全不同的组合。例如,将角色设定为“为小学生举办派对的活跃主持人”,并要求使用“能让孩子们理解的快乐语言”来总结。

应用这个新设定后,输出再次改变。开头可能是:“嘿,了不起的小朋友们!希望你们玩得开心!……” 并且可能会自动加入表情符号,使文本生动有趣。

这个例子可能略显夸张,但它清晰地展示了如何通过设定角色和语气来达成目标。你不需要同时使用两者,根据需求单独使用“角色”或“语气”指令同样有效。

本节课中,我们一起学习了如何通过设定“角色”和“语气”来精确控制大型语言模型的输出风格。你可以根据实际场景,灵活运用这些指令,让模型生成更符合特定场合和受众需求的文本。

大型语言模型实践:P30:基于先前上下文的精炼 🎯

在本节课中,我们将学习如何基于与大型语言模型(LLM)的先前对话历史,来逐步优化和精炼我们的提示(Prompt),以获得更符合需求的输出。这是一种高效的交互策略,无需每次都重复完整的上下文。

回顾初始请求与响应

上一节我们介绍了如何通过提供示例来引导模型输出特定格式。我们曾请求模型以JSON格式提供葡萄牙两个城市的天气数据,并给出了一个示例。模型的响应基本符合要求。

以下是初始请求的示例代码:

{
  "city": "示例城市",
  "temperature": 72,
  "unit": "Fahrenheit"
}

模型成功返回了里斯本(Lisbon)和波尔图(Porto)的数据,但温度单位使用了摄氏度(Celsius)且值为整数。这与我们期望的使用华氏度(Fahrenheit)不符。

进行首次精炼:更改温度单位

基于上述响应,我们可以直接在其基础上进行优化,而无需重述所有要求。以下是精炼过程的核心思路。

我们只需告诉模型:“你的回复看起来不错,但我需要华氏度而不是摄氏度。” 模型会利用整个对话历史来理解这个新指令,并生成更新后的响应。这样,我们就成功地将温度单位从摄氏度修正为华氏度。

进行深度精炼:调整数据结构

在获得符合单位的响应后,我们可以进一步优化数据结构。例如,我们可能觉得分别提供“最高温”和“最低温”不够简洁,希望合并为一个“平均温度”值。

此外,我们可能希望改变JSON的结构。在JSON中,由花括号 {} 包裹的部分称为一个对象(Object)。我们可以要求模型不再为每个城市返回一个对象,而是直接以城市名为键,平均温度为值。

我们可以这样提出要求:“请提供平均温度,而不是最高和最低温度。并且,我不想要对象格式,我希望数据像这样:{“December”: 57}

通过提供这个简单的示例,模型能够理解我们的意图,并输出结构更精简、完全符合我们新要求的数据。

探索更多可能性:请求格式建议

基于不断精炼的对话上下文,我们还可以引导模型探索更多可能性。例如,我们可以询问模型:“除了JSON,这里还可以使用哪些其他数据格式?请为我建议三种不同的类型。”

模型可能会基于当前对话的上下文(即天气数据),推荐如YAML、XML或CSV等格式。这展示了如何通过迭代式对话,逐步将模型的输出引导至你所需要的任何特定形式或格式。

总结

本节课中我们一起学习了“基于上下文的提示精炼”技术。关键在于:

  1. 无需重复:每次精炼时,无需重复之前已提供的所有上下文和示例。
  2. 迭代优化:将模型的每次回复作为新起点,提出具体的改进要求。
  3. 明确指令:通过简短指令或新示例,明确指出希望修改的部分(如单位、结构、格式)。
  4. 探索拓展:在稳固的上下文基础上,可以轻松请求模型提供变体或建议。

这种方法极大地提升了与大型语言模型交互的效率和精准度,使你能够通过连续、聚焦的对话,逐步获得理想的结果。

大型语言模型实践:P31:通过反馈优化指令 🎯

在本节课中,我们将学习一种强大但常被忽视的技巧:如何通过与大型语言模型的互动反馈,来优化你的提示词,从而获得更精确、更有用的回答。

概述

通过反馈优化提示词是一种非常有效的方法。其核心思想是,当你对模型的初始回答不满意时,不要放弃或重新开始,而是主动询问模型:“为了让你给出更好的回答,我还需要提供哪些信息?” 这种方法能帮助你发现自身思考的盲点,并引导模型生成更符合你需求的输出。

上一节我们介绍了如何构建一个基础的提示词。本节中,我们来看看如何通过迭代反馈,让这个基础提示词变得更强大。

从基础提示词开始

我们从一个非常基础的提示词示例开始。假设我们想创办一家专门做阿根廷烤肉(Asado)的餐饮公司。

初始提示词示例:

我想创办一家专门做阿根廷烤肉的餐饮公司。请为我提供一个商业计划书。

让我们看看模型会给出什么回答。

模型初始回答示例:

创办一家餐饮公司可能是一次激动人心的冒险。以下是一个基本的商业计划大纲:
1.  执行摘要
2.  市场分析
3.  服务与菜单
4.  营销策略
5.  运营计划
6.  财务预测
7.  监控与评估
请根据您的具体情况调整每个部分。

这个回答看起来不错,提供了一个标准的商业计划框架。但可能还不够具体,缺乏针对我们特定业务(阿根廷烤肉餐饮)的深度洞察。

主动寻求反馈:询问缺失信息

为了获得更精准的指导,我们可以主动向模型提问,了解我们遗漏了哪些关键信息。

以下是向模型寻求反馈的提示词示例:

感谢你提供的计划。为了让你能给出更好、更具体的回答,你能建议一些我在创办这个生意时可能没考虑到、但对你提供更好指导有帮助的事情吗?请列出最多10项,以便我审视并了解需要向你补充哪些背景信息。

模型可能会给出如下反馈列表:

模型反馈示例(可能包含的项目):

  1. 保险需求
  2. 活动物流安排
  3. 客户服务策略
  4. 营销宣传材料
  5. 定价策略
  6. 长期目标(例如,是单一经营还是计划扩张)
  7. 目标客户群体详情
  8. 菜单的详细构成与定制选项
  9. 供应商与食材来源
  10. 法律法规与许可要求

这个列表很有用,但可能不完全符合我们的预期。由于大型语言模型固有的非确定性行为,每次回答可能略有不同。如果反馈不够精准,问题可能在于我们没有向模型清晰地解释自身需求。

澄清需求,获取精准指导

我们可以进一步澄清问题,引导模型给出更相关的建议。

优化后的反馈请求示例:

我可以提供哪些具体信息,以便你能就我的餐饮生意给我更好的指导?

这次,模型的回答可能更聚焦于商业计划的核心要素:

模型更精准的反馈示例:

为了提供更具体的指导,我需要了解以下信息:
- **定价策略**:你计划如何为服务定价?
- **长期目标**:是希望经营单一业务,还是有扩张计划?
- **活动规模**:你主要承接多大规格的活动?(例如,最多50人的活动)
- **菜单细节**:你的菜单具体包含哪些菜品?(例如,专注于2-3种特色烤肉)
- **目标市场**:你的主要目标客户是什么?(例如,婚礼、企业活动)

现在,我们获得了非常明确的指导。接下来,我们就可以根据这些要点,向模型补充具体信息。

提供补充信息,获得定制化方案

根据模型的反馈,我们向提示词中添加具体的背景信息。

补充信息后的提示词示例:

我想创办一家专门做阿根廷烤肉的餐饮公司。请为我提供一个商业计划书。
补充信息:
- **活动规模**:主要承接最多50人的活动。
- **菜单细节**:专注于提供2种特色烤肉。
- **目标市场**:主要瞄准婚礼市场。
- **长期目标**:初期经营单一业务,暂无扩张计划。

基于这些更丰富的上下文,模型现在能够生成一个高度定制化、更具操作性的商业计划,例如,可能会包含“婚礼套餐设计”、“客户推荐计划”、“灵活菜单选项以适应不同婚礼需求”等具体内容。

通过这种“提问-反馈-补充”的迭代过程,我们成功地将一个模糊的请求,优化成了一个能引导模型产出高质量、高相关性回答的精准提示词。

总结

本节课中,我们一起学习了如何通过反馈循环来优化指令。关键步骤可以总结为以下公式:

优化流程 = 初始提示 → 模型回答 → 寻求反馈(“我还需要提供什么?”) → 根据反馈补充信息 → 获得优化回答

这种方法的核心优势在于,它利用模型自身的“知识”来反推我们提问的不足,特别适合在你不确定从何入手或思考存在盲点时使用。记住,与大型语言模型的有效互动往往是一个迭代过程,清晰的沟通和基于反馈的持续改进是获得理想结果的关键。

大型语言模型实践:P32:理解局限性 🧠

在本节课中,我们将探讨大型语言模型(LLM)在实际应用中的一些关键局限性。理解这些边界对于有效、安全地使用模型至关重要。

上一节我们介绍了如何通过提示工程引导模型,本节中我们来看看模型在哪些方面存在不足,以及如何应对这些限制。

提示的明确性至关重要

当您需要直接、准确的答案时,必须提出直接、具体的问题。如果问题过于宽泛,模型将很难给出精确的回应。

例如,一个非常宽泛的提示是:

bake me a cake

模型可能会感到困惑,因为它不清楚您具体想要哪种蛋糕。它可能会反问或给出一个通用的答案,例如建议烘焙一个生日蛋糕。

为了获得更精确的结果,您需要提供具体细节。以下是一个更具体的提示示例:

I want to bake a specific chocolate cake that has two layers, uses dulce de leche, and is meant for feeding five people.

通过指定蛋糕类型、层数、特殊配料和食用人数,您将获得一个更量身定制、更实用的食谱方案。模型可以据此提供关于糖霜和组装双层蛋糕的具体步骤。

模型的知识与访问限制

大型语言模型存在固有的知识边界。这是一个核心限制,主要源于其训练数据的性质。

模型基于历史数据进行训练,其知识存在截止日期。例如,许多公开模型的知识截止到某个特定时间点(如2022年1月)。因此,它无法知晓该日期之后发生的事件。

以下是模型无法回答的几类问题示例:

  • 实时信息查询:例如,“今天佐治亚州赫雷里塔的天气如何?” 模型没有访问实时天气数据的能力。
  • 个人隐私信息:例如,“我的银行账户里有多少资产和负债?” 模型无法获取任何用户的个人机密数据。
  • 最新事件:例如,“谁刚刚赢得了最新一届高尔夫锦标赛?” 如果该赛事发生在模型知识截止日期之后,它将无法提供正确答案。

理解这些限制非常重要,可以避免对模型产生不切实际的期望。

应对知识局限性的策略

尽管模型有其知识边界,但我们可以通过提供上下文来帮助它完成特定任务。

一种有效的策略是:将相关信息直接提供给模型,然后让它基于这些信息进行分析或总结。

例如,您可以先将一篇关于最新高尔夫锦标赛的长篇新闻报道粘贴给模型,然后给出如下指令:

基于以上文章,告诉我谁赢得了比赛,并总结其获胜的主要原因和重要性。

通过这种方式,模型能够利用您提供的“即时”上下文,生成准确且有针对性的回答,从而绕过其自身知识库的时间限制。


本节课中我们一起学习了大型语言模型的两个主要局限性:对模糊提示的敏感性基于历史训练数据导致的知识时效性与访问限制。我们了解到,通过提出具体、明确的问题,以及主动为模型提供相关上下文,可以在很大程度上克服这些挑战,从而更高效、更准确地利用大型语言模型。

大型语言模型实践:3.2.8:总结与反馈技巧 🎯

在本节课中,我们将学习如何通过与大型语言模型进行交互,获取反馈并优化提示词,从而显著提升模型回答的质量。


上一节我们介绍了如何通过特定指令引导模型输出。本节中我们来看看如何主动向模型寻求反馈,以进一步完善我们的提问方式。

我们探讨了如何进一步优化从基于聊天界面的大型语言模型处获得的回答。我特别欣赏其中关于获取反馈的部分,这在我们与大型语言模型交互时并不常见。我们可以主动向大型语言模型寻求反馈,询问它:“我遗漏了什么?有哪些事情我不太确定或不清楚?我应该告诉你哪些信息,你才能给我更好的回答?”

我们告诉大型语言模型:“请给我反馈,提供一些例子说明我如何改进我的提示词。”然后,我们将这些反馈建议融入我们后续的提示词中。

正如你所见,这将是一个非常有效的技巧。

这是一个值得应用的方法,尤其是当你正在精心设计那些可能会多次使用的提示词时。

这无疑是一个有用的技巧。我很高兴你现在已经了解了如何以这种方式与大型语言模型交互,并提升你所能获得的回答质量。


本节课中我们一起学习了如何通过向大型语言模型寻求反馈来优化提示词。这是一种强大的技巧,能帮助你更高效地利用模型,尤其是在构建可复用的提示词时。记住,主动询问“我该如何问得更好”是提升交互质量的关键一步。

大型语言模型实践:第6章:高级提示工程技巧

在本节课中,我们将学习一系列高级提示工程技巧。我们将超越基础方法,探索一些不那么常见但非常有效的技术。通过学习这些技巧,你将能够更熟练地引导大型语言模型,从而获得更优质、更准确的回答。

认识模型的局限性

在深入高级技巧之前,我们首先需要了解大型语言模型的局限性。当我们向模型提出过于复杂或信息量过大的请求时,它可能会“不堪重负”,导致无法准确回答我们的问题。理解这种极限状态的表现,有助于我们设计更有效的提示。

上一节我们介绍了模型过载的概念,本节中我们来看看如何通过任务分解来规避这一限制。

任务分解:化繁为简

当面对复杂问题时,一个有效的策略是将大任务分解为一系列更小、更简单的子任务。这可以显著提升模型响应的质量和准确性。

以下是进行任务分解的几个关键步骤:

  • 识别核心问题:首先,明确你需要解决的核心问题是什么。
  • 拆解逻辑步骤:将解决核心问题所需的过程,分解成一系列连续的、逻辑清晰的步骤。
  • 分步请求:依次向模型提出这些更简单的子任务请求,而不是一次性提出所有要求。

通过简化模型需要处理的任务,我们通常能得到好得多的回答。

思维链提示法

另一种强大的技巧是“思维链”提示。这种方法的核心是要求模型在给出最终答案前,先展示其推理过程。

思维链提示通常遵循以下结构:

用户:<复杂问题>
助手:让我们一步步思考。首先,[第一步推理]。接着,[第二步推理]。因此,最终答案是:[答案]。

这种技巧能迫使模型进行更深入的逻辑思考,从而减少“一本正经地胡说八道”的情况,并提高答案的可靠性。

其他有效的提示技巧

除了任务分解和思维链,还有许多其他提示结构可以帮助我们获得更好的结果。这些技巧通常涉及对指令的特定安排。

以下是一些值得尝试的提示技巧:

  • 指令前置:在提示的开头就明确提出最重要的指令或角色设定(例如:“你是一位经验丰富的软件架构师…”)。
  • 指令后置:在描述了具体场景或问题后,在提示的结尾处重申或总结关键要求。
  • 提供任务清单:以清晰列表的形式列出模型需要完成的所有事项,确保没有遗漏。

这些技巧的常见程度各不相同,但通过学习和应用这些高级方法,你将能够在提示工程方面变得更为出色,并持续获得更优质的模型响应。

本节课中我们一起学习了如何通过认识模型局限性、运用任务分解、采用思维链提示以及其他结构化技巧,来显著提升大型语言模型的输出效果。掌握这些高级提示工程方法,是有效利用生成式AI的关键一步。

大型语言模型实践:第2课:上下文的局限性 🧠

在本节课中,我们将要学习大型语言模型在处理上下文信息时存在的局限性。我们将通过一个具体的演示,来观察当提供给模型的信息量过大或对话历史过长时,模型可能出现的“力不从心”的情况。

概述

大型语言模型的能力并非无限,其处理信息的容量存在上限。这个上限通常被称为“上下文窗口”。当输入的信息或对话历史超过这个窗口的限制时,模型可能无法准确理解或完整执行复杂的指令,导致输出不完整、错误或中断。

上一节我们介绍了模型的基本交互方式,本节中我们来看看当任务变得极其复杂时,模型会如何表现。

演示:测试上下文极限

为了直观地展示这种局限性,我们设计了一个非常复杂的任务。首先,我们向模型提供了一段R语言代码,并要求它完成一系列繁重的转换和描述工作。

以下是向模型提出的初始指令:

我将向你提供一段R语言代码。我需要你将其转换为包括Python、TypeScript、JavaScript、Golang、Scala、Ruby和Bash在内的多种语言。
然后,你需要为每种语言创建两个段落来描述这段代码。
接着,为每种语言提供一个测试用例。
最后,为每种语言列出三个可以改进代码的潜在机会,并包含每种语言的一个简短设置说明。

模型开始处理这个请求,并逐一生成各种语言版本的代码、描述、测试和改进建议。这个过程会持续一段时间,并产生大量的输出文本。

提出更复杂的要求

在模型完成了第一轮庞大的输出后,我们继续“加码”,提出了更荒谬的要求,以测试其极限。

现在,我们基于已有的代码示例,提出新的指令:

现在我已经有了一些代码示例,我需要你为之前提供的每一种语言,再给出五种不同的代码实现方案。
同时,为每一种方案提供相应的说明。

模型再次开始处理这个新任务。我们可以观察到,随着输出的内容越来越多,模型的响应开始出现一些异常迹象,例如部分代码的语法高亮显示消失。

触及上下文限制

当我们试图基于这海量的对话历史,提出第三个复杂请求时,模型的局限性就彻底暴露了。

我们尝试要求模型将之前的所有内容整合成一篇博客文章:

现在,请基于我们完成的所有内容,生成一篇博客文章。
例如,为每种语言撰写8到9个段落,解释我们做过的不同实现和代码片段。

此时,模型无法完整地执行指令。它的输出在“Scala”语言的部分突然中断,并显示“继续生成”的提示。Bash语言甚至没有出现在列表中。这表明模型已经无法承载和回顾整个冗长的对话历史。

为了进一步验证,我们回到对话的最顶部,尝试修改一个贯穿所有内容的指令:

更新所有的代码示例,让它们不再打印信息,而是将信息写入文件系统。
同时,更新所有相关的描述和建议。

执行这个指令后,我们得到的结果是不完整的。模型没有更新所有代码示例,只修改了部分段落。它进入了一种“崩溃”状态,无法完成我们提出的、需要依赖大量上下文的复杂指令。

总结

本节课中我们一起学习了大型语言模型上下文的局限性。关键点在于,模型能“记住”和有效处理的对话历史与输入信息是有限的。当任务过于复杂,生成的文本量超过其上下文窗口时,模型可能无法:

  • 完整执行需要通篇理解的指令。
  • 保持输出的连贯性和正确性。
  • 避免在生成过程中中断。

这提醒我们,在与大型语言模型交互时,需要将复杂任务拆解为更小的、步骤清晰的子任务,并注意管理输入信息的长度,以确保获得可靠的结果。

大型语言模型实践:P36:分解为更小的任务 🧩

概述

在本节课中,我们将学习一个处理复杂任务的核心策略:将大型任务分解为更小的、可管理的子任务。我们将通过一个具体的例子——从一大段CSV文本数据中提取特定信息——来演示如何通过分步提问,引导大型语言模型(如ChatGPT)精确地完成任务,避免因一次性请求过多信息而导致模型“不知所措”。


将一项大型任务分解成小块,听起来很简单,但当你面对一段复杂的文本或一个需要完成的目标时,情况可能并非如此直接。

我将粘贴一大段CSV格式的文本数据,并尝试提出一个请求,看看大型语言模型是否能真正帮助我们。我有一段很长的CSV文本,需要你帮我提取其中关于葡萄酒的“品酒笔记”部分。我即将粘贴的是一段包含世界各地不同葡萄酒信息的逗号分隔值文本。

以下是CSV内容。

我已经粘贴了大量内容,你可以看到它几乎难以理解。

让我们看看ChatGPT会给出什么。非常好,它能够准确地生成我要求的内容。

所以,你可以看到这里有一些重复,但又不完全是重复,因为这些是非常相似的葡萄酒。如果你需要更多条目的笔记,请随时提出。这很好。

然而,我们可以更进一步。

接下来我要做的是,我会说:记住我粘贴的数据。看起来数据量对它来说太大了,我实际上可以缩减请求。

我会说:有哪些方法可以减少这些数据?只生成2015年及以后年份的葡萄酒的笔记,并且不要提供超过15款葡萄酒。

这看起来是正确的,你可以看到现在我得到了2016和2017年的数据,并且我能够准确地得到我想要的东西。这很棒。

再次强调,我正在进行“分块”处理。我减少了我的请求,这样大型语言模型就不会因为同时处理太多不同的请求而不堪重负。这15款看起来是正确的。

现在我可以做的是,将你提供的内容更新为JSON格式,以便我能在应用程序中使用。

可以随意包含从我原始粘贴的CSV数据中提取的任何其他额外数据。

通过这样做,你可以看到现在它正在回溯我最初粘贴的内容,然后只找出我想要的这些特定内容,并以JSON格式呈现。这正是我所寻找的。

这种提出非常小的请求或控制需要大型语言模型处理的信息量的方式,是确保我能准确获得想要结果而不让模型不堪重负的好方法。

现在这会继续,你可以看到在这里它停止了,因为它开始变得非常冗长。我当然希望它继续生成,因为我非常感兴趣。但现在它开始产生负担了,因为你可以看到这里出现了2008年的数据,这并不好。

所以我开始遇到麻烦了,因为这太多了。

那么,我可以做的是,实际上到这里来。

复制这段代码,然后说:从这个JSON文件中移除任何不是2015年或更新年份的葡萄酒。

然后我会粘贴它生成的代码,并等待它完成。

当然,它会遍历并开始修剪,最终给我我想要的精确结果。

这只是一个与模型来回沟通、试图获得正确答案的过程。


总结

本节课中,我们一起学习了如何通过“任务分解”策略与大型语言模型有效协作。核心要点是:不要一次性向模型提出过于复杂或信息量过大的请求。相反,应将目标拆解为一系列清晰、具体的小步骤,例如先筛选数据范围,再转换格式,最后进行精炼。通过这种迭代和分步的交互方式,我们可以更可靠地引导模型输出精确、符合要求的结果,同时避免模型因信息过载而产生错误或不相关的输出。记住,与AI合作的关键在于清晰的指令和循序渐进的任务规划。

大型语言模型实践:第2章:使用思维链技术 🧠

在本节课中,我们将学习一种名为“思维链”的提示技术。这种技术能引导大型语言模型以逐步推理的方式生成回答,清晰地展示其得出结论的思考过程。

上一节我们介绍了提示工程的基本概念,本节中我们来看看一种更结构化的提示方法。

什么是思维链?

思维链是一种在提示中使用的技术。它允许大型语言模型尝试以逐步的方式回应,并试图复述导致特定结果的准确步骤。

示例对比:常规提示 vs. 思维链提示

为了理解其效果,我们通过一个实际案例来对比两种提示方式。本例不使用常见的数学问题,而采用一个更贴近生活的场景。

场景描述:
一位高水平运动员每周训练17次,每次不超过2小时。该运动员在尝试以100%速度完成5组150米跑时,遭遇了股四头肌撕裂。此时已非休赛期,比赛日益临近。

常规提示的回应

使用常规提示时,模型的回应会列出几个要点,指出一些可能导致受伤的因素。

以下是模型可能给出的要点列表:

  • 训练过度
  • 强度与频率问题
  • 热身不足
  • 肌肉不平衡

思维链提示的回应

现在,我们改用思维链提示。唯一的区别是在提示语末尾添加了“让我们一步步思考”这句话。

通过添加这个指令,模型的回应模式发生了变化。它首先会声明自己并非医疗专业人士,只能提供一般性见解,并强调运动员咨询专业医疗人员至关重要。

接着,模型会以枚举的方式逐步分析:

  • 首先考虑训练量:每周17次可能属于过度训练。
  • 其次分析训练强度:以100%速度进行冲刺训练强度极高。
  • 然后评估准备活动:高强度训练前热身不足可能增加风险。
  • 接着探讨肌肉状况:肌肉不平衡或疲劳可能导致受伤。
  • 最后再次总结,建议寻求专业医疗建议。

思维链技术的价值

虽然两种方式得到的答案相似,但通过添加“让我们一步步思考”这个思维链指令,我们能够引导模型以特定的方式回应。这种方式揭示了大型语言模型用于得出潜在结论的思考链条。

在以下情况中,您可以考虑使用此技术:

  • 当您获得的答案不够充分时。
  • 当您想尝试其他方法时。
  • 当问题涉及多方面事实,获得一个分解式的分析会非常有帮助。

本节课中我们一起学习了思维链提示技术。通过简单地添加“让我们一步步思考”这样的指令,我们可以引导模型进行更逐步、更结构化的推理,从而使思考过程更加透明,有时也能得到更细致的分析结果。这是一种在常规提示效果不佳时值得尝试的有效技巧。

大型语言模型实践:P38:其他有用的提示技术 🧠

在本节课中,我们将学习两种能有效提升提示效果的高级技术。这些技巧能帮助你更精准地从大型语言模型中获取所需信息,尤其是在处理复杂或长篇内容时。

技巧一:先给指令,后提供内容

上一节我们介绍了如何构建清晰的指令。本节中,我们来看看一种更优的实践:将指令与待处理的内容分开发送。这种方法尤其适用于你有一段很长的文本(例如代码)需要模型分析时。

其核心思想是:先向模型清晰地说明任务和要求,然后再粘贴具体内容。这样做可以避免模型在理解冗长内容时分心,从而更专注于你设定的任务。

以下是具体操作步骤:

  1. 发送初始指令:首先,向模型发送一个不包含具体内容的纯指令。例如:

    我需要你帮我处理一段代码的几个问题。我稍后会粘贴代码。请先准备好接收代码并提供改进建议。

  2. 等待模型确认:模型通常会回复表示已准备好,例如“好的,请分享你的代码”。

  3. 发送实际内容:接着,将你需要处理的代码或文本发送给模型。

示例流程

用户:我需要你帮我分析并改进一段Python代码的质量。我稍后会粘贴代码。
AI:好的,请提供你的Python代码,我会进行分析。
用户:(粘贴大段Python代码)
AI:(根据初始指令,提供关于添加文档字符串、错误处理、命名规范等改进建议)

这种方法能确保模型在接触复杂内容前,已明确理解你的核心诉求。

技巧二:首尾呼应,强调指令

当你的指令比较复杂,或者模型在生成长篇回答时容易偏离主题,可以采用“首尾呼应”法。这个技巧是指,在提示的开头和结尾都重申你的核心要求。

这利用了模型对提示开头和结尾部分注意力更高的特性。通过重复关键指令,可以强化模型的记忆,使其输出更贴合你的要求。

以下是构建此类提示的要点:

  1. 开头明确任务:清晰陈述首要任务。
  2. 中间提供上下文:详细说明具体要求、约束条件或背景信息。
  3. 结尾重申任务:用简洁的话再次强调核心要求。

示例提示结构

【开头】请为我接下来粘贴的代码生成5个单元测试。
【中间】代码将使用Pytest框架。请假设依赖已安装,环境就绪。测试需要颗粒度细,失败时应有准确的错误信息,并且每个测试都要有说明其目的的注释。
【结尾】请根据以上要求,生成5个单元测试。

代码示例(指令中描述的目标)

# 假设这是用户提供的代码
def calculate_average(numbers):
    return sum(numbers) / len(numbers)

# 模型根据“首尾呼应”的提示,应生成类似如下的测试代码:
import pytest

def test_calculate_average_with_positive_numbers():
    """测试使用正数列表计算平均值"""
    assert calculate_average([1, 2, 3, 4, 5]) == 3.0

def test_calculate_average_with_single_number():
    """测试使用单元素列表计算平均值"""
    assert calculate_average([5]) == 5.0

def test_calculate_average_with_negative_numbers():
    """测试使用负数列表计算平均值"""
    assert calculate_average([-1, -2, -3]) == -2.0

def test_calculate_average_returns_float():
    """测试返回值是否为浮点数"""
    result = calculate_average([1, 2])
    assert isinstance(result, float)

def test_calculate_average_with_empty_list_raises_error():
    """测试空列表输入是否引发ZeroDivisionError"""
    with pytest.raises(ZeroDivisionError):
        calculate_average([])

通过这种方式,即使指令细节很多,模型也能更可靠地产出符合你预期的结果。


本节课中我们一起学习了两种实用的高级提示技术:“先指令后内容”“首尾呼应强调”。掌握这些技巧能让你在与大型语言模型交互时获得更准确、更有用的输出,特别是在处理代码分析、长文本生成等复杂任务时。请在实践中灵活运用它们。

大型语言模型实践:1.2:总结与核心技巧 🧠

在本节课中,我们将回顾并总结之前探讨的大型语言模型(LLM)的局限性,并学习几种关键的提示词(Prompt)技巧,以帮助我们获得更优的模型响应。

上一节我们介绍了大型语言模型在处理复杂任务时可能遇到的上下文限制。本节中,我们来看看如何通过特定的提示策略来引导模型,从而克服这些挑战。

核心发现与挑战

我们观察到了模型在上下文长度上的限制。当我们要求模型完成的任务超出其处理能力时,它无法给出完整的答案。这本身是一个有价值的发现,因为它让我们直观地理解了模型的边界所在。

提升响应的关键技巧

为了获得更好的结果,我们探索并应用了以下几种提示词技巧:

以下是三种有效的策略:

  1. 思维链(Chain of Thought)引导:通过指令 请逐步思考请分步骤进行,引导模型将复杂问题分解为更小的、连续的推理步骤。
  2. 任务分解:将庞大或复杂的请求拆分成多个较小的、定义清晰的任务,逐一提交给模型处理。
  3. 首尾强调法:在提示词的开头明确陈述核心指令,在结尾处再次重申关键要求或期望的输出格式。这种方法在交互内容变得复杂时尤为有效。

通过结合使用这些技巧,尤其是“首尾强调法”,我们能够从大型语言模型中获得显著更好的响应质量,特别是在处理复杂任务时。


本节课中我们一起学习了大型语言模型的局限性,并掌握了三种实用的提示词技巧:思维链引导、任务分解和首尾强调法。运用这些策略,可以更有效地引导模型,从而在复杂场景下获得更准确、更可靠的输出结果。

大型语言模型实践:第7章:生成式AI应用深入解析

在本章中,我们将深入探讨生成式AI的实际应用。我们将了解如何构建不同类型的生成式AI应用,分析基于API和嵌入式模型的应用架构,并探讨多模态应用以及开发过程中可能遇到的挑战。

概述

上一节我们介绍了大型语言模型的基础概念。本节中,我们将具体看看如何将这些模型应用于实际场景,构建出功能各异的生成式AI应用程序。

基于API的应用架构

首先,我们来看一种常见的构建方式:基于API的应用。这类应用通过调用外部服务提供商(如OpenAI、Azure AI等)提供的API来访问大型语言模型。

以下是构建一个基于API的生成式AI应用通常包含的核心组件:

  1. 用户界面:用户与应用交互的入口,可以是网页、移动应用或聊天界面。
  2. 应用后端服务器:处理业务逻辑,接收用户输入,并负责与AI模型API通信。
  3. 外部LLM API:由第三方提供的模型服务端点,应用通过发送请求并接收文本来利用其能力。
  4. 提示词工程模块:负责将用户输入构造成有效的指令(即提示词),以引导模型生成期望的输出。

其工作流程的核心代码逻辑通常如下所示:

# 伪代码示例:调用LLM API
user_input = get_user_input()
prompt = construct_prompt(user_input)
api_response = call_llm_api(prompt, api_key)
final_output = process_response(api_response)
display_output(final_output)

嵌入式模型应用

接下来,我们看看另一种架构:嵌入式模型应用。与基于API的方式不同,这类应用将模型直接集成或“嵌入”到应用自身的部署环境中。

选择嵌入式模型主要基于以下考虑:

  • 数据隐私与安全:敏感数据无需离开本地环境,降低了泄露风险。
  • 网络延迟与可用性:不依赖外部网络,响应速度可能更快,且不受服务商API可用性影响。
  • 定制化与微调:可以对模型进行更深度的定制,使其更贴合特定领域的需求。
  • 长期成本:对于高频调用场景,可能比按次付费的API更具成本效益。

当然,这种方式也带来一些挑战:

  • 基础设施要求:需要强大的计算资源(如GPU)来运行模型。
  • 部署与维护复杂性:需要团队具备模型部署、更新和运维的能力。
  • 初始成本:硬件投入和模型许可可能带来较高的前期成本。

多模态应用探索

除了纯文本模型,生成式AI正朝着多模态方向发展。多模态应用能够处理和生成多种类型的数据。

以下是多模态应用的几个典型方向:

  1. 文生图:根据文本描述生成对应图像。
  2. 图生文:分析图像内容并生成描述、标题或回答相关问题。
  3. 语音交互:结合自动语音识别和文本转语音技术,实现语音对话助手。
  4. 视频理解与生成:对视频内容进行摘要,或根据脚本生成视频片段。

应用开发中的挑战与要点

在构建生成式AI应用时,我们会遇到一些共通的挑战。了解这些要点有助于更好地设计和规划项目。

开发过程中需要特别关注以下几个方面:

  • 提示词设计与优化:模型输出质量高度依赖提示词,需要精心设计和持续迭代。
  • 输出结果的不可预测性:模型生成的内容可能存在偏差、错误或“幻觉”(即生成看似合理但不真实的信息),需要设计校验和过滤机制。
  • 上下文长度限制:模型一次性能处理的文本量有限,对于长文档或复杂对话需要采用分段、摘要等策略。
  • 成本管理与优化:API调用费用或自有算力成本需要监控,通过缓存、结果复用等方式进行优化。
  • 伦理与负责任AI:需考虑生成内容的偏见、有害性及版权问题,并建立相应的内容审核和使用准则。

总结

本节课中,我们一起学习了生成式AI应用的多种构建方式。我们分析了基于API和嵌入式模型这两种主流架构的组成与优劣,探索了多模态应用的前沿方向,并总结了在实际开发中可能面临的主要挑战与核心考量点。理解这些内容,是着手设计和实现自己生成式AI项目的重要基础。

大型语言模型实践:第1章:生成式人工智能应用的常见类型 🧠

在本节课中,我们将学习生成式人工智能(Generative AI)在现实世界中的几种常见应用类型。我们将从最流行的文本聊天应用开始,逐步扩展到其他领域,了解生成式AI如何融入我们的日常工作与生活。


基于聊天的应用 💬

上一节我们介绍了课程概述,本节中我们来看看生成式AI最广为人知的应用形式:基于聊天的应用。这类应用的核心是用户与大型语言模型进行对话式的交互反馈循环。

以下是几种常见的聊天应用场景:

  • 通用聊天机器人:例如ChatGPT,它通过与用户进行文本对话来提供信息、解答问题或协助创作,这类应用的普及极大地推动了生成式AI的发展。
  • 客户服务聊天机器人:过去,许多客服机器人的体验可能很笨拙,无法准确理解用户的具体问题(例如订单延迟),反而提供不相关的回答(例如推荐新产品),导致用户体验不佳。
  • 集成式对话界面:如今,各种具备对话功能的应用程序越来越普遍,它们将大型语言模型的能力嵌入到产品中,提供更自然的交互方式。

超越聊天:创意与内容生成 🎨

除了聊天应用,生成式AI在创意和内容生成领域也展现出巨大潜力。艺术家和创作者们正在利用它来生成图像、创作音乐甚至制作视频。

以下是生成式AI在内容创作方面的应用:

  • 图像生成:根据文本描述自动创建视觉图像。
  • 音视频生成:辅助或自动生成音乐、语音和视频内容。
  • 多模态融合:结合文本、图像、音频等多种形式进行综合性内容创作。

融入日常工作的生产力工具 ⚙️

如果我们进一步思考,生成式AI的潜力远不止于聊天和创意。它正变得越来越具有生产力,并开始与我们的日常任务紧密结合。

以下是生成式AI提升工作效率的示例:

  • 邮件撰写:辅助或自动生成电子邮件草稿。
  • 会议纪要摘要:在会议结束后自动生成内容摘要。
  • 信息整合与创作:基于多个不同来源的信息,整合并生成所需的文档或报告。

总结与展望 🔮

本节课中,我们一起学习了生成式人工智能的几种常见应用类型。我们从基于聊天的应用开始,看到了它从通用对话到专业客服的演进。接着,我们探讨了其在创意与内容生成领域的突破,如图像和音视频创作。最后,我们了解到生成式AI正作为生产力工具融入日常工作,例如处理邮件和会议摘要。

我们可以预见,未来会有更多突破,生成式AI将更深入地融合到日常任务中,尤其是那些需要总结、整合与创造性输出的工作。我们的工具将越来越多地通过生成式AI得到增强,与它的交互也会变得更加日常化。

大型语言模型实践:P42:基于API的应用概览 🚀

在本节课中,我们将要学习什么是基于API的应用程序,特别是在讨论生成式AI时。我们将了解这种架构如何工作,并通过具体的代码示例来理解其核心概念。


基于API的应用程序正变得非常普遍,这不仅适用于交互式前端,也适用于后端服务。接下来,我们将解释这些含义。

这里有一个将通过HTTP工作的应用程序,它是一个HTTP API。这意味着,当我们的应用程序中的任何事物或用户需要交互时,可能会通过URL使用HTTP进行连接,发送一些信息并检索一些信息。这个过程将通过使用大型语言模型得到增强。

让我们快速浏览一下。你可以看到,具体到OpenAI,它提供了定义模型来源的能力。这里显示它正在与Azure OpenAI通信,并且API类型是Azure。这些是细节,我们尚未深入探讨其具体含义,但本质上,我们讨论的是这个API应用程序将向此处显示的URL发送信息。这意味着,大型语言模型并不存在于这个应用程序内部。


让我们看看代码。这是一个高度简化的单文件示例。我们来看一个更简单的例子。

以下是42行的Python代码。我们不必被Python代码的具体细节分散注意力,但你可以在这里看到我的意思:你在这个代码中看到任何地方定义了大型语言模型吗?没有任何定义。所有这些代码只是加载文件,传递密钥所需的内容,并尝试远程连接到一个OpenAI实例,连接到另一个位于别处的服务器,以帮助我们发送和处理信息。

以下是代码中的关键部分:

# 连接到远程OpenAI服务
client = OpenAI(api_key=api_key)
# 发送提示并获取响应
response = client.chat.completions.create(...)

这里有一些Python服务或辅助函数,将帮助我们连接。当我提到连接位置和密钥时,我们将能够进行身份验证。

你可以看到,我需要理解制作一杯出色浓缩咖啡所涉及的变量。因此,我发送一个提示。当我收到回复时,我将打印并返回该回复。这是一种API类型的交互,我们将信息发送到远程服务器,并从远程接收响应。目前,这就像一个命令行工具,但它完全可以是一个HTTP服务。


我想展示的另一个例子不是Python Web应用程序,而是使用Rust的示例。

如果我进入SRC目录并展示代码,这也会相当简化。你可以看到,我们正在本地连接到一个大型语言模型应用程序。同样,我们使用HTTP,使用这个特定的URL远程连接到另一个将提供大型语言模型服务的应用程序。

以下是连接的核心部分:

// 使用HTTP客户端连接到LLM服务
let client = reqwest::Client::new();
let res = client.post("http://localhost:11434/api/generate")
    .json(&request_body)
    .send()
    .await?;

还有其他类型的应用程序在内部托管模型,即模型将在代码中的某个地方定义,然后应用程序将服务该模型并与之交互。这种关注点分离的架构(在这个例子中是Rust,之前是Python)非常棒,因为它允许你进行扩展,允许多个不同的应用程序与大型语言模型通信。


以上是两个很好的例子,展示了当你尝试创建基于生成式AI的应用程序时,可以考虑与大型语言模型交互的方式。

本节课中我们一起学习了基于API的应用程序架构。我们了解到,在这种模式下,应用程序通过HTTP等协议与远程的大型语言模型服务通信,而不是在本地托管模型。这种分离关注点的设计提高了系统的可扩展性和灵活性。我们通过Python和Rust的简化代码示例,具体看到了如何实现这种远程API调用。

大型语言模型实践:1.3:嵌入式模型应用概览 🧩

在本节课中,我们将要学习什么是嵌入式模型应用。我们将通过一个具体的Python应用示例,来理解模型如何被“嵌入”到应用程序内部运行,并探讨这种架构的特点和考量。


什么是嵌入式模型应用?

上一节我们介绍了大型语言模型的基本概念,本节中我们来看看嵌入式模型应用的含义。嵌入式模型应用意味着大型语言模型本身被包含在应用程序的内部。

具体来说,模型文件将与应用程序代码一同部署和运行,而不是通过远程API调用外部服务。

一个Python应用示例

为了理解嵌入式模型,我们来看一个示例代码仓库。以下是该应用的核心部分:

# 这是一个非常古老的模型,GPT-2
# 可以将其视为现代GPT-4的“曾祖父”
generator = pipeline('text-generation', model='gpt2')

这段代码使用Hugging Face的transformers库,通过pipeline函数动态加载gpt2模型。当应用运行时,这个模型会被下载并集成到应用内部。

以下是该应用API端点的关键设置:

  • API路径/generate
  • 输入限制:最大长度为35个token
  • 输出:返回单个生成序列

这些参数是gpt2模型特有的配置。代码中的generator对象负责与模型进行交互。

运行嵌入式模型应用

现在,让我们看看运行这个应用时会发生什么。在终端中,我们使用uvicorn服务器来启动这个HTTP应用。

运行命令后,可以观察到以下过程:

  1. 系统开始下载模型文件,总计约475MB。
  2. 模型被下载到本地系统,并加载到应用程序的内存中。
  3. 应用成功启动,在本地8000端口提供服务。

通过浏览器访问http://localhost:8000/docs,我们可以与应用的API进行交互。例如,输入“Python applications are”,模型会生成后续文本,如“available in the next part we will look at installing engineX and install it in our test environment”。

终端中显示的所有交互日志,都基于已下载并运行在应用内部的475MB模型文件。这就是“模型与应用程序共存”的含义。

嵌入式模型的考量

这种架构将模型和应用紧密耦合,带来了特定的优缺点。

以下是采用嵌入式模型架构时需要考虑的几个关键点:

  • 关注点分离:这类应用通常不允许将模型服务与业务逻辑清晰分离。
  • 资源占用:每次部署新的应用实例,都需要重新下载模型文件,导致部署包体积庞大。
  • 基础设施:运行应用的机器需要具备足够的存储空间和内存来容纳模型文件,可能成为资源密集型的重型服务。

本节课中我们一起学习了嵌入式模型应用的概念。我们通过一个实际的Python示例,看到了模型如何被直接集成到应用代码中运行,并理解了这种架构带来的便利性与挑战,例如部署便捷性与资源开销之间的权衡。在设计和开发大型语言模型或生成式AI应用时,需要根据具体场景权衡是否采用嵌入式方案。

大型语言模型实践:P44:什么是多模型应用 🧠

在本节课中,我们将要学习多模型应用的基本概念、工作原理及其优势。多模型应用通过将用户请求路由到不同的、高度专业化的机器学习模型来处理复杂任务,从而提升效率和效果。


如果你从未接触过多模型应用,这个概念可能有些难以理解。特别是当你尝试扩展应用或思考如何扩展时。现在,让我们揭开它的神秘面纱,从一个非常基础的例子开始。

多模型应用的基本工作流程

首先,用户会发起一个提示。这个提示会发送到一个框架。框架接收到这个提示后,会根据提示的内容,决定将请求重定向到哪个机器学习模型。

例如,假设你有一个应用,它可以处理数学问题、编程问题或翻译任务。翻译实际上是生成式AI一个很好的例子。框架会根据输入内容来决定使用哪个模型。

以下是其工作流程的分解:

  1. 用户发起提示:流程从用户输入开始。
  2. 框架接收并路由:框架分析提示,并根据其内容(例如,是编程问题还是翻译请求)决定将请求发送给哪个专用模型。
  3. 模型处理并返回:被选中的模型处理请求,生成响应。
  4. 响应返回用户:响应通过框架返回给用户。

例如,如果是一个编程问题,框架会将其路由到专门的代码生成模型。该模型计算出正确答案后,通过框架将响应返回给用户。

有时,问题可能不是关于编程的,而是关于翻译的。我们可以有许多专门用于翻译的不同模型。

为何要使用多模型架构?

那么,为什么实现这样的架构是有用或有意义的呢?

原因在于这类专用模型非常高效。当模型专业化时,会带来几个关键优势:

  • 模型更小:专用模型通常体积更小。对于机器学习模型而言,更小通常更好,因为这意味着消耗的计算资源更少,在扩展和优化时更高效。
  • 响应质量更高:如果模型专门针对某个领域(如这里的数学或编程)进行训练,那么它在该领域的表现会好得多。你可以通过使用专用模型获得更好的体验。

我们可以这样理解:一个通才模型就像一个人,知道很多不同学科的知识,广度很大,但对任何特定领域的知识都缺乏深度。

从通用到专用:权衡与收益

随着我们从通用模型转向非常专用的模型,我们会获得一些收益,也面临一些挑战。这可以通过模型大小和有效性之间的关系来理解。

模型大小 vs. 有效性

  • 通用模型:非常。它试图成为许多不同领域的“专家”,因此必须涵盖所有相关知识,导致模型体积庞大。
  • 专用模型:更加。因为其专业性允许模型只专注于与其工作领域相关的重要部分。例如,一个数学模型只需要用数学知识训练,而无需包含小说或奇幻文学的自然语言信息,因此模型可以高度精简。

在有效性方面:

  • 当模型高度专用时,其有效性会高得多
  • 当模型更通用时,其有效性会降低

例如,一个专门用于生成代码的模型在协助编程语言方面会非常有效。但如果你向这个专用模型询问与编码无关的问题,它的回答就不会很好,有效性会很低。

这些都是我们在审视多模型架构时需要考虑的因素。

框架与模型协作

我特别想回到框架和提示的概念,看看机器学习框架如何与后端各种专用模型对话并生成响应。

在某些情况下,我们还见过一些实现,其中不同的模型可以相互对话,共同构建一个更完善的响应。这是一种更复杂、更深入的设置和架构。

但在最基本的层面上,根据你想要实现的目标来部署多个不同的模型,这种做法是有意义的,也值得理解。

这样,每当你需要处理大规模的问题时,你就有能力探索在聊天或生成式AI类应用的后端使用多模型架构的想法。


总结

本节课中,我们一起学习了多模型应用的核心概念。我们了解到,多模型应用通过一个智能框架将用户查询路由到后端的多个专用机器学习模型。这种架构的主要优势在于专用模型更小、更高效,且在特定任务上表现更出色。虽然通用模型覆盖面广,但专用模型在深度和效率上更具优势。理解这一架构有助于我们在构建需要处理多种复杂任务的可扩展AI应用时,做出更明智的设计决策。

大型语言模型实践:2.3:生成式AI应用类型总结 🧠

在本节课中,我们将总结生成式AI的常见应用类型,并深入探讨这些应用的具体形态。理解这些架构的差异和挑战,对于您未来构建自己的AI应用或做出技术选型将非常有帮助。

上一节我们介绍了多种生成式AI的应用架构,本节中我们来看看这些架构的核心要点与选择考量。

应用架构回顾

我们看到了多种不同的应用架构类型,其中多模态应用尤其值得关注。当您处理高度特定的模型时,这类应用特别有趣。您可能希望实现这类特定模型,因为它们更小、交互更快,并且所需资源更少。

例如,它们对GPU等计算资源的需求更低。这使得您的应用程序变得更加敏捷:部署更快、交互更容易、更轻量。因为它们不需要海量的资源来运行,也不需要庞大的存储空间来启动整个应用。

基于API架构的亮点与挑战

基于API的方法,即将请求卸载到远程模型,无疑也是一种有趣的方案。理解所有这些类型的模型应用(或基于大语言模型的应用)之间的差异与挑战,在您向前推进并尝试做出决策、选择发展方向时,将会非常有用。

以下是基于不同架构的核心特点对比:

  • 特定/轻量模型:公式表示为 模型大小小 & 资源需求低。其优势在于部署速度快交互延迟低成本较低
  • 多模态应用:代码可描述为 处理(文本, 图像, 音频)。这类应用能处理多种输入类型,功能丰富,但集成复杂度较高。
  • 基于API的远程模型:其工作流程为 本地应用 -> API请求 -> 远程LLM -> 返回结果。优点在于无需管理底层模型基础设施,但依赖于网络并可能产生持续的使用成本。

总结

本节课中,我们一起学习了生成式AI的不同应用架构类型及其特点。我们探讨了轻量级特定模型的速度与效率优势,多模态应用的强大功能,以及基于API方案的便利性与考量。理解这些选项的优劣,将帮助您根据自身需求——无论是追求快速部署、低成本运行还是处理复杂输入——来做出更明智的技术选择,从而成功构建您自己的AI应用程序。

大型语言模型实践:第8章:检索增强生成(RAG)简介 🧠

在本节课中,我们将学习一个名为“检索增强生成”的核心概念。这是一种让大型语言模型能够访问其训练数据之外的新信息或近期信息的技术,从而生成更准确、更相关的回答。


检索增强生成是一个初看难以理解,但一旦明白其价值就会立刻想应用的概念。它的实现有一定技巧性,我们将探讨如何使其工作,并让你能在自己的系统中进行尝试。

检索增强生成,通常以其缩写 RAG 指代。我们将看到,这是一种让大型语言模型能够访问其训练数据之外的新数据或近期数据的方法,从而提供更好的答案。

接下来,我们将深入探讨如何管理我们想要在RAG中使用的数据,如何创建嵌入向量并使用搜索数据库,并最终将其与大型语言模型结合使用。


核心概念解析

上一节我们介绍了RAG的基本目标,本节中我们来看看它的核心工作原理。

RAG的核心思想是将信息检索与文本生成相结合。其工作流程可以概括为以下步骤:

  1. 检索:当用户提出一个问题(查询)时,系统首先从一个外部的、专门的知识库中查找与问题最相关的文档片段。
  2. 增强:将这些检索到的相关文本片段与用户的原始问题一起,组合成一个新的、信息更丰富的“提示”。
  3. 生成:将这个增强后的提示输入给大型语言模型,由模型基于这些提供的上下文信息生成最终答案。

这个过程可以用一个简化的公式表示:

最终答案 = LLM( 用户问题 + 检索到的最相关上下文 )

关键技术组件

理解了RAG的流程后,以下是实现它所需的三个关键技术组件:

  • 文档存储与处理:你需要一个包含最新或特定领域知识的外部文档库。这些文档需要被分割成更小的、语义上连贯的块(chunks),以便于检索。
  • 嵌入向量与向量数据库:这是实现高效语义检索的关键。通过嵌入模型(如text-embedding-ada-002)将每个文本块转换为一个高维向量(即嵌入向量)。所有这些向量存储在一个向量数据库(如Chroma、Pinecone、Weaviate)中。当查询到来时,同样将其转换为向量,并在数据库中进行相似度搜索(例如余弦相似度),找到最匹配的向量所对应的文本块。
  • 大型语言模型:作为最终的“大脑”,接收增强后的提示,并生成流畅、准确的回答。其提示模板通常如下所示:
prompt_template = """
请基于以下提供的上下文信息回答问题。
如果上下文信息不足以回答问题,请直接说明你不知道。

上下文信息:
{retrieved_context}

问题:{user_question}

答案:
"""

总结

本节课中我们一起学习了检索增强生成(RAG)。我们了解到,RAG通过为LLM引入外部知识源,有效解决了模型知识陈旧和产生“幻觉”的问题。其核心流程包括检索相关文档、增强原始提示,以及最终由LLM生成答案。实现RAG需要管理文档、使用嵌入向量与向量数据库进行语义搜索,并精心设计提示词来结合检索到的上下文。掌握RAG是构建更强大、更可靠AI应用的关键一步。

大型语言模型实践:1.3:什么是检索增强生成 🧠

在本节课中,我们将要学习一种名为“检索增强生成”的技术。这是一种通过结合外部知识库来提升大型语言模型回答准确性和时效性的重要方法。


检索增强生成是一种通过扩展、基于外部信息来改进结果的技术。它通常使用一个搜索数据库或搜索引擎,有时也称为向量数据库。

为了帮助理解,这里有一个很好的基础实现示例。用户提供输入,与大型语言模型的输出并行处理。通常,大型语言模型的输出与输入是一一对应的。但在RAG中,我们有一组文档,这些文档会被向量化并分割成模型可以理解的块。随后,我们可以利用这些文档来增强模型的回答。

上一节我们介绍了RAG的基本概念,本节中我们来看看它的工作原理。你可以将这个过程理解为对大型语言模型说:“嘿,大型语言模型,我要问你一个问题。”例如,询问关于美国当前的政治事件。当然,语言模型自身回答此类问题的能力是有限的,因为它可能没有使用最新的数据进行训练。

这时,数据库、搜索引擎或向量数据库就派上用场了。你可以通过它们来增强模型,使其获得最新、超级准确的信息。在处理用户请求时,你可以先查询这些文档,获取相关信息,然后再将问题和这些信息一同发送给大型语言模型。这样,模型就能同时接收到原始问题和来自文档的相关搜索结果。

以上就是我想展示的第一张示意图。另一张图来自Microsoft Learn,展示了Azure AI搜索中的检索增强生成流程。请注意,Azure AI搜索最近从“Azure认知服务搜索”更名而来,如果你熟悉旧名称,请记住这个变化。

让我们向下滚动,这张图详细展示了Azure AI搜索的组件,我们后续会深入讲解。但此刻,我想重点分析这个图表本身。

这是一个更完整的应用程序架构。请求首先进入应用程序,应用程序可能包含API、Python代码或容器来处理请求。处理流程如下:

以下是RAG在Azure中的一个典型工作流程:

  1. 用户请求首先被提交到Azure AI搜索服务。
  2. Azure AI搜索利用预先加载的大量信息,生成用于增强请求的必要响应。
  3. 这个增强后的请求随后被发送到Azure OpenAI或其他模型。
  4. 模型生成答案后,经由编排器返回给用户。

本质上,这就是RAG的核心流程。当人们讨论搜索、向量数据库或检索增强生成时,他们通常指的是类似的实现方式。其核心目标都是通过预先加载的文档来增强模型的行为,为模型提供其当前所不具备的额外信息。


本节课中我们一起学习了检索增强生成。我们了解到,RAG通过将用户查询与外部知识库(如向量数据库)检索到的相关信息相结合,再交由大型语言模型处理,从而显著提升回答的准确性和时效性。这是一种弥补模型知识局限性的强大技术。

大型语言模型实践:P48:检索增强生成应用概览 🧠

在本节课中,我们将要学习检索增强生成(RAG)的基本工作原理。我们将通过一个清晰的流程概述,了解用户查询如何通过结合向量数据库的知识来获得更准确、更具上下文的回答。

概述

检索增强生成是一种将大型语言模型与外部知识源(如向量数据库)相结合的技术。其核心目的是为模型提供训练数据之外的最新或特定领域信息,从而生成更可靠的回答。下面,我们将一步步拆解这个流程。

工作流程详解

上一节我们介绍了RAG的概念,本节中我们来看看一个具体的查询是如何在这个系统中流动的。

整个过程始于用户的查询。通常,查询会直接发送给应用框架,然后由框架传递给机器学习模型(如大型语言模型)并返回结果。但在RAG架构中,流程有所不同。

第一步:查询接收与路由

用户提出一个查询。这个查询首先被发送到应用框架。这个框架可以是LangChain、Semantic Kernel等专门工具,也可以是一个直接调用API的普通应用程序。

第二步:转向向量数据库

框架接收到查询后,并不会直接将其发送给大型语言模型。相反,它会先将查询发送给向量数据库

向量数据库将针对这个查询执行一次搜索。例如,假设用户的查询是“昨天的天气如何?”。向量数据库中可能存储了昨天的天气数据,而这些信息是大型语言模型在训练时未曾见过的。

第三步:构建增强上下文

搜索完成后,向量数据库将找到的相关信息(即“答案”)返回给应用框架,而不是直接给用户。

此时,框架会执行一个关键步骤:它将原始的用户查询和从向量数据库获得的答案结合起来,构建成一个增强的上下文

第四步:语言模型加工与回答

这个包含了问题和已知答案的增强上下文,随后被发送给大型语言模型。

可以这样理解:这就像一个学生在考试时拿到了“小抄”。大型语言模型的任务不再是凭空生成答案,而是基于已有的“标准答案”(即上下文),以一种通顺、自然的方式组织语言,将其“包装”好。

最后,模型生成的良好格式的回答被送回框架,再由框架最终呈现给用户。

核心优势与特点

以下是RAG工作模式带来的主要好处:

  • 成本效益:为大型语言模型进行再训练的成本非常高。而向向量数据库中添加或更新文档则相对简单且成本低廉。
  • 信息实时性:模型可以获取其训练截止日期之后的最新信息。
  • 准确性提升:通过提供确切的参考信息,减少了模型“幻觉”(即编造信息)的可能性。
  • 领域适应性:可以轻松地为模型注入特定领域(如公司内部文档、专业资料)的知识。

总结

本节课中我们一起学习了检索增强生成(RAG)的应用概览。我们看到了一个用户查询如何通过框架被路由到向量数据库获取额外知识,然后这些知识与原始查询结合形成增强上下文,最终由大型语言模型加工成流畅的回答。这种架构巧妙地结合了数据库的精确检索能力和语言模型的强大生成能力。在后续课程中,我们将深入探讨如何实现向向量数据库中添加文档的具体过程。

大型语言模型实践:第49课:管理检索增强生成的数据 🗃️

在本节课中,我们将学习如何为构建一个检索增强生成应用准备和管理数据。我们将从一个包含全球葡萄酒信息的CSV文件开始,使用Python的pandas库加载和处理数据,并将其转换为适合后续向量数据库使用的格式。

数据概览与加载

首先,我们需要理解将要使用的数据。数据是一个CSV文件,包含了来自世界各地的葡萄酒信息。具体来说,它包含以下列:name(葡萄酒名称)、region(产区)、variety(葡萄品种)、rating(评分)和notes(品酒笔记)。

例如,产区可能是“纳帕谷”。数据本身可以是任何内容,但这里我们有一个格式良好的CSV文件。我们将使用这些列来创建我们的数据集,该数据集将用于后续的应用开发。

我们将使用Python,特别是pandas库,来与这个逗号分隔值文件进行交互。文件位于项目仓库中。首先确保环境准备就绪,然后导入pandas。

import pandas as pd

现在,从项目根目录加载这个CSV文件。

df = pd.read_csv(‘wines.csv’)

运行代码后,我们可以看到数据的表示形式,包括名称、产区、品种、评分和笔记。这个数据集有很多条目。

len(df)

数据显示我们有1365个条目。观察评分列,其范围通常从80多分到100分。你可以看到有很多96分和97分的记录,这是因为我们从一个更大的数据集中筛选出了评分在96分及以上的子集。

数据转换与格式化

我们已经将数据加载到pandas DataFrame中。接下来,我们将创建一个字典列表。我将展示这样做的原因。

records = df.to_dict(‘records’)

运行这行代码需要一点时间,之后我们将得到数据的字典列表表示形式。

这个操作将在Python中创建一个字典列表。每个字典的键是列名(name, region, variety, rating, notes),对应的值是该行葡萄酒的信息。

我们为每一款葡萄酒都进行这个操作,是为了后续能将其加载到向量数据库中。我们将使用这种格式,以便在创建嵌入向量、对所有输入进行分词时,能够告诉向量数据库:“这是我们的数据,你需要以这种方式处理它,以便我们后续能更成功地搜索它。”

本质上,这就是我们所做的步骤。虽然数据量很大,但步骤非常简单。只用了三四个代码单元就完成了所有数据的加载和转换。

格式选择的重要性

如果在这里没有使用‘records’参数,而是使用其他方式,格式就不会完全正确。

例如,如果不指定‘records’,索引可能会成为键,而值会是其他内容,这不是我们想要的。这就是为什么我选择使用‘records’参数。重新运行正确的代码后,我们得到了完全符合向量数据库需求的格式。

总结

本节课中,我们一起学习了为检索增强生成应用管理数据的基础步骤。我们从加载一个结构化的CSV文件开始,使用pandas库将其读入DataFrame。接着,我们将DataFrame转换为字典列表格式,这是为了后续能顺利地将数据导入向量数据库并进行高效的语义搜索。这个过程虽然涉及数据转换,但通过使用正确的工具和方法,可以变得直接而高效。

大型语言模型实践:P50:验证嵌入与搜索 🔍

在本节课中,我们将学习如何加载数据、创建向量数据库,并执行语义搜索。我们将使用Pandas处理数据,使用Sentence Transformers生成文本嵌入,并利用Qdrant构建一个内存向量数据库来存储和检索信息。


上一节我们介绍了数据处理的基本步骤,本节中我们来看看如何将处理后的数据转换为向量并存入数据库。

首先,我将重复一些步骤来加载CSV文件。

我将使用Pandas加载该文件,如下所示。我仍将对数据做一些调整,将其转换为字典格式。

此处的操作旨在确保数据中不包含“非数字”值。这意味着任何没有值的字段都将被删除。我通过这种方式有效地修剪数据集,以避免在后续序列化过程中出现问题。

运行这些代码。与之前类似,我将获取名称、地区和一些信息,共1300行数据。

现在,我将使用必要的软件来实现向量数据库搜索。我将使用Qdrant。具体来说,我需要导入以下模块:modelsQdrantClient以及sentence_transformers

我会详细解释每个部分的作用,以便你充分理解为何需要它们。

Sentence Transformers 使我们能够进行编码。编码是绝对必需的。我们将使用 all-MiniLM-L6-v2 模型,它会自动在本地下载机器学习模型,以便我们进行分词和生成嵌入向量,从而存入向量数据库。这是后续与大型语言模型对话所必需的。

接着,我们将使用QdrantClient。这个客户端是我们与数据库通信所需的工具。它代表从这里启动的数据库实例。这个导入项使我们能够与该数据库对话。一个很酷的功能是,我们可以使用内存数据库,无需创建基于文件或网络的数据库。这对于示例非常方便,也是我今天选择它来使演示更具吸引力的原因。

接下来,我将创建一个集合。这个集合将存在于数据库中。当我传入特定参数时,我们将设定“距离”度量,其基本作用是进行比较,以找出搜索词与存储数据中哪些短语更接近。

我将创建配置,实际上是集合的向量配置。向量大小由我们使用的模型决定,这里就是确保尺寸正确。我使用余弦距离。完成这些后,我就能创建索引,并将所有内容上传到我们的向量数据库中。

我们将集合命名为 tab_wines。我们将把“品酒笔记”作为向量传入。因此,我们需要对其进行编码,编码结果将作为向量。其余数据将作为元数据存入“载荷”中。我们将遍历所有数据,创建索引文档并进行枚举。运行此代码,这需要一些时间,因为我们要处理大约1300条记录。我将运行它,并等待完成。

在我的系统上,这花了54秒,时间相当长。我建议在演示时减少条目数量以节省时间,但为了完成演示,我不得不等待这54秒。

现在完成了。接下来是关键时刻:我们将执行搜索。为此,我们将使用这里的搜索函数。我们将指定我们的集合,并传入查询。查询同样会经过编码器处理。我们将结果限制为3条,然后查看返回的内容。

我们得到了“99分,来自纳帕谷的赤霞珠,带有碳烤味”等几条结果。你可以看到,向量数据库正在使用“品酒笔记”字段。它确保捕获的正是这里的“笔记”内容,并以此进行搜索,效果相当不错。

但我们也可以尝试改变搜索词,例如搜索“来自阿根廷门多萨的马尔贝克葡萄酒”。

再次运行搜索,这次会得到完全不同的结果,比如“卡氏家族艾拉莫马尔贝克”,这是一款非常出色的葡萄酒。现在你可以看到,这些结果被返回了。

那么,这为何有用且相关呢?因为我们配置的这个向量数据库能够理解我们的自然语言。后续,结合大型语言模型的自然语言处理能力,我们可以获得相关结果,从而增强大型语言模型的响应质量。


本节课中,我们一起学习了从加载数据到构建内存向量数据库并进行语义搜索的完整流程。我们了解了如何使用Sentence Transformers生成文本嵌入,以及如何利用Qdrant客户端配置集合、上传数据并执行基于余弦相似度的搜索。这个过程是将非结构化文本数据转化为机器可理解、可检索格式的关键步骤,为后续集成大型语言模型、实现更智能的问答和内容生成奠定了基础。

大型语言模型实践:P51:将检索增强生成与大型语言模型结合使用 🍷

在本节课中,我们将学习如何将检索增强生成技术应用于大型语言模型。具体来说,我们将把一份葡萄酒数据集导入向量数据库,然后让LLM基于数据库中的信息来生成更准确、更有意义的回答。


上一节我们介绍了向量数据库的基本操作,本节中我们来看看如何将其与大型语言模型结合,构建一个能提供专业建议的智能应用。

首先,我们需要将葡萄酒的CSV数据导入数据库。我们将使用Pandas库来处理数据。

import pandas as pd

为了提升处理速度,我们将数据条目限制为700条。运行以下代码来完成数据加载。

接着,我们将使用Quadrant客户端。需要再次导入一些必要的工具。

# 示例:导入必要的库和初始化客户端
from some_module import QuadrantClient, Encoder

然后,再次运行编码器,并创建向量数据库客户端。

我们将创建一个新的集合来存储数据。这次不是存储书籍,而是存储一些葡萄酒信息,我们将这个集合命名为“top_wines”。运行代码以创建集合,所有设置与之前类似。

创建完成后,我们将把所有数据上传到“top_wines”集合中。这个过程需要几秒钟,因为我们已将数据缩减到700条记录。

等待上传完成。完成后,我们将通过OpenAI API(或兼容的本地模型)来使用这些数据,从而获得有意义的查询结果。

上传已完成,耗时34秒。即使只处理700条记录,在我的机器上也花费了一些时间。现在,我们向下滚动到底部,开始进行查询。

我们将定义一个查询提示。例如:“suggest me an amazing Malbec wine from Argentina”(给我推荐一款出色的阿根廷马尔贝克葡萄酒)。我们将此提示定义为一个变量。

接下来,我们将在数据库中搜索相关信息。我们将获取一些搜索结果。

为了使过程更简便,我们将所有搜索结果应用到一个变量中。然后,连接到OpenAI(或本地模型,如Llamafile)。这里的关键是你可以连接到ChatGPT、OpenAI API或任何兼容的API服务。

在本例中,我运行一个本地模型,不需要API密钥。我们有以下提示设置:

  • 系统提示:你是一个聊天机器人,一名葡萄酒专家。你的首要任务是帮助引导用户选择出色的葡萄酒,并根据他们的请求提供指导。
  • 用户内容:我们之前定义的查询变量(“suggest me an amazing Malbec wine from Argentina”)。
  • 助理角色/内容:这将从我们数据库的搜索结果中获取。

运行查询。让我们看看大型语言模型返回了什么内容。

它回复道:“I suggest you try the Bodega Colomé Altura Máxima Malbec from Argentina. Oh, this is amazing! It has a rating of 96.”(我建议您尝试阿根廷的Bodega Colomé Altura Máxima Malbec。哦,这太棒了!它的评分是96分。)

模型利用了之前的所有上下文信息。如果我们滚动到顶部查看搜索结果,会发现第一条结果正是来自阿根廷Salta产区的一款酒,这证实了模型有效地利用了检索到的信息。


总结

本节课中我们一起学习了如何将检索增强生成与大型语言模型结合使用。我们完成了将特定数据集(葡萄酒信息)导入向量数据库,并让LLM基于该数据库的检索结果来生成准确、上下文丰富的回答。这种方法极大地增强了LLM回答的专业性和可靠性,因为它不仅依赖预训练知识,还能动态引用外部数据源。

大型语言模型实践:4:总结

在本节课中,我们将总结前面关于检索增强生成(RAG)模式的学习内容,回顾如何利用自有数据增强大型语言模型的能力。

课程概述

上一节我们介绍了如何将数据向量化并存入数据库。本节中,我们来看看整个RAG流程的总结与价值。

我们成功探索了如何将检索增强生成(RAG)与大型语言模型结合进行交互。

我们看到了如何管理数据。我特意选择了一个CSV(逗号分隔值)格式的文件,以便使用一种有趣的、在现有示例中不常见的数据格式。我们能够对该数据进行修剪、处理,并创建出特定的数据结构。

核心步骤回顾

以下是实现RAG模式的关键步骤:

  1. 数据准备:对原始CSV格式数据进行清洗和格式化处理。
  2. 创建嵌入:将处理后的文本数据转化为向量嵌入(Embeddings)。其核心是将文本 T 通过嵌入模型 E 映射为向量:E(T) -> Vector
  3. 使用向量数据库:将生成的向量存储到专门的向量数据库中,以便进行高效的相似性检索。
  4. 验证与检索:利用向量数据库检索与用户查询最相关的信息,并将其作为上下文提供给大型语言模型,从而获得更精准的回复。

模式优势总结

本节课中我们一起学习了RAG模式的强大之处。这无疑是一个非常强大的模式,如果你选择实现类似的应用,它将允许你使用自己的数据,而无需重新训练整个大型语言模型。

因此,当你创建基于聊天的应用程序时,例如使用大型语言模型的客服系统,采用RAG模式可以获得质量高得多的响应。

大型语言模型实践:P53:53_03_02_引言_9 🚀

概述

在本节课中,我们将学习如何构建一个基于云的生成式AI应用。我们将探索其核心架构,了解如何将其部署到云端,并验证其功能。课程将以Azure云平台为例,但所涉及的概念和步骤也适用于其他云服务提供商。


探索基于云的生成式AI应用架构

我们将要构建的生成式AI应用将是一个HTTP API。这意味着用户或客户端可以通过发送HTTP请求来与我们的AI模型进行交互。

上一节我们明确了应用的形式,本节中我们来看看实现这个API所需的所有组件。

以下是构建和运行此应用所需的核心组件:

  • 模型服务:托管和运行大型语言模型的核心引擎。
  • API网关/服务器:接收外部HTTP请求,并将其转发给模型服务。
  • 计算资源:在云端运行代码的虚拟服务器或容器。
  • 网络与安全配置:确保API可以被安全地访问。

设置云端组件与环境

我们将使用Azure云平台来部署我们的应用。虽然具体操作界面可能不同,但在其他云平台(如AWS、GCP)上,类似的流程和概念同样适用。

以下是主要的设置步骤:

  1. 创建或选择一个资源组,用于逻辑上组织所有相关资源。
  2. 部署一个计算服务(例如Azure Container Instances、Azure App Service或虚拟机)来托管我们的应用。
  3. 配置网络设置,如虚拟网络、安全组和公共IP地址,以允许外部访问。

部署流程与自动化

部署是指将我们开发好的应用程序代码和配置发布到云端环境,使其能够运行的过程。

一旦我们完成了代码开发,部署流程通常如下所示:

# 这是一个简化的部署命令示例
az webapp up --name my-genai-app --resource-group myResourceGroup

自动化部署(例如使用CI/CD管道)可以确保每次代码更新时,都能快速、可靠地将新版本发布到生产环境。


验证与功能测试

在应用成功部署到Azure并公开可用后,我们必须验证所有组件是否协同工作。

以下是验证步骤:

  • 检查部署状态:在Azure门户中确认所有服务都处于“正在运行”状态。
  • 测试API端点:使用工具(如curl或Postman)向我们的API发送一个测试请求。
  • 验证响应:确保API返回了预期的、由AI模型生成的响应内容。


总结

本节课中,我们一起学习了构建和部署一个云端生成式AI应用的全过程。我们从定义HTTP API开始,逐步介绍了所需的架构组件、在Azure上的设置步骤、部署流程以及最后的验证方法。掌握这些步骤是运营生产级大型语言模型应用的基础。

大型语言模型实践:P54:应用概览 🧠

在本节课中,我们将学习一个基于检索增强生成(RAG)模式的实际应用。这个应用专门为微软的Azure云平台设计,并展示了如何利用Azure OpenAI服务和Azure认知搜索来构建一个简洁、可部署的Web服务。

应用架构与工具概述

上一节我们介绍了RAG模式的基本概念,本节中我们来看看一个具体的实现。这个应用采用了容器化部署,其核心功能是处理用户查询,通过结合向量数据库检索和大型语言模型来生成回答。

以下是构建此应用所需的主要工具和库:

  • Azure Identity:用于处理与Azure服务身份验证相关的任务。
  • LangChain:一个用于简化与提示词工程和API交互的框架。
  • Azure Search Documents:客户端库,用于将数据嵌入并存储到具备向量搜索能力的Azure认知搜索中。
  • OpenAI Python SDK:用于与Azure OpenAI服务的API进行通信。
  • FastAPI:用于构建高效Web API的现代框架。
  • Uvicorn:用于运行FastAPI应用的ASGI服务器。
  • Tiktoken:OpenAI的分词器,用于帮助创建文本嵌入。

应用核心逻辑解析

这个Web应用非常精简,仅由一个约76行代码的文件构成。它被设计为部署到云环境,并从环境变量中获取所有敏感配置(如API密钥和端点地址),确保了安全性。

应用的核心是连接到两个外部服务:Azure OpenAI服务(用于调用大语言模型)和Azure认知搜索(作为向量数据库)。这种设计使得应用本身非常轻量且职责单一。

应用只暴露一个API端点:/ask。当用户向这个端点发送POST请求时,会触发以下处理流程:

  1. 接收请求:从请求体中提取用户的prompt(问题)。
  2. 向量检索:将prompt发送给Azure认知搜索进行相似性搜索,从预先存储的向量数据中找出最相关的5个结果。
  3. 调用大模型:将检索到的上下文信息与原始prompt结合,构造一个增强的提示,然后调用Azure OpenAI的聊天补全API。
  4. 返回响应:将大模型生成的最终答案返回给API调用者。

关键代码段说明

让我们深入看一下搜索和生成回答的关键部分。搜索功能通过以下逻辑实现:

# 伪代码逻辑示意
def perform_search(user_query):
    # 使用Azure认知搜索进行相似性搜索
    search_results = azure_search.similarity_search(query=user_query, k=5)
    # 返回检索到的相关文本内容
    return search_results

检索到的内容随后被用于增强发送给大模型的上下文。提示词的构造类似于以下模式:

enhanced_prompt = f"""
基于以下已知信息,请回答问题:
{search_results}

问题:{user_query}
"""

最终,这个enhanced_prompt被发送给如GPT-4这样的模型,模型会基于提供的上下文生成一个准确且相关的回答。

总结与扩展

本节课中我们一起学习了一个部署在Azure云上的RAG模式应用实例。该应用结构清晰、耦合度低,通过将向量数据库和大语言模型作为外部服务调用,实现了自身的轻量化。

这种模式的优势在于其灵活性和可扩展性。虽然本例基于Azure,但相同的RAG模式和架构设计可以轻松迁移到其他云平台(如AWS、GCP)或使用不同的服务组件。你只需要替换对应的服务端点和客户端库即可。这为构建生产级的生成式AI应用提供了一个实用且强大的蓝图。

大型语言模型实践:P55:部署概览 🚀

在本节课中,我们将学习如何将一个基于大型语言模型的应用部署到云端。我们将了解从代码到最终服务的完整流程,以及各个组件(如GitHub Actions、Docker容器和Azure云服务)是如何协同工作的。

架构概览

理解我们拥有的架构概览将帮助我们明白所有组件将如何协同工作。

部署流程详解

上一节我们介绍了整体架构,本节中我们来看看具体的部署步骤。以下是部署流程的详细步骤:

  1. 代码与API:我们从代码开始。我们的应用程序托管在GitHub上,它包含一个HTTP API,用于接收请求并与模型交互。

  2. 自动化构建:接下来,我们使用GitHub Actions进行自动化。GitHub Actions将与Docker交互,设置一个Docker构建系统并执行命令。

  3. 容器化应用:通过上述步骤,我们将能够构建我们的容器化应用程序。构建容器应用是至关重要的一步,目的是为了将其部署到Azure云上。

  1. 推送镜像:容器构建完成后,我们将进入第四步:将生成的容器镜像推送到注册表。在本例中,我们使用GitHub容器注册表(GHCR)。你也可以使用其他注册表,但这里为了简化,我们使用GHCR,因为用户名和密码等配置已经预先设置好。

  2. 触发云服务:当镜像成功推送到注册表后,GitHub Actions会通知Azure(具体是Azure容器实例服务)去拉取这个新镜像。这是一个触发效应。

  3. 服务发布与扩展:Azure从注册表拉取容器镜像后,便会发布我们的应用。最终,用户可以与这个已部署的应用进行交互。Azure云能够根据请求量水平扩展我们的应用,即创建更多容器实例来处理涌入的请求。

  4. 处理用户请求:当用户向应用发送提示或查询时,请求首先到达Azure云。云中的容器应用会处理这些请求,并与Azure OpenAI服务通信以获取AI响应,最后将结果返回给用户。

总结

本节课中,我们一起学习了将一个LLM应用部署到云端的完整流程。我们从代码开始,通过GitHub Actions实现自动化构建和推送Docker镜像,最终利用Azure云服务进行部署和水平扩展。这个流程清晰地展示了开发、运维和云平台如何紧密结合,让应用能够服务用户。接下来,我们将深入GitHub Actions,查看具体的工作流配置。

大型语言模型实践:P56:设置云组件 🚀

在本节课中,我们将学习如何在Azure门户中创建和管理容器应用服务,为后续部署连接Azure OpenAI服务的应用程序做准备。我们将重点关注资源组和容器应用名称的配置,以确保与自动化部署流程(如GitHub Actions)的正确集成。


上一节我们介绍了云应用部署的准备工作,本节中我们来看看如何在Azure门户中具体创建所需的容器应用服务。

我们再次进入Azure门户。为了启动我们的应用程序或将其部署到云端,我们需要开始创建所需的服务。我们将进入“容器应用”部分来创建一个新的容器应用。但在执行此操作之前,有一个非常重要的细节需要牢记:我们的自动化流程已经就位,但其一个关键方面需要我们注意。

我将切换到代码仓库界面,进入 .github/workflows 目录,查看我已经预先配置好的GitHub Action工作流文件。这里有一个重要的细节:你是否看到了 group namecontainer app name?这些名称至关重要。我需要确保在创建服务时正确输入它们,以便自动化流程能够匹配。创建服务的顺序并不重要(例如,我的自动化配置可能先于服务存在),但如果你还没有创建,请确保在创建容器应用时,这些名称与工作流文件中的定义保持一致。

以下是创建容器应用的核心步骤:

  1. 在Azure门户中,导航至“容器应用”服务。
  2. 点击“创建”按钮,开始新建一个容器应用。
  3. 在创建过程中,选择合适的描述,并指定资源组。资源组名称应与你之前计划或工作流中定义的保持一致,例如 demo-container
  4. 容器应用名称也应设置为相同的值,例如 demo-container
  5. 选择你偏好的部署区域(例如“美国东部”而非“澳大利亚东部”)。
  6. 完成上述配置后,点击“查看 + 创建”进行验证,最后点击“创建”按钮。

这个过程需要一些时间来完成部署。一旦容器应用就绪,我就能够开始使用我的自动化部署流程了。

这些就是我所需要创建的核心资源。我将回到GitHub Action的配置界面进行说明。这个GitHub Action将使用GitHub容器注册表(GHCR)。任何我构建的容器镜像都将存储在GitHub自身的注册表中。这是一种架构组件或编排方式,允许我将容器放置在特定的位置。这并不意味着你必须使用GitHub容器注册表,它同样可以部署到Azure容器注册表。但在此例中,我们将利用GitHub提供的这种非常简便、直接的容器注册表服务。

你将看到,一旦部署开始,这些流程将逐步推进。当所有步骤都完成后,我们将准备好继续推进,尝试部署并自动化我们的应用程序,该程序最终将连接到Azure OpenAI服务。


本节课中我们一起学习了在Azure门户中创建容器应用服务的具体步骤,强调了资源组和应用名称与自动化脚本保持一致的重要性,并介绍了如何利用GitHub容器注册表来简化容器镜像的管理和部署流程。

大型语言模型实践:03:使用Azure云进行部署 🚀

在本节课中,我们将学习如何将我们的应用程序最终部署到Azure云平台。我们将回顾自动化部署流程,排查常见问题,并验证部署是否成功。

概述

现在,我们已准备好部署应用程序。这是我们的最后一步。我们有一个之前创建资源时已部署过的演示容器应用程序。接下来,我们需要前往代码仓库,在Actions步骤中触发部署工作流。

在开始之前,我想展示一个关于构建自动化时的现实情况。当我向下滚动时,你会看到许多失败记录。这完全正常。你很少能从一开始就一切顺利,一次成功。你会遗漏一些变量,出现一些拼写错误,需要通过一些失败才能达到目标。虽然我已经触发了工作流,但让我展示刚开始时的样子,并看看其中的一些组件。

触发部署工作流

我们将点击这里,手动触发部署。Run workflow按钮是手动触发器。我将点击它,从main分支运行这个工作流,这会触发所有流程。我已经执行了这个操作。与其等待两分三十秒,我们不如直接查看这里发生了什么。

以下是工作流的主要步骤:

  • 构建步骤:创建容器,将所有内容打包到容器中,并安装依赖项。
  • 部署步骤:与Azure通信,完成部署。

如果我点击其中一次运行,可以看到日志输出。构建步骤的日志会显示设置Docker、构建镜像、登录GitHub容器注册表等信息。部署步骤的日志则会显示进行Azure登录、将仓库名称转换为小写、以及部署到容器应用程序等操作。这里的一些设置会以星号显示,以防止密钥信息泄露。

好的,部署已完成,一切顺利。

在Azure门户中验证与配置

接下来,看看云端容器这边的情况。我将回到Azure门户,进入容器应用部分,然后在“概览”部分找到应用程序URL。

如果我点击这个URL并在新标签页中打开,可能会遇到第一个问题。我们的容器内部使用的是端口8000,而外部访问默认尝试使用端口80

我们需要返回Azure门户进行检查和配置。以下是需要检查的配置项:

  1. 入口(Ingress)设置:这是设置的一部分。点击进入后,需要一直向下滚动。目标端口指的是容器内部的端口,对我们来说就是端口8000。我将保存这个更改,等待入口更新完成,然后就能验证应用程序是否正常运行了。更新成功后,使用相同的地址重新加载页面,我们的应用程序就出现了。

  1. 测试应用程序:这是我们的FastAPI应用,它正运行在Azure容器应用上。让我们测试一下。像之前一样点击Try it out,输入问题,例如“What is a good one from Oregon? You can recommend.”,然后执行。它会联系我们的索引,实际上是联系Azure OpenAI服务,并获取来自俄勒冈州的回复。完美,这表明一切都在正常运行,并且该应用是公开可用的。

  2. 检查日志与配置:最后,我想展示一些你可能遇到的潜在错误。查看日志流是发现潜在问题的好方法。在这里,我们可以看到一切运行良好,它正在打印一些响应信息,这很好。当出现问题时,这个终端输出也会显示错误信息,帮助你排查。另外,你需要确保在“容器”部分检查你的环境变量属性是否正确。最后,在“缩放和副本”部分,如果你需要进行扩展,可以看到这里范围是0到10,你可以增加副本数以获得更多带宽来应对请求。

总结

本节课中,我们一起完成了应用程序的成功部署。这是我们的Azure示例。我们能够使用GitHub Actions将一切整合起来,实现自动化,并部署到Azure云平台。

大型语言模型实践:5.8:总结与展望 🎯

在本节课中,我们将回顾并总结如何将所有组件整合起来,构建并部署一个基于HTTP API的生成式AI应用程序到云端。


概述

上一节我们介绍了部署验证的具体步骤。本节中,我们将对整个模块进行总结,并展望后续的学习方向。

我们成功整合了创建一个基于HTTP API的生成式AI应用程序所需的所有必要组件。我们将其部署到了云端,并运用了包括自动化在内的一系列最佳实践。

我们使用了GitHub Actions,了解了其含义,并在Azure云上为此次部署设置了相应的组件。这是将所有内容整合起来,与Azure云等平台协同工作的最后一步。

需要说明的是,我并未深入探讨你需要执行的所有具体步骤的每一个细节,因为本课程旨在为你快速概述整个过程的全貌。

如果你想进一步探索,当然有更多课程可供你深入学习。但在本课程中,我们选择为你提供一个快速、简要的概览。

我们介绍了你需要哪些组件、整个流程将如何呈现,以及部署完成后如何验证该部署。

希望这能让你对整个过程如何发生有一个相当清晰的认识。


核心要点回顾

以下是本模块涵盖的核心内容:

  • 组件整合:我们学习了如何将模型、API接口、业务逻辑等组件组合成一个完整的应用。
  • 云端部署:我们将应用部署到了Azure云平台,利用了云服务的可扩展性与可靠性。
  • 最佳实践:我们引入了自动化部署流程,例如通过GitHub Actions来实现CI/CD(持续集成/持续部署)。
  • 部署验证:我们探讨了在应用部署后,如何通过访问端点、测试功能等方式来验证部署是否成功。

总结

本节课中,我们一起学习了构建和部署一个生成式AI Web应用的全流程概览。我们从整合组件开始,到利用自动化工具将其部署至云端,最后完成了部署验证。这为你理解如何将大型语言模型投入实际生产环境奠定了坚实的基础。记住,这只是开始,后续还有更多深入的知识等待你去探索。

大型语言模型实践:1:认识你的课程讲师德里克·威尔士

在本节课中,我们将认识本课程的讲师,并了解课程的基本设置与学习工具。

大家好。我是德里克。我是杜克大学数据科学项目的毕业生。目前我在一家大型科技公司担任产品经理。

今天,我将向大家展示如何使用OpenAI的DALL·E模型,根据文本生成图像。请注意,这项技术发展迅速,在您学习本课程时,部分模型可能已经更新。因此,请务必查阅课程资料中提供的最新文档。

我知道大家在前面的课程中已经接触过OpenAI API。但在接下来的章节中,我将首先展示如何设置GitHub Codespaces作为开发环境。我认为这是一种极佳的云端开发方式,无需担心本地机器的依赖问题,并且能让大家使用Copilot等工具。关于Copilot,我们将在课程后续部分详细讨论。

好的。感谢大家。让我们开始吧。😊

本节课中,我们一起认识了讲师德里克,并了解了课程将使用OpenAI的DALL·E模型进行图像生成,以及推荐使用GitHub Codespaces作为云端开发环境。

大型语言模型实践:04:DALL-E概览 🖼️

在本节课中,我们将要学习OpenAI的DALL-E模型。这是一个能够根据文本描述生成图像的AI系统。我们将了解它的基本工作原理、核心参数以及如何通过API调用它。

在深入实际环境和设置代码空间,并进行一些DALL-E的具体实现之前,我们先快速概览一下它是什么以及它是如何工作的。

DALL-E是什么?

DALL-E是一个图像生成AI。它的简短工作原理如下:它接收文本输入。

以下是其工作原理的更详细说明,我也会提供更多文档链接。这方面有相当多的科学研究。它的流程包含几个核心步骤:

  1. 文本编码器:它接收文本提示(prompt)。
  2. 模型映射:模型将文本编码映射到对应的图像编码。
  3. 图像解码器:最后使用图像解码器生成最终的图像。

这是一个完整的处理流程示意图(例如,描述“一个吹奏喷火喇叭的人”)。这张图来自一个名为“Assembly AI”的优秀网站,它清晰地解释了这一过程。这张图虽然关联DALL-E 2,但其工作原理与DALL-E 3相同。该网站还深入介绍了一些改进,并对这些模型的工作方式提供了易于理解的解析,我会确保包含这个链接。

API调用参数

接下来,我们快速看一下调用参数。这来自OpenAI的官方文档。

其调用方式与标准的OpenAI文本生成API调用类似。你需要指定模型并传入提示(prompt)。与此不同的是,许多参数是基于图像的,而非文本。

以下是核心参数:

  • size:指定生成图像的尺寸。目前只有三种可选尺寸(例如1024x1024)。
  • quality:图像质量,可选“standard”(标准)或“hd”(高清)。请注意,这项技术发展非常迅速。
  • n:请求生成图像的数量,例如 n=1

API的响应以JSON格式返回。你在底部看到的那个高亮命令,就是用于打印出图像URL的方法,点击该URL即可查看生成的图像。

环境准备

好了,让我们切换到实际的操作环境。

本节课中我们一起学习了DALL-E图像生成模型的基本概念。我们了解了它从文本到图像的生成流程,包括文本编码、模型映射和图像解码三个核心阶段。同时,我们也预览了调用其API时需要关注的主要参数,如图像尺寸、质量和生成数量。接下来,我们将进入实践环节,设置环境并开始编写代码。

大型语言模型实践:P61:演示环境设置 🛠️

在本节课中,我们将学习如何设置一个基于GitHub Codespaces的开发环境,以便为后续的LLM项目开发做好准备。我们将从注册GitHub账户开始,逐步介绍如何使用Codespaces功能来创建一个便捷的云端开发环境。

注册GitHub账户

首先,我们需要访问GitHub网站。如果你还没有GitHub账户,需要点击“Sign up”按钮进行注册。注册过程会要求你填写一系列信息以创建账户。由于我已经拥有账户,我将跳过注册步骤,直接展示登录后的界面。

认识GitHub与Codespaces

登录后,你将看到GitHub的主界面。GitHub是一个在线的代码仓库平台。我推荐使用它的一个重要原因是它提供了名为“Codespaces”的强大云端开发环境功能。

虽然本课程使用的代码仓库是私有的,但你仍然可以了解其基本操作。我已经创建了相关的README文件。要启动开发环境,你需要点击“Code”选项卡,然后选择“Codespaces”。

配置Codespaces开发环境

启动Codespaces后,你的本地机器(实际上是云端环境)将加载一个类似VS Code的编辑器界面。在本课程中,我使用Jupyter Notebooks进行演示,因此文件扩展名通常是.ipynb。使用Notebook可以让我清晰地按单元格执行和展示代码,这非常方便。

Codespaces的一个优点是它的智能感知功能。当你创建一个具有特定扩展名(例如.py.ipynb)的文件时,环境会自动提示你安装相应的依赖库。

你可以在集成的终端中执行命令,例如使用pip install来安装Python包。同时,Codespaces与Git的集成非常顺畅。当你修改代码后,可以轻松地提交更改。

以下是使用终端安装包和提交代码的基本流程:

  1. 打开终端:在Codespaces界面中,找到并打开终端面板。
  2. 安装依赖:使用pip命令安装项目所需的Python库。
    pip install package_name
    
  3. 提交代码:使用Git命令将更改提交到仓库。
    git add .
    git commit -m “Your commit message”
    git push
    

这种工作流使得持续集成和代码版本管理变得非常简单。接下来,我将在这个环境中进行一些准备工作,为使用Dolly模型配置好环境,然后我们将进入第一个实践项目。

总结

本节课中,我们一起学习了如何设置基于GitHub Codespaces的开发环境。我们从注册GitHub账户开始,介绍了Codespaces作为云端开发环境的优势,并演示了其基本操作,包括创建环境、安装依赖以及与Git的协同工作。这个环境将为我们后续的大型语言模型实践项目打下坚实的基础。

大型语言模型实践:第4章:使用OpenAI API生成购物清单 🛒

在本节课中,我们将学习如何利用OpenAI的API,根据一份食谱自动生成一份购物清单。我们将编写一个函数来构建提示词,调用GPT模型,并获取结构化的响应。整个过程旨在展示如何将自然语言指令转化为具体的、可执行的任务列表。


准备工作 🛠️

在开始编写代码之前,我们需要完成一些基础设置。这包括导入必要的库,并安全地配置我们的API密钥。

首先,我们需要导入openai库和os库。openai库用于与OpenAI的API进行交互,而os库则用于安全地管理环境变量。

import openai
import os

接下来,我们需要设置OpenAI的API密钥。为了安全起见,最佳实践是将密钥设置为环境变量,而不是直接硬编码在脚本中。你可以通过运行一个单独的代码单元来设置它,完成后再删除该单元,这样密钥就保存在环境变量中而不会在代码中暴露。

# 在你的环境中设置此变量,例如:os.environ[‘OPENAI_API_KEY’] = ‘your-api-key-here’
# 设置完成后,请删除或注释掉这行代码。

构建提示词函数 ✍️

上一节我们完成了环境设置,本节中我们来看看如何构建一个函数来生成发送给AI的提示词。这个函数的核心是创建一个清晰的指令,告诉模型我们想要它做什么。

以下是构建提示词函数的步骤。该函数将接收一个食谱作为输入,并请求模型基于此食谱生成一份购物清单。

  1. 定义一个函数,例如 create_shopping_list_prompt(recipe)
  2. 在函数内部,构建一个字符串格式的提示词(prompt)。
  3. 提示词应明确指示模型的任务,例如:“基于以下食谱,创建一份购物清单,并列出与之搭配良好的食物和烹饪说明。”
  4. 函数最终返回这个构建好的提示词字符串。
def create_shopping_list_prompt(recipe):
    prompt = f"""
    基于以下食谱,创建一份购物清单,并列出与之搭配良好的食物和烹饪说明。

    食谱:
    {recipe}
    """
    return prompt

调用OpenAI API 🤖

现在我们已经有了生成提示词的函数,接下来我们看看如何实际调用OpenAI的API来获取模型的响应。我们将使用gpt-3.5-turbo模型,它是目前性价比较高的选择之一。

以下是调用API的关键步骤:

  1. 使用 openai.ChatCompletion.create() 方法。
  2. 在参数中指定模型,例如 model=“gpt-3.5-turbo”
  3. 构建 messages 列表,其中包含一个系统消息(role: “system”)和一个用户消息(role: “user”),用户消息的内容就是我们上一步生成的提示词。
  4. 可以设置其他参数,如 temperature(控制输出的随机性)和 top_p(控制输出的多样性)。
  5. 从API的响应对象中提取出模型生成的内容。
# 假设 recipe_text 是您的食谱字符串
prompt = create_shopping_list_prompt(recipe_text)

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "system", "content": "你是一个有用的助手。"},
        {"role": "user", "content": prompt}
    ],
    temperature=0.7,
    top_p=1
)

# 提取并打印AI的回复
shopping_list = response.choices[0].message.content
print(shopping_list)

运行代码后,API会返回一个响应对象。我们从中提取出choices[0].message.content,这就是模型为我们生成的购物清单。这份清单通常会很详细,包含所需的食材以及烹饪建议。你可以根据需求,通过调整max_tokens等参数来控制响应的长度和细节程度。


总结与展望 📝

本节课中我们一起学习了如何利用OpenAI API将一份食谱转化为结构化的购物清单。我们首先设置了开发环境,然后构建了清晰的提示词函数,最后通过调用gpt-3.5-turbo模型成功获得了所需的清单。

这个过程展示了大型语言模型在理解自然语言指令并执行具体任务方面的强大能力。生成的购物清单可以作为一个起点,你可以进一步处理它,例如将其发送给像DALL-E这样的图像生成模型,来获取需要购买的食材的图片,使得整个购物计划更加直观和生动。在接下来的课程中,我们可以探索如何实现这一扩展功能。

大型语言模型实践:P63:演示DALL-E生成图像 🖼️

在本节课中,我们将学习如何结合OpenAI的文本生成与DALL-E图像生成API,从一份食谱中提取购物清单,并自动生成所需食材的图片。我们将使用正则表达式处理文本,并调用DALL-E API来创建图像。

概述

我们将首先使用OpenAI模型生成一份食谱及其购物清单,然后通过正则表达式从响应中精确提取出购物清单。接着,我们会将清单中的每一项作为提示词,传递给DALL-E模型,以生成对应的食材图片。这个过程展示了如何将不同的AI服务串联起来,构建一个实用的应用原型。

提取购物清单

上一节我们获得了包含食谱和购物清单的文本响应。本节中,我们来看看如何从中精确提取出购物清单部分。

我们观察到,在模型的响应中,每个食材项都以一个破折号和空格(“- ”)开头。我们将利用这个模式,使用正则表达式来匹配并提取所有食材。

以下是提取购物清单的步骤:

  1. 从OpenAI的响应对象中获取文本内容。
  2. 定义一个正则表达式模式来匹配以“- ”开头的行。
  3. 使用re.findall函数找到所有匹配项。
  4. 将匹配结果存储在一个列表中供后续使用。

相关代码如下:

import re

# 假设 response 是来自 OpenAI API 的响应对象
text_content = response.choices[0].message.content

# 定义正则表达式模式,匹配以破折号和空格开头的行
pattern = r"- .+"

# 查找所有匹配项
shopping_list = re.findall(pattern, text_content)

# 打印查看结果
print("提取的购物清单:")
for item in shopping_list:
    print(item)

运行代码后,我们将得到一个清晰的食材列表,为下一步的图像生成做好准备。

调用DALL-E生成图像

成功提取购物清单后,我们现在可以将其用于图像生成。本节中,我们将学习如何调用DALL-E 3模型,根据购物清单中的食材描述来创建图片。

我们将使用OpenAI的Python客户端库。需要为图像生成指定模型、提示词、尺寸和质量等参数。

以下是调用DALL-E生成图像的核心步骤:

  1. 导入OpenAI库并设置客户端。
  2. 从购物清单中选取一个项目作为提示词(例如第一个项目)。
  3. 配置API调用参数,包括模型、图片尺寸和生成数量。
  4. 发送请求并获取包含图片URL的响应。

相关代码如下:

from openai import OpenAI

# 初始化客户端,假设已设置好API密钥
client = OpenAI()

# 使用购物清单中的第一项作为提示词
prompt = shopping_list[0]

# 调用DALL-E API生成图像
image_response = client.images.generate(
    model="dall-e-3",  # 指定模型
    prompt=prompt,      # 图像描述提示词
    size="1024x1024",   # 生成图像的尺寸
    quality="standard", # 图像质量
    n=1,                # 生成图像的数量
)

# 从响应中获取图像的URL
image_url = image_response.data[0].url
print(f"生成的图像URL: {image_url}")

执行上述代码后,我们会获得一个指向生成图片的URL。点击该链接,就能看到DALL-E根据食材描述创建的图像。在本例中,生成的图像准确描绘了需要从商店购买的物品。

总结与扩展

本节课中,我们一起学习了如何构建一个从文本到图像的AI工作流。我们首先使用OpenAI的文本模型生成购物清单,然后通过正则表达式提取清单内容,最后利用DALL-E模型为清单项目生成对应的视觉图像。

这个过程清晰地展示了将大型语言模型与图像生成模型结合的可能性。以此为基础,你可以轻松地扩展此应用:例如,遍历整个购物清单,为每一项食材生成图片;或者构建一个完整的应用程序,让用户输入食谱名称,自动输出烹饪步骤和所有食材的图片。

通过正则表达式和API调用的组合,我们能够将AI的能力串联起来,解决更复杂、更贴近实际需求的问题。

大型语言模型实践:1.4:OpenAI DALL-E 总结 🎨

在本节课中,我们快速概览了 DALL-E 模型,并学习了如何结合使用 OpenAI API 与 DALL-E API 来生成图像并构建应用程序。

课程内容概述

我们完成了第一课的引导部分。本节将对所学内容进行总结。

核心学习要点

以下是本课涵盖的核心内容:

  • DALL-E 概览:你获得了关于 DALL-E 模型的快速概览。
  • 开发环境设置:你学习了如何使用 GitHub Code Spaces 和自动化结对编程软件来设置 GitHub。
  • API 应用实践:你学习了如何结合使用 OpenAI API 和 DALL-E API 来生成图像,并构建应用程序。

总结与展望

本节课中,我们一起学习了利用现代工具链进行 AI 应用开发的基础步骤。这仅仅是这些工具强大能力的开始,让我们进入下一课,继续探索。

大型语言模型实践:P65:OpenAI微调与项目介绍 🎯

在本节课中,我们将学习微调(有时也称为迁移学习)的过程。这是一个将预训练的大型语言模型(LLM)根据特定应用(例如医疗数据或Reddit问答)进行定制化的技术。

上一节我们介绍了大型语言模型的基础概念,本节中我们来看看如何通过微调来定制模型。

项目概述 📋

我们将使用来自Reddit的问答数据,在CodeSpaces环境中运行代码,通过OpenAI API选择一个基础模型进行微调,最终获得一个定制化的模型,并对其进行测试。

以下是项目的主要步骤流程图:




核心概念与流程

微调的核心是迁移学习。其基本公式可以概括为:

定制模型 = 预训练模型 + 特定领域数据 + 微调过程

以下是实现此流程的关键步骤列表:

  1. 准备数据:获取并导入Reddit的问答数据到开发环境。
  2. 选择模型:通过OpenAI API选择一个适合的基础模型(例如 gpt-3.5-turbo)。
  3. 执行微调:将准备好的数据发送给OpenAI,在所选模型上运行微调作业。
  4. 接收与测试:获取返回的定制模型,并编写代码对其进行效果测试。



进入实践环节

了解基本流程后,接下来我们将进入CodeSpaces环境开始动手实践。


本节课中我们一起学习了微调(迁移学习)的概念,了解了将一个通用大型语言模型根据特定数据(如Reddit问答)定制化的完整项目流程。从数据准备、模型选择到执行微调和最终测试,我们梳理了每个关键步骤。接下来,我们将在代码环境中具体实现这一过程。

大型语言模型实践:04:微调项目第一部分:环境与数据准备 🛠️

在本节课中,我们将学习如何为大型语言模型的微调项目准备开发环境和数据。我们将导入必要的库,设置Git LFS来管理大型数据文件,并读取、清洗和合并来自Reddit的问题与答案数据集,最终为后续的微调步骤准备好格式规整的数据。

导入必要库

首先,我们需要导入项目所需的Python库。这些库将帮助我们处理数据和文件。

以下是需要导入的库:

import json
import pandas as pd

设置Git LFS管理大型文件

上一节我们导入了必要的库,本节中我们来看看如何管理项目中的大型数据文件。由于我们将使用的Reddit数据集文件较大,需要先设置Git LFS(大文件存储)来跟踪这些CSV文件。

以下是设置Git LFS的步骤:

  1. 安装Git LFS(如果尚未安装)。
  2. 在项目目录中,使用命令 git lfs track “*.csv” 来跟踪所有CSV文件。
  3. 将大型的Reddit数据文件(如 reddit_answers.csvreddit_questions.csv)拖放或移动到当前工作目录中。

完成这些步骤后,我们就可以在笔记本中读取这些文件了。

读取并处理答案数据

环境设置好后,我们现在可以开始读取数据。首先,我们读取包含答案的文件。

answers = pd.read_csv(‘reddit_answers.csv’, sep=‘;’)
print(answers.head())

观察数据可以发现,文件没有明确的列标签,并且每个问题ID对应多个答案及其点赞数。我们的目标是选取每个问题下点赞数最高的答案,以控制后续发送给OpenAI API的令牌数量,从而控制成本。

以下是处理答案数据的步骤:

  1. 按问题ID(q_id)和点赞数(votes)对答案进行分组。
  2. 使用 idxmax() 函数获取每个问题下点赞数最高的答案的索引。
  3. 使用 loc 方法根据索引筛选出这些“最佳答案”。
  4. 重命名列名,使其含义更清晰,便于后续操作。
# 获取每个问题下点赞数最高的答案
top_answers = answers.loc[answers.groupby(‘q_id’)[‘votes’].idxmax()]

# 重命名列
top_answers.rename(columns={
    ‘q_id’: ‘id’,
    ‘votes’: ‘answer_votes’,
    ‘answer’: ‘answer’
}, inplace=True)

print(top_answers.head(3))

读取并处理问题数据

处理完答案数据后,接下来我们需要读取对应的问题数据,以便将问题和最佳答案匹配起来。

questions = pd.read_csv(‘reddit_questions.csv’, sep=‘;’)
print(questions.head())

与答案数据类似,我们也需要重命名问题数据的列,使其更直观。

以下是重命名问题数据列的步骤:

  1. q_id 重命名为 id,以便与答案数据合并。
  2. votes 重命名为 question_votes,以区别于答案的点赞数。
questions.rename(columns={
    ‘q_id’: ‘id’,
    ‘votes’: ‘question_votes’
}, inplace=True)
print(questions.head())

合并问题与答案数据

现在,我们有了处理好的问题数据和答案数据。本节中我们将把这两个数据集合并起来,创建一个包含问题及其最佳答案的完整数据集。

我们基于共同的 id 字段来合并两个DataFrame。

merged_df = pd.merge(questions, top_answers, on=‘id’)
print(merged_df.head())

合并后,数据集中包含一些我们不需要的列(如时间戳)。为了使数据结构更清晰,我们需要进行清理和重排。

以下是清理和重排数据的步骤:

  1. 删除多余的列,例如 timestamp_xtimestamp_y
  2. 按照 idquestionanswerquestion_votesanswer_votes 的顺序重新排列列。
# 删除多余的列
columns_to_drop = [‘timestamp_x’, ‘timestamp_y’, ‘Unnamed: 0’]
merged_df.drop(columns=columns_to_drop, axis=1, inplace=True)

# 重新排列列的顺序
desired_order = [‘id’, ‘question’, ‘answer’, ‘question_votes’, ‘answer_votes’]
merged_df = merged_df[desired_order]

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/fbcaa709ae8a24f632ed4ec7702a290e_1.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/fbcaa709ae8a24f632ed4ec7702a290e_3.png)

print(merged_df.head())

筛选与缩减数据集

数据合并并整理好后,我们查看一下数据规模。由于数据集很大(约18.8万行),直接用于微调会产生较高的令牌成本和计算时间。为了教学演示和成本控制,我们将筛选出最受欢迎的答案来创建一个较小的子集。

我们根据 answer_votes 对数据进行降序排序,然后选取前1000行。

# 按答案点赞数降序排序
merged_df_sorted = merged_df.sort_values(by=‘answer_votes’, ascending=False)

# 选取前1000行数据
merged_df_1k = merged_df_sorted.head(1000)

print(merged_df_1k.head(3))
print(f”缩减后的数据集大小: {merged_df_1k.shape}”)

总结

本节课中我们一起学习了为LLM微调项目准备环境和数据的完整流程。我们首先导入了必要的库,然后配置Git LFS来管理大型数据文件。接着,我们逐步读取了Reddit的答案和问题数据,进行了数据清洗、列重命名和合并操作,最终创建了一个包含问题及其最受欢迎答案的规整数据集。最后,为了控制成本和提高效率,我们通过排序和切片得到了一个包含1000条高质量样本的精简数据集,为下一阶段的模型微调做好了准备。

大型语言模型实践:04:微调项目第二部分:开始微调 🚀

在本节课中,我们将学习如何将准备好的数据集转换为OpenAI微调所需的格式,并启动一个微调任务。我们将涵盖数据格式化、格式验证以及通过OpenAI API提交微调作业的完整流程。


上一节我们准备了缩短的数据集,本节中我们来看看如何将其转换为正确的格式并开始微调过程。

首先,我们需要将数据集转换为OpenAI微调所要求的格式。通常,最佳格式是包含“问题”和“答案”对的列表。

以下是转换数据格式的步骤:

  1. 创建格式化列表:我们将使用列表推导式,基于原始数据创建一个包含“提示”和“答案”的字典列表。
  2. 定义系统提示:为模型定义一个角色,例如“事实聊天机器人专家”。
  3. 组合用户问题:将用户的问题放入“用户”角色的内容中。
  4. 组合助手答案:将对应的答案放入“助手”角色的内容中。

以下是实现上述步骤的示例代码:

# 假设 questions_and_answers 是一个包含 (question, answer) 元组的列表
qa_ai_formatted = []
for q, a in questions_and_answers:
    message_list = [
        {"role": "system", "content": "你是一个事实聊天机器人专家,喜欢用项目符号列表回答问题。"},
        {"role": "user", "content": q},
        {"role": "assistant", "content": a}
    ]
    qa_ai_formatted.append({"messages": message_list})

运行此代码后,qa_ai_formatted 列表中的每个元素都将是一个符合OpenAI要求的消息字典。


接下来,我们需要将格式化后的数据写入一个JSONL文件,这是提交给OpenAI的标准格式。

以下是写入文件的代码:

import json

with open('fine_tune_data.jsonl', 'w') as f:
    for entry in qa_ai_formatted:
        json_line = json.dumps(entry)
        f.write(json_line + '\n')

执行此操作后,会在当前目录下生成一个名为 fine_tune_data.jsonl 的文件。


在将文件发送给OpenAI之前,验证其格式是否正确至关重要。OpenAI提供了实用的检查函数。

以下是验证文件格式的步骤:

  1. 导入检查工具:从OpenAI的示例代码库中获取格式验证函数。
  2. 运行验证:对生成的JSONL文件运行验证检查,确保没有缺失字段或格式错误。

验证过程会检查文件是否包含所有必需的参数,并且数据完整无误。相关的验证代码将包含在课程资料中供您使用。


验证通过后,我们就可以开始真正的微调过程了。这需要通过OpenAI API分两步完成。

以下是启动微调的具体步骤:

  1. 上传文件:首先,将格式正确的JSONL文件上传到OpenAI。

    import openai
    openai.api_key = ‘你的API密钥’
    
    file_response = openai.File.create(
        file=open(“fine_tune_data.jsonl”, “rb”),
        purpose=‘fine-tune’
    )
    file_id = file_response.id
    

    执行成功后,您会获得一个文件ID,这是下一步所必需的。

  2. 创建微调作业:使用上传后获得的文件ID来创建一个新的微调任务。

    fine_tune_job = openai.FineTuningJob.create(
        training_file=file_id,
        model=“gpt-3.5-turbo”
    )
    job_id = fine_tune_job.id
    

    创建作业后,您会收到一个作业ID。微调过程将在OpenAI的服务器上开始,这可能需要一些时间。

您可以通过以下方式查看作业状态:

# 列出所有作业
jobs = openai.FineTuningJob.list(limit=10)
# 或检索特定作业
job_status = openai.FineTuningJob.retrieve(job_id)

当微调完成后,OpenAI通常会发送邮件通知。完成后的模型就可以像其他API模型一样被调用使用了。


本节课中我们一起学习了微调GPT模型的核心实践步骤。我们从数据格式化开始,将问答对转换成特定的消息结构。接着,我们写入并验证了JSONL文件,确保其符合平台要求。最后,我们通过OpenAI API上传文件并创建了微调作业,启动了模型的训练过程。整个过程强调了准备工作的严谨性,这是获得良好微调结果的基础。

大型语言模型实践:P68:微调项目第三部分:模型评估 🧪

在本节课中,我们将学习如何评估一个已完成微调的大型语言模型。我们将通过一个具体的例子,向模型提问并分析其回答,同时讨论一个关键概念——模型幻觉。通过这个过程,你将了解如何验证微调后模型的输出是否符合预期。


模型推理与测试

上一节我们介绍了模型的微调过程。本节中,我们来看看如何对微调完成的模型进行实际测试。

我们的模型已经在Reddit风格的数据上完成了微调。因此,我们将向它提出一个类似Reddit论坛上的问题,以观察其响应。这种方法可以将一个通用模型应用于特定场景,例如医院系统或技术文档处理。

以下是测试步骤:

  1. 构建对话消息:我们将按照特定格式构建一个包含系统指令和用户问题的消息列表。
  2. 调用微调模型:与调用基础模型不同,这里需要指定我们刚刚微调好的专属模型ID。
  3. 获取并打印响应:发送请求后,从API响应中提取并查看模型生成的内容。

让我们开始实际操作。首先,定义系统指令和用户问题。

# 定义系统角色和指令
system_prompt = "你是一个官方聊天机器人,喜欢回答问题。你是Reddit专家,喜欢用项目符号列表回答问题。"

# 定义用户问题
user_question = "告诉我做过的最蠢的事。这听起来像一个常见的Reddit帖子。"

接下来,我们将这些信息组合成API所需的格式,并调用我们微调的模型。

# 构建消息列表
messages = [
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": user_question}
]

# 调用微调模型进行补全
response = client.chat.completions.create(
    model="ft:gpt-3.5-turbo-0613:personal::your-model-id", # 替换为你的微调模型ID
    messages=messages
)

# 打印模型的回答
print(response.choices[0].message.content)

运行代码后,我们得到了一个回答,内容大致是:“在啤酒花园酒吧里,试图跳过2米高、3.5米宽的盆栽”。这听起来确实像Reddit上会有人分享的“蠢事”。这表明我们的模型已经学会了生成符合Reddit社区风格的、略带自嘲和幽默的回应。


理解模型幻觉

在测试模型时,有一个必须警惕的重要概念:模型幻觉。它指的是模型生成看似合理但事实上不正确或毫无根据的信息。

虽然在我们当前的简单测试中较难触发,但这里有一个典型的例子。在一次关于萨姆·奥尔特曼(Sam Altman, OpenAI前CEO)被解雇的对话中,模型因为同时“记住”了对话历史中关于大学足球和密歇根大学教练吉姆·哈博(Jim Harbaugh)被禁赛的信息,结果在回答中错误地将这两件事混为一谈,生成了不准确的内容。

核心要点

  • 模型在连续对话中会参考整个会话历史。
  • 这可能导致它混淆不同主题的事实,从而产生“幻觉”。
  • 公式可以表示为:输出 = f(输入 + 对话历史),其中函数 f 可能错误地关联了不相关的历史信息。

因此,每当使用这些模型,尤其是使用自行微调的模型时,必须通过特定的测试用例来验证其输出结果的准确性。


课程总结

本节课中我们一起学习了模型微调后的评估流程。

  1. 测试微调模型:我们实践了如何向微调后的模型提问,并获得了符合目标风格(Reddit风格)的回答。
  2. 认识模型幻觉:我们探讨了模型可能生成不准确或虚构信息的现象,理解了其成因是在多轮对话中混淆了上下文。
  3. 强调验证重要性:我们明确了,在实际应用中,必须对模型的输出进行仔细的校验,不能完全信任其初始结果。

通过评估,我们确认了微调是有效的,同时也意识到了负责任地使用AI模型所需的关键注意事项。

大型语言模型实践:P69:微调总结 🎯

在本节课中,我们将总结关于大型语言模型微调的核心内容。我们将回顾微调的定义、步骤、潜在问题以及其广泛的应用前景。

微调回顾

上一节我们完成了微调的演示。现在,我们来系统性地总结整个过程。

微调的定义是:调整一个模型,使其更适应特定的使用场景。这通常涉及使用特定领域的数据对预训练模型进行额外训练。

微调过程步骤

以下是完成一次微调所涉及的主要步骤:

  1. 理解文档:查阅相关平台(如OpenAI)的官方文档,了解微调的具体要求、数据格式和API调用方式。
  2. 数据工程:准备训练数据。这通常需要将原始数据(如对话记录、文档对)转换成模型可接受的特定格式,例如JSONL文件,其中每行包含一个“提示”和对应的“理想回答”。
  3. 提交训练:将格式化后的数据发送给模型服务提供商(例如OpenAI的微调API),启动微调任务。
  4. 接收与加载模型:任务完成后,接收新的、微调后的模型端点,并在代码中将其加载以备使用。
  5. 测试与验证:使用典型的场景问题(例如,一个模拟的Reddit提问)来测试微调后模型的输出,评估其性能是否符合预期。

潜在问题与注意事项

在微调和使用过程中,需要注意一些潜在问题:

  • 幻觉:模型可能生成看似合理但事实上不准确或完全虚构的信息。
  • 数据质量:微调效果严重依赖于训练数据的质量和代表性。有偏见或不完整的数据会导致模型产生有偏见或不准确的输出。
  • 过拟合:如果微调数据量过小或过于特定,模型可能会过度适应这些数据,从而丧失原有的泛化能力。

应用前景展望

如果我们将思维拓展一下,微调技术可以应用于无数不同的场景。

例如,您可以前往OpenAI、Hugging Face等平台,选取一个基础模型,然后使用特定领域的数据对其进行重新训练。

  • 医疗聊天机器人:使用医学文献和医患问答数据微调模型,打造专业的医疗咨询助手。
  • 行业专属助手:使用您所在行业(如法律、金融、教育)的文档和对话数据,训练一个精通该领域知识的AI助手。
  • 文档智能处理:如果您拥有大量内部编码文档,微调后的模型可以更好地理解、总结或基于这些文档回答问题。

总结

本节课中,我们一起学习了大型语言模型微调的核心流程。我们从定义出发,逐步了解了从数据准备、提交训练到测试验证的完整步骤,并探讨了其中可能遇到的陷阱(如幻觉)以及微调技术广阔的应用潜力。

掌握微调是利用OpenAI等平台提供的强大工具的第一步。感谢学习,我们下节课再见。

大型语言模型实践:P70:OpenAI Whisper模型项目概览 🎤

在本节课中,我们将学习如何使用OpenAI的Whisper API进行语音识别,并构建一个简单的音频转录与摘要应用。我们将从环境设置开始,逐步完成一个完整的项目演示。

上一节我们介绍了课程的整体结构,本节中我们来看看一个具体的API应用项目。

Whisper API简介

Whisper是由OpenAI开发的一个通用语音识别模型。它在大型数据集上训练而成,能够处理多种任务。该模型可以接收音频输入,甚至支持MP4等视频格式,并且具备翻译功能。

项目演示概览

接下来,我们将快速浏览本次课程要完成的演示项目流程。

以下是项目的主要步骤:

  1. 我们将从Code Spaces和Copilot环境开始。
  2. 我们将导入一段罗伯特·F·肯尼迪的就职演讲音频文件到环境中。
  3. 我们将把该音频文件传递给OpenAI的Whisper API。
  4. API将返回识别出的文本。
  5. 我们将编写更多代码,把得到的文本发送出去以获取摘要。

如果你能理解这个流程,就会发现这是构建会议纪要或视频摘要类应用程序的雏形。这就是本项目的目的。

现在,让我们切换到开发环境并开始动手实践。

大型语言模型实践:P71:视频摘要生成器详解 🎬

在本节课中,我们将学习如何利用OpenAI的Whisper和GPT模型,构建一个能够将音频文件(如演讲录音)转换为文本摘要的生成器。我们将从导入必要的库开始,逐步完成音频转录、提示词设计以及调用API生成摘要的完整流程。


上一节我们介绍了课程的整体目标,本节中我们来看看具体的代码实现步骤。

首先,我们需要导入项目运行所必需的Python库。

以下是需要导入的核心库:

import os
import pandas as pd
import openai
from openai import OpenAI

导入完成后,我们运行这些代码来初始化环境。


接下来,我们需要设置OpenAI的API密钥以建立连接。

我们将API密钥导入环境变量,并初始化一个OpenAI客户端会话。

# 假设API密钥已存储在环境变量'OPENAI_API_KEY'中
client = OpenAI()

同时,我已将一个名为“John F. Kennedy inaugural address”的音频文件拖放到了当前工作环境中。


现在,让我们读取这个音频文件。

我们使用Python的标准文件操作来加载音频文件。

# 为本次演示,我们将文件命名为‘audio_file’
with open(‘John_F_Kennedy_inaugural_address.mp3‘, ‘rb‘) as audio_file:
    audio_data = audio_file.read()

代码运行后,音频数据已成功加载。我们可以在后续的单元格中继续使用它。


上一节我们准备好了音频数据,本节中我们来看看如何将其转换为文字。

我们将把音频数据传递给OpenAI的Whisper API来获取转录文本。许多云服务提供商都提供类似服务,但本教程为保持聚焦,将主要使用OpenAI的服务。

调用Whisper API进行转录:

transcription = client.audio.transcriptions.create(
    model=“whisper-1“,
    file=audio_data
)

运行后,我们成功收到了转录文本。


为了查看转录结果,我们需要正确地打印输出。

转录结果是一个对象,我们需要访问其.text属性来获取文本内容。为了便于查看,我们只打印前100个字符。

print(transcription.text[:100])

输出显示转录成功,内容为肯尼迪总统的就职演说片段。


现在我们已经有了演讲文本,下一步是设计一个系统提示词来指导GPT模型进行摘要。

我们将定义一个系统提示词,用于“引导”模型理解我们的任务。这个提示词改编自OpenAI官方文档中的“关键点提取”示例,非常适合用于总结总统演讲。

以下是系统提示词的内容:

你是一个专业的AI助手。请列出以下文本的主要观点并进行总结。

这个提示词与OpenAI官网的示例非常相似,能有效引导模型完成摘要任务。


准备好提示词和转录文本后,现在我们可以调用Chat Completion API来生成摘要。

我们使用client.chat.completions.create方法,并指定模型为gpt-4。同时,我们可以调整一些参数来控制生成效果。

以下是调用API的代码:

response = client.chat.completions.create(
    model=“gpt-4“,
    temperature=0.5,  # 控制生成文本的随机性
    messages=[
        {“role“: “system“, “content“: system_prompt},
        {“role“: “user“, “content“: transcription.text}
    ]
)

代码运行完毕,意味着我们已经从OpenAI获得了响应。


最后,让我们从API响应中提取出生成的摘要内容。

API返回的响应结构包含多个部分,我们需要从正确的位置获取生成的文本。

summary = response.choices[0].message.content
print(summary)

生成的摘要列出了演讲的核心内容,例如:“忠实执行总统职责”、“捍卫自由”、“人权来自上帝而非国家”等。摘要最后提到了那句名言:“不要问你的国家能为你做什么,而要问你能为你的国家做什么。”

通过调整max_tokens(生成文本的最大长度)和temperature等参数,你可以获得略有不同或更详细的摘要。这个项目的核心思想是构建一个会议摘要生成器或类似工具的基础框架。


本节课中我们一起学习了构建视频/音频摘要生成器的完整流程。我们从导入库和设置API密钥开始,然后读取音频文件并通过Whisper API将其转换为文本。接着,我们设计了一个有效的系统提示词,并最终调用GPT-4模型生成了结构化的内容摘要。通过调整参数,你可以灵活控制摘要的长度和风格,这个框架可以作为开发各类自动摘要工具的基础。

大型语言模型实践:P72:Whisper模型API总结 🎤

在本节课中,我们将总结使用OpenAI Whisper API处理音频文件的过程,并简要了解其应用场景。随后,我们将转向讨论相关的商业合作、偏见与安全问题,并结束本模块的学习。

音频文件总结实践

上一节我们介绍了Whisper API的基本调用。本节中,我们来看看一个具体的实践总结。

我们刚刚完成了使用OpenAI的Whisper API对一个音频文件的总结。可以看到,官方文档中提供了许多优秀的示例,展示了如何完成类似的任务。

应用场景示例

以下是Whisper API的一些典型应用场景:

  • 会议记录:无论是Zoom会议还是其他应用场景。
  • 视频内容处理:您可以导入一个视频文件,并让其生成内容摘要。

因此,OpenAI的Whisper API在此类场景中有非常多优秀的用途。

课程内容过渡

接下来,我们将稍微转换一下话题。我们将讨论一些商业合作案例,并简要涉及偏见与安全性的问题。之后,我们将结束本模块的学习。

感谢观看,我们下次再见。


本节课总结:本节课中我们一起学习了如何使用Whisper API处理并总结音频内容,了解了其在实际场景(如会议记录、视频摘要)中的应用,并对后续将讨论的行业合作与伦理议题进行了预告。

大型语言模型实践:P73:人工智能商业环境 📈

在本节课中,我们将了解生成式AI当前的商业环境与市场趋势。课程将展示相关的市场数据、企业合作案例,并解释这些动态对学习者和从业者的意义。

在进入下一个模块之前,有一点需要指出:学习过程可能具有挑战性。但生成式AI技术不会消失,它正持续发展。课程阅读材料中包含了一些相关文章,建议你仔细阅读。为了让你快速把握要点,我将直接展示其中的关键结论。你可以从咨询市场报告等渠道找到大量类似信息。

以下是当前生成式AI市场的支出情况。如图所示,目前支出已达数十亿美元级别。并且,在接下来的几年里,这一数字预计只会持续增长。

因此,学习本课程、掌握相关技能将使你处于有利位置。你正在为未来的发展做正确的准备。接下来,我想强调一些关键的企业合作与收购案例。这不仅关乎学习OpenAI的工具,本课程后续将介绍的其他工具也将为你未来的成功奠定基础。

接下来我们看下一篇文章。戴尔公司在2023年11月宣布与Hugging Face建立合作伙伴关系。

Hugging Face是一个开源模型提供商。

该平台汇集了大量机器学习模型,许多开源模型都发布于此。如今,平台上生成式AI模型也越来越多。根据文章所述,戴尔的计划是通过合作,旨在简化我们在之前视频中探讨过的模型微调等过程。这表明,生成式AI正在被广泛采纳,许多企业都在采取各种策略,无论是使用OpenAI的技术还是开源方案。而本课程将为你做好充分准备,以迎接未来几年即将爆发的市场。

这是一个绝对需要密切关注的市场趋势。即使学习过程有时略显艰难,也请保持信心。

本节课中,我们一起学习了生成式AI的商业环境。我们看到了市场支出的快速增长、重要的企业合作案例,并理解了掌握相关技能在未来市场中的重要性。这是一个持续发展的领域,保持学习将为你带来显著优势。

大型语言模型实践:P74:人工智能伦理原则 🤖

在本节课中,我们将学习人工智能伦理的基本原则。课程将介绍IBM提出的可信与透明原则,这些原则为负责任地开发和使用AI提供了一个简洁的框架。

在继续本课程后续模块之前,我们有必要花一点时间关注人工智能伦理。网络上关于此话题的资料很多,但IBM提出的原则非常实用。这些原则为思考AI伦理提供了一个良好的起点,特别是当你开始使用开源工具或部署定制模型时。从AI伦理的角度来看,遵循这些原则至关重要。

上一节我们提到了关注AI伦理的重要性,本节中我们来看看IBM提出的具体原则框架。

IBM人工智能可信与透明原则

正如刚才提到的,我非常欣赏这些原则。它们提供了一个简单的框架,包含三条简单的规则。在进行任何AI相关工作之前思考这些规则,通常能确保你的方向正确。

以下是三条核心原则:

  1. AI的目的是增强人类智能。 我们并非要取代工作,也不希望仅仅为了裁员而开发系统。我们必须牢记这一点,AI应使我们更高效、更具生产力,而非替代我们。

  1. 数据和洞察属于其创造者。 关于这一点,我能想到的最佳例子是:如果马克·吐温的作品仍受版权保护,而你用其作品大量训练模型,那么模型生成的回应将是独特的。这与使用完全公开的数据(如推特)训练出的结果截然不同。原始作品的创造者有权享有其成果,我认为这条原则很好地体现了这一点。

  1. AI系统必须透明且可解释。 我完全同意这一点,尤其是当你开始用AI审批贷款或类似性质的事务时。我认为这条原则对此概括得非常到位。

课程文档中提供了更多阅读材料,但以上是我想重点强调的原则。

总结

本节课中,我们一起学习了IBM提出的人工智能伦理三大核心原则:增强人类智能尊重数据与洞察的归属权,以及确保系统的透明与可解释性。这些原则为负责任地实践AI技术提供了重要的指导基础。

大型语言模型实践:P75:本地机器学习模型与下门课程预览 🚀

在本节课中,我们将探讨一个日益重要的趋势:本地运行大型语言模型。我们将了解其优势,并通过一个实际演示,预览如何在本地机器上运行LLM。


概述

上一节我们讨论了商业环境,本节中我们来看看一个额外的趋势:本地大型语言模型。本地LLM正变得越来越流行,这主要得益于模型更易获取(例如通过Hugging Face平台),并能有效降低业务风险。这是一个新兴领域,依赖第三方服务可能面临服务商存续时间不确定、服务费用变动等风险。因此,越来越多的用户选择在自己的基础设施上运行模型。本节课我们将切换到Windows的Linux子系统,演示如何完全在本地机器上运行这些模型,这也是对下一门更深入课程的预览。


本地LLM的优势

以下是本地运行大型语言模型的几个关键优势:

  • 降低业务风险:避免因依赖第三方服务商而产生的存续性和稳定性风险。
  • 控制成本:在下载模型(通常是开源免费的)后,无需支付持续的服务费用。
  • 避免速率限制:在本地强大硬件上运行,不受云服务可能存在的请求速率限制。
  • 数据隐私与安全:所有数据处理均在本地进行,增强了敏感数据的控制力。

实战演示:在WSL中运行Ollama

接下来,我们将在Windows子系统Linux中,使用Ollama平台来运行一个本地LLM。Ollama是一个专为在本地运行大型语言模型而设计的尖端平台。

首先,我们需要安装Windows子系统Linux。最简便的方法是通过Microsoft Store进行安装。关于此部分更详细的教程将在后续的本地LLM课程中提供,此处仅作预览。

安装完成后,我们打开终端。以下是运行Ollama及Llama 2模型的核心命令步骤:

  1. 获取并安装Ollama

    curl -fsSL https://ollama.ai/install.sh | sh
    

    此命令会下载安装脚本并执行,整个过程可能需要几分钟。

  2. 启动Ollama服务

    ollama serve
    

    运行此命令后,Ollama会启动一个本地服务,并检测你的计算机资源。请注意终端中显示的本地IP地址(通常是 http://127.0.0.1:11434)。

  3. 拉取并运行模型

    ollama run llama2
    

    这个命令会下载著名的Llama 2大型语言模型,并启动一个交互式聊天会话。之后,你就可以直接在终端与模型进行对话了。


演示结果与潜力

执行上述命令后,模型成功加载并运行。所有文本生成任务都完全在我的本地笔记本电脑上完成,不涉及任何云服务费用。虽然当前演示是在CPU上运行,但如果你拥有更强大的机器(如配备GPU),性能将得到显著提升,且完全不受云服务的速率限制。

在下一门课程中,我们将更深入地探讨如何调整这些模型的参数、进行微调等高级操作。但如演示所示,本地运行的模型已经具备了相当强大的文本生成能力。


总结

本节课中,我们一起学习了本地运行大型语言模型的趋势与优势。我们了解到,本地化部署可以更好地控制成本、规避风险并提升数据安全性。通过使用Ollama平台在Windows Linux子系统中的实战演示,我们预览了完全在本地机器上运行如Llama 2这样先进模型的可能性。这为后续深入学习如何构建和定制本地LLM应用奠定了坚实的基础。

大型语言模型实践:模块总结:第四模块核心回顾 🎯

在本节课中,我们将对第四模块的学习内容进行总结,回顾过去几节课程中掌握的核心技能与概念。

上一节我们探讨了AI伦理与商业环境安全,本节中,我们来系统回顾整个模块的知识体系。

以下是我们在本模块中学习的主要内容列表:

  • 配置开发环境:我们学习了如何设置集成了Copilot的GitHub Codespaces,这是一个AI结对编程工具。
  • 图像生成API应用:我们掌握了如何使用Dolly模型,通过API将文本描述转换为图像。
  • 模型微调:我们学习了如何根据特定用例,使用OpenAI平台对预训练模型进行微调。
  • 音视频内容摘要:我们同样使用OpenAI的技术,学会了如何总结音频和视频文件的内容。
  • AI伦理与前瞻:我们深入探讨了AI伦理、商业环境安全等议题,并对下一门关于本地大型语言模型的课程进行了预览。

本节课中我们一起学习了从环境搭建、多模态生成、模型定制到内容分析与伦理思考的一系列实践技能。这些知识为我们进一步深入理解和应用生成式AI奠定了坚实的基础。

恭喜你完成本模块的学习与测验。我们下一讲再见。

大型语言模型实践:P77:课程总结 🎉

在本节课中,我们将对《生成式AI简介》这门课程的核心内容进行回顾与总结。


课程概述

恭喜你完成了这门关于生成式AI介绍的课程。我们涵盖了大量内容,希望你现在对生成式AI是什么有了一个清晰而坚实的基础认识。

核心内容回顾

上一节我们介绍了部署架构,本节中我们来回顾整个课程的知识体系。以下是我们在课程中探讨的几个关键主题:

  • 生成式AI基础:我们明确了生成式AI的基本概念与范畴。
  • 提示工程:我们学习了什么是好的提示,以及提示工程的具体方法。
  • 检索增强生成:我们探讨了RAG的概念,以及如何实际实现它。这是一个开始接触时颇具挑战性,但在构建优秀、可靠的生成式AI应用时至关重要的组件。
  • 部署概览:我们快速浏览了如何将应用部署到云端。虽然我们没有深入探讨实现所需的所有具体步骤,但我们选择让你对架构如何工作、部署涉及哪些步骤有一个很好的了解。

将应用部署到生产环境是机器学习工程师需要完成的首要任务之一,即如何发布有用的产品并将其投入生产。

总结与展望

本节课中我们一起学习了生成式AI的基础知识、核心技术与部署思路。希望你对所获得的新知识感到满意,并且能够在尝试创建应用程序或开始做出领导决策时, empowered 地决定如何实施这些技术,或者在接近使用AI解决大问题的过程中选择何种路径。

大型语言模型实践:01:认识讲师阿尔弗雷德·德萨

在本节课中,我们将认识本课程的讲师阿尔弗雷德·德萨,并了解他的专业背景与课程内容的关联。

大家好,我是阿尔弗雷德·德萨。我很高兴为大家带来这门关于Azure平台上大型语言模型的课程。

我的经验和背景主要在自动化编程领域。我是一名资深的Python开发者,最近也在大量使用Rust编程语言进行开发。

此外,我在云技术领域有非常长时间的工作经验。这些年来,我的工作重点一直是自动化和构建健壮的基础设施。

我认为我的工作重点在于关注监控,以及在流程(例如一个流水线)运行过程中捕获细节。

在本课程中,当我们学习不同类型的内容时,你们会清楚地看到如何应用我过去的这些经验。

有趣的是,我们将学习如何将过去行之有效的方法,例如自动化、监控、密切关注细节,以及我们构建健壮且可靠的基础设施和应用程序的方法,应用到像大型语言模型这样的新技术上。

因此,结合我的背景,以及我在微软的工作经验,我希望你们能够对在Azure上运行的大型语言模型有一个非常透彻的理解。


本节课中,我们一起认识了讲师阿尔弗雷德·德萨,了解了他深厚的自动化编程与云技术背景,以及这些经验将如何帮助我们深入理解并实践Azure上的大型语言模型。

大型语言模型实践:P79:关于本课程 📘

在本课程中,我们将深入探讨大型语言模型(LLMs)的诸多细节,特别是结合微软的云平台Azure。我们不仅会学习大型语言模型的工作原理及其基础核心知识,还将掌握如何与Azure云平台进行交互。

我们将从最基础的部分开始,大量使用Azure门户(Azure Portal)来创建和管理资源。我会分享在部署这些资源时,关于创建和管理的最佳实践建议。

课程内容概览

上一节我们介绍了课程的整体目标,本节中我们来看看具体的课程安排。以下是本课程将涵盖的核心模块:

  • Azure平台上的LLMs:探讨在Azure上使用大型语言模型时的差异。例如,Azure OpenAI服务与在Azure机器学习工作室中部署其他大型语言模型有何不同?部署这些模型在计算资源方面有哪些区别?
  • 与LLMs交互:深入介绍如何与这些模型进行交互。我们将了解API的形态。虽然Azure OpenAI服务目前非常流行且备受关注,但我们也会探讨与这些新技术交互的其他方式。
  • 专业化应用开发:我们将尝试与API交互,并在应用程序中编写代码,以创建新的应用。交互方式不仅限于简单的问答模式,还会涉及增强功能。我们将讨论检索增强生成(Retrieval-Augmented Generation, RAG) 等概念,了解其含义,以及它如何利用新数据让潜在的应用变得更加有趣。
  • 集成与部署:在课程最后,我们将把所有概念整合起来,并能够将应用部署到云端。是的,我们将使用Azure云,并会稍微涉及容器和Docker技术。

学习方法与目标

整个课程将以非常实践的方式进行,确保你能亲手操作。你可以将这些示例应用到自己的项目中,从而在课程结束时,能够更自信地尝试与Azure、新的大型语言模型、不同的API以及所学到的各种知识进行交互。这样,你可以在尝试整合方案、深入学习Azure云时,选择最适合自己的策略。


总结:本节课中我们一起学习了本课程的整体框架和学习路径。我们将从Azure和LLMs的基础知识开始,逐步深入到API交互、高级应用开发(如RAG),最终完成一个集成项目的云端部署。课程注重实践,旨在帮助你获得直接可用的技能。

大型语言模型实践:03_01_01:引言

在本节课中,我们将学习Azure平台在大型语言模型应用方面的一些关键组成部分和差异。我们将介绍Azure OpenAI服务、Azure机器学习及其工作室,并了解一些学习本课程所需的基础知识。

Azure平台与大型语言模型

我们将首先探索Microsoft Learn平台。这是一个理解API、查找文档和示例的优秀资源。同时,我们也会了解Azure平台内部与大型语言模型相关的一些差异。

理解这些差异和概念,并知道去哪里寻找更多答案,对我们后续的学习至关重要。这将在课程后续内容中得到体现。

核心服务与工具

以下是本课程中将涉及的核心Azure服务与工具简介。

  • Azure OpenAI服务:这是微软Azure平台上提供的托管服务,允许开发者访问和使用OpenAI开发的大型语言模型。
  • Azure机器学习:这是一个用于构建、训练和部署机器学习模型的云端环境。
  • Azure机器学习工作室:这是一个基于Web的交互式工作区,用于在Azure机器学习中进行低代码或无代码的模型开发和操作。

课程学习基础

为了顺利进行本课程,你需要熟悉一些基础概念。以下是几个需要理解并感到舒适的关键点。

  • 了解云计算和API的基本概念。
  • 对机器学习有初步认识。
  • 能够使用Microsoft Learn等平台查找技术文档。

本节课中,我们一起学习了Azure平台中与大型语言模型相关的核心服务,包括Azure OpenAI服务和Azure机器学习。我们还明确了利用Microsoft Learn等资源进行自主学习的重要性,并概述了学习本课程所需的基础知识。在接下来的章节中,我们将对这些服务进行更深入的探讨。

大型语言模型实践:04:Azure门户介绍 🚪

在本节课中,我们将学习Azure门户的基础知识。Azure门户是管理和使用所有Azure服务的统一Web界面。了解其布局和核心功能,是高效使用Azure(包括Azure OpenAI服务)的第一步。

概述

上一节我们介绍了课程背景,本节中我们来看看Azure的门户界面。Azure门户是与Azure云平台交互的主要图形界面。无论您是要创建资源、管理服务还是查看账单,都需要通过这个门户进行操作。熟悉它的布局和功能,能帮助您更顺畅地开展后续工作。

门户首页布局

当您登录Azure门户后,首先看到的是首页。首页经过定制,会显示您最近访问过的服务和资源,方便快速跳转。

以下是首页的主要区域:

  • 常用服务区域:此区域会显示您最近访问过的服务。例如,在我的门户中,显示了存储账户、资源组和Azure OpenAI服务。
  • 资源列表:此区域显示您创建的具体资源实例及其名称。请注意“服务”与“资源”的区别:服务是一个类别(如Azure OpenAI),而资源是该类别下的一个具体实例(如一个名为“demo-alfredo-openai”的OpenAI服务)。

查看与管理资源

现在,让我们具体看看如何查看一个资源。如果我想查看Azure OpenAI服务,可以点击首页上对应的服务卡片。

进入Azure OpenAI服务页面后,您可以看到已创建的所有OpenAI资源实例。在这个页面,您可以管理该服务的各种设置。例如,您可以找到访问服务所需的密钥终结点,这些信息对于后续通过代码调用API至关重要。我们将在后续课程中详细探讨这些功能。

搜索功能

如果您在首页没有找到需要的服务或资源,可以使用顶部的全局搜索栏。

例如,如果我需要找到“Azure机器学习”服务,只需在搜索栏中输入名称即可。搜索功能支持模糊匹配,输入“Azure machine learning”后,它会列出相关结果。点击结果即可进入对应的服务页面。如果尚未创建任何资源,页面会引导您开始创建。

资源组的概念与管理

在Azure中工作时,理解“资源组”的概念非常重要。资源组是一个逻辑容器,用于将相关的Azure资源(如虚拟机、数据库、存储账户)组合在一起进行统一管理。

资源组的主要优势在于生命周期管理。您可以将为一个项目或演示创建的所有资源放入同一个资源组。

例如,我有一个名为 demo-ml 的资源组,其中包含了我为某个机器学习演示创建的所有资源:一个存储账户、一个密钥保管库、一个应用程序洞察实例等。

当项目结束,需要清理所有资源时,您无需逐个删除每个服务。只需删除整个资源组,Azure就会自动删除该组内的所有资源。这极大地简化了资源清理工作。

在门户中删除资源组的操作如下:

  1. 进入目标资源组页面。
  2. 点击“删除资源组”按钮。
  3. 在弹出的确认框中输入资源组名称进行确认。
  4. 确认后,该资源组及其包含的所有资源将被永久删除。

其他管理工具

最后需要了解的是,Azure门户并非管理Azure的唯一方式。根据您的习惯和自动化需求,还可以选择其他工具:

  • Azure CLI:基于命令行的工具,适合脚本化和自动化任务。
  • Azure SDK:支持多种编程语言(如Python, .NET),允许您通过代码来创建和管理Azure资源。

总结

本节课中,我们一起学习了Azure门户的核心功能。我们了解了门户首页的布局,学会了如何查找和管理服务与资源,掌握了使用搜索功能快速定位目标,并深入理解了资源组作为逻辑容器对于资源管理的重要性。最后,我们还了解到除了门户,还可以使用Azure CLI和SDK进行管理。掌握这些基础知识,将为您后续在Azure上部署和操作大型语言模型打下坚实基础。

大型语言模型实践:P82:05_01_04_使用 Microsoft Learn 📚

在本节课中,我们将学习如何有效利用 Microsoft Learn 平台。该平台是学习和使用 Azure 服务,特别是与大型语言模型(LLM)相关服务的重要资源。我们将了解其核心组成部分,包括代码示例、技术文档和培训路径,并掌握如何通过这些资源来加速你的学习和开发进程。

概述 Microsoft Learn 平台

Microsoft Learn 是一个综合性的学习平台,其网址是 learn.microsoft.com。当你使用 Azure 或学习我们即将介绍的 LLM 运维及大型语言模型相关内容时,这个平台会是你熟悉且重要的工具。实际上,对于任何与 Azure 相关的工作,你都应该访问这个平台。

平台的核心组成部分

Microsoft Learn 的首页提供了多种资源,例如动手实践、技术文档等。我们可以将这些资源大致分为几个非常重要的部分:文档培训代码示例

上一节我们介绍了平台的整体情况,本节中我们来看看具体的资源类型。

代码示例

首先,让我们从代码示例开始。点击页面上的“代码示例”入口。

进入后,你可以通过搜索找到特定主题的示例。例如,搜索“Open AI”并回车。

搜索结果中会显示相关的代码项目,例如“使用 Azure SQL 和 Azure OpenAI 进行向量相似性搜索”。点击该项目,你可以看到具体的代码示例。

这些示例可以帮助你扩展在特定领域的知识。例如,这个示例展示了如何将 Azure SQL 和 Azure OpenAI 服务集成在一起,以及如何创建向量表。如果你对这方面感兴趣,这些示例是非常好的学习材料。

技术文档

那么,代码示例和文档有什么区别呢?现在,让我们进入“文档”部分。

同样,你可以进行搜索。例如,搜索“Azure OpenAI 服务”并回车。

你将获得与该特定服务紧密相关的详细文档。例如,你会看到一个关于 Azure OpenAI 服务的文档首页,其 URL 类似于 learn.microsoft.com/azure/ai-services/openai

这个页面是关于该服务所有文档的根目录。它提供了各种内容,例如快速入门指南和详细的功能说明。

以下是文档页面通常包含的内容结构:

  • 快速入门:帮助你快速开始使用服务。
  • 概念:解释服务的核心原理和组件。
  • 教程:提供分步指导的实践指南。

让我们快速浏览一下教程。假设你想学习如何对 GPT-3.5 Turbo 模型进行微调。

点击相关教程后,它会引导你完成所需的所有步骤。文章会列出所有先决条件,并提醒你可能遇到的一些限制和注意事项。这非常有用。

有时,文档还会针对不同编程语言(如 Python)提供特定的实现细节。

培训与学习路径

最后一部分是“培训”。点击进入后,你会看到各种“学习路径”。

学习路径允许你按照特定的知识体系进行系统学习。你需要登录以跟踪学习进度。

虽然培训路径很有用,但我建议首先从代码示例和文档入手。这两者是你在使用 Azure 进行 LLM 开发时,取得进展和解决问题的非常有用的第一站。

总结

本节课中,我们一起学习了如何利用 Microsoft Learn 平台。我们了解了它的三个核心部分:代码示例技术文档培训路径。对于初学者,建议优先查阅代码示例来获得实践灵感,并通过详细的技术文档来深入理解特定服务(如 Azure OpenAI)的用法。这个平台是学习和掌握 Azure 云上大型语言模型相关技术不可或缺的助手。

大型语言模型实践:P83:识别Azure AI解决方案 🔍

在本节课中,我们将学习如何在Azure平台上识别和区分两种核心的机器学习服务:Azure OpenAI服务Azure机器学习。我们将了解它们各自的功能、定位以及适用场景。


Azure OpenAI服务 🤖

上一节我们介绍了课程目标,本节中我们来看看第一种服务:Azure OpenAI服务。该服务允许你在Azure环境中直接部署和使用来自OpenAI的模型。

在Azure门户中,你可以找到“Azure OpenAI服务”。我已经创建了一个实例。我们无需深究创建细节,但可以快速浏览其功能。

进入Azure OpenAI Studio后,你将看到可以与OpenAI模型交互的能力。关键点在于:Azure OpenAI服务中的模型并非运行在OpenAI的服务器上,而是运行在Azure内部。这意味着这些模型部署在你自己的Azure订阅中,是一个独立的服务。

以下是该服务的主要特点:

  • 你可以选择并部署一系列OpenAI模型。
  • 这些模型会持续更新和刷新。
  • 你可以完全独立地管理这些模型,并设置任何你想要的约束和配置。

Azure机器学习 🧠

了解了专注于OpenAI模型的Azure OpenAI服务后,我们再来看看功能更广泛的Azure机器学习服务。

回到Azure门户,进入“Azure机器学习”。这里我已经有一个服务实例。点击进入并启动“Azure机器学习工作室”。这个平台与Azure OpenAI服务不同,它提供了更广泛的模型和工具。

在Azure机器学习工作室中,你不仅可以访问一些语言模型,还能使用包括视觉模型在内的其他类型模型。更重要的是,它提供了一系列工具,让你能够从头开始创建和定制自己的模型。

以下是该平台提供的一些核心工具:

  • 自动化机器学习:你可以上传自己的数据,让Azure在后台自动尝试构建和优化模型。
  • 教程与资源:平台提供了丰富的学习资源,例如如何创建你的第一个分类模型或生成准确预测的教程。
  • 设计与提示流:还有其他工具(如设计器和提示流),它们能帮助你创作模型,并在需要实时推理时进行部署。

目前,我还没有部署任何端点,因此系统提示我创建一个。这正体现了该平台的核心功能之一:部署你自己创建或管理的模型端点。


服务对比与总结 📊

本节课中,我们一起学习了Azure平台上两种关键的AI服务。

  • Azure OpenAI服务:专门用于部署和管理来自OpenAI的预训练模型。它提供了一个直接、集成的环境来使用这些先进的生成式AI模型。
  • Azure机器学习:是一个功能更全面的机器学习平台。它不仅允许你部署包括OpenAI模型在内的多种模型,更重要的是,它提供了强大的工具集(如自动化机器学习),支持你使用自己的数据从头开始构建、训练和部署自定义模型。

理解这两者的区别非常有用。简单来说,Azure OpenAI服务专注于OpenAI模型的托管与使用,而Azure机器学习是一个支持全生命周期(从构建到部署)的综合性机器学习平台

大型语言模型实践:P84:Azure机器学习简介 🚀

在本节课中,我们将学习如何在Azure门户中开始使用Azure机器学习工作室。我们将创建一个新的机器学习工作区,并探索其核心功能,包括模型管理、计算资源设置等。

概述

Azure机器学习是一项云服务,用于加速和管理机器学习项目生命周期。本节将指导你完成创建工作区、了解其界面以及配置基本计算资源的过程。

创建工作区

上一节我们介绍了Azure机器学习的定位,本节中我们来看看如何创建一个新的工作区实例。

首先,在Azure门户中,你需要找到Azure机器学习服务。如果它没有显示在“最近使用的服务”列表中,你可以通过顶部搜索栏进行查找。

输入“Azure Machine Learning”进行搜索,然后从结果中选择该服务。

进入服务页面后,你可以看到之前创建的所有工作区。为了进行演示,我们将创建一个新的工作区。点击“创建”按钮开始。

创建工作区时,需要填写一些基本信息。为资源组选择一个有意义的名称非常重要,这有助于你日后管理和识别资源。例如,可以命名为 demo-azure-machine-learning

创建工作区时,Azure会自动创建一些必需的关联资源,包括:

  • 存储账户:用于存储数据、模型和日志。
  • 密钥保管库:用于安全地管理密钥和机密。
  • Application Insights:用于监控应用程序性能。

需要注意的是,容器注册表默认不会自动创建。如果你需要构建和使用Docker容器,可以在此处选择创建新的注册表。在本演示中,我们保持默认的“无”选项。

填写完所有信息后,点击“审阅并创建”。系统会进行验证,并确认部署区域。确认无误后,点击“创建”。部署过程需要几分钟时间。

探索机器学习工作室

创建工作区后,点击“转到资源”。在资源页面,最重要的操作是点击“启动工作室”,这将打开Azure机器学习工作室的Web界面。

工作室界面左侧是导航栏,提供了各种功能的入口。例如,“笔记本”部分允许你创建和运行Jupyter Notebooks。系统还提供了丰富的教程和示例,是初学者入门的好帮手。

在“模型”目录中,你可以看到包括Azure OpenAI模型在内的多种模型。但需要注意的是,若要部署Azure OpenAI模型(如GPT系列),系统会引导你到专门的Azure OpenAI资源中去完成,而不是直接在机器学习工作室内部署。

管理模型与计算资源

上一节我们浏览了工作室界面,本节中我们来看看如何管理模型和配置计算资源。

在“模型”页面,你可以注册、上传或导入自己训练的模型。如果从本地文件上传,可以使用 上传文件 功能。

“终结点”页面用于管理已部署的模型服务,你可以创建实时终结点或批处理终结点。

“计算”部分是配置算力的核心。以下是主要的计算类型:

  • 计算实例:一种完全托管的云工作站,主要用于数据探索、模型开发和测试。适合作为交互式开发环境。
  • 计算集群:可自动缩放的虚拟机集群,用于大规模训练作业或批处理推理。当没有作业运行时,可以自动缩放到零节点以节省成本。
  • Kubernetes集群:可用于高级部署和模型服务场景。
  • 附加计算:允许你附加Azure中已有的计算资源(如虚拟机或Kubernetes集群)。

创建计算实例时,你可以选择不同的虚拟机类型。例如,如果需要GPU加速,可以在筛选器中选择“GPU”。选择适合的规格后,点击“创建”即可。

总结

本节课中我们一起学习了Azure机器学习的基础操作。我们创建了一个新的工作区,探索了Azure机器学习工作室的界面,并了解了如何管理模型以及配置计算实例和集群等核心计算资源。这些是使用Azure平台进行机器学习项目开发的第一步。

大型语言模型实践:1.1:Azure OpenAI服务简介 🚀

在本节课中,我们将学习如何在Azure门户中创建和配置Azure OpenAI服务实例。我们将从访问门户开始,逐步完成资源创建、配置网络选项,并最终在Azure OpenAI Studio中部署一个聊天模型进行交互。


访问Azure门户与服务

首先,我们需要回到Azure门户并找到OpenAI服务。

如果你最近使用过该服务,可以在资源列表中找到它。如果你已经部署或创建了一个Azure OpenAI服务实例,它会直接显示在资源列表中。

如果你尚未部署或访问过Azure OpenAI服务,则需要通过搜索或服务列表来定位它。我将点击该服务进入。

假设我目前没有任何现有资源,我将创建一个新的实例。


创建新资源

以下是创建新资源的具体步骤。

1. 选择订阅与资源组
在创建过程中,你需要选择一个订阅,并决定是创建一个新的资源组还是复用现有的。本例中,我选择创建一个新的资源组。

2. 命名资源组
我将这个新资源组命名为 demo-azure-openai。请注意,OpenAI的拼写要正确。点击“确定”以确认创建,这有助于后续统一管理和清理所有相关资源。你可以看到,我之前删除其他资源组时收到了相应的通知。

3. 选择区域
区域选择非常重要,因为配额(Quota)是按区域分配的。点击区域下拉菜单,你可以看到所有可用区域。请确保你选择了拥有配额的正确区域。

4. 填写实例详情
接下来填写实例详情。我将服务实例名称也设为 demo-azure-openai。请注意,服务实例名称不必与资源组名称相同,但如果该名称在Azure OpenAI服务的全局域名中已被占用,你会遇到问题。

这是因为服务会创建一个唯一的子域名(DNS记录)。我通常会在名称中加入自己的名字(例如 demo-azure-openai-alfredo)来确保其唯一性。

5. 选择定价层
目前只有一个“标准(Standard)”定价层可供选择。你可以点击查看完整定价详情,这会打开一个新标签页。我选择标准层,然后点击“下一步”。


配置网络与安全

上一节我们完成了基本设置,本节中我们来看看如何配置网络访问。

在配置步骤中,系统会询问你希望如何公开即将部署的模型。这是Azure OpenAI服务特有的设置,使其与其他服务区分开来。

你有几个选项:可以将其完全置于防火墙后,或配置私有端点来完全禁用公共访问。你也可以选择特定网络并配置Azure AI服务的网络安全性。

考虑到演示目的,我将保持所有网络开放。点击“下一步”继续。


完成创建与部署

接下来是可选的标签步骤,用于在Azure中标识服务,我将其留空。最后,点击“审阅并提交”,然后点击“创建”。

这将初始化并提交部署任务。你会看到部署进度,资源开始被配置。我们等待部署完成。

部署已成功。点击“转到资源”按钮。


获取密钥与终结点

一个重要的注意事项是:密钥和终结点信息会显示在资源的概览页面上,而不是在Azure OpenAI Studio中。

点击进入后,你可以在这里找到通信所需的终结点(Endpoint)。这就是所有模型的统一访问地址。同时,你还需要使用密钥(Keys)进行身份验证。

让我们回到概览页,点击“在Azure OpenAI Studio中探索”。


使用Azure OpenAI Studio

一旦Azure OpenAI Studio加载完成,你会看到聊天游乐场(Chat Playground)、补全游乐场(Completions Playground)等界面。

我们重点看一下聊天游乐场,这可能是你最感兴趣的部分。要开始使用,你需要先创建一个新的部署。

1. 创建部署
在这里,你可以选择模型和版本,并为其命名。例如,我将其命名为 test-chat。你还可以为令牌(Tokens)设置高级选项,因为计费是基于令牌使用量进行的,这一点我们后续会详细讲解。

2. 开始交互
部署完成后(这个过程非常快),你就可以选择助理角色、设置系统消息,并开始聊天了。例如,我输入“Hi chatbot”,它回复“Hello! Can I assist you today?”。这样,你立即就拥有了一个可以交互的AI助手。


管理部署与模型

除了交互,你还可以管理部署和配置参数。

1. 部署管理
在管理部分,你可以看到我的 test-chat 部署,包括模型名称、版本、部署类型、容量和状态。

2. 模型库
进入“模型”部分,你可以看到可用的各种模型。你还可以创建自定义模型或上传数据文件,以便对模型进行微调(Fine-tuning)。这对于定制化需求非常有用,但如果你不熟悉微调概念,可能会有些复杂。

3. 配额与使用量
“配额(Quotas)”部分非常实用,你可以在这里查看使用量限制。例如,部署了 gpt-35-turbo 模型后,其使用限制就会显示在这里。

4. 内容过滤器
“内容过滤器(Content Filters)”也很有用。你可以创建自定义的内容过滤器,或者在配置模型时添加默认的内容过滤策略。


总结

本节课中,我们一起学习了Azure OpenAI服务的完整创建与配置流程。我们从访问Azure门户开始,逐步创建了资源组和服务实例,配置了网络选项,并最终在Azure OpenAI Studio中成功部署并测试了一个聊天模型。Azure OpenAI服务提供了丰富的管理功能,包括模型部署、配额管理和内容过滤,使得构建和定制AI应用变得简单快捷。

大型语言模型实践:1.1:Azure LLM基础概念总结 🎯

在本节课中,我们将学习与大型语言模型交互时,涉及到的Azure平台基础概念。我们将回顾Azure门户、关键的AI服务,并介绍一个重要的学习资源。

上一节我们介绍了课程的整体背景,本节中我们来总结在Azure平台上操作大型语言模型所涉及的核心基础概念。

我们梳理了几个与大型语言模型相关的、用于和Azure交互的基础概念。

我们初步了解了Azure门户的界面。我们识别了不同的AI服务,例如Azure机器学习工作室Azure OpenAI服务

我们还查看了Microsoft Learn平台。此处引入Microsoft Learn,是因为它是一个非常优质且可靠的资源。在你学习本课程内容以及未来寻求更多细节或了解技术更新时,都可以利用Microsoft Learn来推进学习。技术发展日新月异,该平台能帮助你紧跟变化。

本节课中我们一起学习了Azure门户的基本面貌、两大核心AI服务(Azure机器学习工作室与Azure OpenAI服务),以及持续学习的重要资源Microsoft Learn。这些是开始在Azure平台上探索和实践大型语言模型操作的重要基础。

大型语言模型实践:1:引言与概述

在本节课中,我们将学习大型语言模型的基础知识,包括其工作原理、核心特性、潜在优势与风险,以及整个课程的学习路径。

课程概览

对大型语言模型有一个整体认识,对于整个课程的学习至关重要。

大型语言模型简介

上一节我们介绍了课程概览,本节中我们来看看大型语言模型本身。我们将从大型语言模型入手,具体探讨它们如何工作,以及它们具备哪些特性。

我们不会深入过多技术细节,但了解其基本原理,将有助于我们在后续课程中更好地使用大型语言模型。

LLM的工作原理与特性

我们将探讨大型语言模型在底层究竟是如何运作的。以下是其核心工作原理的简要说明:

  • 核心机制:大型语言模型基于海量文本数据进行训练,学习预测给定上下文后最可能出现的下一个词或标记。其核心是一个包含数十亿甚至万亿参数的Transformer神经网络架构。
  • 工作方式:模型接收一段文本输入(称为“提示”或“上下文”),通过其内部复杂的计算,生成一个概率分布,输出最可能跟随的下一个词序列。

优势、风险与缓解措施

在了解其原理后,我们还需要认识其两面性。我们将看到大型语言模型带来的一些好处,同时也存在风险,以及如何具体地缓解这些风险。

以下是大型语言模型的主要优势与风险点:

  • 优势
    • 强大的内容生成与理解能力。
    • 能够执行多种任务,如翻译、总结、问答。
    • 通过微调可以适应特定领域。
  • 风险与缓解
    • 风险:可能生成错误、有偏见或不安全的内容。
    • 缓解措施:通过精心设计提示词、实施内容过滤、进行人类反馈强化学习等技术来降低风险。

关于LLM Ops

最后,我们非常高兴能正式开始讲解LLM Ops。在后续视频中,我将介绍大型语言模型的生命周期,探讨其含义,并学习如何在课程推进中利用这些知识。

本节课中我们一起学习了大型语言模型的基本概念、工作原理、优势与风险,并对即将深入学习的LLM Ops(大型语言模型运维)领域进行了展望。这些基础知识将为我们后续的实践学习奠定坚实的基础。

大型语言模型实践:1.1:什么是大语言模型及其工作原理 🧠

在本节课中,我们将要学习大语言模型(LLM)的基本概念及其核心工作原理。我们将从理解文本如何被模型处理开始,逐步揭示其作为“概率机器”的本质。

要理解大语言模型及其确切的工作原理,我们首先需要从“词元”开始,理解什么是“词元化器”。我们有一段文本提出了问题:“什么是词元化器?”其确切含义是,词元化器是一个将文本(例如这里的这个短语)转换为数字的过程。大语言模型将以文本作为输入,并生成文本作为输出。

但这是如何发生的呢?其过程是处理像这样的一个短语,并将其分割成更小的块。例如,其中一个块可能是什么?其中一个片段将被转换为一个数值。在这种情况下,“what”这个词或许会被转换为一个数值,比如318。所有这些片段最终都将被转换为数字,并被放入一种数组中。这是机器随后能够处理它们并尝试更好地识别它们的方式。通过使用数值来表示这些片段,我们创建了一种索引。这个索引是原始文本块的编码。

我们之所以说“块”或“片段”,是因为它不一定按单词划分。在这里,我们可能会说“what is a”是一个块。但它也可能包含一些空格,空格本身也可能被表示为一个完整的块。有时,词元化器甚至会将一个单词分割成两部分。像这样的问号也可能构成一个块。所有这些表示方式将使机器学习模型更容易理解文本。否则,对于机器来说,这是目前理解文本的最佳方法。

以上是分析部分,或者说,是将这些文本块分割并转换为数值的过程。那么,我们这里处理的究竟是什么?我喜欢称之为“概率机器”。为什么是概率机器?它只是试图理解所有这些较小的文本块(或者说词元),并尝试预测从一个词元到下一个词元的精确概率。例如,从这个词元到第二个词元,再到第三个、第四个,依此类推。因此,以一种过度简化的方式解释,它本质上只是一个概率问题。基于海量的文本,我们将看到一个机器学习模型试图确定,给定一段文本,所有后续词元的概率是什么。

这就是为什么我想强调这正是一台概率机器。这样思考这些模型也很容易,因为有时它们表现得非常出色,像一台能输出事实的机器。即使某些生成的文本看起来准确、正确且符合现实,我们也不应将其视为事实机器。因为它的本质只是概率:给定特定的输入,基于训练文本的数量,下一个输入、下一个块、下一个片段、下一个词元是什么的概率。

以“今天是个晴天,并且……”这样的短语为例。这个短语是理解“……”部分将是哪个特定单词的概率的完美方式。在这种情况下,“今天是个晴天,并且……”后面很可能是一个“好”字。这意味着什么?基于训练文本的数量、文本本身、将文本分解为词元的过程以及生成的所有索引,机器理解到,你很可能想要的是“好”这个词,甚至可能前面还有一些空格,以便生成的文本能被正确表示。

所以,本质上,这就是具有大语言生成能力的机器学习模型、大语言模型和文本生成的工作原理:首先通过分解文本来创建索引,然后作为一台概率机器运行。


本节课中,我们一起学习了:

  1. 词元化:文本被分割成“词元”并转换为数值索引的过程。
  2. 概率本质:大语言模型的核心是基于海量文本数据,计算并预测下一个最可能出现的词元。
  3. 工作原理:模型通过“词元化-索引化”处理输入,再以“概率机器”的方式生成连贯的文本输出。

理解这些基础概念是掌握大语言模型后续应用与操作的关键。

大型语言模型实践:第12章:使用大语言模型的优势与风险 🧠

在本节课中,我们将探讨使用大型语言模型(LLMs)的优势与潜在风险。我们将通过具体的实例,帮助你理解如何有效利用这些工具,同时识别并规避其可能产生的问题。


概述

大型语言模型是强大的工具,能够生成文本、总结信息并协助创作。然而,它们并非完美无缺。本节我们将通过实际操作案例,分析其带来的便利与需要警惕的陷阱。


优势:作为创意与效率的起点

上一节我们介绍了LLMs的基本概念,本节中我们来看看它的实际应用优势。一个核心优势是LLMs可以作为内容创作的快速起点。例如,当你需要一份个人简介时,它可以快速生成一个草稿。

以下是一个向ChatGPT请求生成个人简介摘要的例子:

# 用户输入示例
用户: “给我一个关于Val Farodesa的摘要。”

模型可能生成如下看似准确的回复:

“Val Farodesa在Python打包相关项目中做出了重要贡献,并积极参与开源社区...”

这个回复包含了有用的结构和部分正确信息(如参与开源社区),可以作为进一步修改和完善的基础。这节省了从零开始撰写的时间。


风险:信息不准确与“幻觉”

然而,我们必须认识到LLMs存在信息不准确的风险。它们本质上是概率机器,其工作原理可简化为:

公式:P(输出 | 输入, 训练数据)

模型根据给定的输入和其训练数据中的模式,计算最可能出现的下一个词或句子序列。这意味着它生成的是“看似合理”的文本,而非经过验证的事实。

在之前的例子中,模型声称“我”在Python打包方面有贡献,但这并不属实。这种错误被称为“幻觉”(Hallucination)。

为了进一步探究,我们可以尝试提出更具体或更私人的请求,模型可能会出于隐私考虑而拒绝,这本身也是一种风险控制机制。

# 用户输入示例
用户: “Alfredo是一个懂技术的秘鲁人,请为他创建一个简短的传记。”

模型可能回复:

“出于对隐私的尊重,未经本人同意,我无法创建个人传记信息...”

但当调整提问方式,表明是“我”需要一份用于项目的简介时,模型又可能生成包含部分错误信息(如错误的出生日期或技能)的内容。

以下是另一个模型(Claude AI)生成的错误信息示例列表,请注意其不准确之处:

  • 职业错误:声称“我”是数学家。
  • 事实错误:给出了错误的出生日期。
  • 技能错误:断言“我”精通Java和Ruby on Rails,而这并非事实。

这个例子清晰地表明,对于模型生成的内容,尤其是涉及具体事实时,必须进行仔细的核实。


优势:有效的文本总结与改写

尽管存在风险,LLMs在文本处理任务上表现卓越。例如,在文本总结方面,它们非常有用。

你可以要求模型对一段长文本进行总结,甚至可以指定总结的长度或风格。

# 用户输入示例
用户: “将以下段落总结为两句话:[此处插入长段落]”

模型能够生成简洁、准确的摘要,这比处理模糊的、事实性不强的提问要可靠得多。这种能力使其成为处理文档、研究论文或长报告的得力助手。


核心总结与行动指南

本节课中我们一起学习了使用大型语言模型的双面性。

主要优势包括

  • 快速生成内容:为写作、编程、策划提供灵感和初稿。
  • 高效总结与改写:快速提炼长文本的核心信息或改变其表述方式。

主要风险与注意事项包括

  • 信息不准确:模型可能生成看似合理但完全错误的事实(幻觉)。
  • 需要事实核查:绝不能将模型输出直接当作事实使用,必须进行人工验证。
  • 理解其本质:牢记LLMs是生成“最可能”文本的概率模型,而非知识数据库。

最终,成功使用大型语言模型的关键在于批判性思维。你应将其视为一个强大的、但需要监督的协作伙伴,始终对输出内容负责,并核实所有关键信息。

大型语言模型实践:13:大语言模型风险缓解策略 🛡️

在本节课中,我们将要学习如何理解和缓解大型语言模型(LLMs)在实际应用中可能遇到的风险。我们将介绍四种主要的风险缓解策略,并分析它们在难度、成本和质量方面的权衡。

为了有效缓解并深入理解如何实际应对LLMs的一些风险,下面这张图表非常有用。

策略一:提示工程 ✍️

让我们从最顶层的“提示工程”开始。提示工程是我们向专门从事语言生成的机器学习模型提供输入、准确描述问题或指令的方式。当我们精心设计一个高质量的提示时,我们通常会得到更好的结果。

在图表顶部,这代表了一件相对容易操作的事情。它的难度最低,是你在这个层面上最容易做的事情。随着我们向图表右侧移动,难度和成本都会增加。提示工程的成本几乎为零,难度也大大降低。这意味着我们的任务仅仅是能够为机器学习模型描述一个好的输入。

然而,在质量方面,我们得到的结果质量相对较低。我们可以有一个非常好的提示,但如果模型本身不擅长手头的任务,效果也会有限。举个例子,如果你试图为一个特定国家的法律程序或法律问题获取准确的回答,而模型没有接受过相关训练或缺乏相关知识,那么仅靠提示工程可能帮助不大。

策略二:检索增强生成(RAG) 🔍

接下来,我们讨论“检索”或“搜索”,也就是检索增强生成。这意味着我们可以将搜索与提示工程结合起来。

具体来说,你可以将多种操作组合起来:首先根据提示内容进行搜索,然后将搜索结果作为提示的一部分输入给模型。这本质上会比单纯的提示工程稍微复杂一些,也会涉及更高的成本。

对于检索增强生成或RAG(本质上就是搜索),你需要某种存储系统和搜索引擎来实现。在质量方面,它会比单纯的提示工程有所提升。例如,某些模型是基于过去事件训练的,你可以通过检索搜索来缓解这个问题,因为你可以用更相关、更新的数据来持续更新搜索内容。

策略三:微调 🎛️

继续深入,我们将进入“微调”阶段。微调要复杂得多,你需要大量的数据,并且需要一个持续的过程来用这些额外数据训练模型并进行微调。

这比检索增强生成或提示工程要困难得多,当然成本也更高。为了快速完成微调,你可能需要一些GPU。然而,在质量方面,如果微调做得很好,你会获得更高的质量。不过,我个人的偏好仍然更倾向于检索增强生成和提示工程,因为微调的难度较大。

策略四:从头训练模型 🏗️

最后一项,我在这里标为第四点,就是“训练模型”,即从头开始训练一个模型。同样,这也是大多数大型语言模型必须做的事情,因为它们需要生成一个实际的模型。

这将是难度和复杂度的顶峰,也是你在这里能看到的最昂贵的操作。至于质量,根据你的目标,它可能会达到更高的水平,也就是更好的质量。

总结与综合应用 💡

理解如何缓解一些风险,从这里你可以很好地了解所有不同的步骤和选项。比较提示工程和从头训练模型意味着什么?这对成本和难度又意味着什么?当然,还有它们与质量的关系。

有些方法在缓解特定风险时可能更成问题,无论如何你可能都需要使用一些防护措施。需要明确的是,这些部分——比如这里的提示工程——并不意味着如果你在训练模型,就不能使用提示工程了。你完全可以在训练模型的同时,也使用提示工程、微调、检索增强生成或搜索,并将所有这些方法很好地结合起来运用。

因此,你对这些策略理解得越透彻,你就能掌握越多的工具和方法,以便在处理大型语言模型时,能够更好地缓解可能遇到的问题。


本节课总结

本节课中,我们一起学习了四种缓解大型语言模型风险的核心策略:

  1. 提示工程:成本低、难度小,通过优化输入指令来提升输出质量。
  2. 检索增强生成(RAG):中等成本和难度,通过结合外部实时信息来增强模型的准确性和时效性。
  3. 微调:高成本和高难度,使用特定领域数据对预训练模型进行进一步训练,以提升在特定任务上的性能。
  4. 从头训练:最高成本和难度,完全从零开始构建模型,能获得最高的定制化程度,但资源消耗巨大。

理解这些策略的权衡(成本、难度、质量)有助于我们根据实际需求和资源,选择最合适的组合方法来构建可靠、高效的LLM应用。

大型语言模型实践:14:LLM运维简介 🚀

在本节课中,我们将要学习大型语言模型运维(LLM Ops)的基本概念。LLM Ops 涵盖了从数据准备、模型选择到部署和监控的完整流程,旨在确保基于大语言模型的应用能够高效、稳定地运行。我们将逐一拆解这个流程中的关键环节。

数据准备 📊

一切始于数据。你可能拥有数据,也可能完全没有。例如,如果你只想进行文本摘要,可能不需要依赖特定数据。但如果你有一个专业领域,比如拥有大量关于葡萄酒的描述数据,并希望构建一个葡萄酒相关的服务,那么数据就是必需的。

模型选择 🤖

在拥有数据并确定目标后,下一步是选择合适的模型。你很可能需要复用一些现有的模型,并选择一个能契合你特定任务需求的模型。市面上存在许多不同类型的模型,它们经过了各种专门的调优。

一个很好的例子是 Codex,这是一个专门处理代码和开发者任务的大型语言模型,擅长生成代码。而其他不专注于编码的语言模型可能就不适合此类任务。

测试与评估 🧪

选定模型后,需要进行测试。这里的测试将对你的任务目标进行评估,以判断模型的表现是否符合预期。

数据与搜索集成 🔍

根据你所拥有的数据,它可能代表某种交互,但除非你使用某种搜索机制,否则这种交互无法体现。如果你需要数据,并且希望数据能持续更新(例如,每天都有新数据加入),你就需要建立一种方式,让数据与搜索系统通信,将数据存储在搜索系统中,并建立相应的处理流程。

自动化与检索增强生成 🤖

以上提到的过程,尤其是数据和用于检索增强生成(RAG) 的搜索部分(我们稍后会详细讨论),需要某种自动化和步骤来使其无缝衔接。

提示工程 💬

第五个环节是提示和提示工程。这涉及你如何设计和构建提示,以使得与大语言模型的交互顺畅高效。

部署与打包 🚢

接下来是第六步:部署。你需要进行打包,确保所有组件正常工作,并考虑扩展性。你很可能需要将应用部署到云端。

部署过程同样需要设置自动化和检查步骤,以防止在付出大量努力后系统出现问题。在你定义了模型、进行了测试、处理了大量数据、优化了提示工程、并将数据集成到搜索系统后,你希望让这个模型变得有用。

监控与持续改进 📈

最后,当然还需要有能力监控模型的性能和行为,尤其是在模型部署后,开始服务真实用户时。你选择的模型可能经过了微调,或者集成了搜索引擎以提供有意义的响应。所有这些组件、步骤和环节都需要自动化,需要被持续监控、检查和改进。

这是一个永无止境的过程。即使实现了全自动化,你的数据仍可能出问题,质量可能下降。因此,你必须部署一些检查和自动化流程来处理这些问题,防止其再次发生。

所有这些部署流程、打包、验证、推理、监控指标、数据漂移检测,以及建立可重复的模式、流水线和步骤,就是大型语言模型运维(LLM Ops) 的全部内容。


本节课中,我们一起学习了LLM运维的核心流程。我们从数据准备出发,探讨了如何根据任务选择合适的模型,并强调了测试评估的重要性。接着,我们了解了将数据与搜索系统集成以实现持续更新的必要性,以及自动化提示工程在其中的关键作用。最后,我们涵盖了应用部署的步骤和持续监控与改进的循环,明确了LLM Ops是一个确保大语言模型应用全生命周期高效、稳定运行的综合性实践。

大型语言模型实践:P92:15_01_06_总结_1

在本节课中,我们将总结关于大型语言模型(LLM)的基础知识、其工作原理、相关风险以及一个重要的实践框架——大型语言模型运维(LLMOps)。

大型语言模型概述

上一节我们介绍了大型语言模型的基本概念,本节中我们来总结其核心要点。我们探讨了大型语言模型的具体细节及其工作原理。

分词器与模型工作机制

我们特别介绍了分词器(Tokenizer)的作用。它是将文本转换为模型可处理数字(令牌)的关键组件。其工作流程可以简化为:
文本 -> 分词器 -> 令牌ID序列 -> 模型处理

大型语言模型的优势与风险

我们分析了使用大型语言模型带来的益处和潜在风险。了解这些风险对于安全、负责任地使用AI技术至关重要。

以下是大型语言模型的主要风险类别:

  • 生成不准确或虚假信息(幻觉)
  • 输出可能存在偏见或有害内容
  • 存在数据隐私和安全问题
  • 可能被用于制造误导性信息

风险缓解策略

认识到风险后,我们探讨了如何缓解这些与大型语言模型相关的风险。这包括实施内容过滤、持续的人类监督以及遵循伦理开发准则。

当前可用模型的注意事项

观察当前作为网络应用程序免费提供的普通大型语言模型所存在的一些注意事项和潜在问题,这很有意义。关注这些缺陷和风险非常重要,以便你能对其有充分的理解。

大型语言模型运维简介

最后,我们简要介绍了LLMOps(大型语言模型运维)。这是本课程的基础,我们将看到从数据到应用和部署的自动化及其生命周期,在后续课程中如何协同工作。

课程总结

本节课中我们一起学习了大型语言模型的核心机制、其双面性(优势与风险)以及管理其生命周期的LLMOps框架。理解这些基础概念是进一步学习和安全应用生成式AI的关键第一步。

大型语言模型实践:P93:16_01_01_引言_3

📖 概述

在本节课中,我们将学习在Azure平台上部署大型语言模型(LLM)的多种不同方式。我们将探索并评估Azure上的相关服务,包括Azure Machine Learning和OpenAI服务。我们不仅会了解部署选项,还会深入分析Azure Machine Learning Studio与Azure OpenAI服务之间的具体区别,以及在不同场景下如何选择使用它们。


🚀 在Azure上部署大型语言模型

我们可以在Azure上通过多种不同的方式来部署大型语言模型,接下来我们将看到其中一些选项。

我们将探索并评估Azure上的大型语言模型。

我们将使用不同的服务,例如Azure Machine Learning以及OpenAI。

我们不仅会了解部署选项,还会尝试明确Azure Machine Learning Studio与OpenAI服务之间的具体区别。

我们将分析Azure OpenAI服务,明确其具体差异,并探讨在何种情况下你可能希望选择使用其中一种而非另一种。


🔍 核心服务对比

上一节我们介绍了Azure上部署LLM的多种途径,本节中我们来看看两个核心服务:Azure Machine Learning Studio 和 Azure OpenAI Service。理解它们的区别对于选择合适的部署方案至关重要。

以下是Azure Machine Learning Studio与Azure OpenAI Service的主要区别点:

  • 服务定位:Azure Machine Learning是一个全面的机器学习平台,支持从数据准备到模型训练、部署和管理的全生命周期。而Azure OpenAI Service则是一个专门为访问和部署OpenAI强大模型(如GPT系列)而设计的托管服务。
  • 核心功能:Azure Machine Learning Studio侧重于提供工具和环境,让用户能够构建和部署自定义的机器学习模型。Azure OpenAI Service则侧重于提供对预训练好的、业界领先的大型语言模型的API访问。
  • 使用场景:当你需要基于自有数据训练定制化模型,或管理复杂的ML工作流时,Azure Machine Learning是更合适的选择。当你希望快速集成和使用如文本生成、代码补全、内容摘要等开箱即用的高级AI能力时,应选择Azure OpenAI Service。
  • 管理复杂度:使用Azure Machine Learning通常需要更多的机器学习专业知识来配置和管理训练管道及计算资源。Azure OpenAI Service作为托管服务,简化了底层基础设施的管理,让开发者能更专注于应用开发。

✅ 总结

本节课中,我们一起学习了在Azure云平台上部署大型语言模型的概况。我们了解到存在多种部署路径,并重点对比分析了两个核心服务——Azure Machine Learning StudioAzure OpenAI Service。关键点在于:前者是一个用于构建和部署自定义模型的综合性ML平台,而后者是一个用于快速集成预训练大语言模型的专用托管服务。根据你的具体需求是模型定制开发还是快速能力集成,你可以做出更合适的选择。

大型语言模型实践:P94:在Azure中发现与评估大语言模型

概述

在本节课中,我们将学习如何在Azure门户中探索和评估可供使用的大语言模型。我们将了解如何导航至Azure机器学习工作室,使用模型目录筛选模型,并理解不同模型来源(如Hugging Face和Azure OpenAI)的部署要求。


导航至Azure机器学习工作室

首先,我们需要进入Azure门户。您可以通过点击页面上的“Azure服务”或直接查找已部署的Azure机器学习实例来访问。

以下是如何操作的步骤:

  1. 在Azure门户中,找到并选择您的Azure机器学习实例。
  2. 根据您的订阅,您会看到所有实例列表。在本例中,我们选择名为“demoMl”的订阅。
  3. 最后,点击“启动工作室”,这将跳转至一个独立的网站界面。

现在,我们已经进入了Azure机器学习工作室的仪表板界面。


探索模型目录

上一节我们介绍了如何进入Azure机器学习工作室,本节中我们来看看其核心功能之一——模型目录。请注意,该网站界面和仪表板布局可能经常更新,因此您看到的界面可能与教程略有不同。

模型目录会展示Azure云平台内所有可供我们使用的模型选项。

首先,请注意页面上的几个选项:

  • 您可以“建议一个模型”。
  • 也可以“导入模型笔记本”,这是一个有趣的功能。

当现有模型不完全符合您的需求时,这些是您可以考虑的选项。


使用筛选器查找模型

进入模型目录后,您会看到各种模型集合。页面顶部通常会有公告,介绍新模型如何被集成到Azure中,例如NVIDIA的模型或Azure OpenAI语言模型。

右侧的筛选器功能非常强大。您不仅可以通过“集合”来筛选,例如,如果您特别喜欢Hugging Face的模型,只需点击它。

应用筛选器后,页面将只显示来自Hugging Face的模型。但您可能不想局限于单一来源。

微软研究院也提供了自己的模型,如Phi-1.5和Phi-2,它们专注于文本生成,性能非常出色。

以下是按任务类型筛选的步骤:

  1. 您可以看到“推理任务”筛选器。
  2. 根据您的任务需求,可以筛选出特定模型。例如,“文本摘要”是一个常见任务。
  3. 点击该任务后,左侧的筛选器会生效。此时,您不仅会看到Hugging Face的模型,还会看到来自其他来源的、能完成该任务的所有模型。

关于Hugging Face模型的说明

您可能会好奇,既然Hugging Face有自己的平台和网站来托管众多模型,为什么还会出现在这里?

这是因为Azure模型目录中的所有模型都经过审核,确保它们能在Azure云上正确运行并达到一定标准。这就是它们被收录的原因。

目录中有大量的Hugging Face模型,继续向下滚动,您还会看到其他来源的模型,例如Mistral AI和Cohere的模型。您可以点击进入任一模型查看更多详情。

我们不会详细探讨这里的所有选项,但了解模型目录提供的多种能力是非常有益的。


部署Azure OpenAI模型

最后,我想提一下Azure OpenAI模型。如果您在目录中查找并点击例如GPT-4这样的模型,准备部署时,系统会要求您转到Azure OpenAI服务。

例如,点击GPT-4后,如果部署选项不可用,则意味着您需要在当前Azure机器学习工作室工作区所在的区域,拥有一个可用的Azure OpenAI服务实例。

这一点需要特别注意,它说明了Azure机器学习工作室内的模型目录与独立的Azure OpenAI服务之间存在区别。在本课中,我们主要关注的是Azure机器学习工作室内部的模型目录。


总结

本节课中,我们一起学习了如何在Azure机器学习工作室中发现和评估大语言模型。我们掌握了导航至工作室的方法,探索了模型目录,并学会了使用集合和任务类型筛选器来缩小模型选择范围。我们还了解了不同模型来源(如Hugging Face)的集成方式,以及部署特定模型(如Azure OpenAI服务中的模型)时需要注意的区域兼容性要求。

大型语言模型实践:P95:推理部署选项

概述

在本节课中,我们将学习在 Azure 机器学习工作室中进行模型推理部署的主要选项。我们将了解如何创建实时与批量端点,如何配置计算资源,以及部署过程中的关键设置。

Azure 机器学习工作室的推理选项

我们首先打开 Azure 机器学习工作室。在主页或登录页面上,我们可以看到所有可用的模型和其他资源。无论我们想进行何种操作,都可以从这里开始。

例如,如果我们想部署某个模型,可以快速点击进入部署部分。

部署端点类型

在部署部分,我们主要有两种选择:批量端点实时端点。大多数情况下,我们会尝试部署类似实时端点的服务。

如果我们选择创建实时端点,系统可能会提示我们没有足够的配额来创建虚拟机。某些模型需要特定类型的配额。我们可以通过点击相关链接,找到部署所需的确切资源。

例如,部署某些模型可能需要强大的 GPU,如果我们没有足够的配额,就无法进行。如果我们有配额,可以看到“实例计数”选项非常有趣,因为它允许我们进行扩展。我们甚至可以将实例数从 1 调整到 3。此外,我们还可以选择不同的配置选项。

部署配置详情

部署时,我们会遇到一些配置项,例如数据收集和模型打包。我们可以找到关于这些选项的更多信息,并根据需要选择。部署完成后,我们会获得一个特定的终结点域名,以及如何消费该模型的说明。不过,我们在此不深入这些细节。

如果我们愿意,还可以获得一系列可供选择的虚拟机。以上就是我想展示的第一个方面。

模型部署示例

接下来,我们转到“模型”部分,点击并选择一个模型。例如,这里有一个我上传的名为 SqueezeNet 的模型。这是一个 ONNX 模型。

对于这类模型,部署限制较少,流程更直接,我们在选择上有更大的自由度。

Kubernetes 部署选项

如果我选择创建实时端点,实际上可以选择使用 Kubernetes 进行部署。这非常有趣,因为部署到 Kubernetes 唯一需要做的就是点击这个按钮,然后我们需要部署一个 Kubernetes 集群。这可以通过 Azure Kubernetes 服务完成。

由于我没有现成的集群,我需要点击“管理”来创建一个。这很方便。

身份验证与访问设置

身份验证类型默认已配置好。在 Azure 中,我们可以创建身份验证机制来防止未授权访问。我们可以选择基于令牌或基于密钥的身份验证。这两种方式有所不同,我们可以根据偏好选择。

基于密钥的身份验证会提供一个不会过期的主密钥和辅助密钥,这是它与基于令牌验证的一个区别。

接下来是公共网络访问设置,我们可以选择是否将终结点公开暴露。

部署参数配置

完成上述设置后,我们将选择要部署的模型,然后进入部署配置。在这里,我们可以设置超时时间。例如,如果评分过程超过 60 秒,请求就会超时,不会返回结果。当然,我们可以修改这个值,比如设置为 90 秒。

我们可以设置超过 90 秒(即一分半钟)的超时。但可以想象,让用户等待超过 90 秒可能会使其失去耐心。

计算资源配置

配置完这些选项后,我们就可以进行部署了。不过,在点击部署之前,我想展示最后一点:计算资源部分。

在“计算”部分,我们可以配置用于部署的 GPU 或 CPU 资源。这里会提供选项让我们选择想要部署的机器类型。

当使用 CPU 时,根据我们的配额,会有不同的选项可供选择。我们可以根据需要挑选。

如果想要 GPU,这里会显示可选的 GPU 机型。同样,我目前没有某些机型的配额。但我们可以根据需求,在这里挑选一些推荐的计算规格,价格信息也会直接显示在旁边。

除此之外,我们还可以在 CPU 选项下,从所有其他规格中进行选择。如果某些规格不在推荐列表中,比如这个只有 2 个核心和 14 GB 内存的选项,我们也可以手动选择并完成配置。

部署完成与管理

以上就是在 Azure 机器学习工作室中进行不同类型部署的一些有趣选项。

一旦我们部署了类似的计算资源,当尝试部署模型时,这些资源就会变为可用。模型部署完成后,它们会出现在“终结点”部分。我们创建的实时端点会显示在这里。

即使我们想查看一些 Azure OpenAI 相关的资源,也能在这里找到。虽然我目前没有任何已部署的资源,但如果我们有,就可以在这里看到它们。

总结

本节课中,我们一起学习了在 Azure 机器学习工作室中进行模型推理部署的核心流程。我们了解了如何选择实时或批量端点,如何配置计算资源(包括 CPU 和 GPU),以及设置身份验证、网络访问和超时等关键参数。掌握这些选项,是成功将机器学习模型投入生产应用的重要一步。

大型语言模型实践:P96:Azure AI内容安全功能详解 🔒

在本节课中,我们将学习Azure AI内容安全功能。这是一个用于审核和过滤用户生成内容及AI生成内容的API服务,尤其适用于与大型语言模型(LLM)和生成式AI集成的应用场景。我们将了解其核心功能、应用场景以及如何通过Azure门户和API进行使用。

在深入探讨Azure AI内容安全的细节之前,我们先来看一下其官方文档。

功能概述与应用场景

我们正在浏览Microsoft Learn文档。文档中指出了几个与生成式AI和大型语言模型高度相关的核心功能。本质上,Azure AI内容安全是一个API服务,您可以提交内容,并获得经过内容修订内容拦截的反馈,从而控制应用程序的行为。

以下是其主要应用场景:

  • 游戏:例如,防止不当聊天内容通过。
  • 教育:此类系统在教育领域也非常有用。

但对于大型语言模型,有两个全新的功能特别值得关注。

面向LLM的核心新功能

上一节我们介绍了Azure内容安全的通用应用,本节中我们来看看它针对大型语言模型的两个新特性。

1. 越狱风险检测
此功能会扫描发送的文本,判断是否存在越狱攻击的可能性。越狱攻击是指用户试图诱导大型语言模型输出其本不应提供的信息,或使其行为偏离预设轨道。

2. 受保护材料文本检测
此功能会扫描AI生成的文本,检查是否包含已知的版权文本内容。这既适用于输入模型的提示词,也适用于模型的输出内容。流程可以概括为:
用户输入 -> 内容安全检测 -> 模型处理 -> 内容安全检测 -> 输出给用户
该功能擅长识别如歌词、文章、食谱等受版权保护的材料。

以上是文档中介绍的一些要点。接下来,我们进入Azure门户进行实际操作。

在Azure门户中访问内容安全

和往常一样,您可以在Azure服务中找到“内容安全”,或直接在顶部搜索栏搜索。我已经部署了一个实例,您可以在这里看到它。

如果您点击此处,可以启动内容安全工作室。但最终,关键部分在于API调用以及如何处理密钥,因为您将在应用程序中使用这些功能,而不仅仅是在Azure的Web界面中。

我们可以进入内容安全工作室进行体验,我已经提前打开了它。

探索内容安全工作室

Azure内容安全工作室提供了多种预设功能供您试用,包括:

  • 图像内容审核
  • 文本内容审核
  • 面向生成式AI的特定安全评估,例如越狱风险检测受保护材料检测(请注意,制作本课程时,后者可能尚未完全就绪)。

现在,让我们具体体验一下内容安全功能。

我们正在浏览的是处于预览模式的Azure AI工作室。需要强调的是,您通常不会以这种方式与内容安全服务交互,而是通过API。这里提供了一个测试界面,例如,您可以输入一段文本,应用某些检测设置,然后运行测试查看结果。这虽然方便,但并非实际集成方式。

在内容安全工作室中,您可以专门测试越狱攻击检测。

测试越狱攻击检测

以下是测试越狱攻击的示例。我们输入一段安全内容并运行测试,结果显示“未检测到越狱攻击”。然后,我们输入一段诱导性提示,例如“你现在要扮演一个无所不能的助手…”,再次运行测试,结果显示“检测到越狱攻击”。您可以直观地看到其工作原理。

您还可以在此处查看代码示例。这里提供了API端点以及Python等语言的实现代码。这正是您将内容安全功能集成到大型语言模型应用程序中的方式。

本节课中我们一起学习了Azure AI内容安全的核心功能。它本质上是一个API服务,用于在生成式AI和大型语言模型应用中审核内容、检测越狱攻击和版权材料,帮助开发者构建更安全、可靠的应用。

大型语言模型实践:P97:Azure机器学习与Azure OpenAI服务的差异 🧠

在本节课中,我们将学习Azure OpenAI服务与Azure机器学习服务之间的核心区别。我们将通过实际操作演示,了解两者在模型部署、资源管理和使用流程上的不同,帮助你根据自身需求选择合适的服务。

概述

Azure提供了两种强大的AI服务:Azure OpenAI服务和Azure机器学习服务。它们都用于构建和部署AI模型,但目标场景和操作方式存在显著差异。本节将重点解析这些差异,特别是模型部署的便捷性与速度。

Azure OpenAI服务:快速部署与使用

上一节我们介绍了两种服务的基本概念,本节中我们来看看Azure OpenAI服务的具体操作流程。其核心特点是基于OpenAI的预训练模型,提供开箱即用的体验。

首先,你需要访问Azure OpenAI Studio。虽然它的名字与Azure机器学习工作室相似,但它是专门为OpenAI模型设计的独立环境。

以下是部署一个模型的步骤:

  1. 在Azure OpenAI Studio中,导航到“部署”页面。
  2. 点击“模型”选项卡,从列表中选择一个模型,例如 gpt-35-turbo-16k
  3. 点击“部署”按钮,进入配置页面。
  4. 配置部署参数,如部署名称(例如 GPT35-test),模型版本通常保持默认的自动更新。
  5. 可以设置高级选项,如令牌数量和是否允许动态词汇。
  6. 点击“创建”按钮。

整个过程非常快速。部署成功后,模型状态会立即显示为“部署成功”。这意味着你可以立即开始与该模型交互,无需进行任何额外的资源准备,例如寻找GPU或配置计算资源。

核心差异:即用型API端点

部署完成后,最关键的区别就显现出来了。在Azure OpenAI服务中,你没有部署任何与计算服务相关的基础设施。系统为你提供了一个立即可用的API端点。

你可以立即前往“游乐场”进行测试。在聊天界面中,系统会自动配置使用你刚刚创建的部署。更重要的是,你可以点击“查看代码”,获得一段完整的、可直接用于Python应用程序的代码示例。

# 示例代码结构
import openai

openai.api_type = "azure"
openai.api_base = "你的Azure OpenAI端点"
openai.api_version = "2023-05-15"
openai.api_key = "你的API密钥"

response = openai.ChatCompletion.create(
    engine="GPT35-test", # 你的部署名称
    messages=[...]
)

这段代码包含了API基础地址、密钥和部署名称,你可以直接将其集成到应用中并开始开发。这种便捷性源于服务为你完全托管了模型运行所需的所有底层计算和资源。

何时选择Azure机器学习服务

那么,在什么情况下不应该使用Azure OpenAI服务或Azure OpenAI Studio呢?当你需要更多定制化能力时,Azure机器学习服务是更合适的选择。

以下是需要转向Azure机器学习服务的几种情况:

  • 使用不同的模型:如果你想使用非OpenAI提供的模型,例如Hugging Face上的开源模型或其他定制模型。
  • 使用自有模型:如果你有自己的机器学习模型需要部署和托管。
  • 微调自定义模型:如果你需要对模型进行特定领域的微调,而OpenAI提供的模型无法满足需求。
  • 完全控制训练流程:如果你想从零开始训练一个全新的模型,并控制整个机器学习生命周期。

在Azure机器学习工作室中,你可以从丰富的模型库中选择,或上传并注册自己的模型,然后将其部署到你自己定义的计算资源(如GPU集群)上。

总结

本节课中我们一起学习了Azure OpenAI服务与Azure机器学习服务的关键差异。Azure OpenAI服务的核心优势在于速度与简便性,它提供预构建的OpenAI模型,能够实现秒级部署和即时API调用,无需管理底层计算资源。而Azure机器学习服务则提供了高度的灵活性与控制权,适用于需要使用自定义模型、第三方模型或需要完全控制训练和推理基础设施的场景。

简单来说,若你需要快速使用最先进的大语言模型(LLM),请选择Azure OpenAI服务;若你的需求涉及定制化、特定模型或完整MLOps流程,则Azure机器学习服务是更强大的工具。理解这一区别,将帮助你在Azure云上更高效地开展AI项目。

大型语言模型实践:P98:总结与回顾

在本节课中,我们将总结在Azure平台上探索大型语言模型(LLM)部署选项、Azure AI内容安全服务以及相关平台的核心要点。我们将回顾关键概念,帮助您理解如何在实际应用中整合这些服务。

Azure上的大型语言模型部署选项

上一节我们介绍了大型语言模型的基本概念,本节中我们来看看在Azure云平台上的具体部署选择。

我们探讨了Azure上可用的大型语言模型部署选项。这些选项为开发者提供了灵活的方式来集成和利用先进的AI能力。

Azure AI内容安全服务

了解了部署选项后,一个重要的考虑是如何确保应用的安全性。接下来,我们将深入了解Azure AI内容安全服务。

我们不仅探索了部署选项,还初步了解了Azure AI内容安全服务。这项服务意味着为您的应用程序增加一个强大的内容审核与安全层。

我个人认为,随着您开始更多地与大型语言模型交互,在应用程序中集成此类安全层是一个极佳的补充。它可以有效帮助净化内容,并调整与用户交互的语言风格。

扩展架构与服务

在基础部署和安全之上,构建健壮的AI应用还需要考虑整体架构。以下是您可以开始整合到整体架构中的其他有趣服务和事项:

  • 内容净化:确保生成内容的清洁与合规。
  • 交互适配:根据用户群体调整语言模型的交互方式。
  • 服务集成:将LLM能力与其他Azure AI服务结合,构建复杂应用。

随着项目的推进,整合这些服务能更轻松地管理内容并优化用户体验。

核心平台辨析

最后,清晰理解Azure提供的不同AI平台至关重要,这有助于我们选择合适的工具进行开发和部署。

明确区分Azure机器学习工作室Azure机器学习服务与Azure OpenAI服务之间的区别非常有用。

  • Azure机器学习工作室:是一个基于Web的交互式工作区,用于低代码或无代码的模型训练、部署和管理。
  • Azure机器学习:是一个更全面的企业级服务,提供用于端到端机器学习生命周期的SDK和基础设施。
  • Azure OpenAI服务:提供对OpenAI强大模型(如GPT系列)的托管访问,专注于生成式AI任务。

我认为现在这个概念已经清晰,这将使我们更容易探索这两个平台,并了解如何自然地开始部署模型并与它们交互。


本节课中我们一起学习了Azure上LLM的部署选择、Azure AI内容安全服务的重要性,以及关键AI平台(Azure机器学习工作室、Azure机器学习和Azure OpenAI服务)之间的区别。掌握这些知识有助于您构建更安全、更高效的大型语言模型应用。

大型语言模型实践:1:引言与Azure机器学习概述

在本节课中,我们将学习如何在Azure机器学习平台,特别是Azure机器学习工作室中,使用和操作大型语言模型。我们将从了解GPU资源开始,到实际部署模型并使用其推理API,为您提供一个完整的入门指引。

🎯 课程目标概述

我们将首先探索Azure机器学习平台及其对大型语言模型的支持。接着,我们会深入了解一个关键前提:GPU配额与可用性。最后,我们将动手实践,学习如何部署一个模型并通过HTTP API与之交互。

💻 探索Azure机器学习工作室

上一节我们介绍了本课程的整体目标,本节中我们来看看我们的主要操作环境:Azure机器学习。

我们将使用Azure机器学习,特别是其集成开发环境Azure机器学习工作室,来开展大型语言模型的相关工作。这个平台提供了管理模型生命周期所需的工具和界面。

⚙️ GPU配额与可用性

理解了操作平台后,一个实际且关键的步骤是确保我们有足够的计算资源。本节我们将重点关注GPU资源。

部署大型语言模型时,大多数情况(并非全部)都需要大量的GPU算力。因此,了解Azure平台,特别是Azure机器学习工作室中GPU配额的管理规则和可用性,对于我们后续成功部署模型至关重要。

🚀 模型部署与推理API使用

在确保资源就绪后,我们就可以进入核心的模型部署环节了。本节我们将实际操作并观察一个模型的部署过程。

我们将看到在Azure机器学习工作室中部署一个模型的具体步骤。部署完成后,我们会学习如何使用其推理API。

我们将通过HTTP API与已部署的模型进行交互。以下是使用该API的典型流程:

  1. 向模型端点发送HTTP请求。
  2. 请求中需包含符合模型要求的输入数据(通常是JSON格式)。
  3. 接收模型返回的HTTP响应,其中包含推理结果。

🌐 在Azure门户中创建与管理资源

模型部署并运行后,我们需要知道如何管理它。本节我们将在Azure门户中进行实际操作。

我们将在Azure门户中创建必要的云资源。我们会看到如何对部署在Azure机器学习工作室中的模型进行这些管理操作。

📚 课程总结

本节课中我们一起学习了在Azure机器学习平台操作大型语言模型的入门知识。我们从平台概述开始,明确了GPU资源的重要性,并逐步完成了从模型部署到通过API进行交互的完整流程,最后还了解了在Azure门户中进行资源管理的基本方法。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P100:34_04_02_CargoLambda简介 🚀

在本节课中,我们将要学习 Cargo Lambda,这是一个在无服务器计算领域带来显著进步的工具。我们将了解它如何简化 Rust 语言在 AWS Lambda 上的开发与部署流程。

概述

Cargo Lambda 解决了无服务器开发中的一些常见痛点。它最大的优势之一是无需依赖容器或虚拟机,这对于开发环境受限的情况尤其有用。例如,你的计算机可能不支持容器化或虚拟化技术,或者存在资源限制。使用 Cargo Lambda,你可以直接在本地计算机上构建和部署 Lambda 函数。

Cargo Lambda 的核心优势

上一节我们介绍了 Cargo Lambda 的基本概念,本节中我们来看看它的具体优势。

Cargo Lambda 使得 Rust 函数的开发变得简单,其背后由新兴的系统编程语言 Zig 提供支持。它为开发者提供了原生的开发体验,并且安装过程非常简单。这是笔者最喜欢的与 AWS Lambda 协作的方式之一。

以下是 Cargo Lambda 的主要特点:

  • 无外部依赖:无需容器或虚拟机。
  • 原生开发体验:安装和使用都非常简单。
  • 集成 Cargo 生态:作为 Cargo 的一个子命令,无缝融入 Rust 开发生态。
  • 功能全面:支持构建、部署、初始化、调用和监控等完整开发流程。

安装与初探

现在,让我们开始动手实践。首先需要安装 Cargo Lambda。

安装过程非常简单。在 AWS Cloud9 环境、Linux 或 macOS 上,你只需要执行以下命令:

brew install cargo-lambda

安装完成后,在终端输入 cargo lambda 命令,你会看到一个帮助菜单。这表明 Cargo Lambda 已经成功安装,并且它被描述为一个用于在本地处理 AWS Lambda 函数的 CLI 工具。

创建新项目

安装好工具后,下一步是创建一个新的 Lambda 项目。

创建一个新项目非常简单。只需执行以下命令:

cargo lambda new lambda_project
cd lambda_project

执行命令后,CLI 会询问几个问题来配置项目,例如是否是一个 HTTP 函数(可由 API Gateway 等触发),或者是否是一个事件驱动的函数。对于初学者,可以直接按回车键使用默认选项。

项目结构解析

创建项目后,让我们看一下生成的项目结构。这有助于理解 Cargo Lambda 为我们搭建的基础。

Cargo Lambda 自动生成了 Cargo.toml 配置文件,其中已经配置好了必要的运行时依赖。它使用了 serde 库进行序列化,tokio 用于异步处理,并默认启用了追踪功能。一切都已经准备就绪。

src 目录下,你可以找到 main.rs 文件,这是函数的主文件。文件底部是函数的主要逻辑部分,即 handler 函数。你的 Rust Lambda 函数的大部分工作都将在这里发生。它的代码结构清晰,甚至有点像 Python 代码。文件中的 tokio::main 部分会调用执行实际工作的函数,这部分是样板代码。

本地运行与测试

了解了项目结构后,本节中我们来看看如何在本地运行和测试我们的 Lambda 函数。

在本地运行函数非常简单。首先,使用 watch 命令在本地启动一个模拟 Lambda 环境:

cargo lambda watch

然后,要测试一个基本函数,可以使用 invoke 命令。这是一个非常方便的功能,让你能在本地完成所有测试。例如:

cargo lambda invoke

在编译并创建二进制文件后,你可以输入测试数据,例如 “hi, hi, hi”。命令会调用本地的 Lambda 函数并返回结果。整个过程非常直观。此外,你也可以模拟来自 API Gateway 的请求进行测试。

构建与部署

本地测试通过后,下一步就是将函数部署到 AWS Lambda。

构建用于生产环境的发布版本同样简单:

cargo lambda build --release

这个命令会构建一个可以部署到 AWS Lambda 的版本。

部署到 AWS 只需要一个命令:

cargo lambda deploy

部署成功后,你可以在 AWS 管理控制台的 Lambda 服务中看到一个以你项目名命名的函数(例如 new_lambda_project)。你可以直接在 AWS 上调用它,验证部署是否成功。

总结

本节课中我们一起学习了 Cargo Lambda 工具。它提供了一种非常直接的方式来开始用 Rust 编写 Lambda 函数。通过消除对容器或虚拟机的依赖,Cargo Lambda 让本地开发变得异常轻松,使得构建、测试和部署 Rust 无服务器函数的流程变得高效而简单。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P101:构建Rust版AWSLambda加法函数 🦀

概述

在本节课中,我们将学习如何使用Rust语言构建一个简单的AWS Lambda函数。这个函数将执行加法运算,我们将从创建项目、编写代码、本地测试,一直讲解到部署和远程调用。通过这个简单的例子,你将了解Rust在构建低成本、高性能Lambda函数方面的优势。

项目架构与启动

首先,我们来看一个非常简单的Lambda函数系列架构,这些函数最终将被包装在一个Step Function中。但第一步,我将从Rust开始,构建一个名为add的函数。

这个函数非常简单:它接收一个x和一个y,然后返回它们的总和。我喜欢使用Rust的原因是,它可能是实现成本效益最高的Lambda调用的最简单方式。

接下来,让我们看看具体如何操作。这里我们有一个AWS Lambda项目。我能够创建这个项目,是通过使用cargo-lambda工具。

如果你输入cargo lambda,它会显示一系列选项,包括new。这就是我创建的新项目。

现在,让我们看一下项目的树状结构。这里我们主要有一个main.rs文件和一个Cargo.toml文件。自动生成的Cargo.toml文件已经填充了所有必要的依赖项,如序列化、异步、编码、追踪和运行时库,一切都已为你设置好。

编写Lambda函数逻辑

为了使用这个Lambda,我在函数内部添加了一些逻辑。让我们逐步了解它的功能。

首先,我添加了一条注释,说明我们正在构建一个简单的加法函数。这特意设计得很简单,以便我能解释Rust Lambda的工作原理。

请注意这里的这个结构体(struct),它将作为传入的请求。它包含xy两个字段。我们需要在derive部分定义它。

接下来是响应结构体。这是我完成后将要返回的内容。你可以把它看作是x + y的结果,即total

最后,在主要的逻辑部分,我们有一个异步的Rust函数。除了async关键字外,这个函数本身内容不多。async关键字允许我们使用Tokio库进行异步通信。此外,我们还有function_handler函数,它将完成所有内部工作。它接收这个Lambda请求,并返回一个结果对象。

目前看来,这与脚本语言没有太大区别。负载(payload)在此函数外部被解析。同样,我们可以看到这个负载来自这里的请求。

然后我们将数字相加。代码是:let total = x + y;

为了返回响应,我们只需创建let response并传入那个总和,以便将其返回。然后,我们使用Ok包装这个响应。这就是结果响应错误。

现在,剩下的唯一事情就是通过这个主处理器(main handler)将所有东西连接起来。实际上,你不需要做任何事情,它已经为你设置好了。它所要做的就是调用那个function_handler函数,该函数同样在这里定义。

本地开发与测试

为了使用它,实际上相当简单,如果你掌握一些技巧的话。我喜欢做的事情之一是创建一个Makefile。

我喜欢创建Makefile的原因是我只想快速构建,而不愿过多思考。本地开发的方法之一是使用cargo lambda watch命令。

所以我只需输入make watch。这样它就会运行,并让我在本地进行任何需要的操作。

现在,如果我点击这个分屏终端,我们可以更多地尝试并实际运行这个调用。

这与Python等脚本语言非常不同,因为你需要使用Docker并进行各种设置。但实际上,由于无需安装第三方工具,一切都已经为你设置好了。

如果我想继续并输入make invoke,这将实际调用我的本地二进制文件。看,你可以看到具体发生了什么。我传入了一个xy。我们已经知道它能工作,不需要再做更多了。

因此,真正的下一步将是停止这个进程,并实际构建它以进行部署。

构建与部署

那么我们如何构建呢?再次使用cargo lambda build --release。不过这里有一个技巧:如果你只使用基本的Rust代码,并且相当确定它不会做任何复杂的事情,那么使用ARM 64架构可能是一个很好的选择,因为你的构建成本会更低。

所以我实际上要在这里构建最便宜的Lambda。我只需输入make build。好了。

一旦我构建完成,部署就变得微不足道了。我再次使用cargo lambda deploy,我甚至可以指定区域(region)。所以我们可以直接说make deploy

由于这个二进制文件非常小,部署再次变得非常简单。

远程调用与验证

现在,情况变得更好,因为我甚至可以在不做任何额外操作的情况下远程调用它。

所以我要继续并关闭另一个终端,以获得更多空间。让我们关掉它。

现在看看这个:我只需像之前一样输入cargo lambda invoke,但加上--remote和函数名,就这样。

所以让我们继续这样做,我们可以直接输入make aws-invoke。好了。

现在你可能会想,哦,我们确定这能工作吗?让我们继续检查一下。让我们双重确认我们实际上是在调用已部署的函数。这总是一个好主意。

如果我们往下看,我们可以通过监控来做到这一点。查看最近调用是查看它的更简单方法之一。事实上,我们刚刚看到一个,持续时间是0.89毫秒,相当快。

我们实际上可以看到关于它的一切。我们可以看到持续时间再次小于1毫秒,这简直不可思议。实际上,分配的内存大小也很小。

如果我们想在控制台中实际测试它,这是另一种很好的方法。我们到这里,注意我在这里创建了一个包含xy的事件。所以此时我们要做的就是回到测试部分,点击这个按钮,我们可以看到,事实上它也返回了结果。再次强调,持续时间非常非常短,只有1.37毫秒,我们可以看到构建持续时间是2毫秒。

这也是Rust相对于Python等语言的优势之一,Python的默认内存使用量是Rust的70倍,而Rust只使用了15 MB。

我们为什么关心这个?因为你的费用是按内存使用量计算的。所以默认配置允许你以Python不可能达到的成本效益执行许多Rust操作,这确实是使用Rust构建AWS Lambda函数的主要优势之一。

总结

本节课中,我们一起学习了如何使用Rust构建和部署一个简单的AWS Lambda加法函数。我们从项目创建开始,详细讲解了函数逻辑的编写、本地测试方法,以及如何利用cargo-lambda工具高效地进行构建、部署和远程调用。通过对比,我们看到了Rust在运行速度、内存占用和成本效益方面的显著优势,这使其成为构建高性能、低成本Serverless应用的优秀选择。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P102:01_01_01:认识你的课程讲师诺亚·吉夫特 👨‍🏫

在本节课中,我们将认识本课程的讲师诺亚·吉夫特,并了解他的专业背景以及本课程将要涵盖的核心内容。

大家好,我的名字是诺亚·吉夫特,我是本课程的讲师。

本课程将涵盖广泛的内容,从 Databricks 开始,一直到使用本地大型语言模型。

首先介绍我的背景。我是一位多产的 Coursera 讲师,在 Coursera 平台上已经创作了相当于一个硕士学位课程量的内容。目前,我是杜克大学的驻校高管。这意味着我与研究生数据科学项目以及“产品创新人工智能”项目合作,围绕数据工程、云计算、机器学习运维开发内容,并进行现场教学。

我拥有大约30年的行业经验,涉足领域广泛,从游戏、电影到软件即服务,再到生产环境中的机器学习。我将把这些技能全部融入我在 Coursera 平台上创作的内容中。

本课程有很多内容需要学习。让我们立即开始吧。时间宝贵,不容浪费。


本节课中我们一起学习了课程讲师诺亚·吉夫特的背景,他是一位经验丰富的行业专家和资深教育者,并了解了本课程将围绕 Databricks、AWS 和本地大型语言模型等主题展开。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P103:02_01_03_Databricks湖仓平台简介

在本节课程中,我们将学习数据架构的演进历程,并重点介绍湖仓一体(Lakehouse)这一现代数据平台概念。我们将了解其定义、关键特性、优势以及当前存在的局限性。

首先,让我们回顾数据架构的演进过程。在左侧的图表中,我们可以看到从数据仓库到数据湖,再到湖仓一体的发展路径。这种演进的一个原因是,传统数据仓库在处理大规模非结构化数据时存在局限性。同时,数据湖的某些承诺因缺乏治理而未能完全实现。

上一节我们介绍了数据架构的演进背景,本节中我们来看看湖仓一体的具体定义。

湖仓一体是一种将数据仓库的优势与数据湖相结合的新架构。数据仓库的优势包括生成商业智能报告和执行ETL(提取、转换、加载)流程。湖仓一体在一个新的架构中融合了这些优势。

以下是湖仓一体与数据湖的一些关键区别:

  • 在湖仓一体中,除了数据分析,你还可以进行数据科学和机器学习工作。
  • 它支持处理结构化、半结构化和非结构化数据。
  • 它在提供分析和机器学习所需治理、质量和性能的同时,也保持了架构的灵活性。

湖仓一体也采用了传统云数据仓库的做法,即将存储与计算资源分离。这种分离带来了更好的扩展性和成本效益。

了解了基本定义后,我们来看看湖仓一体的关键属性。

湖仓一体的关键属性包括:

  • 支持ACID事务和模式强制,这与传统的SQL解决方案类似。
  • 基于低成本对象存储的开放格式。例如在AWS上,这类似于S3服务。
  • 统一支持批处理、流处理、SQL查询和机器学习工作负载。
  • 具备企业级能力,如安全性、访问控制和审计。这些对于合规性和正确的数据治理至关重要。

接下来,我们总结一下湖仓一体相较于过去系统的优势。

湖仓一体带来的主要益处包括:

  • 架构极大简化:取代了多个专用系统。
  • 更快的洞察时间:无需复制或移动数据。
  • 成本节约:运营单一系统的基础设施。
  • 灵活性高:支持从商业智能到人工智能的多样化分析。

最后,我们也要客观看待湖仓一体当前的局限性与未来展望。

湖仓一体目前的一些局限性包括:

  • 成熟度早期:可能在某些方面落后于旧系统。
  • 查询性能:可能存在优化空间。
  • 非SQL工具支持:可能需要更好地支持非SQL工具和用户角色。

在选择这些新解决方案时,需要认识到这些差距将随着时间的推移而逐渐缩小,同时湖仓一体所具备的简洁性和成本优势将得以保留。

总而言之,湖仓一体代表了当前数据架构发展的一个演进阶段。这种演进模式在众多技术创新的历史中屡见不鲜。

本节课中我们一起学习了数据架构从数据仓库、数据湖到湖仓一体的演进,明确了湖仓一体的定义、核心特性、主要优势以及现阶段的挑战。理解这一现代数据平台概念,对于后续在Databricks等平台上进行高级数据工程和LLM实践至关重要。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P104:03_01_04_Databricks架构概述 🏗️

在本节课中,我们将要学习Databricks平台的核心架构。我们将了解其如何通过分离控制平面与计算平面来组织工作,以及这种设计如何为用户带来安全、灵活和高效的数据处理体验。

架构总览

上图展示了Databricks架构的总体概览。其核心结构分为控制平面计算平面

控制平面与计算平面

上一节我们介绍了架构总览,本节中我们来看看这两个核心组件的具体职责。

  • 控制平面:由Databricks公司管理和维护。它是所有管理操作发生的地方,负责处理后端服务,例如存储笔记本和作业。
  • 计算平面:运行在客户的云环境中。它负责处理客户的数据和工作负载。在本例中展示的是AWS,但它也可以是Azure、GCP或其他云平台。

这种职责分离意味着Databricks负责管理控制平面服务以减轻客户负担,而客户则保持对其业务数据的所有权和控制权。这与AWS的共享责任模型非常相似,在该模型中,您管理资源的某些部分(如云配置),而AWS管理其他部分(如物理数据中心)。

数据流与工作负载

了解了基础架构后,我们来看看数据是如何在其中流动和处理的。

连接器负责集成外部数据以供摄取,随后数据湖将数据安全地存储在客户的云存储中。因此,Databricks架构构建在对象存储和计算资源之上。在AWS的案例中,这对应着S3和EC2。

一个典型的工作流程如下:

  1. 数据通过连接器从源端摄取到云存储(如S3)中。
  2. 计算资源按需启动,以处理和分析这些数据。
  3. 交互式工作负载、笔记本、批处理作业和SQL查询都共享同一架构。
  4. 处理结果输出回由客户控制的云存储。

架构优势 🎯

基于上述设计,Databricks架构带来了多项关键优势:

以下是Databricks架构的主要优点:

  • 完全托管的控制平面:降低了运维开销。
  • 客户云账户提供安全与隔离:保障了数据主权和安全性。
  • 灵活处理多样化数据工作负载:能够适应不同的数据处理需求。
  • 按使用计算付费:通过无服务器产品,只为实际使用的计算资源付费。

总而言之,借助Databricks,您可以通过利用其顶层的控制平面来管理复杂的工作流。该控制平面包含Web应用程序、笔记本、作业与查询以及集群管理等功能。它的能力远不止于数据工程,还包括MLOps(机器学习运维)等。

本节课中我们一起学习了Databricks的核心架构,包括其控制平面与计算平面分离的设计、典型的数据工作流以及该架构带来的主要优势。理解这些是有效利用Databricks平台进行大规模数据工程和机器学习操作的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P105:04_01_05:创建和管理集群

在本节课中,我们将学习如何在Databricks环境中创建和管理计算集群。这是管理Databricks环境的重要任务之一。

计算界面概览

让我们首先查看Databricks界面中的“计算”选项卡。你可以看到有几个不同类别的选项。

第一个是“通用计算”。如果你打算使用笔记本或执行基本的数据工程操作,可以从这里开始。例如,图中显示了一个名为“thrifty”的正在运行的集群。要启动它,只需点击并确认即可。

创建新集群

如果我们想从头创建一个集群,可以点击“创建计算”并查看选项。

你会看到我使用的是“无限制策略”。这是Databricks的一项新功能,用于控制用户允许执行的操作。策略的目的是限制用户只能使用预设设置创建集群。

例如,如果你的公司GPU资源有限,你可能希望限制单个用户使用的资源量。策略还可以简化界面、控制成本,甚至强制使用特定库,例如只允许组织成员使用你创建的库。这些都是很好的控制选项。

访问模式与运行时

回到访问模式,你可以选择“多节点”或“单节点”。Databricks的主要目的是进行集群计算,因此在许多场景下你会需要多节点。单节点主要用于原型设计。切换到单节点模式只会启动一台机器,而多节点模式的优势在于能够扩展Hadoop文件系统的磁盘和计算能力。

接下来看默认运行时。运行时已经为你预先配置好,包含了最新版本的Scala和Spark。你可以根据需求切换版本。对于常规的笔记本操作和SQL查询,你会需要这个标准运行时。如果你想进行高级的机器学习操作,请注意这里有GPU选项,以及不同版本的Spark和预配置的库,这样你就不需要手动选择安装内容。运行时允许你在标准数据工程问题和机器学习之间切换,并自动为你配置正确的库。

工作节点与自动缩放

我们还可以看到可以调整最小工作节点数或最大工作节点数。默认设置通常就很好用。但如果你知道需要处理大量数据,可能需要增加最小工作节点数,例如始终使用至少四个工作节点。你也可以将最大工作节点数调得更高。所有这些调整都会根据云服务商提供的资源得到反馈。

我们也可以查看驱动程序类型。在这种情况下,我们希望它与工作节点相同。至于自动缩放,这个按钮允许你使用设置的最小和最大值。

终止策略与标签

另一个非常重要的设置是:是否在一段时间后终止集群。对于进行大量临时演示和探索的情况,你通常会希望启用此功能。另一方面,如果你运行的是24/7不间断的集群,则应关闭此功能,因为不活动时终止可能会导致其他用户的操作中断。这完全取决于你的环境需求。

你还可以在这里添加标签。例如,你可以添加一个“团队:数据科学”的标签,以明确标识集群的用途。

集群管理与监控

一旦集群开始运行,回到“计算”界面,你可以查看其详细信息。你可以查看与之关联的笔记本和库,安装新库,还可以查看Spark用户界面,了解作业运行情况,查看指标。这在运行作业时非常重要,可以帮助你判断是否需要更大的规模,例如是否需要增加最大节点数,因为CPU、磁盘或内存可能已过载。你可以从这里查看所有信息。因此,计算界面是管理基本计算所需一切的一站式商店。

其他计算选项

此外,还有“计算作业”选项,允许你执行和管理临时作业。还有“SQL仓库”,这是另一个选项。我们还有“池”,它允许你逻辑分组以分配计算能力。你也可以将自动缩放池中的集群分配给某个团队或单位。最后,你可以在这里创建自定义策略,例如简化启动流程或限制使用GPU的能力。所有这些都可以直接在Microsoft Azure Databricks、AWS Databricks或你使用Databricks的任何平台界面中进行管理。

总结

本节课中,我们一起学习了如何在Databricks中创建和管理计算集群。我们介绍了计算界面的各个部分,包括创建集群时的策略、访问模式、运行时选择、工作节点配置、自动缩放、终止策略和标签管理。我们还了解了如何监控运行中的集群,并简要介绍了其他计算选项,如作业、SQL仓库和池。掌握这些知识对于有效利用Databricks进行数据工程和机器学习任务至关重要。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P106:05_01_06:配置集群运行时 🚀

在本节中,我们将学习如何在Databricks中配置集群运行时。我们将了解不同类型的运行时及其适用场景,并演示如何在界面中进行选择和配置。

概述

Databricks提供了多种预配置的集群运行时,这些运行时针对不同的工作负载进行了优化。使用这些托管运行时可以节省大量维护和配置时间,因为Databricks会自动管理底层细节。

Databricks运行时类型

以下是Databricks提供的主要运行时类型及其用途。

标准运行时

标准运行时是通用型运行时,适用于ETL操作、数据管道和批处理任务。例如,如果你有一个需要按特定时间间隔运行的调度作业,通常可以使用标准运行时。它支持多种编程语言,包括Python、R、Scala和SQL。

Photon运行时

Photon运行时专为处理海量数据和表扫描进行了优化。它非常适合在PB级别数据上进行ETL操作,能提供更高的性能。

机器学习运行时

机器学习运行时预装了进行机器学习任务所需的库。它包含了TensorFlow、PyTorch、Keras等深度学习框架,也支持如pandas等常规机器学习API。这使得数据科学家可以立即开始工作,而无需手动安装大量依赖。

SQL分析运行时

SQL分析运行时针对SQL查询和商业智能用例进行了优化。它与标准运行时的主要区别在于,你可以调整语言和库的属性、内存、I/O、CPU、查询引擎以及并发限制等参数。这些细粒度的调整由Databricks管理,用户无需关注底层细节。

界面操作演示

上一节我们介绍了各种运行时的概念,本节中我们来看看如何在Databricks界面中进行实际操作。

在Databricks界面中,你可以看到不同运行时集群的运行实例。例如,一个正在运行的ML集群会明确显示使用的是ML运行时,以区别于常规运行时。这种设计的好处是,用户无需自行安装大量库,许多常用工具已经预装完毕。

如果你想创建一个新的计算集群,可以按照以下步骤操作:

  1. 导航至创建新计算集群的选项。
  2. 在配置过程中,浏览并选择所需的运行时类型,如“标准”、“ML”或“未分类”等。
  3. 你还可以切换到SQL运行时或池的选项,这里有多种不同的配置可供选择。

最终,由你决定需要创建多少种不同类型的集群,例如一个用于机器学习的集群、一个用于数据处理的基础集群,以及一个用于SQL分析的集群。所有这些选项都可以在Databricks界面中灵活配置。

总结

本节课中我们一起学习了Databricks集群运行时的配置。我们了解了标准、Photon、机器学习和SQL分析这几种主要运行时类型的区别与适用场景,并通过界面演示了如何选择和创建配置了不同运行时的集群。利用这些托管运行时,用户可以高效地开展多样化的工作,而无需在环境维护上花费过多时间。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P107:06_01_07_终止集群

在本节课中,我们将学习如何在Databricks环境中终止一个正在运行的集群。我们将介绍通过集群管理界面和直接从笔记本界面终止集群的两种主要方法,并解释“终止”与“删除”操作的关键区别。

通过集群管理界面终止集群

上一节我们介绍了Databricks集群的基本概念,本节中我们来看看如何通过集群管理界面来终止一个集群。

在Databricks界面中,有一个集群已经在运行。可以看到有几个笔记本与此集群相关联。同时,这里也有一个新集群正在启动。如果我想控制这个集群,终止它的方法之一是先选中它。

首先,如果你启用了自动终止功能,即使你什么都不做,集群也会在闲置一段时间后自动停止。例如,你可以看到这里设置了“120分钟后终止”,这意味着当集群处于非活动状态(即你没有进行任何操作)时,它将自动终止。

但是,有一种更明确的手动终止方式。如果你转到这个区域并点击“终止”按钮,系统会询问“你确定要立即终止集群吗?”。这个操作将直接停止集群。

其他控制选项与“终止”与“删除”的区别

请注意,界面上还有其他控制选项。如果我们点击这里,你还可以“克隆”这个集群,或者“重启”它。

然而,“删除”操作会永久地移除集群,包括其全部配置信息。因此,“终止”和“删除”的关键区别在于:

  • 终止:只是停止集群的运行,其配置被保留,以后可以重新启动。
  • 删除:是永久移除集群及其所有配置。

从笔记本界面终止集群

除了从集群列表管理,还有其他方式可以终止集群。其中一种更便捷的方法是从笔记本内部进行操作。

现在,让我们转到“新建”选项,然后选择“笔记本”。注意,此时“em”集群已被选中,并且显示为绿色,表示正在运行。

那么,我该如何终止它呢?我可以将鼠标悬停在界面上的“em”集群名称上。这时,你会看到我拥有直接从此界面终止它的能力。这是更便捷的方法之一。

假设你已经完成了一个项目,并且正在笔记本内部,你已经保存了工作,或许还将其提交到了版本控制系统。此时,要停止集群,你只需选择“终止”,然后点击“确认”。系统将开始执行终止流程,你可以在这里看到终止请求已被发出。

总结

本节课中我们一起学习了在Databricks中终止集群的两种主要方法:通过集群管理界面手动终止,以及从活动的笔记本界面直接终止。我们明确了“终止”(临时停止,保留配置)与“删除”(永久移除)操作的根本区别。掌握这些操作有助于有效管理计算资源,在完成任务后及时停止集群以控制成本。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P108:07_01_08_重启集群 🔄

在本节课中,我们将学习如何在Databricks环境中重启计算集群。当集群出现异常行为、过载或内存不足等问题时,重启是一个有效的解决手段。我们将介绍两种不同的重启方法。


重启集群的必要性

上一节我们介绍了集群的基本管理。本节中我们来看看如何重启一个集群。有时,计算集群可能表现异常、过载或内存不足。重启操作可以将其置于全新状态,清除内存中的所有遗留问题,从而解决这些故障。

方法一:通过集群列表重启

以下是第一种重启方法,通过Databricks工作区的集群管理界面进行操作。

  1. 在Databricks工作区中,定位到需要重启的集群(例如,名为“thrifty”的集群)。
  2. 点击该集群右侧的菜单按钮。
  3. 从弹出的菜单中选择“重启”选项。
  4. 确认操作后,集群将进入重启流程。这将使集群重新启动,所有内存状态和运行进程都将刷新。

方法二:通过关联的笔记本重启

除了直接从集群列表操作,我们还可以通过与之关联的笔记本来重启集群。这种方法在您正在使用笔记本时可能更加便捷。

以下是具体步骤:

  1. 打开一个与目标集群关联的Databricks笔记本。
  2. 在笔记本界面中,找到并点击当前所选集群的名称。
  3. 在弹出的集群列表中,将鼠标悬停在目标集群上。
  4. 点击出现的“重启”按钮。
  5. 通过此方式,您可以从笔记本内部直接完成集群重启,效果与方法一完全相同。

总结

本节课中我们一起学习了在Databricks中重启计算集群的两种方法:通过集群列表直接重启,以及通过关联的笔记本界面重启。这两种方法在您遇到集群性能问题时都非常实用,可以帮助您快速恢复集群的正常工作状态。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P109:08_01_09_过滤集群列表

在本节课程中,我们将学习如何在Databricks的计算界面中高效地管理和筛选计算集群。当您管理的集群数量庞大时,快速找到特定集群至关重要。

界面概览与按名称筛选

这里是Databricks的计算界面。当前显示了三个不同的集群。如果您需要管理数百个集群,您需要能够根据名称或运行时环境进行快速筛选。

以下是实现快速筛选的方法之一:您可以使用界面上方的“筛选计算资源”菜单。当我们点击该菜单并输入“ML”时,可以立即筛选出名称中包含“ML”的集群。

按运行时版本筛选

另一个常见的需求是根据特定的运行时版本来查找集群。例如,您知道某个ML运行时具有特定的版本号。

您可以直接在筛选框中输入版本号,例如“14.2”。或者,对于其他版本,可以输入“13.3”或“13.2”。输入“13.2”可能没有匹配项,但输入“13.3”时,我们看到有两个集群匹配。这个功能让您能够在拥有数百个运行时环境的大型组织中快速切换和定位。

收藏常用集群

结合筛选功能,另一个非常有用的操作是“收藏”您常用的集群。

同样,如果您有20、30甚至40个不同的集群,除了使用筛选,您还可以将最常使用的两个集群“置顶”或收藏。这样,默认情况下,您就能始终快速访问这些常用集群。

本节总结

本节课中,我们一起学习了在Databricks中管理计算集群的实用技巧。我们介绍了如何通过名称和运行时版本快速筛选集群,以及如何收藏常用集群以提升工作效率。这些功能对于在拥有大量计算资源的环境中高效工作非常有帮助。

大型语言模型实践:P110:总结与回顾

在本节课中,我们将回顾并总结使用Azure OpenAI服务的关键步骤与要点。我们将涵盖服务访问、模型部署以及使用Playground进行快速实验的核心内容。

访问Azure OpenAI服务

我们学习了如何使用Azure OpenAI服务。首先,需要了解如何实际获取对Azure OpenAI服务的访问权限。

需要注意的是,尽管目前访问权限受到一定限制,但随着服务日益普及,未来这些限制可能会放宽,相关情况也可能发生变化。

部署模型与使用Playground

上一节我们介绍了服务访问,本节中我们来看看模型部署。我们还学习了如何部署一个Azure OpenAI模型,并使用了Playground环境。

我认为Playground是一个极佳的入门工具,它能让你几乎不费力气地开始调整和探索已部署的Azure OpenAI模型。你看到部署几乎是瞬间完成的,这使得使用Playground变得非常简便且极具吸引力。

以下是使用Playground的优势:

  • 可以轻松尝试不同的策略。
  • 帮助你开始思考在部署和使用Azure OpenAI服务中的模型时,有哪些可能性。

课程总结

本节课中我们一起学习了Azure OpenAI服务的基本使用流程。我们了解了服务访问的现状与未来趋势,掌握了通过Azure平台部署LLM模型的方法,并重点体验了Playground这一强大且用户友好的工具,它能帮助我们快速进行模型测试与策略探索。

大型语言模型实践:P111:34_02_01:引言 🚀

在本节课中,我们将学习如何超越Azure OpenAI服务的Playground界面,开始通过编程方式与大型语言模型进行交互。我们将介绍Azure OpenAI服务的API、如何通过Python代码调用它们,以及如何管理资源的使用配额与清理。

从Playground到API

上一节我们介绍了如何在Azure OpenAI服务的Playground中部署和使用模型。本节中,我们来看看如何通过编程接口与这些模型进行交互。

超越Playground界面,超越仅仅在Playground中部署和使用Azure OpenAI模型,下一步是了解Azure OpenAI服务的API。我们将探讨这意味着什么,以及我们如何实际与这些API进行交互。这些API本质上是HTTP API。

我们将使用不同类型的策略与这些模型进行通信。我们会稍微关注这方面的编码实现,并将使用Python创建一个简单的示例,尝试与部署在Azure OpenAI服务上的大型语言模型进行交互。

核心概念与交互策略

我们将通过HTTP请求与模型通信。核心的交互通常涉及向特定的API端点发送一个包含提示(prompt)和其他参数的POST请求,并接收模型生成的响应。

以下是一个基础API调用的伪代码结构:

import requests

response = requests.post(
    url=ENDPOINT_URL,
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "prompt": "你的问题或指令",
        "max_tokens": 100
    }
)
generated_text = response.json()["choices"][0]["text"]

资源管理与清理

最后,我们将了解使用量和配额管理,这对于尝试消费Azure OpenAI服务上的资源非常重要。我们还将学习如何清理这些资源,并了解一些可以采取的措施,以确保在使用完这些大型语言模型后,资源能被正确清理和销毁。

以下是资源管理的关键步骤列表:

  • 监控使用量:在Azure门户中跟踪令牌消耗和API调用次数。
  • 设置预算与警报:配置支出上限,在接近限额时接收通知。
  • 删除未使用的资源:完成实验或项目后,删除相关的Azure OpenAI资源组或特定实例。

总结

本节课中,我们一起学习了如何从Azure OpenAI的图形化Playground过渡到通过API编程调用模型。我们了解了API交互的基本原理,预览了使用Python进行调用的方法,并强调了管理使用配额和及时清理资源的重要性。这是将大型语言模型集成到实际应用程序中的关键一步。

大型语言模型实践:P112:使用密钥与端点 🔑

在本节课中,我们将学习如何在Azure OpenAI服务中使用API密钥和端点。我们将了解如何查找和管理这些关键信息,以及根据不同的使用场景(如Python库或直接API调用)如何正确配置它们。

概述

上一节我们介绍了Azure OpenAI服务的基本概念。本节中,我们来看看如何获取和使用访问服务所必需的密钥与端点。这是与模型进行编程交互的基础。

查找密钥与端点

在Azure门户中管理OpenAI服务资源时,可以找到密钥和端点信息。

以下是具体步骤:

  1. 在资源管理页面,可以找到“密钥和终结点”部分。
  2. 此处会显示端点区域位置以及两个API密钥
  3. 密钥管理功能允许你重新生成密钥或复制密钥值。

例如,如果你不小心泄露了密钥,或者像在演示中担心密钥被暴露,可以在此处重新生成。

理解端点类型

现在你还可以查看模型部署。密钥和端点信息就在这里。但有一个需要注意的地方:这里显示的端点是通用的,并不特定于我实际部署的模型。

在我的案例中,我已经部署了模型,但它们没有显示在这里。这会在某些情况下显示。让我们看看这些情况是什么。

我将转到Azure AI Studio,进入“模型”部分。这里列出了我已部署的几个模型以及可用的模型。然后我进入“部署”部分,可以看到我已经部署的几个模型。

让我们查看名为 demo-alfredo 的部署。它运行的是 gpt-35-turbo 模型,这符合我们的需求。

在代码中使用端点

现在让我转到Playground。我点击“打开Playground”,选择聊天模式,然后立即打开这个部署。我想向你展示的是,在聊天会话中点击“查看代码”。

当你想使用Python等语言时,你将能够使用 openai 库。你会看到需要定义这些变量。这个代码示例需要一个特定版本,这没问题。但我想让你看看这里的 openai.api_base

在这个例子中,它是 https://devs-demo-alfredo.openai.azure.com/。这就是我们之前看到的通用端点,它并不具体。那么,Azure如何知道我们指的是哪个具体模型呢?

对于Python这样的场景,你需要这个通用的API基础地址,这没问题。但对于其他情况,你将需要特定的端点。我知道这可能会让人困惑。

关键在于,你看到这里的 engine 参数,它写着 demo-alfredo。这指的是我们实际部署并命名为 demo-alfredo 的模型。如果我给它起了不同的名字,这里也会不同。

令人困惑的是,你既获得了一个端点,也获得了一个密钥(你只获得一个密钥。如果你想使用另一个密钥,可以返回OpenAI服务的上一个仪表板)。但你是否注意到,这里的端点实际上是特定的?

这是因为当你通过不使用OpenAI库的方式与API通信时,你可以使用这个特定端点。如果我们在这里查看cURL命令行示例,你会看到它实际上使用了完整的、特定的API。

这是使用 https 的实际端点。对于Python的OpenAI库,它在幕后为你构建了这个地址。你可以在这里看到 preview1,然后 demo-alfredo 出现在这里。

核心要点总结

以下是需要牢记的几点:

  • 密钥管理:始终在Azure门户中安全地管理你的API密钥,并可以在必要时重新生成。
  • 端点类型:存在两种端点:
    • 通用端点:格式通常为 https://{your-resource-name}.openai.azure.com/。当使用OpenAI客户端库(如Python的 openai 库)时使用,库会帮你处理具体模型的路径。
    • 特定模型端点:格式为 https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-name}/...。当直接调用REST API(如使用cURL、Postman或其他不依赖特定SDK的客户端)时使用。
  • 模型标识:在代码中,通过 enginedeployment_id 参数来指定你要使用的具体模型部署(例如 demo-alfredo)。

代码示例对比

使用Python openai 库(通用端点 + 引擎参数)

import openai

openai.api_type = "azure"
openai.api_base = "https://devs-demo-alfredo.openai.azure.com/"  # 通用端点
openai.api_version = "2023-05-15"
openai.api_key = "YOUR_API_KEY"

response = openai.ChatCompletion.create(
    engine="demo-alfredo",  # 在此指定具体部署
    messages=[...]
)

使用cURL直接调用API(特定模型端点)

curl https://devs-demo-alfredo.openai.azure.com/openai/deployments/demo-alfredo/chat/completions?api-version=2023-05-15 \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages":[ ... ]}'

本节课中,我们一起学习了如何在Azure OpenAI服务中定位和管理API密钥与端点,并理解了通用端点与特定模型端点的区别及其在不同调用方式中的应用。正确配置这些信息是与大型语言模型成功交互的关键第一步。

大型语言模型实践:第2课:创建简单Python示例 🐍

在本节课中,我们将学习如何使用Python与OpenAI的API进行交互,创建一个简单的聊天机器人示例。我们将从环境设置开始,逐步讲解代码结构,并演示如何运行它。


上一节我们介绍了API的基本概念,本节中我们来看看如何用Python代码实现一个简单的交互程序。

我们保留了示例代码,现在开始与它交互,并使用Python。关于Python有几点需要注意。如果你直接复制这里的代码,它可能无法工作。代码示例要求openai Python库的版本为0.28.1或更低。因此,你一开始可能会在Python包管理上遇到挑战。如果你从未使用过Python,建议你使用这里提供的curl示例,它使用在大多数Unix系统终端(如苹果电脑、Linux电脑或Windows的WSL子系统)中可用的curl命令。

不过,让我们看看如何使用Python,并了解其具体操作。我将快速切换到我的文本编辑器,向你展示如何操作。这段代码是自上而下的,没有函数,只是代码。让我们看看我整合到一个脚本中的样子。

好的,这是相同的内容,但有一些区别。这里有一些声明。你可以看到openai_api_key是一个环境变量。我确保在打开这个脚本之前已经导出了它,稍后会展示具体做法。

然后,我没有采用自上而下的方式,而是创建了一个非常小的函数,并做了一些小的改动。我将添加一个user_message参数,当我传递它时,它会被附加在这里。这是模型与我交互的方式。我会说系统角色是“你是一个帮助人们查找信息的AI助手”,用户角色意味着“嘿,我是一个用户,我要传递一条消息”。然后,我将调用completion,它会有这些预先设置好的参数,与我们在Azure门户上看到的代码示例相同。

接下来,我将创建一个无限循环。我会要求用户输入消息,然后将用户消息传递给函数。然后,我会执行这里的操作,即从completion.choices中获取第一个选项,再从该选项中获取message,最后从该消息中获取content。这是因为在Python中,这背后是一个字典结构。我们不会深入Python的细节,只是说明它将如何工作。

好的,这看起来没问题。现在,我想展示另一件事,即requirements文件。我将关闭这些文件,你可以看到我已经按照要求安装了openai==0.28.1。双等号意味着我固定了这个版本,即精确选择版本0.28.1。

我将切换到我的终端。在终端中,我已经激活了一个虚拟环境。虚拟环境是Python中的一个概念,如果你从未使用过,可以执行类似python3 -m venv venv的命令来创建一个,然后使用source venv/bin/activate(在Windows上是venv\Scripts\activate)来激活它。激活后,你就可以安装依赖项了。在这个例子中,我们将使用pip并通过-r requirements.txt来安装。

本视频不会详细介绍Python的所有细节,只是快速演示。我已经预先安装好了所有依赖项。现在,我将运行python chat.py

好的,程序启动了:“欢迎,我今天能帮你什么?” 我可以说:“我觉得Python依赖管理有点棘手。”

消息被发送出去,然后收到了回复。很快,我们得到了回复:“Python依赖管理可能具有挑战性,尤其是在处理复杂项目时。一个流行的Python工具是Pip,我们一直在使用它。” 就是这样。

回到聊天程序,我们做了一点修改,使用了while True循环,这允许我们保持对话进行,不断添加更多消息并获取更多回复。你可以做类似的事情,或者添加你自己的变体。


以下是实现此功能的关键步骤和代码结构:

1. 环境变量设置
在运行脚本前,需要设置OpenAI API密钥为环境变量。

export OPENAI_API_KEY='your-api-key-here'

2. 依赖管理
创建一个requirements.txt文件来固定库版本。

openai==0.28.1

3. 核心Python脚本
主要代码逻辑封装在一个函数中,并包含一个交互循环。

import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")

def get_completion(user_message):
    messages = [
        {"role": "system", "content": "You are an AI assistant that helps people find information."},
        {"role": "user", "content": user_message}
    ]
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages,
        temperature=0.7,
        max_tokens=150
    )
    return response.choices[0].message.content

while True:
    user_input = input("You: ")
    if user_input.lower() in ['quit', 'exit']:
        break
    reply = get_completion(user_input)
    print(f"Assistant: {reply}")

本节课中我们一起学习了如何用Python创建一个简单的OpenAI API交互程序。我们涵盖了从设置环境变量、管理依赖到编写核心交互代码的完整流程。关键点包括使用特定版本的openai库、通过环境变量管理密钥、构建消息列表以及处理API响应。通过这个基础示例,你可以进一步扩展功能,构建更复杂的应用。

大型语言模型实践:第2章第4节:审查用量与配额 📊

在本节课中,我们将学习如何在Azure OpenAI服务中查看和管理你的模型使用量与配额。这对于监控成本、了解资源消耗以及规划后续使用至关重要。

上一节我们介绍了如何部署和调用模型,本节中我们来看看如何监控其使用情况。

我已经与Azure OpenAI服务进行了一些交互,部署了一个模型并使用了它。现在,我将去查看配额。配额选项就在“管理”栏目下,点击它并等待加载。

加载完成后,页面会显示我的部署具体使用了多少资源。我们等待它加载完毕。

加载已经完成。这里显示的是每分钟的令牌使用量(以千为单位),对应的是我实际部署的gpt-35-turbo模型。

目前,我的使用量是122,而总限额是240。这意味着在刚才简短的交互中,我已经使用了总限额的51%。这就是查看配额的方法。

你还可以看到这里列出了其他几项,因为我确实可以部署很多不同的模型。我将滚动到顶部,看看具体有哪些信息。

以下是配额页面的主要组成部分:

  • 按部署分离:我的使用量是按不同部署分开显示的。
  • 使用量限制:这里显示了我有一个部署的使用量是122,另一个是120,它们共同构成了我这个模型的总使用量。

对于同一个模型(本例中是gpt-35-turbo),你可以创建多个部署。目前,我为这个模型创建了两个部署。

需要记住的是,收费是基于使用量,而不一定是基于计算资源。这一点非常巧妙,因为它允许你专注于部署,只需担心API的消耗,而不必过多考虑底层计算资源。这提供了很大的灵活性。

这种机制让你能够密切关注正在使用的资源,并设置一些限制。

本节课中我们一起学习了如何在Azure OpenAI门户中查看配额和使用量报告,理解了按部署监控消耗的方式,以及基于使用量(而非纯计算)的计费模式带来的灵活性。这有助于你有效地管理和控制项目成本。

大型语言模型实践:第2章第5节:清理Azure资源 🧹

在本节课中,我们将学习如何在Azure平台上清理已使用的资源,特别是与Azure OpenAI服务相关的资源。我们将重点介绍如何使用资源组来高效、安全地批量删除资源,以避免产生不必要的费用。

上一节我们介绍了如何部署和使用Azure OpenAI服务。本节中,我们来看看如何在使用完毕后,系统地清理这些云资源。

理解资源组的概念

在Azure中,资源组是一个核心管理概念。它可以将多个服务于同一目的的资源(例如虚拟机、数据库、AI服务)逻辑上组合在一起。这极大地简化了资源的管理和生命周期操作。

核心公式资源组 = 逻辑容器(包含多个相关的Azure资源)

清理资源的步骤

以下是清理资源的推荐流程,其核心是通过删除整个资源组来一次性移除所有关联资源。

  1. 定位资源组
    登录Azure门户,在左侧导航栏中找到并点击“资源组”。页面会列出您账户下所有订阅中的资源组。为了便于管理,建议在创建演示或测试资源时,为资源组使用统一的命名前缀(例如“demo-”)。

  2. 确认资源组内容
    点击您想要删除的资源组名称(例如“demo-alfredo-azure”)。在资源组详情页面,您可以查看该组内包含的所有资源列表。这有助于在删除前进行最终确认。

  3. 删除资源组
    在资源组的工具栏或概览页面中,找到并点击“删除资源组”按钮。系统会要求您输入资源组的名称以确认操作。请注意,此操作不可逆,将永久删除该资源组内的所有服务。

  4. 等待删除完成
    确认删除后,Azure会开始异步删除过程。您会看到资源组的状态变为“正在删除”。此过程可能需要一些时间,具体取决于组内资源的数量和类型。删除完成后,所有相关资源及其产生的消费都将停止。

总结

本节课中我们一起学习了Azure资源清理的最佳实践。关键要点是:利用资源组对相关资源进行逻辑分组,并通过删除整个资源组来高效、彻底地清理所有资源。这种方法避免了逐个查找和删除单个服务的繁琐,并能有效控制云服务成本,特别适用于实验和演示环境的资源管理。请务必在删除前仔细确认资源组内容。

大型语言模型实践:3.2.6:总结与资源管理 🧹

在本节中,我们将总结如何与Azure OpenAI服务进行交互,并学习如何查看使用情况以及清理资源,以避免产生不必要的费用。

上一节我们介绍了通过Python代码调用Azure OpenAI API的具体方法。本节中,我们来看看如何管理我们的资源。

课程内容回顾 📝

我们学习了如何与Azure OpenAI服务及其API进行交互。

具体来说,我们研究了HTTP API,查看了其端点(endpoints)的构成。我们在Azure OpenAI服务工作室(studio)中查看了一些示例,这些示例清晰地展示了在模型部署后,我们应如何与之交互。

我们创建了一个简单的Python示例来实际调用API。

资源管理与清理 🗑️

最后,回顾使用情况并妥善清理资源至关重要。理解其工作原理以及如何清理资源是必要的。这样,当你完成工作后,就可以销毁这些资源,避免为不再使用的资源付费。

以下是资源管理的核心步骤:

  1. 监控使用情况:定期在Azure门户中检查服务的用量和费用。
  2. 识别闲置资源:确定哪些部署或资源已经不再需要。
  3. 执行清理操作:删除或停用不再使用的模型部署和相关资源。

总结

本节课中我们一起学习了与Azure OpenAI服务交互的全过程:从了解API端点,到通过工作室和Python代码进行调用,最后强调了监控使用情况和清理闲置资源的重要性。掌握这些步骤能帮助你高效、经济地利用云上AI服务。

大型语言模型实践:1.1:引言与可扩展性概述

在本节课中,我们将要学习大型语言模型(LLM)可扩展性的核心概念。理解这一点对于正确运用已部署的模型至关重要。

可扩展性的重要性

当你拥有一个已部署的实际模型时,例如Azure OpenAI服务中的OpenAI模型,正确把握其可扩展性就变得非常关键。

你的应用程序的关键差异化因素将在于你如何与这个已部署的模型进行交互。显然,直接使用默认的原始模型是不够的,我们有多种方法来扩展它。

本课程核心内容

接下来,我们将深入探讨如何通过特定框架来改进提示工程。我们将介绍一个名为Semantic Kernel的框架。

我们将了解Semantic Kernel究竟是什么,以及如何在Azure环境中与之交互。课程中会使用系统提示,并初步探索一些高级系统提示的用法。


本节课中我们一起学习了大型语言模型可扩展性的基本概念及其重要性,并预览了后续将深入学习的改进提示工程的方法与Semantic Kernel框架。

大型语言模型实践:1.2:什么是语义内核 🧠

在本节课中,我们将要学习什么是语义内核(Semantic Kernel)。它是一个由微软提供的框架,旨在帮助开发者更灵活、更统一地与不同的大型语言模型进行交互和集成。

概述

语义内核是一个多语言支持的框架。它的核心能力在于允许开发者对不同模型(特别是大型语言模型)的交互功能进行抽象和泛化。这意味着你可以创建自己的组件和扩展,完全掌控如何与模型交互,而不会被强制绑定到某个特定的模型提供商。

语义内核的核心概念

上一节我们介绍了语义内核的基本定义,本节中我们来看看它的核心组成部分。框架的核心被称为 Kernel

在 Kernel 这个核心框架内,你将拥有一个上下文(Context)。你可以向其中提供、添加或放入内容,供大型语言模型使用。此外,你将能够创建函数(Functions)、进行规划(Planning)、实现记忆召回(Recall Memory) 等功能。

一个特别重要的概念是原生函数(Native Function)。这是一种通过调用本地代码来扩展大型语言模型功能的方式。

支持的语言与我们的重点

以下是语义内核框架目前支持的编程语言:

  • C#
  • Python
  • Java

在本课程中,我们将重点使用 Python 来创建API和运行示例。我们会确保所有操作都基于 Azure 的聊天补全服务,而不是直接使用OpenAI的接口,但两者的差异不会造成理解上的困难。

与其他工具的对比

如果觉得语义内核的概念难以掌握,需要知道市场上存在其他类似的选择。其中一个著名的、开源的、并非微软专属的替代品是 LangChain。不过,本课程将专注于讲解和使用语义内核。

总结

本节课中我们一起学习了语义内核。本质上,语义内核是一个框架。它使我们能够以统一的方式与多种大型语言模型(如Azure部署的模型或OpenAI的模型)进行交互,并构建包含自定义函数、规划和记忆等高级功能的应用。接下来,我们将尝试使用它,并探索如何让其与Azure协同工作。

大型语言模型实践:第3课:在Azure中使用语义内核 🚀

在本节课中,我们将学习如何通过语义内核框架,在Azure OpenAI服务上构建一个简单的聊天应用。我们将从获取必要的Azure配置信息开始,逐步完成代码的编写与执行。

概述

语义内核是一个用于构建AI应用的框架。要让它与Azure OpenAI服务协同工作,我们需要从Azure门户获取特定的配置信息,并在代码中进行正确设置。本节教程将引导你完成这一过程。

从Azure门户获取配置

上一节我们介绍了语义内核的基本概念,本节中我们来看看如何从Azure门户获取必要的连接信息。

首先,我们需要登录Azure OpenAI服务门户,查看已部署的模型。

  1. 在Azure门户中,找到并点击你的部署。本示例中使用的是名为 demodallfredo 的部署。
  2. 点击部署名称,进入详情页。这一步非常重要,错误的配置会导致后续步骤失败。
  3. 在详情页中,打开“Playground”界面。
  4. 在Playground中向下滚动,直到找到“代码”示例部分。我们需要从这里获取两个关键信息:端点密钥

关于端点地址,需要注意语义内核的调用方式可能造成混淆。在代码示例中,你可能会看到一个完整的URL,例如:
https://demodallfredo-openai.openai.azure.com/

然而,语义内核框架在配置时,通常只需要URL的特定部分作为“基础端点”。具体需要哪一部分,我们将在代码中明确。

接下来,复制你的API密钥。这些信息需要被妥善保存,我们将在下一步将其放入代码的配置文件中。

设置开发环境与依赖

获取配置信息后,我们现在切换到开发环境来编写代码。你可以使用任何喜欢的编辑器,这里以VS Code为例。

首先,确保安装了正确版本的语义内核库,这对于代码的稳定运行至关重要。你可以通过终端命令查看已安装的版本。

以下是检查版本的命令:

pip show semantic-kernel

确认版本后,我们开始编写主要的聊天应用文件。这个应用将是一个独立的Python脚本。

编写聊天应用程序

现在,我们来逐步构建这个聊天应用。核心步骤包括导入库、加载密钥、初始化内核以及执行查询。

首先,我们需要导入必要的模块,其中 AzureChatCompletion 是用于连接Azure服务的核心类。

为了避免将敏感的API密钥和端点硬编码在脚本中,我们将它们存储在一个单独的 .env 配置文件中。这需要使用 python-dotenv 库来读取。

以下是如何在代码中加载配置文件的示例:

from dotenv import load_dotenv
import os

# 加载 .env 文件中的环境变量
load_dotenv()

# 从环境变量中读取配置
api_key = os.getenv("AZURE_OPENAI_API_KEY")
endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
deployment_name = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")

配置文件 .env 的内容如下所示,请替换为你自己的值:

AZURE_OPENAI_API_KEY=你的API密钥
AZURE_OPENAI_ENDPOINT=你的端点URL
AZURE_OPENAI_DEPLOYMENT_NAME=你的部署名称

回到主脚本,初始化过程遵循语义内核的规范:

  1. 创建一个内核实例。
  2. 添加一个基于Azure的聊天完成服务,并传入部署名称、端点和API密钥。
  3. 准备用户输入的问题。
  4. 调用内核来获取模型的回复。

以下是执行查询的核心代码片段:

import asyncio
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel import Kernel

async def main():
    # 初始化内核
    kernel = Kernel()
    
    # 添加Azure聊天服务
    chat_service = AzureChatCompletion(
        deployment_name=deployment_name,
        endpoint=endpoint,
        api_key=api_key,
    )
    kernel.add_chat_service("chat_completion", chat_service)
    
    # 定义用户输入
    user_input = "你的问题在这里"
    
    # 调用模型并获取回复
    reply = await kernel.invoke_chat_async(chat_service, user_input)
    print(reply)

# 运行异步主函数
asyncio.run(main())

运行与测试

代码编写完成后,我们可以在终端中运行它来测试是否一切正常。

使用以下命令运行脚本:

python chat_app.py

如果配置正确,脚本将通过HTTP请求与Azure OpenAI模型交互,并将模型的回答打印到终端。例如,对于关于如何制作出色咖啡的问题,模型可能会返回涉及烘焙、研磨、水温等变量的详细步骤。

总结

本节课中我们一起学习了在Azure上使用语义内核框架的完整流程。关键步骤包括:从Azure门户获取端点和密钥、在开发环境中设置依赖、通过配置文件管理敏感信息、初始化语义内核并添加Azure聊天服务,最后执行查询并获取结果。请特别注意端点的配置方式以及密钥的安全管理,这是成功连接服务的基础。

大型语言模型实践:P120:使用系统提示

概述

在本节课中,我们将学习如何通过修改“系统提示”来定制大型语言模型(如GPT)的聊天行为。系统提示是一种配置方式,它允许开发者在不改变用户输入的情况下,引导模型以特定的风格、角色或格式进行回复。我们将通过一个简单的天气查询聊天机器人示例来演示其应用。

系统提示的概念与作用

上一节我们介绍了如何调用聊天完成接口。本节中,我们来看看如何通过系统提示来塑造聊天机器人的“个性”和回复方式。

系统提示是发送给模型的一条隐藏指令,它设定了模型的角色、任务和回复规范。用户看不到这条提示,但模型的每一次回复都会遵循其中的设定。这就像在幕后为模型编写了一个“角色扮演”的脚本。

实践:修改系统提示

以下是修改系统提示并观察其效果的具体步骤。

  1. 定义系统提示内容
    我们首先需要编写一个系统提示。例如,我们可以这样设定:

    system_prompt = “你是一个旅行天气聊天机器人。你的名字是Frederick。你的任务是帮助人们查找某城市在某月份的平均气温。请始终以你的名字和一个友好的问候语开头进行回复。”
    
  2. 将提示集成到请求中
    在调用模型的API时,我们需要将这条系统提示作为消息列表的一部分发送。通常,消息列表的第一条就是系统提示。

    messages = [
        {“role”: “system”, “content”: system_prompt},
        {“role”: “user”, “content”: “西雅图六月的平均气温是多少?”}
    ]
    
  3. 观察模型回复的变化
    当模型收到包含上述系统提示的请求后,它的回复将不再是通用的答案,而是会遵循我们的设定。例如,它可能会回复:“你好!我是Frederick。很高兴为您服务。西雅图六月的平均气温大约在15摄氏度左右。”

增强系统提示的功能

我们可以通过增加指令来进一步细化模型的行为。例如,在原有的系统提示末尾加上:“并且,请总是以正式的方式建议使用防晒霜。”

修改后的系统提示如下:

system_prompt = “你是一个旅行天气聊天机器人。你的名字是Frederick。你的任务是帮助人们查找某城市在某月份的平均气温。请始终以你的名字和一个友好的问候语开头进行回复。并且,请总是以正式的方式建议使用防晒霜。”

再次向模型提问同样的问题,回复可能会变为:“你好!我是Frederick。很高兴为您服务。西雅图六月的平均气温大约在15摄氏度左右。此外,户外活动时注意防晒总是个好主意,建议您使用防晒霜。”

通过这种方式,我们无需改变任何用户交互界面或后端逻辑,仅仅通过修改一条隐藏的指令,就为聊天体验增加了新的功能层。

总结

本节课中,我们一起学习了系统提示的用途和配置方法。系统提示是一个强大的工具,它允许开发者在不改变应用核心代码的情况下,精细地控制大型语言模型的输出风格、内容和行为。通过定义明确的角色、任务和回复规范,我们可以轻松地创建出具有特定个性和功能的聊天机器人,从而为用户提供更定制化、更专业的交互体验。

大型语言模型实践:P121:高级系统提示

在本节课中,我们将学习如何构建一个高级的系统提示。我们将结合系统提示和用户输入,通过一个具体的例子来展示如何灵活地引导大型语言模型生成特定内容。

上一节我们介绍了基本的提示模板配置,本节中我们来看看如何通过组合系统角色和用户输入来创建更复杂的交互场景。

环境与配置

首先,我们像之前一样加载运行内核所需的一切。我们仍然添加相同的Azure聊天补全服务端点,没有做任何更改。我们正在构建这个补全提示模板配置。

以下是核心的配置代码:

# 加载内核所需的一切
# 添加Azure聊天补全端点
# 构建补全提示模板配置

定义系统角色

在本例中,情况略有不同。我们定义了一个系统角色:“你是一名葡萄酒专家(侍酒师),你的名字是Solfredo。” 是的,我给它起了和我一样的名字,这没问题。

这里有一个关键的调整:“你只了解品丽珠(Canet franc)。因此,你提出的任何推荐都必须坚持将品丽珠作为替代选择。” 这有点有趣。我将“品丽珠”应用到了系统提示中,这意味着这个信息对用户是抽象的。你可能会说,但这只是一个系统提示,用户可能想要进行一些调整。

组合用户输入与额外上下文

在聊天提示模板中,你可以传递用户输入,这没有问题。所以,{user_input} 将代表用户要询问的内容。然后,我向这个输入添加了额外的上下文。我添加了字符 \n\n 来创建两个新行,这是一个有趣的做法。

以下是添加到用户输入后的额外指令:

请提供三种葡萄酒选项并附上描述。可以编造葡萄酒的描述,我的意思是,我是故意这么做的,我会编造一些不太准确的内容。可以编造不存在的葡萄酒的描述,所以我告诉模型放松,不必那么精确。

执行与输出

让我们看看具体的问题。我将在这里执行,用户输入将是:“我想要一款适合晚餐派对的葡萄酒。” 这看起来不错。我们实际上是在让这个模板能够接收用户输入。你在这里看到的 {user_input} 将来自这个变量。此外,这段文本将被附加到用户输入之后,模型将接收到所有这些信息:即用户输入加上我们附加的额外指令。

让我们切换回终端,运行 Python chat.py,看看会发生什么。

输出结果如下:

当然,为您的晚餐派对准备了三款绝佳的葡萄酒选项,它们一定会给您的客人留下深刻印象。
选项一:Château Beaulieu Cane Franc
选项二:Domaine du Cane Franc Réserve
选项三:Labelveier Cane Franc
全部都是品丽珠,完美。
请注意,所有这些选项都突出了品丽珠的多功能性和独特特性,使它们成为您晚餐派对的绝佳替代选择。

这是一个有趣的方法,也是一种巧妙的方式,可以让你灵活地调整输入并获得出色的输出。这非常有趣。从这里我们可以看到,像语义内核这样的框架开始展现出其作为工具的实用性,并且能够在更复杂的场景中发挥作用。

总结

本节课中我们一起学习了如何构建高级系统提示。我们通过定义一个特定的系统角色(葡萄酒专家Solfredo)并为其添加严格的约束(只推荐品丽珠),然后将用户输入与额外的、鼓励创造性的指令相结合,最终引导模型生成了符合所有预设条件的输出。这种方法展示了如何通过精心设计的提示工程,灵活且有效地引导大型语言模型的行为,为处理更复杂的应用场景提供了基础。

大型语言模型实践:4.6:总结 🎯

在本节课中,我们将回顾并总结关于语义内核(Semantic Kernel)及其与Azure OpenAI服务集成的关键内容。我们将探讨系统提示词的重要性,以及如何通过调整它来优化用户与大型语言模型的交互。

回顾语义内核与Azure的集成

上一节我们介绍了语义内核的基本概念,本节中我们来看看如何将其与外部服务连接。

我们研究了语义内核,并初步探索了如何与之交互。我们学习了如何将语义内核这个非常有用的框架,与Azure平台,特别是Azure OpenAI服务以及我们先前部署的一些模型进行连接。

系统提示词的重要性与应用

理解了框架的连接方式后,接下来我们关注如何塑造模型的交互行为。

我们也涵盖了一些关于系统提示词的内容。这之所以重要,是因为我们可以通过它开始调整用户与大型语言模型之间可能的交互方式。这是一个非常重要且关键的方面,因为这是你真正开始思考如何将这些类型的框架和代码组件融入你的应用程序架构的起点。

当你开始思考希望如何与你的用户进行交互时,拥有一个系统提示词,乃至一个高级的系统提示词,是一种非常有趣且实施起来并不费力的方法。我们看到了如何开始调整它,以及如何在大型语言模型部署后立即获得效果,使其开始与用户产生特定的交互。

核心收获与未来方向

以下是本部分内容的核心要点总结:

  • 框架连接:语义内核可以与Azure OpenAI Service 无缝集成,调用已部署的模型。
  • 控制交互:通过精心设计系统提示词(System Prompt),开发者可以引导和塑造LLM的对话行为与输出风格。
  • 快速迭代:对系统提示词的调整能够快速生效,便于开发者即时测试和优化交互效果。

本节课中我们一起学习了语义内核与Azure服务的集成方法,并深入探讨了系统提示词在引导大型语言模型行为中的关键作用。掌握这些概念是构建基于LLM的应用程序的重要基础。

大型语言模型实践:1.3:使用函数扩展交互 🛠️

在本节课程中,我们将学习如何超越简单的提示词调整,通过使用“函数”来扩展与大型语言模型的交互能力。我们将了解函数是什么、如何定义它们,以及如何在实际中与LLM结合使用。此外,我们还将探讨一个非常实用的话题:如何处理使用过程中可能出现的错误。

什么是函数?

上一节我们介绍了如何通过系统提示词来引导模型行为。本节中,我们来看看如何通过“函数”来赋予大型语言模型更强大的交互与执行能力。

函数本质上是一段预定义的、可被模型调用的代码或操作。它允许LLM不仅生成文本,还能触发外部工具、查询数据或执行特定计算,从而将模型的“思考”能力与外部系统的“执行”能力结合起来。

如何定义与使用函数?

理解了函数的概念后,接下来我们需要知道如何定义它们,并将其集成到与LLM的交互流程中。

以下是定义和使用函数的核心步骤:

  1. 函数定义:首先,你需要以结构化格式(通常是JSON Schema)明确描述函数的名称、目的、所需参数及其类型。这相当于为模型提供一份清晰的“工具说明书”。

    {
      "name": "get_weather",
      "description": "获取指定城市的当前天气",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "城市名称,例如:北京"
          }
        },
        "required": ["location"]
      }
    }
    
  2. 函数调用:在对话中,当LLM判断需要调用某个函数来完成用户请求时,它不会直接输出答案,而是会返回一个结构化的函数调用请求,其中包含要调用的函数名和具体的参数值。

  3. 执行与返回:你的应用程序接收到这个调用请求后,在后台执行真正的函数代码(例如,调用一个天气API),然后将执行结果返回给LLM。

  4. 结果整合:LLM收到函数的执行结果后,会将这些信息整合到上下文中,并生成最终面向用户的自然语言回复。

处理错误与故障排除 🚨

在扩展LLM功能时,事情并非总能一帆风顺。理解可能出现的错误并知道如何应对,是构建健壮应用的关键。

当函数调用或执行过程中出现问题时,可能会遇到以下几种典型错误:

  • 参数错误:模型提供的函数参数不符合定义的要求(例如类型错误、缺少必需参数)。
  • 执行失败:外部函数本身执行时出错(例如API服务不可用、数据库查询失败)。
  • 上下文误解:模型错误地判断了调用函数的必要性或时机。

为了从容地处理这些错误,你可以采取以下策略:

  • 在代码中实现完善的错误捕获和异常处理机制。
  • 设计清晰的错误信息反馈路径,让模型能够理解问题所在并尝试调整。
  • 在系统提示词中预先说明函数的限制和常见问题。

通过系统地处理错误,你可以快速定位和修复应用中的问题,确保用户体验的流畅性。

课程总结

本节课中,我们一起学习了如何通过“函数”来扩展大型语言模型的交互能力。我们首先了解了函数的基本概念,然后详细探讨了从定义、调用到执行的完整工作流程。最后,我们还介绍了在集成函数时可能遇到的错误类型以及基本的处理策略,帮助你构建更可靠、功能更强大的LLM应用。

大型语言模型实践:P124:功能概述 🧠

在本节课中,我们将要学习大型语言模型中“功能”的概念及其工作原理。功能是增强LLM能力的关键机制,允许模型与外部数据源或API进行交互,从而提供更准确、更具体的回答。


用户输入与初始流程

我们首先从用户输入开始。用户输入是指用户向大型语言模型提出的任何问题或发出的任何指令,本质上就是一个提示词。

整个流程的第一步是收集这个提示词。随后,这个提示词会被发送到聊天应用程序进行处理。这个聊天应用程序可以是任何能够与LLM交互的框架或库,例如Semantic Kernel,也可以是简单的库。

流程示意:
用户输入 -> 聊天应用 -> LLM


传统流程的局限性

上一节我们介绍了基本的交互流程。接下来,我们通过一个具体例子来理解其局限性。假设用户提问:“波士顿一月的天气如何?”

按照传统流程,这个提示词会从聊天应用直接发送给LLM。LLM会基于其训练数据生成一个通用的、概率性的回答。然而,LLM本身并不具备获取实时天气数据的能力,因此其回答可能不够准确或具体。

传统流程:
用户输入(天气问题) -> 聊天应用 -> LLM -> 聊天应用 -> 用户回答(基于训练数据的通用回答)


引入功能作为中间步骤

为了解决上述局限性,我们引入“功能”作为中间步骤。功能充当了LLM与外部世界之间的中介。

当LLM收到提示词(如天气查询)后,它不会直接生成最终答案。相反,LLM会与聊天应用进行逻辑判断,识别出用户意图可能需要调用某个特定功能。例如,LLM会判断:“这个问题似乎与天气有关,调用天气API功能可能更合适。”

于是,流程变为:聊天应用将LLM识别出的关键信息(如地点“波士顿”、时间“一月”)发送给对应的功能(例如一个天气API)。该功能执行操作(调用API获取实时数据),并将结果返回给聊天应用。

引入功能后的流程:
用户输入 -> 聊天应用 -> LLM -> 聊天应用 -> 功能(如天气API) -> 聊天应用 -> LLM -> 聊天应用 -> 用户回答


功能的工作机制与价值

虽然这个流程看起来比传统方式复杂,但其核心价值在于为LLM赋予了“超能力”。LLM本质上是一个概率机器,擅长理解和生成语言,但缺乏获取实时、特定外部数据的能力。

功能机制通过以下方式增强了LLM:

  1. 提供落地信息:为LLM的回答补充具体、准确的事实数据。
  2. 添加上下文:引入外部知识,使回答更具相关性和实用性。
  3. 扩展能力边界:使LLM能够完成原本无法独立完成的任务,如查询天气、检索数据库、执行计算等。

我们可以将这个过程想象为给LLM插上了一个“插件”,让它能够按需调用各种工具和服务。


核心概念总结

本节课中我们一起学习了LLM中功能的核心概念。关键要点如下:

  • 功能定义:功能是LLM与外部系统(如API、数据库)交互的中间件。
  • 工作流程:用户输入经LLM解析后,触发特定功能执行,功能返回的结果再经LLM整合,最终形成给用户的回答。
  • 核心价值:功能为LLM提供了落地性扩展性,使其回答基于实时、准确的外部数据,而不仅仅是训练数据中的概率模式。

通过引入功能,我们能够构建更强大、更实用的基于大型语言模型的应用程序。

大型语言模型实践:P125:48_03_03_定义功能

在本节课中,我们将学习如何在语义内核(Semantic Kernel)中定义功能。我们将了解语义内核中“功能”的概念,它与传统编程中的函数有何不同,并通过一个具体的“葡萄酒插件”示例来演示其结构和配置方法。


语义内核中的“功能”概念

上一节我们介绍了语义内核的基本概念,本节中我们来看看如何定义功能。首先需要明确,语义内核中的“功能”可能容易引起混淆。它并非特指像Python函数那样的编程函数,而是语义内核的组件。这些组件可以是一个实际的函数,也可以是其他形式,它更像是一组配置的集合,类似于“插件”的概念。我们稍后将看到这些插件如何工作。

对于当前我们要进行的实现,我们不会讨论实际的Python函数(在语义内核中也称为内联函数或原生函数)。这些概念可能在其他框架(如LangChain)中也有类似体现,具体取决于你使用的框架,你需要弄清楚你正在使用哪种能力。

代码结构与初始化

以下是定义功能的基本代码结构。我们将逐步解析每一部分。

# 定义文件路径并加载密钥
import os
from dotenv import load_dotenv

load_dotenv()

# 初始化内核
from semantic_kernel import Kernel
kernel = Kernel()

# 加载配置文件并提取OpenAI部署信息
deployment_name = os.getenv("OPENAI_DEPLOYMENT_NAME")
endpoint = os.getenv("OPENAI_ENDPOINT")
api_key = os.getenv("OPENAI_API_KEY")

# 初始化内核聊天服务
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
kernel.add_chat_service("chat_completion", OpenAIChatCompletion(deployment_name, endpoint, api_key))

导入与使用插件

接下来,我们将导入一个名为“wine_plugin”的插件。请注意,在语义内核的文档和示例中,“技能”(skill)和“插件”(plugin)这两个术语有时会混用。为了与文档保持一致,此处我们沿用相同的布局。

# 导入插件(技能)
plugins_directory = "./plugins"
wine_plugin = kernel.import_semantic_skill_from_directory(plugins_directory, "wine_plugin")

# 使用插件中的功能
result = wine_plugin["sommelier"]("Merlot")
print(result)

代码中,plugins_directory 是一个相对路径,指向包含插件的目录。我们调用了插件中名为 sommelier 的功能,并传入参数 "Merlot"

插件目录结构

现在,让我们查看插件的物理结构,以理解其组织方式。

以下是插件目录的结构示例:

plugins/
└── wine_plugin/
    └── sommelier/
        ├── config.json
        └── skprompt.txt

可以看到,这与我们代码中的引用路径 plugins/wine_plugin/sommelier 完全对应。每个功能(如 sommelier)都是一个独立的子目录,其中包含必要的配置文件。

配置文件解析

每个功能目录下通常包含两个关键文件:config.jsonskprompt.txt

首先,我们看看 config.json 文件的内容:

{
  "schema": 1,
  "type": "completion",
  "description": "Given a type of wine, suggest possible dishes.",
  "completion": {
    "max_tokens": 500,
    "temperature": 0.5,
    "top_p": 1.0,
    "presence_penalty": 0.0,
    "frequency_penalty": 0.0
  },
  "input": {
    "parameters": [
      {
        "name": "input",
        "description": "The type of wine to suggest possible dishes for.",
        "defaultValue": ""
      }
    ]
  }
}

这个配置文件定义了功能的类型、描述、与大语言模型交互的参数(如token数量、温度等),以及输入参数的名称和描述。这里的输入参数名为 input

提示词模板

接下来,我们查看 skprompt.txt 文件,它包含了发送给大语言模型的具体提示词模板。

Generate three potential dishes for pairing with the given wine.
The wine can be a distinct grape, a type of wine like red, white, or bubbly.
Sometimes the given wine description might not be super accurate, so make sure you always suggest dishes regardless.

Wine: {{$input}}

提示词模板中,{{$input}} 是一个变量,它会被替换为调用功能时传入的实际参数值(例如 "Merlot")。这个 input 变量名与 config.json 中定义的输入参数名 input 必须一致。如果你在配置中将参数名改为其他名称,那么提示词模板中的变量名也需要相应更改。


总结

本节课中我们一起学习了在语义内核中定义功能的方法。我们明确了语义内核的“功能”是类似于插件的配置组件,并逐步解析了其代码结构、插件导入方式、目录组织以及核心的配置文件和提示词模板。通过 config.jsonskprompt.txt 两个文件的配合,我们可以灵活地定义和配置一个非原生的语义功能,为后续构建更复杂的应用打下基础。

大型语言模型实践:P126:在大型语言模型中使用功能

概述

在本节课程中,我们将学习如何在Azure平台上部署的实际大型语言模型中使用功能。我们将通过一个具体的例子——为特定葡萄酒推荐搭配菜肴——来演示如何正确配置和调用模型,并指出配置过程中常见的陷阱。

配置与准备工作

上一节我们介绍了功能的基本概念,本节中我们来看看如何将其应用于实际的Azure大型语言模型。首先,我们需要确保正确配置了访问模型所需的密钥和参数。

我们定义了三个关键参数来连接Azure OpenAI服务:

  • 部署名称 (deployment_name)
  • 终端节点 (endpoint)
  • API密钥 (api_key)

正确配置这些参数至关重要。一个常见的错误是混淆它们的顺序或格式,这会导致调用失败。务必使用关键字参数的形式来传递它们,以确保清晰和准确。

以下是使用openai库初始化客户端的代码示例:

client = AzureOpenAI(
    api_key=api_key,
    api_version="2023-05-15",
    azure_endpoint=endpoint
)

执行模型调用

配置好客户端后,我们就可以向模型发送请求了。我们的目标是让模型根据输入的葡萄酒类型,推荐三道可能的搭配菜肴。

我们构建的提示词(prompt)结构如下:

  • 指令:为给定的葡萄酒生成三道潜在的搭配菜肴。
  • 输入:葡萄酒的类型(例如:Merlot)。

以下是调用模型完成请求的代码:

completion = client.chat.completions.create(
    model=deployment_name,
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": prompt}
    ]
)

运行示例与调试

现在,让我们在终端中运行脚本。输入葡萄酒类型为“Merlot”。

执行命令:

python chat.py

如果所有配置正确,模型将返回推荐菜肴,例如:烤肋眼牛排、蘑菇烩饭、黑巧克力慕斯。

然而,配置错误是常见问题。如果参数传递顺序错误或格式不对(例如,误将API密钥当作URL),你会收到类似“URL parsing”的错误提示。这时,需要返回并仔细检查deployment_nameendpointapi_key这三个参数的赋值是否正确。

尝试不同输入

调试成功后,我们可以轻松更改输入来获取不同的推荐。例如,将输入从“Merlot”改为“white wine”。

再次运行脚本,模型将返回适合白葡萄酒的菜肴推荐,例如:烤柠檬香草鸡、扇贝意大利面、卡普里沙拉。

这个过程展示了模型的灵活性,但也再次强调了初始配置准确性的重要。

总结

本节课中我们一起学习了在Azure大型语言模型中调用功能的具体步骤。核心在于正确配置连接参数并使用关键字参数来避免混淆。我们通过一个葡萄酒配餐的实例,演示了从构建提示词、调用模型到处理结果和调试错误的完整流程。记住,仔细检查deployment_nameendpointapi_key是成功调用的关键。

大型语言模型实践:P127:处理错误 🔧

在本节中,我们将学习如何识别和处理在使用Azure与语义内核(Semantic Kernel)时可能遇到的一些常见错误。理解这些错误信息对于调试和确保应用程序正常运行至关重要。

概述

我们已经初步了解了在使用Azure和语义内核工作时可能遇到的一些问题。本节将专门介绍几种你可能遇到的错误类型。这些错误常常出人意料,是开发过程中的痛点。我们将快速浏览几种常见情况,帮助你更好地应对。

部署名称错误

首先,我们从部署名称开始。我将故意使用一个不正确的部署名称。这是最容易犯的错误之一,请务必亲自尝试,因为你的环境情况也可能发生变化。

以下是部署名称错误时的处理步骤:

  1. 运行包含错误部署名称的Python文件。
  2. 系统通常会返回一个404错误,这表示“未找到”。
  3. 错误信息会明确指出“部署未找到”,并提示“此资源的API部署不存在”。

需要记住的是,在Azure中,如果你刚完成部署且时间少于五分钟,有时也可能收到相同的错误。虽然这令人沮丧,但至少错误信息指明了原因。因此,如果刚刚创建了部署,请至少等待五分钟再尝试。

现在,让我们修正这个错误,使其正常工作。

终端点(Endpoint)错误

接下来,我们看看终端点错误。你可能收到提示,指出这不是一个有效的URL。例如,如果输入为空,你会收到验证错误:“输入应为有效的URL,输入为空”。

让我们尝试一个错误的URL,例如 https://example.do.co,然后保存并运行代码。

我们可能会在异常中看到一个比较刻意的错误,例如“未找到错误”(404)。这个错误信息可能不够清晰,它不会明确告诉你问题出在终端点上。因此,请务必确保终端点指向你环境中实际存在的有效地址。

现在,让我们修正终端点,填入正确的值。

API密钥错误

最后,我们来处理API密钥错误。首先,尝试将API密钥设置为None

此时,你会收到提示:“请提供API密钥、令牌或令牌提供者”。这个信息虽然没有以非常友好的方式明确指出问题,但你能看到这里传入了None

接着,我们将其改为一个字符串,但使用一个完全无效的API密钥,例如“empty_token”。

运行后,我们会收到“未经授权:访问令牌缺失、无效或受众不正确”的错误。这是一个很好的身份验证错误,明确指出了访问令牌的问题,非常有用。据此,我可以判断这个密钥不正确。

现在,让我们去修正它。

总结

在本节课中,我们一起学习了如何处理Azure语义内核中的常见配置错误。你需要确保部署名称终端点API密钥这三部分信息都正确无误。通过这样的试错过程,你将能够理解什么是有效的、什么是无效的,并至少对如何尝试修复问题有一个基本的概念。

大型语言模型实践:5.3.6:总结 🎯

在本节中,我们将总结关于扩展大型语言模型功能的核心方法,特别是通过使用函数(Functions)来实现。我们将回顾如何定义和使用函数,并探讨在不同框架中处理函数时需要注意的差异。

概述

本节课我们学习了如何利用函数来增强大型语言模型的功能。我们看到了函数的具体定义和使用方法,并了解了在处理错误时应关注的关键点。最后,我们展望了函数在不同框架中的扩展性及其在构建实际应用中的潜力。


函数功能的扩展与应用

上一节我们介绍了函数的基本概念和调用方法。本节中,我们来看看如何将函数与大型语言模型结合使用,并总结其中的关键要点。

我们看到了如何使用函数来扩展功能。同时,理解函数在不同框架中可能具有不同含义这一点也很有用。但我们最终成功定义了一个函数,并将其与大型语言模型结合使用。

在最后阶段,我们还处理了错误,并分析了当操作失败时,你应该关注的一些潜在问题。


函数的通用性与框架扩展性

我认为,函数本身以及你在诸如 Semantic Kernel 等框架中看到的扩展性——以及我们尚未接触的其他框架如 LangChain——将非常有趣。

以下是关于函数扩展性的核心价值:

  • 跨框架应用:函数是连接不同工具和服务的通用模式。
  • 功能增强:通过 function_nameparameters 的定义,LLM 可以调用外部能力。
  • 错误处理:健壮的应用需要包含对 error handlingfallback strategies 的考量。

当我们尝试构建应用程序,或思考可以利用大型语言模型部署的潜在应用时,如何利用这些不同的组件将会非常有趣。


总结

本节课中,我们一起学习了如何通过定义和使用函数来扩展大型语言模型的功能。我们掌握了函数与LLM集成的关键步骤,并认识到函数在不同开发框架中的灵活性与重要性。同时,我们也初步了解了构建可靠应用时必须考虑的错误处理机制。这些知识为我们未来利用LLM框架构建更复杂的应用打下了坚实的基础。

大型语言模型实践:P129:52_03_01_引言

在本节课中,我们将学习如何将函数与外部API结合使用,构建一个能够处理输入参数并与外部服务交互的“粘合”函数。我们将探讨这种微服务的可能形态。

🚀 课程概述

上一节我们介绍了大型语言模型的基础概念。本节中,我们将进一步探索如何扩展其能力。

我们将从简单的方法开始,逐步过渡到稍复杂的实现。我们会看到这些部分如何组合在一起,形成一个虽然更复杂但功能强大的整体。这是一个非常注重实践和动手操作的课程,包含一个实际可运行的示例。

🔗 核心内容:结合外部API的函数

我们将创建一个函数,它能够处理输入参数,并与外部服务进行交互。以下是实现这一目标的关键步骤:

  1. 定义函数接口:首先,我们需要定义一个函数,它接收特定的参数。例如,一个查询天气的函数可能接收 locationdate 作为参数。

    def get_weather(location: str, date: str):
        # 函数逻辑
    
  2. 调用外部API:在函数内部,我们将构造请求并调用一个外部服务(如天气API)。

    import requests
    def get_weather(location: str, date: str):
        api_url = f"https://api.weather.com/v1/forecast?location={location}&date={date}"
        response = requests.get(api_url)
        return response.json()
    
  3. 处理与整合:函数将处理API的返回结果,并将其格式化为大型语言模型能够理解或使用的形式。

🧩 从简单到复杂的构建过程

我们将遵循从简单到复杂的路径,确保每个部分都能协同工作。当所有部分组合在一起时,我们将得到一个功能显著增强的系统。

💡 实践意义与应用前景

这个实际的工作示例非常实用。希望通过它,你能看到这些技术的部分优势与可能性,并思考其潜在的应用场景。

📚 本节总结

本节课中,我们一起学习了如何创建与外部API交互的函数,并了解了如何将其集成为更复杂系统的一部分。我们从概念到实践,逐步构建了一个微服务的雏形,为后续更深入的应用开发奠定了基础。

大型语言模型实践:03:创建胶合函数

概述

在本节课中,我们将学习如何在不依赖复杂配置的情况下,使用Python和Semantic Kernel框架创建一个原生的胶合函数(或插件)。我们将构建一个名为TravelWeather的类,它能根据给定的城市和月份返回该月的平均气温。通过这个过程,你将理解如何定义函数、设置参数,并让大型语言模型(LLM)自动调用这个功能。


构建原生函数类

上一节我们介绍了Semantic Kernel的基本概念,本节中我们来看看如何从零开始构建一个功能类。

我们将创建一个名为TravelWeather的类。这个类将使用Semantic Kernel提供的装饰器来定义其功能。以下是构建此类所需的关键导入和结构:

from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
from semantic_kernel.orchestration.sk_context import SKContext

类定义与装饰器

我们首先定义一个类,并使用@sk_function装饰器来标记核心功能方法。这个装饰器会告诉Semantic Kernel这是一个可供LLM调用的函数。

class TravelWeather:
    @sk_function(
        description="获取指定城市在指定月份的平均气温。",
        name="travel_weather"
    )
    async def get_weather(self, context: SKContext) -> str:
        # 函数逻辑将在这里实现
        pass
  • description: 为LLM提供函数功能的描述。
  • name: 指定函数的调用名称,最好与类名相关联以便识别。

添加上下文参数

为了让LLM知道需要向函数传递哪些信息,我们使用@sk_function_context_parameter装饰器来定义参数。

以下是定义“城市”和“月份”两个必需参数的代码:

    @sk_function_context_parameter(
        name="city",
        description="需要获取平均气温的城市。",
        default_value=""
    )
    @sk_function_context_parameter(
        name="month",
        description="需要获取平均气温的月份。",
        default_value=""
    )
    async def get_weather(self, context: SKContext) -> str:
        # 现在可以从context中获取city和month参数
        city = context["city"]
        month = context["month"]
        return f"The average temperature in {city} in {month} is 75 degrees."
  • 每个装饰器定义一个参数,包括其namedescriptiondefault_value
  • 在函数内部,可以通过context字典访问这些参数的值。

配置与调用函数

定义好函数类之后,我们需要在Semantic Kernel中注册并配置它,以便LLM能够发现和调用。

导入与技能注册

首先,我们导入必要的模块并创建Semantic Kernel实例。

import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion

kernel = sk.Kernel()
# 配置Azure OpenAI服务
kernel.add_chat_service(
    "chat_completion",
    AzureChatCompletion(
        deployment_name="your_deployment_name",
        endpoint="your_endpoint",
        api_key="your_api_key",
        api_version="2023-07-01-preview"  # 此示例需要此特定版本
    )
)

接下来,我们导入之前定义的TravelWeather类,并将其作为一个“技能”注册到内核中。

from your_module import TravelWeather

travel_weather_skill = kernel.import_skill(
    TravelWeather(),
    skill_name="TravelWeather"  # 技能名称
)

配置聊天提示模板

为了让LLM知道在对话中如何使用这个技能,我们需要设置一个系统提示词。

prompt_template_config = sk.PromptTemplateConfig(
    description="一个旅行天气查询助手。",
    default_services=["chat_completion"],
    schema=1,
    type="completion",
    completion=sk.PromptTemplateConfig.CompletionConfig(
        temperature=0.7,
        top_p=0.8,
        max_tokens=2000
    )
)

# 创建包含系统指令的提示模板
system_message = """
你是一个旅行天气聊天机器人,名字叫Frederick。
你的目标是帮助人们查询某个城市在某个月份的平均气温。
"""
prompt_template = sk.PromptTemplate(
    template=system_message + "{{$user_input}}",
    prompt_template_config=prompt_template_config,
    kernel=kernel
)

调用与执行

以下是调用流程的步骤:

  1. 我们创建一个包含用户问题的上下文。
  2. 让Semantic Kernel处理这个上下文,决定是否需要调用我们注册的函数。
  3. 检查结果,查看是否有函数被调用及其参数。
# 定义用户输入
user_input = "西雅图六月的平均气温是多少?"

# 创建上下文
context = kernel.create_new_context()
context["user_input"] = user_input

# 调用语义函数(这里指我们的提示模板流程)
result = await kernel.run_async(prompt_template, input_vars=context)

# 检查结果中是否包含函数调用
if hasattr(result, 'function_call') and result.function_call:
    print(f"将要调用的函数: {result.function_call.name}")
    print(f"函数参数: {result.function_call.arguments}")
else:
    # 如果没有函数调用,直接输出LLM的回复
    print(result.result)

在这个示例中,LLM会分析用户输入“西雅图六月的平均气温是多少?”,识别出意图,并决定调用travel_weather函数,同时自动提取出city="Seattle"month="June"作为参数。


调试与注意事项

创建胶合函数涉及多个组件协同工作,调试可能具有挑战性。在开发过程中,你可以使用Python的调试工具(如pdb.set_trace())来深入检查context对象的内容、函数调用流程以及参数传递是否正确。

核心在于确保:

  1. 函数装饰器的namedescription清晰准确。
  2. 上下文参数的定义与函数内部获取参数的键名一致。
  3. 技能被正确导入到Semantic Kernel中。

总结

本节课中我们一起学习了如何使用Python和Semantic Kernel创建原生的胶合函数。我们完成了一个TravelWeather类的构建,它能够接收城市和月份参数并返回模拟的平均气温。关键步骤包括:

  1. 使用@sk_function@sk_function_context_parameter装饰器定义函数及其参数。
  2. 配置Semantic Kernel并导入自定义技能。
  3. 设置系统提示模板来引导LLM的行为。
  4. 编写调用逻辑,处理可能发生的函数调用。

通过这种方式,我们可以将自定义的、确定性的代码逻辑(如查询数据库、调用API)无缝地集成到LLM的推理流程中,极大地扩展了AI应用的能力。虽然初始设置涉及多个环节,但一旦理解其模式,就能高效地构建出强大的AI辅助功能。

大型语言模型实践:P131:使用函数参数

概述

在本节课中,我们将学习如何在大型语言模型(LLM)的上下文中使用函数参数。我们将看到LLM如何自动解析用户输入,提取关键信息(如城市和月份),并将其作为参数传递给我们的函数,从而省去了手动解析文本的复杂工作。

函数参数的作用

上一节我们介绍了函数调用的基本概念。本节中,我们来看看函数参数如何成为整个流程的“魔法”所在。为了构建一个可工作的函数,我们需要明确它需要哪些信息。

让我们回顾一下顶部的实际类方法,它本身也是一个函数。这个方法需要一个上下文,并且在该上下文中,我们必须提供city(城市)和month(月份)信息。

考虑一段需要特定信息才能运行的代码。大型语言模型的强大之处在于,它允许我们无需手动解析句子就能获取这些信息。例如,在一句“我想知道西雅图六月的天气”中,我们需要精确地知道城市和月份才能提供有用的回答。手动解析句子来识别这些实体是复杂的,而大型语言模型借助我们提供的描述和配置,可以自动完成这项工作。

因此,当流程进行到这一步时,上下文将包含我们精确理解所需的信息,使我们能够以有意义的方式使用这些参数。

探索函数调用

现在,让我们滚动到底部,开始实际操作。我们将重点关注函数调用本身,即函数名和其参数。因为我们设置了自动解析,这些信息已经为我们整理好了。

以下是探索步骤:

  1. 打开终端,进入Python环境并导入我们的聊天模块。
  2. 调用相关函数,观察返回结果。

运行后,我们可以看到返回的信息:被调用的函数名是travel_weather,函数参数是city: Seattlemonth: June。这非常有趣,因为现在我们可以在函数内部使用这些参数了。

我们可以尝试改变输入来验证其鲁棒性。例如,输入“我要去西雅图旅行,平均气温会是多少?”。清除之前的输出并再次运行。

你会发现,即使输入句式改变,我们仍然能精确地获取到城市(Seattle)和月份(June)。这就是解析的“魔法”——它使我们能够稳定地提取关键参数。

参数传递与使用

通过这种方式获取到函数参数后,我就能将它们传递给我的函数(实际上是一个类中的方法)。在函数内部,我们将能够访问这些参数,因为它们将成为执行上下文的一部分。

总结

本节课中,我们一起学习了大型语言模型如何自动解析用户输入并提取函数参数。我们看到,通过合理的配置,模型可以将自然语言中的关键信息(如城市和月份)准确映射到我们定义的函数参数上。这省去了复杂的手动文本解析工作,使得我们的函数能够稳定、精确地接收所需数据,从而提供有用的响应。

大型语言模型实践:P132:使用原生函数 🛠️

在本节课中,我们将学习如何通过定义和使用原生Python函数,来更灵活、更可控地与语言模型内核进行交互。我们将看到如何将模型生成的参数传递给这些函数,并执行自定义逻辑。


概述

之前我们已经接触过一些控制模型输出的方法。接下来要展示的,是我个人认为能提供更强控制力的最佳方式。如果你希望获得更多控制权,本节内容将非常关键。我们将定义一个原生的Python函数,并通过内核来调用它。

定义原生函数

首先,我们定义一个名为 travel_weather 的函数。这个函数接收两个参数:city(城市)和 month(月份)。我们将这两个参数设置为关键字参数,并默认值为 None

以下是函数的定义:

def travel_weather(city=None, month=None):
    # 目前,我们简单地返回一个固定的平均温度
    return "The average temperature is 75 degrees."

这个函数目前只是返回一个固定的温度信息。我们还会创建一个辅助字典 native_functions,用于将函数名称(字符串)映射到实际的函数对象上。

native_functions = {
    "travel_weather": travel_weather
}

我们将不再使用之前演示的其他方法,而是专注于这种原生函数的方式。

调用原生函数

现在,我们来看看如何调用这个函数。假设我们从语言模型那里收到了一个JSON格式的字符串,其中包含了要调用的函数名和参数。

例如,我们可能收到这样的数据:

{
  "function": "travel_weather",
  "arguments": "{\"city\": \"Seattle\", \"month\": \"August\"}"
}

我们的处理步骤如下:

  1. 解析参数:首先,我们需要加载这个JSON字符串来获取参数。我们使用 json.loads() 方法将字符串解析为Python字典。

    import json
    arguments_dict = json.loads(arguments_string)
    
  2. 查找并调用函数:接着,我们从 native_functions 字典中根据函数名找到对应的函数对象。然后,使用 ** 操作符将参数字典作为关键字参数传递给该函数。

    function_to_call = native_functions[function_name]
    result = function_to_call(**arguments_dict)
    
  3. 执行与输出:运行上述代码后,函数会被调用。对于输入“Seattle”和“August”,函数将返回“The average temperature is 75 degrees.”。

测试与灵活性

我们可以轻松地修改提示词来测试不同的输入。例如,将提示词改为询问秘鲁利马(Lima)八月的天气。

运行后,我们可能得到相同或不同的结果,这完全取决于 travel_weather 函数内部的逻辑。目前我们的函数逻辑很简单,总是返回75度。但关键在于,我们现在拥有了完整的控制权。

为了展示这种控制力,我们可以修改函数,使其对特定城市返回定制化的信息:

def travel_weather(city=None, month=None):
    if city == "Lima":
        return "Lima in August is an amazing choice!"
    else:
        return f"The average temperature in {city} during {month} is 75 degrees."

保存并再次运行脚本,当查询利马时,我们就会得到“Lima in August is an amazing choice!”这个更具针对性的回复。

为何这是更好的选择

我认为这种方法是一个更好的替代方案,原因如下:

  • 完全控制:它为你提供了对参数处理的完全控制权。
  • 高度灵活:你可以用更简单、更符合Python风格的方式定义函数,并在其中实现任何你想要的逻辑。
  • 易于扩展:这种方法为后续集成更复杂的业务逻辑或外部API调用奠定了基础。

在接下来的课程中,我们将探索利用这种方法还能实现哪些更强大的功能。


总结

本节课中,我们一起学习了如何通过定义和注册原生Python函数来与语言模型内核交互。我们掌握了将模型输出的JSON参数解析并传递给函数的方法,并理解了这种模式在提供控制力和灵活性方面的优势。这为我们构建更复杂、更可靠的AI应用打下了坚实的基础。

大型语言模型实践:P133:函数微服务概述 🧩

在本节课中,我们将学习如何将一个外部微服务集成到大型语言模型(LLM)的整体架构中。我们将通过一个提供历史温度数据的API示例,来理解如何通过连接外部服务来增强LLM的响应能力。

微服务架构概述

上一节我们讨论了LLM应用的基本结构,本节中我们来看看如何将外部功能以微服务的形式接入。我们将使用一个具体的API示例,该API旨在提供历史温度数据。在此之前,我们的应用可能只返回简单的字符串,而现在我们将尝试连接一个外部微服务。

这个微服务使用Python编写,但理论上可以使用任何语言,因为其核心是通过HTTP协议进行通信。这意味着它将作为一个HTTP API运行。

运行与演示

以下是该微服务的运行方式。具体启动细节并非重点,重要的是它将在本地主机的端口8000上运行。

我已经提前启动了该服务,现在向大家展示它的运行情况。这个API支持一些端点,并且目前仅支持GET请求。

我们可以通过Swagger界面来与这个正在运行的API进行交互。Swagger是一种用于测试和可视化API的工具。

现在,让我们尝试执行一个请求,看看能得到什么结果。

可以看到请求的URL,并且目前它只返回葡萄牙的数据。这很有趣。

让我们取消当前操作,尝试获取某个城市的月平均温度。我们将输入国家“Portugal”和城市“Porto”,然后执行请求。

我们得到了一个成功的200响应,返回的数据包含了高温和低温信息,这非常有用。

回顾这个微服务的代码库和Web应用,我们会发现它结构相当简单,只包含少数几个路由,并不复杂。目前它仅返回葡萄牙的数据。

微服务与LLM的关联

这个设计理念的核心在于,通过引入外部API,我们可以增强LLM提示词(prompt)的响应能力,并提供LLM本身可能不具备的数据。在本例中,我们提供的就是仅限于葡萄牙的历史温度数据。

虽然目前这个服务运行在本地主机上,但你完全可以将其部署到生产环境中,以这种方式来增强你的应用程序。

在接下来的课程中,我们将看到如何将这个微服务实际“插入”到我们的大型语言模型应用中,并开始向其发送请求,从而真正实现功能的增强。

总结

本节课中,我们一起学习了外部微服务在LLM架构中的角色。我们通过一个历史温度API的实例,了解了如何构建、运行一个简单的HTTP微服务,并探讨了将其集成到LLM应用中以提供额外数据和增强响应能力的可能性。这为扩展LLM的功能边界提供了一种实用方法。

大型语言模型实践:第57课:使用外部微服务API 🚀

在本节课中,我们将学习如何通过调用外部微服务API来增强大型语言模型的功能。我们将构建一个旅行天气查询应用,演示如何让LLM与一个独立的天气服务进行交互,以获取动态数据。


概述

我们将创建一个简单的聊天应用,当用户询问特定城市和月份的天气时,应用会调用一个我们预先搭建好的外部微服务API来获取真实的平均高温数据,而不是返回硬编码的答案。这展示了如何扩展LLM的能力,使其能够处理实时或动态信息。

上一节我们介绍了函数调用的基本概念,本节中我们来看看如何将函数调用与一个真实运行的外部服务结合起来。

启动应用与微服务

首先,我回到了我的文本数据环境,并决定启动应用程序。

该应用正在VSCode的终端中本地运行,端口为8000。我这样做是为了让你能直观地看到交互过程。现在,我将向上滚动代码,以便你能看到我是如何增强 travel_weather 函数的,使其能够发起微服务请求。

我定义了微服务的URL。在本例中,地址是 localhost。如果在生产环境中,你可能不会使用这样的地址,而会采用更健壮的方案,但出于演示目的,这已经足够好。

以下是增强后的函数核心代码:

import requests

def travel_weather(city, month):
    microservice_url = "http://localhost:8000/weather"
    params = {'city': city, 'month': month, 'country': 'Portugal'}
    response = requests.get(microservice_url, params=params)
    result = response.json()
    return f"The average high temperature in {city} in {month} is {result['high']} degrees."

理解请求过程

现在,我们来剖析一下结果。requests 库将执行一个GET请求。请记住,我们的微服务目前只接受GET请求,并且仅支持查询葡萄牙的城市。

我们将传入 city(城市)和 month(月份)参数。发送请求后,我们将响应加载为JSON格式。最后,我们使用响应中的数据来组织回复语句:“[城市] 在 [月份] 的平均高温是 [结果] 度”。这里的 result[‘high’] 是JSON响应的一部分。当我们发起请求时,终端中也会显示这些变量。

这就是整个应用程序和外部微服务的架构。接下来,我们将回到之前的终端进行测试。

在测试之前,我想最后展示一下即将发生的实际请求内容。假设我计划去葡萄牙的波尔图旅行,时间在八月。我想知道那里的平均温度。

进行测试查询

我将运行 python chat.py。我们将看到 travel_weather 函数被调用,并获取到函数参数“Porto”和“August”。

我们得到的回复是:“波尔图在八月的平均高温是77度”。请注意,这个数据不再是硬编码的了。如果我快速向上滚动查看代码,你会发现这个数据来自于微服务的返回结果。

为了确认我的外部微服务确实被调用了,我可以切换到运行微服务的终端标签页,看到那里记录了一次状态码为200的OK请求,查询参数是葡萄牙、波尔图和八月,这证明调用是正确的。

尝试更多查询

我可以将其更改为另一个城市,比如里斯本,并尝试不同的月份。

将查询改为:“Lisbon in January”。再次保存并运行提示:python chat.py

查询结果是:“里斯本在一月的平均高温是57度”。如果我切换终端标签页,会看到来自里斯本查询的另一个200状态码响应。

错误处理与注意事项

目前这个实现还达不到生产级别,它只是一个示例。在实际应用中,你需要防范各种异常情况。

例如,如果我查询“Madrid”(马德里),程序就会崩溃。因为外部API只接受葡萄牙的城市,而马德里在西班牙。你会在这里看到JSON解码错误。如果查看运行微服务的终端,会发现到处都是错误提示。

这是运行微服务时需要注意的一个问题。但本质上,这个示例很好地展示了如何通过使用微服务来增强和构建大型语言模型应用。


总结

本节课中我们一起学习了如何为大型语言模型集成外部微服务API。我们构建了一个天气查询功能,演示了如何从硬编码响应过渡到动态数据获取。关键步骤包括定义API端点、使用 requests 库发送HTTP GET请求、解析JSON响应以及处理潜在的异常。虽然示例简单,但它清晰地揭示了扩展LLM能力、使其与外部世界连接的核心模式。记住,在生产环境中,需要增加更完善的错误处理、身份验证和日志记录。

大型语言模型实践:3.7:总结

在本节课中,我们将总结如何创建和使用语义内核中的原生函数,并探讨其与外部微服务集成的模式。


我们成功创建了函数,并在语义内核中创建了所谓的“原生函数”。我们了解了它的具体形态,并看到了其中一些关键机制。这些机制使我们能够接收参数,并在后台利用大语言模型来帮助我们识别这些参数,以便将它们传递给函数。

上一节我们介绍了函数的创建,本节中我们来看看如何利用这些参数与外部服务进行通信。

拥有一个微服务,即一个外部的微服务API或HTTP API,是一种非常普遍的做法和模式。这使我们能够将信息处理的责任委托给一个独立的服务。

我决定将这部分内容纳入课程的主要原因之一,就是希望你能看到,在尝试将这些服务组合在一起时,还存在哪些其他可能性和扩展服务的方式。

以下是使用原生函数与外部API通信的核心优势:

  • 它允许你将特定任务(如数据检索)委托给专门构建的服务。
  • 通过大语言模型解析用户输入,可以动态地确定需要传递给外部API的参数。
  • 这种模式为扩展应用功能提供了清晰、模块化的途径。

具体到本例中,这些能够从用户处接收参数的原生函数(或Python函数),用于检索信息,是一个非常稳固且可以实际实施的模式。


本节课中,我们一起学习了在语义内核中创建原生函数的方法,理解了其利用大语言模型解析参数并与外部微服务API集成的机制。这种委托职责给独立服务的模式,是构建可扩展、模块化AI应用的重要基础。

大型语言模型实践:P136:引言

在本节课中,我们将学习如何使用微软云服务构建一个端到端的大型语言模型应用。我们将从应用的整体架构入手,了解其核心组件,并介绍检索增强生成的基本概念与模式。最后,我们会简要探讨如何利用GitHub实现自动化部署。

应用架构概览 🏗️

上一节我们介绍了课程的整体目标,本节中我们来看看大型语言模型应用的具体架构。

整个课程中,我们一直倾向于使用微软的Azure云平台。在本部分,我们将审视大型语言模型应用的架构,了解其具体形态。

我们将查看该应用的架构概览,包括其中的所有组件。

检索增强生成基础 🔍

了解了整体架构后,接下来我们需要掌握一个核心概念:检索增强生成。

我们还将介绍RAG(检索增强生成)的初步概念和基本原理。

RAG模式是什么样子的?我们又将如何开始实施它?

Azure AI 搜索服务 ⚙️

当然,实施RAG模式需要用到Azure的另一项不同组件。

这要求我们了解Azure的另一个不同组件——Azure AI搜索。该服务最近从Azure认知搜索更名而来。

自动化与部署 🤖

最后,我们将快速浏览一下使用GitHub进行的自动化与部署。

我们将简要了解如何利用GitHub和GitHub Actions实现自动化部署,以及其中存在的一些可能性。


本节课中,我们一起学习了构建端到端LLM应用的Azure云架构、检索增强生成的基础概念、Azure AI搜索服务的作用,以及利用GitHub进行自动化部署的初步思路。这些构成了在微软云平台上开发大型语言模型应用的核心知识框架。

大型语言模型实践:04:检索增强生成(RAG)架构概述 🧠

在本节课中,我们将学习检索增强生成(Retrieval-Augmented Generation, RAG)的基本工作原理和架构流程。这是一种让大型语言模型能够访问并利用外部知识库来生成更准确、更相关回答的技术。


架构流程概述

上一节我们介绍了RAG的基本概念,本节中我们来看看它的具体工作流程是如何进行的。

整个流程始于用户的查询。通常,查询会直接发送给应用框架,然后由框架调用机器学习模型(如大型语言模型)来生成回答。但在RAG架构中,流程有所不同。

第一步:接收查询

用户提出一个问题,例如:“昨天的天气怎么样?” 这个问题首先被发送到应用框架。

第二步:查询转向向量数据库

应用框架接收到查询后,并不会直接将其发送给大型语言模型。相反,它会先将查询发送给向量数据库进行搜索。

以下是这个过程的伪代码表示:

# 用户查询
user_query = "昨天的天气怎么样?"
# 框架将查询发送至向量数据库进行搜索
search_results = vector_database.search(user_query)

第三步:数据库检索与返回上下文

向量数据库执行相似性搜索,从存储的文档或数据中找出与查询最相关的信息。例如,它可能检索到“昨天本地气温为25度,晴朗”这条记录。

检索到的信息(我们称之为“上下文”)会返回给应用框架,而不是直接给用户。

第四步:构建增强提示

应用框架现在同时拥有了原始的用户查询和从数据库检索到的相关上下文。它会将这两者组合起来,构建成一个增强的提示,准备发送给大型语言模型。

这个过程可以概括为:
最终提示 = 用户查询 + 检索到的上下文

第五步:模型生成最终回答

这个包含了“答案线索”的增强提示被发送给大型语言模型。此时,模型的任务不再是凭空生成答案,而是像一个“开卷考试”的学生——它已经拿到了“参考答案”(即检索到的上下文),只需要将这些信息组织成流畅、自然的语言。

模型生成回答后,将其返回给应用框架,框架最终将回答呈现给用户。


流程优势与特点

以下是RAG架构的几个关键优势:

  1. 成本效益:为大型语言模型重新训练以纳入新知识的成本非常高。而RAG通过向向量数据库添加文档来更新知识,成本低廉且操作简单。
  2. 知识实时性:模型可以访问训练数据截止日期之后的信息,解决了模型知识陈旧的问题。
  3. 答案准确性:通过提供确切的参考依据,减少了模型“幻觉”(即编造信息)的可能性。
  4. 可追溯性:回答基于具体的检索文档,使得答案的来源可追溯,增强了可信度。

总结

本节课中我们一起学习了检索增强生成(RAG)的核心架构。我们了解到,RAG通过在用户查询和大型语言模型之间引入一个向量数据库检索的步骤,将外部知识动态地注入生成过程。其核心路径是:用户查询 → 应用框架 → 向量数据库检索 → 构建增强提示 → 大型语言模型生成 → 返回用户。这种架构以较低的成本显著提升了模型回答的准确性和相关性,是构建高效AI应用的关键模式之一。在后续课程中,我们将深入探讨如何具体实现和部署这一架构。

大型语言模型实践:04:什么是RAG 🧠

在本节课中,我们将学习检索增强生成(RAG)技术。这是一种通过整合外部知识源来增强、优化大型语言模型输出的方法。我们将了解其核心概念、工作原理以及它在实际应用中的架构。

概述

检索增强生成是一种通过使用搜索数据库或搜索引擎(有时也称为向量数据库)来扩展、锚定和改进结果的技术。它旨在弥补大型语言模型在特定、最新或专有知识上的不足。

RAG的基本概念

上一节我们概述了RAG,本节中我们来看看它的基本工作原理。其核心思想是,在用户提问和模型生成答案之间,引入一个检索步骤。

RAG的核心流程可以概括为以下步骤:

  1. 用户提出问题。
  2. 系统从外部文档库中检索相关信息。
  3. 将问题和检索到的信息一同提交给大型语言模型。
  4. 模型基于所有输入生成更准确、更可靠的回答。

例如,当询问“美国当前的政治事件”时,语言模型自身可能因训练数据时效性限制而无法准确回答。此时,数据库、搜索引擎或向量数据库就发挥了作用。它们可以提供最新的信息,使回答变得超级准确。在处理用户请求时,系统可以先从文档中获取相关信息,然后将这些信息连同问题一起发送给大型语言模型。

因此,大型语言模型实际接收到的是问题本身以及从文档中检索到的任何相关搜索结果

RAG在Azure AI中的架构

理解了基本概念后,我们进一步看看RAG在云平台(如Azure)中是如何具体实现的。下图来自Microsoft Learn,展示了Azure AI搜索中的检索增强生成架构。

请注意,Azure AI搜索最近已从“Azure认知服务搜索”更名。如果您熟悉旧名称,现在它叫Azure AI搜索。

以下是该架构中各组件的简要说明,我们将在后续课程中详细覆盖:

  1. 应用程序/协调器:接收用户请求的入口点,通常由API、Python代码或容器实现。
  2. Azure AI搜索:请求首先被提交到这里。它利用预先加载的大量信息进行检索,生成用于增强提示的必要响应。
  3. Azure OpenAI:接收增强后的请求(即原始问题+检索结果),调用大型语言模型生成最终答案。
  4. 响应流程:答案经由协调器返回给用户。

本质上,这就是RAG的运作方式。当人们谈论搜索、向量数据库或检索增强生成时,他们指的是类似的实现方案:通过预先加载的、能提供模型当前所不具备的额外信息的文档,来增强模型的行为。

总结

本节课中,我们一起学习了检索增强生成(RAG)。我们了解到,RAG是一种通过整合外部知识源(如搜索数据库或向量数据库)来提升大型语言模型回答准确性、时效性和可靠性的关键技术。其核心流程是在模型推理前加入检索步骤,用相关信息“增强”用户的问题。我们还初步了解了RAG在Azure AI平台上的典型应用架构。

大型语言模型实践:P139:Azure AI搜索概述 🧠

在本节课中,我们将学习Azure AI搜索服务。该服务是Azure平台上的核心组件,能帮助我们在应用程序中嵌入文档时增强其能力。我们将快速浏览其界面,并演示如何创建一个新的搜索资源。

概述

Azure AI搜索,之前被称为Azure认知搜索,是Azure平台提供的一项强大服务。它主要用于增强应用程序处理文档的能力,特别是在我们尝试将文档嵌入应用时。接下来,我们将快速概览其功能,并演示创建新资源的步骤。

创建Azure AI搜索资源

上一节我们介绍了Azure AI搜索的基本概念,本节中我们来看看如何创建一个新的搜索服务实例。

首先,我们需要创建一个新的资源。我将使用一个演示资源组,并遵循“demo”前缀的命名惯例,以便于后续管理和清理资源。

以下是创建步骤:

  1. 服务名称需要全局唯一,例如可以命名为 demoFredoSearch
  2. 选择区域,例如 US2
  3. 选择定价层。这里有一个非常有用的选项:免费层。它提供50MB的存储空间,支持基本操作,且无需任何费用。对于我们的学习目的,选择免费层非常合适。
  4. 配置副本和分区数量。在免费层中,最大副本数为1,分区数也为1,只有一个搜索单元,这完全满足我们当前的需求。
  5. 最后,点击“审阅并创建”。系统会进行验证,然后开始创建资源。

创建成功后,我们可以点击“转到资源”来进入新创建的服务。

探索服务功能

现在我们已经创建了资源,让我们进入服务界面,看看有哪些核心功能。

在服务主界面,你会看到“导入数据”的选项,这非常实用。更具体地说,是“导入和矢量化数据”。当我们计划结合大型语言模型处理数据时,矢量化是一个关键步骤。

你可以通过用户界面(UI)完成此操作。点击后,系统会提示你创建Blob存储账户(如果你还没有的话),然后选择存放数据的容器和文件夹。由于我们目前没有现成的数据存储,这里暂不深入演示此流程,但后续会介绍其他实现方式。

索引与搜索示例

为了更全面地了解,我想展示一个我之前创建的其他搜索服务实例。在这个实例中,我已经上传了数据并完成了索引构建,数据也进行了矢量化处理。

在这个实例中,你可以执行搜索表达式,可以按字段筛选,也可以浏览结果。例如,我之前处理了一些关于葡萄酒的数据,执行搜索后可以看到返回了许多结果。虽然这些结果目前看来不相关,但这没关系,我们将在后续课程中学习如何具体实现和应用。

本质上,这就是快速开始使用Azure AI服务,特别是AI搜索的方法。你可以创建自己的实例和资源,以便在准备好与大型语言模型及RAG模式(检索增强生成)交互时,将你的应用程序连接起来。

总结

本节课中,我们一起学习了Azure AI搜索服务。我们从概述开始,了解了其核心价值。接着,我们逐步演示了如何创建一个免费的搜索服务资源。然后,我们探索了服务界面,重点介绍了数据导入和矢量化功能。最后,通过一个已有索引的实例,我们预览了搜索的基本操作。掌握这些步骤,你就能为自己的应用程序创建AI搜索能力,为后续集成大型语言模型和实现RAG模式打下基础。

大型语言模型实践:P140:使用GitHub实现自动化与部署 🚀

在本节课中,我们将学习如何利用GitHub Actions实现端到端应用的自动化部署。这是一种强大且直接的方法,能够简化从代码到云服务的发布流程。

概述

GitHub Actions提供了一种自动化工作流的方式,通过定义YAML配置文件,可以实现代码构建、容器镜像推送以及云服务部署等一系列操作。本节将快速概览其核心概念与基本结构。

GitHub Actions工作流基础

上一节我们介绍了自动化部署的概念,本节中我们来看看如何具体配置一个GitHub Actions工作流。

其核心在于在代码仓库中创建一个特定目录和配置文件。你需要创建一个名为 .github 的目录,并在其下创建 workflows 子目录。在此子目录中,你可以放置YAML格式的工作流定义文件。

工作流文件结构解析

以下是工作流YAML文件的一个通用结构示例。GitHub提供了模板帮助你快速上手。

name: Deploy to Azure Container App

on:
  workflow_dispatch: # 允许手动触发

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Build Docker image
        run: docker build -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/myapp:${{ github.sha }} .

      - name: Log in to Azure Container Registry
        uses: azure/docker-login@v1
        with:
          login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Push Docker image
        run: docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/myapp:${{ github.sha }}

      - name: Deploy to Azure Container Apps
        uses: azure/container-apps-deploy-action@v1
        with:
          appSourcePath: ${{ github.workspace }}
          acrName: ${{ secrets.REGISTRY_NAME }}
          containerAppName: my-huggingface-app
          resourceGroup: my-resource-group

在这个示例中,name字段定义了工作流的名称。on字段定义了触发条件,例如示例中的workflow_dispatch表示允许手动触发工作流。被注释掉的环境变量会显示为灰色。

核心步骤详解

工作流由一系列步骤组成,以下是其主要步骤的分解:

  1. 检出代码:第一步是使用actions/checkout操作将仓库代码拉取到运行环境中。
  2. 构建Docker镜像:此步骤根据项目中的Dockerfile文件构建容器镜像。
  3. 登录容器注册表:此步骤对之前创建的Azure容器注册表进行身份验证。如何创建注册表不是当前重点,重点是获得构建和推送镜像到实际注册表的能力。
  4. 推送镜像:将构建好的Docker镜像推送到指定的容器注册表中。

使用GitHub Actions的一个重要优势在于它能安全地管理密钥。所有以${{ secrets.XXX }}格式引用的都是存储在GitHub仓库设置中的加密密钥,这保证了敏感信息的安全性。

部署到Azure容器应用

构建并推送镜像后,下一步是将其部署到云平台。以下是部署阶段的关键操作:

  1. 身份验证:首先需要向Azure进行身份验证,以获得部署权限。
  2. 执行部署:最后,我们将应用部署到Azure容器应用服务。Azure容器应用是一个托管服务,专门用于运行容器化应用。

在部署配置中,我们通过一系列选项指定:从哪个注册表获取容器镜像、需要为容器分配多少内存和CPU资源,以及要拉取的具体镜像标签(例如huggingface-azure)。

关于GitHub Secrets

最后需要提及的是GitHub Secrets。Secrets是GitHub Actions的一个特定功能,它允许你将敏感信息(如密码、API密钥)安全地存储在GitHub仓库设置中。你可以在工作流文件中安全地引用它们,从而实现配置的复用。设置过程非常直接,添加后即可实现高复用性。

总结

本节课中我们一起学习了使用GitHub Actions进行自动化部署的快速概览。我们了解了工作流的基本结构、核心构建与部署步骤,以及如何利用Secrets安全地管理凭证。这是一种直接且不复杂的方式,能够高效地将应用(例如连接Azure OpenAI服务的应用)从代码部署到云环境。我们将在后续课程中看到其更详细的工作过程。

大型语言模型实践:P141:总结与部署

在本节课中,我们将对构建大型语言模型应用的基础知识进行总结,并了解如何将其部署到云端。我们将回顾检索增强生成(RAG)的可能性,以及如何利用Azure AI搜索资源。最后,我们将探讨使用Github Actions实现自动化部署的流程。

课程内容概述

上一节我们介绍了RAG与Azure AI搜索的集成。现在,我们对大型语言模型应用的整体架构、RAG的应用潜力,以及如何借助Azure AI搜索资源使其运行,已经有了一个坚实而全面的认识。

这一切都是基础性的,是将所有组件整合起来并最终部署到Azure云平台的第一步。

自动化部署:Github Actions

以下是实现自动化部署的一个核心组件与模式。

我认为其中一个特别值得展示的组件是使用Github Actions。这或许令人意外,但了解Github Actions如何帮助我们整合应用程序并随后将其部署到Azure云,是一个非常可靠的模式,也是当你尝试将代码部署、让应用与用户通过Azure云进行交互时,开始自动化部署能力的绝佳方式。

课程总结

本节课中,我们一起学习了构建大型语言模型应用的基础框架,探讨了检索增强生成(RAG)的应用场景及其与Azure AI搜索的协作方式。最后,我们介绍了使用Github Actions实现自动化部署到Azure云的有效模式,为将应用投入实际使用奠定了重要基础。

大型语言模型实践:P142:65_04_01_引言

概述

在本节课中,我们将学习如何使用检索增强生成技术。我们将重点介绍如何利用Azure AI搜索服务,结合Azure OpenAI,来实现让大型语言模型与我们自己的数据进行交互。

课程内容

上一节我们介绍了课程的整体目标,本节中我们来看看具体的实现路径。我们将通过Azure平台的不同服务来完成一个完整的检索增强生成流程。

以下是实现RAG模式需要完成的主要步骤:

  1. 了解并创建所需的Azure服务。
  2. 学习如何为文本数据创建嵌入向量。
  3. 掌握如何将数据索引上传至搜索服务。
  4. 验证生成的嵌入向量是否正确。
  5. 最终,集成所有组件,使用Azure OpenAI实现检索增强生成模式。

我理解这里提到了许多尚未讲解的新概念和不同组件。但我会使用非常简单明了的示例进行说明。最有趣的是,我们将充分利用Azure云平台为我们完成的大量基础工作。

这样,我们就能获取一段文本,并生成大型语言模型与我们的私有数据交互所需的一切。本质上,我们正是要通过使用自己的数据,来扩展大型语言模型的功能。

总结

本节课我们一起学习了检索增强生成的基本概念和实现蓝图。我们了解到,借助Azure AI搜索和Azure OpenAI等服务,可以构建一个系统,使大型语言模型能够安全、有效地访问和处理我们的私有数据,从而扩展其应用能力。

大型语言模型实践:04:创建Azure资源与准备开发环境

在本节课中,我们将学习如何为构建基于向量数据库的应用程序创建必要的Azure资源,并配置相应的Python开发环境。我们将创建Azure OpenAI服务,部署嵌入模型,并安装项目所需的Python库。


创建Azure OpenAI资源

上一节我们介绍了Azure AI Search服务。本节中,我们来看看如何创建Azure OpenAI资源。

首先,我们需要创建一个新的Azure OpenAI资源。我们将它命名为 demoredo,并确保它位于之前创建应用程序时使用的同一个资源组中。资源组位置选择 US2US。资源名称需要确保全局唯一。

创建过程中,在配置网络访问时,选择允许从所有网络访问。我们暂时不添加任何标签。确认所有信息无误后,点击“创建”按钮。资源部署需要一些时间来完成。

部署嵌入模型

资源创建完成后,我们需要部署一个用于生成嵌入向量的模型。

我们需要进入新创建的Azure OpenAI服务的“工作室”界面。在工作室中,导航到“模型”部分,然后查看可用的“嵌入”模型。我们将选择 text-embedding-ada 模型进行部署。

部署时,需要指定一个部署名称,例如 demo-search。这个名称非常重要,后续在代码中会用到它来调用嵌入服务,从而将我们的数据向量化。高级选项可以保持默认,无需修改。点击“创建”后,部署过程通常很快。部署成功后,可以在列表中看到名为 demo-search 的部署。

安装Python依赖库

现在,我们来看看编写代码需要安装哪些Python库。

以下是项目所需的依赖库及其特定版本,这是确保所有功能正常工作的关键。

  • azure-search-documents:用于与Azure AI Search服务进行交互。
  • langchain:这是一个类似于我们之前见过的Semantic Kernel的框架,专门用于简化与大语言模型的交互。
  • openai:这个库让我们能够无缝地与Azure OpenAI服务进行交互,尤其是在配合Langchain使用时。
  • fastapi:后续我们将构建应用程序,因此需要这个Web框架。
  • antitick-token:这是一个用于配合 azure-search-documents 进行嵌入操作的必要组件。

工具与库的作用

接下来,我们简要说明这些工具和库在项目中的角色。

在后续的Notebook中,我们将看到为什么需要同时使用 openailangchainlangchain 为我们提供了连接Azure Search的能力。同时,通过 langchain,我们也能方便地使用Azure OpenAI的嵌入服务。嵌入服务是帮助我们生成向量数据的关键,这些向量数据将用于填充我们之前提到的索引。


本节课中我们一起学习了创建Azure OpenAI资源、部署嵌入模型以及配置Python开发环境的完整流程。完成这些步骤后,你就为开始处理数据并构建应用程序做好了准备。

大型语言模型实践:4.4:创建嵌入向量 🧠

在本节课中,我们将学习如何为文本数据创建嵌入向量,并将其上传至 Azure AI 搜索服务。我们将使用一个葡萄酒评分数据集作为示例,演示从加载数据、分割文本到生成嵌入向量的完整流程。

上一节我们介绍了 Azure AI 搜索的基础设置,本节中我们来看看如何实际处理数据并创建嵌入向量。


现在,我们准备创建嵌入向量。我们已经准备好分割文本,并开始将数据上传到 Azure AI 搜索(之前称为 Azure 认知服务搜索)。

我们将使用 Jupyter Notebook 来完成这项工作。与其直接点击每个单元格的播放按钮来展示执行过程,不如先说明我们将要做什么。

我们将处理一些葡萄酒评分数据。这些评分数据来自我之前下载的一个资源库。我想展示一下它的样子。

这是一个名为 wine_ratings.csv 的 CSV 文件。它包含索引列、名称、国家/地区、产区、葡萄品种、评分和品酒笔记。

这是一种与我们想要扩展的服务进行交互的有趣方式。我们希望让服务更容易地为我们提供信息。

然而,检索增强生成的一个问题是,当我们将文档分割成小块时,对于像 CSV 这样的数据集(本质上是逗号分隔值数据),有时并不完全清楚该如何处理。

LangChain 框架将允许我们获取所有这些内容,将它们分割成块,并能够将它们嵌入到数据库中。

这是 wine_ratings.csv 文件。我将滚动到顶部,开始逐一讲解。

请注意,我有一个 .env 文件。你必须准备好你的 Azure 应用程序的密钥和机密信息。

如果我快速展示一下 README 文件,你会看到这里解释得非常清楚。这里以渲染良好的方式展示了密钥应该如何配置。

我正在使用搜索服务名称、搜索 API 密钥和搜索索引名称。我使用的是 Azure 认知搜索或 Azure AI 搜索。我这样称呼它们是因为稍后部署时,如果这些密钥长度超过 20 个字符,可能会出现问题。

因此,你必须确保所有数据都已准备好在你的 .env 文件中,否则数据将无法加载。

我将关闭 README,回到 Jupyter Notebook,并开始执行代码。

数据已加载,我的 Azure 密钥一切就绪。

我将使用 OpenAI 嵌入模型。这个类来自 LangChain,它将负责创建嵌入向量,并允许我分割文本。

然后,我将创建嵌入实例。这里需要指定块大小以及 OpenAI 的部署名称(例如 demo-embedding,无论你如何命名你的部署)。这一步至关重要。

现在,连接到 Azure 认知搜索。我们将在这里完成这一步。代码将使用端点、正确的端点、API 密钥以及我们在创建 Azure AI 搜索时指定的搜索索引名称。这个索引名称在那里至关重要。

嵌入函数将来自我们之前定义的 embed_query。所有这些都为我们处理好了。

我们如何处理、如何分割、如何获取那个 CSV 文件?我们将使用 LangChain 的另一个辅助工具——文档加载器。有一个非常方便的 CSV 加载器可供使用。

我们需要做的就是传入文件路径,然后执行加载器进行加载。我们将运行这段代码,这大约只花了半秒钟。

至此,我们已经能够使用 CSV 文件、收集信息并完成加载。接下来,我们将实际把这些数据块“塞”进去,稍后会看到结果。


本节课中我们一起学习了如何为结构化数据(CSV)创建嵌入向量的完整流程。我们了解了使用 LangChain 框架加载 CSV 文件、配置 OpenAI 嵌入模型以及连接到 Azure AI 搜索服务的关键步骤。核心在于将文本数据分割成块,并通过嵌入模型将其转换为向量,以便后续的语义搜索和检索增强生成任务。

大型语言模型实践:第4章:创建并上传索引 📚

在本节课中,我们将学习如何将数据文档分割成块,并将其上传到Azure认知搜索服务中,以构建可供大型语言模型查询的索引。

上一节我们介绍了如何连接到Azure认知搜索并加载数据文件。本节中我们来看看如何对数据进行分块处理并上传。

数据分块处理

首先,我们需要使用LangChain库中的文本分割器功能。这里我们将使用字符分割器,它能将文本分割成更小的块。这是必要的步骤,因为我们需要将大文档分解成适合处理的片段。

以下是使用字符分割器的代码示例:

from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)

上传文档至索引

完成分块后,下一步是将这些文档块添加到我们之前创建的Azure认知搜索索引中。我们通过变量ACS来引用该服务。

以下是上传文档的核心步骤:

  1. 使用分割器处理文档。
  2. 调用索引服务的添加文档方法。

关于服务层级的注意事项

需要牢记一点:我之前创建服务时使用的是免费层级。当前操作产生的数据量可能会远超免费层级的允许上限。如果执行上传,可能会在达到限制后无法继续运行。

因此,我不会再次运行此代码,因为它已经为我生成了一个良好的索引。如果你尝试重复添加文档,并且所在层级的配额已达上限,也可能会遇到限制。

处理时间说明

此外,这个过程可能需要相当长的时间。因为你需要将所有文本分块处理,并连接这些服务。文档越大,处理所需的时间就越长。


本节课中我们一起学习了如何使用文本分割器创建数据块,以及如何将它们上传到Azure认知搜索以构建索引。同时,我们也了解了服务层级限制和处理时间等实际注意事项。

大型语言模型实践:第4章:验证嵌入向量

在本节课中,我们将学习如何验证在Azure AI搜索服务中创建的索引和嵌入向量。我们将通过搜索示例数据来确认向量化数据已正确生成并可用于检索。


上一节我们介绍了如何创建索引和生成嵌入向量。本节中,我们来看看如何验证这些嵌入向量是否已成功集成到我们的搜索索引中。

现在我们已经生成了嵌入向量,并回到了Microsoft Azure门户。我已经导航到我之前创建的AI搜索服务。接下来,我将进入“搜索浏览器”来测试我拥有的索引。

我将点击这里进入搜索浏览器。请记住,我使用了一个关于葡萄酒的CSV文件。该文件包含产区、品名、评分和葡萄品种等列,虽然列数不多,但足以让我们开始探索。例如,我们可以搜索“Oregon”。我知道数据中有一些来自俄勒冈州的记录。

当我点击搜索后,搜索词“Oregon”立即被执行,我们在此处得到了返回的内容。你可以看到,内容被分割成了新的行。如果你还记得,我的索引中包含名称、葡萄品种、产区和种类。

这里的返回结果实际上是“sparkling”和“champagne”,这并不完全符合我的预期。因此,让我们尝试调整一下搜索词。

那么,试试搜索“Stags Leap red wine”。我们将搜索词改为“Stags Leap red wine”。完美,我们得到了来自纳帕谷的“Cabernet Sauvignon”。

这样我们就成功检索到了一些内容。让我们再确认一下,看看它是否真的来自“Stags Leap”这个纳帕谷内非常著名的子产区。由于界面限制,我无法逐字搜索,但让我看看能否在这里直接修改。

我滚动到这里,找到了。来源显示为“Rutherford and Stags Leap”。我在这里尝试并希望演示的是,Azure AI搜索的搜索能力允许你使用像这里这样的搜索词,它会处理我CSV文件中的所有文本块,并能够定位并返回我需要的信息。

现在,对于大型语言模型来说,有趣的部分来了。你看到这里所有绿色的部分了吗?那些绿色高亮就是我们之前创建的嵌入向量——我们创建的文本块。那些就是向量。这也正是为什么这类数据库有时被称为向量数据库,因为模型能够理解这些向量,它们是所生成文本对应的数值表示。

以上就是你如何验证索引是否已正确创建,并包含了大型语言模型所需的向量化数据。


本节课中,我们一起学习了如何在Azure AI搜索中验证嵌入向量索引。我们通过执行搜索查询,确认了文本数据已被成功转换为向量,并且搜索服务能够基于这些向量返回相关结果。这验证了我们的数据管道已为后续的LLM应用准备好了结构化的向量数据。

大型语言模型实践:第4章:在Azure OpenAI中使用RAG

概述

在本节课中,我们将学习如何在Azure OpenAI服务中实现检索增强生成(RAG)。我们将把之前准备好的文档数据与Azure AI搜索结合,通过向大型语言模型提供相关上下文,来生成更准确、更相关的回答。


上一节我们介绍了如何使用CSV加载器准备数据。本节中,我们来看看如何将这些数据与Azure AI搜索和Azure OpenAI服务连接起来,构建一个完整的RAG应用。

首先,我们将使用相似性搜索功能来查找与查询最相关的文档。以下是执行此操作的代码:

# 使用Azure AI搜索进行相似性搜索
search_results = vector_store.similarity_search_with_relevance_scores(
    query="What is the best governance of wine in Napa Valley above 94 points?"
)

运行这段代码后,我们会得到一个结果列表。例如,我们可能得到“Declaration Napa Valley Governance”这样的相关文档片段。这证明了我们的搜索索引工作正常。

接下来,我们需要设置Azure OpenAI服务,以便将搜索到的上下文发送给大型语言模型进行处理。以下是配置Azure OpenAI客户端所需的组件:

import os
from openai import AzureOpenAI

# 从环境变量加载配置
client = AzureOpenAI(
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
    api_key = os.getenv("AZURE_OPENAI_KEY"),
    api_version = "2023-05-15"  # 注意:这是API版本,至关重要
)

这里需要特别注意api_version参数。如果你需要使用更新或不同版本的API,必须在此处指定,否则调用将失败。

配置好客户端后,我们需要构建发送给模型的“消息”列表。这是RAG流程的核心部分,消息结构如下:

以下是构建消息列表的步骤:

  1. 系统消息:设定AI助手的角色和背景。用户看不到此消息。

    {"role": "system", "content": "You are a chatbot that helps you find the best wine for your taste."}
    
  2. 用户消息:包含用户的实际查询。

    {"role": "user", "content": "What is the best governance of wine in Napa Valley above 94 points?"}
    
  3. 助手消息:包含从Azure AI搜索中检索到的额外上下文内容。这部分内容将来自我们之前执行的相似性搜索的结果。

当所有这些消息准备就绪后,我们就可以看到各个部分是如何组合在一起的:系统消息设定了背景,用户消息提出了问题,而助手消息则提供了从外部知识库(Azure AI搜索)中获取的具体信息。

最后,我们调用Azure OpenAI的聊天补全接口来获取最终答案:

# 调用模型生成回复
response = client.chat.completions.create(
    model="your-deployment-name",  # 你的模型部署名称
    messages=messages  # 上面构建的消息列表
)

# 打印模型的回复
print(response.choices[0].message.content)

运行上述代码,大约1.2秒后,我们得到了模型的回复。回复内容可能是:“这里有一款来自纳帕谷、评分高于94分的高分赤霞珠葡萄酒:2014年的Declaration Cabernet Sauvignon。不过其评分91分并不算很高。”

你可以看到,模型能够以一种清晰的方式整合信息并输出回答。

为了验证整个流程的灵活性,我们可以尝试一个不同的查询。例如,将问题改为:“What is the best Pinot Noir wine in Oregon above 94 points?”

我们需要确保新的查询被正确传递到搜索和消息构建步骤中。修改查询后重新运行代码,模型会基于新的上下文生成回答:“一款来自俄勒冈州、评分高于94分的高分黑皮诺葡萄酒是……”

至此,我们已验证了所有组件都已正确连接并协同工作。我们成功地将Azure AI搜索(之前称为Azure Cognitive Search)与Azure OpenAI服务结合,实现了一个功能完整的RAG应用。


总结

本节课中,我们一起学习了在Azure平台上构建RAG应用的关键步骤。我们首先使用Azure AI搜索检索相关文档,然后配置Azure OpenAI客户端,接着构建包含系统指令、用户查询和检索上下文的消息列表,最后调用模型生成基于上下文的精准回答。这个过程展示了如何将外部知识库与大语言模型的能力相结合,以提供更可靠、更相关的信息。

大型语言模型实践:P148:总结与回顾

在本节课中,我们将回顾如何利用简单的工具在Azure平台上创建和验证向量索引,并理解检索增强生成模式的关键组件。

使用Jupyter Notebook创建与验证索引

上一节我们介绍了检索增强生成的基本概念,本节中我们来看看其具体的实现步骤。我们学习了如何使用一个非常简单的Jupyter笔记本来尝试创建向量嵌入、上传索引,并验证这些嵌入在Azure平台上的工作状态。

我选择使用Jupyter笔记本,是为了演示实际创建那个索引是多么容易,该索引是Azure AI搜索的一个组成部分。

以下是创建和验证索引的核心步骤:

  • 准备数据并生成向量嵌入。
  • 将生成的索引上传至Azure AI搜索服务。
  • 运行查询以验证嵌入检索功能正常工作。

从探索到应用:代码的迁移

通过Jupyter笔记本的交互式探索,我们确保了所创建组件的功能性。我们看到了如何将Jupyter笔记本中的那些组件、代码片段和代码块,在后续整合到实际应用程序中。

但我认为,有趣的是看到在我们试图确保最终创建的东西确实能工作的过程中,可以如何使用Jupyter笔记本来进行试验和调整。

核心服务的连接与集成

我认为,有趣的是看到我们如何能够实际连接Azure OpenAI服务。我们将已部署的模型与使用Azure AI搜索的检索增强生成模式结合起来。

这个连接的核心逻辑可以用以下伪代码表示:

# 1. 用户输入查询
user_query = "用户的问题"
# 2. 使用Azure AI搜索检索相关上下文
retrieved_context = azure_ai_search.retrieve(user_query)
# 3. 将查询与上下文组合,发送给Azure OpenAI模型
enhanced_prompt = f"基于以下上下文:{retrieved_context}, 回答:{user_query}"
# 4. 获取并返回模型生成的答案
final_answer = azure_openai_model.generate(enhanced_prompt)

本节课中我们一起学习了如何利用Jupyter笔记本在Azure AI搜索上快速构建和测试向量索引,并理解了如何将Azure OpenAI服务与检索增强生成模式相集成,为构建更智能的问答应用奠定了基础。

大型语言模型实践:P149:72_04_01_引言_12

概述

在本节课中,我们将学习如何在Azure云上使用GitHub Actions来部署和扩展我们的应用程序。我们将了解应用程序的概览、涉及的组件,并设置必要的Azure组件,特别是容器化部分。虽然我们不会使用Kubernetes,但它是可选的方案。我们将选择Azure中的一项容器化服务,学习如何使其工作,并完成部署、验证和故障排除。最后,我们会探讨在将应用程序部署到云端并与之交互时需要注意的事项。

应用程序部署概览

上一节我们介绍了课程的整体目标,本节中我们来看看具体的部署流程概览。我们将使用GitHub Actions作为自动化工具,在Azure云平台上部署一个容器化的应用程序。

以下是部署流程涉及的核心阶段:

  1. 应用程序概览分析:理解待部署应用的结构与依赖。
  2. Azure组件设置:配置所需的云服务,特别是容器化服务。
  3. 部署与验证:执行自动化部署并验证应用是否正常运行。
  4. 故障排除与注意事项:识别并解决部署中的常见问题,了解最佳实践。

Azure组件与容器化选择

我们不会在本教程中使用Kubernetes,但它是一个可行的替代选项。你可以根据需求,混合使用我将展示的模式和组件,选择不同的部署类型。

我将选择Azure提供的一项容器化服务(例如 Azure Container InstancesAzure App Service 的容器功能)作为部署目标。核心的部署操作可以通过GitHub Actions工作流文件(通常命名为 .github/workflows/deploy.yml)来定义,其中包含触发条件、构建和推送容器镜像、部署到Azure等步骤。

部署、验证与故障排除

在成功部署应用程序后,我们需要验证其是否按预期工作。这包括检查服务端点、查看日志以及确保所有组件正常通信。

以下是在验证和故障排除过程中需要关注的几个方面:

  • 服务健康状态:通过Azure门户或CLI命令检查部署服务的运行状态。
  • 应用程序日志:查看容器或应用服务输出的日志,以诊断运行时错误。
  • 网络与安全配置:确保防火墙规则、网络路由和身份验证设置正确无误。

云端部署的注意事项

当你尝试将这些应用程序部署到云端并希望与之交互时,有一些关键点需要牢记。

以下是部署到云端时的一些核心注意事项:

  • 成本管理:监控和优化云资源的使用,避免产生意外费用。
  • 安全性:妥善管理密钥、证书和访问权限,遵循最小权限原则。
  • 可扩展性:设计应用架构时应考虑如何轻松地进行横向或纵向扩展。
  • 监控与告警:设置监控指标和告警,以便及时响应潜在问题。

总结

本节课中,我们一起学习了利用GitHub Actions在Azure云上部署和扩展容器化应用程序的完整流程。我们从应用程序概览开始,逐步设置了必要的Azure组件,选择了合适的容器化服务,并完成了部署、验证与基础故障排除。最后,我们讨论了将应用成功部署至云端并维持其稳定运行所需关注的核心事项,为后续的实际操作打下了基础。

大型语言模型实践:P150:应用概览 🚀

在本节课中,我们将把之前学到的所有组件整合起来,构建一个完整的应用程序。我们将创建一个基于FastAPI的API服务,该服务会部署在Azure容器中,但在部署前,我们可以在本地进行验证。

应用架构概述

上一节我们介绍了各个独立组件,本节中我们来看看如何将它们组合成一个完整的应用。我们的应用将使用OpenAI的嵌入模型和Azure认知搜索,通过一个API接口来响应用户的查询。

核心组件与代码实现

我们将从定义应用开始,首先需要导入所有必要的库并配置相关服务。

import openai
from azure.core.credentials import AzureKeyCredential
from azure.search.documents import SearchClient
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

以下是应用启动和配置的关键步骤:

  1. 初始化FastAPI应用:创建FastAPI实例作为我们的Web框架。
  2. 配置服务连接:设置连接到OpenAI和Azure认知搜索所需的密钥和端点信息。
  3. 定义数据模型:使用Pydantic模型来定义API请求体的结构。

定义API路由

我们的应用将暴露两个主要路由。根路由/将重定向到文档页面,而核心功能则通过/ask路由提供。

以下是定义的路由及其功能:

  • GET /:根路径,重定向到API文档。
  • POST /ask:核心接口,接收用户查询并返回AI生成的答案。

/ask路由的处理流程分为三步:

  1. 将用户查询提交给Azure认知搜索进行检索。
  2. 将查询和检索结果一起发送给大型语言模型(助手函数)。
  3. 将LLM生成的增强响应返回给用户。

响应的JSON结构为:{"response": chatgpt_response}

辅助函数详解

接下来,我们深入看看支撑应用运行的两个核心辅助函数。

搜索函数

search函数与之前在Jupyter笔记本中使用的逻辑完全相同。它执行相似性搜索并返回相关度分数。我们添加了print语句以便在运行应用时查看搜索返回的内容,方便调试。

def search(query: str):
    # 连接到Azure认知搜索索引
    search_client = SearchClient(endpoint=AZURE_SEARCH_ENDPOINT,
                                 index_name=INDEX_NAME,
                                 credential=AzureKeyCredential(AZURE_SEARCH_KEY))
    # 执行搜索并打印结果
    results = search_client.search(search_text=query, top=5)
    for result in results:
        print(f"Score: {result['@search.score']}, Content: {result['content'][:100]}...")
    return results

助手函数

assistant函数负责与OpenAI服务进行AI交互。它遵循我们之前在Jupyter笔记本中使用的相同模式。

以下是构建请求的步骤:

  1. 系统消息:设定AI助手的角色和行为。
  2. 用户消息:包含原始的用户查询。
  3. 上下文内容:包含从Azure AI搜索返回的文本信息。

最后,我们将所有这些信息组合到messages列表中,并提交给OpenAI的聊天补全接口。响应内容将从response.choices[0].message.content中提取。

运行与测试应用

要运行此应用,我们需要安装依赖并启动服务器。

依赖与环境

应用的主要依赖是:

  • uvicorn:用于运行FastAPI应用的ASGI服务器。
  • fastapi:构建API的Web框架。

其他与OpenAI和Azure相关的依赖与之前相同。应用将通过Docker容器化,Dockerfile中会安装所有依赖并使用Uvicorn作为Web服务器。

本地启动与验证

在终端中,我们可以使用以下命令启动应用:

uvicorn main:app --host 0.0.0.0 --port 8000 --reload

命令解析:

  • main:appmain是Python文件名,app是FastAPI应用实例变量。
  • --host 0.0.0.0:允许所有网络接口访问。
  • --port 8000:指定运行端口。
  • --reload:开发模式下,代码更改后自动重启。

启动后,我们可以在浏览器中访问http://localhost:8000,看到自动生成的API文档。通过/ask路由,我们可以提交查询进行测试。例如,提问“What is a good choice for Cabernet Franc in California?”,应用会调用搜索和LLM,最终返回一个包含推荐葡萄酒(如“2016 Andy Cabernet Franc”)及其评级的答案。

在后台,我们可以看到打印出的搜索日志,验证了应用确实从我们最初加载的CSV数据中检索到了相关信息,并被大型语言模型成功利用。

总结

本节课中我们一起学习了如何构建一个端到端的LLM应用。我们从整合数据检索(Azure认知搜索)与文本生成(OpenAI LLM)开始,使用FastAPI框架将其封装为Web服务,并在本地成功运行和测试。这个应用概述了我们即将部署到Azure容器的完整服务流程,实现了从数据准备到部署为可用服务的全过程。

大型语言模型实践:P151:设置Azure组件 🛠️

在本节课中,我们将学习如何设置Azure云服务中的关键组件,以便为后续部署连接到Azure OpenAI服务的应用程序做好准备。我们将重点关注创建容器应用,并确保其配置与自动化部署脚本相匹配。


创建容器应用

上一节我们介绍了项目背景,本节中我们来看看如何在Azure门户中创建容器应用。这是将应用程序部署到云端的第一步。

我们再次进入Azure门户。接下来,我们将导航到“容器应用”服务并创建一个新的容器应用。但在开始之前,有一个非常重要的细节需要注意:我们的自动化部署脚本已经就位,其配置必须与我们将要创建的资源名称保持一致。

为了确保配置正确,我们需要切换到代码仓库查看预置的GitHub Actions工作流文件。以下是关键步骤:

  1. 访问GitHub仓库的 /.github/workflows/ 目录。
  2. 查看已有的GitHub Action工作流文件。
  3. 找到其中定义的资源组名称和容器应用名称。这两个名称至关重要。

在我的例子中,这些资源在创建服务之前就已经存在。但如果你还没有创建,只需确保在创建容器时,使用的名称与自动化脚本中定义的名称完全匹配即可。


在门户中配置资源

现在,我们回到Azure门户进行实际操作。我将进入“容器应用”服务。我之前已经创建过一个,这次我将从头开始创建一个新的。

点击“创建”按钮后,需要填写以下信息:

  • 资源组:选择或创建一个新的资源组。我将使用之前提到的 demo-container
  • 容器应用名称:将其设置为与资源组相同的名称 demo-container,以确保自动化流程能正确识别。

我发现 demo-container 资源组已经存在,因此可以直接从下拉菜单中选择它。将应用程序命名为相同的名称,可以确保后续步骤能够正常工作。

接下来需要选择区域。Australia 不是我的首选区域,我更喜欢 East US。确认所有信息无误后,点击“查看 + 创建”进行验证,最后点击“创建”。

这个过程需要一些时间。一旦资源创建完成,我们就可以开始使用自动化部署流程了。


理解自动化部署架构

这些就是我们所需的核心资源。现在,让我们回到GitHub Action来理解其工作原理。

这个GitHub Action将使用 GitHub容器注册表。这意味着,我构建的任何容器镜像都会存储在GitHub自身的服务中。

这是一种架构设计选择,允许我将容器存储在特定的位置。你并非必须使用GitHub容器注册表,也可以选择将镜像推送到Azure容器注册表。但在本教程中,我们将利用GitHub提供的简单直接的容器注册表服务。

一旦资源就绪,你将看到部署进度开始推进。当所有步骤完成后,我们的环境就准备就绪,可以继续推进,实现连接到Azure OpenAI服务的应用程序的自动化部署。


总结

本节课中,我们一起学习了在Azure中设置容器应用的核心步骤。关键点在于确保手动创建的资源名称(如资源组和容器应用名称)与自动化部署脚本中的定义完全一致。我们还了解了如何使用GitHub容器注册表作为镜像仓库,为后续的自动化部署流程奠定了基础。

大型语言模型实践:P152:架构概览 🏗️

在本节课中,我们将学习如何将一个基于大型语言模型的应用部署到云端。我们将通过一个清晰的架构概览,了解从代码开发到最终用户交互的完整流程,以及各个组件是如何协同工作的。

概述

理解我们拥有的架构概览,将帮助我们理解所有组件如何协同工作。

我们从代码开始。我们有一个应用程序,其代码托管在 GitHub 上。该应用包含一个 HTTP API,用于接收请求并与模型交互。那么,这个应用将如何实际部署呢?

部署流程详解

上一节我们介绍了整体目标,本节中我们来看看具体的部署步骤。以下是实现从代码到云端部署的核心步骤:

  1. 代码与 GitHub:我们从应用程序代码开始,代码托管在 GitHub 仓库中。
  2. 自动化构建 (GitHub Actions):我们将使用 GitHub Actions 来实现自动化。GitHub Actions 将与 Docker 交互,设置 Docker 构建系统并执行命令。
  3. 容器化构建:通过上述步骤,我们将能够构建我们的容器化应用程序。构建容器应用是至关重要的一步,目的是为了将其部署到 Azure 云上。这个过程会构建一个容器。
  4. 推送镜像到仓库:构建完成后,我们将把生成的容器镜像推送到一个注册表。在本案例中,我们使用的是 GitHub 容器注册表 (GHCR)。当然,你也可以使用其他注册表。这里我们选择简化流程,因为用户名和密码等配置已经为我们预先设置好了,稍后我们在查看 GitHub Actions 工作流时会详细看到这些细节。
  5. 触发 Azure 拉取镜像:当注册表步骤完成后,GitHub Actions 会通知 Azure(具体是 Azure 容器实例服务)去从我们的注册表中拉取构建好的镜像。这是一个触发效应,我们告诉 Azure:“镜像已就绪,可以拉取了。”
  6. 应用部署与运行:Azure 从注册表(GHCR)拉取容器后,便会将其发布并运行起来。

用户交互与系统扩展

现在,让我们进一步看看应用运行起来后,用户如何与之交互,以及系统如何处理负载。

最终,用户将开始与我们的应用程序交互。用户会发送一些提示或查询。

这些请求将被 Azure 云接收,因为我们的应用程序就运行在云端。Azure 能够扩展我们的应用程序,这被称为水平扩展。随着请求增多,Azure 可以部署更多的小单元(即容器)来处理这些请求。这种根据需求增长容器数量的能力,就是一个水平扩展系统,它使我们能够处理所有涌入容器的请求。

当请求到达容器后,应用程序便能与 Azure OpenAI 服务进行通信。

一旦能够与 Azure OpenAI 服务通信,用户的请求就会被处理:请求发送到容器,容器与 Azure OpenAI 服务交互,处理完成后,响应再通过 Azure 返回给用户。

总结

本节课中,我们一起学习了将一个 LLM 应用部署到 Azure 的完整架构流程。我们不仅看到了应用程序、HTTP API 和代码本身,更重要的是理解了如何通过 GitHub Actions 实现自动化构建与部署,以及 Azure 如何提供容器化运行环境和水平扩展能力。这个概览为你提供了一个坚实的概念基础,接下来我们将深入 GitHub Actions,查看具体的工作流配置。

大型语言模型实践:P153:在Azure中使用GitHub Actions 🚀

在本节课中,我们将学习如何配置和使用GitHub Actions,以实现将应用程序自动构建并部署到Azure容器应用服务。我们将详细解析工作流程文件,并说明如何设置必要的认证信息。


上一节我们介绍了Azure容器应用的基本概念,本节中我们来看看如何通过GitHub Actions实现自动化部署。

GitHub Actions与Azure的结合使用是我非常推荐的方式。正如之前简要提到的,其核心是一个YAML配置文件。该文件位于我们的应用程序代码仓库中(在我的账户下是azure-dash-rag仓库)。我们的目标是在此文件中定义一系列自动化步骤。虽然之前已经快速浏览过,但我会再次强调一些核心组件。

除了可以自定义的name字段外,以下部分至关重要:

  • env 环境变量部分:这里定义了容器应用服务的名称。例如,我创建的服务名为 demo-container。如果你使用其他名称,需要在此处修改。
  • on 触发器部分:workflow_dispatch 选项非常重要,它允许我们手动触发工作流。这意味着工作流不会在代码推送到主分支时自动运行。如果你确信代码变更经过验证并希望自动部署到云端,未来可以改为监听 push 事件。目前,我们依赖手动触发。

接下来是构建阶段。此阶段将构建Docker容器,并认证到GitHub容器注册表。可以看到,GITHUB_ACTOR(会解析为我的用户名)和GITHUB_TOKEN已预先设置好,无需额外操作。这为后续Docker推送镜像到注册表做好了认证准备。

需要注意,镜像标签使用了 ghcr.io 前缀,这至关重要。构建完成后,镜像将被推送到GitHub容器注册表。

最后是部署阶段。我们将在此与Azure交互。为了进行身份验证,必须预先设置Azure凭据。这需要创建一个服务主体。

以下是创建Azure服务主体的步骤:

  1. 在Azure门户使用Cloud Shell或本地终端,运行以下命令(需替换你的订阅ID):
    az ad sp create-for-rbac --name "myApp" --role contributor --scopes /subscriptions/<subscription-id>/resourceGroups/<resource-group-name> --sdk-auth
    
  2. 命令会输出一段JSON。复制整个JSON输出。
  3. 进入GitHub仓库的Settings -> Secrets and variables -> Actions
  4. 点击New repository secret
  5. 将秘密名称设为AZURE_CREDENTIALS,并将复制的JSON内容粘贴到值中,然后保存。

完成上述步骤后,就可以在工作流中使用 azure/login 动作登录Azure,并开始向容器应用部署。

在工作流中,我们使用 azure/CLI 动作来运行Azure CLI命令。首先,我们设置容器应用的注册表信息,包括应用名称、资源组、服务器地址(GitHub容器注册表)、用户名(GITHUB_ACTOR)和密码。

密码使用的是名为 PAT 的个人访问令牌。你需要创建一个具有write:packages权限的GitHub个人访问令牌。

  • 访问 https://github.com/settings/tokens/new 创建令牌。
  • 描述可设为“Azure Container Apps”,权限选择write:packages
  • 创建后,复制令牌值,并像设置AZURE_CREDENTIALS一样,在仓库的Actions Secrets中创建一个名为PAT的秘密。

回到工作流文件,接下来我们设置一些环境变量,这些变量将注入到容器应用中:

  • OPENAI_TYPE: 设置为 azure
  • OPENAI_BASE: 你的Azure OpenAI部署端点。
  • OPENAI_KEY: Azure OpenAI API密钥(需设置为GitHub秘密)。
  • AZURE_SEARCH_SERVICE: 你的Azure AI搜索服务名称。
  • AZURE_SEARCH_KEY: 搜索服务的API密钥(需设置为GitHub秘密)。
  • AZURE_SEARCH_INDEX: 搜索索引的名称,例如 demoredo

然后,我们配置容器应用的计算资源,例如2个CPU核心和4GB内存。由于是Python应用,需要这些资源来保证运行。

最后,通过命令指示容器应用拉取新构建的镜像并开始部署。工作流文件的第66行负责执行此操作。

完成所有配置后,我们就可以触发工作流。成功后,应用程序将自动部署到Azure并开始运行。


本节课中我们一起学习了如何配置GitHub Actions工作流文件,以及如何设置Azure服务主体和GitHub个人访问令牌等关键秘密,最终实现将应用自动化部署到Azure容器应用服务。掌握这些步骤,你就能建立一套高效的CI/CD流程。

大型语言模型实践:P154:验证与故障排除部署 🚀

在本节课中,我们将学习如何验证和排查一个已部署到Azure容器应用(Azure Container Apps)的应用程序。我们将通过检查工作流日志、修正配置错误以及验证应用功能,来确保部署成功。


概述

我们已经准备好部署应用程序。这是最后的步骤。我们有一个之前创建资源时部署过的演示容器应用。现在,我们需要前往代码仓库,在Actions(操作)步骤中手动触发部署工作流。

在开始之前,需要了解一个关于自动化构建的现实:失败是常态。你很少能第一次就完全正确。你可能会遗漏变量、出现拼写错误,需要通过查看失败日志来定位问题。

我已经触发了工作流。接下来,我们将查看工作流的运行情况,而不是等待它完成。


检查工作流日志

工作流包含两个主要步骤:构建(Build)部署(Deploy)

以下是每个步骤的功能:

  • 构建步骤:创建容器镜像,安装所有依赖项,并将应用打包。
  • 部署步骤:将构建好的容器镜像推送到Azure容器应用。

点击任意一个步骤,可以查看详细的日志输出。在部署步骤的日志中,你会看到它执行了Azure登录、处理仓库名称,并最终完成部署。一些敏感设置会以星号(*)显示,以防止泄露。

现在,部署已经成功完成。


排查应用访问问题

上一节我们确认了部署流程成功,本节中我们来看看如何访问已部署的应用。

接下来,我们需要在Azure门户中验证应用是否正常运行。在容器应用的“概览”部分,可以找到应用URL。

点击这个URL在新标签页中打开。你可能会遇到第一个问题:页面可能显示连接错误或重置。这是因为我们的容器内部使用的是端口 8000,而Azure容器应用默认尝试访问的是端口 80

要解决此问题,请按以下步骤操作:

  1. 在Azure容器应用页面,找到并点击“入口(Ingress)”设置。
  2. 向下滚动,找到“目标端口(Target Port)”设置。
  3. 将目标端口从默认值修改为 8000
  4. 保存更改,并等待入口配置更新完成。

更新成功后,使用相同的URL重新加载页面,现在应该能看到我们的FastAPI应用程序界面了。这表明应用正在Azure上成功运行。


验证应用功能

现在应用可以访问了,我们需要测试其核心功能是否正常。

在FastAPI的交互式文档页面(通常为 /docs),点击“Try it out”按钮。例如,我们可以输入一个问题:“What is a good wine from Oregon you can recommend?”(你能推荐一款俄勒冈州的好葡萄酒吗?)。

点击执行后,应用会:

  1. 联系我们集成的索引。
  2. 通过Azure OpenAI服务处理请求。
  3. 返回一个关于俄勒冈州葡萄酒的推荐回答。

如果能看到正确的回答,就证明从前端界面到后端Azure OpenAI服务的整个链路都是通畅的,并且应用已公开可用。


监控与高级配置

应用运行后,持续的监控和正确的配置是保证其稳定性的关键。

1. 查看日志流(Log Stream)
在Azure门户中进入“日志流(Log Stream)”,可以实时查看容器的终端输出。这是排查运行时问题(如代码错误、异常请求)的首要位置。如果一切正常,你会看到常规的请求和响应日志。

2. 检查环境变量
在“容器(Containers)”设置中,确认所有环境变量(如API密钥、端点URL)都已正确设置。这是应用能连接到Azure OpenAI等外部服务的基础。

3. 调整缩放与副本(Scale and Replicas)
在“缩放(Scale)”设置中,你可以配置应用的处理能力。例如,可以将副本数范围设置为 010。增加副本数可以提升应用处理并发请求的能力和带宽。


总结

本节课中我们一起学习了部署后的验证与故障排除全流程。我们首先检查了GitHub Actions的工作流日志,确认了构建和部署步骤的成功。接着,我们排查并修复了因容器端口(8000)与默认入口端口(80)不匹配导致的访问问题。然后,我们通过调用API验证了应用功能与Azure OpenAI服务的连接是正常的。最后,我们介绍了如何通过日志流监控应用状态,以及如何检查环境变量和配置缩放规则以确保应用性能。

至此,我们的应用程序已成功部署到Azure容器应用,并通过GitHub Actions实现了自动化部署流程。

大型语言模型实践:4.7:总结

在本节课中,我们将回顾并总结如何利用自动化流程,在Azure平台上部署一个集成了多种服务的大型语言模型应用。

概述

本节将总结整个部署流程。我们最终成功地将应用部署到了Azure平台。这个过程中,我们综合运用了GitHub Actions实现自动化部署、Azure AI搜索服务、Azure OpenAI服务以及我们之前创建的一些模型。

部署流程回顾

上一节我们介绍了具体的部署步骤,本节中我们来看看整个项目的核心收获。

我们首先需要创建索引,以确保应用程序能够正确运行。这一步骤为后续的搜索和问答功能奠定了基础。

核心组件与能力

通过本课程的学习,你应该对可用的所有组件有了扎实的理解。这使你能够根据需求,在构建与大型语言模型相关的应用时,精确地选择和组合所需的服务。

以下是本课程涵盖的核心服务与概念:

  • 自动化部署:使用 GitHub Actions 工作流实现持续集成与部署。
  • 向量搜索:利用 Azure AI Search 服务存储和检索文本的向量表示。
  • 模型服务:通过 Azure OpenAI Service 调用强大的语言模型。
  • 自定义索引:创建并管理专有数据的索引,为应用提供上下文。

项目的灵活性与扩展性

本课程的重点在于大型语言模型应用的自动化与运维化。我们以一个看似简单的“葡萄酒信息查询”应用为例,但你可以看到其架构的灵活性。

你可以用自己的信息和数据替换其中的某些组件,从而产生全新的应用创意。整个课程的侧重点在于为你提供所需的基础知识,使你能够构建与我演示的类似或完全不同的应用,并为你提供实现目标的所有必要工具。

挑战与价值

我们最终成功部署了一个有用的应用,虽然过程中遇到了一些棘手的难题,但我们也探索了许多引人入胜的技术。

特别是在Azure平台上,结合使用大型语言模型和Azure OpenAI服务,展现了巨大的潜力。希望你觉得这些模式和概念很有用,并能在尝试部署自己的应用程序时应用它们。

总结

本节课中我们一起学习了如何利用自动化工具链在Azure云平台上部署一个集成化的大型语言模型应用。我们回顾了从创建索引、组合AI服务到通过GitHub Actions实现自动化部署的完整流程,并探讨了如何将此项目模式灵活应用到你自己的创意和数据集之中。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P1:01_01_01:认识你的讲师阿尔弗雷多·德萨 👨‍🏫

在本节课中,我们将认识本课程的讲师阿尔弗雷多·德萨,并了解他的技术背景与课程内容之间的联系。

大家好,我的名字是阿尔弗雷多·德萨。我很高兴为大家带来这门应用数据工程课程。我的背景是软件工程。我实际上是从系统管理员开始的,因此很自然地,我成为了一名开发运维专家。

在我的职业生涯中,我做过许多不同的事情,包括一些Python开发,以及网站前端开发、分布式文件系统,到构建复杂的CICD系统。

现在,你将在整个课程中看到,我在开发强大应用程序和进行大量Python编程方面的经验。当我开始提及构建自动化以及构建应用数据工程中具有弹性的基础设施组件时,你将看到这一点。在应用数据工程中,你需要弹性,因为事情不会总是一帆风顺。

我很高兴你将看到所有这些部分汇集在一起,并被纳入本课程。希望你能在尝试超越我们将要涵盖的一些概念时感到得心应手,例如向量数据库、队列系统、RabbitMQ、Python应用程序。这些应用程序将产生工作单元,由消费者使用,并且你也将进行一些处理。

因此,本课程将为你提供入门所需的一切。希望你在课程结束时会发现它非常有用。


本节课中我们一起学习了讲师阿尔弗雷多·德萨的背景,他拥有从系统管理员到开发运维专家的丰富经验,涉及Python开发、前端、分布式系统等多个领域。本课程将融合这些经验,重点教授构建具有弹性的数据工程系统,涵盖向量数据库、消息队列等核心概念,旨在为学习者提供扎实的入门基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P2:02_01_04:关于本课程 📘

在本课程中,我们将深入探讨高级数据工程中的多种关键技术。我们将从消息队列开始,逐步学习如何构建、处理和管理数据管道,并最终将这些概念应用于解决现实世界的问题。

消息队列与Python应用 🚀

上一节我们介绍了课程的整体目标,本节中我们来看看第一个核心组件:消息队列。我们将从研究队列系统开始,特别是RabbitMQ以及各类可用的消息代理。我们会学习如何将其连接到Python应用程序。

我们将看到如何从Python应用程序中生成工作项或工作单元,然后将其连接并放入队列中供后续处理。队列提供了一些仅使用纯Python难以实现或效率低下的能力。

以下是队列能实现的一些关键能力示例:

  • 将任务异步化,提升应用响应速度。
  • 实现不同服务或应用之间的解耦通信。
  • 对涌入的大量任务进行缓冲和流量控制。
  • 确保重要任务在系统故障后仍能被处理。

掌握消息队列是迈向高级数据工程概念的重要一步,无论你是希望提升技能的数据工程师,还是想从全新视角审视基础设施和数据管道的软件工程师,这都将使你受益匪浅。

使用Apache Airflow构建数据管道 🔄

在了解了如何通过队列传递数据单元后,我们面临的下一个问题是:如何有序地组织和调度这些数据处理任务?这就是Apache Airflow的用武之地。

接下来,我们将探讨Apache Airflow是什么、它如何工作,以及如何利用它创建一个稳固可靠的数据管道。在数据工程中,我们不仅需要生成数据,更重要的是能够以可被利用的方式处理和转换数据。

我们将看到,当数据被处理到可供后续流程使用的状态时,不同类型的处理操作才能有效发生。Airflow帮助我们定义、调度和监控这些复杂的工作流。

数据存储:向量、图与键值数据库 💾

处理完数据后,我们需要将其存储起来。除了使用队列和生成数据,我们还需要将数据存储在某个地方。

现在,让我们把目光转向数据存储。我们将研究向量数据库、图数据库和键值数据库。当你需要选择其中一种时,了解它们之间的差异至关重要。

特别是向量数据库,由于自然语言处理和我们所处的当前AI时代,它变得非常流行。我们将探讨为什么向量数据库如今在自然语言处理任务中备受青睐,其核心优势在于能够高效存储和检索高维向量数据,例如通过相似度计算(如余弦相似度)来寻找语义相近的文本。

综合实践:高级数据工程项目 🏗️

最后,我们将通过真实的、高级的数据工程项目来整合所学内容。我们将看看如何将你在整个课程中学到的许多概念,应用到解决现实世界的问题中。

让我们来解决一些你可能会遇到的问题,这能让你很好地了解,作为一名数据工程师、软件工程师、数据科学家或机器学习工程师,当处理大规模数据时,应如何应对这些挑战。

总结 📝

本节课中我们一起学习了本高级数据工程课程的核心路线图。我们从消息队列(如RabbitMQ)与Python的集成开始,学习了异步任务处理;接着探索了使用Apache Airflow编排复杂数据管道;然后分析了向量数据库等现代数据存储方案的优势与应用场景;最后,课程将以综合性的实战项目收尾,帮助你将所有概念融会贯通,以解决实际的工程问题。希望你通过本课程的学习,能够获得足够的知识与信心,去应对数据工程领域的重大挑战。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P3:03_01_02:引言_1

在本节课中,我们将学习如何与消息队列协作,了解其行为特性,并探索如何将数据放入队列以及如何从中取出数据。我们还将介绍如何配置队列的各种行为。接着,我们会探讨Celery,它是一个独立的进程,在Python开发中非常有用。我们将学习如何将Python应用程序连接到消息代理,特别是RabbitMQ。最后,我们会深入了解RabbitMQ的一些典型应用场景,解释为什么在开发中需要队列或RabbitMQ这样的工具,尤其是在使用Flask应用生成工作单元时。Flask是一个强大的Python框架,我们将用它来演示如何将这些技术整合在一起,构建一个可运行的应用程序。

消息队列基础

上一节我们介绍了课程的整体目标,本节中我们来看看消息队列的核心概念。消息队列是一种允许应用程序通过发送和接收消息来进行通信的中间件。它的主要作用是解耦生产者和消费者,使系统更具弹性和可扩展性。

以下是消息队列的几个关键行为:

  • 数据入队:生产者将消息发送到队列中。这个过程通常是异步的。
  • 数据出队:消费者从队列中接收并处理消息。
  • 持久化:可以配置队列将消息保存到磁盘,防止服务重启时数据丢失。
  • 消息确认:消费者处理完消息后,可以向队列发送确认,确保消息被成功消费。
  • 负载均衡:多个消费者可以从同一个队列消费消息,实现工作负载的分配。

使用Celery连接Python与消息代理

了解了队列的基本行为后,我们来看看如何在实际应用中使用它。Celery是一个分布式任务队列,它允许你将任务执行从主应用程序进程中分离出来。

Celery本身不提供消息服务,它需要一个消息代理来传递任务。我们将使用RabbitMQ作为消息代理。连接过程的核心是创建一个Celery应用实例,并为其配置消息代理的地址。

以下是一个基本的连接示例代码:

from celery import Celery

# 创建Celery应用实例,并指定消息代理(RabbitMQ)的地址
app = Celery('my_app', broker='pyamqp://guest@localhost//')

# 定义一个简单的任务
@app.task
def add(x, y):
    return x + y

在这段代码中,broker参数指定了RabbitMQ服务器的连接地址。Celery应用会通过这个地址与RabbitMQ建立连接,发送和接收任务消息。

RabbitMQ的应用场景

你可能会问,为什么需要RabbitMQ或类似的队列系统?接下来,我们深入探讨其应用场景,特别是在从Flask应用产生工作单元的上下文中。

RabbitMQ的核心价值在于异步处理应用解耦。例如,在一个Web应用(如Flask应用)中,用户上传文件后需要立即返回响应,但文件处理(如格式转换、分析)可能非常耗时。如果同步处理,用户会长时间等待。

使用RabbitMQ后,流程变为:

  1. Flask应用接收到文件后,立即将一个“处理文件”的任务消息放入RabbitMQ队列。
  2. Flask应用随即向用户返回“任务已接收”的响应。
  3. 后台的Celery工作进程从RabbitMQ队列中取出该任务消息,并执行耗时的文件处理工作。

这种方式带来了以下好处:

  • 提升用户体验:Web请求响应迅速。
  • 提高系统可靠性:即使后台处理服务暂时不可用,任务消息也会安全地存储在队列中,等待恢复后处理。
  • 易于扩展:可以通过增加Celery工作进程的数量来并行处理更多任务。

技术整合与实践

最后,我们将使用Flask框架,把前面所学的知识整合起来。Flask负责提供Web API接口,RabbitMQ作为消息中间件,Celery作为后台任务执行者。

一个典型的工作流是:

  1. Flask路由接收到HTTP请求。
  2. 在视图函数中,调用Celery任务(如add.delay(4, 4)),这会将任务发送到RabbitMQ。
  3. Celery的工作者进程监听到新任务,从RabbitMQ获取并执行它。
  4. 任务执行结果可以存储起来(例如在Redis中),供后续查询。

通过这种架构,我们能够构建出高性能、可维护且松耦合的应用程序。

总结

本节课中我们一起学习了消息队列的基本概念和行为,包括数据的入队与出队。我们介绍了如何使用Celery将Python应用程序连接到RabbitMQ消息代理。我们还探讨了RabbitMQ在异步处理和应用解耦方面的关键应用场景,理解了它在构建响应式Web应用(如使用Flask)中的重要性。最后,我们概述了如何将这些技术——Flask、RabbitMQ和Celery——整合在一起,形成一个完整、高效的工作流。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P4:04_01_03_队列概述 📚

在本节课中,我们将要学习队列的基本概念。队列是消息传递和异步处理系统中的核心组件,理解其工作原理对于后续学习RabbitMQ等消息队列工具至关重要。

队列的基本概念

上一节我们介绍了数据处理的基本流程,本节中我们来看看队列在其中扮演的角色。队列本质上是一个可以存放工作项的地方。这些工作项代表需要被处理的单元。

例如,这些工作项可以是数据、一封待发送的电子邮件,或任何需要在某个时间点执行的任务。这些工作单元以某种方式被生产出来,然后进入一个类似传送带的系统。这个传送带系统会接收这些工作单元,并进行处理。通常,会有另一个组件来处理这些工作单元并执行相应的操作。

简而言之,这是一个非常快速的概述:工作单元被生产出来,而队列则负责管理这些被生产出来的工作。

队列的工作模式

接下来,我们需要了解队列有多种不同的工作模式。

以下是两种常见的队列处理模式:

  • 后进先出:在这种模式下,最后进入队列的项目将最先被取出。假设我们有一系列按顺序进入队列的项目:A最先进入,B其次,依此类推,F最后进入。当需要从队列中消费一个项目时,字母F将是第一个被取出的。
  • 先进先出:在这种模式下,最先进入队列的项目将最先被取出。以同样的项目序列为例,如果A最先进入,那么无论队列中有多少其他项目,队列都会优先让A被消费。A被取出后,B将是下一个,依此类推。

因此,队列可以是“后进先出”,即最后进入的第一个出去;也可以是“先进先出”,即最先进入的第一个出去。

生产者-消费者架构

为了总结这部分内容,我们需要理解一个完整的队列系统通常包含两个部分:生产者和消费者。

在这种架构中,总会有一个组件负责生产工作项,我们称之为生产者。生产者会将项目放入队列。例如,生产者可能先放入A,然后放入B。这些工作单元进入的队列可以是像RabbitMQ这样的消息队列。RabbitMQ等消息队列本身也有多种类型。

生产者将项目放入队列后,另一个独立的进程——消费者——会查看队列并获取下一个需要处理的项目。这种架构和工作模式是你在实现和使用队列时应该关注的。

生产者和消费者协同工作。如果消费者没有任务可做,它将保持空闲状态,直到队列中有新的项目出现。这种工作模式非常有用,因为生产者可以持续向队列中添加项目,而消费者可以按照自己的节奏从队列中取出并处理。这种关注点分离使得消费者可以独立于生产者运行,并且这些系统可以根据你正在处理的工作负载类型进行独立扩展。

总结

本节课中我们一起学习了队列的核心概念。我们了解到队列是用于存放和管理工作单元的地方,并探讨了先进先出后进先出两种基本工作模式。最后,我们介绍了基于队列的生产者-消费者架构,这种模式通过分离生产与消费过程,提高了系统的可扩展性和灵活性。理解这些基础知识是后续学习具体消息队列技术(如RabbitMQ)的重要前提。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P5:05_01_04:什么是Celery 🐇

在本节课中,我们将要学习Celery,一个用于处理分布式任务队列的Python包。我们将了解它的核心作用、支持的中间件(Broker)以及它如何作为Python应用与消息队列(如RabbitMQ)之间的“中间人”来协调工作。

概述

Celery是一个Python包,它能够与多种不同的框架和消息代理(Broker)协同工作,例如RabbitMQ。它的核心作用是充当中间人,允许你在Python中创建工作项,并将这些工作项发送到其他地方(如RabbitMQ)进行处理。

Celery的核心角色

上一节我们概述了Celery的基本概念,本节中我们来看看它的具体角色和工作原理。

简单来说,Celery是一个中间人。它让你能够在Python环境中生成工作任务,并将这些任务放置到别处。在我们将要演示的案例中,这个“别处”就是RabbitMQ(一个消息队列)。文档中详细说明了任务队列的具体细节,我们已经对其有了一些初步了解。

AMQP是RabbitMQ所使用的协议。从图中可以看到,Celery明确支持该协议。

我相信Celery最初发布时,首先支持的就是RabbitMQ。

支持的Broker与功能

了解了Celery的角色后,我们来看看它支持哪些消息代理以及具备哪些功能。

以下是Celery支持的部分消息代理(Broker):

  • 你可以使用RabbitMQ(这也是我们课程的重点)。
  • 它支持Redis
  • 它支持Amazon SQS等更多服务。
  • 你甚至可以使用数据库作为队列。我个人认为RabbitMQ非常出色。

这意味着你的Python应用会生成工作任务,这些任务会连接到Celery,然后由Celery将它们放到其他地方,比如RabbitMQ。因此,Celery扮演着中间人的角色。

我倾向于将Celery看作邮递员,负责来回传递所有消息。生产者(你的Python应用)就像写信的人,Celery就像负责将信件送往别处的邮递员,它负责投递。而邮局就是RabbitMQ,本质上负责找出传递所有这些消息的路径。

结果存储与特性

Celery不仅负责发送任务,还能处理任务执行后的结果。

这里还提供了存储结果的后端。这意味着当任务不仅被生产出来,而且被处理完成后,你可以捕获这些结果并能够将它们取回。这表明Celery允许你消费一些消息,并能将它们存储回来。

当然,它还支持并发和序列化。你可以看到它支持Pickle、JSON、YAML等消息格式。我们不会深入探讨所有这些,但会快速浏览一下。

那么,这究竟意味着什么?本质上,Celery是必需的,因为它让我们的工作变得更轻松。当我们在Python中工作,并想使用像RabbitMQ这样的服务时,Celery提供了极大的便利。

总结

本节课中我们一起学习了Celery。我们了解到Celery是一个用于分布式任务队列的Python包,它充当Python应用程序与消息代理(如RabbitMQ)之间的中间人。它负责将Python中产生的任务发送到消息队列,并可以处理任务结果的返回与存储,从而简化了在Python中使用消息队列的复杂性。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P6:06_01_06_RabbitMQ的用例 🐇

在本节课程中,我们将学习RabbitMQ的几个核心应用场景。我们将参考RabbitMQ官方文档中的教程,并挑选其中一些典型用例进行讲解,以帮助你理解消息队列在实际系统中的用途。

工作队列(Work Queues) ⚙️

上一节我们介绍了消息队列的基本概念,本节中我们来看看RabbitMQ的第一个常见用例:工作队列。工作队列本质上就是我们之前描述的模式:一个生产者创建工作任务单元,并将其放入队列;同时,多个消费者从该队列中取出并处理任务。这是一种“一对多”的关系,但也可以是“多对多”的,即多个生产者向队列投放任务,多个消费者从队列消费任务。

以下是工作队列的一个典型应用示例:

  • 图像处理:我曾构建过类似的系统。用户上传一张可能很大的图片,系统将其作为一个任务单元放入队列。随后,独立的处理节点会从队列中获取这个图像任务,并执行不同格式的尺寸调整。这对于运行大规模网站非常有用,例如需要为大型图像生成多种缩略图。

发布/订阅(Publish/Subscribe) 📢

接下来,我们探讨发布/订阅模式。这种模式适用于需要发送消息的场景。想象一个需要在多个组件之间进行通信的系统,你有多个不同的生产者,而消费者可以订阅一个队列。

订阅队列意味着当特定事件发生时,你能收到通知。发布/订阅(常简称为Pub/Sub)模式可以实现多种功能,它允许消费者接收的不仅是工作任务单元,更可以是用于通信的消息,从而实现多个节点间的相互通信。

路由(Routing)与RPC(远程过程调用) 🔀

我们还有路由功能,它允许选择性地接收消息。这更像是声明“我想将这些消息发送到这个队列,将那些发送到另一个队列”。这与其说是一种独立功能,不如说是一种架构模式,类似于主题(Topics)模式。

然而,RPC(远程过程调用)是一个非常有趣的模式。在RPC中,你不仅可以发出请求,还能收到回复。如下图所示,客户端发送请求,通过队列到达服务器,然后服务器会回复响应。这种请求-回复模式也非常有用。

总结 📝

本节课中,我们一起学习了RabbitMQ的几个关键用例。最常见的模式包括用于处理耗时任务的工作队列,以及用于系统间通信和事件通知的发布/订阅模式。理解这些模式将帮助你在设计分布式系统时,有效地利用消息队列来解耦组件、平衡负载和实现可靠通信。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P7:07_01_08_Flask与Celery应用概述 🚀

在本节课中,我们将要学习一个结合了Flask、Celery和RabbitMQ的应用程序的概述。这个应用程序包含了多个示例,旨在演示不同的功能,因此其结构并非为单一目的而设计得极其简洁。我们将从查看项目依赖开始,逐步了解其核心组件和基本工作流程。

项目依赖与核心组件 📦

首先,我们来看看这个应用程序安装了哪些核心库。以下是requirements.txt文件中的关键依赖:

  • Flask: 作为Web应用框架。
  • Celery: 作为处理异步任务的中间件。
  • BeautifulSoup4requests: 作为支持库,用于网页抓取等辅助功能。

这个应用的核心架构是:Flask处理Web请求,而Celery作为中间人处理后台的异步任务。

应用结构与初始化 🔧

应用程序的主要逻辑位于app子目录中。让我们快速浏览一下main.py文件,了解其初始化过程。

main.py中,通常会看到一些辅助函数来设置应用环境。例如,有专门设置Celery的代码,以及设置Flask应用并为其配置Celery的代码。这些配置的细节我们将在后续课程中深入探讨。

应用路由与功能示例 🌐

现在,我们来看看应用程序定义的具体路由和功能。

当有请求访问网站的根路径(/)时,应用会返回一个简单的HTML页面。这个页面包含了一个curl命令示例,你可以用它来尝试触发Celery任务。

接下来是一个典型的用例。假设你需要发送邮件,你会有一个同步路由。请求到达这个路由后,会被处理,然后它会异步地调用另一个函数。这个异步函数是如何工作的呢?我们通过一个shared_task装饰器来定义它。在任务函数中,我们特意使用time.sleep(5)让任务休眠5秒,这样可以清晰地观察到任务是如何被放入队列,并在5秒后被处理的。这是一种常见模式:一个暴露的同步路由接收请求,然后将其交给后台的异步代码处理。

类似地,我们还将详细展示其他类型的路由。在这些路由中,你不仅可以触发像发送邮件这样的操作,还可以选择返回一个任务ID。这样,你不仅可以在后台处理任务,还可以在之后通过这个ID来查询任务的处理结果。

总结 📝

本节课我们一起学习了一个集成Flask、Celery和RabbitMQ的应用程序的快速概述。这个应用虽然简单直接,但它清晰地展示了这些组件如何协同工作:Flask负责Web接口,Celery管理异步任务队列,而RabbitMQ作为消息代理。在后续课程中,我们将深入这个应用的细节,并按顺序研究这些示例的具体实现。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P8:08_01_09_总结_1

概述 📋

在本节课中,我们将回顾并总结关于消息队列的核心知识,包括其工作原理、行为模式、在应用架构中的重要性,以及如何与Flask和Celery等工具协同工作。

消息队列基础回顾 🔄

上一节我们介绍了消息队列的基本概念。本节中,我们来总结其核心要点。

我们了解了消息队列如何运作的基础知识。我们甚至深入探讨了可以从队列中预期的行为,例如先进先出(FIFO)后进先出(LIFO),以及这些行为如何影响队列本身。

公式/概念

  • 先进先出 (FIFO): 第一个进入队列的任务将第一个被处理
  • 后进先出 (LIFO): 最后一个进入队列的任务将第一个被处理

我们不会过多涉及如何配置RabbitMQ这类消息代理队列的具体细节,但理解消息如何被生产以及如何连接到消费者是非常有用的。

关注点分离与可扩展性 ⚙️

同样,我们也看到了分离关注点的重要性。通过分离生产者和消费者对工作单元的关注,允许我们实现扩展。可扩展性是一个需要牢记的重要方面,尤其是为了未来当我们希望提升应用能力时。

应用架构:Flask与Celery 🧩

最后,我们快速浏览了我们的应用将如何与Flask和Celery协同工作,以及为什么Celery如此重要。我们看到,Celery将与我们的Flask应用一同工作。

您还对RabbitMQ有了一些认识,并了解了一些可以做的事情,例如传递消息或执行简单的任务——您将任务放入队列,供其他进程处理。我还简要描述了一些示例,如图像处理。

总结 🎯

本节课中我们一起学习了构成我们工作流的各个组件,一个应用程序将如何被组装起来,以及它将如何协同工作。希望您现在对我们将要使用的所有部分、应用程序的组装方式及其工作模式有了扎实的理解。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P9:09_01_02:引言_2

在本节课中,我们将学习如何将一个Flask应用与Celery任务队列集成,以实现异步任务处理。我们将涵盖从基础配置到启动完整工作流的全过程,并探讨在同步代码中嵌入异步任务的常见模式。


使用Flask应用配置Celery可能有些复杂。

但我们将了解如何使这个过程变得非常直接,如何创建一些任务,并使它们与Celery协同工作。

我们将启动整个流程:启动Celery,启动RabbitMQ,并观察它们是如何协同工作的。我们还将启动应用程序本身。

然后,我们将探讨在处理同步任务时的一些可能性,例如你可能看到的某些模式。在这些模式中,一段同步代码(例如处理HTTP请求的代码)会尝试执行一些工作,然后将这些工作发送给异步任务处理。我们将看看如何将这些部分组合在一起。

我们将再次尝试保持整个过程非常简单明了。


上一节我们介绍了课程的整体目标,本节中我们来看看具体的实施起点。

以下是配置Flask与Celery协同工作的核心步骤概述:

  1. 安装必要的依赖:这通常包括 FlaskCelery 库。
  2. 配置消息代理:例如,设置并启动 RabbitMQ 作为Celery的任务消息队列。
  3. 创建Flask应用:初始化一个基本的Flask应用。
  4. 初始化Celery实例:在Flask应用中配置并创建Celery客户端。
  5. 定义异步任务:编写具体的函数,并使用 @celery.task 装饰器将其声明为Celery任务。
  6. 在视图函数中调用任务:在Flask处理HTTP请求的同步代码中,调用上一步定义的异步任务。
  7. 启动服务:分别启动Flask开发服务器、Celery worker进程以及消息代理。

通过以上步骤,我们可以将耗时的操作从直接的HTTP请求响应循环中剥离出来,交给Celery在后台异步执行,从而提升Web应用的响应速度和吞吐量。

本节课中我们一起学习了集成Flask与Celery的基本概念和流程概要。我们了解到,这种架构的核心在于利用消息队列(如RabbitMQ)解耦Web请求与任务执行。从下一节开始,我们将逐步实现这个架构的每一个部分。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P10:在Flask中配置Celery 🚀

在本节课中,我们将学习如何在Flask应用中配置Celery。Celery是一个分布式任务队列,常用于处理后台任务。我们将一步步讲解配置过程,确保Flask应用能与Celery协同工作。

概述

我们将配置一个Flask应用,使其能够使用Celery处理异步任务。这个过程涉及初始化Celery应用、配置消息代理(如RabbitMQ),并确保Flask的应用上下文能正确传递给Celery任务。

配置步骤详解

上一节我们介绍了Celery的基本概念,本节中我们来看看如何在Flask项目中具体配置它。

初始化Celery应用

首先,我们需要创建一个Celery应用实例,并将其与Flask应用关联。以下是关键步骤:

以下是初始化Celery应用的核心代码:

from celery import Celery

def make_celery(app):
    celery = Celery(
        app.import_name,
        broker=app.config['CELERY_BROKER_URL']
    )
    celery.conf.update(app.config)
    return celery

这段代码定义了一个函数make_celery,它接收一个Flask应用实例作为参数。函数内部创建了一个Celery实例,其名称与Flask应用相同,并从Flask配置中获取消息代理的URL。最后,它将Flask的配置更新到Celery实例中。

配置Flask应用

接下来,我们需要在Flask应用工厂函数中创建并配置Celery。

以下是Flask应用工厂函数中的配置部分:

from flask import Flask

def create_app():
    app = Flask(__name__)
    # 配置Celery的消息代理URL,这里使用RabbitMQ
    app.config['CELERY_BROKER_URL'] = 'amqp://localhost:5672'

    # 初始化Celery
    celery = make_celery(app)
    app.celery = celery

    return app

在这段代码中,我们首先创建了一个Flask应用实例,并设置了Celery所需的消息代理URL。这里使用的是RabbitMQ,运行在本地主机的5672端口,并采用AMQP协议。然后,我们调用之前定义的make_celery函数来创建Celery实例,并将其附加到Flask应用上,以便在其他地方使用。

创建独立的Celery启动文件

由于Celery需要作为一个独立的进程运行,我们通常需要创建一个单独的启动文件。

以下是启动Celery工作进程的脚本示例:

# make_celery.py
from main import create_app

app = create_app()
celery = app.celery

if __name__ == '__main__':
    celery.start()

这个文件从主应用模块导入create_app函数,创建Flask和Celery应用实例。当直接运行此脚本时,它会启动Celery工作进程,准备执行任务。

总结

本节课中我们一起学习了在Flask应用中配置Celery的完整流程。我们首先初始化了Celery应用并将其与Flask绑定,然后配置了基于RabbitMQ的消息代理,最后创建了独立的Celery进程启动文件。理解这些配置步骤是构建能够处理异步任务的可扩展Web应用的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P11:11_01_06_将Celery与RabbitMQ连接 🚀

在本节课中,我们将学习如何将Celery任务队列与RabbitMQ消息代理连接起来。我们将从检查环境开始,逐步完成依赖安装、应用启动和连接验证,并会指出在此过程中可能遇到的常见问题及其解决方法。

环境检查与准备

上一节我们介绍了Celery和RabbitMQ的基本概念,本节中我们来看看如何在实际环境中建立连接。首先,需要确认RabbitMQ服务正在运行。

我当前有一个运行RabbitMQ的环境。让我们查看一下系统类型。系统是Debian 11,这没有问题。在这个Debian 11系统中,我们已经运行了RabbitMQ。让我们再次确认。

我将检查所有进程,并查找RabbitMQ。这是检查RabbitMQ是否运行的好方法。可以看到系统中已经运行和执行了许多不同的进程。这是连接Celery的前提条件。

接下来,我们需要检查Python版本。和往常一样使用Python时,我们需要再次确认版本。我们使用的是Python 3.12。我将使用Python3并通过venv模块创建一个.venv文件夹。

Python 3正在为我创建该文件夹。现在让我们激活这个虚拟环境。这创建了一个虚拟环境,它是一个子目录,所有Python依赖项都将安装在这里。你会看到提示符已经改变,这是Python的标准做法。

安装依赖与启动应用

现在我们需要安装项目依赖。我们之前已经见过requirements.txt文件。我将运行pip install -r requirements.txt命令。等待安装完成。

安装完成后,我们需要检查是否安装了Celery命令行工具。我们确实安装了Celery。接下来,我们需要进入app目录。点击app文件夹,让我们查看make_celery文件。我们之前见过它,就是这个文件。我们将使用它和Celery来启动Celery应用。这是一个必要步骤。

我将清空一些空间,以便查看我们将要看到的内容。我们将运行命令:celery -A make_celery worker --loglevel=info。如果你不在正确的目录中,就会遇到这类错误。如果我们进入app目录,然后找到make_celery文件,就应该能正常运行,没有问题。

我们运行这些命令,可能会发现一些问题。这里发生了什么?我们的应用遇到了问题,其中一个依赖项(requests)没有安装。这是你在尝试连接Celery时可能遇到的另一个问题。因为Celery在运行时会加载那个Python应用,你只需要确保你的requirements.txt文件中列出的所有依赖都已安装。Python包管理有时会比较棘手。但这并不是大问题。

我们需要确保requests已安装。现在看起来已经准备就绪。我们已经看到了一些可能出错的地方。让我们再试一次。我将使用命令celery -A make_celery worker --loglevel=info启动Celery。

连接验证与任务队列

现在Celery已经启动。让我们看看这里发生的一些事情。在最顶部,我们获得了一些信息。这是我们的应用名称,记住是flask_queue。这非常重要,因为它确保我们连接到了正确的队列。我们正在连接到运行在本地主机的RabbitMQ实例。

我们还获得了一些并发信息。那么有哪些队列呢?队列就在这里,它们是async_parse_exploitsasync_send_email。我们稍后会看到它们。这些队列基本上来自我的Flask应用,我在那里定义了它们。这很有用,因为我可以确保一切正常,并且Celery正确加载了我的Flask应用,完全理解这些任务来自哪里。

你可以在这里看到Celery已经准备就绪。当我们开始与这些任务交互时,我们将在这里看到一些活动。

总结

本节课中我们一起学习了将Celery与RabbitMQ连接的全过程。我们从检查RabbitMQ服务状态开始,然后创建并激活Python虚拟环境,安装项目依赖,最后启动Celery worker并验证其成功连接到RabbitMQ。我们还探讨了可能遇到的常见问题,如依赖缺失和路径错误,并提供了相应的解决方案。成功连接后,Celery worker就能开始处理来自Flask应用定义的异步任务队列了。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P12:12_01_07_在Flask中定义Celery任务 🚀

在本节课中,我们将学习如何在Flask应用中定义Celery任务。我们将探讨两种定义任务的方式:一种是简单的“发送邮件”示例,另一种是更复杂的、用于解析网页漏洞信息的真实世界示例。通过本节内容,你将理解如何使用Celery的shared_task装饰器来创建后台任务,以及如何将任务放入队列进行异步处理。

定义Celery任务的不同方式

在Flask应用中结合Celery定义任务有多种方法。接下来,我们将详细展示本应用中已经使用过的方式。

模拟发送邮件任务 📧

首先,我们来看一个“发送邮件”的示例。在这个例子中,我们将模拟发送邮件的过程,而不是真正发送。让我们看看它是如何工作的。

以下是一个同步函数,它将调用我们的异步send_email任务。其中的delay()方法是关键,它能确保任务被放入后台,进入Celery队列,并在稍后被处理。

@app.route('/send_email')
def send_email_sync():
    # 调用异步任务
    send_email.delay()
    return "邮件发送请求已提交"

我们使用@shared_task装饰器来定义这个Celery任务。使用shared_task主要是为了方便。如果你想深入了解如何为生产环境配置Celery,可能不会使用shared_task,因为它本质上只是简单地连接本地现有的RabbitMQ(或第一个可用的消息代理)并开始工作。

在这个任务函数中,我们将接收来自前一个函数的参数,然后简单地返回一个成功状态。这个处理过程非常简单直接。

from celery import shared_task

@shared_task
def send_email():
    # 这里可以放置模拟发送邮件的逻辑
    # 例如:记录日志、调用第三方API等
    # 本例中我们仅模拟处理
    print("模拟发送邮件中...")
    # 模拟处理完成
    return {"success": True}

在这里,你可以根据需要进行任何额外的处理。这只是一个基础示例。

解析漏洞报告的复杂任务 🛡️

上一节我们介绍了一个简单的后台任务。本节中,我们来看看一个更复杂的、来自真实世界的操作示例:解析漏洞报告。

这个任务将从exploit-db.com网站解析漏洞信息。该网站提供的HTML结构比较粗糙,我们需要从中提取数据。最后,任务将返回一个任务ID或解析出的漏洞列表。

让我们看一下这个使用shared_task定义的任务。

@shared_task
def parse_exploits():
    import requests
    from bs4 import BeautifulSoup

    url = "https://www.exploit-db.com/"
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    exploits = []
    # 假设漏洞信息在特定的表格中
    tables = soup.find_all('table')
    for table in tables:
        rows = table.find_all('tr')
        for row in rows:
            # 这里需要根据实际的粗糙HTML结构编写解析逻辑
            # 例如提取每个行的列数据
            cols = row.find_all('td')
            if cols:
                exploit_data = [col.text.strip() for col in cols]
                exploits.append(exploit_data)
    # 返回解析结果
    return exploits

我们将请求目标URL,使用BeautifulSoup进行解析,抓取内容,并查看表格和行以捕获信息。由于HTML结构粗糙,提取这些信息需要一些技巧。

定义在这些共享任务中的所有操作,都是你可以执行的示例。它们可以是“触发后不管”的任务,也可以是你希望稍后捕获信息的任务。在本例中,我直接返回了漏洞信息。

你可以将Celery连接到后端数据库,以便稍后存储处理过的信息。你也可以在这里尝试让事情发生。在本例中,为了使内容超级简单,我只是返回漏洞信息。接下来我们将看看它是如何工作的。

总结

本节课中,我们一起学习了在Flask应用中定义Celery任务的两种主要方式。我们从一个简单的模拟发送邮件任务开始,了解了如何使用delay()方法将任务推入后台队列。接着,我们探讨了一个更复杂的真实世界示例,即解析粗糙的HTML页面以提取漏洞信息。通过使用@shared_task装饰器,我们可以方便地创建异步任务,无论是进行简单的操作还是复杂的网页抓取与数据处理。理解这些模式是构建高效、可扩展后台处理系统的关键。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P13:Flask中的即发即弃任务

概述

在本节课程中,我们将学习如何在Flask应用中实现“即发即弃”类型的异步任务。我们将通过一个具体的例子,演示如何发送一个HTTP请求,该请求会触发一个后台长时间运行的任务,而不会阻塞主请求的即时响应。

环境准备与启动

首先,我们需要启动两个应用程序。在终端中,我们首先启动saraly应用。接着,我们在另一个端口启动Flask应用。

以下是启动应用的命令:

# 启动saraly应用
python saraly_app.py

# 启动Flask应用(假设运行在端口5000)
flask run --port=5000

启动后,Flask应用将在本地主机的5000端口运行。我们暂时不在浏览器中打开它。

发送异步请求

现在,我们将使用curl命令向Flask应用发送一个POST请求。这个请求将模拟触发一个后台任务。

我们将发送以下JSON数据:

{
  "email": "johndoe@example.org",
  "subject": "Hi from saraly",
  "body": "A test"
}

请求的目标端点是http://localhost:5000/email

执行以下curl命令:

curl -X POST http://localhost:5000/email \
  -H "Content-Type: application/json" \
  -d '{"email":"johndoe@example.org", "subject":"Hi from saraly", "body":"A test"}'

观察请求响应

执行curl命令后,你会发现终端立即返回,并且没有收到任何响应内容。这表明请求被快速处理并返回,没有等待。

然而,在saraly应用的后台,一个耗时任务正在执行。我们在代码中明确设置了5秒的休眠来模拟这个长时间处理。

理解即发即弃机制

为什么主请求没有阻塞5秒呢?让我们来分析其工作原理。

上一节我们介绍了基本的请求-响应模型,本节中我们来看看异步任务处理。

关键在于,Flask应用在收到请求后,并没有自己执行耗时操作。它执行了以下步骤:

  1. 立即返回一个“成功”响应给客户端。
  2. 将需要处理的真实任务(如发送邮件)及其数据放入一个消息队列(例如RabbitMQ)。
  3. 独立的saraly应用作为“工作者”,从消息队列中取出任务并执行。

这个过程就像一个“即发即弃”的操作:主程序发出指令后就不再关心其执行过程,由后台系统负责完成。

验证后台任务

虽然curl请求立即返回,但我们可以验证后台任务确实执行了。

如果你查看saraly应用的后台日志或输出,大约5秒后,你会看到类似以下的信息:

Success: true
Processing started...
Task succeeded.

这证实了耗时5秒的任务已被saraly应用成功处理。

核心概念总结

以下是实现“即发即弃”异步任务的核心组件和工作流程:

  1. 消息队列:作为任务的中转站,解耦请求发送者和任务执行者。常用工具有RabbitMQRedisApache Kafka

    # 伪代码示例:将任务发布到队列
    channel.basic_publish(exchange='', routing_key='task_queue', body=json.dumps(task_data))
    
  2. 生产者:即Flask应用。它接收HTTP请求,创建任务消息,并将其发布到消息队列,然后立即响应客户端。

    # 伪代码示例:Flask路由处理函数
    @app.route('/email', methods=['POST'])
    def send_email():
        task_data = request.get_json()
        # 将task_data发布到消息队列
        publish_to_queue(task_data)
        return jsonify({"status": "accepted"}), 202  # 202 Accepted 状态码表示请求已接受处理
    
  3. 消费者:即saraly应用。它作为一个独立进程运行,持续监听消息队列。当有新任务时,它取出任务并执行其中的耗时逻辑。

    # 伪代码示例:消费者处理任务
    def callback(ch, method, properties, body):
        task_data = json.loads(body)
        # 执行耗时操作,例如模拟处理5秒
        time.sleep(5)
        process_email(task_data['email'], task_data['subject'], task_data['body'])
        print("Task succeeded.")
    

总结

本节课中我们一起学习了如何在Web开发中处理耗时任务。通过将Flask作为生产者、消息队列作为中间件、独立的工作者应用作为消费者,我们构建了一个“即发即弃”的异步处理系统。这种模式确保了Web服务器能够快速响应客户端请求,同时将繁重的计算或I/O操作卸载到后台,极大地提升了应用的可伸缩性和用户体验。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P14:从异步任务中检索值

概述

在本节课中,我们将学习如何从异步任务中检索处理结果。之前我们已经了解了如何发起“发射后不管”类型的请求,本节我们将探讨如何获取异步处理完成后的具体数据。

从异步任务中检索结果

上一节我们介绍了如何发起异步请求。本节中我们来看看,如果我们确实需要处理结果,应该怎么做。

我们可以修改之前的 parse_exploits 端点。与返回空内容不同,我们将返回一个任务ID。这个ID可以在之后用于查询处理结果。

需要注意的是,这个ID在系统内部与处理信息相关联。信息会被存储在后端存储中。虽然本应用没有配置具体的后端存储(因为那会涉及更复杂的设置),但本节内容将为你提供一个坚实的理解和基础,让你能够在此基础上构建存储功能,并理解其工作原理。

让我们开始操作。我们将向 parse_exploits 端点发送一个POST请求。这个请求看起来更简单,因为它不需要提交负载数据,我们只需发送POST请求来触发任务。

以下是具体步骤:

  1. 我们使用 curl 命令发送POST请求。
  2. 命令目标是 localhost:5000/parse_exploits
  3. 执行后,我们将获得一个任务ID。

运行命令:curl -X POST http://localhost:5000/parse_exploits

执行后,我们几乎立即获得了一个任务ID。虽然只花了一秒钟,但系统在后台已经完成了处理:它向外部网站提交了请求,进行了数据解析,并发现CV编号 2009-4186 关联到了一个漏洞利用程序。

在后台,处理过程是这样的:系统会构建漏洞利用列表,并将找到的漏洞利用ID和CV ID配对,然后追加到一个列表中。

理解任务ID的用途

这就是进行更多处理的方式。你会得到一个特定的任务ID,例如本例中的 077F6。这个ID是关联工作任务、处理信息和在请求被处理时所捕获的所有内容的关键。

返回这个ID是一种关联工作负载和信息的方法。

总结

本节课中我们一起学习了如何从异步任务中检索值。关键点在于,通过让异步端点返回一个任务ID,我们能够在之后查询到该任务的处理结果。这为构建能够跟踪和返回异步操作结果的系统奠定了基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P15:15_01_10_总结 📚

在本节课中,我们将对之前关于在Flask应用中集成RabbitMQ和Celery的内容进行总结,梳理核心概念,并展望这些技术如何构建强大、可扩展的系统。

课程内容回顾

上一节我们介绍了任务队列中的错误处理。本节中,我们来看看整个模块的要点总结。

我们完成了与Flask中RabbitMQ和Celery相关的所有内容,并使其协同工作。我们尝试理解了任务是什么,以及它们如何协同工作。

核心概念与要点

以下是关于Celery,我们需要关注的一些要点:

  • 任务本质:理解了任务作为异步执行单元的概念。
  • 错误处理:探讨了当Celery任务中出现错误时会发生什么。有时这些错误信息并不明确。
  • 故障排查基础:这部分知识非常有用,因为当系统出现故障时,你将具备基础知识和一个良好的起点来尝试修复问题,并最终使其运行得更好。

技术价值与应用前景

你现在能够使用Python和RabbitMQ这类消息代理进行的工作,将使你能够创建非常强大的系统。

这些系统可以应用于常规的数据工程任务。

同时,也可以考虑将其用于机器学习和数据科学领域,以及在数据产生和传入时进行数据维护。

我认为这是理解计算机科学经典概念的一个非常好的方式,即我们试图设计这些架构系统,以实现可扩展性。

它将允许你创建非常健壮的基础设施。

这种基础设施将具备弹性,以便你可以接入更多组件,并以更高效的方式完成更多工作。

Python本身并不擅长轻松处理所有异步工作。因此,依赖队列这样的机制无疑是正确的选择。

总结与展望

本节课中,我们一起学习了在Flask框架中集成RabbitMQ和Celery的实践。我们很高兴能够演示Flask框架、Celery和RabbitMQ结合的一些可能性。这为你构建可扩展、健壮的异步处理系统奠定了坚实的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P16:MySQL概述

概述

在本节课程中,我们将学习与MySQL数据库进行交互的几种高效、非传统方法。这些方法侧重于利用现有系统工具和编程语言标准库,快速实现数据查询、导出和处理,特别适合在资源有限或需要快速原型开发的场景下使用。

使用“黑客式”方法快速交互

上一节我们介绍了MySQL的基本概念,本节中我们来看看如何利用系统自带工具和标准库,以更灵活、更快速的方式与MySQL进行交互。

除了使用官方的MySQL SDK或图形化界面(GUI)外,还存在一种更偏向传统Linux“黑客”风格的数据工程方法。在某些情况下,你可能需要非常快速地完成某项任务。例如,假设你只有MySQL、Python和Bash环境(这在虚拟机或容器中很常见),并且你希望在不陷入复杂的包管理、反复安装卸载依赖的情况下构建解决方案。幸运的是,使用MySQL,你可以非常迅速地开展工作。

将查询结果导出到文件

以下是几种核心的快速操作方法。

1. 导出查询结果为CSV文件

你可以将数据库中的特定查询结果直接导出到磁盘文件。例如,执行一个查询并将结果输出为CSV格式文件。一旦数据保存在CSV文件中,我们就可以使用Linux命令行工具或Python等传统工具进行后续处理。

代码示例:将查询结果导出为CSV

mysql -u username -p database_name -e "SELECT * FROM your_table;" > output.csv

2. 利用Python标准库构建Web服务

需要特别指出的是,Python标准库本身就是一个功能极其丰富的集合,你无需依赖第三方库就能使用Python完成许多任务,这是它的优势之一。标准库内置了各种功能,甚至包括一个简单的Web服务模块。

假设你需要快速构建一个Web服务来处理数据库中的数据,你可以这样做:先执行查询并将结果导出到磁盘,然后编写一段非常简单的Python代码来运行一个Web服务,读取那个CSV文件,最后通过curl命令来获取处理结果。这种方法非常适合黑客马拉松,或者与实验室的科学家合作时需要快速搭建原型的情况。

代码示例:使用Python标准库创建简易Web服务

# 这是一个简化的示例框架
import http.server
import socketserver

class MyHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        # 在此处添加读取CSV文件并返回数据的逻辑
        self.send_response(200)
        self.end_headers()
        # ... 返回CSV数据 ...

PORT = 8000
with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
    httpd.serve_forever()

3. 导出并操作整个数据库

另一种值得一提的“黑客式”MySQL用法是导出整个数据库。这也是一种令人兴奋的工作方式:你可以使用mysqldump命令获取大量SQL格式的数据,然后利用一些Linux工具(如grepsort等)来解析和处理这些数据,再进行其他操作。

代码示例:导出数据库并用Linux工具处理

# 导出整个数据库
mysqldump -u username -p database_name > dump.sql
# 使用grep查找特定内容
grep "some_pattern" dump.sql

总结

本节课中我们一起学习了与MySQL交互的几种快速、灵活的方法。核心在于利用系统自带工具(如命令行、mysqldump)和编程语言标准库(如Python),绕过复杂的包管理,直接对数据进行操作。很多时候,我们可能总想安装各种功能强大的库和工具,但对于尝试解决一个快速、临时的问题而言,首先使用这些传统工具,看看它们能带你走多远,然后再决定是否需要引入更重量级的工业级解决方案,这通常是一个有价值的起点。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P17:17_01_04_从终端使用MySQL 🖥️➡️🗄️

在本节课中,我们将学习如何从终端直接连接和操作MySQL数据库。我们将从登录数据库开始,逐步完成创建数据库、定义表结构、插入数据以及查询数据等核心操作。通过终端操作,你可以更直接地理解数据库命令的执行过程。

登录MySQL

首先,我们需要登录到MySQL服务器。我们将以root用户身份登录,这是新安装MySQL后的默认管理员账户。

以下是登录命令:

mysql -u root

执行此命令后,你将进入MySQL的命令行提示符。

修改用户密码 🔐

成功登录后,一个常见的后续步骤是修改root用户的密码,以增强安全性。

以下是修改密码的SQL命令:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Db_password';

请将'Db_password'替换为你想要设置的新密码。

创建数据库 🗃️

MySQL安装后默认没有用户数据库,因此我们需要创建一个。这为后续存储数据提供了空间。

以下是创建数据库的命令:

CREATE DATABASE my_demo;

此命令创建了一个名为my_demo的数据库。

选择数据库

创建数据库后,我们需要明确指定后续操作将在哪个数据库中进行。

以下是选择(使用)数据库的命令:

USE my_demo;

执行此命令后,终端提示符通常会发生变化,表明你现在已连接到my_demo数据库。

创建数据表 📊

数据库本身是空的,我们需要在其中创建表来存储数据。表类似于电子表格,有固定的列(字段)和数据类型。

以下是创建一个简单用户表的命令:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);

这段代码创建了一个名为users的表,包含三个字段:

  • id:整数类型,作为主键且自动递增。
  • name:可变长度字符串,最大100个字符。
  • email:可变长度字符串,最大100个字符。

向表中插入数据 ➕

表结构定义好后,我们就可以向其中添加数据了。

以下是向users表插入两条示例数据的命令:

INSERT INTO users (name, email) VALUES
('John', 'john@gmail.com'),
('Jane', 'jane@yahoo.com');

每条INSERT语句都会向表中添加一行数据。这里我们插入了两个用户:John和Jane。

查询数据 🔍

数据插入后,我们可以使用查询语句来检索和查看表中的数据。这是与数据库交互最常用的操作。

以下是查询users表中所有数据的命令:

SELECT * FROM users;

执行此命令后,终端将返回users表中的所有行和列,即我们刚刚插入的John和Jane的信息。

总结

本节课中我们一起学习了从终端操作MySQL数据库的完整基础流程。我们从登录MySQL开始,依次完成了修改密码、创建数据库、选择数据库、定义表结构、插入数据以及最终查询数据。通过终端直接操作,没有任何图形界面的阻隔,能够帮助你更牢固地理解每条SQL命令的作用和数据库的核心工作流程。掌握这个流程是进行更复杂数据工程任务的重要基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P18:归档与删除数据库

在本节课程中,我们将学习MySQL数据库管理中的三个核心操作:备份数据库、在数据库间复制数据以及安全地删除数据库和表。掌握这些操作是进行数据工程和模型部署前数据准备的重要基础。

备份数据库

上一节我们介绍了数据库的基本概念,本节中我们首先来看看如何为现有数据库创建备份。在进行任何重大数据操作前备份数据库是一个必须遵循的良好实践。

以下是使用 mysqldump 命令进行完整备份的步骤:

  1. 打开终端。
  2. 输入命令:mysqldump -u root -p my_demo > backup_my_demo.sql
    • -u root 表示以root用户连接。
    • -p 会提示输入密码。
    • my_demo 是要备份的数据库名称。
    • > backup_my_demo.sql 将备份输出重定向到一个名为 backup_my_demo.sql 的文件中。
  3. 根据提示输入数据库密码。

备份完成后,建议立即验证备份文件是否有效且不为空。可以使用以下命令检查文件大小和内容:

  • 检查文件大小:ls -lh backup_my_demo.sql
  • 查看文件前几行内容:head backup_my_demo.sql
  • 查看前100行内容:head -n 100 backup_my_demo.sql

验证时,你可能会看到类似 DROP TABLE IF EXISTSCREATE TABLE 的SQL语句,这表明备份文件包含了数据库的完整结构和数据。

在数据库间复制数据

完成备份后,我们可以安全地对数据库进行操作。接下来,我们将学习如何将数据从一个数据库复制到另一个新数据库,这在数据归档或创建实验环境时非常有用。

以下是复制数据的步骤:

  1. 登录MySQL:mysql -u root -p,然后输入密码。
  2. 查看所有数据库确认目标数据库存在:SHOW DATABASES;
  3. 创建一个新数据库:CREATE DATABASE my_demo_2;
  4. 切换到新数据库:USE my_demo_2;
  5. 通过查询旧数据库的数据来创建新表并复制数据:
    CREATE TABLE users_2 AS SELECT * FROM my_demo.users;
    
    这条SQL语句从 my_demo 数据库的 users 表中选取所有数据,并在当前数据库(my_demo_2)中创建一个名为 users_2 的新表来存放这些数据。
  6. 操作完成后,可以退出并重新登录,使用 SHOW DATABASES; 命令确认新数据库 my_demo_2 已创建成功。

这个过程演示了如何在MySQL实例内部轻松地迁移或复制数据。

删除数据库和表

最后,当我们完成实验或需要清理时,需要安全地删除数据库对象。请注意,删除操作是不可逆的,务必谨慎执行。

以下是删除表和数据库的步骤:

  1. 确保你正在使用正确的数据库:USE my_demo_2;
  2. 删除指定的表:DROP TABLE users_2;
  3. 删除整个数据库:DROP DATABASE my_demo_2;

DROP DATABASE 是一个极其危险的命令,它会立即永久删除数据库及其所有内容。在本例中,因为我们提前进行了备份并特意创建了这个实验数据库,所以可以安全地执行删除。

执行删除后,再次使用 SHOW DATABASES; 命令,你会发现 my_demo_2 数据库已不存在。这正是我们在第一步进行备份的重要性体现——即使误删,也可以从备份文件中恢复。

总结

本节课中我们一起学习了MySQL数据库管理的三个关键操作。我们首先介绍了如何使用 mysqldump 命令对数据库进行完整备份,这是所有重要操作前的安全网。接着,我们探讨了如何通过 CREATE TABLE ... AS SELECT ... 语句在数据库之间复制数据,用于归档或创建测试环境。最后,我们了解了如何使用 DROP TABLEDROP DATABASE 命令进行清理,并强烈强调了在执行删除前进行备份的必要性。掌握这些操作能让你在数据工程实践中更加自信和安全地管理数据。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P19:导入外部数据库Sakila 🗄️

在本节课中,我们将学习如何导入并使用一个名为Sakila的MySQL示例数据库。这是一个经典的参考数据库,常用于学习和测试数据库操作。我们将从下载数据库文件开始,逐步完成在MySQL终端中的导入过程,并学习一些基础的查询操作来探索数据库的结构和数据。

概述与准备工作

首先,我们需要获取Sakila示例数据库。该数据库的官方文档可以从MySQL网站获得。拥有一个参考数据库对于理解和测试特定数据库的操作非常有帮助。

以下是获取数据库文件的步骤:

  • 访问官方文档页面:dev.mysql.com/doc/index-other.html
  • 从该页面下载Sakila数据库文件包。

下载的文件包通常包含三个文件:

  • Schema文件:用于创建数据库表结构。
  • Data文件:包含要插入到表中的实际数据。
  • .MWB文件:专用于MySQL Workbench图形化工具,本教程中我们不需要使用它。

导入数据库到MySQL

上一节我们准备好了数据库文件,本节中我们来看看如何在MySQL命令行终端中执行导入。

首先,我们打开终端,导航到存放数据库文件的目录,并查看文件。可以看到数据文件通常比结构文件大得多。

ls -lh sakila*

接下来,我们需要登录MySQL。使用以下命令,并根据提示输入密码:

mysql -u root -p

成功登录MySQL后,就可以导入数据库了。导入分为两步:首先创建表结构,然后填充数据。我们需要使用SOURCE命令来执行对应的SQL文件。请注意,你需要将/path/to/替换为文件在你电脑上的实际路径。

SOURCE /path/to/sakila-schema.sql;
SOURCE /path/to/sakila-data.sql;

执行过程可能需要一些时间。完成后,我们可以切换到sakila数据库,并查看其中包含的所有表,以确认导入成功。

USE sakila;
SHOW FULL TABLES;

探索数据库结构与数据

现在数据库已准备就绪,我们可以开始探索它。充分利用官方文档中的结构图和表定义是理解数据库设计的关键,这对于数据库工程师或数据工程师规划自己的数据库非常有帮助。

首先,我们可以使用DESCRIBE命令来查看特定表的结构。例如,查看actor表有哪些列及其数据类型:

DESCRIBE actor;

了解表结构后,就可以进行数据查询了。一个良好的习惯是,在不确定查询结果大小时,使用LIMIT子句限制返回的行数。

SELECT * FROM actor LIMIT 5;

我们可以尝试更复杂的操作,例如表连接(JOIN)。以下是一个示例查询,它连接了多个表,以获取电影标题、租金、以及出演该电影的演员姓名。

SELECT f.title, f.rental_rate, a.first_name, a.last_name
FROM film f
INNER JOIN film_actor fa ON f.film_id = fa.film_id
INNER JOIN actor a ON fa.actor_id = a.actor_id
LIMIT 10;

此外,聚合函数如COUNT()可以帮助我们快速了解数据规模。

SELECT COUNT(*) AS total_films FROM film;

总结

本节课中我们一起学习了如何导入并探索Sakila示例数据库。我们完成了从下载文件、在MySQL终端中导入,到使用DESCRIBESELECTJOINCOUNT等基本命令来了解数据库结构和数据的全过程。像Sakila这样拥有完善文档的示例数据库,是增强数据库操作技能的绝佳工具,它比随意找一个未知数据库进行练习更有指导意义。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P20:修改Sakila数据库 🗄️

在本节课中,我们将学习如何对一个名为Sakila的示例电影数据库进行扩展和修改。我们将通过创建新表、插入数据、查询数据以及最终清理实验性数据等一系列操作,来模拟一位导演为电影库添加后期制作笔记的场景。这个过程将帮助你理解基本的数据库操作流程。

连接到数据库并查看现有结构

首先,我们需要登录到MySQL数据库系统,并查看其中包含的数据库。Sakila数据库是一个关于电影行业的示例数据库,其中包含了演员、电影等信息。

以下是连接到数据库并查看其内容的步骤:

  1. 使用命令 mysql -u root -p 登录MySQL。
  2. 输入密码后,使用 SHOW DATABASES; 命令查看所有数据库,确认 sakila 数据库存在。
  3. 使用 USE sakila; 命令切换到该数据库。
  4. 使用 SHOW TABLES; 命令查看数据库中的所有表,例如 actorcategoryfilm 等。

扩展数据库:创建新表

上一节我们查看了数据库的现有结构,本节中我们来看看如何扩展它。假设我们是一位导演,希望为电影库中的影片添加后期制作笔记。为此,我们需要创建一个新表来存储这些信息。

我们将创建一个名为 director_notes 的表,它包含以下字段:

  • note_id:笔记的唯一标识,使用 INT AUTO_INCREMENT PRIMARY KEY 定义,可自动递增。
  • film_id:关联的电影ID,使用 INT 类型。
  • director_note:导演的笔记内容,使用 TEXT 类型,允许存储较长的自由文本。
  • edit_date:编辑日期,使用 DATE 类型。

创建该表的SQL语句如下:

CREATE TABLE director_notes (
    note_id INT AUTO_INCREMENT PRIMARY KEY,
    film_id INT,
    director_note TEXT,
    edit_date DATE
);

执行此命令后,新表 director_notes 就被创建了。

向新表中插入数据

表创建好后,里面还没有数据。为了使它变得有用,我们需要向其中插入一些记录。这里我们将模拟为两部电影添加导演笔记。

以下是插入数据的SQL语句示例:

INSERT INTO director_notes (film_id, director_note, edit_date)
VALUES
(1, 'Fix the sound in minute 20', '2023-11-01'),
(2, 'Shorten the battle scene', '2023-11-02');

这条语句向 director_notes 表插入了两条记录,分别为ID为1和2的电影添加了笔记和编辑日期。

查询与关联数据

仅仅查看笔记表本身信息有限。通常,我们需要将新表与原有的电影表关联起来,以获得更有意义的视图,例如看到电影标题对应的导演笔记。

我们可以使用 JOIN 语句来关联 film 表和 director_notes 表。

以下是一个查询示例,它选取电影标题、导演笔记和编辑日期:

SELECT f.title, dn.director_note, dn.edit_date
FROM film f
LEFT JOIN director_notes dn ON f.film_id = dn.film_id;

执行此查询后,结果会显示所有电影,但只有我们添加过笔记的两部电影(如“A Dinosaur”和“A Goldfinger”)会显示具体的笔记内容。这种查询结果非常适合构建一个供导演查看所有影片及其待办笔记的应用程序界面。

清理实验环境

假设上述操作只是一个数据副本上的实验,现在我们希望清理这个实验性的表。这可以通过删除表来实现。

删除表的SQL命令非常简单:

DROP TABLE director_notes;

执行此命令后,director_notes 表将从数据库中移除。再次使用 SHOW TABLES; 命令可以确认该表已被成功删除。

总结

本节课中我们一起学习了如何对一个现有的Sakila数据库进行修改和扩展。我们完成了从登录数据库、查看结构,到创建新表、插入数据,再到关联查询,最后清理实验环境的完整流程。这个过程涵盖了数据库操作的基本环节,是熟悉示例数据库和练习SQL语句的好方法。建议你在自己的环境中尝试类似的扩展操作,以加深理解。

大型语言模型实践:P21:使用MySQL的Bash管道 🛠️💾

概述

在本节课中,我们将学习如何通过Bash Shell与MySQL数据库进行交互。这是一种高效的数据工程技术,它结合了SQL的强大功能和Shell脚本的灵活性,无需依赖特定编程语言即可完成数据操作。


连接到MySQL并查看数据库 🔌

首先,我们需要连接到MySQL数据库系统。使用以下命令,以root用户身份登录:

mysql -u root -p

登录后,我们可以查看当前有哪些数据库。输入以下SQL命令:

SHOW DATABASES;

执行后,你会看到数据库列表。在本例中,我们将使用名为 sequila 的数据库,其中包含一个演员电影数据库。


查询数据并输出到文件 📤

上一节我们连接到了数据库,本节中我们来看看如何执行查询并将结果保存到文件中。

在MySQL中,我们可以执行一个简单的查询来查看actor表的前5条记录:

SELECT * FROM actor LIMIT 5;

但更有趣的是,我们可以直接将查询结果导出到磁盘上的一个文件。为此,我们使用 INTO OUTFILE 语句:

SELECT * FROM actor INTO OUTFILE ‘/coder/project/actors.txt‘;

这条命令会将actor表的所有数据导出到指定路径的actors.txt文件中。


在Shell中处理导出的数据 🐚

现在我们已经将数据导出到文件,可以退出MySQL,在Shell环境中对数据进行进一步操作。

首先,切换到文件所在的目录:

cd /coder/project

然后,我们可以使用Shell命令来处理actors.txt文件。例如,使用catgrep和管道符来筛选数据:

cat actors.txt | grep Penn

这个命令会找出所有姓氏包含“Penn”的演员记录,结果显示为“Gary Penn”和“Richard Penn”。

你还可以将筛选结果写入一个新文件:

cat actors.txt | grep Penn > penn_actors.txt

之后,这个新文件penn_actors.txt可以被重新导入到MySQL的一个新表中,或者用于其他分析。

通过这种方式,我们可以在SQL中操作数据,然后利用Shell管道进行更复杂的处理,两者结合非常强大。


不登录MySQL直接导出数据 🚀

除了在MySQL内部操作,我们还可以完全不登录MySQL,直接从命令行导出数据。

使用 mysqldump 工具可以导出整个表或数据库。例如,导出sequila数据库中actor表的结构和数据:

mysqldump -u root -p sequila actor > full_actors.sql

执行后需要输入密码。这个命令会生成一个包含表结构和数据的SQL文件full_actors.sql

现在,让我们比较一下不同方式生成的文件大小:

  • actors.txt (纯数据): 约8KB
  • full_actors.sql (结构+数据): 约12KB
  • penn_actors.txt (筛选后的数据): 约4KB

我们可以看到,通过不同的方法,我们成功地对数据进行了子集划分。


使用Shell工具进行快速分析 📊

Shell还提供了许多快速分析文本数据的工具。例如,使用 wc (word count) 命令可以统计文件的行数。

统计penn_actors.txt的行数(即演员记录数):

wc -l penn_actors.txt

输出显示有2行(条记录)。

统计原始actors.txt文件的行数:

wc -l actors.txt

输出显示有200行,即总共有200位演员。

这种方法展示了Shell与数据库协同工作的巨大优势。很多时候,我们无需切换到Python或Ruby这类功能强大的编程语言,仅使用Shell进行一些操作和管道处理,就能高效地完成许多任务。


总结

本节课中,我们一起学习了如何通过Bash Shell与MySQL数据库交互。我们掌握了连接数据库、执行查询、将结果导出到文件的方法,并探索了如何在Shell中使用grepwc等命令对导出的数据进行筛选和快速分析。最后,我们还了解了如何使用mysqldump工具直接从命令行备份数据。这种结合SQL和Shell管道的工作流,为数据工程师提供了灵活而强大的数据处理能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P22:MySQL到Python标准库Web服务器 🚀

在本节课中,我们将学习如何从MySQL数据库中提取数据,并将其转换为一个简单的Web服务。整个过程将仅使用命令行工具、SQL和Python标准库完成,无需任何第三方依赖。


连接到MySQL并导出数据

首先,我们需要连接到MySQL数据库,并从中查询数据。

上一节我们介绍了课程目标,本节中我们来看看如何操作MySQL。

在终端中,使用以下命令连接到MySQL服务器:

mysql -U root -p

连接成功后,我们可以查看可用的数据库。执行以下SQL命令:

SHOW DATABASES;

结果显示存在一个名为 Sequila 的数据库,其中包含电影数据。

接下来,我们选择使用这个数据库:

USE Sequila;

为了了解数据库中有哪些表,我们执行:

SHOW TABLES;

命令会列出数据库中的所有表。

为了进行后续操作,我们将执行一个预写好的SQL查询。这个查询会从 actor 表中选择所有数据,并进行一些数据清洗以确保格式正确,最后将结果导出到一个CSV文件中。

以下是执行的SQL命令:

SELECT * FROM actor INTO OUTFILE ‘/tmp/actors.csv‘ FIELDS TERMINATED BY ‘,‘ ENCLOSED BY ‘“‘ LINES TERMINATED BY ‘\n‘;

执行完毕后,我们可以退出MySQL:

EXIT;

验证数据并准备Python环境

退出MySQL后,我们回到终端,可以验证CSV文件是否已成功创建。

使用以下命令查看文件的前几行:

head /tmp/actors.csv

这可以确认数据已正确导出。

现在,我们将使用Python创建一个Web服务来提供这个CSV数据。为了编写代码,我们需要打开一个代码编辑器。

在终端中,我们可以创建一个新的Python文件:

touch server.py

然后,在编辑器中打开这个文件进行编辑。


创建Python Web服务器

我们将编写一个简单的Python脚本,利用其内置的 http.servercsv 模块来创建一个Web服务。

以下是 server.py 文件的内容:

import http.server
import socketserver
import csv

PORT = 8080

class CSVHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header(‘Content-type‘, ‘text/html‘)
        self.end_headers()
        # 读取并发送CSV文件内容
        with open(‘/tmp/actors.csv‘, ‘r‘) as file:
            csv_reader = csv.reader(file)
            for row in csv_reader:
                self.wfile.write(f“{‘,‘.join(row)}<br>“.encode())

with socketserver.TCPServer((““, PORT), CSVHandler) as httpd:
    print(f“Serving at port {PORT}“)
    httpd.serve_forever()

代码解释如下:

  1. 我们导入了必要的模块:http.serversocketservercsv
  2. 定义了一个自定义的请求处理类 CSVHandler,它重写了 do_GET 方法。
  3. do_GET 方法中,我们设置HTTP响应头,然后打开CSV文件,逐行读取并将其作为HTML内容发送回客户端。
  4. 最后,我们启动一个TCP服务器在指定端口(例如8080)上永久运行。

保存文件后,在终端运行这个服务器:

python server.py

如果端口8080已被占用,服务器会报错。此时只需将脚本中的 PORT 变量改为其他值(如8081),然后重新运行即可。

服务器成功启动后,会打印类似 Serving at port 8081 的信息。


测试Web服务

服务器运行后,我们可以使用 curl 命令或浏览器来测试它。

在终端中,使用以下命令向服务器发送请求:

curl http://localhost:8081

命令会返回CSV文件的内容,格式化为HTML。

这个过程展示了Python标准库的强大功能。很多时候我们过于关注复杂的第三方库,但实际上,对于快速构建简单、高效的解决方案,使用Bash、SQL和Python标准库就足够了。


本节课中我们一起学习了如何将MySQL数据导出为CSV文件,并利用Python标准库快速构建一个轻量级的Web服务来提供这些数据。这演示了如何利用现有工具高效地完成数据工程任务。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P23:23_02_02_引言_3

概述 📋

在本节课中,我们将要学习Apache Airflow的基础知识。Apache Airflow是一个强大的工具,它允许数据工程师构建和管理复杂的数据处理流程。我们将从最基础的概念开始,逐步构建一个简单可用的工作流,并探讨如何将其应用于实际生产环境。


Apache Airflow是一个非常有趣的软件。

它允许数据工程师创建功能强大的流水线。这些流水线可以包含许多不同的任务,涵盖从数据提取、转换到在整个流程中持久化数据的各个环节。

这些流程和任务的集合通常被称为流水线。

我的名字是Alfredodes。我很高兴能深入探讨Apache Airflow的基本概念。我们将从基础开始,构建一个简单可用的示例,这是学习任何新事物的第一步。然后,我们会进一步学习如何将不同的步骤连接起来,形成一个适用于生产环境的、有意义的流程。

我们将学习如何检索远程信息源,会使用Apache Airflow特有的某些概念,并尝试将它们整合成一个你可以实际练习的项目。希望你能通过实践获得经验,从而增强你自己的流水线,或在完成我即将介绍的所有知识后,解决你自己的数据工程问题。


总结 ✨

本节课中我们一起学习了Apache Airflow的初步介绍。我们了解到它是一个用于构建、调度和监控工作流的平台,其核心是创建由多个任务组成的流水线。我们从学习基础概念开始,这是掌握任何新工具的第一步。后续我们将深入探讨如何连接不同任务,并构建适用于实际场景的解决方案。通过动手实践,你将能够运用这些知识来优化自己的数据处理流程。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P24:什么是Apache Airflow 🚀

在本节课中,我们将要学习Apache Airflow的核心概念。我们将了解它是什么、为什么使用它、它的适用场景以及一些重要的细节。通过本教程,你将能够理解Airflow的基本工作原理和它在数据工程工作流中的角色。


什么是Apache Airflow?

Apache Airflow是一个开源项目。它允许你将特定的作业批量组织在一起。如果你熟悉CI/CD系统,它的工作方式与之类似,即设置某些任务在特定时间执行。因此,我们需要处理一些概念,例如触发任务和执行某些操作的代码片段。

本质上,Apache Airflow是一个开源批量工作流平台。它是一个平台,你处理的是将要执行操作的工作流,并且这些操作是批量执行的,我们稍后会详细探讨。

你必须使用Python编写所有内容,即用Python来定义所有任务以及它们如何协同工作。它提供了一个Web用户界面,用于监控和跟踪这些工作流的执行情况及其状态。这与某些CI/CD平台非常相似,你可以在UI中查看工作流并了解正在发生的情况。

你当然可以从笔记本电脑部署它。虽然我不完全推荐用于生产环境,但为了尝试和入门,这非常容易,我们稍后会看到。


为什么选择Apache Airflow?

上一节我们介绍了Airflow的基本定义,本节中我们来看看选择它的主要原因。

Apache Airflow允许你编排特定任务。想象一下,你有一些想要执行的操作或任务,你可以将它们组合在一起,让它们协同工作。这就是编排平台的功能,而Airflow在这方面表现卓越。

以下是选择Airflow的一些关键原因:

  • 清晰的工作流定义与配置:你可以通过工作流拥有所有这些定义和配置。你有一种非常清晰、简单直接的方式来启动和结束需要在特定时间间隔执行的批量工作。这些间隔不一定是规律的,可以是规律的,也可以是非规律的。同样,这些设置都是使用Python构建和定义的,你需要编写一些Python代码来整合所有内容。
  • 丰富的调度与执行能力:这意味着不仅能够调度任务,还可以有多种方式触发运行。例如,回填功能允许历史重新运行,这使你可以回溯并执行特定操作。想象一下,如果你要从头开始填充一个数据库,你可以在历史数据上重新运行流水线。另一个例子是重新运行部分流水线,比如在中间发生某些情况时,你想要修复一些错误。这在数据工程中非常常见,你可能在执行过程中意外地需要修复某些问题,而Airflow提供了这种能力。
  • 强大的监控与用户界面:用户界面提供了流水线或任务检查功能。你可以查看正在发生的情况、任务何时开始、是否失败或成功。你完全可以获得流水线随时间推移的概览,例如这个流水线在过去一个月或一年中是如何工作的,以及这些任务执行时的情况。当然,还包括日志输出和失败时的重试。你还可以配置重试策略,如果某些任务失败,你可能不希望重试它们,因为这不合理。但在某些情况下,例如处理网络问题时,重试功能会非常有用。
  • 开源与高度可定制:开源总是一件好事,因为它拥有全球开发和使用的社区。这意味着你拥有支持、生态系统和社区感。在处理大型项目时,社区也提供了大量支持、资源和可扩展性,这一点我非常喜欢,也非常重要。高度可定制的架构也非常出色,你可以通过API与之交互来实现目标。

Airflow的局限性

在了解了Airflow的优势之后,我们也需要认识它的局限性,以便在正确的场景中使用它。

Airflow并不完全适用于事件驱动的工作流,并且任务不会无限期运行。你希望任务按计划触发,处理某些内容,执行某个操作。如果发生问题,你可能希望重试。但如果你需要不同的东西,例如,如果你是一个流处理平台,想要处理某些事件流,那么Airflow可能不太适合。

另一个方面是,如果你想减少编码,不想进行太多开发,而希望更多地使用用户界面,那么Airflow肯定不是最佳选择。


总结

本节课中我们一起学习了Apache Airflow。我们了解到它是一个用于编排和调度批量工作流的开源平台,完全使用Python定义。它提供了强大的调度、监控、回填和重试功能,并拥有一个活跃的社区支持。然而,它主要适用于计划驱动的批处理任务,而非实时事件流处理,并且需要一定的Python开发能力。理解这些核心特性和适用场景,将帮助你在数据工程项目中做出正确的技术选型。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P25:从PyPI安装Apache Airflow 🚀

在本节课中,我们将学习如何通过Python的包管理工具Pip,从Python包索引(PyPI)安装Apache Airflow。我们将创建一个约束文件来管理依赖版本,并设置一个虚拟环境以确保安装的隔离性和可重复性。最后,我们将验证安装是否成功。


Apache Airflow有多种安装方式。我们将概述如何使用Pip和Python安装工具从Python包索引(PyPI)获取Apache Airflow。

首先,我们需要创建一个约束文件。

以下是创建约束文件的步骤。我们可以通过执行命令或编写文件来完成,这里我们选择编写一个文件。让我们快速浏览一下这个约束文件的内容。

我们有一个Apache Airflow版本,此处为2.7.1。然后,我通过一个命令获取Python版本,该命令将准确提供我所需的Python版本信息,并以此构建一个约束URL。

这个操作会获取一个约束文本文件。这意味着,如果我查看该文件,它会列出依赖关系。Pip可以利用这个文件来确保在安装某些组件时,对版本施加约束。

现在,让我快速退出并“source”这个文件。我将执行 source constraints.txt

然后,我可以执行例如 echo $PYTHON_VERSION 来检查Python版本,这里显示为Python 3.9。如果我执行 echo $CONSTRAINT_URL,你会看到Apache Airflow版本和约束URL都已设置好。

如果我们想快速查看这个约束文件的内容,可以获取并查看它。你会发现它看起来很像一个 requirements.txt 文件,但这个约束文件基本上锁定了所有不同的依赖版本。Apache Airflow在这方面做得很好,努力确保所有组件都能协同工作。

接下来,我们可以先创建一个虚拟环境。我将执行 python3 -m venv ./venv。这意味着我将运行Python 3,使用 venv 模块,在 ./venv 目录下创建一个虚拟环境。

创建完成后,我需要激活它。执行 source ./venv/bin/activate。激活后,你会看到我的命令行提示符发生了变化,出现了 (venv) 标识。

现在,我可以使用来自虚拟环境的Pip进行安装。执行 pip install "apache-airflow==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}"。请注意,这里使用花括号 ${} 来引用变量。

这个命令将安装依赖。运行它,安装过程会很快,因为我之前已经预先安装好了所有组件。

很好,所有内容都已安装完毕。现在,我们应该有一个Airflow二进制可执行文件。执行 airflow --help 来查看所有可用的命令,这可以确认Apache Airflow已成功安装。

现在,让我们看看如果运行 airflow standalone 会发生什么。它将运行数据库迁移,为我们设置好一切。大量日志信息会输出,并告诉我Airflow已准备就绪,管理员用户名为 admin,密码为终端中显示的一串字符。

一切看起来都正确,它将在本地主机的8080端口上运行。让我快速打开浏览器检查一下。访问 localhost:8080,它会提示输入用户名。我将粘贴从终端获得的密码,然后登录。登录后,所有功能都将准备就绪。

这就是不仅通过Pip安装Airflow,还通过运行独立版本来验证安装是否实际工作的方法。


本节课中,我们一起学习了如何从PyPI安装Apache Airflow。我们创建了约束文件来管理依赖版本,在虚拟环境中完成了安装,并通过启动Airflow的独立模式验证了安装成功。这为后续使用Airflow进行工作流编排奠定了基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P26:在Docker中使用Apache Airflow 🐳

在本节课中,我们将学习如何使用 Docker Compose 来快速搭建一个 Apache Airflow 的本地开发与测试环境。我们将下载官方的 Docker Compose 配置文件,启动所有必要的服务,并验证 Airflow 的 Web 界面是否能够正常运行。


概述与准备工作

上一节我们介绍了 Apache Airflow 的基本概念。本节中,我们来看看如何使用 Docker 容器化技术来运行 Airflow。使用 Docker Compose 是尝试 Apache Airflow 的另一种方式。你可以围绕调度器进行一些操作,并拥有一个本地开发环境。同时,你也能借此机会深入研究,了解更多关于 Airflow 的强大功能。

我再次打开了终端。我将下载一个为我准备好的 Docker Compose 文件。值得注意的是,这个配置不适用于生产环境,而更像是为了尝试一个容器化的环境。当然,如果你的本地已经设置好了 Docker 工具,就可以直接运行它。

下载 Docker Compose 文件

首先,我将下载那个文件。以下是我将要使用的命令。我将使用 curl 命令从这个位置下载文件。这个位置是 airflow.apache.org,来自官方文档。你同样可以 100% 通过浏览器获取这个文件,但我选择在终端中完成所有操作。

这个文件将使用 Apache Airflow 版本 2.7.1。如果你想获取不同的版本,你需要能够更改那里的版本号。

以下是下载命令:

curl -LfO ‘https://airflow.apache.org/docs/apache-airflow/2.7.1/docker-compose.yaml‘

好的,让我们开始吧。很好,下载完成了。现在让我们看看我们的 Compose 文件。

解析 Docker Compose 文件

我们在这里拥有的基本上是我们需要的所有东西。你可以看到这里定义了很多内容。你拥有很大的灵活性来更改端口、密码和用户名等设置,这些你都可以 100% 自定义。

正如你所知,Apache Airflow 包含很多不同的组件。它有一个 UI 界面,但也有数据库连接。除了数据库连接,你还需要处理 SQLAlchemy。当你尝试在 Docker Compose 中定义这样的东西时,所有这些都被抽象化了,但你开始看到一点端倪,了解一切是如何组合在一起的。

因为你看到了 SQLAlchemy、PostgreSQL、psycopg2(这是让 Python 能与 PostgreSQL 通信的驱动)。让我们继续向下滚动。

你可以看到这里有一些 Celery,这是一个用于发送和消费消息的工具,它将使用 Redis 作为消息代理。后端将使用 PostgreSQL。所以这里有很多东西会为我们定义好。

这个文件实际上有 300 行长,所以我们不会逐行检查所有内容,但我们会查看将要实例化的服务。

以下是文件中定义的关键服务:

  • PostgreSQL:数据库服务,会挂载一个数据卷,并有健康检查确保一切就绪。
  • Redis:消息代理服务,同样有健康检查和一些超时设置。
  • Web Server:Airflow 的 Web 服务器,将运行在本地主机的 8080 端口。
  • Scheduler:Airflow 调度器,也运行在本地主机,但使用不同的端口,同样有 /health 健康检查端点。

启动 Airflow 环境

启动这些服务的常用方式是使用 docker compose up 命令。docker compose up 将允许你启动所有服务。

然而,对于 Apache Airflow,官方的实际指令推荐你先运行 docker compose up airflow-init。这个命令将确保所有数据库表被预先创建和初始化,一切准备就绪。

所以让我们先运行这个初始化命令。运行这个命令会产生大量输出。让我们花点时间,直到它完成拉取所有镜像层并实例化我们所需的一切。完成后我们会回来。

好的,Airflow 初始化完成了。现在我们可以看到“Airflow 已创建,用户为 admin”这样的消息。这正是你想看到的消息,它以退出代码 0 结束。

一旦初始化完成,你就可以运行 docker compose up,一切应该就能正常工作了。

完美,所有容器都在启动和运行,我们会看到大量的日志输出。稍后等它完成,我们再检查用户界面是否再次运行。

验证 Airflow 运行状态

现在启动已经完成,你会看到这里有很多日志。Web 服务器确实在正确运行。如果我非常快地滚动到顶部,也会看到 Redis 在那里,还有关于 Web 服务器的更多信息。你可以看到权限被添加了,这是一个非常完整的过程,很多东西被添加并开始运行。

现在,我将快速切换到我的网页浏览器。浏览器会告诉我一切是否就绪。我将访问 localhost:8080。登录用户名是 airflow,密码也是 airflow。然后登录。

你应该看到的界面,与你通过 Python 包索引(PyPI)全新安装并尝试时非常相似。但 Docker Compose 方式允许你拥有独立的容器来处理独立的工作和关注点,而不是一个“一体式”的应用。它实际上会使用 PostgreSQL 以及 Redis 和 Celery 等服务,这看起来和感觉上会更像生产环境。但这仍然不是生产就绪的配置,所以建议仍然如此。

我们暂时不会深入探讨 UI 的细节,但这只是一种验证一切是否正常工作的方式。


总结

本节课中我们一起学习了如何使用 Docker Compose 来搭建和运行 Apache Airflow。我们完成了从下载官方 Compose 文件、解析其服务构成、初始化数据库到最终启动全部服务并验证 Web 界面可访问的完整流程。这种方法为你提供了一个隔离的、模块化的本地环境,便于你体验 Airflow 的核心功能并进行开发测试。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P27:探索Airflow用户界面 🖥️

在本节课中,我们将探索Apache Airflow的用户界面。我们将了解其核心功能、如何管理DAG(有向无环图)以及如何通过界面监控和操作任务。本节内容旨在帮助初学者快速熟悉Airflow UI的基本布局和常用操作。


本地环境与生产环境差异

上一节我们介绍了Airflow的基本概念,本节中我们来看看其用户界面。请注意,我当前使用的是本地运行环境,而非生产环境。

如果向上滚动,你会看到一些在生产环境中不应使用的组件提示。例如,我使用了SQLite。SQLite是一个嵌入式数据库,在文件系统中看起来像一个文件,本质上是一个允许交互的数据库。但这并非生产环境的理想选择。在生产中,通常会选择PostgreSQL或MySQL等数据库。同样,Sequential Executor也仅适用于尝试和测试。在浏览用户界面时,你会看到这些警告信息。


浏览与管理DAG

让我们快速查看可用的DAG。我已经启用了其中一个DAG。

“启用”一个DAG意味着什么?界面上有一个开关,允许你根据需要开启或关闭特定的DAG。一旦开启,计划的或手动触发的运行就可以开始。

在界面上,你可以看到DAG的所有者、运行状态等信息。将鼠标悬停在状态图标上,可以看到“已排队”、“运行中”、“成功”或“失败”等状态。目前,我没有失败或正在运行的任务,但之前手动触发了一个并成功运行了。了解这些空圆圈图标的含义非常有用。

界面上还显示了一些基本信息,例如上次运行的时间戳和下一次计划运行的时间。记住,某些DAG依赖于其他DAG的运行,界面会显示下一次计划运行的时间。


任务详情与操作

以下是关于近期任务的信息。为了让视图更清晰,我稍微调整了界面大小。

你可以看到近期任务列表,并可以对它们执行一些操作。例如,你可以触发一个任务运行,或者将其删除。

现在,让我们放大视图,仔细查看。将鼠标悬停在DAG上,你会看到“暂停”和“取消暂停”的选项,这与我之前解释的功能一致。目前,我只激活(即取消暂停)了名为 dataset_consumes_1 的DAG,其他DAG都处于暂停状态。正如所见,当前没有正在运行或失败的任务。


深入查看DAG详情

让我们点击 data_consumes 这个DAG来查看更多元数据和更详细的运行信息。

在这个详情页面,你可以看到更细粒度的数据,例如任务的最大运行时长、平均运行时间等计算指标。由于我只运行过一次,所以数据目前是静态的。但这里是你获取运行准确信息的地方。

页面提供了不同类型的可视化图表。虽然我这里没有太多数据,但其中一个有趣的功能是“代码”选项卡。


查看与审查DAG代码

“代码”选项卡允许你探索DAG的定义。我尝试向下滚动,你可以看到实际执行任务的代码。这是一个示例DAG,也是包含所有代码的Python文件。

这是一种查看和检查正在运行内容的简洁方式。我们尚未深入探讨DAG是如何构建的,或者界面上所有元素的含义,但如果你清楚自己在做什么,这是一个检查具体执行内容的好方法。这个DAG的代码量不小,大约有130行,你可以直接从UI快速审查它,这个功能我非常喜欢。

在详情页,你还可以看到任务运行时长图表,并且有“自动刷新”的选项。如果点击“触发”或“播放”按钮,自动刷新功能会启用。


触发与监控任务运行

让我们回到“网格”视图。如果我点击“触发”按钮,你可以看到任务开始运行。

现在自动刷新已开启,任务实际上已经在这里启动了。这是我的第一次运行,发生在稍早之前,而这是另一次运行。这里的任务并不复杂。

如果我带你回到代码视图,你会看到它只是运行一个Shell命令:在执行其他操作前先休眠几秒钟。

让我们实际看看它在做什么。是的,命令是 sleep 5,这正是它执行的内容,这个过程大约需要7秒。下一个任务实际上没有执行,但这没关系,因为它是这样配置的。


其他有用视图与功能

浏览界面时,还有一些我非常喜欢的功能。以下是其他有用的视图:

  • 任务尝试:查看任务每次尝试执行的详细信息。
  • 着陆时间:分析任务完成的时间点。
  • 日历:日历视图尤其有用。你可以看到我有两次触发记录,并且所有记录都用颜色编码,提供了非常直观的日历可视化。这一切都是为了让你有能力准确了解正在发生的情况。
  • 审计日志:审计日志会包含日志输出。在这里你可以看到我的用户名、触发操作等信息,所有者信息也会显示在这里。它提供了更详细的信息供你探索和进行更多操作。

界面上还有各种不同的配置项,例如启用插件、配置提供者、管理资源池等。这让你拥有完全的控制权。

本节内容主要是对Apache Airflow用户界面的快速概述,并非深入教程,但对于理解一些基础知识仍然非常有用。


总结

本节课中,我们一起探索了Apache Airflow的用户界面。我们了解了本地环境与生产环境的区别,学习了如何浏览、启用、暂停DAG,以及如何查看任务详情、运行状态和DAG代码。我们还实践了触发任务并利用日历、审计日志等视图进行监控。这些基础操作是使用Airflow进行工作流编排和管理的重要第一步。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P28:28_02_02:引言_4

在本节课中,我们将学习有向无环图(DAGs)的基本概念。我们将从最简单的实现方法开始,逐步了解其组成部分、构建方式,并实践使用Python和相关依赖来创建一个DAG。我们还将探索用户界面(仪表板)以监控任务执行,最后理解“回填”操作的含义与实施方法。

什么是有向无环图(DAGs)?

有向无环图,简称DAGs,是一种由节点和有向边组成的数据结构。其中,边表示节点间的依赖关系,并且整个图不允许出现循环。这意味着任务只能沿着一个方向执行,不会形成闭环。

上一节我们介绍了DAGs的基本定义,本节中我们来看看如何构建一个最简单的DAG。

使用Python构建基础DAG

我们将从最基础的案例开始,使用Python来构建一个DAG。这通常需要安装任务可能依赖的特定Python库。

以下是构建一个简单DAG的基本步骤:

  1. 导入必要的库:首先,需要导入用于定义和调度DAG的框架库,例如Apache Airflow的核心模块。
  2. 定义DAG对象:创建一个DAG实例,并设置其基本属性,如唯一标识符、开始日期和调度间隔。
    from airflow import DAG
    from datetime import datetime
    
    dag = DAG(
        dag_id='my_simple_dag',
        start_date=datetime(2023, 1, 1),
        schedule_interval='@daily'
    )
    
  3. 定义任务(Operators):在DAG中,每个节点代表一个任务。我们需要使用特定的“操作符”来定义这些任务。
    from airflow.operators.python_operator import PythonOperator
    
    def print_hello():
        print("Hello from the DAG!")
    
    hello_task = PythonOperator(
        task_id='hello_task',
        python_callable=print_hello,
        dag=dag
    )
    
  4. 设置任务依赖关系:通过定义任务执行的先后顺序来构建DAG的边。例如,如果存在多个任务,可以使用 >> 运算符设置依赖。
    # 假设有另一个任务 goodbye_task
    hello_task >> goodbye_task
    

探索用户界面(仪表板)

在定义并部署DAG之后,我们可以通过用户界面(通常是一个Web仪表板)来监控和管理它。仪表板允许我们直观地查看DAG的运行状态、触发任务执行、检查日志以及分析任务执行的历史记录。

通过操作仪表板,我们可以实时反思刚刚被触发的任务动作,确认其是否按预期执行。

理解并执行回填操作

最后,我们将探讨“回填”的概念。回填是指针对过去某个时间段内的数据,重新执行DAG中的任务。这在以下场景中非常有用:当添加了新任务、修改了数据处理逻辑,或者需要补全历史数据时。

回填操作意味着调度器会根据DAG的定义,为指定的历史日期范围创建并运行任务实例,而不是仅仅等待未来的调度时间点触发。

本节课中我们一起学习了有向无环图(DAGs)的核心概念。我们从最简单的Python实现入手,了解了DAG的组成部分和构建流程。随后,我们探索了如何通过用户界面监控任务执行。最后,我们掌握了回填操作的含义及其应用场景。通过这些步骤,你已具备了构建和操作基础数据流水线的初步能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P29:29_02_03:探索有向无环图(DAG)🔍

在本节课中,我们将要学习Apache Airflow中的有向无环图(DAG)。我们将从Airflow自带的示例DAG入手,分析其结构和组件,并了解如何通过代码定义和配置一个DAG。通过本教程,你将掌握DAG的基本构建方法。

概述

我们将首先查看Apache Airflow内置的示例DAG,特别是“example_python_operator”示例。通过分析其代码,我们将理解DAG的构成要素、任务定义以及依赖关系。同时,我们也会参考官方文档中的教程DAG,以加深对核心概念的理解。

探索示例DAG

上一节我们介绍了本课程的目标,本节中我们来看看Apache Airflow中自带的示例DAG。我们将从“example_python_operator”开始,它已经成功运行过一次。

除了Python操作符示例,我们还需要了解官方文档提供的信息。因此,我们将转到文档部分,快速浏览“教程DAG”以获取更多背景知识。

以下是切换到文档网站后的步骤,我们将跳过许可证部分,直接关注将要处理的组件。

DAG的构成要素

一个DAG文件通常包含以下部分:

  • 导入语句:首先需要导入所有必需的模块。例如,BashOperator用于执行Bash命令,DAG类是创建DAG所必需的。
  • DAG实例化:使用with语句创建DAG对象,并传入各种配置参数。
  • 任务定义:在DAG上下文中,定义各个任务(Task),并指定其操作符(如BashOperatorPythonOperator)和参数。
  • 依赖关系:通过设置任务的上下游关系(如 t1 >> [t2, t3])来定义执行顺序。

分析教程DAG

在教程DAG中,我们通过with DAG(...)语句实例化DAG。with语句是一个上下文管理器,它确保DAG在正确的上下文中创建和执行。

在创建DAG时,可以传递许多参数来精细控制其行为。例如:

  • depends_on_past:如果设置为True,则任务执行依赖于前一次执行的成功。
  • email:设置接收通知的邮箱地址。
  • email_on_failure:任务失败时是否发送邮件。
  • end_date:设置DAG的结束日期,避免无限期运行。

定义好DAG后,我们开始创建任务。在教程示例中,t1t2t3是任务变量,它们调用了BashOperator

每个任务都需要一个唯一的task_id。例如,t1执行date命令,t2执行sleep 5命令。t1doc_md参数用于添加Markdown格式的文档,这会在Airflow界面上以友好的方式呈现,但它是可选的。

任务还可以使用Jinja模板引擎,这提供了在任务中动态渲染内容的能力。

最后,通过 t1 >> [t2, t3] 这样的语法定义了依赖关系,表示t1完成后,t2t3将并行执行。

深入Python操作符示例

了解了基础结构后,我们来看看“example_python_operator”的具体代码。这个示例展示了更多Python特有的功能。

以下是该示例DAG的主要组成部分:

  • 导入操作符:导入了ExternalPythonOperatorPythonVirtualenvOperator。这些操作符对于管理Python依赖至关重要,尤其是在需要隔离环境或安装外部包时。
  • DAG定义:使用with DAG(...)定义DAG,并设置了dag_idschedule(本例中为None)、start_datetags等参数。
  • 任务函数与装饰器
    • print_context 函数使用 @task 装饰器,它打印上下文信息并返回一个字符串,该字符串会输出到日志中。
    • log_sql_query 是另一个被装饰的任务函数。
  • 动态生成任务:通过一个for循环动态创建了5个睡眠任务(sleeping_task),这演示了如何以编程方式生成多个类似任务。
  • 虚拟环境管理vm_installed任务检查是否处于虚拟环境中。vm_task任务则使用@task.virtualenv装饰器,并指定了依赖项(如colorama),这确保了任务在包含所需包的独立虚拟环境中运行。
  • 外部Python任务external_python_task展示了如何调用一个指定路径的Python解释器来执行任务,而不依赖主Airflow环境。

在代码末尾,通过设置任务间的依赖关系(如 run_this >> log_sql >> sleeping_tasks)来定义整个工作流的执行图。

查看DAG运行图

当我们运行这个DAG时,可以在Airflow的图形视图(Graph View)中看到其结构。执行顺序将是:首先运行print_context,然后是log_sql_query,接着是动态生成的5个睡眠任务(sleeping_task_0sleeping_task_4)。

这种可视化清晰地展示了任务之间的依赖关系和并行执行路径。通过检查每个任务的日志详情,我们可以验证其执行过程和输出。

总结

本节课中我们一起学习了Apache Airflow中有向无环图(DAG)的核心概念。我们从分析内置的示例DAG开始,理解了其基本结构,包括导入、DAG实例化、任务定义和依赖设置。我们重点剖析了example_python_operator,学习了如何使用Python装饰器定义任务、动态生成任务、以及管理Python虚拟环境依赖。最后,我们通过图形视图直观地看到了DAG的执行流程。这些知识为你构建灵活、可靠的数据管道奠定了坚实基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P30:30_02_05_创建DAG 📁

在本节课中,我们将学习如何在Apache Airflow中创建一个简单直接的DAG。我们将遵循Airflow提供的文件夹结构,并逐步构建一个使用Pandas库处理数据的示例任务。


理解Airflow目录结构

首先,我们需要了解Apache Airflow的默认目录结构。Airflow的配置和DAG文件通常位于用户主目录下的airflow文件夹中。这是一个非生产环境,因此我们使用SQLite嵌入式数据库。

airflow目录下,有多个子目录和文件,例如数据库文件和管理员密码文件。我们的重点是dags子目录,这是存放所有DAG文件的地方。

创建DAG文件

接下来,我们进入dags子目录并创建一个新的Python文件。我们将这个文件命名为pandas_example.py。你可以使用任何文本编辑器来创建和编辑这个文件。

以下是创建DAG文件的具体步骤。

导入必要的库

在文件的开头,我们需要导入一些必要的Python库和Airflow模块。

import logging
from datetime import timedelta
from airflow import DAG
from airflow.decorators import task
from airflow.operators.python import PythonVirtualenvOperator

定义DAG和任务

现在,我们开始定义DAG本身及其包含的任务。我们将设置DAG的ID、调度间隔、开始日期和标签。

# 定义DAG
dag = DAG(
    dag_id='pandas_tutorial',  # DAG的唯一标识符
    schedule_interval=timedelta(days=1),  # 每天运行一次
    start_date=datetime(2023, 10, 1),  # 开始日期
    tags=['example'],  # 用于在UI中分类的标签
)

# 初始化日志记录器
logger = logging.getLogger(__name__)

使用PythonVirtualenvOperator

我们将使用PythonVirtualenvOperator来创建一个隔离的Python环境,并在其中运行我们的任务。这确保了依赖项不会与系统或其他任务冲突。

# 定义任务函数
def process_csv():
    import pandas as pd
    # 假设的CSV数据URL
    csv_url = 'https://example.com/data.csv'
    df = pd.read_csv(csv_url)
    # 处理数据,例如返回前10行
    result = df.head(10)
    return result

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/91735dec7c258cee4c1f7c2d60d06411_6.png)

# 创建任务实例
pandas_task = PythonVirtualenvOperator(
    task_id='process_csv_task',
    python_callable=process_csv,
    requirements=['pandas==2.1.1'],  # 指定Pandas版本
    system_site_packages=False,  # 不使用系统包
    dag=dag,
)

保存并检查DAG

保存文件后,Airflow会自动检测dags目录中的新文件并将其导入。我们可以在Airflow的Web UI中查看新添加的DAG。

在Airflow UI中验证DAG

打开Apache Airflow的Web界面,我们可以通过标签搜索我们的DAG。例如,搜索“example”标签,应该能看到我们刚创建的pandas_tutorial DAG。

点击DAG名称,可以查看其代码、日志和运行状态。确保DAG的ID是唯一的,以避免与其他DAG冲突。

调试与注意事项

如果在UI中没有看到新创建的DAG,可能是由于ID冲突或语法错误。检查DAG的ID是否唯一,并确保代码没有错误。Airflow会自动重新加载dags目录中的文件,但有时可能需要手动刷新。


本节课中,我们一起学习了如何在Apache Airflow中创建和配置一个简单的DAG。我们了解了Airflow的目录结构,编写了一个使用Pandas处理数据的任务,并在Airflow UI中验证了DAG的正确性。记住,保持DAG ID的唯一性和代码的正确性是成功运行工作流的关键。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P31:运行回填 🚀

在本节课中,我们将要学习 Apache Airflow 中的一个重要概念——回填。我们将了解任务调度中日期部分的含义,并通过实际操作演示如何使用命令行界面执行回填操作,以处理过去特定时间段内的任务。

任务调度与日期的概念

上一节我们介绍了 Airflow 的基本任务调度。本节中我们来看看任务调度中“开始日期”和“计划”的具体含义。

Apache Airflow 的一个重要概念是调度,以及在我们处理任务时如何理解日期部分。这里的开始日期和调度,并不一定意味着在某个特定日期开始运行,而是指为某个特定日期开始执行任务。这意味着你可以让任务的执行遵循一个日历视图。例如,如果你指定某个任务为 2023 年 4 月执行,即使我们现在已经不在 2023 年 4 月,你仍然可以运行任务来“填补”那个时间段。

你可以指定需要在 4 月发生的那些天运行这些任务。每当一个任务定义了这些日期和调度(例如,每天运行多少次或间隔时间),你实际上就定义了一个需要执行这些操作的时间线。执行这类操作的方式就是通过回填

什么是回填? 🔄

上一节我们明确了日期调度的含义,本节中我们来看看实现它的具体工具——回填。

回填是一种指令 Airflow DAG(在本例中是 pandas_tutorial)在给定时间范围内按照给定调度运行的方式。它允许你“回到过去”执行任务。

以下是执行回填的核心命令结构:

airflow dags backfill -s <开始日期> -e <结束日期> <DAG_ID>

执行回填操作 💻

了解了回填的概念后,接下来我们通过终端实际操作一遍。

让我们回到终端,看看具体如何操作。我这里有一个实际的命令。我将运行 airflow 这个 Apache Airflow 的命令行界面工具。我会使用 dags 子命令,然后是 backfill 子命令。我将指定 pandas_tutorial 作为我的 DAG 的唯一 ID,并传入开始日期 2021-12-12 和结束日期 2021-12-13

airflow dags backfill -s 2021-12-12 -e 2021-12-13 pandas_tutorial

执行时可能会遇到错误,例如 DAG ID 不唯一。看到这些错误和跟踪信息是有用的,因为它能让我们在事情不按预期发展时感到更从容。修正 DAG ID 后,我们再次尝试运行。

现在,我们将看到一些输出。因为 Apache Airflow 会尝试理清所有正在发生的事情,我们可能会看到其他任务的输出。但我们会看到 pandas_tutorial 开始运行。即使其他任务可能因无法导入 pandas 而失败,但我们关注的 pandas_example 任务会正确运行。

关于 DAG 文件夹路径(如 ~/airflow/dags),Airflow 使用它来定位 DAG 文件,这个位置是可配置的。

验证回填结果 ✅

任务执行完成后,我们需要到 Web UI 界面查看结果。

回填完成后,让我们转到 Web UI 查看结果。我切换到日历视图并刷新页面。

现在你可以看到,因为我指定了 2021 年的日期,所以 2021 年的调度出现了。由于我指定了两天且每天运行一次,这里有两个运行实例。你可以看到 2021年12月12日和12月13日各有一个成功的运行。点击其中一个,你会看到它确实成功了。运行类型显示为“回填”。

通过这种方式,你可以在 DAG 定义的约束条件下,为你能定义的非常具体的时间框架执行回填操作。

总结 📝

本节课中我们一起学习了 Apache Airflow 中的回填操作。我们首先理解了任务调度中“为特定日期执行”的含义,然后明确了回填是一种用于在历史时间范围内按计划执行 DAG 的机制。接着,我们通过命令行演示了执行回填的具体步骤和命令格式,并最终在 Web UI 中验证了回填任务的执行结果。掌握回填功能,使你能够灵活地处理过去遗漏的任务或测试历史数据流水线。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P32:测试与验证 🧪

在本节课中,我们将学习如何对创建的Airflow DAG进行测试与验证,确保其功能正确且运行稳定。我们将通过一系列命令行操作来检查DAG的语法、任务列表,并执行任务测试。

概述

我们将进入Airflow的DAGs子目录,针对之前创建的pandas_example.py DAG文件进行测试。测试内容包括检查DAG ID与文件名的对应关系、使用Python直接执行文件以验证语法、使用Airflow命令列出任务,以及直接测试特定任务。这些步骤有助于在部署前发现潜在问题。

DAG ID与文件名的对应关系

首先,需要注意DAG ID与存放文件的名称可能不一致。在我们的例子中,DAG文件名为pandas_example.py,但DAG ID在代码中被定义为pandas_tutorial

代码示例:

# 在pandas_example.py文件中
with DAG(
    dag_id="pandas_tutorial",  # 这是DAG ID
    schedule_interval="@daily",
    start_date=datetime(2021, 1, 1),
    catchup=False,
    tags=["example"],
) as dag:
    # ... 任务定义

这种不一致可能导致混淆。为了便于管理,建议将DAG ID与文件名保持一致,例如将文件命名为pandas_tutorial.py。规范化命名能使工作流更清晰易懂。

使用Python进行语法验证

一个推荐的验证方法是直接使用Python解释器执行DAG文件。这能快速检查文件是否存在语法错误或导入模块缺失等问题。

操作命令:

python pandas_example.py

如果文件中存在未安装的依赖(例如尝试导入pandas但未安装),执行此命令会抛出ModuleNotFoundError。这有助于在将DAG提交给Airflow调度器之前发现环境配置问题。

使用Airflow列出DAG任务

确认文件语法无误后,可以使用Airflow命令行工具验证DAG及其任务是否被正确识别。

操作命令:

airflow tasks list pandas_tutorial

此命令会列出pandas_tutorial这个DAG中定义的所有任务。在我们的例子中,应该只看到一个名为virtualenv_python的任务。这验证了任务定义已成功加载到Airflow中。

直接测试Airflow任务

最核心的测试是直接运行一个任务。Airflow允许我们为特定执行日期测试某个任务,而无需触发整个DAG。

操作命令:

airflow tasks test pandas_tutorial virtualenv_python 2021-12-12

以下是执行此测试时会发生的事情:

  1. 创建虚拟环境:任务会首先创建一个独立的Python虚拟环境。
  2. 安装依赖:在虚拟环境中安装任务所需的依赖包(例如pandas==2.0.1)。
  3. 执行任务逻辑:运行任务中定义的Python函数,处理数据。
  4. 输出日志:任务的所有输出(例如我们代码中打印的CSV数据)都会显示在日志中。
  5. 标记状态:任务完成后,会被标记为成功或失败。

通过观察测试输出的完整日志,可以清晰地了解任务每一步的执行情况,确认其行为符合预期。

错误处理与验证技巧

在测试过程中,主动验证错误处理机制同样重要。例如,在我们的任务中,我们检查了virtualenv是否已安装。

原始警告代码:

if not is_virtualenv_installed:
    log.warning("Virtualenv is not installed. Please install it.")

然而,仅记录警告可能不够明显。更好的做法是直接抛出异常,使错误在测试时更醒目。

改进后的错误处理代码:

if not is_virtualenv_installed:
    raise RuntimeError("Virtualenv is not installed. Please install it.")

virtualenv未安装时,再次运行任务测试会收到一个显眼的红色错误异常信息,这比在日志中寻找警告更有利于快速定位问题。

总结

本节课我们一起学习了Airflow DAG的测试与验证流程。我们首先探讨了保持DAG ID与文件名一致性的最佳实践。接着,我们使用python命令进行基础语法验证,使用airflow tasks list确认任务加载。最后,我们深入使用airflow tasks test命令执行了单任务测试,观察了从环境搭建到任务执行的完整过程,并学习了如何通过抛出异常来改进错误处理的可见性。这些技巧是开发可靠数据管道的重要保障。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P33:33_02_09_总结_2

在本节课中,我们将总结关于Apache Airflow的核心概念,包括有向无环图(DAG)的构建、依赖管理以及调度机制。这些是构建更复杂工作流前必须掌握的基础知识。

探索与构建有向无环图(DAG)

上一节我们介绍了Airflow的基本架构,本节中我们来看看如何具体构建一个工作流。

我们探索了有向无环图(DAG)以及如何组装一个DAG。我们使用了Python的虚拟环境管理工具。

定义依赖与简单组装

以下是构建DAG的关键步骤。

我们能够定义特定的依赖关系,安装它们,并将一些非常简单的组件组装在一起。必须承认,这目前还不复杂,但让我们循序渐进。同时,理解回填以及这些触发日期的含义至关重要。

理解核心调度概念

掌握以下基础概念对于提升你的Airflow知识水平以及未来构建更复杂的工作流是必要的。

这些是关于回填和触发日期的重要基础知识。这些是必要的核心基础,能让你提升对Airflow的理解,并为后续实际构建更复杂的内容打下基础。

总结

本节课中我们一起学习了Apache Airflow的基础操作。我们实践了如何构建一个简单的DAG,使用Python工具管理依赖,并理解了工作流调度中关于回填和触发日期的核心概念。这些知识是迈向构建更高级、自动化数据管道的重要一步。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P34:34_02_02_引言_5

在本节课中,我们将学习如何实现一个数据处理流水线。流水线是一个包含多个不同步骤的过程。我们将了解其重要性,并学习如何使用Airflow等工具来构建和管理这些步骤。


流水线的重要性与概念 🧩

在数据工程中,将复杂任务分解为一系列独立的步骤至关重要。这种“分而治之”的方法允许我们专注于每个较小的步骤,便于测试和调试,而不会影响整个流程。这种将步骤和操作分组执行的“配方”或模式,就被称为流水线

上一节我们介绍了流水线的概念,本节中我们来看看Airflow如何帮助我们优雅地实现它。

Airflow使得创建任务、定义任务间的依赖关系以及将它们组合成一个完整流程变得非常高效和清晰。


流水线的工作流程 🔄

我们将编写一些代码,远程获取数据,进行一系列操作,并最终将所有结果整合在一起。

以下是构建一个典型数据处理流水线所涉及的核心步骤:

  1. 任务定义:将整个数据处理过程分解为独立的、可执行的任务单元。
  2. 依赖关系管理:明确指定任务之间的执行顺序,例如,任务B必须在任务A成功完成后才能开始。
  3. 调度与执行:按照预定的时间表或触发条件自动运行整个流水线。
  4. 监控与错误处理:跟踪每个任务的执行状态,并在失败时进行重试或告警。

让我们看看这个流水线将如何工作。


总结 📝

本节课中我们一起学习了数据处理流水线的基本概念及其在数据工程中的重要性。我们了解到,流水线通过将复杂流程分解为独立的步骤,提高了代码的可测试性、可维护性和可调试性。同时,我们介绍了像Airflow这样的工具如何帮助我们定义任务、管理依赖并构建健壮的自动化流程。在接下来的实践中,我们将应用这些概念来构建具体的流水线任务。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P35:识别构建DAG的任务 🧩

在本节课中,我们将学习如何识别适合使用Apache Airflow构建数据管道的任务。我们将通过一个具体的示例仓库,分析在确定哪些数据处理步骤可以转化为Airflow任务时需要考虑的关键因素。

概述

Apache Airflow是一个用于编排复杂工作流的平台。要有效地使用它,首先需要识别出可以编排为有向无环图(DAG)的独立任务。本节我们将通过一个葡萄酒评分数据集的分析,来学习如何识别这些任务。

分析示例数据仓库

我们首先查看一个示例仓库,它包含一个葡萄酒评分数据集(wine_ratings.csv文件)和一个Jupyter笔记本。这个案例能帮助我们理解,在决定使用Apache Airflow处理什么任务时,哪些方面是值得关注的。

ratings.csv文件结构相对简单,但由于其大小(13MB),无法在GitHub上完整显示。其核心数据列包括:name(名称)、grape(葡萄品种)、region(产区)、variety(类型)、rating(评分)和notes(品酒笔记)。每一行代表一款葡萄酒的评分信息。

然而,仅仅了解数据结构还不够。我们需要深入分析,以判断它是否适合用Airflow管道处理。

在Jupyter笔记本中识别数据处理任务

打开配套的Jupyter笔记本,我们可以看到它加载并分析了CSV文件,这为我们提供了一个发现潜在数据处理任务的好机会。

以下是分析过程中识别出的几个关键任务:

1. 处理缺失数据
在初步查看数据时,我们发现grape(葡萄品种)列存在大量NaN(非数字)值。一个可能的处理任务是直接删除这一列,或者根据其他信息填充缺失值。

2. 正确处理索引
使用pandas读取CSV时,如果不指定index_col参数(本例中应为0),pandas会自动生成一个行索引列。我们需要确保现有的索引列被正确识别和使用,避免产生重复或错误的索引。

3. 清洗文本数据(关键任务)
数据清洗中一个至关重要的任务是移除notes(品酒笔记)字段中的换行符(\n)或回车符(\r)。这是因为,当数据被导入某些服务或系统时,这些特殊字符可能会被错误地解释为新行的开始,从而破坏原本整齐的结构化数据格式,导致列数据无法对齐。因此,将这些换行符替换为空格或直接删除,是一个必要的数据预处理步骤。

为何这些任务适合Apache Airflow

以上这些任务都非常适合纳入一个Apache Airflow管道。虽然你可以在Jupyter笔记本或普通脚本中手动执行它们,但Airflow提供了更强大的优势:

  • 可编排与可视化:将这些步骤定义为独立的Airflow任务,可以构建一个清晰、可视化的数据处理管道。
  • 自动化与调度:管道可以按计划自动运行,确保数据处理的及时性和一致性。
  • 依赖管理与错误处理:Airflow能自动处理任务间的依赖关系,并提供完善的重试和错误处理机制。

如何识别Airflow任务

那么,我们如何系统地识别这些任务呢?关键在于观察数据处理流程:当我们有一组需要应用于某个数据集的特定操作或转换,目的是从初始数据得到最终结果时,这些操作通常就是潜在的Airflow任务。它们通常具有“输入 -> 处理 -> 输出”的明确模式。

在接下来的课程中,我们将学习如何把这里识别出的任务(如删除列、清洗文本)具体实现为一个Apache Airflow的DAG管道。

总结

本节课中,我们一起学习了如何识别适合用Apache Airflow构建DAG的任务。我们通过分析一个葡萄酒评分数据集,实践了从数据中发现问题(如缺失值、索引问题、脏数据),并将这些问题的解决方案转化为明确的数据处理任务。核心在于寻找那些可以独立定义、具有明确输入输出、并且需要按特定顺序或条件执行的操作步骤。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P36:检索远程数据 📡

在本节课中,我们将学习如何从远程数据源检索数据,并将其整合到我们的数据处理流程中。具体来说,我们将通过一个实际的例子,了解如何获取葡萄酒相关的CSV数据,并理解Apache Airflow中数据集(Dataset)和出口(Outlet)的概念。


上一节我们介绍了数据处理流程的概览,本节中我们来看看如何具体实现远程数据的检索。

为了创建我们之前浏览的CSV所需的葡萄酒相关数据,我们需要先获取这些数据。让我们看看这是如何工作的。我们将在Web界面上向下滚动,找到名为 wine_data_get 的任务。这个任务目前没有设置调度计划,我们将点击它来检查代码,以理解其具体执行过程。

这里的代码与我们之前看到的略有不同。我们定义了一个数据集(Dataset),这个数据集将成为我们工作流程中的一个关键部分。

现在,当我们像这样调用一个数据集时,其内容可以是任何东西。你实际上可以在其中放入任何类型的字符串。它主要作为一个标识符。例如,我使用的 file://localhost/... 这个字符串本身除了对我有含义外,对系统并无实际意义。我是在表明,这将是一个存储在本地数据集,该字符串代表了我想要显示的位置。

定义这个 raw_wine 数据集之所以重要,是因为通过它,我为其他需要使用此数据的任务设定了预期。

第一步是获取数据。那么我们要做什么呢?首先,我们有一个唯一的任务ID。这个 get 任务将代表我们尝试执行的操作。它目前没有调度计划,因此我们可以手动触发它。此任务依赖于一个虚拟环境(virtual environment),如果未安装虚拟环境,运行时将会出错。如果已安装,我们将使用 pandas 2.1.1

这里还有一个我们之前未见过的新概念:出口(outlets)。代码如下所示:

outlets=[raw_wine]

outlets 参数是一个列表,包含单个项目,即我们在线10定义的 raw_wine 数据集。这是一个对我们数据的引用。

为什么这很重要?因为如果任务正确完成,我们就可以声明 raw_wine 数据集已被更新。这是Apache Airflow的一个约定,用于确定一个出口何时被修改或变更,以便其他任务可以依赖于此来触发后续操作。虽然我们现在还看不到具体的后续操作,但你可以想象我们将进行一些数据处理。

在实际的函数内部,我们将读取远程的CSV文件。请注意,我使用了完整的URL来获取该CSV文件,然后将其保存到文件系统中。我在这里使用了一个规范化的路径,它将保存在我的主目录下的 airflow/datasets 目录中。在生产环境中,你可能不会以这种方式保存数据集。我建议使用云服务提供商,以便通过网络将数据传输到其他指定位置。

但就演示而言,我们只需要检索数据集并将其存储在本地,以便后续处理。这就是我构建此远程数据处理第一步的方式。最重要的是定义出口,在本例中,就是我们在第10行定义的 raw_wine 数据。


本节课中我们一起学习了如何从远程源检索数据,在Apache Airflow中定义数据集和出口,以及如何将数据保存到本地文件系统以备后续处理。理解出口的概念是构建依赖关系和数据驱动工作流的关键。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P37:清洗与规范化数据

在本节课中,我们将学习如何在Apache Airflow中构建一个数据消费者任务。这个任务将依赖于上游生产者任务生成的数据集,并在数据更新时自动触发执行。我们将重点讲解如何配置基于数据集的调度、执行数据清洗与规范化操作,以及如何在Airflow界面中可视化任务间的依赖关系。

返回Airflow用户界面

上一节我们介绍了数据生产者任务,本节中我们来看看数据消费者任务。

我们向下滚动到名为 wine_consumer 的DAG。之前我们查看的是 wine_dataset_get 任务,现在我们将关注 wine_consumer 任务。这个任务有一个明显的不同:它有一个自动应用的“数据”标签。将鼠标悬停在标签上会显示“由数据触发的调度”。接下来,我们将探究其工作原理及其重要性。

解析消费者任务代码

点击任务并进入代码视图,让我们详细查看其内容。

首先,在第10行,我们定义了此任务所依赖的数据集。这与之前的调度定义方式略有不同。此处的调度被定义为一个列表,其中包含 raw_wine_dataset

schedule = [raw_wine_dataset]

这意味着,每当 raw_wine_dataset 这个数据集发生变化时,当前任务就会自动被触发执行。这非常完美,它使得我们可以依赖数据生产者的动作:一旦数据就绪,消费者任务便能可靠地启动。

任务执行环境与处理逻辑

与生产者任务类似,我们将继续依赖虚拟环境,并安装pandas库以进行数据处理。

以下是任务将要执行的核心处理步骤:

  1. 数据来源变更:我们不再从网络位置获取原始的葡萄酒数据。因为可以确信 raw_wine_dataset 已被成功获取并存于本地,所以我们将直接从本地文件系统读取。
  2. 数据清洗:我们将对数据进行两项主要的清洗操作。
    • 移除回车符和换行符等特殊字符。
    • 删除“grape”列,因为该列充满了“非数字”值。
  3. 数据保存:清洗完成后,数据将被保存到本地文件系统,路径为 clean_data.csv
  4. 数据集注册:在任务最后,我们需要调用相应方法,将生成的新数据集正确注册到Airflow中,以便可能触发下游的其他任务。

理解数据集与可视化依赖

最后,我想展示Airflow中数据集的可视化管理功能。

在Airflow界面中点击“Datasets”菜单。这里的关键在于,raw_wine_dataset 这样的字符串主要是一个标识符。最重要的功能是Airflow提供的可视化视图。

这个视图清晰地展示了任务间的数据依赖关系:

  • wine_dataset_get 任务生产了 raw_wine_dataset 数据集。
  • wine_consumer 任务消费了 raw_wine_dataset 数据集。

你可以点击数据集图标查看其生产者与消费者,也可以点击任务图标查看其依赖的DAG图。这为理解和监控数据流水线提供了极大的便利。

总结

本节课中我们一起学习了如何在Apache Airflow中创建基于数据集触发的数据消费者任务。我们了解了如何通过定义 schedule=[dataset] 来实现任务间的数据驱动依赖,探讨了在消费者任务中进行数据清洗(如移除特殊字符、删除无效列)和保存的流程,并学会了在Airflow的Datasets界面可视化地查看任务与数据集之间的生产-消费关系。这种模式是实现可靠、自动化数据流水线的核心机制之一。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P38:在用户界面中检查结果 🧐

在本节课中,我们将学习如何触发并运行之前构建的数据处理流程,并在Airflow的用户界面中检查任务的执行结果与输出数据。

上一节我们完成了数据处理DAG的构建,本节中我们来看看如何实际运行它并验证结果。


现在,我们已经将所有组件整合在一起,可以开始触发流程了。

我们将再次使用数据生产者和消费者。数据生产者(有时也称为生产者)将生成我们要处理的数据,而消费者则会处理数据生产者的输出。

首先,我们需要启用消费者任务。它不会自动触发,因为它的触发器依赖于一个数据集。因此,我们先启用它。

接着,我们转到wine_dataset任务并启用它。

然后,我们在此处手动触发这个DAG。这是它的首次运行。

任务正在运行。我们可以点击此处查看状态,显示运行成功。

现在,我们应该能够查看其他DAG的运行情况。我们快速向下滚动,可以看到消费者任务已被触发,并且状态从“运行中”变为“已完成”。

本质上,这里发生的过程是:我们触发了数据获取任务,而wine_dataset消费者任务基于我们之前定义的数据集依赖关系被成功触发。

接下来,让我们详细检查wine_dataset消费者任务。它运行正确。

我们查看任务详情。状态为成功,一切运行正常。

我们再尝试查看审计日志。日志看起来也没问题。

这表明任务已正确完成。要查看实际的执行日志,需要进入具体的任务实例。一个DAG可能包含多个任务,在本例中,我想检查这个任务。

如果我点击这里的“日志”按钮。

我将看到完整的日志输出。日志显示正在收集pandas数据,这表明我们在检查任务是否正确执行。

在这个案例中,任务没有返回任何输出,这看起来是正确的。

为了检查生成的文件,我将快速切换到终端。在我的终端中,我将列出Airflow工作目录下的内容。根据之前的设置,输出文件将保存在此。

我将进入datasets目录,并列出其内容。

现在,我将看到两个CSV文件。一个是清洗后的数据集,另一个是原始的葡萄酒数据集。两个文件内容相似。

为了查看原始数据集的前几行,我使用以下命令:

head -n 20 raw_wine_dataset.csv

原始数据集中,某些字段可能为空。例如,在两个逗号之间没有任何内容,代表该字段值为空(NaN)。

现在,让我们查看清洗后的数据集。

使用命令查看清洗后的数据:

head -n 20 clean_wine_dataset.csv

我们将看到,清洗后的数据集中,grape(葡萄品种)字段已被删除。如果我们滚动到原始文件的顶部,会发现grape字段是存在的。

这验证了我们之前定义的数据清洗逻辑:grape字段在清洗过程中被成功移除了。


以上就是在用户界面中检查结果的基本方法。你通过UI检查任务状态、日志,并通过检查生成的文件来验证数据处理逻辑。

需要记住的是,在本演示中,我们将结果数据集保存在了本地磁盘上。在生产环境中,你很可能需要将这些数据集注册到云端环境(如AWS S3、Databricks等)或其他远程存储中,而不是像这里一样保存在本地文件系统。


本节课中我们一起学习了如何触发Airflow DAG、在Web UI中监控任务执行状态、查看日志,并通过检查生成的输出文件来验证数据处理流程的正确性。这是确保数据流水线按预期工作的重要步骤。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P39:39_02_09_总结_3

概述 📋

在本节课中,我们将总结如何构建一个数据处理流水线。我们将回顾流水线的核心组成部分,并探讨如何将所学知识应用于更复杂、更健壮的生产环境。

流水线构建回顾 🔄

上一节我们介绍了数据处理流水线的概念。本节中,我们来看看我们是如何将一系列任务组合成一个完整流水线的。

我们成功地将一个流水线组合在一起。这个流水线由不同的任务分组构成。在本案例中,它包含了几个任务。一个任务是从远程位置检索数据。然后我们进行了一些数据转换。我们能够将最终的数据集保存到文件系统中。

需要指出的是,在生产环境中,可能不会依赖单个主机在本地保存数据。你可能会将数据保存到远程位置。这可能来自某个云服务提供商,在众多提供商中选择一个。你当然可以将数据保存到远程文件系统。

核心知识与未来应用 🚀

现在,关于如何创建流水线的基础知识,使你能够灵活调整我们已涵盖的某些部分。正如我提到的,你可以将数据保存到远程实例,而不是本地保存。通过分离关注点,这实际上是流水线之所以有用的原因,你将能够在未来创建更健壮、更复杂的流水线。

以下是构建流水线时需要考虑的几个关键点:

  • 任务模块化:将数据检索、转换和保存等任务分离。
  • 存储灵活性:基础流水线支持从本地存储切换到云存储等远程系统。
  • 关注点分离:这是设计健壮流水线的核心原则,允许各部分独立演进和替换。

总结 ✨

本节课中我们一起学习了构建一个基础数据处理流水线的完整过程。我们回顾了从数据获取、转换到保存的核心步骤,并理解了通过模块化设计和关注点分离,可以将此基础模式扩展至更复杂的生产环境。掌握这些基础知识是未来设计高效、可靠数据流水线的关键。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P40:选择合适数据库 🗄️

在本节课中,我们将学习如何为构建在大型语言模型之上的系统选择合适的数据库技术。数据库的选择是系统架构中的关键决策,直接影响应用的性能、可扩展性和开发效率。

概述

构建新系统时,最重要的事项之一是考虑正确的数据库技术。数据库有多种不同的类别,从SQL到NoSQL,再到新兴数据库和分析平台。我们将逐一探讨它们的特点和适用场景。

SQL数据库

上一节我们概述了数据库的重要性,本节中我们首先来看看SQL数据库。SQL数据库采用具有固定模式的关系模型,支持ACID事务。这意味着你关心数据的一致性,并且需要进行复杂的连接和聚合操作。

以下是SQL数据库的一些关键特性:

  • 关系模型与固定模式:数据以表格形式组织,结构预先定义。
  • ACID事务:保证原子性、一致性、隔离性和持久性。
  • 复杂查询:擅长处理涉及多表连接和聚合的复杂查询。

一些常见的SQL数据库示例包括MySQL、PostgreSQL和SQL Server。

这里有一个特例是SQLite。它是一个独立的数据库,能够处理高达三分之一PB的海量数据。它常用于移动应用程序,对于数据科学家进行独立项目也非常有用。

NoSQL数据库

了解了强调一致性的SQL数据库后,我们来看看NoSQL数据库。NoSQL数据库非常灵活,你无需担心模式问题。它们更侧重于可用性和可扩展性。

在CAP定理中,我们需要在一致性和可用性之间做出权衡。对于NoSQL数据库,我们更关心可用性。因此,这些数据库通常是最终一致性的数据源。

NoSQL数据库有多种数据模型,具体取决于所选数据库。以下是其主要数据模型:

  • 键值模型:如Redis。
  • 文档模型:如MongoDB。
  • 列式模型:如Cassandra。

一些NoSQL数据库的示例包括MongoDB、Cassandra和Redis。

新兴数据库

除了传统分类,我们还拥有一些非常有趣的新兴数据库,它们提供了新的特性。这些数据库为解决特定类型的问题提供了更优的方案。

图数据库

图数据库是新兴数据库的一种形式。你可以将数据存储在由边连接的节点中。它能够对社交网络等关联数据进行优化,并支持非常强大的遍历查询。

一些图数据库的示例是Neo4j和Neptune。我个人认为它们非常令人兴奋的一点是能够提供诸如中心性、PageRank等新型描述性统计。因为数据以图的形式存在,你可以用不同于传统数据(如中位数)的方式来理解和沟通数据。

向量数据库

向量数据库也很有趣,它们能够深入处理不同类型的数据集。例如,如果你想构建推荐引擎,向量数据库可能是一个绝佳选择,因为它可以即时找出所有特征之间的相关性。

此外,对于任何类型的机器学习问题,你都可以使用向量数据库来优化某些工作流程。因此,它们也是许多新兴机器学习用例的一个新兴选择。

分析平台

最后,我们来看分析工作流平台。在这个领域,主要有两大竞争者:Databricks和Snowflake。

它们提供针对分析优化的列式存储、内存缓存以加速查询,以及高级分析函数。再次举例,Snowflake、BigQuery和Redshift都具备将分析作为平台服务的能力,其中一些(如Databricks和Snowflake)还支持跨云部署。

总结

本节课中,我们一起学习了如何为LLM应用选择合适的数据库。我们探讨了SQL数据库(强调一致性和复杂查询)、NoSQL数据库(侧重灵活性和可扩展性)、新兴数据库(如图数据库和向量数据库,为特定问题提供新特性)以及分析平台(为大规模数据分析优化)。理解这些数据库类别的特点和适用场景,是设计高效、可扩展系统架构的基础。

大型语言模型实践:P41:什么是向量数据库及其工作原理 🧠

在本节课中,我们将学习向量数据库的基本概念、工作原理以及它的常见应用场景。向量数据库是处理高维数据(如文本、图像嵌入)的核心工具,尤其在语义搜索、推荐系统和生成式AI等领域发挥着关键作用。

向量数据库的定义与核心功能

向量数据库的核心功能是存储和查询向量索引。具体而言,你可以对向量数据库中的内容执行近似最近邻搜索

执行此操作的原因是,你可以根据余弦相似度内积等度量标准,找出与查询向量最相似的向量。其公式可以表示为:

相似度 = 查询向量 · 数据库向量 / (||查询向量|| * ||数据库向量||)

这允许在存储向量的同时存储元数据,并赋予你过滤结果的能力。这种数据库能够处理高维度和大规模数据,并且可以利用分布式存储和处理技术。

向量数据库的常见应用场景

基于其向量处理能力,向量数据库催生了许多新型应用。以下是其主要应用场景:

  • 语义搜索:使用自然语言进行查询,然后返回相关的文档或特定产品。这基于查询和文档嵌入向量的语义相似性。
  • 推荐引擎:基于用户行为或物品属性的学习到的向量表示,寻找相似的用户或物品。
  • 异常检测:根据向量空间中与最近邻的偏差来识别异常值。
  • 药物发现:为候选药物寻找具有相似向量表示的分子。
  • 图像搜索:基于视觉向量嵌入返回相似的图像。
  • 聊天机器人:存储对话历史以实现个性化交互。

向量数据库生态与发展

随着大型语言模型和生成式AI的兴起,向量数据库领域变得异常活跃。市场上涌现了许多专门的向量数据库,例如 Pinecone、Quadrant、Milvus 等,它们都在为高效处理向量数据提供解决方案。


本节课中,我们一起学习了向量数据库的核心原理及其在语义搜索、推荐系统等多个领域的应用。理解向量数据库是掌握现代AI数据工程,特别是处理非结构化数据和构建智能应用的重要基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P42:42_03_04:实现语义搜索 🧠🔍

在本节课中,我们将要学习如何为初学者实现一个简单的语义搜索系统。我们将使用Quadrant向量数据库,通过一个具体的例子来演示如何存储文本数据、生成向量嵌入,并基于语义相似性进行查询。


环境准备与安装 📦

首先,我们需要确保拥有运行本教程所需的所有软件包。以下步骤将指导你完成环境设置。

以下是安装所需依赖的步骤:

  1. 确保你有一个类似Codespaces的代码环境。
  2. 项目通常包含一个 requirements.txt 文件来列出所有依赖。
  3. 运行 make install 命令来安装所有被锁定的依赖包。

安装完成后,我们就可以在Python环境中开始工作了。


导入必要的库与模型 🤖

上一节我们准备好了环境,本节中我们来看看需要导入哪些核心库和模型来启动我们的语义搜索项目。

首先,我们需要导入Quadrant的客户端以及用于生成文本嵌入的模型。

# 导入Quadrant客户端
from qdrant_client import QdrantClient
# 导入用于生成句子嵌入的模型
from sentence_transformers import SentenceTransformer

准备数据与嵌入模型 📚

现在,我们将准备要存入数据库的数据,并初始化用于将文本转换为向量的嵌入模型。

我们需要一个包含书籍信息的列表,每本书都有元数据,如名称、作者、出版年份和简短描述。

# 定义书籍数据
book_metadata = [
    {
        "name": "The Hitchhiker's Guide to the Galaxy",
        "author": "Douglas Adams",
        "publication_year": 1979,
        "description": "A comedy science fiction series."
    },
    {
        "name": "Dune",
        "author": "Frank Herbert",
        "publication_year": 1965,
        "description": "A epic science fiction novel about desert planet."
    },
    {
        "name": "The Three-Body Problem",
        "author": "Liu Cixin",
        "publication_year": 2008,
        "description": "A hard science fiction novel about alien invasion."
    }
]

# 初始化嵌入模型
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')

创建向量数据库集合 🗃️

在将数据存入向量数据库之前,我们需要创建一个“集合”(Collection)来组织这些数据。集合是Quadrant中组织数据的基本单位。

以下是创建集合的关键步骤:

  1. 指定存储位置。对于本交互式演示,我们使用内存存储。
  2. 调用 recreate_collection 函数来创建或重置名为“my_books”的集合。
  3. 定义向量维度和用于计算向量间距离的度量方法。
# 创建Qdrant客户端(使用内存存储)
client = QdrantClient(":memory:")

# 创建或重新创建集合
client.recreate_collection(
    collection_name="my_books",
    vectors_config={"size": 384, "distance": "Cosine"} # 向量大小和距离度量
)

说明

  • recreate_collection 在多次运行脚本进行实验时非常有用,它会尝试删除已存在的同名集合。
  • vectors_config 中的 size 参数定义了集合中向量的维度。
  • distance 参数指定了用于衡量两个向量点之间距离的函数,这是向量数据库的核心优势之一。

上传数据到集合 ⬆️

集合创建好后,接下来我们需要将准备好的书籍数据转换为向量并上传到数据库中。

我们将遍历书籍列表,使用嵌入模型为每本书的描述生成向量,然后将向量和对应的元数据(载荷)一起上传。

# 上传数据到集合
for book in book_metadata:
    # 为书籍描述生成向量嵌入
    vector = embedding_model.encode(book["description"]).tolist()
    # 准备载荷(即原始的元数据)
    payload = book
    # 将向量和载荷上传到集合中
    client.upsert(
        collection_name="my_books",
        points=[{"id": id(book), "vector": vector, "payload": payload}]
    )

执行语义搜索查询 ❓

数据上传完毕,现在我们可以进行语义搜索了。我们将把一个查询语句转换为向量,然后在数据库中查找与之最相似的书籍向量。

让我们首先搜索与“外星人入侵”相关的书籍。

# 定义搜索查询
query = "alien invasion"
# 将查询文本转换为向量
query_vector = embedding_model.encode(query).tolist()

# 在集合中搜索最相似的向量
hits = client.search(
    collection_name="my_books",
    query_vector=query_vector,
    limit=3  # 返回最相似的3个结果
)

解析与展示搜索结果 📊

上一节我们执行了搜索查询,本节中我们来看看如何解析返回的结果并理解其含义。

搜索返回的结果列表(hits)中包含了最相似的条目,每个条目都有其关联的元数据(载荷)和一个相似度分数。

以下是遍历和打印搜索结果的代码:

# 遍历并打印搜索结果
print(f"查询: '{query}'")
for hit in hits:
    print(f"书名: {hit.payload['name']}")
    print(f"描述: {hit.payload['description']}")
    print(f"相似度分数: {hit.score:.4f}")
    print("-" * 30)

结果分析
搜索引擎会返回与原始查询最相关的几个响应。每个响应都附有一个分数,用以表明该响应与原始查询的接近程度。例如,对于“外星人入侵”这个查询,最相关的结果很可能是《三体》这类书籍。


进行更精确的过滤搜索 🎯

向量数据库的强大之处在于可以结合向量搜索和元数据过滤。例如,我们想查找“2000年代初期出版的、与未来科技相关”的书籍。

我们可以构建一个同时包含向量查询和过滤条件的搜索。

# 新的查询:关注2000年代早期的书籍
query_2 = "future technology"
query_vector_2 = embedding_model.encode(query_2).tolist()

# 执行带过滤条件的搜索
hits_2 = client.search(
    collection_name="my_books",
    query_vector=query_vector_2,
    query_filter={"must": [{"key": "publication_year", "range": {"gte": 2000}}]}, # 过滤2000年之后出版的书籍
    limit=3
)

# 打印结果
print(f"查询: '{query_2}' (过滤: 2000年后出版)")
for hit in hits_2:
    print(f"书名: {hit.payload['name']} ({hit.payload['publication_year']})")
    print(f"描述: {hit.payload['description']}")
    print(f"相似度分数: {hit.score:.4f}")
    print("-" * 30)

这次,结果可能会更精确地指向像《三体》(2008年出版)这样的书籍。


总结 🎓

本节课中我们一起学习了语义搜索的基本实现流程。我们从环境配置开始,逐步完成了数据准备、向量数据库集合创建、数据上传,并最终执行了简单的语义搜索和结合元数据的过滤搜索。通过这个使用Quadrant数据库的示例,你可以看到,向量数据库能够高效地根据语义相似性查找信息,并且由于其底层使用Rust编写,具备非常快的速度。你可以尝试使用其提供的Python或Rust客户端,继续探索和构建更复杂的搜索应用。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P43:43_03_05_Qdrant快速入门

在本节课程中,我们将学习如何为向量搜索引擎Qdrant配置和使用Rust客户端。我们将从克隆代码库开始,启动本地数据库,并运行一个示例查询程序来验证整个流程。

介绍Qdrant Rust客户端

上一节我们介绍了向量数据库的基本概念,本节中我们来看看如何实际操作一个具体的向量搜索引擎——Qdrant。Qdrant是一个向量搜索引擎,幸运的是,由于它是用Rust语言编写的,因此对Rust客户端有很好的支持。

要使用这个客户端,你只需要执行以下命令来添加依赖:

cargo add qdrant-client

如果我们查看项目的依赖,会发现它只依赖了很少的库,例如tonic库。

准备开发环境

为了开始使用,我们需要先克隆代码库,然后运行后端服务。

以下是准备步骤:

  1. 首先,确认你已经获取了代码库的路径。
  2. 克隆HPS代码库。我已经将其克隆到本地。
  3. 进入Rust客户端目录,可以使用git remote -v命令确认。

进入目录后,因为这是一个Cargo项目,我们可以轻松地运行示例程序。

启动Qdrant数据库

在运行客户端之前,我们需要先启动Qdrant数据库服务。

我们将使用Docker来启动数据库。执行以下命令:

docker run -p 6333:6333 qdrant/qdrant

这个命令会在本地启动Qdrant数据库。在GitHub Codespaces环境中运行这类服务非常方便,你可以直接在这里启动它。如果需要,你还可以查看仪表板以获取更多信息。

运行Rust客户端示例

对于Rust项目,运行示例程序非常简单。我们首先可以查看示例代码examples/search.rs。这个文件包含了一个主函数,由于使用了Tokio运行时,它被标记为async。该函数会对一个集合执行搜索操作。

运行Rust示例的标准方法是使用Cargo命令。

以下是运行示例的具体命令:

cargo run --example search

我们回到终端,粘贴并执行这个命令。请注意,Docker容器正在前台运行,我们需要打开另一个终端来执行客户端命令。

现在,我们将能够运行查询。你可以看到程序在反复执行查询。它实际上使用的是本地的Docker接口,并且配置了Actix运行时,监听在HTTP端口上。

总结

本节课中我们一起学习了为Qdrant配置Rust客户端的完整流程。整个过程非常直接:克隆代码库、运行Docker容器、使用Cargo运行示例程序,之后你就可以顺利开始使用了。通过这个实践,我们掌握了在本地环境中快速搭建和测试向量搜索服务的基本方法。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P44:44_03_06_Qdrant Rust客户端 🦀

在本节课中,我们将学习如何使用 Rust 客户端连接和操作 Qdrant 向量搜索引擎。Qdrant 是一个高效的向量相似性搜索数据库,而 Rust 客户端因其原生支持而性能优异。

概述

我们将从安装 Rust 客户端依赖开始,然后启动 Qdrant 服务的 Docker 容器,最后运行一个示例程序来执行向量搜索查询。整个过程旨在展示 Rust 生态系统中集成向量数据库的便捷性。

安装与依赖管理

上一节我们介绍了 Qdrant 的基本概念,本节中我们来看看如何为其设置 Rust 客户端。

首先,我们需要将 qdrant-client 添加为项目的依赖。这可以通过 Cargo 包管理器轻松完成。

以下是添加依赖的命令:

cargo add qdrant-client

观察项目的 Cargo.toml 文件,你会发现依赖项数量很少,主要包含了 tonic 等库。这表明客户端设计得轻量且高效。

获取代码并启动服务

为了运行示例,我们需要先克隆包含示例代码的仓库,并启动 Qdrant 后端服务。

以下是必要的步骤:

  1. 克隆 GitHub 仓库。
  2. 进入项目目录。
  3. 使用 Docker 运行 Qdrant 服务。

我们将使用以下 Docker 命令在本地启动 Qdrant 数据库:

docker run -p 6333:6333 qdrant/qdrant

在 GitHub Codespaces 这类环境中,你可以直接运行此命令来启动服务,这非常方便。

运行示例程序

现在 Qdrant 服务已在后台运行,我们可以专注于 Rust 客户端了。Rust 项目的一个优点是,可以轻松地运行特定的示例文件。

我们的目标是运行 examples/search.rs 文件。该文件包含一个异步的 main 函数,它使用 Tokio 运行时来连接 Qdrant 并对一个集合执行搜索查询。

以下是运行示例的命令:

cargo run --example search

执行此命令后,客户端将通过本地 Docker 容器的 gRPC 接口(默认位于 http://localhost:6333)与 Qdrant 通信,并反复执行预设的搜索查询。

总结

本节课中我们一起学习了 Qdrant Rust 客户端的完整使用流程。整个过程非常直接:克隆仓库、用 Docker 启动服务、然后通过 Cargo 运行示例程序。这充分展示了在 Rust 项目中集成向量搜索功能的便捷性。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P45:向量数据库架构 🏗️

在本节课中,我们将学习向量数据库的核心架构。我们将了解其各个关键组件如何协同工作,以实现高效、可扩展的相似性搜索,这对于AI服务、推荐引擎和检索增强生成(RAG)应用至关重要。

架构概览

向量数据库的架构旨在处理大规模向量数据的存储与检索。其设计核心是支持快速的相似性搜索,并具备水平扩展、高可用性和容错能力。

核心组件详解

上一节我们介绍了架构的整体概览,本节中我们将逐一深入解析每个核心组件。

客户端应用层

用户通过多种客户端应用与向量数据库进行交互。这些客户端提供了访问数据库功能的接口。

以下是主要的客户端类型:

  • SDK: 为不同编程语言提供的软件开发工具包,例如 PythonGoRust
  • CLI: 命令行界面,便于管理员进行脚本化操作和系统管理。
  • WebUI: 图形化网页界面,为用户提供直观的操作和管理体验。

代理与API服务层

客户端发出的请求首先到达一个HTTP代理层。该层负责请求的路由和转发。

代理将API请求导向gRPC服务。这个gRPC服务是整个系统的核心API端点,它通过gRPC协议暴露向量数据库的所有核心功能。

gRPC服务处理诸如创建集合、插入向量、执行搜索等操作。其核心逻辑可以概括为:

# 伪代码示例:gRPC服务处理搜索请求
def handle_search_request(query_vector):
    # 1. 接收查询向量
    # 2. 调用查询规划器
    # 3. 执行搜索并返回结果
    pass

查询处理与索引层

当一个搜索请求抵达gRPC服务后,服务会调用查询规划器。查询规划器负责优化查询策略,并将搜索任务分发到所有相关的向量索引和数据分片上。

向量索引是实现超高速相似性搜索的关键。它采用了高效的算法来组织向量数据。

以下是两种常见的索引算法:

  • HNSW (Hierarchical Navigable Small World): 一种基于图结构的近似最近邻搜索算法,在精度和速度之间取得了良好平衡。
  • PQ (Product Quantization): 一种量化方法,通过压缩向量来减少内存占用和加速距离计算。

存储与分布式协调层

为了支持海量数据,索引本身会被分片,并分布到多个节点上。分片机制使得索引能够随着数据增长而水平扩展。

每个索引分片需要可靠的底层存储,通常会依赖如 RocksDB 这样的高性能嵌入式键值存储引擎。

后台工作进程负责数据的摄取、索引的构建以及在节点间的分片复制。

最后,为了确保所有节点状态的一致性,系统会采用一种共识协议,例如 Raft。Raft协议保证了数据的最终一致性,使得数据在节点间复制,从而实现了高可用性和容错性。即使部分节点发生故障,整个系统也能保持运行。

总结

本节课中我们一起学习了向量数据库的完整架构。我们从用户交互的客户端开始,经过负责路由的代理层和核心的gRPC API服务,深入到了执行高效搜索的查询规划器与向量索引(如HNSW、PQ)。接着,我们了解了支撑可扩展性的数据分片、用于持久化存储的RocksDB,以及确保系统高可用与最终一致性的后台复制流程与Raft共识协议。这种专为AI时代设计的系统架构,是构建推荐引擎、RAG应用等服务的坚实基础。理解这些关键概念,有助于你在自己的组织中有效地部署和应用向量数据库。

大型语言模型实践:P46:动手实验:增强语义搜索 🔍

在本节课中,我们将学习如何扩展向量数据库的语义搜索功能。我们将通过一个动手实验,在预配置的环境中安装必要的工具、加载数据、创建向量索引,并执行带过滤条件的语义查询。

概述 📋

上一节我们介绍了向量数据库的基本概念。本节中,我们将通过一个具体的实验来实践增强语义搜索。实验将引导我们完成从环境搭建到执行复杂查询的全过程。

实验步骤详解

第一步:启动代码空间

首先,我们需要启动一个Github Codespace,这是一个预配置了实验环境的在线开发容器。

以下是启动步骤:

  • 点击提供的链接,在Github上启动Codespace。
  • 该环境包含一个开发容器配置文件(devcontainer.json)和一个Dockerfile。
  • Dockerfile已配置好Python虚拟环境,这意味着环境已准备就绪,无需额外设置。

第二步:安装依赖包

环境启动后,我们需要安装实验所需的Python包。

以下是安装方法:

  • 实验的依赖项已定义在requirements.txt文件中。
  • 通过运行make install命令,可以一键安装所有必要的包,包括quadrantsentence-transformers

第三步:准备数据

接下来,我们需要准备用于语义搜索的示例数据。

以下是数据准备方法:

  • 根据官方教程,我们需要创建一个books.py文件。
  • 在该文件中,定义一个包含多本图书元数据的字典列表。每个字典代表一本书,包含如标题、描述、出版年份等信息。

第四步:创建向量集合与索引

数据准备好后,我们将在向量数据库中创建集合并构建索引。

以下是关键操作:

  • 按照教程指示,初始化一个内存中的quadrant数据库实例。
  • 使用sentence-transformers模型将图书描述文本转换为向量。
  • 将这些向量及其元数据(如图书标题、年份)插入到创建的集合中,并建立向量索引以支持快速检索。

第五步:执行语义查询与过滤

最后,我们将利用构建好的向量数据库执行语义搜索。

以下是查询过程:

  • 执行语义查询:输入一段关于图书内容的自然语言描述,系统将返回语义上最相关的图书。
  • 添加元数据过滤:修改查询,使其在语义匹配的基础上,增加对元数据(如“仅返回近年出版的书籍”)的过滤条件,从而得到更精确的结果。

进阶挑战 🚀

完成基础实验后,你可以尝试以下挑战来深化理解:

  • 使用更大数据集:例如,尝试使用维基百科文章摘要作为数据源。
  • 性能基准测试:比较不同向量维度大小对搜索性能和精度的影响。
  • 应用多重过滤:在查询中同时添加多个元数据过滤条件,例如按作者和年份组合筛选。
  • 可视化向量:使用主成分分析(PCA)等降维技术,将高维向量可视化,直观观察语义空间的分布情况。

总结

本节课中,我们一起学习了如何增强向量数据库的语义搜索功能。我们从启动预配置的实验室环境开始,逐步完成了依赖安装、数据准备、向量索引构建,最终实现了支持元数据过滤的语义查询。这个实验环境配置完善,为你进一步探索和优化向量数据库应用提供了良好的起点。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P47:图数据模型与数据库概念

在本节课中,我们将要学习图数据库的核心概念。我们将探讨图数据库的定义、关键特性、组成部分以及典型应用场景,帮助你理解为何以及何时应选择图数据库来处理数据。

图数据库概述

图数据库是一种专门用于存储和处理图结构数据的数据库。它擅长揭示数据点之间复杂的关系和模式,这是传统关系型数据库难以高效完成的。

上一节我们介绍了图数据库的基本概念,本节中我们来看看图数据库的五个关键特性。

以下是评估图数据库时需要关注的五个关键点:

  1. 以图格式存储数据:图结构由节点属性组成。这种结构支持进行传统数据难以实现的描述性统计分析,例如中心性分析最短路径查找PageRank算法(常用于搜索引擎排名)。
  2. 为高度互联的数据和复杂关系优化:图数据库非常适合提出涉及多重关系的复杂问题,例如“与这个人关联的第二层联系人中,谁最有可能执行某个特定操作?”
  3. 灵活的架构:与需要预先定义完整结构的SQL数据库不同,图数据库的架构是灵活的。你可以动态地更改结构,并根据要执行的查询进行优化。
  4. 通过遍历关系进行查询:查询通过遍历节点之间的关系来执行,这再次使我们能够获得各种强大的描述性统计结果。
  5. 支持特定查询语言和API:图数据库通常使用专门的查询语言(如Cypher)和面向编程语言的API,可以以独立或分布式方式部署。

为何使用图数据库?

了解了图数据库的特性后,我们来看看它的典型应用场景。图数据库在需要深入分析实体间关系的领域尤为强大。

图数据库的传统用例包括分析社交网络、构建知识图谱以及实现推荐系统。

图数据库的核心组件

为了更深入地理解图数据库的工作原理,我们需要明确其基本构成要素。

以下是图数据库的三个核心组件:

  • 节点:代表实体,例如地点事物
  • :代表节点之间的关系。
  • 属性:节点和边都可以拥有属性,用于存储具体的数据。

在查询时,我们使用图遍历来收集相关联的数据,这正是图数据库强大分析能力的基础。

本节课中我们一起学习了图数据模型与数据库的概念。我们了解了图数据库以节点、边和属性存储数据,擅长处理高度互联的关系,并拥有灵活的架构。其典型应用包括社交网络分析、知识图谱和推荐系统。掌握这些概念是理解和运用图数据库进行高级数据分析的第一步。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P48:Amazon Neptune简介 🗄️

在本节课中,我们将要学习Amazon Neptune,这是AWS生态系统内构建的一个快速、可靠的图数据库服务。我们将了解其核心特性、如何启动实例,以及如何通过不同的工具与其进行交互。

什么是Amazon Neptune?

Amazon Neptune是AWS提供的一项完全托管的图数据库服务。它专为处理高度互联的数据而设计,支持流行的图查询语言,并深度集成在AWS生态系统中。

上一节我们介绍了图数据库的概念,本节中我们来看看Amazon Neptune的具体实现和操作方法。

启动Neptune实例

首先,我们需要在AWS控制台中启动一个Neptune实例。启动界面提供了两种主要选项:预置型(Provisioned)和无服务器型(Serverless)。

以下是启动时需要考虑的关键配置选项列表:

  • 数据库类型:选择“预置型”或“无服务器型”。无服务器模式无需自行管理集群,是一个巨大的优势。
  • 使用场景:选择“开发测试”或“生产”。在生产环境中,系统默认会在不同可用区创建读副本以保障高可用性。如果仅是测试,则无需此配置。
  • 网络连接:选择要连接的VPC(虚拟私有云)。
  • 安全组:可以选择使用现有的VPC安全组或创建新的安全组来管理访问权限。

完成所有配置并启动实例后,下一步就是探索如何与数据库进行交互。

使用Notebook进行交互

Neptune提供了Notebook功能,允许你连接并操作图数据库。这些Notebook运行在独立的生态系统中,并深度集成于Amazon SageMaker。

打开Notebook后,你会看到几种不同的界面选项:

  • Jupyter:传统的Jupyter Notebook界面。
  • JupyterLab:功能更丰富的下一代Jupyter界面。
  • Graph Explorer:专用于图数据库可视化的工具。

让我们首先点击Jupyter。进入后,导航到Neptune目录,这里提供了一系列入门教程Notebook。

以下是入门Notebook提供的一些核心学习路径:

  • 入门示例:“hello world”通常是第一个要运行的示例。
  • 查询方式:教程展示了如何使用多种方式与数据库通信,包括SparkGremlinopenCypher
  • 状态检查:你可以执行状态调用来查看集群的运行状态。
  • 图查询实践:甚至可以运行Gremlin查询来操作图数据。

使用Graph Explorer进行可视化

除了Notebook,另一个强大的工具是Graph Explorer。它提供了一个独特的视角来观察数据。

回到Neptune主界面,点击打开Graph Explorer。它的优势在于能够对连接到数据库中的图数据进行可视化展示。这对于理解和分析复杂的数据关系非常有帮助。

总结

本节课中我们一起学习了Amazon Neptune。总而言之,Neptune是托管在AWS上的一个图数据库服务。它提供了像Jupyter Notebook和Graph Explorer这样的传统工具,是在AWS平台上开始使用图数据库的一个绝佳方式。

图算法实战:P49:图算法:UFC图中的中心性(Rust实现)

概述

在本节课中,我们将学习如何使用图算法分析网络关系。具体来说,我们将探索中心性这一概念,并使用Rust语言实现一个分析UFC(终极格斗冠军赛)选手对战关系的案例。我们将计算接近中心性,这是一种衡量网络中某个节点到所有其他节点平均距离的指标。


图与中心性简介

上一节我们介绍了图算法的基本概念。本节中,我们来看看中心性这一具体度量指标。

许多从事数据科学工作的人都了解描述性统计。这是一种观察数据并获取中位数、异常值、均值或最大值等信息的方法。在图分析中,我们也可以进行类似的操作,但使用的是完全不同的度量标准。这里我们将关注中心性,更具体地说,是接近中心性。接近中心性是一个度量指标,它表示网络中一个节点到所有其他节点的平均距离。

为了使内容更有趣,我将使用UFC(终极格斗冠军赛)的数据。这个分析能够提供关于一名选手与其他选手交战情况的洞察。这里的“距离”指的是两个节点之间的最短路径。在当前语境下,即两名选手之间的比赛场次数。


项目设置与依赖

首先,让我们看看将要使用的库。这个库叫做 petgraph。以下是我的 Cargo.toml 文件配置,可以看到我已经导入了这个库。

[dependencies]
petgraph = "0.6"

数据结构定义

接下来,我们查看代码。这里我定义了一个结构体。初次看到结构体及其实现时可能会有点困惑,但它实际上与以下Python代码是等价的。在Python中,如果你要给一个对象添加一个 name 属性,在这里也是类似的。我添加了 fighter_name 属性。我还定义了一些用于显示的方法。

以下是定义节点(选手)数据结构的代码:

use std::fmt;

// 定义表示UFC选手的结构体
struct Fighter {
    name: String,
}

// 为Fighter实现Display trait,以便打印
impl fmt::Display for Fighter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}

构建图与添加关系

然后,我有一些用于添加边的代码。这样就能将边(对战关系)添加到图中。最后,我将所有部分整合在一起。

main 函数中,我创建了一个可变的图数据结构,然后将选手们添加进去。这些都是非常知名的UFC选手:Dustin Poirier, Khabib, Jose Aldo, Conor McGregor, Nate Diaz。他们在比赛历史上互有关联。

以下是构建图的主要步骤:

  1. 创建图对象:使用 petgraph 库的 Graph
  2. 添加节点:将每位选手作为节点加入图中。
  3. 添加边:根据历史对战记录,在对应的选手节点之间添加边,代表一场比赛。
use petgraph::graph::{Graph, NodeIndex};

fn main() {
    // 创建一个无向图
    let mut graph = Graph::<Fighter, ()>::new();

    // 添加选手节点
    let dustin = graph.add_node(Fighter { name: "Dustin Poirier".to_string() });
    let khabib = graph.add_node(Fighter { name: "Khabib".to_string() });
    let jose = graph.add_node(Fighter { name: "Jose Aldo".to_string() });
    let conor = graph.add_node(Fighter { name: "Conor McGregor".to_string() });
    let nate = graph.add_node(Fighter { name: "Nate Diaz".to_string() });

    // 添加对战关系(边)
    graph.add_edge(dustin, khabib, ()); // Dustin vs Khabib
    graph.add_edge(khabib, conor, ());  // Khabib vs Conor
    graph.add_edge(conor, dustin, ());  // Conor vs Dustin
    graph.add_edge(conor, jose, ());    // Conor vs Jose
    graph.add_edge(conor, nate, ());    // Conor vs Nate
    graph.add_edge(dustin, nate, ());   // Dustin vs Nate
    graph.add_edge(jose, nate, ());     // Jose vs Nate
}

这类似于任何涉及社交媒体或现实世界关系的网络分析。我们定义了以下对战关系:

  • Dustin Poirier 对阵 Khabib
  • Khabib 对阵 Conor McGregor
  • Conor McGregor 对阵 Dustin Poirier
  • Conor McGregor 对阵 Jose Aldo
  • Conor McGregor 对阵 Nate Diaz
  • Dustin Poirier 对阵 Nate Diaz
  • Jose Aldo 对阵 Nate Diaz

计算与解释中心性

接下来的这个循环,它的作用是计算每位选手的姓名、度中心性、接近中心性,然后打印出接近中心性的结果。

我还添加了一些基于中心性得分的解释说明。如果你是一名数据工程师、机器学习工程师或数据科学家,当你想创建一个自定义度量或图表时,这可能会是一种常见的做法。

以下是计算和输出结果的代码逻辑:

    // 计算并打印每位选手的接近中心性
    for node in graph.node_indices() {
        let name = &graph[node].name;
        let degree = graph.neighbors(node).count(); // 度中心性:连接数
        // 注意:此处为简化演示。petgraph库需要额外计算最短路径来求精确接近中心性。
        // 这里我们用 1.0 / (degree as f64 + 1.0) 作为一个简单的近似替代。
        let closeness_approx = 1.0 / (degree as f64 + 1.0);

        println!("{}: 度中心性 = {}, 接近中心性(近似) = {:.2}", name, degree, closeness_approx);

        // 根据选手名字添加解释
        match name.as_str() {
            "Conor McGregor" => println!("  解释: Conor McGregor的中心性最低,因为他与网络中所有其他选手都有过对战。较低的接近中心性意味着较高的交战数量。"),
            _ => {}
        }
    }

我匹配了名字“Conor McGregor”,我们可以看到他的中心性将是最低的,因为他与其他所有选手都有过比赛,等等。所以我根据中心性得分打印了解释。


运行结果与分析

让我们运行这个程序来查看实际效果。输入 cargo run,程序将运行并打印出结果。

运行程序后,我们可以看到类似以下的输出(数值为示例):

  • Dustin Poirier的接近中心性是0.33。
  • 然而,中心性最高(即数值最低)的是Conor McGregor,他的中心性是0.25。

Conor中心性最低的原因在于,他与网络中的所有其他选手都有过对战。因此,较低的接近中心性意味着较高的比赛数量。所以,在这个特定的关系网络中,这实际上是最好的得分。

我们可以看到,得分最差的是Khabib和Jose Aldo,他们的得分都是0.5,大约是Conor McGregor得分的两倍。而Dustin和Nate则并列第二名。


总结

本节课中,我们一起学习了如何使用图算法中的接近中心性来分析网络关系。我们通过一个UFC选手对战关系的具体案例,使用Rust语言和petgraph库构建图、添加节点与边,并计算了中心性指标。

这是一种非常有效的方法,可以用来计算那些对于现实世界关系、体育关系或社交网络来说真正独特的自定义度量指标。当然,你可以非常轻松地用Rust来实现它。这种方法的核心在于将复杂的关系网络抽象为图结构,并利用中心性等指标来量化网络中节点的重要性或影响力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P50:Kosaraju图社区检测 🕸️

在本节课中,我们将学习如何使用图算法进行社区检测。具体来说,我们将探索如何利用Kosaraju算法在社交网络数据中识别紧密关联的用户群体,例如在推特数据中发现“水军”社区。

上一节我们介绍了图数据库Neo4j在社区检测中的应用。本节中我们来看看如何用纯Rust代码实现一个高效的社区检测模块。

概述与背景

Neo4j图数据库曾用于检测2016年美国总统大选期间推特上的“水军”账号。我们基于这个想法,使用真实的推特数据混合部分假设数据,在Rust中实现了一个社区检测模块。

核心算法与数据结构

我们将使用Kosaraju算法来检测图中的强连通分量。这是本教程的核心技巧,它能有效识别图中紧密连接的节点群。

以下是算法依赖的关键库和数据结构:

use petgraph::algo::kosaraju_scc;
use petgraph::graph::DiGraph;
use std::collections::HashMap;

我们使用petgraph库来处理图结构和算法,并用HashMap来存储“谁与谁互动”的关系。

实现步骤详解

以下是构建和运行社区检测程序的主要步骤。

首先,我们创建图结构并存储节点索引。

let mut graph = DiGraph::<&str, ()>::new();
let mut node_indices = HashMap::new();

接着,我们迭代处理包含用户名数据的文件。文件格式是“用户”后跟着“提及的用户”。

for line in data_lines {
    let parts: Vec<&str> = line.split(',').collect();
    let user = parts[0];
    let mention = parts[1];
    // 添加节点到图和哈希映射中
}

然后,我们在代表“转发”关系的两个用户节点之间添加边。

graph.add_edge(user_idx, mention_idx, ());

最后,我们运行Kosaraju算法来发现强连通分量,即检测到的社区。

let scc = kosaraju_scc(&graph);

运行与结果分析

运行程序非常简单。进入项目目录后执行以下命令:

cd community_detection
cargo run

程序输出会显示发现的社区。例如,它可能识别出三个记者账号(journalist1, journalist2, journalist3)因频繁相互转发而形成一个社区。同时,它也能找出2016年发现的真实“水军”账号群。我们额外添加的假社区数据则用于展示不同社区之间的区别。

对于每个发现的社区,我们可以打印其成员。你还可以添加更多描述性统计,例如节点数量,甚至为发现的社区动态生成名称。

for component in scc {
    println!("Discovered community: {:?}", component);
}

应用与优势

这种方法可以成为一个高效的运行时算法,适用于社交网络或拥有大量客户/用户的公司。你可以完全从零开始用Rust构建它,获得极佳的性能,甚至可以将其打包成二进制工具部署到生产环境中。

本节课中我们一起学习了如何利用Kosaraju算法进行图社区检测。我们从概念入手,逐步实现了数据读取、图构建、算法应用和结果分析的全过程。你掌握了使用Rust和petgraph库来识别复杂网络中紧密关联群体的实用技能。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P51:51_03_06_图的最短路径 🗺️

在本节课中,我们将学习如何使用 Rust 语言和 petgraph 库,通过 Dijkstra 算法 来寻找图中两个节点之间的最短路径。我们将以葡萄牙里斯本的两个地标为例进行演示。


概述

我们将使用一个名为 petgraph 的 Rust 图库,它内置了 Dijkstra 算法的实现。Dijkstra 算法是一种经典的图遍历算法,用于寻找从单个源节点到图中所有其他节点的最短路径。这意味着,如果我们有许多可以到达的不同位置,该算法可以找出需要遍历的最短节点序列及其实际距离。

构建图结构

首先,我们需要创建一个图并添加节点。我们将创建一个无向图,这意味着边没有方向,两个节点之间的连接是双向的。

以下是创建图并添加节点的代码:

use petgraph::graph::UnGraph;

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/bb48a0d1cc64aea5770e1858f3ba5577_2.png)

let mut graph = UnGraph::<&str, i32>::new_undirected();

let belem_tower = graph.add_node("Belem Tower");
let monastery = graph.add_node("Monastery");
let lisbon_cathedral = graph.add_node("Lisbon Cathedral");

在上面的代码中,我们初始化了一个无向图,并添加了三个节点,分别代表里斯本的三个地标。

添加边与权重

接下来,我们需要在节点之间添加边,并为每条边分配一个权重(在本例中代表距离)。这定义了节点之间的连接关系。

以下是添加边和权重的代码:

graph.extend_with_edges(&[
    (belem_tower, monastery, 1),
    (belem_tower, lisbon_cathedral, 8),
    (monastery, lisbon_cathedral, 7),
]);

这段代码创建了三条边:

  • Belem TowerMonastery,距离为 1。
  • Belem TowerLisbon Cathedral,距离为 8。
  • MonasteryLisbon Cathedral,距离为 7。

应用 Dijkstra 算法

现在图已经构建完成,我们可以使用 petgraph 库内置的 dijkstra 函数来计算最短路径。该函数会返回从源节点到所有其他节点的最短距离。

以下是计算最短路径的代码:

use petgraph::algo::dijkstra;

let node_map = dijkstra(&graph, belem_tower, Some(lisbon_cathedral), |e| *e.weight());

在这段代码中,我们调用了 dijkstra 函数,传入了图、起始节点(belem_tower)、目标节点(lisbon_cathedral)以及一个获取边权重的闭包。

获取并输出结果

最后,我们可以从结果映射中提取并打印出从 Belem TowerLisbon Cathedral 的最短距离。

以下是输出结果的代码:

if let Some(distance) = node_map.get(&lisbon_cathedral) {
    println!("The shortest distance from Belem Tower to Lisbon Cathedral is {} km.", distance);
} else {
    println!("No path found.");
}

运行程序后,输出结果将是:
The shortest distance from Belem Tower to Lisbon Cathedral is 8 km.

总结

本节课中,我们一起学习了如何使用 Rust 和 petgraph 库解决图的最短路径问题。我们首先构建了一个代表里斯本地标的无向图,然后为节点之间的连接添加了权重。接着,我们利用库中内置的 Dijkstra 算法高效地计算出了两个地标之间的最短距离。

这种方法的优势在于:

  1. 性能优异:Rust 能提供接近 C 语言级别的高性能。
  2. 内存安全:Rust 的所有权系统保证了内存安全,避免了常见错误。
  3. 部署简单:编译后的二进制文件可以轻松部署,资源占用极低。

通过解决这类经典问题,数据工程师或机器学习工程师可以将其应用于物流、路径规划等众多现实场景中,构建出既高效又可靠的解决方案。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P52:52_03_07_Rust CLI工具的关键组件

在本节课中,我们将学习如何使用 Rust 语言中的 clap 库来构建命令行界面工具。我们将了解 clap 如何简化参数解析、帮助信息生成和错误检查,从而使开发者能够专注于应用程序的核心逻辑。

概述

clap 是一个用于 Rust 的库,它提供了一种简单的方式来定义程序将接受的命令、参数和选项。通过 Rust 代码设置 clap,可以将命令行定义编译到最终的用户可执行程序中。当用户运行该程序并传入文本形式的命令和选项时,clap 会解析这些输入,并将其转换为代码可以使用的结构化数据。

CLI 应用与 clap 的作用

命令行界面应用程序允许用户运行命令并传递选项。clap 库的核心作用是移除通常解析文本输入、处理帮助消息和进行错误检查所需的大量样板代码。最终结果是,用户可以通过终端获得一个良好的界面来控制应用程序,而 Rust 代码则可以专注于核心逻辑,而不是命令行解析。

上一节我们介绍了 clap 的基本概念,本节中我们来看看它的具体工作流程。

clap 的工作流程

下图展示了一个简单的工作流程。

以下是该流程的关键步骤:

  1. 定义阶段:开发者使用 Rust 代码设置 clap,定义程序接受的命令、参数和选项。
  2. 编译阶段:这个 CLI 定义会被编译到最终的程序可执行文件中。
  3. 运行与解析阶段:用户运行 CLI 应用程序,并传入文本形式的命令和选项。clap 解析这些输入。
  4. 逻辑执行阶段:你的主 Rust 代码从 clap 获取解析后的参数,并根据用户传入的内容执行预期的操作。

clap 的高级功能

事实上,clap 提供了丰富的选项。开发者不仅可以构建基本的命令和选项,还可以构建子命令和嵌套选项,以创建更复杂、功能更强大的命令行工具。

最后,构建在 target 目录中的二进制文件可以分发给用户使用。

总结

本节课中我们一起学习了 Rust clap 库在构建命令行界面工具中的关键作用。我们了解到,clap 通过将命令行定义集成到 Rust 代码中,自动化了参数解析、帮助生成和错误处理,极大地提升了开发效率。最终,它帮助开发者构建出用户友好、功能强大的终端应用程序,同时让代码逻辑更加清晰和专注。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P53:53_03_08_实验演练:构建Rust图CLI工具 🛠️

在本节课程中,我们将学习如何将一个现有的Rust图数据库项目,转换成一个功能更强大、更灵活的命令行界面工具。我们将通过添加参数解析、文件读取和结果输出等功能,使核心算法能够以更便携的方式被使用。

项目概述与目标 🎯

我们当前有一个图数据库项目。该项目包含一个用于检测社区的良好算法。

在这个特定的代码仓库中,我们的任务是将此项目转换为一个命令行工具。

这在用包括Rust在内的其他语言进行项目开发时非常常见。你通常希望将核心算法变得更便携、更灵活,方法是在其之上添加一些命令行工具接口。

现有代码结构分析 🔍

如果我们查看这里的代码,我们需要完成以下步骤:添加clap工具库、添加解析器、添加一些参数、解析参数,然后读取文件并填充图数据。

这可以是任何外部图数据,你将在其中寻找某种类型的社区。

让我们看看这在Lib目录中是如何工作的。

我们有一些来自Twitter上一个知名实际“水军”接口的数据。我们能够识别出一组特定人群,并希望围绕他们创建一个社区。

下一步,在代码内部,我们实际上有能力创建一个新的有向图,其结构为HashMap。然后遍历数据以填充图,将用户添加到图中,最后找出如何检测强连通组件。

重申一下,这可以是任何你想要填充到此处的数据集,这就是为什么命令行工具会非常有用。

如何运行当前项目 🚀

首先,我们需要进入该目录。

然后我们可以使用cargo,只需输入cargo run。这将进行编译,并在最后打印出此代码的一个静态版本。

我们可以看到输出:“3个节点在社区中发现:journalist1, Journal2, Journal3”,以及“10个节点在社区中发现”。这表明它能够在这里找出两种不同类型的社区,并将所有结果排序输出。

实验任务:增强工具功能 📝

你在这个特定实验中的任务是,通过以下方式使其更具便携性,以便你能灵活地使用不同种类的选项。

以下是你可以实现的功能列表:

  • 你可以尝试加入新的算法。
  • 你也可以研究如何输入新的数据。
  • 最后,当你完成后,可以定制输出格式,例如文本或JSON。
  • 添加一个可选的CI参数。
  • 允许接受多个输入。
  • 支持从标准输入读取数据。
  • 添加子命令,例如analyze(分析)、visualize(可视化)等。
  • 将输出保存到特定文件。
  • 甚至可以在处理过程中添加日志输出。

祝你好运。

本节总结 📋

本节课我们一起学习了如何将一个Rust图分析项目改造为命令行工具。我们分析了现有代码的结构和运行方式,并明确了实验任务:通过集成clap库解析参数、支持多种数据输入输出方式以及添加子命令等功能,来提升核心算法的便携性和灵活性。掌握这项技能有助于你将任何核心算法封装成易于使用的工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P54:学习用于DynamoDB开发的AWS CloudShell 🐚

在本节课中,我们将要学习AWS CloudShell,这是一个在开发和配置工作中常被忽视但功能强大的工具。我们将探索如何利用它来高效地管理Python环境、以编程方式操作AWS服务(如DynamoDB),并通过自定义别名来优化工作流程。


AWS CloudShell是AWS控制台内嵌的一个被严重低估的开发和配置资源。你可以在任何控制台用户界面中开启或关闭它。

接下来,让我们看看它的一些有趣功能。你可以看到,我停用了一个Python虚拟环境。例如,如果你想在每次登录Shell时自动加载特定的Python代码集,你可以使用这里的VI编辑器。

你可以查看你的.bashrc文件,并设置每次登录Shell时自动激活一个Python虚拟环境。这非常有用。例如,如果我在这里输入source ~/.bashrc,你会看到它现在加载了这个Python虚拟环境。

这意味着,如果我想安装例如Boto3,我可以轻松地安装它并开始基于它进行开发。这本身已经相当酷了。

但还有另一件基于Shell可以做的事情。让我们先停用这个环境。那就是我还可以以编程方式与其他资源交互,例如DynamoDB。

我可以在这里做的一件事是创建一个新表。你可以看到,如果我想以编程方式创建一个表,目前这里没有表。让我们粘贴命令进去,我们可以看到aws dynamodb create-table命令。我创建了一个名为customers的表,然后我只需要执行它。

这将允许我通过这个CloudShell环境以编程方式开始构建东西。因此,这是一种非常方便的快速编程控制方式,因为AWS也提供了基于命令和工具的SDK。

然后,如果我想做一些事情,比如列出所有表,我可以输入aws dynamodb list-tables。这在开发时是一种非常高效的入门方式,你可以来回切换,将这些东西放入CloudShell中测试你的想法。在许多情况下,这比在图形界面中点击操作要快得多,甚至比在代码中开发还要快。

现在,让我们看看另一个技巧作为结尾。如果我们回到.bashrc文件,如果你发现自己反复执行很多命令,你可能想在这个文件中输入一些别名。

这样,每次你打开Shell时,它们都会自动加载。我们可以在这里设置一个别名。

我们创建一个名为listtables的别名。我们可以输入这个命令:aws dynamodb list-tables。实际上,我们想把它改成不是扫描表,而是列出表。

让我们保存这个文件。然后在这里刷新一下,输入source ~/.bashrc。现在,如果我们输入listtables,注意它会自动显示并补全。同样,如果我输入alias,它也会在这里显示出来,作为可用的别名之一。

如果我们运行它,我们现在就可以自动列出表了。因此,通过在CloudShell环境中创建别名,你可以在工作流程中引入许多关键的创新。对于开发者来说,在某些场景下,这可能是针对AWS服务进行开发最高效的方式。


本节课中我们一起学习了AWS CloudShell的核心用法。我们了解了如何将其用作一个快速的编程环境,包括管理Python虚拟环境、通过AWS CLI以编程方式操作DynamoDB等服务,以及通过自定义.bashrc文件中的别名来显著提升日常开发效率。掌握这些技巧,能让你的AWS开发和测试工作变得更加流畅和高效。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P55:55_04_04:学习用于Dynamo开发的AWS CodeCatalyst 🚀

在本节课中,我们将学习如何使用AWS提供的一款名为CodeCatalyst的集成开发工具。我们将了解如何创建云端开发环境,并集成CodeWhisperer等AI编程助手,从而高效地进行DynamoDB相关的开发工作。

登录与启动

首先,在AWS工具包中,我们可以看到包括CDK、CodeWhisperer以及CodeCatalyst在内的多个工具。要开始使用,我们需要点击启动按钮。

接下来,我们需要登录AWS Builder账户。点击“使用AWS Builder ID连接CodeCatalyst”选项,系统将引导我们完成登录流程。

登录成功后,我们可以在工具包中进行操作,例如克隆代码仓库、打开现有的开发环境,或者创建一个全新的环境。

创建开发环境

上一节我们介绍了如何登录,本节中我们来看看如何创建一个新的云端开发环境。

点击创建新开发环境的按钮后,我们会看到几个选项。

以下是创建环境时的关键配置选项:

  • 代码仓库:可以选择使用现有的CodeCatalyst仓库,或者创建一个空的开发环境。对于初次探索,从空环境开始是个不错的选择。
  • 空间与项目:需要选择一个可用的空间和项目。我们可以将其用作一个临时项目。
  • 环境别名:可以为环境设置一个别名,例如“delete me”,以便后续识别和清理。
  • 资源配置:默认配置提供2个CPU、4GB内存、16GB存储,并在闲置15分钟后自动超时关闭。这是一个经过精心设计的免费套餐配置。
  • 高级配置:如果为CodeCatalyst账户启用了计费,还可以选择启动配置更高的“大型”环境。

为了演示,我们选择创建一个更大的环境,然后点击“创建开发环境”。

连接与探索环境

创建过程完成后,系统会自动弹出一个新的Visual Studio Code窗口。这个窗口通过SSH自动连接到远程的云端机器,整个过程非常流畅和便捷。

现在,我们可以开始在这个环境中进行开发。首先,打开一个新的终端。

在终端中,我们可以输入 uname -a 命令来查看系统信息,确认它运行的是Amazon Linux。我们也可以输入 whoami 来查看当前用户,这与我们本地的操作系统用户是不同的。

集成CodeWhisperer

为了提升开发效率,我们可以在环境中集成AWS的AI编程助手CodeWhisperer。

在AWS工具包中,选择CodeWhisperer按钮。系统会提示我们进行登录授权,点击“使用AWS Builder ID连接CodeWhisperer”,并在浏览器中完成确认。

授权成功后,CodeWhisperer功能即被激活。现在,我们可以开始利用它来辅助编程。

使用AI辅助编程

要使用CodeWhisperer,我们只需创建一个新文件并开始编写代码。例如,创建一个名为 hello.py 的Python文件。

在文件中,我们可以尝试输入一些注释或代码片段。例如,输入 # hello world python,然后在新的一行输入 def hello():,CodeWhisperer可能会自动补全一个简单的“Hello World”函数。

同样,我们也可以创建Bash脚本来操作DynamoDB。创建一个新文件,输入 #!/bin/bash# scan table called customers 作为注释。然后,当我们开始输入 aws dynamodb scan 命令时,CodeWhisperer会提供相关的参数建议和补全。

通过这种方式,我们可以看到CodeCatalyst云端开发环境与CodeWhisperer AI编程助手的结合是一个非常强大的组合。它的设置过程简单,并且提供免费的套餐选项。当然,如果需要更强大的计算资源,也可以轻松启动更大的开发环境。

总结

本节课中我们一起学习了AWS CodeCatalyst的基本使用流程。我们从登录和创建云端开发环境开始,然后探索了如何通过SSH连接到该环境。接着,我们集成了CodeWhisperer AI编程助手,并演示了它如何辅助我们编写Python脚本和AWS CLI命令(例如针对DynamoDB的操作)。这套工具组合为云端开发提供了便捷、高效且智能化的体验。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P56:利用AWS CodeWhisperer进行Dynamo开发 🚀

在本节课中,我们将要学习如何利用AWS CodeWhisperer这一强大的AI编程助手来提升DynamoDB的开发效率。我们将了解其核心功能、安装配置方法,并通过一个具体的Bash脚本编写示例,展示它如何在实际开发中提供智能代码建议。

概述

Amazon CodeWhisperer是一个能够显著提升DynamoDB编程技能的工具。它提供无限的代码建议,完全免费,并且基于数十亿行代码进行训练,特别针对AWS工作流进行了优化。它是一个能极大提高生产力的优秀工具,支持包括Python、Rust、Bash在内的多种编程语言。

安装与配置

上一节我们介绍了CodeWhisperer的核心优势,本节中我们来看看如何在开发环境中启动并使用它。

在Visual Studio Code环境中,CodeWhisperer集成在AWS Toolkit扩展中。将鼠标悬停在扩展上,可以看到它提供了对CodeWhisperer、Code Catalyst以及Lambda、S3等服务的支持。

其便捷之处在于,我们可以直接在开发环境中启用它并进行各种设置。进入扩展设置,可以确认CodeWhisperer已安装,并查看关于如何使用它的建议。

如果需要确认其安装状态,可以在VS Code底部的状态栏查看。在AWS菜单中,可以找到CodeWhisperer的开关选项。将鼠标悬停其上,可以确认它已被选中。我们可以在此处停止或运行代码建议功能。

此外,CodeWhisperer还具备安全扫描功能,这有助于发现潜在的安全漏洞。另一个很酷的功能是代码溯源,它可以显示建议代码的来源,方便开发者参考和学习。

实践:使用CodeWhisperer编写Bash脚本

了解了基本配置后,我们通过一个具体的例子来看看如何在实际工作流中使用它。

以下是如何开始使用CodeWhisperer进行基于Bash的工作流开发。

首先,一个有趣的尝试是创建一个新的Bash脚本文件。我们可以先执行 git pull 获取最新代码,然后使用 touch 命令重新创建一个我之前已经构建过的系统脚本,我们将其命名为 scan_table.sh

查看这个文件时,我首先要做的是添加Shebang行(#!/bin/bash)。神奇的是,CodeWhisperer已经预知了我的意图并帮助我自动补全了这行代码。

它甚至能帮助我编写文档注释。例如,如果我输入注释“此脚本将扫描名为‘customers’的表”,CodeWhisperer会立即给出关于后续操作的代码建议。

先编写文档注释的好处在于,CodeWhisperer能据此自动生成实现相应功能的正确命令。在这个例子中,它为我生成了执行扫描表操作的命令。

我认为,开始使用CodeWhisperer最简单的方式之一就是深入Bash脚本编写,让它帮助你完成代码补全等工作。对于初学者来说,这可能是性价比最高的入门方式:如果AWS上的某项服务支持命令行接口,你就可以在此编写一些小型的Bash脚本,并让CodeWhisperer为你自动补全。你可以看到,这在提升生产力方面是一个巨大的胜利。

当然,你也可以用它来构建其他语言的项目。例如,我这里有一些Rust项目,你显然可以在Rust语言中使用它,同样也适用于Python等。

核心功能与总结

本节课中我们一起学习了AWS CodeWhisperer在DynamoDB开发中的应用。

最重要的收获是,如果你正在构建AWS相关的代码,使用CodeWhisperer的自动补全功能将带来巨大的效率提升。它还具有许多独特的功能,包括安全扫描,以及代码溯源,后者可以显示代码片段的原始出处。

核心优势公式可总结为:
开发效率提升 ≈ 智能补全 + 安全扫描 + 代码溯源

通过本教程,你应该已经掌握了如何配置CodeWhisperer,并理解了如何利用其智能建议来加速Bash脚本及其他语言的开发流程,从而更高效地进行DynamoDB及相关AWS服务的开发工作。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P57:57_04_06_使用CLI创建表

在本节课中,我们将学习如何使用AWS命令行界面(CLI)在DynamoDB中创建一个表。我们将通过一个具体的例子,演示创建名为“customers”的表的完整过程。

创建DynamoDB表的CLI命令

为了创建一个表,你可以使用AWS CLI的DynamoDB命令。以下是创建表所需的基本命令结构。

命令结构

aws dynamodb create-table --table-name <表名> --attribute-definitions <属性定义> --key-schema <键模式> --provisioned-throughput <预置吞吐量>

命令详解与执行

上一节我们介绍了创建表的基本命令结构,本节中我们来看看如何填充具体参数并执行命令。

以下是创建“customers”表的具体命令示例:

aws dynamodb create-table --table-name customers --attribute-definitions AttributeName=customerID,AttributeType=S --key-schema AttributeName=customerID,KeyType=HASH --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5
  • --table-name customers:指定要创建的表的名称。
  • --attribute-definitions AttributeName=customerID,AttributeType=S:定义表的主键属性。这里定义了一个名为“customerID”、类型为字符串(S)的属性。
  • --key-schema AttributeName=customerID,KeyType=HASH:指定键模式。这里将“customerID”属性定义为哈希(分区)键。
  • --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5:设置表的预置读写容量单位。

将上述命令复制到终端并执行。如果成功,命令行将返回一个JSON响应,确认表已创建。

在AWS管理控制台中验证

执行CLI命令后,我们可以通过AWS管理控制台来验证表是否已成功创建。

打开AWS Toolkit或直接访问AWS管理控制台,导航到DynamoDB服务。在资源列表中,你现在应该能看到新创建的“customers”表。点击该表,可以查看其详细信息,确认其配置(如主键、吞吐量设置)与我们通过CLI命令指定的完全一致。

本节课中我们一起学习了如何使用AWS CLI在DynamoDB中创建表。我们详细讲解了create-table命令的结构和关键参数,并演示了从执行命令到在控制台验证结果的完整流程。掌握CLI操作是进行高效数据工程管理的重要技能。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P58:批量记录填充表

在本节课中,我们将学习如何使用AWS DynamoDB的batch-write-item命令,通过一个JSON文件一次性向数据库表中填充多条记录。这种方法对于批量数据导入和更新操作非常高效。

概述

上一节我们介绍了DynamoDB的基本操作,本节中我们来看看如何执行批量写入操作。批量写入允许我们一次性添加或更新多个数据项,这比逐条写入要快得多。

批量写入操作详解

以下是执行批量写入的核心命令结构:

aws dynamodb batch-write-item --request-items file://your_file.json

在这个命令中,--request-items参数用于指定一个包含所有待写入记录的JSON文件。

JSON文件结构

为了确保批量写入成功,我们需要准备一个结构正确的JSON文件。这种方式的优点在于,你可以轻松地对JSON进行格式校验,确保数据结构无误。

以下是JSON文件的一个示例结构:

{
  "YourTableName": [
    {
      "PutRequest": {
        "Item": {
          "CustomerID": {"S": "C001"},
          "Address": {"S": "123 Main St"},
          "Name": {"S": "Alice"}
        }
      }
    },
    {
      "PutRequest": {
        "Item": {
          "CustomerID": {"S": "C002"},
          "Address": {"S": "456 Oak Ave"},
          "Name": {"S": "Bob"}
        }
      }
    }
  ]
}

执行批量写入

现在,让我们来实际运行这个操作。首先,从项目文档中复制相应的命令。

将命令粘贴到终端并执行:

aws dynamodb batch-write-item --request-items file://records.json

命令执行速度非常快。完成后,我们可以立即在DynamoDB控制台中查看结果。

验证结果

操作执行完毕后,我们前往AWS DynamoDB控制台进行验证。

在对应的数据表中,我们可以看到所有通过JSON文件导入的记录都已成功添加,包括CustomerIDAddressName等字段。

总结

本节课中我们一起学习了如何使用AWS CLI的batch-write-item命令,通过一个结构化的JSON文件向DynamoDB表批量填充数据。这种方法不仅效率高,而且便于通过校验JSON结构来确保数据的准确性,是进行大规模数据初始化和更新的有效工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P59:查询表中的记录

在本节课中,我们将学习如何在AWS DynamoDB中执行查询操作,以根据特定条件检索表中的记录。我们将使用AWS CLI工具,通过定义查询表达式和参数来精确获取所需数据。


概述

DynamoDB是一个NoSQL数据库服务,允许我们存储和查询数据。本节将演示如何基于特定参数(如客户ID和地址)查询DynamoDB表中的记录。我们将使用一个预定义的JSON文件来传递查询参数,使查询过程可重复且易于管理。


查询DynamoDB表

上一节我们介绍了DynamoDB表的基本结构。本节中,我们来看看如何执行一个具体的查询操作。

在DynamoDB中,我们有一个名为customers的客户表。查看表内数据,可以看到其中包含了不同客户的详细信息,如地址和姓名。现在,我们将基于一组特定参数来查询这个表。

为了执行查询,我们需要返回到VS Code编辑器,并使用AWS DynamoDB的查询命令。


构建查询命令

以下是构建查询命令的关键步骤。我们将使用aws dynamodb query命令,并指定表名、查询条件表达式以及参数值。

首先,传入表名,即customers表。接着,定义查询表达式,本例中条件是客户ID等于某个特定值。同时,我们使用过滤表达式来匹配特定地址。最后,通过一个JSON文件传入表达式属性值。

这种方法的有趣之处在于,我们可以将参数值保存在一个文件中,命令执行时会自动替换这些占位符。例如,对于客户ID,它会查找值为3的记录;对于地址,则会匹配789 Elm Street


执行查询

回到readme文件,可以看到它将把这个JSON文件传递给查询命令。现在,让我们执行这个命令。

执行成功后,我们能够精确检索到匹配查询条件的记录。这种方法的强大之处在于,你可以保存这个JSON文件,它代表了一种特定类型的查询,可以匹配你正在进行的某项操作。这使得将确切的查询需求以代码形式保存并纳入版本控制变得非常直接。

例如,这可以作为一个数据工程系统的基础,比如用于仪表板或某些机器学习应用。


总结

本节课中,我们一起学习了如何在DynamoDB中执行条件查询。我们使用了AWS CLI,通过定义查询表达式和借助JSON文件传递参数值,精确地检索了表中的记录。这种方法不仅使查询过程清晰可重复,还为构建更复杂的数据处理流程(如仪表板或机器学习应用的数据管道)奠定了基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P60:项目演练 🧪

在本节课中,我们将学习一个关于Amazon DynamoDB的实践项目。该项目旨在通过一系列具体任务,帮助你掌握DynamoDB的核心操作,包括创建表、加载数据、执行查询以及清理资源。完成基础任务后,我们还将探讨如何扩展项目,并思考NoSQL数据库的设计与使用。

项目任务概述

以下是本项目需要完成的核心任务列表。我们将逐一讲解每个步骤。

  1. 创建DynamoDB表:使用给定的名称和主键创建一个DynamoDB表。
  2. 加载样本数据:使用一个相邻的JSON文件将样本数据加载到表中。
  3. 执行条件查询:编写查询,基于多个过滤条件检索表中的项目。
  4. 清理资源:删除表中的所有项目,并最终删除该表。

任务详解

上一节我们介绍了项目的整体目标,本节中我们来看看每个任务的具体内容和操作方法。

任务一:创建DynamoDB表

首先,我们需要创建一个DynamoDB表。这可以通过AWS管理控制台或AWS CLI/ SDK完成。核心是定义表名和主键(分区键,或分区键加排序键)。

例如,使用AWS CLI创建表的命令结构如下:

aws dynamodb create-table \
    --table-name YourTableName \
    --attribute-definitions AttributeName=id,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST

任务二:加载样本数据

创建表之后,下一步是将样本数据加载到表中。项目中提供了一个JSON文件(records.json),其中包含了要插入的数据记录。

以下是使用Python Boto3 SDK执行批量写入操作的示例代码:

import boto3
import json

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('YourTableName')

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/e3a6f039c4f891151e35dd0023484b31_2.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/e3a6f039c4f891151e35dd0023484b31_3.png)

with open('records.json') as f:
    records = json.load(f)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/e3a6f039c4f891151e35dd0023484b31_4.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-llm-prac/img/e3a6f039c4f891151e35dd0023484b31_5.png)

with table.batch_writer() as batch:
    for item in records:
        batch.put_item(Item=item)

任务三:执行条件查询

数据加载完成后,我们可以执行查询操作。DynamoDB允许使用KeyConditionExpressionFilterExpression来精确检索数据。

例如,查询status"active"category"books"的项目:

response = table.query(
    KeyConditionExpression=Key('partition_key').eq('user123'),
    FilterExpression=Attr('status').eq('active') & Attr('category').eq('books')
)
items = response['Items']

任务四:清理资源

最后,为了管理成本和资源,我们需要清理本项目创建的所有资源。这包括清空表和删除表。

清空表中所有项目的代码:

scan = table.scan()
with table.batch_writer() as batch:
    for item in scan['Items']:
        batch.delete_item(Key={'id': item['id']})

删除表的代码:

table.delete()

挑战与扩展

完成上述基础任务后,项目还提出了进一步的挑战,旨在深化你对DynamoDB的理解。

以下是建议的扩展挑战任务:

  1. 添加全局二级索引(GSI):为表添加一个GSI,以支持对不同属性的高效查询。
  2. 更换数据源:尝试从CSV文件而非JSON文件加载数据集。
  3. 尝试不同查询场景:设计并执行更复杂的查询或扫描(Scan)操作。

反思与总结

在本节课中,我们一起学习了DynamoDB的基本操作流程。通过这个项目,你应该对以下问题有了更深的体会:

  • NoSQL数据库(如DynamoDB)的优势是什么?
  • 如何为快速查询高效地建模数据?
  • 哪些因素决定了预置容量(Provisioned Capacity)的需求?
  • 使用AWS CLI/SDK与使用管理控制台操作DynamoDB的体验有何不同?

总而言之,请逐步完成这个项目,尝试挑战任务,进行深度反思。这将帮助你构建一个出色的作品集项目,充分展示你对DynamoDB的掌握程度。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P61:61_04_02_引言_6

概述

在本节课中,我们将学习如何结合Apache Airflow构建一个更健壮、更贴近真实世界的场景。我们将基于之前见过的Apache Airflow示例,从远程数据源检索信息,进行数据处理,并进一步将处理结果持久化到数据库中。

构建真实场景的数据管道

上一节我们介绍了Apache Airflow的基本任务编排。本节中,我们将构建一个更完整的示例,涵盖从数据获取到存储的完整流程。

我们将基于已有的Apache Airflow示例进行扩展。首先,我们将从一个远程数据源检索信息或数据。

我们将执行与之前类似的数据处理步骤。

然后,我们将进一步增加一个任务。在这个任务中,我们将把处理结果持久化。与之前使用文件系统不同,这次我们将使用一个数据库。

在本例中,我们将使用SQLite数据库。需要说明的是,SQLite并非生产环境数据库,但它足以演示如何实现从数据处理到存储的完整流程。

这个示例将展示如何从一个远程数据集出发,进行一系列转换,然后根据特定的条件和业务逻辑,将最终结果持久化到数据库中。

接下来,让我们尝试将这些步骤组合起来,看看完整的流程是怎样的。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P62:管道需求概述 🚀

在本节课中,我们将学习如何构建一个更复杂的数据处理管道。我们将基于一个葡萄酒评分的CSV文件,创建能够执行多项任务、并将数据持久化到数据库的管道。

数据源与目标概述

我们之前已经见过这个葡萄酒评分的CSV文件。我们的目标是构建一个更复杂的任务集。我们将创建一个管道,执行多个不同的操作,并将从CSV中获取的特定信息持久化存储。CSV文件包含以下列:name(名称)、country(国家)、region(产区)、variety(品种)、rating(评分)和notes(品酒笔记)。

数据处理需求详解

根据我们想要实现的目标,我们只希望捕获 name(名称)、country(国家)、region(产区)、variety(品种)和rating(评分)这几列信息,并且我们不希望将 notes(品酒笔记)与这些信息放在同一个数据组中。

然而,我们仍然会保留 notes 列。这是因为假设本项目后续将使用这些笔记数据来训练一个机器学习模型。该机器学习模型的具体细节并不重要,但需求是必须单独捕获所有的 notes 数据。

为了实现这个目标,我们将把数据存入两个不同的表:notes 数据将进入一个表,而其他列的数据(name, country, region, variety, rating)将进入另一个表。我们将以这种方式对信息进行分组,并丢弃 index(索引)和 grape(葡萄)列,因为我们对这些不再感兴趣。

以上就是核心需求。

现有DAG结构回顾

现在,让我们快速回顾一下我们已有的DAG(有向无环图)结构。我们有一个 dataset_get 任务。如果你还记得,我们需要从GitHub仓库中获取数据。

在这个任务中,我们使用Apache Airflow的 Dataset 类定义了 raw_wine_data。这只是一个字符串标识符,用于指明我们要处理的对象。我们将安装pandas库,检索数据并将其保存到磁盘。这个任务相当直接,我们之前已经见过。一旦它完成,它将触发在代码第10行定义的 raw_wine_dataset

消费者任务与未来改动

如果我们回到DAG并查看消费者(consumer)任务,这里将是我们要进行改动的地方。在消费者任务中,我们将依赖于 raw_wine_dataset 来执行一些更改。

我们将在这个DAG中执行数据处理:清洗数据,然后将其持久化到磁盘。此处的构想是,我们将使用这个消费者任务在同一个数据库中创建两个表。

确保操作幂等性

我们将使这个操作具备幂等性。这意味着它可以运行多次并产生相同的结果。接下来我们将看到如何实现这一点。

任务扩展计划

目前我们只有一个任务(消费者任务)。为了完成我们的需求——将数据持久化到一个至少包含两个新表的数据库中,我们将创建至少两个额外的任务。

总结

本节课中,我们一起学习了构建一个复杂数据处理管道的需求。我们分析了源数据,明确了需要将品酒笔记与其他葡萄酒信息分开存储到不同数据库表的需求。我们还回顾了现有的Airflow DAG结构,并规划了通过增加新任务来实现数据分离和持久化的步骤,同时强调了确保操作幂等性的重要性。在接下来的课程中,我们将着手实现这些任务。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P63:将SQLAlchemy与Pandas结合使用 🛠️

在本节课中,我们将学习如何将Pandas与SQLAlchemy结合使用,以便将数据处理结果持久化存储到数据库中。我们将看到Pandas如何生成SQL语句,而SQLAlchemy如何作为桥梁,将这些语句发送到数据库并执行。

上一节我们介绍了数据处理的基本工具,本节中我们来看看如何将处理好的数据保存到数据库中。

概述

为了将我们学到的知识整合起来,我们需要了解如何让Pandas与SQLAlchemy协同工作。SQLAlchemy是一个库,它允许我们连接到各种不同的数据库后端。Pandas能够生成所需的SQL语句,而SQLAlchemy理解这些SQL,并知道如何将其发送到数据库并实现数据持久化。

环境准备

首先,我们需要设置一个虚拟环境并安装必要的库。我已经创建了一个名为sqlite的虚拟环境。我们将安装最新版本的SQLAlchemy和Pandas。

以下是安装步骤:

pip install sqlalchemy pandas

安装完成后,我们可以看到SQLAlchemy版本为2.0.1,Pandas版本为2.1.1。

连接数据库

现在,让我们看看如何让它们工作。我将打开Python交互式解释器,并导入所需的库。

import pandas as pd
from sqlalchemy import create_engine

create_engine函数允许我为将要通信的数据库创建通信层。引擎由一个特定的连接字符串定义。

以下是创建引擎的命令:

engine = create_engine('sqlite:///temporary_demo.db')

这个字符串配置了所有连接信息。sqlite:///部分告诉SQLAlchemy,我正在连接一个SQLite数据库。三个斜杠表示路径是相对的,这个相对路径将基于我当前所在的临时目录。

加载数据

现在我需要获取数据集。我将粘贴一个URL,以避免手动输入整个URL时出错。

url = 'https://raw.githubusercontent.com/your-repo/wine-data.csv'
df = pd.read_csv(url)

现在,df变量中包含了葡萄酒数据。如果我查看数据框的前几行,就能看到所需的列。

保存数据到数据库

如果我想将所有数据保存到SQLite数据库,该怎么做呢?

以下是操作步骤:

df.to_sql('wines', engine)

这个调用接受两个参数:一个是表名,另一个是引擎。这里发生的是:Pandas将生成SQL,把数据框df转换为实际的SQL语句。它会使用wines这个参数来创建一个名为wines的表。引擎则来自我们之前创建的engine对象,它定义了这是一个SQLite数据库及其路径。

SQLAlchemy具有连接各种不同类型后端的能力和灵活性,包括MySQL和PostgreSQL。在本演示中,为了简便,我们只使用SQLite。

执行后,响应是32780。这表示它写入了32780行数据。

验证数据

现在,让我退出Python解释器,并列出当前目录的文件。可以看到,现在有了一个temporary_demo.db数据库文件。

让我们调用SQLite并在这个数据库上执行命令,以查看其中的数据。

sqlite3 temporary_demo.db

为了更清晰地查看,让我们做一些设置。打开表头显示,然后执行一个查询。

.headers on
SELECT * FROM wines LIMIT 20;

运行这个查询后,我们将看到索引、Unnamed: 0namegraderegionvarietyratingsnotes等列。这基本上就是我们CSV文件中的所有内容,现在它们已经存储在SQLite数据库中了。

总结

本节课中,我们一起学习了如何将Pandas与SQLAlchemy结合使用,将数据从CSV文件加载到Pandas数据框,然后持久化存储到SQLite数据库中。这是将数据移植到Apache Airflow等管道工具中的第一步,以便我们能够以流水线的方式生产数据。理解如何同时使用SQLAlchemy和Pandas,对于我们后续在管道实现中集成它们至关重要。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P64:在任务中持久化数据 📂

在本节课中,我们将学习如何在Airflow任务中实现数据的持久化存储。具体来说,我们将创建一个新的任务,将已清洗的数据集保存到SQLite数据库中,并建立任务间的依赖关系,确保数据清洗完成后才执行持久化操作。


上一节我们介绍了数据清洗任务,本节中我们来看看如何将清洗后的结果持久化保存。

我们将遵循清洗数据集任务中的模式,创建一个新的任务。首先,在代码中快速创建一个新任务。

以下是创建新任务的步骤:

  1. 创建一个新行,定义任务。
  2. 使用 @task.virtualenv 装饰器,并指定任务ID。
  3. 为任务指定所需的Python库。

具体代码如下:

@task.virtualenv(
    task_id="persist_sqlite",
    requirements=["pandas", "sqlalchemy==2.0.21"],
)

注意,这里使用的SQLAlchemy版本是2.0.21,而非1.4。

任务创建后,需要定义被装饰的函数。我们将其命名为 persist_dataset

接下来,我们需要在函数内部编写导入语句和逻辑。关键点在于复用之前创建的 clean_dataset 作为数据源。

以下是函数实现的核心步骤:

  1. 创建SQLite数据库引擎,指向一个绝对路径(例如 /tmp/wine_data.db),并设置 echo=True 以输出所有操作日志。
  2. 通过读取 clean_dataset 创建一个Pandas DataFrame。
  3. 使用DataFrame的 to_sql 方法,将主数据保存到名为 wine_dataset 的表中。
  4. 同时,将DataFrame中的 nodes 列单独保存到另一个名为 wine_nodes 的表中。

为了实现任务间的顺序执行,我们需要建立依赖关系。我们希望 clean_dataset 任务先执行,然后才执行 persist_dataset 任务。

为此,我们使用位运算符 >> 来定义任务流:

clean_dataset >> persist_dataset

这表示 persist_dataset 任务将等待 clean_dataset 任务完成后才会执行。

这样,我们就构建了一个完整的数据管道。它不仅完成了数据清洗,还能按照我们的要求将所有数据持久化,并将节点数据单独存储在一个表中。


本节课中我们一起学习了如何在Airflow中创建数据持久化任务。我们通过复用上游的清洗数据集,使用SQLAlchemy引擎将数据保存到SQLite数据库,并利用位运算符建立了清晰的任务依赖关系,从而构建了一个自动化、可重复的数据处理流程。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P65:结果审查 🧐

在本节课中,我们将学习如何审查和验证一个Apache Airflow数据管道的运行结果。我们将通过用户界面和终端两种方式,确认数据处理任务是否按预期执行,并成功将数据持久化到数据库中。


重置与启动任务

上一节我们完成了代码的修改,本节中我们来看看如何从头开始运行整个流程。首先,所有环境已重置,数据库也已清空,没有任何历史运行记录。

以下是启动流程的步骤:

  1. 在Airflow用户界面中,找到并启用 wine_dataset_get 任务。
  2. 触发该任务开始运行。

触发后,任务需要一些时间来完成。一旦完成,它将自动触发下游的 data_consumer 任务。


在UI中监控任务依赖

现在,让我们回到DAGs总览页面并滚动到底部。可以看到 wine_dataset_get 正在运行,并很快会变为完成状态。紧接着,data_consumer 任务被触发。

点击进入 data_consumer 的运行详情,可以看到其运行ID和当前状态。在任务关系图中,可以清晰地看到各个子任务的状态流转:virtualenv_python 已完成,sqlite_perpoint_data 正在运行。这个视图直观地展示了任务间的依赖关系。


审查SQL执行日志

为了深入验证数据处理的细节,我们可以查看任务日志。进入 sqlite_perpoint_data 任务的日志输出。

由于在代码中设置了 echo=True,SQLAlchemy会将生成的所有SQL语句打印到日志中。在日志里,我们可以看到:

  • 数据库引擎被成功创建。
  • wine_notes 表被创建。
  • 插入数据的SQL语句被执行,其中包含了完整的葡萄酒数据集和品酒笔记。

日志内容可能很长,因为所有数据都以长字符串的形式插入,但这证实了数据持久化过程确实发生了。


在终端中进行最终验证

最后,我们通过终端直接查询数据库,进行最终的结果验证。

首先,进入项目目录并启动SQLite3命令行工具,连接到我们的数据库文件:

sqlite3 wine_data_set.db

然后,启用列显示模式以便更好地查看结果:

.mode column

接下来,我们可以检查数据库中存在的表:

.tables

查询 wine_data_set 表的前三条记录,以确认主数据已存入:

SELECT * FROM wine_data_set LIMIT 3;

查询结果应包含索引、名称、产区、品种、评分和笔记等所有预期字段。

同样,我们可以查询 wine_notes 表来验证品酒笔记数据:

SELECT * FROM wine_notes LIMIT 3;

查询结果将显示每条笔记及其关联的索引。


总结与扩展

本节课中我们一起学习了如何完整地审查一个Apache Airflow管道的运行结果。我们从UI触发任务、监控依赖执行,到查看详细的SQL日志,最后在终端中直接验证数据库里的数据,完成了一个闭环的验证流程。

我们成功构建的这条管道满足了所有既定需求。本次演示使用的是SQLite嵌入式数据库,但Apache Airflow的强大之处在于其灵活性。你可以轻松地将连接配置更改为PostgreSQL或其他远程数据库,从而为构建更复杂、更健壮的数据处理流程奠定坚实基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P66:总结

概述

在本节课中,我们将回顾并总结如何构建一个更复杂的Apache Airflow数据管道。这个管道涵盖了从远程数据源获取数据、进行数据转换、应用业务逻辑,到最终将处理结果持久化存储到数据库的完整流程。

课程内容回顾

上一节我们介绍了数据转换和业务逻辑的应用,本节中我们来看看整个管道的构建总结与关键概念。

我们成功创建了这个更复杂的Apache Airflow管道。我们能够从远程位置检索数据。我们进行了一些数据转换,就像之前所做的一样。我们能够对数据应用一些业务逻辑:我们处理了数据,然后从中提取出对我们有意义、应用了业务逻辑的特定内容。业务需求指出,我们需要这些表格,需要这里的这些特定数据和那里的那些数据。

我们将数据分离,并放入数据库的不同表中。我们成功地完成了这些任务。需要再次说明的是,我们使用了SQLite作为本地数据库进行持久化存储,但相同的概念在生产环境中同样适用。你可以将SQLite替换为其他平台,例如远程PostgreSQL实例(这是一个非常强大的开源数据库)、MySQL,或任何其他允许持久化数据的平台。

这通过使用SQLAlchemy实现,它是Python中一个用于与数据库交互的卓越库。

核心收获与展望

以下是本课程涵盖的核心技能与概念:

  • 管道构建:掌握了构建包含数据提取、转换、加载(ETL)流程的完整Airflow管道的技能。
  • 业务逻辑集成:学会了在数据处理流程中融入具体的业务规则和要求,例如数据筛选与分离。
  • 数据持久化:理解了如何使用SQLAlchemy这样的ORM库与数据库进行交互,其核心操作通常通过类似session.add(record)session.commit()的代码来完成。
  • 技术栈可扩展性:认识到演示中使用的SQLite可以轻松替换为如PostgreSQL或MySQL等生产级数据库,概念具有普适性。

这些概念不仅允许你构建一个管道,现在更能看到一个真实的应用场景示例,你可以在此基础上进行构建,借鉴这些示例来实际构建你自己的管道,并应用一些相同的概念。

总结

本节课中我们一起学习了如何构建一个集成了业务逻辑的复杂Apache Airflow数据管道。我们从数据获取开始,经历了转换和业务规则应用,最终实现了数据的分表持久化存储。关键点在于理解了使用SQLAlchemy进行数据库操作的可移植性,以及整个流程如何模拟真实世界的用例。你可以利用这些核心概念作为基础,去构建和定制满足特定需求的数据处理解决方案。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P67:01_01_01:课程介绍

在本节课中,我们将要学习这门课程的总体介绍,了解课程内容、讲师以及学习目标。

大家好,我是Noah Gift,我是这门课程的讲师。我是杜克大学的常驻高管,也是一位多产的Coursera课程作者。

这门课程令人兴奋,因为它涵盖了在AWS平台上关于生成式人工智能的前沿技术。这包括云端开发Ormind GPs。同时,课程也会涉及像Codewhiser这样的结对编程工具,以及Amazon Q。

接下来,我们将深入探讨Bedrock服务,这项服务允许你与多个基础模型进行交互,例如Cloud Miroll。然后,我们还会深入研究一些无服务器解决方案。

最后,在课程结束时,我们会进入项目挑战环节。这门课程的理念是注重实践、动手操作和特定技能。在课程结束时,你需要挑战自己,根据我们在课程中学到的知识来构建项目。

课程内容非常丰富。让我们开始吧。


本节课中我们一起学习了课程的整体介绍,明确了课程将聚焦于AWS平台上的生成式AI实践、相关工具与服务,以及最终的项目挑战,为后续深入学习奠定了基础。

大型语言模型实践:P68:02_01_03:人工智能云服务模型 🏗️

在本节课中,我们将要学习云计算的基础服务模型,并探讨在人工智能时代这些模型发生了哪些演变。我们将从传统的三层模型开始,逐步深入到为AI量身定制的新型服务模式。

概述

云服务模型是理解云计算的基础框架。然而,在人工智能时代,这一模型已经发生了变化和扩展。我们将逐一剖析这些服务层级,并了解在构建AI应用时如何选择适合的服务。

基础设施即服务 (IaaS)

基础设施即服务是云计算中最基础的服务层级。它为用户提供了最底层的计算资源。

在AWS平台上,一个典型的例子是EC2。EC2是一种计算实例,是你在计算方面可以获得的最低级别服务。它提供了计算、存储、网络等基础构建模块。

以下是基础设施即服务的一些关键特征:

  • 所有IaaS产品都能够按需使用。
  • 它是更高级别服务的基础。

其他基础设施即服务还包括:

  • S3 对象存储服务。
  • VPC 虚拟私有云。

平台即服务 (PaaS)

上一节我们介绍了基础的计算资源,本节中我们来看看如何更高效地构建应用。平台即服务提供了一个更高级别的抽象,让开发者能专注于应用逻辑本身。

在AWS平台上,一个很好的例子是AppRun服务。你可以将一个函数或微服务放入云端运行。AWS Lambda也可以被视为一种平台即服务,它允许你部署一段逻辑代码。

这些服务让你能够专注于:

  • 应用开发
  • 测试
  • 部署
  • 安全性
  • 监控

这意味着你关注的是业务逻辑,而非管理服务器,从而节省大量时间。

软件即服务 (SaaS)

平台即服务简化了开发,而软件即服务则提供了最完整的解决方案。软件即服务提供完全通过互联网运行的完整应用程序。

我认为许多人都熟悉这种模式,例如Zoom视频会议或各种邮件服务。整个应用在互联网上运行,你无需进行任何运维,只需开通服务并按使用付费。

人工智能时代的新兴模型

传统的三层模型为我们提供了基础,但在人工智能时代,出现了一些新兴的服务模型。让我们来看看其中一些是什么。

数据分析即服务

数据分析即服务提供了可扩展、安全的数据存储,以及数据摄取、转换和可视化等服务。

在AWS平台上,一个很好的例子是QuickSight。它允许你上传数据,并自动为你生成可视化图表。SageMaker Canvas也属于此类服务。

模型即服务

模型即服务是AI时代的一个重要发展。Bedrock就是一个很好的例子。

在这个服务中,你可以托管许多不同的模型,例如开源的Mistral,或者专有模型如Claude。所有这些模型都集中在这个服务中,你可以通过统一的API进行访问。

这样做的一个优势是,你无需为尝试的每个模型都构建自定义的API,而是有一个集中的位置来启动和使用这些服务。

人工智能即服务

人工智能即服务实际上已经存在相当长一段时间了。

一个很好的例子是Rekognition,它提供了开箱即用的计算机视觉功能,如图像标注和识别。我们还有用于自然语言处理的Comprehend。这些服务实际上是在大语言模型时代之前开发的,但这并不意味着它们不会继续发展。

此外,像ChatGPTClaude这样的聊天机器人,我们也可以将它们视为人工智能即服务。因此,在人工智能时代的云计算中,思考你希望在哪一层级进行构建非常重要。

总结

本节课中我们一起学习了云服务模型的演变。从基础的基础设施即服务,到简化开发的平台即服务,再到开箱即用的软件即服务。在AI时代,我们看到了数据分析即服务模型即服务人工智能即服务等新兴模式的兴起。

例如,在最低层级,你可以使用EC2并配备GPU来自行管理一切;而在最顶层,你可以直接使用聊天即服务。但在某些情况下,数据治理、隐私问题或法律原因可能要求你在本地运行模型。因此,在AI时代,你必须根据具体需求、合规性和技术目标,来决定在哪个服务层级进行构建和部署。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P69:03_01_04:人工智能云部署模型 ☁️🤖

在本节课中,我们将要学习人工智能时代的云部署模型。我们将探讨公有云、私有云和混合云这三种主要部署方式,分析它们各自的优势、劣势以及适用场景,帮助你理解如何为大型语言模型项目选择合适的部署策略。


云部署的主要模型

在人工智能时代,云部署引入了一些新的概念。首先,我们来谈谈主要的开发部署模型。

公有云 🌐

公有云是指通过公共互联网提供资源。以下是其主要特点:

优势:

  • 可扩展性:资源可以根据需求弹性伸缩。
  • 灵活性:能够快速获取和配置所需服务。
  • 按需付费定价:仅为实际使用的资源付费。
  • AI推理能力:如果延迟允许,可以利用云服务商(如AWS)提供的众多服务进行AI推理。

劣势:

  • 技能要求:需要具备有效使用云原生技术的专业技能。

私有云 🔒

私有云意味着资源在组织自己的数据中心内专供该组织使用。以下是其主要特点:

优势:

  • 安全控制:对数据和基础设施拥有完全的控制权。
  • 低延迟:例如,服务器可以紧邻部署,从而获得极低的网络延迟。

劣势:

  • 灵活性受限:可能无法在需要时立即购买到硬件,因为所有设备都需要预先采购。
  • 潜在弹性牺牲:可能无法像公有云那样,在第一天就实现全球部署或在多个数据中心之间灵活迁移。
  • 复杂性高:需要雇佣专业人员来管理服务器、更换硬盘等数据中心运维工作。
  • 成本问题:在某些场景下,私有云的成本可能更高。

混合云 ⚖️

混合云能够结合公有云和私有云的优势。以下是其主要特点:

应用场景:

  • 可以在私有云上进行AI训练,以确保数据安全和低延迟。
  • 可以在公有云上进行AI推理,以根据需求弹性扩展。
  • 这种方式能够在成本、性能和安全之间取得平衡。

其他适用情况:

  • 数据治理:由于监管要求,数据可能不被允许存放在公有云上。
  • 竞争优势保护:为防止竞争对手通过云服务商获取数据。
  • 迁移策略:从私有云向公有云迁移过程中的过渡方案。
  • 临时扩展:在已有私有云的基础上,偶尔将负载扩展到公有云以满足峰值需求。

随着进入在本地运行大型语言模型的专业化时代,混合云可能会重新流行起来。许多组织在选择大型语言模型的应用场景时,至少应该考虑混合云方案。


本节课中,我们一起学习了人工智能时代的三种主要云部署模型:公有云、私有云和混合云。我们分析了每种模型的特点、优势、劣势以及典型应用场景。理解这些模型有助于你根据项目的具体需求(如安全性、成本、延迟和扩展性)做出明智的部署决策。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P70:04_01_05_云计算优势 ☁️

在本节课中,我们将要学习云计算的核心优势。我们将探讨比较优势原则如何驱动企业采用云服务,并详细解析云计算的各项关键益处,包括成本、速度、敏捷性以及专注业务等。

概述

云计算的优势根植于比较优势原则,这是驱动企业采用云服务的关键。其核心在于关注最低的机会成本,即为了专注于核心业务,你愿意放弃什么。这本质上是云计算的基本原则。

云计算的核心优势

上一节我们介绍了云计算的基本理念,本节中我们来看看其具体的优势体现在哪些方面。

1. 资本支出与可变支出 💰

首先,在资本方面,你将资本性支出转换为了可变支出。这意味着你无需一次性投入数百万美元购买大量服务器。你可以在需要时逐步增加容量,并且这种容量可以是动态的。你可以随时增加或减少资源。这很像使用公用事业公司(如水电)的服务。

2. 规模经济效益 📈

我们还能从规模经济中获益。因为云提供商批量采购资源,他们的成本更低,并能凭借规模优势将这些资源交付给用户。

3. 无需猜测容量 🔮

我们同样无需猜测容量需求。就像使用公用事业公司一样,你可以随时“关闭恒温器”。想象一下,如果你必须购买一堆木材,并精确猜测整个冬天需要多少木材。无论高估还是低估,你都会陷入难以解决的问题中。云计算避免了这种困境。

4. 速度与敏捷性 ⚡

速度是另一个优势。能够快速部署、快速行动非常重要。当我们把速度和敏捷性结合起来时,你就能真正快速转向、高速发展。这可能意味着你的业务效率有10倍甚至100倍的提升。

以下是速度与敏捷性的区别:

  • 速度:意味着你可以快速行动,频繁部署。
  • 敏捷性:意味着你可以完全更换基础设施,例如将键值数据库换成关系型数据库。你能进行这类变更,正是因为同时具备了速度和敏捷性。

5. 专注于业务,而非运维 🎯

云计算还让你能减少对数据中心的关注,更多地聚焦于业务本身。许多公司不想成为数据中心专家,也不想雇佣专门负责网络和服务器维护的员工。这是云计算带来的关键优势,而且在很多场景下,云提供商会比你做得更好。

6. 全球部署能力 🌍

你能够立即利用云提供商的全球基础设施足迹。这是云计算的一个巨大优势。

7. 深化比较优势 🚀

我们还能深化你已有的比较优势。假设你是某项特定技术的专家,你无需将时间花在不擅长的领域。你可以专注于真正能让你的业务取得成功的事情,或者专注于你工作中更高价值的方面。

总结

本节课中我们一起学习了云计算的多项核心优势。总的来说,利用比较优势、将你不希望成为专家的领域外包出去,并专注于那些机会成本低或能带来最高投资回报率的事情,具有非常重要的意义。这些优势共同构成了企业选择云计算服务的强大驱动力。

大型语言模型实践:P71:AWS人工智能云采用框架 🏗️

在本节课中,我们将学习AWS(亚马逊云科技)的云采用框架,并特别关注其在人工智能(AI)和机器学习(ML)领域的应用视角。我们将从业务、人员、治理、平台、安全和运维等多个维度,系统性地探讨企业在云上成功采用AI技术所需考虑的关键因素。

业务视角

上一节我们介绍了课程概述,本节中我们首先来看看企业采用AI时的业务视角。当一家公司考虑使用AI时,首先需要明确其AI战略。

以下是企业在制定AI战略时需要思考的几个核心问题:

  • 能否解锁新的业务价值? 例如,组织中是否存在大量手动、重复性的工作,而AI可以协助完成,如自动生成特定文档或从历史数据中总结文档。
  • 如何管理数据驱动的、AI赋能的产品生命周期?
  • 如何利用AI和ML进行预测性洞察和分析?
  • 如何识别哪些AI项目能与所需的业务成果对齐?
  • 如何利用AI和ML能力创新商业模式?
  • 如何微调和定制基础模型? 这是一个重要议题。你或许有一个表现不错的模型,但能否让它变得更好?

人员视角

在明确了业务战略后,接下来我们需要关注“人”的因素。从人员视角出发,企业需要构建支持AI成功落地的团队与文化。

以下是人员视角下的关键考量点:

  • 如何构建团队的AI和ML知识素养与通用术语?
  • 如何吸引、赋能和管理AI人才?
  • 能否促进跨团队协作?
  • 能否培育一种“AI/ML优先”的文化?

治理视角

除了人员和业务,有效的治理是确保AI项目合规、可控且高效的关键。接下来,我们将探讨治理视角。

以下是治理工作的核心内容:

  • 优化和衡量AI与ML的云成本。
  • 确保对数据资产和产品进行有效管理。
  • 管理AI与ML相关的风险。
  • 确保AI的负责任开发与使用。

平台视角

一个强大且灵活的技术平台是AI项目的基石。从平台视角看,企业需要构建能够支撑AI工作负载的基础设施。

以下是平台视角的关键任务:

  • 为AI工作负载建立可扩展的架构。
  • 将AI能力集成到应用程序中。
  • 管理完整的机器学习生命周期。这里需要思考:你是在做无差异化的繁重工作,还是在利用云服务来简化流程?

安全视角

在AI时代,安全被赋予了新的内涵。从安全视角出发,我们需要特别关注AI模型本身可能带来的风险。

安全视角的核心任务包括:

  • 识别并缓解AI模型的漏洞。例如,如果使用某种特定类型的开源模型,它可能会暴露出有缺陷的代码。你能否通过更严格的代码审查或选择更安全的编程语言来缓解此风险?

运维视角

最后,当AI系统上线后,持续的运维与监控至关重要。本节我们来看看运维视角。

运维视角主要关注以下两点:

  • 如何管理和监控AI的性能?
  • 如何识别并应对未预见到的AI行为?

本节课中,我们一起学习了AWS人工智能云采用框架的六个核心视角。当企业计划在云上采用AI技术时,需要综合考量业务、人员、治理、平台、安全与运维这六大方面。这些类别必须协同工作,才能确保企业在战略和执行层面都做出正确的决策,从而成功、负责任地部署和管理AI解决方案。

大型语言模型实践:P72:06_01_02:人工智能开发环境 🛠️

在本节课中,我们将要学习在AWS上进行人工智能开发时可用的多种开发环境选项。我们将探讨基于云的环境、新兴的GPU环境、本地开发选项以及跨云工具,帮助你根据项目需求选择最合适的开发平台。

基于云的开发环境 ☁️

上一节我们介绍了课程概述,本节中我们来看看几种主要的云开发环境。AWS提供了多种用于AI开发的云环境,它们各有特点。

首先,我们有AWS Code Catalyst。这是一个基于CPU的云端开发环境。Code Catalyst的有趣之处在于,你可以选择预配置了AWS选项的实例,例如Amazon Linux 2。所有工具都已就绪,并且它也能与本地IDE协同工作。例如,你可以从IntelliJ等IDE与之交互,连接到那个特定的云端环境。你甚至可以根据要解决的问题,拥有一整套专门的环境。

这在AI流水线中很有帮助,因为你可以构建,例如,使用Step Functions和Lambda的无服务器流水线。这可以成为一个快速开发解决方案的理想场所。

新兴的GPU云环境 ⚡

上一节我们讨论了基于CPU的云环境,本节中我们来看看功能更强大的GPU环境。现在,甚至出现了更有趣的新兴云环境,这些新环境嵌入了GPU。

其中之一是AWS Lightsail for Research。你可以访问NVIDIA GPU,也可以访问其他AWS功能,例如弹性文件系统(EFS)或EBS。这真正有趣的地方在于,这意味着许多人可以协作进行基于GPU的项目。例如,假设你在AWS Lightsail中运行LlamaFile,然后这个结果可能会进入一个EFS卷。假设你正在查看一堆文档,总结这些文档,然后将结果放入某个数据库,所有这些都可以在这个AWS Lightsail for Research环境中完成。

另一个新兴环境是AWS SageMaker Code Editor。它同样可以访问GPU资源,并且你可以在一个更传统的SDK类型环境中进行开发。使用Visual Studio Code,你实际上也可以开始开发代码。

这些环境非常有趣,因为你既能访问GPU,又能访问整个AWS云环境。从你仍然身处云端、拥有低延迟并同时能访问GPU这个意义上说,这确实很独特。

本地AI开发环境 💻

上一节我们介绍了云端GPU环境,本节中我们来看看本地开发选项。我们现在也开始看到一种集成,它同样为AI开发提供了本地环境。

以下是几种本地开发选项:

  • AMD:随着对使用AMD GPU运行本地大语言模型的支持越来越多。
  • NVIDIA:拥有CUDA驱动程序,你可以将其安装在Linux笔记本电脑上,进行本地大语言模型开发。
  • Mac M系列:包括M1、M2、M3系列以及未来的M4,所有这些都开始能够用于本地运行大语言模型。

一个很好的例子是来自Zilla的LlamaFile。你可以获取最新的模型,在Mac上运行,并使用所有那些M系列GPU,同时也能使用NVIDIA和AMD GPU。因此,你既可以在本地环境也可以在云环境中使用它。

过去情况并非如此,你未必拥有本地环境。本地环境有一些优势,这在AI领域改变了局面。当然,基于云的环境仍然有很多优点,因为它们直接位于AWS云内部,延迟低。但现在,本地环境也有很多值得青睐的地方。

跨云与批处理工具 🔄

上一节我们探讨了本地环境,本节中我们来看看一个能简化多云部署的工具。另一个我要讨论的工具是SkyPilot。它允许你在云中运行LLM和AI批处理作业,也允许你选择不同的云服务提供商。

例如,你可以放入一个YAML文件并运行lx命令,这允许你使用来自Perplexity的开源技术同时运行许多不同的模型。所有这些功能,在你使用这种云环境或本地环境混合进行开发时都是可用的。

总结 📝

本节课中我们一起学习了在AWS上进行AI开发时可用的多种环境。了解这些特性非常重要,以便为你手头的任务选择正确的工具。每种方法都有其优缺点,但在开始为云端AI进行开发之前,最好先了解你有哪些选择。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P73:07_01_03_Rust与Python中的MLOps挑战与机遇

在本节课中,我们将要学习MLOps(机器学习运维)的核心概念,并深入探讨在Python和Rust这两种编程语言中实施MLOps时所面临的挑战与机遇。我们将对比两者的特性,帮助你理解为何在某些场景下Rust可能成为更优的选择。

概述:什么是MLOps及其必要性

首先,我们来看MLOps的定义及其重要性。MLOps不仅仅是部署模型的一个开关,它是一个需要将问题分解为不同部分的系统性过程。

以下是构成MLOps基础的几个关键部分:

  • DevOps是前提:如果没有健全的DevOps实践,就无法实现MLOps。这包括持续集成、持续交付、基础设施即代码和微服务等迭代式最佳实践。这些是迈向MLOps的基石。
  • 数据操作是核心:必须专注于数据操作,遵循数据工程的最佳实践,构建能够稳健处理批数据和流数据的强大数据管道。
  • 模型质量是关键:对于机器学习,模型本身至关重要。必须确保模型适合你试图解决的问题,具有良好的准确性,能够限制偏见,并能以合乎道德的方式获取数据。这些都是模型层面必须关注的问题。
  • 解决实际业务问题是目标:即使上述所有技术环节都正确无误,确保解决实际的业务问题也至关重要。如果盲目地将AI部署到生产环境而不明确目标,最终可能只是产生无用的“幻觉”,无法为企业带来价值。例如,一家保险公司希望分析历史数据并通过总结文档来获取关键洞察,这就是一个具体的业务用例,能为客户带来价值。
  • 警惕笔记本的局限性:需要意识到,如果在笔记本环境中构建系统,几乎从一开始就采用了错误的方法。笔记本适用于尝试和验证想法,但在一个强调持续集成和测试的系统中,依赖这种非为测试而设计的、具有特殊性的工具,与MLOps的理念是相悖的。

上一节我们介绍了MLOps的基本构成,本节中我们来看看在具体技术栈选择上的考量,首先从广泛使用的Python开始。

Python在MLOps工程中的挑战

Python在机器学习工程方面存在一些严重的局限性,因为它本质上是一种原型语言。

以下是Python在MLOps工程化中面临的主要挑战:

  • 缺乏二进制部署:Python没有原生的二进制部署概念。而二进制部署非常强大,因为它将所有依赖打包成一个可执行文件,便于推送到生产环境,使得使用无服务器技术或进行推理变得简单。
  • 性能较差:Python从未被设计为高性能语言。它擅长可读性和开发者友好性,但在CPU和内存性能方面表现不佳。
  • 并发瓶颈:Python存在并发瓶颈。它没有真正的线程,即使未来引入了多线程,也可能因为缺乏编译器对并发安全性的检查而引发各种问题。
  • 虚拟环境带来的“生产力税”:每次使用Python时,你都必须处理虚拟环境,这就像一种“生产力税”。虽然标准库非常强大,但一旦需要安装第三方包,就必须决定使用venvConda还是其他解决方案,而这些方案之间甚至可能存在冲突,导致生产力下降。
  • 安全与打包问题:需要考虑现代安全和安全问题,以及普遍的安全性问题。此外,如前所述,Python在健壮的打包方面(例如处理环境依赖)并非其强项。

了解了Python的局限性后,我们来看看另一种语言——Rust,它为MLOps带来了哪些不同的优势。

Rust为MLOps带来的机遇

Rust具备许多能弥补Python不足的优点。

以下是Rust在机器学习运维方面的主要优势:

  • 二进制部署:二进制部署是使MLOps更高效的一个巨大优势。你只需将二进制文件部署到任何地方,例如容器、无服务器环境,甚至是用于推理的GPU(如在Llamafile中的应用场景中)。
  • 高性能:Rust具有C语言级别的性能。
  • 强大的并发能力:Rust拥有出色的、无瓶颈的并发能力,并且有像rayon这样非常健壮的库支持。编译器会保护你免受许多常见并发问题的影响。
  • 安全性设计:Rust为安全性而设计。由于其内存模型和所有权模型,许多安全漏洞在Rust中根本不存在。
  • 优秀的MLOps生态库:有非常适合MLOps、LLMOps和数据工程的优秀库,例如你可能听说过的PolarsCandle

现在,让我们看看从Python转向Rust时需要了解的一些关键概念。

Rust的核心概念与工作流

如果你从Python转向Rust,需要了解其工作方式有所不同。最大的区别在于Rust有一个工具为你处理一切。

以下是Rust工作流中的关键特点:

  • 一体化的Cargo工具Cargo是Rust的一大优势,本质上是你需要处理的唯一入口。所有操作都在基于树状结构的项目中进行,没有全局状态的概念(不像虚拟环境)。所有内容都集中在一个目录下,由Cargo.toml文件管理依赖,src目录存放库和主代码。
  • 所有权与借用:在Rust语言中,所有权和借用机制是自动获得的。你必须显式声明变量是可变的还是不可变的,安全机制是默认内置的。
  • 内存安全与类型系统:内存安全类型同样存在。在脚本语言中,类型可能对许多人来说是个大问题,你经常会发现单元测试基本上只是类型检查器。
  • 自动集成与快速反馈:通过生成可在target目录中执行的二进制文件,实现了自动的持续集成。这对于MLOps来说是一个巨大的胜利,因为它提供了非常快速的反馈循环。

我们可以这样思考:在生成式AI的世界里,Rust可以成为你代码的“蹦床”。

利用生成式AI辅助Rust学习

一个好的比喻是:如果你想尝试后空翻但遇到困难,可以去蹦床上练习。如果你已经掌握了一些不错的技巧,蹦床可以帮助你达到新的水平,从而完成那个后空翻。

同样,尽管Rust有许多看起来令人不快的方面,其语法也比Python更难掌握(这很像吃蔬菜),但编译器对你的严格要求实际上对你有益。你可以依赖Cargo生态系统来解决许多问题,也可以借助生成式AI工具。因此,Rust并非一门纯粹难学的语言,它实际上也有很多好处,就像西兰花或抱子甘蓝一样。

特别是在生成式AI的世界里,你能获得更多的想法和建议。一门非常严格的语言(如Rust)与生成式AI工具(例如AWS CodeWhisperer)的结合,可以成为一个强大的组合。

总结

本节课中我们一起学习了MLOps的基本框架,并深入比较了Python和Rust在实现MLOps时的不同表现。我们了解到,Python虽然拥有丰富的库和易用性,但在性能、部署和工程化方面存在挑战。而Rust凭借其高性能、安全性、卓越的并发模型和便捷的二进制部署,为构建健壮、高效的MLOps系统提供了新的机遇。结合现代生成式AI工具的辅助,学习并应用Rust可以成为提升机器学习工程实践水平的有力跳板。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P74:08_01_04_Rust生成式AI工作流 🦀

在本节课中,我们将要学习如何为Rust编程语言构建一个结合了生成式AI工具的高效开发工作流。我们将探讨编程的本质,如何选择AI工具,并最终构建一个集成了代码补全、外部聊天机器人以及传统DevOps最佳实践的强大开发环境。

编程的本质与自动化

上一节我们介绍了课程概述,本节中我们来看看编程的核心是什么。Rust语言促使我们思考编程的本质。

编程中存在着许多“无用的痛苦”,这些是应该被自动化的部分。以下是“无用的痛苦”的例子:

  • 打包系统:例如,选择使用PIP、Conda、虚拟环境还是其他工具。
  • 调试运行时错误和语法错误
  • 编写样板代码
  • 管理虚拟环境
  • 排查逻辑错误
  • 搭建开发环境:有些地方需要花费一个月来搭建环境,而在基于云的开发环境时代,只需点击一个按钮就能获得完整环境。

所有这些都与编程本身无关,并且可能让新手感到困惑,因为他们觉得自己在浪费时间,却不知道这些与编程无关。

编程的本质是:输入 -> 处理单元 -> 输出。这就是编程的全部,除此之外只涉及逻辑本身。还有一些可选部分,可能有用也可能没用:

  • 面向对象编程:在Python中,你完全可以进行数十年的函数式编程,而无需涉及面向对象。
  • 并发:不一定是你需要立即采用的解决方案。
  • 复杂算法:如果标准库已经提供了,就不需要自己实现。
  • 框架、Scrum、敏捷、测试驱动开发等。

一旦开始思考我们真正关心什么,答案就是逻辑本身,以及用逻辑来解决问题。这就是编程的本质。

生成式AI工具的选择策略

理解了编程的核心后,当我们考虑使用生成式AI工具时,我们知道它们很有用,但也必须从众多工具中做出选择。

我们可以比较不同的工具,例如,一个工具可能侧重于客户信任,另一个侧重于生产效率。我们需要像使用天平一样权衡利弊。以下是一些需要考虑的因素:

  • 公司结构与领导者
  • 产品与公司的能力
  • 相关网络
  • 数据来源是否合乎道德:数据是否包含随意拼凑的盗版数据集。

这就像选择“海豚友好”的金枪鱼还是普通金枪鱼。你会选择那些存在公认有害副作用的方案吗?对于生成式AI,你应该为所要解决的问题选择合乎道德的解决方案。

Rust生成式AI工作流构建

现在,我们决定使用生成式AI这一伟大技术。让我们看看如何在Rust中实现。

Rust的工作流程与常规操作类似。以下是构建步骤:

  1. 初始化项目:使用 cargo new my_project 命令。
  2. 项目结构:你会得到一个包含 Cargo.toml 文件和 src 目录(内含 lib.rsmain.rs 等)的树形结构。
  3. 引入Makefile:我喜欢使用Makefile来定义构建、格式化、链接和测试等任务。
  4. 核心文件
    • Cargo.toml:管理项目依赖。
    • main.rs:CLI(命令行界面)的脚手架代码。
    • lib.rs:核心业务逻辑和测试代码。

此时,一个高效的工作流开始发挥作用:使用代码补全工具,例如支持多行Rust代码的AWS CodeWhisperer。这样,你就获得了一个融合DevOps最佳实践的反馈循环:

  • Makefile与Cargo的最佳实践。
  • CLI的脚手架代码。
  • 一个能补充现有DevOps实践的优秀工具。

此外,我还建议使用一个外部聊天机器人,如Claude、Mixtral或其他开源模型。你可以向一个模型提问,再用另一个模型验证答案,实现一种“专家混合”的策略。你仍然需要遵循传统的DevOps最佳实践:

  • 格式化代码。
  • 检查代码风格。
  • 测试代码。
  • 运行代码。

事实上,通过格式化和检查代码,你会微调代码的外观。如果你将调整后的代码再次放入代码助手,它可能会给出略有不同的答案,或者你可以获得增强的反馈。因此,对于像Rust这样的语言,将DevOps最佳实践与生成式AI结合是相辅相成的。这是一种非常强大的技术,许多人在转向Rust时应该考虑,因为它能让你充分利用强大语言(Rust)、DevOps和生成式AI最佳实践之间的协同效应。

总结

本节课中我们一起学习了如何为Rust设计一个高效的生成式AI开发工作流。我们首先探讨了编程的本质是逻辑处理,并识别了应被自动化的“无用的痛苦”。接着,我们讨论了选择生成式AI工具时需要考虑的伦理和实用性因素。最后,我们详细构建了一个结合了cargo项目结构、Makefile、代码补全工具(如AWS CodeWhisperer)、外部聊天机器人以及格式化、检查、测试等传统DevOps最佳实践的完整工作流。这个工作流充分发挥了Rust语言、现代开发实践和人工智能辅助之间的协同作用,能显著提升开发效率与代码质量。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P75:09_01_05:Rust与生成式AI时代下的Python数据科学 🐍⚙️

在本节课中,我们将探讨在Rust和生成式AI兴起的背景下,Python数据科学的现状、挑战与未来策略。我们将分析Python的优势与局限,并探索如何结合Rust等新技术来构建更高效、更强大的数据科学工作流。

Python的优势:黄金时代 🏆

上一节我们介绍了课程背景,本节中我们来看看Python语言在数据科学领域的核心优势。Python是全球最流行的编程语言,在多个方面表现出色。

以下是Python的主要优势:

  • 优秀的数据科学库:Python拥有成熟且强大的数据科学库生态系统。
  • 卓越的原型开发能力:Python语法简洁,能快速实现和验证想法。
  • 强大的深度学习库:如TensorFlow和PyTorch,为AI研究与应用提供了坚实基础。
  • 出色的教学与文档:Python代码易于阅读和理解,其丰富的文档有助于学习各种系统。

当Python运行在托管的Notebook环境(如Google Colab、优化后的Jupyter环境或Coursera的指导性实验)中时,其优势能得到最大发挥。因为这些环境已预先配置好所需的软件包,规避了Python包管理系统的弱点。

Python标准库也为原型开发提供了强大支持,它内置于大多数系统中,无需处理复杂的包依赖即可直接利用。

增长的瓶颈:是否已达顶峰? 📈➡️📉

然而,指数增长遵循S型曲线。初期快速增长后,由于已达到能力上限,回报开始递减,增长趋于平缓。

这就引出一个问题:对于已经极其成功的Python语言,继续为其增加新特性(如类型注解、线程、新的包管理系统等)是否能带来显著价值?还是说,我们应该转向尝试新的工作流、新的语言和新的理念?

我们需要思考:Python的顶峰在何处?减少对纯Python和Jupyter的依赖会是什么样子?我们是否会看到更多基于Rust的工具出现?事实上,这种转变正在有机地发生,例如:

  • 一些Python代码检查工具正被更快的Rust工具取代。
  • 像Polars这样的Rust基础库在数据操作中提供了惊人性能。

我们可能正处在Python的“顶峰”时期。

混合策略:Python与Rust的强强联合 🤝

那么,如何利用这两个生态系统的优势呢?一个极具前景的策略是将Python与Rust混合使用。

对于拥有丰富Python经验的开发者,混合编程是一个绝佳的解决方案。一个非常有趣的模式是使用 PyO3 库。

PyO3 库允许你在Rust模块中编写计算密集型操作,并将其编译为Python可以调用的共享库(.so.pyd 文件)。

以下是一个概念性示例,展示如何用Rust实现一个计算密集型函数,并通过PyO3暴露给Python:

// 在Rust中使用PyO3
use pyo3::prelude::*;

/// 用Rust实现的高性能加法函数
#[pyfunction]
fn fast_add(a: i64, b: i64) -> i64 {
    // 此处可包含复杂计算逻辑
    a + b
}

/// 将模块封装给Python
#[pymodule]
fn rust_calculator(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(fast_add, m)?)?;
    Ok(())
}

编译后,在Python中即可调用:

import rust_calculator
result = rust_calculator.fast_add(5, 3) # 结果为8

你可以创建一个高效的Makefile来管理初始化、安装、构建和清理流程。更进一步,可以结合像 Python Fire 这样的库,自动将代码模块转换为命令行工具。

对于需要与大量科研人员和原型开发者协作的场景,这种混合模式可能是最优解,它能兼顾Python的易用性与Rust的性能。

性能驱动:为何选择Rust? ⚡

我们之所以看到众多用于Python的Rust工具涌现,根本原因在于性能的显著提升。

  • 极致的速度:在某些场景下,Rust能带来10倍到100倍甚至更高的性能提升。例如在代码检查(Linting)方面,基于Rust的工具(如ruff)速度极快,使得其他工具相形见绌。
  • 数据处理性能:像Polars这样的库提供了惊人的数据处理速度。
  • 无服务器(Serverless)成本效益:在无服务器架构中,费用通常与内存使用量和执行时间挂钩。使用更高效、内存占用更低的Rust代码可以显著降低运营成本。

因此,出于对性能和经济性的追求,开发者们开始有机地混合使用Rust和Python。

总结与展望 🎯

本节课中我们一起学习了在Rust和生成式AI时代下,Python数据科学面临的机遇与挑战。

我们回顾了Python在数据科学库、原型开发和教学方面的核心优势,特别是在托管Notebook环境中的卓越体验。同时,我们也认识到其包管理系统的弱点以及语言可能面临增长平台期的挑战。

面对这些挑战,我们探讨了一个强大的策略:混合Python与Rust。通过使用PyO3等工具,我们可以在保留Python生态和开发效率的同时,引入Rust的极致性能来处理计算密集型任务,从而构建出更稳健、更高效的工作流。

在生成式AI对算力要求日益增长的今天,拥有这样一个性能优化策略,对于构建面向未来的、强大的数据科学和工程应用至关重要。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P76:10_01_06:新兴Rust-LLMOps工作流 🦀

在本节课中,我们将要学习一些新兴的、基于Rust编程语言的LLMOps工作流。Rust以其高性能、内存安全和出色的并发能力,正成为构建高效、可靠LLM应用的有力工具。

概述

本节将介绍一系列强大的Rust库和工具,它们构成了现代Rust-LLMOps工作流的基础。我们将探讨这些工具如何协同工作,以支持从模型推理到高性能数据处理的各个环节。

核心Rust库与工具

以下是构成Rust-LLMOps生态系统的几个关键库。

  • Rust Torch Bindings:这是一个围绕C++ PyTorch框架的绑定库。它赋予开发者在纯Rust环境中执行深度学习任务的能力。
  • HuggingFace Candle:该库允许你用Rust包装大型语言模型。它让你能充分利用Rust框架的优势来开发LLM应用。例如,你可以拉取最新的Mixtral模型库并运行它,或轻松运行其他新发布的模型。
  • Polars:这是一个高性能的数据框操作库,专为快速数据处理和分析而设计。
  • Actix Web:这是一个高性能的Web服务框架,被认为是全球最快的Web框架之一。
  • Cargo Lambda:此工具支持你将基于二进制的应用部署到AWS Lambda,实现低内存消耗和毫秒级响应。你可以选择ARM架构以节省成本。
  • Clap:这是一个用于编写命令行工具的库,帮助快速构建用户友好的CLI界面。
  • Lx:该工具允许你在云端构建AI工作负载,并获得极佳的性能。

所有这些Rust集成工具共同赋予了我们强大的能力。可以看到,在不同的应用场景下,它们能发挥巨大作用。例如,在构建数据工程流水线时,你可以将数据加载到Polars中处理,通过Cargo Lambda和HTTPS部署函数,并接入诸如SQS、SNS等消息流服务。

云端开发环境的优势

除了强大的库,云端开发工作站也为Rust-LLMOps带来了显著优势,并且这一领域正在快速发展。

使用个人笔记本电脑进行开发存在一些实际问题,包括环境非确定性、成本高昂,以及开发环境与最终部署环境不一致等。当然,使用高性能笔记本电脑也有优势,例如你可以将所有数据保存在本地,无需发送到云服务商。

但总体而言,云端开发工作站具备许多有趣的功能。它们通常配备GPU,并提供编码辅助工具(如与IntelliJ集成的AWS CodeWhisperer)。此外,还有具备GPU能力的AWS Lightsail实例、配备GPU的AWS SageMaker,以及Coab Notebooks等。

我们在这里看到,基于云端的开发环境优势非常明显,尤其对于Rust而言,它在启用了GPU的云端环境中运行得非常好。

一个推荐的Rust-LLMOps工作流

上一节我们介绍了工具和云端环境,本节中我们来看看一个具体的工作流。对于许多考虑为本地或自托管大型语言模型开发工作流的组织来说,我认为以下是一个非常优秀的实践方案。

这个工作流的核心是使用Rust Candle库。其流程如下:

  1. 你触发一次构建。
  2. 代码流水线会生成一个包含所有必要依赖的新镜像。
  3. 该镜像随后发布一个经过优化的二进制文件,该文件能够利用GPU进行计算。
  4. 你可以将任何大型语言模型以及微调后的模型加载到S3存储中。
  5. 之后,你可以通过多种方式调用它:例如,在CPU客户端上使用本地量化版本;在无服务器应用中调用;使用Spot实例以节省成本;甚至将其安装到本地设备上。

这个基于Rust Candle的工作流是一个非常有趣且正在兴起的新模式。

总结

本节课中,我们一起学习了新兴的Rust-LLMOps工作流。由于Rust在性能、打包部署方面的卓越表现,以及其生态系统对大型语言模型非常友好,它确实为LLM应用开发提供了丰富的选择。从高性能推理(Candle)、数据处理(Polars)到高效部署(Cargo Lambda, Actix),Rust工具链为构建下一代可靠、高效的LLM系统奠定了坚实基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P77:11_01_07_Rust版CodeCatalyst入门 🚀

在本节课中,我们将要学习如何使用亚马逊的CodeCatalyst服务进行基于云的Rust开发。CodeCatalyst是AWS提供的一项较新的服务,它支持云端开发,并提供了一些功能强大的计算资源。我们将通过一个测试来了解其基本操作。

了解CodeCatalyst开发环境

上一节我们介绍了CodeCatalyst的基本概念,本节中我们来看看它的开发环境是如何工作的,以及你能用它做些什么。

这里有一个开发环境。在这个特定环境中,可以看到一个正在运行的实例。

以下是CodeCatalyst开发环境的一些核心功能:

  • 你可以通过点击“创建开发环境”来在浏览器中启动一个开发环境。
  • 这项功能非常出色,因为Cloud 9允许你拥有一个预配置好的AWS环境。
  • 许多复杂的设置都会因为这个Cloud 9环境而消失,我们稍后会用到它。
  • 你也可以使用Visual Studio Code或JetBrains IDE(如IntelliJ、GoLand、PyCharm等)。
  • 这里有一些非常酷的集成功能。这些都是通过AWS Toolkit插件代理连接到CodeCatalyst环境的本地集成。

启动并访问开发环境

了解了环境的功能后,现在来看看如何实际访问它。

只需点击“打开”,这将打开一个新环境。让我们看看它是什么样子。可以看到它打开了这个环境。我已经打开了一个,所以不再重复操作。

在环境中安装Rust

环境准备就绪后,下一步就是安装开发工具。为了安装Rust,你只需复制这里的命令,然后粘贴到你的环境中。这就是安装Rust并继续安装过程所需做的全部。

一旦安装了Rust,开始开发就相当简单了。接下来,我们来谈谈这个特定Cloud 9环境的一些独特之处。

配置AWS与CodeWhisperer

首先需要注意的一点是,在左上角我们有AWS,注意我使用的是AWS Builder ID进行连接。这是一个你可以免费获取的ID,它不连接到你的AWS账户,并允许你向其他服务进行身份验证,例如CodeWhisperer。

CodeWhisperer是这里的代码补全工具,可以看到它当前正在运行。我们如何实际使用它来编写一些Rust代码呢?让我们一起来看看。

使用CodeCatalyst进行Rust开发实战

首先,我将输入 cargo new 命令来创建一个新项目。

cargo new hello

我们将输入“hello”来创建一个“Hello World”应用程序。在这里我们有一个主文件。一切准备就绪,我可以直接输入命令或进入hello项目目录。

cd hello
cargo run

运行成功,我们得到了一个“Hello World”。现在,如果我想做一个稍微复杂一点的程序,我们可以利用CodeWhisperer,实际上可以制作一个计算器。

我可以添加一个Rust注释来说明这是一个计算器脚本。

// calculator script

然后从这里,我们可以保存它。我可以说,第一件事我们可以做一个加法函数。

fn add(a: i32, b: i32) -> i32 {
    a + b
}

然后我将得到一些不错的代码补全。接着我们在这里做一个减法函数。

fn subtract(a: i32, b: i32) -> i32 {
    a - b
}

我们可以稍微调整一下。可以看到这里有一些合理的代码补全。

然后为了稍微调整一下,我将设置一些变量并进行计算。

fn main() {
    let a = 10;
    let b = 5;
    let sum = add(a, b);
    let difference = subtract(a, b);
    println!("Sum: {}", sum);
    println!("Difference: {}", difference);
}

这是一种直观的代码补全。如果我们输入 cargo run,就可以成功运行。这是旧版本的输出。注意我保存了它。如果我再次运行 cargo run,就会得到新版本计算出的和与差。

云端开发的优势与总结

从入门开始,你就会发现云端开发的许多优点。想象一下,你可以保存这些环境,安装特定的软件包,配置好一切。对于大型语言模型来说,这也可能是一个值得探索的方向,尤其是在构建无服务器管道的量化环境中。

因此,对于构建用于大型语言模型和机器学习运维的Rust应用来说,CodeCatalyst绝对是一个值得关注的环境,而且它非常容易上手。

本节课中我们一起学习了:如何使用亚马逊CodeCatalyst创建云端开发环境,在该环境中安装和配置Rust,并利用AWS Builder ID和CodeWhisperer工具来辅助编写和运行一个简单的Rust计算器程序,体验了云端开发的便捷性。

大型语言模型实践:P78:SageMaker Studio Code Editor入门 🚀

在本节课中,我们将学习如何开始使用AWS SageMaker Studio的Code Editor功能。这是一个基于浏览器的、功能完整的集成开发环境,特别适合进行机器学习和大型语言模型的开发工作。

认识SageMaker Studio环境

上一节我们介绍了课程背景,本节中我们来看看SageMaker Studio的核心界面。SageMaker Studio是一个用于处理机器学习和大型语言模型的成熟环境。

在界面左侧,可以看到多种功能选项。以下是可用的主要工具和服务:

  • 启动Jupyter Lab
  • Studio Canvas
  • Code Editor
  • Studio Classic(旧版本)

此外,界面上方还有多个功能选项卡。以下是各个选项卡对应的功能:

  • Running Instances:运行实例
  • Data:数据管理
  • AutoML Experiments:自动机器学习实验
  • Jobs:任务管理
  • Pipelines:流水线
  • Models:模型管理
  • JumpStart Deployments:快速启动部署

这基本上构成了一个完整的MLOps(机器学习运维)流水线。

聚焦Code Editor功能

虽然功能丰富,但本节课我们重点演示的是Code Editor。这是一个非常新的功能,它内置了一个开源的Visual Studio Code编辑器。

你可以在浏览器内直接测试、调试和运行分析与机器学习代码。它可以使用Open VSX扩展注册表中的全部IDE扩展。

环境与身份识别

现在,让我们看看它的工作方式。请注意,这里有一个运行环境,你可以停止或启动它。

如果想回到已经打开的SageMaker Code Editor界面,我们需要确认自己身处的是Code Editor,而非一个普通的托管式VS Code环境。以下是两种识别方法:

  1. 查看界面左上角的Logo。
  2. 观察终端提示符中显示的“sageMaker”字样。

开发者工具集成

接下来,我们看看其他一些非常有趣的功能。如果你点击“AWS”菜单,可以在这里启用其他开发者工具。

这是一个重大的改变。因为许多传统的SageMaker工具都围绕Jupyter构建,而Jupyter对于构建应用程序并不十分友好。现在,有了这个开发者环境,你可以直接开始编写代码。

如果你有软件工程背景,就可以利用这一背景在SageMaker Studio Code Editor内部构建代码。

代码开发与版本控制

现在,让我们看看这里可以进行哪些操作。其中一个很酷的功能是,我们可以直接进行Git远程操作。

可以看到,我一直在试验一个大型语言模型库(例如Hugging Face的Candle)。如果我想进行一些开发或提交Pull Request等操作,都可以直接在这个环境中完成。

GPU加速支持

另一个需要提及的强大功能是,它已经启用了GPU支持。这一点非常重要。

我们可以通过命令来验证。例如,输入以下命令:

nvidia-smi -l

这将弹出一个对话框,实时监控CUDA版本、驱动程序版本以及GPU使用情况。在这里,我们可以看到它使用的是Tesla T4显卡。

因此,我们完全有能力开始进行GPU编程。我们可以用Rust、Python或任何你希望使用的语言进行编程。

使用Rust等语言的一个显著优势是,你可以实现基于二进制的大型语言模型部署。这正是一种新兴的尖端技术。

总结

本节课中,我们一起学习了SageMaker Studio Code Editor的入门知识。我们了解到,它提供了一个集成的开发环境,并配备了完整的MLOps流水线。由于环境中已预装Rust,我们可以立即开始在SageMaker Studio Code Editor内为大型语言模型开发Rust代码。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P79:研究型Lightsail入门 🚀

在本节课中,我们将要学习AWS的一项新服务——研究型Lightsail。这项服务允许我们启动性能强大的机器,用于大型语言模型开发、机器学习工作以及运行模拟等任务。我们将了解其基本功能、如何启动实例以及两种主要的访问方式。

服务概览与实例创建

上一节我们介绍了课程背景,本节中我们来看看研究型Lightsail的具体界面和创建过程。

AWS的研究型Lightsail服务提供了启动高性能计算资源的能力。在创建界面中,可以看到一些默认的配置选项。

以下是可选的预置环境:

  • 基础Ubuntu:纯净的Ubuntu操作系统。
  • Jupyter Lab:集成的Jupyter Lab数据科学环境。
  • SAB:一个特定的应用环境。
  • VScodium:一个社区驱动的开源代码编辑器。
  • 我们的工作室:一个定制的工作环境。

我们首先选择基础Ubuntu环境。请注意,在这里可以选择不同的实例规格,例如 standard2Xstandard4X。这些规格定义了虚拟CPU(vCPU)的数量、强大的GPU配置、内存大小和存储空间。该服务采用按使用量付费的模式。

接下来,我们选择一个简单的配置,并将实例命名为 test2。点击创建虚拟机器后,系统将开始构建这个应用实例。实例运行后,会提供其他功能选项,例如关闭会话或删除虚拟机。

浏览器内直接访问

上一节我们完成了实例的创建,本节中我们来看看如何通过浏览器直接访问并进行开发。

界面上显示我已经有一个正在运行的名为 LLM Ops Sandbox 的实例。要启动访问,只需点击相应的按钮。从这里,我可以直接在浏览器内开始使用它。

这是一种非常便捷的开始开发的方式,因为从一开始,我无需进行任何复杂设置就能获得访问权限,并可以开始在上面安装我的编辑器。这样,我就拥有了一个位于云端的完整工作空间,它提供了许多我在桌面开发中习惯的功能。

通过SSH访问实例

除了浏览器访问,还有另一种访问方式,即通过SSH连接,这种方式同样强大但稍复杂一些。

以下是SSH连接的基本步骤:

  1. 按照界面上的指引,为你的计算机获取密钥对。
  2. 根据说明运行几个特定的命令。
  3. 通过SSH协议连接到实例。

我已经完成了这些设置。现在,我打开一个终端,通过输入类似 ssh -i [密钥路径] ubuntu@[实例IP] 的命令连接到这台机器。连接成功后,我们可以验证环境。例如,我想检查是否安装了Rust,可以运行 rustup 命令。运行结果显示它已经安装。接着,我可以运行 rustc 命令来确认Rust编译器也已就绪。

这是一种在基于研究的环境中非常强大的开发方式。你既可以获得桌面环境,也可以使用终端,并且拥有高度的自定义能力。如果你身处大语言模型或MLOps领域,这项功能绝对值得关注。此外,该服务还提供快照、成本控制等功能。本质上,研究型Lightsail提供了一个功能齐全的云端实验室环境。

本节课中我们一起学习了AWS研究型Lightsail服务。我们了解了它作为高性能云端开发环境的核心价值,逐步完成了从选择配置、创建实例到通过浏览器和SSH两种方式访问实例的全过程。这是一个为大型语言模型和机器学习研究量身定制的便捷、强大的工具。

大型语言模型实践:P80:基于AWS Bedrock的无服务器架构图 🏗️

在本节课中,我们将探讨两种基于AWS Bedrock构建的生成式AI无服务器工作流。我们将了解如何利用AWS的无服务器服务(如S3、Lambda和OpenSearch)与Bedrock的大型语言模型(LLM)结合,实现文档处理和知识库问答等高级功能。

传统文档处理工作流 📄

上一节我们概述了课程内容,本节中我们来看看第一种基于AWS Bedrock的传统文档处理工作流。

该工作流适用于许多AWS Lambda应用程序,其核心流程如下:

以下是该工作流的关键步骤:

  1. 文档存储:用户将文档(如PDF、TXT文件)上传至Amazon S3存储桶。
  2. 事件触发:S3上传事件自动触发一个AWS Lambda函数。
  3. 调用LLM:Lambda函数调用AWS Bedrock服务中的大型语言模型(例如Claude 2.1)。
  4. 文档处理:Lambda将S3中的文档内容(最多可达20万令牌)发送给LLM,并执行指定任务,如摘要生成内容增强

公式示例Lambda(S3_Event) -> Invoke_Bedrock_LLM(Document, Prompt) -> Result

这种架构的典型应用场景是自动化分析。例如,金融分析师可以自动读取美国证券交易委员会(SEC)的公司备案文件,通过提示词让LLM分析公司的盈利能力或识别关键条件的变化,从而获得统一、高效的分析报告。

检索增强生成(RAG)工作流 🔍

了解了传统的文档处理流程后,我们来看看另一种新兴且强大的模式——检索增强生成工作流。

这种工作流旨在为LLM提供外部知识源,使其生成基于特定领域知识的准确回答。以下是构建RAG工作流的主要环节:

以下是构建RAG系统的核心步骤:

  1. 数据准备:收集原始文本数据(例如,某位教授的YouTube视频字幕文稿),并将其存入Amazon S3
  2. 向量化存储:使用嵌入模型将文本数据转换为向量,并存储到向量数据库(如Amazon OpenSearch Serverless)中。
  3. 查询与检索:当用户提出问题时,系统将问题转换为向量,并在向量数据库中检索出最相关的文本片段。
  4. 增强生成:将检索到的相关文本作为上下文,与用户问题一同提交给AWS Bedrock的LLM(例如Claude 2.1),生成最终答案。

代码示例response = llm.generate(query=user_question, context=retrieved_documents)

无服务器架构的优势与集成 ⚡

无论是传统工作流还是RAG工作流,其核心优势都建立在无服务器架构之上。

所有提到的组件(S3、Lambda、OpenSearch Serverless、Bedrock)都是全托管、无服务器的服务。这意味着开发者无需管理底层基础设施,可以专注于业务逻辑。AWS Lambda 可以作为整个系统的统一接口,通过API Gateway、聊天工具或Web前端暴露给用户。

公式示例User_Request -> API_Gateway -> Lambda -> (S3/Bedrock/OpenSearch) -> Lambda -> Response

这种架构为快速开发和自动化提供了巨大机会。它既可以是传统无服务器功能的扩展(如文档自动摘要),也可以实现复杂的RAG应用,将生成式AI模型“锚定”在特定知识库上。RAG不仅能确保模型基于指定数据生成回答,还能在响应中提供数据来源引用,极大地提高了结果的准确性和可信度。


本节课中我们一起学习了两种基于AWS Bedrock的无服务器架构。第一种是传统的文档处理流水线,通过S3触发Lambda调用LLM处理文档。第二种是检索增强生成工作流,它结合了向量数据库,使LLM能够基于特定知识库生成精准答案。这两种模式都充分利用了AWS无服务器服务的弹性、可扩展和易集成的特点,为构建高效的生成式AI应用提供了强大蓝图。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P81:15_01_03_AWS Bedrock知识代理演示

在本节课程中,我们将学习如何使用AWS Bedrock平台创建一个知识库,并利用检索增强生成技术,让大型语言模型基于我们自己的数据来回答问题。我们将通过一个具体的演示,展示如何配置知识库、上传数据并进行查询。

概述:AWS Bedrock知识库与检索增强生成

上一节我们介绍了AWS Bedrock的基本概念。本节中,我们来看看如何利用Bedrock的知识库功能,实现检索增强生成。这是一种强大的技术,它允许AI模型在生成回答时,参考并“引用”我们提供的特定数据源,从而提供更准确、更相关的信息。

知识库配置与数据源

这里我们打开了Amazon Bedrock平台,并且已经设置好了一个知识库。

这个知识库的核心是使用向量数据库来实现检索增强生成。你可以看到这里有一个知识库数据源,它是我从S3存储桶上传的一些课程转录文本。这些是我之前做过的一些讲座内容。

以下是知识库配置的关键组件:

  • 嵌入模型:我在这里使用了Titan嵌入模型,它是知识库的一部分,负责将文本转换为向量表示。
  • 向量引擎:在配置中,你可以看到“向量引擎”选项,这里使用的是Amazon OpenSearch Serverless。这是一个托管的向量搜索引擎,用于高效存储和检索文本向量。

测试向量数据库检索功能

配置完成后,我们首先需要测试向量数据库是否正常工作。

一个简单的方法是直接输入一个查询,看看它能否从我们的数据中找到相关信息。让我们输入“什么是Rust”,然后看看会发生什么。

系统现在会执行搜索。我们可以看到结果中列出了在不同转录文本里所有提到“Rust”的地方。这证明向量检索功能是有效的,它成功地从我们上传的数据中找到了相关内容。

使用生成式AI进行增强回答

在确认检索功能正常后,下一步是结合生成式AI模型来产生完整的回答。

为此,我需要选择一个生成模型。我已经在这里选择了Claude 2.1模型来协助完成生成式AI任务。

现在,让我们输入一个更具体的问题:“为什么Rust被用于MLOps?”,看看结果如何。

检索增强生成的实际效果

现在,AI模型能够基于我上传的数据来“落地”其回答。它将生成一个AI回复,并且这个回复会引用我提供的课程资料中的内容。

这是一种非常强大的技术。你可以看到这里的回答:“Rust被用于MLOps是由于其性能优势”,并且我实际上能在下方的检索结果中,看到这个结论所引用的具体转录文本片段。

这个演示的核心价值在于,你可以让生成式AI模型基于你认为可靠、特定的数据源来生成结果。显然,你拥有的关于某个主题的数据越多、质量越高,生成的结果就会越好。

总结

本节课中,我们一起学习了如何在AWS Bedrock上配置和使用知识库。我们了解了如何设置数据源和向量引擎,测试了基础的检索功能,并最终结合Claude模型实现了检索增强生成。这项技术使你能够利用自有数据来增强大型语言模型的能力,确保其回答既具有生成模型的流畅性,又具备特定领域数据的准确性和相关性。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P82:AWS Bedrock CLI 演示 🚀

在本节课中,我们将学习如何通过 Rust 编程语言和 AWS SDK 来与 Amazon Bedrock 服务进行交互。我们将从查看 AWS 控制台界面开始,然后逐步编写一个简单的 Rust 程序来列出 Bedrock 中所有可用的基础模型。

概述 Amazon Bedrock 控制台

上一节我们介绍了课程背景,本节中我们来看看 Amazon Bedrock 服务的用户界面。

在 AWS 控制台中,你可以看到 Amazon Bedrock 的界面。你可以切换到图标视图,查看托管在此处的基础模型的描述信息。你也可以切换到列表视图,查看种类繁多的不同模型及其支持的令牌数量。其中一个顶级模型是 Anthropic 公司提供的 Claude 3。

使用 Rust 与 Bedrock 交互

除了控制台,另一种与 Bedrock 交互的方式是使用 Rust 语言。接下来,我们将看到如何使用 AWS SDK for Bedrock。

使用 AWS SDK for Bedrock 的好处是,从 Rust 调用 Bedrock 服务非常直接。让我们开始吧。

这里有一个我正在开发的名为 Gennyi 的项目。在 Cargo.toml 文件中,我引入了以下依赖:

  • aws-config
  • aws-sdk-bedrock
  • tokio(为 Rust 提供异步能力)

代码逐步解析

现在,让我们一步步解析代码。

第一步:导入 SDK
首先,我们导入 AWS Bedrock SDK。

use aws_sdk_bedrock as bedrock;

第二步:设置异步主函数
接着,我们标记主函数,以便能够进行异步调用。这需要 Tokio 运行时的支持。

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 函数体
}

这个异步主函数将能够返回结果并处理错误。

第三步:加载配置
然后,我们加载调用所需的配置,包括包含区域信息的环境配置。

let config = aws_config::load_from_env().await;

第四步:创建客户端
创建客户端非常简单,只需一行代码。

let client = bedrock::Client::new(&config);

第五步:列出基础模型
还记得控制台的界面吗?我们可以在那个面板上列出所有模型。在代码中,我们执行相同的操作。

let resp = client.list_foundation_models().send().await?;

我们发送列出基础模型的请求,等待响应,并处理可能发生的任何错误。

第六步:打印输出
最后,我们只需将结果打印出来。这里的代码会进行美观的格式化打印。

println!("{:#?}", resp);

第七步:返回成功
在函数末尾,我们返回 Ok(()) 表示程序执行成功。

Ok(())

运行程序

让我们运行这个程序。在终端中输入:

cargo run

程序开始运行。输出内容可能较多,不易阅读。

这里有一个我常用的小技巧:将输出通过管道传递给 less 命令。

cargo run | less

这样,你就可以滚动浏览所有不同的 Bedrock 模型了。

总结与展望

本节课中,我们一起学习了如何通过 Rust 和 AWS SDK 来列出 Amazon Bedrock 中的基础模型。

如果你计划将 Rust 作为主要接口,它在无服务器运行时(如 AWS Lambda、App Runner,甚至 Fargate)中会运行得非常好。由于 Rust 的高效性,并且它是 AWS 平台最新的通用 SDK,因此在大语言模型的新世界中具有巨大潜力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P83:17_01_06_Rust无服务器方案架构图

在本节课中,我们将学习在AWS上部署Rust应用的无服务器架构选项。我们将探讨两种主要的设计思路:以二进制文件为中心和以容器为中心,并分析它们各自的优势与适用场景。

以二进制文件为中心的方案

上一节我们介绍了课程概述,本节中我们来看看第一种方案:以二进制文件为中心的Rust无服务器架构。这是Rust语言的一个显著优势,开发者无需单独打包依赖项。在许多情况下,依赖项可以直接编译进二进制文件中。

例如,使用 cargo lambda 这样的工具,可以轻松部署一个无服务器函数。这个函数能够执行诸如使用Polars进行数据工程,或使用Pipedream等服务集成等任务。之后,你可以通过AWS Step Functions来编排和扩展这些功能。

在无服务器领域,拥有Rust生态系统是一个竞争优势。其优势体现在延迟、性能、能耗和成本上。根据具体用例,性能提升可能达到10倍、100倍,甚至1000倍。

以下是该方案的核心优势列表:

  • 依赖管理简单:依赖项可内置于二进制文件。
  • 部署便捷:使用 cargo lambda 等工具简化部署流程。
  • 功能强大:可集成Polars等库进行数据工程。
  • 性能卓越:在延迟、性能和成本方面具有显著优势。
  • 易于扩展:可通过Step Functions编排工作流。

以容器为中心的方案

了解了基于二进制的轻量级方案后,我们接下来看看另一种以容器为中心的方案,它主要围绕AWS Fargate构建。Fargate的优势在于它能简化操作,并提供了与多种AWS服务集成的接口。

让我们讨论其中几种服务:

  • AWS App Runner:这项服务非常引人注目,它允许你推送一个容器镜像,并自动完成部署,从而实现开箱即用的持续交付。
  • Amazon ECS:这是AWS管理的容器服务。你可以运行一些长时间运行的自定义任务,这些任务可以与Fargate配合工作,实现无服务器化。
  • AWS Batch:这项服务本身也很有吸引力。如果你想运行短生命周期作业,甚至可以利用Spot实例,你可以将一些Rust应用部署到AWS Batch中。例如,基于GPU的训练、推理任务或一些数据工程任务,都能从中获得出色的性能。
  • Amazon EKS:Kubernetes可以通过EKS进行管理,并且它同样可以与AWS Fargate协同工作。

因此,如果你倾向于以容器为中心的方案,可以选择Fargate及上述服务;如果你更倾向于以无服务器二进制文件为中心的方案,则可以选择AWS Lambda。两者都是在AWS上运行Rust应用的优秀选项。

本节课中我们一起学习了在AWS上部署Rust应用的两种主要无服务器架构。我们探讨了以二进制文件为中心的方案,其优势在于依赖内嵌和极致性能;也分析了以容器为中心的方案,它通过Fargate提供了灵活的服务集成和任务管理能力。开发者可以根据具体的性能需求、部署复杂度和集成场景来选择最合适的路径。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P84:18_01_07_Rust Axum贪婪硬币微服务组件架构图

在本节课中,我们将要学习一个基于Rust和Axum框架构建的“贪婪硬币找零”微服务。我们将详细拆解其各个组件,包括其架构设计、核心逻辑、测试方法以及多种部署选项。

微服务概述

首先,我们来看这个微服务本身。它使用Tokio框架来获得异步能力,这是目前可用的最快的框架之一,这是它的一个优点。同时,它的路由设计也非常直观。

路由与控制器

在路由处理部分,微服务会接受一个表示美元和美分的参数。这个参数随后会被传递给一个找零函数。

这里需要注意的一个设计模式是,我将业务逻辑分离到了一个名为LibRS的目录中。这是一个很好的模式,可以清晰地分离关注点。控制器部分(即微服务本身)和业务逻辑部分(放在库中)被分开了。

核心业务逻辑

以下是核心业务逻辑的实现。它是一个相当简单的函数,使用了“贪婪启发式”算法。

// 伪代码示例:贪婪找零算法
fn make_change(amount: i32) -> HashMap<Coin, i32> {
    let mut remaining = amount;
    let mut result = HashMap::new();
    let coins = [25, 10, 5, 1]; // 硬币面值

    for &coin in &coins {
        if remaining >= coin {
            let count = remaining / coin;
            result.insert(coin, count);
            remaining %= coin;
        }
    }
    result
}

这个算法的效率在于,它首先尝试使用最大面额的硬币(25美分),尽可能多地处理剩余金额。如果还有剩余,则尝试下一个最大面额,依此类推。这种方法以最少的迭代次数为你提供找零,并且优先给出大面额硬币,这样就不会过早耗尽小面额硬币的库存。

测试

我们在LibRS库中还可以看到测试代码。这是许多Rust项目中一个很好的模式,你可以将测试放在文件底部。这样可以测试业务逻辑,而业务逻辑通常是代码中最复杂、最容易出错的部分。确保核心逻辑正常工作至关重要。

依赖管理与部署

现在,我们来看看Cargo.tml文件。可以看到这里安装了一些包,包括axumTokio,以及用于序列化和反序列化的serde库。

此外,还有一个无发行版的Dockerfile。这是可选的,但如果你想进行基于容器的部署,这个文件会很有用。这种Dockerfile的优点在于,它能将镜像精简到几乎只包含二进制文件,使得Docker镜像可以非常小(例如20-30兆字节),这让部署变得非常容易。

当使用Rust和Axum时,还有二进制部署的方式。实际上,它与AWS Lambda配合得非常好。你可以使用cargo lambda工具,对你的代码进行少量修改,然后进行基于二进制的部署。甚至有一些库可以在两种不同风格(容器与Serverless)之间做代理,这样你完全不需要修改代码。

部署选项与生成式AI集成

由此可见,在使用Rust Axum时,你拥有一个完整的框架可以使用。你可以进行无服务器部署,也可以部署到容器(如ECS),或者部署到Kubernetes,还可以进行二进制部署。选择非常多。

它在生成式AI领域也能很好地工作,因为你可以直接代理到某些GenAI服务,例如使用RAG(检索增强生成)的服务。这个RAG服务可以很好地集成到你的微服务架构中。

总结

本节课中,我们一起学习了一个Rust Axum贪婪硬币找零微服务的完整架构。我们分析了其高性能的Tokio异步框架、清晰的控制器与业务逻辑分离设计、高效的贪婪算法核心、内嵌的测试模式,以及灵活多样的部署选项(包括轻量级Docker容器、AWS Lambda等)。这种架构模式不仅高效、可测试,而且能轻松适应现代云原生和生成式AI的应用场景。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P85:19_01_08_Rust Axum贪婪硬币演示

在本节课中,我们将学习如何使用Rust编程语言和Axum框架构建一个简单的微服务。这个微服务的核心功能是实现一个“贪婪硬币找零”算法,并通过HTTP API对外提供服务。我们将分析项目的代码结构,理解其工作原理,并学习如何运行和测试它。

项目结构概述 🗂️

我们有一个使用Rust和Axum框架的微服务项目。项目主要包含两个文件:lib.rsmain.rslib.rs文件包含了所有的核心业务逻辑,而main.rs文件则负责处理HTTP路由和服务器启动。

核心逻辑:贪婪硬币找零算法 💰

上一节我们介绍了项目的整体结构,本节中我们来看看核心的找零算法是如何实现的。

lib.rs文件中定义了一个名为greedy_coin_change的函数。这个函数的功能是计算给定金额(以美分为单位)所需的最少硬币数量。它采用“贪婪算法”,即优先使用最大面额的硬币,直到无法再使用为止,然后转向下一个较小面额的硬币。

以下是该函数的代码描述:

pub fn greedy_coin_change(amount: u32) -> Vec<u32>
  • 输入:一个u32类型的整数,代表总金额(单位:美分)。
  • 输出:一个包含u32类型的向量(Vec<u32>),代表找零所需的各面额硬币数量。硬币面额预设为1美分、5美分、10美分和25美分。
  • 算法逻辑:函数会遍历一个预设的硬币面额列表(例如 [25, 10, 5, 1]),对于每个面额,计算最多可以使用多少枚,然后将剩余金额传递给下一个面额继续计算。

为了确保算法的正确性,lib.rs文件中还包含了一个测试套件。以下是测试用例的示例:

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_greedy_coin_change() {
        // 测试不同金额的找零结果
        assert_eq!(greedy_coin_change(34), vec![25, 5, 1, 1, 1, 1]);
    }
}

HTTP服务与路由设置 🌐

理解了核心算法后,我们来看看如何通过Web服务将其暴露给外部调用。这部分逻辑主要在main.rs文件中。

首先,通过use语句导入lib.rs中定义的函数:

use rust_axum_greedy_coin_microservice::greedy_coin_change;

接着,我们设置Axum的路由。项目定义了两个主要路由:

  1. 默认路由 (/):这是一个静态路由,用于返回微服务的使用说明。
  2. 找零路由 (/change/:dollars/:cents):这是一个动态路由,接收美元(dollars)和美分(cents)两个参数。

处理找零请求的函数会从路径中提取dollarscents参数,将它们合并为总美分数,然后调用greedy_coin_change函数进行计算。最后,将结果封装成一个JSON负载返回给客户端。

所有的路由配置和服务器启动逻辑最终在Tokio运行时中被整合。关键代码如下:

let app = Router::new()
    .route("/", get(root))
    .route("/change/:dollars/:cents", get(get_change));

let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();

项目配置与辅助文件 ⚙️

为了便于开发和维护,项目还包含一些配置文件:

  • Cargo.toml文件:列出了项目所需的所有Rust依赖包,例如axum, tokio, serde等。
  • Makefile文件:包含了一些常用的命令(例如cargo run, cargo test),开发者无需记忆完整的命令,直接执行make run即可启动服务。

运行与测试微服务 🚀

现在,我们已经了解了项目的所有组成部分,本节我们来实际操作,运行并测试这个微服务。

首先,我们需要启动微服务。在项目根目录的终端中,执行以下命令:

cargo run

服务器将在前台启动,并监听3000端口,等待HTTP请求。

接下来,我们打开另一个终端会话,使用curl命令来测试API。

  1. 访问默认路由,获取使用说明:

    curl http://localhost:3000/
    
  2. 测试找零功能。例如,计算3美元4美分的找零方案:

    curl http://localhost:3000/change/3/4
    

    服务将返回一个JSON响应,其结构可能如下:

    {
      "dollars": 3,
      "cents": 4,
      "coins": [25, 25, 25, 25, 25, 5, 1, 1, 1, 1]
    }
    

    这表示,对于304美分的总金额,贪婪算法给出的找零方案是:5枚25美分硬币,1枚5美分硬币,以及4枚1美分硬币。

除了使用curl,你也可以直接在Web浏览器中访问上述地址来测试API。

总结 📝

本节课中我们一起学习了如何构建一个完整的Rust Axum微服务。我们从分析项目结构开始,深入探讨了核心的“贪婪硬币找零”算法的实现。然后,我们了解了如何使用Axum框架设置HTTP路由,将算法功能封装成Web API。最后,我们通过运行服务和发送HTTP请求,实际验证了微服务的功能。这个项目展示了Rust在构建高效、可靠网络服务方面的能力,其清晰的模块化设计(分离lib.rsmain.rs)也体现了良好的工程实践。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P86:20_01_09_Rust Axum Docker工作流演示

在本节课程中,我们将学习如何使用Docker容器化一个基于Rust和Axum框架的微服务应用。我们将涵盖从编写Dockerfile、构建镜像、运行容器到测试和清理的完整工作流程。这个流程模拟了生产环境的部署,是现代化应用开发的关键技能。

项目结构与代码概览

我们使用IntelliJ IDE打开了一个Rust微服务项目。项目包含一个库文件(lib.rs)用于存放应用的核心逻辑,以及一个主文件(main.rs)用于设置路由。

以下是主文件中定义的一个简单路由示例,它接收一个金额参数并返回处理后的结果:

// main.rs 中的路由示例
#[get("/change/<amount>")]
async fn change(amount: f64) -> String {
    format!("Change for ${}", amount)
}

构建精简的Docker镜像

上一节我们介绍了项目的基本代码结构,本节中我们来看看如何将其打包成Docker容器。关键在于Dockerfile的编写,我们使用distroless基础镜像来创建体积极小的容器镜像。

以下是Dockerfile的核心内容:

# 使用多阶段构建来减小镜像体积
FROM rust:latest as builder
WORKDIR /usr/src/app
COPY . .
RUN cargo build --release

# 使用极简的distroless镜像运行
FROM gcr.io/distroless/cc-debian12
COPY --from=builder /usr/src/app/target/release/my_rust_app /app/
WORKDIR /app
EXPOSE 3000
CMD ["./my_rust_app"]

这个Dockerfile执行了以下操作:

  1. 在第一阶段(builder)使用完整的Rust环境编译应用。
  2. 在第二阶段仅复制编译好的二进制文件到极简的distroless镜像中。
  3. 暴露应用运行的端口(3000)。
  4. 设置容器启动时运行的命令。

这种方法生成的镜像非常小,便于快速部署和传输。

构建与运行容器

理解了Dockerfile的原理后,接下来我们执行具体的命令来构建和运行容器。我们将使用终端命令进行操作,同时也会观察Docker Desktop图形界面提供的信息。

以下是构建和运行容器的主要步骤:

  1. 构建Docker镜像:在项目根目录下执行以下命令,-t参数用于给镜像打上标签。

    docker build -t my-rust-image .
    
  2. 运行Docker容器:使用-d参数让容器在后台运行,-p参数将主机的3000端口映射到容器的3000端口。

    docker run -d -p 3000:3000 my-rust-image
    

在构建和运行过程中,可以打开Docker Desktop查看资源使用情况、容器列表和日志。终端命令效率高,而图形界面能提供更直观的全局视图,两者结合使用非常方便。

测试应用与理解端口映射

容器在后台运行后,我们需要验证应用是否正常工作。同时,理解Docker的端口映射机制至关重要。

我们可以使用curl命令来测试之前定义的路由:

curl "localhost:3000/change/34"

预期会收到响应:"Change for $34"

为了确认容器的网络配置,可以执行:

docker ps

该命令会列出运行中的容器。在输出中,可以看到PORTS列显示为0.0.0.0:3000->3000/tcp。这表示主机的3000端口(外部)被映射到了容器内部的3000端口。

停止与清理容器

完成测试后,为了释放系统资源,我们需要停止并移除容器。

以下是清理资源的步骤:

  1. 停止容器:首先使用docker stop命令停止运行中的容器,需要提供容器ID。

    docker stop <container_id>
    
  2. 移除容器:容器停止后,可以使用docker rm命令将其删除。

    docker rm <container_id>
    

执行docker ps再次检查,确认容器已从运行列表中消失。

容器化工作流的优势总结

本节课中我们一起学习了完整的本地Docker容器工作流。我们从一个Rust微服务代码开始,编写Dockerfile,构建出精简的镜像,运行并测试了容器,最后进行了清理。

这种工作流的核心优势在于“一次构建,随处运行”。我们在本地开发环境构建的容器镜像,可以几乎不做修改地部署到各种生产环境中,例如:

  • Amazon ECSEKS(亚马逊弹性容器服务/ Kubernetes服务)
  • AWS App Runner
  • AWS Lambda(通过容器镜像支持)
  • Google Cloud Run

容器化技术确保了开发、测试和生产环境的一致性,极大地简化了部署流程,是云原生应用开发的基础。

大型语言模型实践:P87:提示工程工作流 🧠

在本节课中,我们将学习提示工程的核心概念与几种实用工作流。提示工程是一门通过精心设计输入文本来引导大型语言模型生成特定、高质量输出的艺术。我们将探讨提示的定义、几种关键技巧及其在代码生成等场景中的应用。

什么是提示?💡

上一节我们介绍了课程概述,本节中我们来看看提示的基本定义。提示是一个文本输入,它为模型提供上下文,并引导模型产生特定的响应。

以下是一个简单的例子。我们有一段Rust代码和一个提示:

// 提示:请逐行详细注释这段Rust代码,解释其功能。
fn marcopolo() {
    for i in 1..=100 {
        if i % 15 == 0 {
            println!("Marcopolo");
        } else if i % 3 == 0 {
            println!("Marco");
        } else if i % 5 == 0 {
            println!("Polo");
        } else {
            println!("{}", i);
        }
    }
}

在应用提示后,模型会为代码生成详细的逐行注释。这对于帮助新加入团队的开发者快速理解现有代码库非常有用。

少样本学习示例 🎯

理解了提示的基础后,我们来看看少样本学习。这种技巧通过提供少量示例来“教导”模型执行特定任务。

以下是使用少样本学习教模型编写华氏度转摄氏度函数的例子。我们提供了几个输入输出对作为示例:

示例1:
输入: 32°F
输出: 0°C

示例2:
输入: 212°F
输出: 100°C

示例3:
输入: 98.6°F
输出: 37°C

任务: 请根据以上模式,编写一个将华氏度转换为摄氏度的函数。

模型在学习了这几个例子后,就能够理解转换规则并生成相应的函数代码。

角色扮演风格 🎭

除了少样本学习,另一种有趣的技巧是角色扮演。这指的是指示模型以特定人物或风格来生成文本。

在代码注释的场景中,我们可以要求模型模仿一种独特的风格。例如:

提示:请以莱纳斯·托瓦兹(Linus Torvalds)的风格为以下代码添加注释。众所周知,他在代码审查中言辞犀利。

模型可能会生成诸如“得了吧,这代码是五岁小孩写的吗?简直是浪费时间,我奶奶都能写出更好的。”之类的注释。虽然这种风格不一定鼓励人,但它展示了如何通过调整提示来改变输出的语气和风格。

思维链推理 🔗

现在,让我们探讨一种更结构化的方法:思维链。这种方法要求模型将推理过程分解为一系列连续的步骤,对于解决复杂问题尤其有效。

在编程任务中,一个完整的思维链提示可能包含以下部分:

  1. 明确目标:在开头清晰陈述要解决的问题。
  2. 描述高级策略:概述实现目标将采用的整体方法。
  3. 初始化步骤:列出并说明准备工作。
  4. 分步注释:为代码的每个部分添加解释其目的的注释。
  5. 验证结果:展示预期的输出以验证代码的正确性。

这种结构化的提示方式不仅适用于提示工程,其本身也是一种优秀的设计和编程实践。它为模型提供了一个清晰的“脚手架”,使其能够更准确地填充和完成剩余部分。

核心技巧总结 📝

以下是本节课介绍的几种核心提示工程技巧的简要回顾:

  • 基础提示:提供清晰的上下文和指令来引导模型。
  • 少样本学习:通过提供少量输入输出示例来教导模型新任务。
  • 角色扮演:指定一种风格或角色,让模型以此风格生成内容。
  • 思维链:将复杂问题分解为一系列逻辑步骤,引导模型逐步推理。

总结

本节课中我们一起学习了提示工程的基本概念和几种关键工作流。我们了解到,提示是为模型提供指引的文本输入。通过少样本学习,我们可以用少量示例教会模型新技能。角色扮演技巧允许我们控制输出的风格和语气。而思维链方法则通过结构化、分步的提示来提升模型处理复杂任务的可靠性和准确性。

尽管提示工程有时被视为简单或噱头,但在实际应用中,尤其是在代码生成、理解和设计方面,精心设计的提示能显著提升大型语言模型的输出质量和实用性。掌握这些技巧是有效利用现代AI工具的关键一步。

大型语言模型实践:P88:使用Claude进行文本摘要 📝

在本节课中,我们将学习如何利用Anthropic公司的Claude AI助手进行文本摘要。我们将通过一个具体的例子——分析海明威的《老人与海》——来演示如何上传文档、请求摘要、提取关键信息,并最终结合自身想法生成新的内容。


上一节我们介绍了Claude作为通用AI助手的基本概念。本节中,我们来看看如何具体操作,利用它处理文本并进行摘要。

这里我们有Anthropic公司的Claude,它是一个通用AI助手。我们可以用它来处理海明威的《老人与海》这本著名书籍,并就其文本内容提出一些问题。

以下是操作步骤:

首先,我向下滚动并复制书籍内的所有文本。使用Claude的一个好方法是,你可以直接上传文档。它会自动识别并将其放入一个文本文件中。

接着,我可以要求它为这段文本提供一个简短的段落摘要。

我们可以输入指令:summarize this book in a small, concise paragraph.

这类技术的一个优点是能够使用上传的文档。这相比仅能聊天是一个显著的增强,因为你可以为它提供更丰富的上下文信息,说明你试图完成的任务。此外,你还能处理不同格式、不同风格的数据,而不仅仅局限于聊天界面。

我们可以看到,它给出了回复:“以下是《老人与海》的简洁段落摘要:《老人与海》讲述了一位年迈的古巴渔夫在84天没有捕到鱼后,终于钓到一条巨大的马林鱼。他与鱼搏斗了三天并将其杀死。在返回岸边的途中,鲨鱼袭击并吞噬了马林鱼,只留下骨架。尽管老人没有带回战利品,但他在磨难中展现的坚韧证明了他的英雄精神,他在精神上取得了胜利。”

实际上,我很难想象能写出比这更好的《老人与海》摘要了。由此可见,这些AI助手在某些能力上是非常精准的。


在了解了基础摘要功能后,我们还可以进一步要求它以更精炼的形式提取信息。

我们甚至可以要求它提供三个关键点。例如,我们可以说:give me three key lessons and only use one word for the lessons.

与AI助手互动的方式之一,就是充分利用它最擅长的功能,即摘要阅读大量文本的能力。这实际上是一种很好的头脑风暴方式,可以说,在处理生成式AI时,它能像一个同事一样与你协作。

我们可以看到,它给出了三个词:perseverance(毅力)、fortitude(坚韧)、resilience(韧性)。


基于AI提取的核心概念,我们可以进一步结合自己的想法,引导它生成更具体、更具创造性的内容。

然后,我可以在此基础上进行扩展,要求它利用我自己的想法,基于已获得的信息再深入一步。

我们可以说:write a small synopsis based on sports that is at most three lines and discusses these traits in an American high jumper who goes to the Olympics.

这实际上是结合AI助手最擅长的能力与我个人的生活经验和想法,产生协同效应。这将是接下来使用这些AI助手的最佳方式之一。

显然,我们也可以通过API、在云平台上完成这些任务。我们可以基于使用像生成式AI这样的云端机器学习解决方案,结合我现有的基础设施、用户界面和命令行工具,来真正开发新兴技术。

它给出的三行摘要如下:“在多年未能跳过七英尺后,一位跳高运动员经过不懈训练终于成功,并前往奥运会。在那里,他第一次试跳失败,但拒绝放弃,最终越过横杆赢得金牌。他的毅力和韧性熠熠生辉。”

我认为这是一个相当好的反馈循环示例。它确实是让你真正理解什么是生成式AI、以及我该如何使用它的最佳途径之一。它并非魔法,而是一个我们可以用来构建新解决方案的有用工具。


本节课中,我们一起学习了如何使用Claude AI助手进行文本摘要。我们从上传《老人与海》的文本开始,逐步演示了如何获取段落摘要、提取单字关键词,并最终结合体育场景的创意,生成了一个关于奥运跳高运动员的简短故事。这个过程展示了生成式AI在信息处理、创意激发和内容生成方面的强大辅助能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P89:在Cloud9中使用Rust版CodeWhisperer 🦀

在本节课中,我们将学习如何在AWS Cloud9环境中,结合Amazon CodeWhisperer这一AI编程工具,来编写和运行Rust代码。我们将从设置环境开始,逐步演示如何使用AI辅助编程功能来构建一个简单的计算器程序。

概述

Amazon CodeWhisperer是一个AI驱动的编程工具,它能以编程方式帮助你构建代码。它作为一个AI编码伴侣,可以与集成开发环境(IDE)协同工作。它既可以在Visual Studio Code中使用,也可以在AWS Cloud9环境中运行。

探索Cloud9环境

首先,让我们来看看Cloud9。它的一个优点是能够轻松创建新的、可随时丢弃的环境来测试各种功能。

如果进入Cloud9并选择创建环境,我们可以为其命名(例如“test”),并从众多选项中进行选择,包括一些性能强大的机器。列表中包含各种大型机器实例,甚至包括裸金属服务器。我们还可以选择在Amazon Linux上构建环境,这有助于确保我们编写的代码能很好地适用于亚马逊的部署环境。

在配置环境时,还可以设置超时时间,这是一种很好的配置方式。你甚至可以通过SSH进入环境进行控制,或者将其放入VPC中。

配置与启动CodeWhisperer

我已经有一个正在运行的环境,并且已经集成了AWS CodeWhisperer。让我们看看它是如何工作的。

点击AWS图标,可以看到有关AWS的信息,我可以控制不同的服务。进入开发者工具,在这里我已经打开了CodeWhisperer。可以看到它正在主动为我的代码提供建议。

一个Rust示例

让我们来看一个具体的例子。注意,在Rust代码中,我可以插入注释。例如,我写了一个注释“构建一个打印1+1的函数”,CodeWhisperer能够根据这个注释生成相应的代码。让我们找到这个示例,它在hello项目中。进入hello目录,如果输入cargo run,就能看到我能够利用这些建议来运行和修改我的代码。

需要指出的是,为了让Rust在Cloud9上运行,你需要执行rustup命令。只需复制屏幕上显示的指令,粘贴并运行即可。它会提示你进行安装,选择“proceed with installation”(继续安装)、“customize installation”(自定义安装)或“cancel”(取消)。由于我已经完成此步骤,这里选择取消。

从零开始构建项目

现在,让我们从头开始构建一个项目。首先,向上返回一个目录,然后输入cargo new cw_project来创建一个名为“cw_project”的新项目(代表CodeWhisperer项目)。创建完成后,进入这个新目录。

在这里,如果查看src目录下生成的main.rs文件,会发现它包含了入门级的代码,即经典的“Hello, world!”程序。运行cargo run命令来执行它。

使用CodeWhisperer编写代码

接下来,让我们开始使用CodeWhisperer。首先,我会创建一个多行Rust注释来设定程序上下文,这是使用AI结对编程工具时非常重要的一步。我会写下:“这是一个充当基本计算器的脚本”。

设定好上下文后,我开始引导它生成代码。例如,我输入“使用标准输入输出库”,它会给出导入std::io的建议。我们可以接受或拒绝这些建议。在这个例子中,我选择自己输入:“创建一个加法函数”。

引导AI就像指导同事一样。它生成了函数的基本结构,看起来不错。然后它继续补全了这个函数的具体实现。

现在,我可以继续整合代码。我输入“将两个数字相加”,然后定义变量来存储结果:let result = ...。接着,我输入打印结果的语句,注意到CodeWhisperer会自动进行替换以使其正常工作。

现在运行cargo run。哦,看起来有个问题,编译器提示“未闭合的分隔符”。这正是结合使用像Rust这样强大的语言和CodeWhisperer的好处之一:编译器告诉我哪里错了,而AI结对编程工具则帮助我构建代码。它会自动补全那个代码块。

再次运行cargo run,现在程序成功构建并运行了。

代码格式化与扩展功能

另外一些有趣的点是,我喜欢对代码进行格式化。cargo fmt命令可以帮我整理代码格式。回到环境中,输入cargo fmt,可以看到它自动清理了代码。

因此,结合“正确描述要构建的功能”(设定提示词)、逐步引导、运行编译(cargo run)以及格式化(cargo fmt),你就能充分利用AI结对编程的所有优势,同时享受编译器带来的好处。

最后,让我们再扩展一下功能。我输入“创建一个减法函数”。它很智能,知道我想要做什么。它给出了相应的代码。然后,我们可以添加第二个结果变量,比如let res2 = ...,并将其改为result2

运行cargo fmt进行格式化,再运行cargo run。看,我们得到了-1和5两个结果。

总结

本节课中,我们一起学习了如何在AWS Cloud9环境中利用Amazon CodeWhisperer进行Rust开发。关键在于:有时选择特定的部署目标(这里是运行Amazon Linux的Cloud9),主动向AI寻求代码建议,运行编译器进行检查,同时利用结对编程工具形成一个高效的反馈循环,从而获得最佳的开发结果。

大型语言模型实践:P90:安装与配置 CodeWhisperer CLI 💻

在本节课中,我们将学习如何安装和配置 AWS CodeWhisperer 的命令行界面(CLI)。我们将了解其核心功能,包括智能自动补全和自然语言转 Bash 命令,并完成基本的设置步骤。

安装与认证

上一节我们介绍了课程背景,本节中我们来看看如何获取并安装 CodeWhisperer CLI。

首先,你需要从官方文档下载适用于 Mac OS 系统的 CodeWhisperer CLI 安装包。下载完成后,你需要使用一个 Builder ID 进行身份认证。完成认证后,你便可以在你的 Shell 环境中使用所有增强的自然语言处理功能。

核心功能与界面

安装完成后,我们可以打开其偏好设置界面。以下是你可以开始使用的一些主要功能。

  • 智能自动补全:界面会显示一个窗口,实时展示所有正在进行的操作。它提供便捷的自动补全建议,帮助你导航文件夹,并为不同的目录提供选项。
  • CLI 命令补全:此功能会展示所有你可以执行的不同操作。你还可以通过自定义设置来增强它,例如:
    • 允许在空格后立即执行命令。
    • 允许执行危险命令(适合专家用户)。
    • 启用模糊搜索,根据你的具体用例,这可能非常有用。
    • 配置不同的字体等显示设置。

自然语言转 Bash 命令

除了自动补全,许多人可能还对自然语言转 Bash 命令的功能感兴趣。

你可以使用 # 符号或 cw ai 命令来触发此功能。由于我个人工作流中经常使用 #,我将选择使用 cw ai 命令。触发后,你可以输入自然语言问题,例如 list files(列出文件)。系统会进行处理,并为你提供一个可执行的命令选项,你可以选择执行它。

集成与配置

最后,你可以通过配置界面设置快捷键绑定、集成和偏好设置。

CodeWhisperer CLI 支持与多种终端和编辑器集成,包括 Hyper 终端、VS Code 终端、iTerm2,甚至对 JetBrains 系列 IDE 也提供了实验性支持。例如,如果你使用 IntelliJ IDEA 进行开发,也可以配置集成。

总结

本节课中我们一起学习了 AWS CodeWhisperer CLI 的完整安装与配置流程。我们了解了如何下载安装、进行身份认证,并探索了其核心功能:智能自动补全和强大的自然语言转 Bash 命令能力。最后,我们还查看了它与其他开发工具的集成选项。完成这些步骤后,你只需在终端中输入 cw ai,即可开始使用自然语言来辅助你的命令行操作。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P91:使用CodeWhisperer CLI 🛠️

在本节课中,我们将学习如何使用AWS CodeWhisperer的命令行界面(CLI)工具。我们将探索它如何帮助理解AWS命令、生成代码片段以及辅助完成日常开发任务。

概述

AWS CodeWhisperer CLI是一个强大的工具,它允许开发者使用自然语言与命令行交互,并智能地生成AWS服务相关的命令。本节将演示其核心功能,包括命令自动补全、自然语言翻译为Shell命令,以及作为AWS API的探索工具。

启动与基础使用

首先,我们需要在已安装AWS CodeWhisperer CLI的终端中启动它。

在终端中输入以下命令来启动工具:

code whisper ai start

启动后,我们可以使用自然语言向它提问。例如,输入“List files”,工具会将其翻译为Shell命令 ls -l。这对于不熟悉Shell命令的用户尤其方便。

启动后,界面会提供一个菜单,允许我们执行命令、编辑命令、重新生成答案、提出新问题或取消操作。

现在,让我们执行生成的 ls -l 命令。

AWS命令自动补全

上一节我们体验了基础的自然语言翻译功能。本节中我们来看看CodeWhisperer CLI一个强大的特性:针对AWS命令的智能自动补全。

由于此工具由AWS开发,它对AWS命令有出色的自动补全支持。例如,输入 aws s3 后,工具会自动列出所有可用的S3相关命令。

这非常有用,因为查阅官方文档通常很耗时。我们可以利用这种探索式的方法快速了解可执行的操作。

继续输入命令,例如 aws s3 ls,即可查看所有的S3存储桶。

这个功能不仅限于S3服务。输入 aws ec2 等前缀同样有效。这是一种极佳的方式来理解AWS各服务的API,无论你使用的是Ruby、Python还是其他语言。我认为这是该工具最有价值的初始用途之一。

生成工作流命令

除了自动补全,CodeWhisperer CLI还能帮助我们构思新的工作流程。

以下是它作为工作流生成器的一个例子。假设我们想将本地文件复制到S3存储桶。

我们可以输入一个自然语言请求,例如:“copy files from downloads to a S3 bucket in my account”。

工具会生成一个接近我们需求的命令。虽然可能不完全精确,但它提供了一个极佳的起点。如果需要,我们可以将生成的命令复制到编辑器中进一步调整。

这个功能也是一个AWS命令的“灵感生成器”。例如,你可能之前不知道可以使用递归复制命令。

与复杂AWS服务交互

我们已看到工具处理基础命令和生成工作流的能力。接下来,我们探索它如何协助与更复杂的AWS服务进行交互,例如DynamoDB。

从命令行操作DynamoDB可能较为复杂。CodeWhisperer CLI可以简化这个过程。

例如,输入:“list all dynamo DB tables”。工具会生成对应的AWS CLI命令 aws dynamodb list-tables

执行该命令,我们可以看到当前账户下的DynamoDB表,例如一个名为“music”的表。

如果我们想向这个表添加一个项目,可以继续提问。例如:“Add the term Classical to my Dynamo DB table Music”。

工具生成的命令可能不是完全准确或完美的,但它提供了一种文档式的起点。此时,我们可以将这些命令分步复制到更专业的编程环境中去执行和调试。

总结

本节课中我们一起学习了AWS CodeWhisperer CLI的核心用途。总而言之,该工具的优点是:

  • 出色的自动补全:帮助你洞察AWS命令的工作方式。
  • 生成一次性命令:协助处理常规的批处理或Shell任务。
  • 提供灵感和起点:作为探索AWS API和生成命令原型的有效工具。

AWS CodeWhisperer CLI是一个非常实用的工具,值得尝试。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P92:构建Bash CLI工具 🛠️

在本节课中,我们将要学习如何构建一个Bash命令行界面工具。我们将了解其基本结构,并通过一个公式化的方法来分解和实现它,使初学者也能轻松掌握。


什么是Bash命令行工具? 🤔

让我们先来看看Bash命令行工具是什么。首先,脚本有一个名称。这是第一部分。然后,你需要传入一些选项来收集值。例如,我们看到这里的 count 选项会是 --count,并且有一个与之关联的值。这里还有另一个选项 phrase,即 --phrase。因此,我的代码需要能够解析这些选项。


构建Bash CLI工具的公式 📝

实际上,我总结出了一个公式,你可以将其应用于几乎任何Bash命令行工具。

以下是构建步骤:

  1. 构建代码功能:这可以是一个加法函数、计数函数,或者任何你正在构建的功能,比如一个备份脚本。你需要将其构建成一个Bash函数。
  2. 解析输入:你需要编写能够解析从命令行传入内容的代码。
  3. 整合与执行:当你具备了以上两部分后,就可以将它们整合起来,并将收集到的输入传递给功能函数。

这个公式是构建命令行工具的一个绝佳方法。接下来,让我们看看它的实际应用。


公式实战演练 💻

让我们看一下之前展示的命令行工具,并验证这个公式。

首先,我们再次看到脚本的名称,这里是 ci.sh。我需要解析一些选项,并且需要能够运行一些逻辑代码。

第一部分:定义功能(A部分)

这是功能定义部分,用于多次生成短语。

让我们逐步分解:

generate_phrases() {
    local count=$1
    local phrase=$2
    for ((i=0; i<count; i++)); do
        echo "$phrase"
    done
}
  • generate_phrases 是函数名。
  • 实际工作是一个 for 循环,根据传入的计数次数,重复输出传入的短语。

第二部分:解析选项(B部分)

这是设置选项解析的地方,这部分可以相当公式化。

while [[ $# -gt 0 ]]; do
    case $1 in
        --count)
            COUNT="$2"
            shift 2
            ;;
        --phrase)
            PHRASE="$2"
            shift 2
            ;;
        *)
            echo "未知选项: $1"
            exit 1
            ;;
    esac
done
  • 这里使用了一个 while 循环,只要还有参数,就继续处理。
  • 在循环内部,case 语句允许我在不同的选项值之间切换,捕获 --count--phrase 的值。
  • 处理完成后,结束整个循环。

第三部分:整合与执行(C部分)

现在我已经获得了输入,只需要将其传递给我之前定义的函数即可。

generate_phrases "$COUNT" "$PHRASE"

在这个例子中,我只是打印出计数和短语。


工具运行示例 🚀

那么它是如何工作的呢?我们可以从命令行运行它。

./ci.sh --count 5 --phrase "Hello"

我们可以改变参数值:

./ci.sh --count 2 --phrase "I love coding."

这将为我们生成两个“I love coding.”的输出。


总结 📚

本节课中,我们一起学习了构建Bash命令行工具的完整流程。我们介绍了一个实用的三部分公式:

  1. A部分(功能):编写实现核心逻辑的Bash函数。
  2. B部分(解析):使用 while 循环和 case 语句来解析命令行传入的选项和参数。
  3. C部分(整合):将解析得到的参数传递给功能函数并执行。

当你构建命令行工具时,思考这个A-B-C结构会非常有帮助:A部分是功能实现,B部分是输入解析,C部分是将所有部分整合起来并运行你的代码。遵循这个模式,你可以更有条理地创建出功能强大的Bash脚本工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P93:Bash函数 🐚

在本节课中,我们将要学习Bash脚本中一个非常强大的概念——函数。我们将了解函数是什么、为什么使用它们,并通过具体的例子来掌握如何定义和调用Bash函数。

概述:什么是Bash函数?

Bash函数可以被看作是一个“小机器”。就像你家中的洗碗机一样,它接收输入(脏碗碟和水),执行一个过程(清洗),然后产生输出(干净的碗碟)。在编程中,函数也遵循类似的逻辑:它接收输入(参数),执行一系列操作,并产生输出(结果)。

函数的基本结构

上一节我们介绍了函数的核心类比,本节中我们来看看如何在Bash中定义一个函数。

Bash函数的基本结构非常简单。它由函数名、一对圆括号和包含代码块的花括号组成。

function_name() {
    # 在这里编写你的代码
}

以下是一个最简单的函数示例,它模拟(mimic)传入的参数:

mimic() {
    echo $1
    echo $2
}

这个mimic函数会回显(echo)传入的第一个和第二个参数。如果你调用mimic one two,它将输出onetwo

函数的核心优势:代码复用

为什么你需要一台洗碗机?因为你可以反复使用它。同样,为什么你需要一个Bash函数?因为它允许你反复使用同一段代码。

以下是使用mimic函数两次的例子:

mimic one two
mimic 99 100

请注意,我们不需要为第二次调用重写echo代码。这就是编写函数的核心概念——可复用性。无论是备份脚本还是其他逻辑,你都可以将通用操作封装成函数,只需传入不同的参数即可。

Bash函数的独特之处:没有显式的return

与其他编程语言不同,Bash函数没有显式的return语句来返回值。那么,如何从函数中获取结果呢?唯一的办法是捕获函数的echo输出。

让我们看一个更复杂的例子:一个执行加法运算的函数。

add() {
    num1=$1
    num2=$2
    result=$((num1 + num2))
    echo $result
}

在这个add函数中:

  1. 我们将第一个参数赋值给变量num1
  2. 我们将第二个参数赋值给变量num2
  3. 我们使用$((...))语法计算两者的和,并将结果赋值给result变量。
  4. 最后,我们使用echo $result将结果输出到标准输出(stdout)。

调用add 1 2将会在终端上打印出数字3

捕获函数输出并再次使用

由于Bash函数通过echo输出结果,我们可以捕获这个输出并将其赋值给另一个变量,或者传递给另一个函数。

以下是如何捕获add函数输出的示例:

output=$(add 4 9)

这行代码执行了add 4 9,计算结果是13。这个结果没有直接打印到屏幕,而是被捕获并存储在了output变量中。

现在,我们可以对这个值做任何操作。例如,我们可以将它再次传入add函数:

final_result=$(add $output $output)
# 这相当于执行 add 13 13,final_result 的值将是 26

这个过程演示了Bash函数的强大之处:通过巧妙地使用echo和命令替换($()),我们可以实现数据的传递和复杂逻辑的构建。

总结

本节课中我们一起学习了Bash函数的核心概念和应用。

我们首先将函数比作一个接收输入、执行处理、产生输出的“机器”。接着,我们学习了定义Bash函数的基本语法。我们重点探讨了函数的核心优势——代码复用,这避免了重复编写相同逻辑的代码。然后,我们了解了Bash函数的一个关键特性:它没有显式的return语句,而是通过echo命令来输出结果。最后,我们掌握了如何捕获函数的输出结果,并将其存储到变量中或作为其他函数的输入,从而实现更复杂的操作流程。

掌握Bash函数能让你写出更加模块化、可维护和强大的脚本。

大型语言模型实践:P94:Amazon Bedrock核心组件 🏗️

在本节课中,我们将探索Amazon Bedrock平台的核心组件。我们将了解其概览、基础模型、微调功能以及智能体与知识库的集成,学习如何通过简单的点击操作来构建和实验大型语言模型解决方案。

概览与基础模型

首先,我们来看Amazon Bedrock的概览界面。这个界面看起来简洁明了,但其核心亮点在于基础模型

基础模型通常指参数规模达到十亿级别或更多的预训练模型。在Bedrock中,你可以看到来自不同公司(包括亚马逊自身)提供的多种基础模型。

以下是探索基础模型的方法:

  • 在“基础模型”区域查看可用的模型列表。
  • 点击模型示例,可以获取各种应用场景的提示词范例。例如,在进行角色扮演时,你可以看到具体的提示词是如何构建的。

一个备受关注的重要模型是Claude,它提供了200K的上下文长度。选择该模型后,你可以直接点击“在Playground中打开”进行体验。

模型游乐场与微调

上一节我们介绍了基础模型,本节中我们来看看如何与它们进行交互和定制。

在Playground中,你可以直接与模型对话以测试其能力。例如,你可以输入提示:“什么是健康的紫色水果?”,然后运行并获取模型的回答。这是一个获取灵感和探索API功能的绝佳方式。

此外,在Playground下方,你还可以查看关于此次交互的详细性能指标

除了直接对话,Bedrock还提供了便捷的模型微调功能。其理念是,你可以通过点击按钮来完成微调,这大大简化了流程。

以下是创建微调任务的基本步骤:

  1. 导航至“自定义模型”区域。
  2. 点击“创建微调任务”。
  3. 按照指引配置你的训练数据和参数。

智能体与知识库

接下来,我们将了解Bedrock中更强大的功能:智能体知识库

智能体可以作为一个接口,与特定的知识库进行通信。你可以将其理解为一个定制化的聊天机器人。你可以增强它,并在其中加入任何额外的提示指令,从而获得极其丰富的交互体验。

知识库和智能体的强大之处在于,你可以通过简单的点击操作来构建解决方案。

例如,你可以向连接了知识库的智能体提问:“REST在MLOps中有什么用途?”。智能体会从知识库中检索信息并回答,例如提到“对并发和并行的高支持度”等优点。

你还可以查看详细的执行轨迹,了解整个问答过程是如何被处理的。这清楚地展示了智能体是如何引用你之前建立的知识库来生成答案的。

总结 🎯

本节课中我们一起学习了Amazon Bedrock的核心组件。总而言之,Amazon Bedrock本质上是一个功能强大的实验平台。在这里,你可以通过点击操作来:

  • 使用最新的大型语言模型技术。
  • 对模型进行微调。
  • 实验和构建能够投入生产的解决方案。

这一切,往往只需几次点击即可完成。

大型语言模型实践:P95:探索Boto3 Bedrock客户端Python SDK 🚀

在本节课中,我们将学习如何通过编程方式访问Amazon Bedrock服务中的基础模型。我们将从AWS Cloud Shell开始,逐步深入到使用Python的Boto3 SDK,并了解如何通过Bedrock Runtime来实际调用模型。


访问Amazon Bedrock基础模型

Amazon Bedrock提供了一个基础模型版块,其中包含多种模型,例如Claude、Claude Instant等。用户可以通过AWS管理控制台查看这些模型。


使用AWS Cloud Shell探索模型

上一节我们介绍了Bedrock控制台,本节中我们来看看如何通过命令行工具快速探索可用模型。

一种便捷的起步方式是使用AWS Cloud Shell。在Cloud Shell环境中,无需安装任何额外包,即可直接运行AWS CLI命令。

以下是可用的命令示例:

  • aws bedrock list-foundation-models:列出所有可用的基础模型。
  • 输入aws bedrock可以查看其他相关命令,例如list-custom-models

通过运行aws bedrock help命令,可以查看完整的命令列表和文档。



使用Python Boto3 SDK进行编程访问

虽然CLI工具适合快速探索,但在实际应用中,我们通常需要编写可操作化的代码。这时,Python的Boto3 SDK是更好的选择。

AWS为Bedrock提供了Python客户端,其使用方式与大多数Boto3服务一致。

以下是初始化客户端并查看可用方法的代码:

import boto3
client = boto3.client('bedrock')
# 查看可用方法,例如 list_custom_models, list_foundation_models


通过Bedrock Runtime调用模型

仅仅列出模型还不够,我们的核心目标是调用模型进行推理。这里需要注意一个关键点:模型调用功能并不在主要的bedrock客户端中,而是在bedrock-runtime客户端里。

以下是调用模型的核心步骤:

  1. 创建bedrock-runtime客户端。
  2. 使用invoke_model方法。
  3. 在请求中指定模型ID和包含提示词(prompt)的载荷(payload)。

例如,如果你想使用Claude 2.1模型,需要先在Bedrock控制台找到该模型对应的确切ID,然后在API请求中使用这个ID。



总结与资源

本节课中我们一起学习了以编程方式访问Amazon Bedrock的多种途径。

我们首先通过AWS Cloud Shell和CLI命令快速探索了可用模型。然后,我们介绍了如何使用功能更强大的Python Boto3 SDK,并重点讲解了通过bedrock-runtime客户端来调用模型的关键步骤。

要获取更详细的信息,你可以查阅以下资源:

  • AWS CLI官方文档。
  • Boto3 for Bedrock的官方文档。


大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P96:30_03_03:探索Cargo Rust SDK 🦀

在本节课中,我们将学习如何使用 Rust 编程语言中的 Cargo 工具来探索和集成 AWS SDK for Bedrock。我们将了解如何通过查看 crate 文档来理解其功能,并将其集成到一个新的 Rust 项目中,从而能够调用 AWS Bedrock 的强大服务。

概述 AWS SDK for Bedrock Crate

首先,我们看到的这个 crate 是 AWS SDK for Bedrock。它的描述是:提供用于创建和管理 Amazon Bedrock 模型的 API 操作。

Cargo.toml 文件中,我们可以看到相关的依赖配置。其中包含了 aws-config(用于 AWS 服务配置)、aws-sdk-bedrock(Bedrock 服务的 SDK 本身)以及 tokio(一个 Rust 异步运行时,为我们提供异步编程能力)。

使用 SDK 的基本步骤

上一节我们介绍了 SDK 的基本构成,本节中我们来看看如何使用它。使用这个 SDK 实际上相当直接。

以下是使用 SDK 的基本代码结构:

use aws_sdk_bedrock as bedrock;

#[tokio::main]
async fn main() {
    // 你的代码将在这里
}

首先,你需要通过 use 语句引入 SDK。然后,在 main 函数中,你可以调用 SDK 提供的各种可用操作。

探索可用的 API 操作

为了开始使用,一个很好的起点是列出所有可用的基础模型。你可以通过调用相应的客户端方法来实现。

此外,为了充分利用 SDK,深入查看客户端文档至关重要。文档会详细列出所有可用的功能。

以下是文档中可能包含的一些功能类别:

  • 自定义模型
  • 标签管理
  • 训练数据配置
  • 等等。

通过仔细阅读 crate 本身的文档,你可以清晰地了解所有可用的功能。

创建并运行你的项目

了解了可用的功能后,下一步就是将其集成到你的项目中。

以下是创建和运行项目的步骤:

  1. 使用 cargo new [项目名] 命令创建一个新的 Rust 项目。
  2. 在项目的 Cargo.toml 文件中添加必要的依赖。
  3. 编写你的业务逻辑代码。
  4. 使用 cargo build 命令构建项目。
  5. 最后,使用 cargo run 命令运行项目。

完成这些步骤后,你应该能够成功调用 AWS SDK for Bedrock,从而利用 AWS Bedrock 的所有强大功能。

总结

本节课中我们一起学习了如何探索和使用 Rust 的 AWS SDK for Bedrock。我们从查看 crate 描述和依赖开始,学习了基本的代码结构,并强调了查阅官方文档以了解全部可用功能的重要性。最后,我们回顾了从创建新项目到构建和运行它的完整流程。掌握这些步骤后,你就可以在 Rust 应用中轻松集成并调用 AWS Bedrock 服务了。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P97:31_03_04_Python调用列表模型

在本节课中,我们将学习如何使用Python和Boto3库来调用Amazon Bedrock服务,以编程方式列出可用的基础模型。我们将从一个已配置好的IntelliJ Python项目开始,逐步解析代码结构并执行脚本。

项目结构与配置

首先,我们来看一下项目的基本结构。我们使用ls命令来查看目录内容。

可以看到项目中包含一个Makefile和一个requirements.txt文件。由于我们处于快速原型开发阶段,requirements.txt文件中的依赖项没有固定版本,主要包含boto3blackruff

Makefile文件中的内容也很简单,定义了installformatlens等基本命令。

核心代码解析

上一节我们介绍了项目的基本配置,本节中我们来看看实现模型列表功能的核心代码。

代码的工作原理如下:首先导入boto3库,然后创建一个客户端请求。

由于Bedrock是一项较新的服务,有时需要明确指定服务区域。在本例中,我们指定区域为us-west-2

接着,我们发起请求来列出所有基础模型。获取响应后,我们对数据进行清理,因为我们只关心模型名称中包含“claude”的模型,这是我们后续将要使用的模型。

最后,如果找到了相关信息,我们就将其打印出来,以便后续使用。

核心代码逻辑

import boto3

# 创建Bedrock客户端,指定区域
client = boto3.client('bedrock', region_name='us-west-2')

# 列出基础模型
response = client.list_foundation_models()

# 过滤并处理响应数据
# ... (过滤逻辑)

这是开始以编程方式访问Bedrock服务的方法之一,使用Boto3库通常能获得最好的支持。

运行与验证

以下是运行脚本的步骤。

首先,我喜欢运行make formatmake lens命令来确保代码格式整洁。然后,我们直接运行Python脚本。

执行命令python list_models.py,脚本成功运行。

我们可以看到打印出的结果正是我们想要的:Anthropic Claude V2模型,并且是拥有200K上下文窗口的版本。

通过Bedrock的Boto3接口,你可以快速获取大量信息。同时,编写一些样板代码来清理和格式化响应数据,将为你即将开始的自动化工作提供最佳的数据形式。

总结

本节课中我们一起学习了如何使用Python和Boto3库与Amazon Bedrock服务进行交互。我们了解了如何设置项目、编写代码来列出并过滤基础模型,以及如何运行和验证脚本。这种方法为后续的模型调用和自动化任务奠定了基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P98:32_03_06_Rust调用列表模型

在本节课中,我们将学习如何使用Rust编程语言与AWS Bedrock API进行通信,具体是列出可用的基础模型。我们将从Python代码中获得灵感,然后将其转换为更高效的Rust实现。

概述

我们有一个智能开发环境。我将编写一些代码来与Bedrock API通信。

首先,我可以查看Python版本的代码,即Python list models。但由于Python存在我希望避免的性能问题,我决定使用Rust来构建这个功能。

从Python到Rust的转换

上一节我们提到了性能考量,本节中我们来看看具体的实现方法。

我们可以将Python代码作为参考文档。然后,进入我已设置好的Rust项目。查看项目结构,可以看到这里有一个Cargo.toml文件。

以下是该文件的核心依赖配置:

[dependencies]
aws-config = "0.57.1"
aws-sdk-bedrock = "0.31.0"
tokio = { version = "1.0", features = ["full"] }

在某些方面,使用这里的Rust接口实际上更简单,代码量也更少,具体取决于你要实现的功能。

构建Rust客户端

首先,我引入AWS SDK并导入Bedrock模块。然后进行配置。

以下是创建客户端并列出模型的代码:

use aws_config::BehaviorVersion;
use aws_sdk_bedrock as bedrock;

#[tokio::main]
async fn main() -> Result<(), bedrock::Error> {
    // 加载AWS配置
    let config = aws_config::load_defaults(BehaviorVersion::latest()).await;
    // 创建Bedrock客户端
    let client = bedrock::Client::new(&config);

    // 调用list_foundation_models API
    let resp = client.list_foundation_models().send().await?;

    // 打印模型摘要
    if let Some(models) = resp.model_summaries() {
        for model in models {
            println!("Model ID: {}", model.model_id().unwrap_or("Unknown"));
        }
    }

    Ok(())
}

如你所见,创建客户端后,列出这些基础模型并打印模型摘要实际上是一行代码就能完成的功能。

运行与结果

让我们运行这段代码。只需输入cargo run命令。

编译完成后,程序运行速度非常快。因此,我们需要将输出通过管道传递给less命令,以便清楚地查看发生了什么。

从输出中,我可以查看所有模型的ID。这样,我就可以在后续编程中控制这些基础模型,调用它们并提供自定义提示等。

总结与建议

本节课中我们一起学习了如何使用Rust SDK与AWS Bedrock交互并列出可用模型。

使用Rust的Bedrock SDK时,一个好的起点是:不要害怕偶尔回头参考Python代码。查看它,获取一些文档信息,感受其用法,然后再回到Rust,像我们在这里所做的一样构建一个示例。

大型语言模型实践:P99:通过Bedrock Runtime API调用Claude

概述

在本节课中,我们将学习如何使用Python代码,通过AWS的Bedrock Runtime API来调用Anthropic的Claude模型。我们将了解如何列出可用的基础模型,并实际发送一个请求来获取模型的响应。


列出可用的基础模型

上一节我们介绍了Amazon Bedrock的基本概念。本节中我们来看看如何用Python代码列出Bedrock服务中所有可用的基础模型。

首先,我们需要导入boto3库,它是AWS服务的Python SDK统一接口。一个重要的技巧是,我们需要指定正确的AWS区域,因为不同的模型可能部署在不同的区域。

以下是列出基础模型的代码示例:

import boto3

# 创建Bedrock客户端,指定模型所在的区域(例如us-west-2)
client = boto3.client('bedrock', region_name='us-west-2')

# 调用list_foundation_models方法
response = client.list_foundation_models()

# 打印可用的模型信息
for model in response['modelSummaries']:
    print(f"模型提供商: {model['providerName']}")
    print(f"模型名称: {model['modelName']}")
    print(f"模型ID: {model['modelId']}")
    print("-" * 20)

运行这段代码后,我们可以看到Anthropic等提供商提供的模型,例如Claude 2.1。这为我们下一步调用特定模型做好了准备。


调用Claude模型生成响应

在了解了可用的模型之后,本节我们将实际调用Claude模型来回答一个问题。

以下是调用Claude模型的核心步骤:

  1. 导入必要的库。
  2. 创建Bedrock Runtime客户端。
  3. 构建符合模型要求的请求体。
  4. 发送请求并解析响应。

以下是调用Claude模型的完整代码示例:

import boto3
import json

# 创建Bedrock Runtime客户端,注意服务名称是'bedrock-runtime'
client = boto3.client('bedrock-runtime', region_name='us-west-2')

# 构建请求体,格式需符合Claude模型的要求
body = json.dumps({
    "prompt": "\n\nHuman: 什么是颜色为紫色的健康水果?\n\nAssistant:",
    "max_tokens_to_sample": 300,
    "temperature": 0.5,
    "top_p": 0.9,
})

# 指定要调用的模型ID
modelId = 'anthropic.claude-v2:1'

# 调用模型
response = client.invoke_model(
    body=body,
    modelId=modelId,
    accept='application/json',
    contentType='application/json'
)

# 解析响应
response_body = json.loads(response['body'].read())
print(response_body['completion'])

在这段代码中,我们通过prompt字段向模型提出了一个关于“紫色健康水果”的问题。max_tokens_to_sample参数限制了模型生成文本的最大长度。我们指定了模型ID为anthropic.claude-v2:1,并通过invoke_model方法发送请求。

由于AI模型需要进行GPU推理来“思考”,请求会花费一些时间。最终,我们会得到一个包含答案的响应。例如,模型可能会回答“紫色的健康水果包括紫葡萄、紫李子等”。

这个响应是一个结构化的JSON负载,我们可以轻松地将其集成到无服务器应用(如AWS Lambda)或其他解决方案中。


关键要点与总结

本节课中我们一起学习了通过Bedrock Runtime API操作基础模型的两个核心环节。

以下是需要记住的关键点:

  • 使用boto3.client('bedrock', region_name='<区域>')来列出可用的基础模型。
  • 调用模型时,必须使用Bedrock Runtime客户端,即boto3.client('bedrock-runtime', ...)
  • 请求体(body)需要构建成符合特定模型要求的JSON格式。
  • 必须指定正确的modelId(如anthropic.claude-v2:1)和区域。

除了Python,你也可以使用Rust等其他语言进行调用,它们可能具有更好的性能和部署便利性。掌握这些步骤后,你就可以灵活地将强大的基础模型能力集成到自己的应用程序中了。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P110:09_01_10_通用集群与作业集群对比

在本节中,我们将学习Databricks中两种核心的计算资源类型:通用集群与作业集群。我们将了解它们各自的设计目的、适用场景以及关键区别。

概述

Databricks平台提供了两种主要的集群类型来支持不同的工作负载。通用集群适用于交互式开发和探索,而作业集群则专为自动化、生产级的批处理任务而优化。理解两者的差异对于高效构建数据管道和机器学习工作流至关重要。

通用集群

上一节我们介绍了通用集群的基本概念。通用集群,或称“All Purpose Compute”,是Databricks中一种基础的计算资源。

这种集群类型非常适合运行交互式任务,例如:

  • 在Notebook中进行数据探索和分析。
  • 进行临时的数据查询和可视化。
  • 交互式的机器学习模型开发与调试。

通用集群的设计目标是提供一个灵活、可交互的开发环境。

作业集群

本节中,我们来看看另一种专门为生产任务设计的集群类型:作业集群。要了解作业集群,我们可以导航至“Data Engineering”下的“Job Runs”界面。

在这里,可以看到之前所有作业的运行记录。例如,一个已成功完成的作业运行了大约六分钟。这个界面提供了一个清晰的视图,用于监控作业的成功、失败或跳过状态。

现在,如果我们点击“Create Job”,就可以深入配置一个作业集群。默认情况下,系统会提供一个作业集群配置。

作业集群的核心思想是为运行生产作业而优化和专用。它具有以下特点:

  • 自动伸缩默认启用:以动态应对作业负载的变化。
  • 空闲后自动终止:在闲置一段时间后会自动关闭,以节省成本。

因此,作业集群是处理以下任务的理想选择:

  • 按计划运行的ETL(提取、转换、加载)管道。
  • 周期性的批处理任务。

核心对比与选择

我们已经分别介绍了两种集群。现在,让我们对它们进行直接对比,并了解如何选择。

简而言之,通用集群更适用于交互式的通用数据分析,而作业集群则专为自动化的生产作业设计

在创建作业时,例如我们选择一个Notebook来运行,就可以在配置中看到作业集群的具体规格。与通用集群相比,作业集群通常具有不同的资源配置。例如,它可能拥有更大的内存(如126GB)和更多的核心(如36核)。界面会明确标示此为“Job Cluster”,并将其与现有的“All-Purpose Clusters”区分开来。

作业集群是您工具库中的另一个重要工具。如果您需要运行基于批处理的作业或执行ETL操作,使用作业集群是一个高效且经济的选择。

总结

本节课中,我们一起学习了Databricks中两种关键的计算集群:通用集群和作业集群。我们明确了通用集群适用于交互式开发和数据分析,而作业集群则专为自动化、可调度的生产任务(如ETL和批处理)优化,具备自动伸缩和成本控制特性。理解并根据任务类型选择合适的集群,是构建稳健数据工程流程的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P111:10_01_02:为Databricks配置IntelliJ与Go环境 🛠️

在本节课程中,我们将学习如何在IntelliJ环境中配置Go语言开发环境,并创建一个能够与Databricks SDK交互的简单Go程序。Go语言正成为数据工程师进行SDK开发的一个新兴标准。

概述

我们将从创建一个新的Go模块开始,引入Databricks SDK依赖,编写一个列出所有Databricks集群的示例程序,并最终运行它。整个过程旨在展示Go语言与Databricks集成的便捷性。

创建Go项目目录

首先,我们需要在IntelliJ的Databricks认证数据工程师项目中创建一个新的目录来存放Go代码。

以下是具体步骤:

  1. 创建一个名为 goHo 的新目录。
  2. 进入这个新创建的目录。

初始化Go模块

上一节我们创建了项目目录,本节中我们来看看如何初始化一个Go模块。Go模块用于管理项目的依赖关系。

goHo 目录中,执行以下命令来初始化Go模块:

go mod init sample

这个命令会创建一个初始的 go.mod 文件,该文件将记录我们项目所需的所有依赖项。

引入Databricks SDK依赖

初始化模块后,下一步是引入必要的依赖库。我们将添加官方的Databricks SDK。

运行以下命令来添加Databricks SDK依赖:

go mod edit -require github.com/databricks/databricks-sdk-go@latest

执行后,你可以在 go.mod 文件中看到新添加的SDK依赖。

创建主程序文件

依赖配置完成后,我们需要创建程序的主文件。

接下来,创建一个名为 maingo 的空文件:

touch maingo

这个文件初始是空的,我们将把示例代码粘贴进去。

编写示例代码

现在,让我们向 maingo 文件中添加代码。以下代码来自Databricks官方文档,功能是列出所有可用的集群。

以下是代码内容:

package main

import (
    "context"
    "fmt"
    "github.com/databricks/databricks-sdk-go"
    "github.com/databricks/databricks-sdk-go/service/compute"
)

func main() {
    // 创建Databricks客户端
    w := databricks.Must(databricks.NewWorkspaceClient())
    // 请求集群列表
    all, err := w.Clusters.ListAll(context.Background(), compute.ListClustersRequest{})
    // 错误处理
    if err != nil {
        panic(err)
    }
    // 遍历并打印集群信息
    for _, c := range all {
        fmt.Printf("Cluster: %s (ID: %s)\n", c.ClusterName, c.ClusterId)
    }
}

代码解析:

  • import 部分引入了必要的包,包括上下文、格式化输出以及Databricks SDK。
  • main 函数中,首先创建了一个Databricks工作区客户端。
  • 然后,使用该客户端请求所有集群的列表。
  • 如果发生错误,程序将终止(panic)。
  • 如果没有错误,程序将遍历返回的集群列表并打印每个集群的名称和ID。

整理依赖与构建

代码编写完成后,我们需要下载所有缺失的依赖项并为构建做准备。

执行以下两个命令:

  1. 整理依赖,确保 go.mod 文件与代码中的导入匹配:
    go mod tidy
    
  2. 将依赖包复制到本地的 vendor 目录,以支持构建:
    go mod vendor
    

运行程序

所有配置和构建步骤完成后,现在可以运行我们的Go程序了。

使用以下命令编译并运行程序:

go run maingo

程序将连接你的Databricks工作区,获取集群列表,并在控制台中打印出来。如果配置正确,你将看到类似以下的输出:

Cluster: MyProductionCluster (ID: 1234-567890-abcd12)
Cluster: JobCluster-1 (ID: 2345-678901-bcde23)

总结

本节课中我们一起学习了如何在IntelliJ环境中为Databricks配置Go语言开发环境。我们完成了从创建项目、初始化模块、添加SDK依赖、编写代码到最终运行程序的完整流程。可以看到,使用Go语言操作Databricks SDK实际上非常直接。Go语言具有强大的优势,并且对Databricks SDK有良好的支持。如果你需要为团队提供一个可以部署到Kubernetes或无服务器平台、并与Databricks通信的二进制文件,Go是一个相当不错的解决方案。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P112:11_01_03_安装和使用Databricks CLI

在本节课中,我们将要学习如何在Mac平台上安装和配置Databricks CLI,并探索如何使用命令行界面来管理Databricks工作区,例如启动集群和查询集群信息。

安装Databricks CLI

在Mac平台上,你可以使用Homebrew包管理器来安装Databricks CLI。安装过程非常简单直接。

以下是安装步骤:

  1. 打开终端。
  2. 输入命令 brew install databricks-cli 并执行。
  3. 系统将自动下载并安装CLI工具。

如果你已经安装过,系统会提示已存在,无需重复安装。安装完成后,你可以通过输入 databricks 命令来验证安装是否成功。

配置CLI环境

安装完成后,下一步是配置CLI以连接到你的Databricks工作区。这个步骤会设置工作区地址和认证信息。

你需要运行 databricks configure 命令。这个命令会引导你输入工作区的URL以及个人访问令牌(Token)来进行身份验证。配置完成后,CLI就能与你的Databricks环境进行通信了。

探索CLI命令

配置好环境后,你可以通过 databricks --help 命令查看所有可用的命令。CLI提供了丰富的功能来管理你的Databricks资源。

以下是部分关键命令类别:

  • 账户管理:查看和管理账户设置。
  • 集群操作:启动、停止、列出和获取集群信息。
  • 文件系统:在本地和Databricks工作区之间同步文件和目录。
  • 作业管理:提交和监控作业。

使用CLI管理集群

上一节我们介绍了CLI的基本命令,本节中我们来看看如何具体使用它来管理计算集群。这是日常数据科学工作中非常实用的功能。

首先,你可以使用 databricks clusters list 命令来列出工作区中所有现有的集群及其状态。例如,你可能会发现一些集群处于“已终止”状态,这意味着它们曾经运行过但现在已停止。

如果你想启动一个特定的集群,可以使用 databricks clusters start --cluster-id <CLUSTER_ID> 命令。执行后,CLI会在前台等待并显示启动过程的详细信息,例如正在寻找新节点,直到集群状态变为“运行中”。

查询集群详细信息

当管理大量集群时,你可能需要快速查询特定集群的配置信息,例如硬件类型。CLI结合JSON查询工具可以高效地完成这个任务。

使用 databricks clusters get --cluster-id <CLUSTER_ID> 命令可以获取一个集群的完整详细信息,这些信息以JSON格式返回。为了更清晰地查看特定字段,你可以使用 jq 工具进行过滤。

例如,要查看集群的节点类型,可以运行:

databricks clusters get --cluster-id <CLUSTER_ID> | jq .node_type_id

这条命令会输出类似 “Standard_DS3_v2” 的结果,帮助你快速确认硬件规格。你同样可以查询集群名称或其他任何在JSON负载中的属性。

总结

本节课中我们一起学习了Databricks CLI的安装、配置和基本使用方法。我们了解到,通过命令行界面,你可以方便地列出和启动集群,并通过组合命令与 jq 工具来查询集群的详细配置信息。对于日常使用Databricks系统的用户来说,CLI是一个不可或缺的工具,它允许你在没有Web界面的情况下,也能高效地管理工作区、启动作业并与集群进行交互。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P113:12_01_04_安装和使用RStudio版Databricks 🖥️➡️📊

在本节中,我们将学习如何在R和RStudio环境中使用Databricks。我们将介绍如何安装实验性的Databricks R SDK,并通过R脚本远程管理Databricks集群。

概述

Databricks同样支持R语言和RStudio环境。通过使用Databricks R SDK,用户可以在本地R环境中配置并连接到Databricks工作区,从而执行诸如创建集群等管理操作,无需依赖Web界面。这对于习惯使用R的数据科学从业者来说非常方便。

配置环境与安装SDK

上一节我们介绍了Databricks的基本概念,本节中我们来看看如何在RStudio中具体配置和使用它。首先,你需要在本地R环境中设置Databricks的连接信息。

以下是配置和安装Databricks R SDK的核心步骤:

  1. 获取连接凭证:从Databricks管理控制台获取你的工作区URL和个人访问令牌。
  2. 设置环境变量:将工作区URL和令牌安全地保存在本地的 .Renviron 文件中。注意:此文件包含敏感信息,切勿提交到版本控制系统。
  3. 安装开发工具:在R控制台中,运行 install.packages(“devtools”) 来安装 devtools 包。
  4. 加载开发工具并安装SDK:运行 library(devtools),然后直接从GitHub安装实验性的Databricks R SDK。

在RStudio中实践操作

现在,让我们进入RStudio,看看如何实际运用这些步骤来创建一个Databricks集群。

首先,我已经在R控制台中执行了安装命令。接下来,我打开了一个新的R脚本文件。

在R脚本中,第一步是加载我们刚刚安装的Databricks库。

require(databricks)

加载库之后,我们需要初始化一个客户端实例。这个客户端是与Databricks服务通信的桥梁。

client <- databricks::db_client()

创建客户端后,我们就可以通过它来执行各种命令。例如,这里有一个创建集群的命令。如果你熟悉R语言,这将非常有用,因为你无需打开Web界面就能管理基础设施。

以下是创建集群的代码示例及其参数说明:

response <- client$clusters$create(
  cluster_name = “my_r_cluster”,
  spark_version = “10.4.x-scala2.12”,
  node_type_id = “i3.xlarge”,
  autotermination_minutes = 15,
  num_workers = 1
)
  • cluster_name:为集群指定一个名称,例如 “my_r_cluster”
  • spark_version:指定要使用的Spark运行时版本。
  • node_type_id:选择节点类型。这一点至关重要,因为不同的节点类型适用于不同的工作负载(例如机器学习任务或数据工程任务),你需要选择符合需求的类型。
  • autotermination_minutes:设置集群自动终止的时间,15分钟是一个合理的默认值,有助于控制成本。
  • num_workers:对于实验性用途,设置一个工作节点通常就足够了。

命令执行后,会返回一个结果,其中包含工作区URL等信息。最后,我们可以打印出响应来确认操作成功。

workspace_url <- response$webui
# 确保URL以斜杠结尾
if (!endsWith(workspace_url, “/”)) {
  workspace_url <- paste0(workspace_url, “/”)
}
print(paste(“Cluster created. Workspace URL:”, workspace_url))

实际上,我已经成功运行了这段代码。在我的环境中,现在有一个名为“my_r_cluster”的集群正在运行。从返回信息可以看到,它成功设置了主机节点和工作节点,总计两个节点。

验证操作结果

为了验证集群是否真的创建成功,我们可以在RStudio中使用Databricks CLI命令进行查询。

在R控制台中运行以下命令:

system(“databricks clusters list”, intern = TRUE)

执行后,我们应该能在输出列表中看到 my_r_cluster。事实上,查询结果确实显示该集群正在运行。这证明通过R语言远程管理Databricks基础设施是完全可行的。

总结

本节课中我们一起学习了如何在RStudio环境中集成并使用Databricks。我们完成了从安装实验性R SDK、配置连接凭证,到编写R脚本远程创建并验证Databricks集群的完整流程。对于熟悉R语言并主要工作在RStudio环境中的数据科学从业者而言,这提供了一种高效、便捷的Databricks基础设施管理方式。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P114:13_01_05:Databricks笔记本系统介绍

在本节课中,我们将要学习Databricks笔记本界面的基本操作,包括如何创建笔记本、使用不同编程语言、组织项目结构以及查询数据。

界面概览与创建笔记本

首先,让我们看一下Databricks的笔记本界面。你可以通过导航到“新建”区域并点击“笔记本”选项卡来创建一个新笔记本。

我已经创建了一个笔记本,并将其命名为“data science”。在数据科学项目中,构建一个探索性数据分析工作流是非常常见的需求。

选择编程语言

请注意,默认情况下,笔记本支持使用SQL。但你也可以切换到其他语言,例如Python、Scala或R。具体使用哪种语言取决于你的项目需求。目前,我们先保留默认的SQL设置。

组织笔记本结构

接下来,我将展示在开始使用笔记本时,我认为一个良好的第一步是什么。

首先,我们有一个Markdown单元格。从目录中可以看到它。如果你在这里放置一个Markdown单元格,并双击它,你会看到它使用了Markdown标签,这可以为我们创建层级结构。

对于一个数据科学工作流,我建议首先创建“数据摄取”部分。

然后,你可以通过复制、粘贴并修改的方式,在这里创建另一个Markdown单元格,我们可以将其命名为“EDA”(探索性数据分析)。

现在,如果我们回到目录,可以看到新增了一个部分。我们还可以再创建一个单元格,例如命名为“建模”,如果你打算进行一些机器学习工作。

最后,我们可以再创建一个“结论”部分,例如展示预测分析的结果。

查询与探索数据

现在,如果我们进入这些部分中的任何一个,这里都是放置新单元格并编写代码的好地方。请注意,在“数据摄取”阶段,我运行了一个SQL命令。

那么,我是如何知道从哪里开始查看数据的呢?

如果我们转到工作区这里,可以看到我可以查看其他笔记本,或者查看数据目录。

在目录中,你可以从示例数据集开始。这里有几个示例数据集,例如纽约市出租车数据集。

如果我想查询它,可以点击中间的加号。从这里,我可以开始精确地查询这个层级结构。

例如,输入 SELECT * FROM samples.nyctaxi.trips LIMIT 10。要运行这个查询,只需按 Shift + Enter

它会快速运行查询,并提供一个表格供我滚动浏览和查看不同的数据项。这非常方便,因为我不需要做太多操作,就可以轻松地交互式探索数据。

管理单元格与项目总结

当然,我也可以隐藏这些单元格。这是一个需要注意的功能,你可以根据需要隐藏单元格。

如果我想要创建新的单元格,例如用于探索性数据分析、建模或结论,都可以轻松添加。

最后,我可以回到我的层级目录,点击任何部分,它就会直接导航到那里。

综上所述,一个标准的数据科学项目设置流程是:创建“数据摄取”、“探索性数据分析”、“建模”、“结论”这样的结构;通过查询来探索你的数据集(首先确保你知道要使用哪个数据集,例如你已经上传的数据或示例数据);在项目结束时,你可以将笔记本分享给团队中的其他成员。

本节课中,我们一起学习了Databricks笔记本的基本界面操作、如何选择编程语言、使用Markdown组织项目结构、查询和探索数据以及管理笔记本单元格。掌握这些是进行高效数据科学工作的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P115:14_01_06_执行笔记本 📓

在本节课中,我们将要学习如何在Databricks笔记本界面中执行代码。我们将探索多种执行方式,从运行单个单元格到调度整个笔记本作业,并了解一些能提升效率的辅助功能。

多种执行方式

上一节我们介绍了Databricks笔记本的基本界面,本节中我们来看看如何执行其中的代码。Databricks提供了灵活的执行选项,你可以根据需要选择不同的运行模式。

以下是主要的执行方式列表:

  • 运行全部:一次性执行笔记本中的所有单元格。
  • 运行选定单元格:仅执行当前选中的单元格,适用于处理大数据时避免重复运行所有代码。
  • 运行上方所有单元格:执行从笔记本开头到当前单元格(包含)的所有代码。
  • 运行下方所有单元格:执行从当前单元格到笔记本末尾的所有代码。
  • 运行最后执行的单元格:重新运行上一次执行过的单元格。

重置与调度执行

除了基本的运行命令,还有一些高级执行功能非常实用。例如,当你反复运行笔记本后,可能对当前状态感到不确定,或者代码发生了变更。

这时,你可以选择 “清除所有状态并全部运行”。这个操作会重置笔记本的执行环境,然后从头开始运行所有单元格,确保你处于一个已知的、正确的配置状态。

另一个强大的功能是调度执行。你可以将笔记本设置为一个定时任务。

以下是调度作业的典型应用场景和设置选项:

  • 应用场景:例如,每天定时运行的网络爬虫或数据收集任务。
  • 通知设置:可以设置向个人邮箱发送作业开始、成功或失败的通知。
  • 作业管理:可以为调度的任务命名,并选择立即手动运行或未来定时运行。

代码辅助与提示功能

最后,另一个值得指出的高级特性是代码辅助功能。它能帮助你在编写查询时获得提示,提高编码效率。

如果你输入了部分代码,例如键入 select,系统会提供代码自动补全建议。

此外,按下 Shift + Option + Space(在Mac上;Windows/Linux上通常是 Shift + Alt + Space)组合键,系统会给出一些你可能想要运行的查询示例。虽然这些示例可能不完全符合你的需求,需要进行修改,但这是一种快速获取灵感和执行思路的好方法。


本节课中我们一起学习了Databricks笔记本的执行功能。我们了解了如何通过“运行”菜单选择不同的执行范围,如何清除状态以确保环境干净,以及如何将笔记本调度为定期运行的作业。我们还探索了使用代码补全和快捷键获取执行提示的技巧,这些都能显著提升在Databricks平台上的工作效率。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P116:15_01_07_共享笔记本

在本节中,我们将学习如何在Databricks平台中共享已创建的笔记本,并精细控制协作者的权限。这对于团队协作和数据科学项目的管理至关重要。

当你创建了一个包含所有所需内容的笔记本后,可以将其与团队中的其他成员共享。

以下是共享笔记本的具体步骤。

首先,点击界面右上角的共享图标。该操作会弹出一个窗口,允许你与团队成员共享此笔记本。

窗口会显示一些建议的共享对象,例如管理员。你可以从中选择,或输入特定用户名,然后生成一个共享链接。

接下来,你可以精确控制协作者对笔记本的操作权限。这对于管理大数据项目的开发者非常有用。

例如,你可能希望数据科学家只能查看笔记本,因为他们需要执行运行操作,但你并不希望他们修改笔记本内容。同样,你也可以允许某人重新运行笔记本。

在“仅查看”权限下,协作者只能查看笔记本中的结果。这对于某些只需要审查结果的数据科学任务可能已经足够。

然而,“运行”操作需要消耗大量计算资源,并且要求协作者了解你所在组织的集群规模等背景信息。因此,授予运行权限可能是一项更高级别的特权。

“编辑”权限则应保留给极少数你信任的共享对象。你不希望有人随意修改笔记本,导致其未来运行失败,尤其是当它是一个定时调度任务时。

最后,“管理”权限代表最高级别的特权。拥有此权限的用户可以重新调度任务或更改运行任务所需的集群类型。

在Databricks内部考虑共享时,这里提供了许多可控制的选项。

完成权限设置后,你可以直接复制生成的共享链接。

你可以将此链接粘贴到Slack等聊天系统中,或通过电子邮件发送给同事。例如,你可以说:“嘿,能帮我看一下这个笔记本吗?我遇到了一些问题。”

如果对方拥有编辑权限,他们甚至可以直接为你修改笔记本,然后发回链接并告知:“我想我已经修复了它。”

本节课中,我们一起学习了在Databricks中共享笔记本的完整流程。我们了解了如何生成共享链接,并重点掌握了四种核心权限(查看、运行、编辑、管理)的区别与适用场景。通过精细的权限控制,可以确保团队在高效协作的同时,保障项目资产的安全与稳定。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P117:16_01_08_多语言支持

在本节课中,我们将要学习如何在Databricks笔记本环境中使用多种编程语言。默认情况下,笔记本支持SQL,但它也提供了对Python、Scala、R以及通过特定方式使用Bash的支持。我们将逐一演示这些语言的使用方法,并了解如何在不同语言间切换和执行代码。

默认SQL查询

首先,我们来看默认的SQL语言。在Databricks笔记本中,SQL是一种直接查询数据的便捷方式。

以下是一个简单的SQL查询示例,它从数据集中选取有限数量的行,以避免在测试时处理大量数据导致长时间等待。

SELECT * FROM diamonds LIMIT 10;

要运行这个SQL单元格,只需点击单元格上的“运行”按钮。执行后,查询结果会直接显示在单元格下方。

Python语言支持

上一节我们介绍了SQL查询,本节中我们来看看如何使用Python。Python在数据分析和处理中非常流行,Databricks同样提供了完整的支持。

在单元格的开头使用 %python 魔法命令,可以告知笔记本此单元格的内容为Python代码。

以下是Python部分的一个示例:

%python
import pandas as pd
# 挂载Databricks文件系统并读取CSV文件
df = pd.read_csv('/dbfs/.../your_file.csv')
display(df.head(10))

运行此Python单元格,代码将被执行,并使用 display 函数展示数据框的前10行。对于小型数据处理,这种方式很有效。若需处理更大规模的数据,则需要利用Spark接口。

R语言支持

除了Python,Databricks也支持R语言,这对于习惯使用R进行统计分析和数据可视化的用户非常有用。

在单元格中使用 %r 魔法命令来指定R语言环境。

以下是使用R语言的步骤说明:

  1. 首先,需要加载SparkR库以与Spark集成。
  2. 然后,可以读取数据并转换为Spark数据框进行处理。
  3. 最后,执行分析并输出结果。

一个具体的R代码示例如下:

%r
library(SparkR)
# 将diamonds数据集读取为Spark数据框
sparkDF <- read.df(source = "databricks", path = "diamonds")
# 后续的数据分割与处理逻辑...
print(head(sparkDF))

运行这个R单元格,代码会执行并打印出相应的输出信息。

Scala语言支持

接下来,我们看看Scala。Scala是运行在JVM上的语言,与Spark原生集成,性能出色。

在单元格中使用 %scala 魔法命令来运行Scala代码。

以下是Scala的一个基础示例,展示了如何创建Spark会话并执行SQL查询:

%scala
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder.appName("Example").getOrCreate()
val df = spark.sql("SELECT * FROM diamonds LIMIT 10")
df.show()

执行此Scala单元格后,Spark会运行查询并通过 show() 方法展示结果。

通过Python执行Bash命令

最后,我们来探索一个隐藏功能:在笔记本中执行Bash命令。这可以通过Python的魔法命令实现。

有两种方式可以在Python单元格中运行Shell命令:

  • 使用 %sh 魔法命令。
  • 在Python代码中使用感叹号 ! 前缀。

例如,要列出当前目录的文件,可以这样做:

%sh
ls -la

或者,在Python单元格中使用:

!ls -la

这种方式非常有用,可以用于文件管理、环境检查或运行外部脚本等操作,极大地扩展了笔记本的功能。

本节课中我们一起学习了在Databricks笔记本中使用SQL、Python、R、Scala以及Bash命令的方法。掌握这些多语言支持能力,能让你根据任务需求灵活选择最合适的工具,从而更高效地进行数据工程和大型语言模型相关的开发工作。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P118:17_01_09_Databricks代码仓库概览

在本节课中,我们将要学习如何在Databricks环境中使用工作空间(Workspace)和代码仓库(Repos)来组织、共享和版本控制你的Notebook。我们将了解两者的基本操作及其在团队协作中的重要性。

工作空间(Workspace)简介

当你开始大量使用Notebook时,你会希望探索工作空间。工作空间是一种在你的环境中与他人共享不同内容、组织内容以及管理代码仓库的方式。

首先,让我们看看工作空间。在工作空间内部,我们可以执行的操作之一是添加文件夹。这个文件夹可以用于存放特定类型的Notebook,例如,一些Scala Notebook。

你可以将它们全部放在某个特定目录中。一旦你创建了Notebook目录,你就可以在其中放置Notebook。我们可以将其命名为“Scala Test”,然后将默认语言更改为Scala。

完成这些步骤后,如果你返回工作空间,可以看到那个Notebook已经存在。最后,我可以通过选择“共享”来与其他人共享整个文件夹。这是一种本地工作流,它有很多好处。

代码仓库(Repos)与版本控制

另一方面,很多时候你会希望接入版本控制系统,并对你的Notebook进行版本控制。让我们来看看代码仓库。

如果我们进入“Repos”部分,可以看到已经添加了一个仓库。如果我选择“添加文件夹”,你实际上可以在文件夹内部组织它们。这是一种管理方式。

同样,如果我们进入这里,我们可以选择“添加”来添加一个新的代码仓库。在添加仓库时,你需要提供URL。你可以在这里输入一个HTTP URL。

我们也可以从多个提供商中选择,包括GitHub、Bitbucket、GitLab、Azure DevOps和AWS CodeCommit。这里有很多选项,具体取决于你组织的需求。然后你在这里输入仓库名称。

完成这些操作后,你可以看到一个示例。你将能访问Notebook内部的所有内容,并且可以开始对你正在进行的工作进行版本控制,这样工作就不会丢失,并且能够通过版本控制系统与他人共享。

你也可以直接在这里添加内容。如果你浏览这里,你可以添加文件、添加Notebook、创建文件夹,因此你具备与它们交互的能力。

版本控制的最佳实践

在Databricks中,有几种不同的方式可以对你的系统进行版本控制。你总是可以下载Notebook然后添加进去,或者你可以使用直接的工作空间集成功能,将内容从代码仓库移动到工作空间,或从工作空间移动到代码仓库。

总的来说,对你的Databricks Notebook进行版本控制是一个最佳实践。


本节课中我们一起学习了Databricks工作空间和代码仓库的基本概念与操作。我们了解了如何使用工作空间来组织Notebook并与他人共享,以及如何利用代码仓库接入版本控制系统来管理代码变更和历史。掌握这些工具对于在团队中高效、安全地进行数据工程和机器学习项目开发至关重要。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P119:18_01_02_使用Spark SQL进行高效数据转换

在本节课中,我们将要学习如何使用Spark SQL来高效地查询和转换Databricks文件系统中的数据。我们将从浏览数据目录开始,逐步学习如何执行SQL查询、进行数据剖析以及创建可视化图表。

🗂️ 浏览数据目录

让我们开始使用Spark SQL,这是一种使用SQL查询整个Databricks文件系统的方法。

首先,我们来看一下这里的目录。

查看这里,可以看到这些目录,实际上还有示例数据,例如sampledefaultNew York TaxiTPCH

我们也可以从另一个视图查看它。如果打开底部面板,它提供了从终端进行查询的能力。

输入命令 ls dbfs:/,这将显示Databricks文件系统内部的内容。

我们也可以查看实际的数据集。输入 datasets

如果想查看例如nyc.sample,可以看到数据实际存储的位置。

甚至可以进入该目录。执行最后的导航命令,进入目录。

然后可以看到,例如,里面有一个包含JSON文件的目录。执行 du 命令,这将显示整个示例数据集的大小。

也可以单独查看,会发现文件大小差异很大,例如70MB、105MB。这是一个很好的方式来探索本地Databricks文件系统。

🔍 使用SQL查询数据

我们也可以使用SQL来查询它,这是这里的默认语言。

进入这里,可以输入 SELECT *

然后说 FROM,我们想查询samples中的nyc_taxi数据。

查看trips表。执行查询,并限制只获取大约1000条记录。

这是一个SQL查询,但可以使用笔记本的高级功能来稍微清理一下,使其看起来更好。

点击这里的选项,选择“格式化SQL”。运行它。

现在SQL格式更好了。然后运行这个查询,将会启动一个巨大的Spark作业,如果需要,甚至可以检查运行情况。

总的来说,好处是能够实际查看这些数据,查看不同的视图,例如排序。

📊 数据剖析与可视化

还可以点击这个加号图标,有两种模式可以深入探索:可视化和数据剖析。

首先进行数据剖析,可以找到例如描述性统计信息,这通常是查看数据时首先想做的。

可以看到特定列的标准偏差是某个值。可以查看中位数,例如trip_distance列的中位数是1.63,这很有趣。

可以看到数据严重偏向极短的行程。同时可以查看fare_amount,分布更广一些,但仍然有偏度,中位数是9。

然后查看pickup_zip_codedropoff_zip_code。通过数据剖析,可以对数据有一个感觉,这非常方便。

也可以点击这个加号进行可视化。进行可视化。

从比条形图更有趣的内容开始,可以看散点图或气泡图,我们做气泡图。

然后选择要在散点图上展示的内容。选择trip_distancefare_amount

得到了一个不错的对数关系图,在达到某个点之前是线性的,之后似乎开始呈对数曲线。

这可能是因为一旦到达城市的某个特定区域,可能是固定费率之类的。总的来说,通过查看这个,我们能够获得良好的可视化效果。

如果想保存,可以点击“保存”。然后这个可视化图表就可以保存在笔记本中。

🎯 总结

本节课中我们一起学习了如何使用Spark SQL在Databricks中进行高效的数据操作。我们首先浏览了数据目录,然后执行了SQL查询来获取数据。接着,我们利用数据剖析功能了解了数据的统计特性,如中位数和分布。最后,我们创建了可视化图表来直观地探索数据关系,例如行程距离与车费之间的关系。这是一个在组织中快速开始创造价值的绝佳方式,使用SQL进行描述性统计并获得出色的可视化效果并不困难。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P120:19_01_03_使用目录浏览器

在本节课程中,我们将学习如何使用Databricks中的目录浏览器。目录浏览器是一个用户界面,它允许你浏览、搜索、管理和组织Databricks工作空间中的不同数据对象,例如表、视图和仪表板。通过本教程,你将了解如何利用这个工具高效地探索和管理你的数据。

🗂️ 目录浏览器简介与核心功能

目录浏览器提供了一个集中式的门户,用于搜索、筛选和浏览数据表、仪表板及模型。你可以为对象添加标签、管理访问权限,并查看数据表中的底层数据。这是一个非常便捷的数据探索工具。

以下是目录浏览器的一些核心功能:

  • 集中浏览与搜索:在一个界面中查找所有数据资产。
  • 对象标记与管理:为数据对象添加标签和注释,便于团队协作。
  • 权限控制:管理谁可以访问哪些数据。
  • 数据预览:无需编写代码即可查看数据样本和详细信息。

🔍 探索数据表

现在,让我们通过一个具体例子来看看目录浏览器的实际应用。假设我们有一个名为 samples.nyctaxi.trips 的数据表。

点击这个数据表后,界面会自动展示其列结构。你可以为列添加注释,这对于团队协作非常有用。例如,你可以添加注释:“此列数据需要清理”。


此外,你还可以查看数据的描述性样本,这让你无需编写任何代码就能了解数据概貌。同时,可以查看详细信息,例如数据在磁盘上的实际存储位置。了解这一点很有用,因为你可能想对这些数据执行其他操作。

💻 查询与操作数据

在目录浏览器中,你可以直接对数据执行操作。一个很好的起点是运行查询。

例如,你可以创建一个查询:

SELECT * FROM samples.nyctaxi.trips LIMIT 100;

Shift + Return 执行查询。系统内置了保护机制,默认将查询结果限制在1000行以内,以防止意外拖慢系统。执行后,你可以看到返回了100行数据,耗时仅385毫秒。这是一个非常高效的功能。

📊 创建可视化与仪表板

除了查询,你还可以快速创建可视化图表。点击界面上的“+”号,选择“可视化”。

例如,你可以创建一个散点图,选择 trip_distance 作为X轴,fare_amount 作为Y轴。这样,你就得到了一个直观的图表。

你还可以继续构建,例如添加过滤器。这使你能够创建与数据关联的存储视图或仪表板。当团队其他成员查看此数据集时,他们可以立即看到这些预设的分析视角,从而快速理解数据。

🔄 与SQL编辑器的交互

另一个重要的功能是目录浏览器与SQL编辑器之间的无缝切换。你可以在SQL编辑器中编写复杂查询,然后轻松切换回目录浏览器查看数据对象的结构和详情。

很多时候,你可能先在目录浏览器中浏览数据,当需要修改或深入分析时,再切换到SQL编辑器。两者之间的这种交互极大地提升了工作效率。

📁 深入Databricks文件系统

目录浏览器还有一个强大的功能,就是可以直接深入Databricks文件系统。

例如,在“文件存储”部分,你可能会看到一些尚未创建元数据表的数据文件。之后,如果你想为这些数据创建元数据,可以回到Databricks文件系统,找到对应的路径,然后在目录浏览器中为其创建表。创建完成后,你就可以像之前一样对这部分数据执行查询或创建可视化图表。

🎯 本节总结

本节课我们一起学习了Databricks目录浏览器的核心用法。目录浏览器是管理Databricks文件系统上元数据的起点。通过它,你可以轻松浏览、查询、可视化数据,并与SQL编辑器协同工作。如果你能为常用数据集设置好自动化的可视化和描述性统计,将能为团队节省大量时间,并让其他成员立即开始从数据中获取价值。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P121:从文件创建表 📁

在本节课中,我们将要学习如何在Databricks中完成一个常见但可能令人困惑的任务:如何手动将数据添加到Databricks文件系统(DBFS),并基于这些文件创建可供查询的表。我们将介绍两种主要方法:使用SQL编辑器直接创建表,以及通过Catalog Explorer界面直观地上传数据并自动建表。

查看DBFS中的数据

首先,我们需要了解如何查看已存在于DBFS中但尚未在Catalog中注册为表的数据。通过导航到DBFS,我们可以浏览文件系统并找到目标数据文件。例如,我们可能发现一个CSV文件存储在路径 dbfs:/FileStore/tables/height_weight.csv 中,但它尚未出现在Catalog Explorer的列表里。

上一节我们介绍了如何定位DBFS中的文件,本节中我们来看看如何将这些文件注册为正式的表。

方法一:使用SQL编辑器创建表

如果数据文件已存在于DBFS中,我们可以通过执行SQL CREATE TABLE 语句来手动创建表。以下是具体步骤:

  1. 打开Databricks工作区中的SQL编辑器。
  2. 编写一个创建表的SQL查询。关键是指定正确的文件路径和格式。

以下是创建表的核心SQL语法示例:

CREATE TABLE height_weight_25k
USING CSV
OPTIONS (
  path “dbfs:/FileStore/tables/height_weight.csv”,
  header “true”
)

在这个代码中:

  • CREATE TABLE height_weight_25k 指定了新表的名称。
  • USING CSV 声明了数据源格式为CSV。
  • OPTIONS 子句用于提供具体参数:
    • path 指向DBFS中CSV文件的确切位置。
    • header “true” 告知系统将文件第一行作为列名处理。

执行此查询后,系统会读取指定路径的数据并创建一个名为 height_weight_25k 的表。之后,你可以在Catalog Explorer的“default”数据库下找到这个新创建的表,并查看其列信息和数据预览。

方法二:通过Catalog Explorer上传并创建表

对于需要从零开始上传数据的情况,Databricks提供了更直观的图形界面操作方式。

以下是使用Catalog Explorer上传文件并创建表的流程:

  1. 在Databricks侧边栏导航至“Catalog”。
  2. 点击“添加数据”或类似按钮。
  3. 在打开的界面中,点击“浏览”选择本地计算机上的数据文件(例如一个名为“nba_2017.csv”的文件)。
  4. 系统会提供数据预览。确认无误后,你可以直接在此界面创建新表。
  5. 为表命名(例如 nba_2017),然后点击“创建表”。

使用这种方法,Databricks会自动处理文件上传(将其保存到DBFS)和表的注册过程。创建完成后,你可以立即在Catalog Explorer中看到新表,浏览其样本数据,甚至利用这些数据快速创建可视化仪表板来分析内容,例如球员薪资与维基百科页面浏览量的关系。

总结

本节课中我们一起学习了在Databricks中从文件创建表的两种核心方法。第一种是通过SQL编辑器手动编写DDL语句,适用于管理已存在于DBFS中的文件。第二种是通过Catalog Explorer的图形化界面直接上传文件并自动建表,这种方式对于新数据导入更为便捷。掌握这两种方法,你就能灵活地将各种数据源引入Databricks环境,为后续的数据处理、分析和机器学习任务做好准备。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P122:21_01_05_查询外部数据源

在本节课中,我们将学习如何在Databricks平台中查询外部数据源。我们将探讨多种集成外部数据的方法,包括通过界面直接添加、利用原生集成以及通过合作伙伴进行数据摄取。

🗂️ 添加外部数据源

上一节我们介绍了Databricks的基本概念,本节中我们来看看如何将外部数据引入系统。

在Databricks目录(Catalog Explorer)中,点击“添加”(Add)按钮,可以看到一个专门用于添加外部数据的区域。这是开始查询外部资源最简单的方法之一。例如,你可以将数据文件放入Blob存储中,然后直接将其集成到你的工作区。

🔗 原生集成选项

除了直接添加,Databricks还支持与多种数据库和服务的原生集成。

以下是支持的部分数据源列表:

  • 数据库:Cassandra、Snowflake、MySQL、PostgreSQL。
  • 数据流与搜索:Kafka、Elasticsearch。
  • 文档存储:MongoDB。
  • 云存储:DBFS(Databricks文件系统本身)。
  • 应用与服务:Google Drive、Salesforce。

可以看到,我们有许多不同的方式可以从外部源添加数据。

🤝 通过合作伙伴摄取数据

另一种集成外部数据的方式是通过“合作伙伴”(Partner)进行数据摄取。这与直接添加略有不同。

通过此方式,你可以直接从这些合作伙伴资源中获取数据集。例如,选择“5t”这个集成,进入高级选项,数据将直接存入你的DBFS,之后便可使用。

🛠️ 丰富的数据应用生态

Databricks的集成能力不仅限于数据接入,还覆盖了完整的数据工作流。

以下是其他可连接的集成类型:

  • 商业智能与可视化(BI and visualization)
  • 数据准备与转换(Data preparation, transformation)
  • 机器学习(Machine learning),例如Data I/O, Labelbox
  • 安全与数据治理(Security, data governance)

因此,连接外部数据源的方式远不止从当前界面直接添加这一种。你还可以通过“通过合作伙伴摄取”(Ingest via partner)功能与众多服务提供商连接。

📝 总结与后续步骤

本节课中我们一起学习了在Databricks中查询外部数据源的多种途径。总的来说,Databricks提供了丰富的资源集合,能够将各类数据轻松拉取到你的系统中。

当数据就绪后,你可以立即利用所有现有接口开展工作,例如:

  • 创建新的Notebook进行分析。
  • 在SQL编辑器中直接查询数据。
  • 直接进入机器学习流程,运行自动化实验。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P123:检查表结构 📊

在本节课中,我们将学习如何在 Databricks 中检查数据表的结构和元数据。我们将了解如何访问 Catalog Explorer、查看表的基本信息、列定义、样本数据,以及如何为表和列添加注释。


上一节我们介绍了 Databricks 的基本环境,本节中我们来看看如何具体地检查和理解一个数据表。

首先,进入 Catalog Explorer。Catalog Explorer 需要一个正在运行的仓库,以便你能够实际检查表。

在这里,我们可以看到 hive_metastore,这是用户上传数据保存的地方,同时还有 samples 等默认目录。

例如,如果我们想查看 trips 表,可以注意到其所有者是 databricks。这让我们能看到该表最初创建时的情况。

Databricks 在两年前创建了它,我们看到其大小为 531 KB。我们也可以在这里查看列信息。

我们还可以获取一些样本数据,这能很好地概述表内的情况。

此外,我们可以查看详细信息,这里显示了数据在磁盘上的存储位置。这在执行某些操作时可能很有用,比如你想将某些内容复制到该位置。

我们还可以查看权限设置以及历史记录。不过,对于默认数据,历史记录可能帮助不大。

如果我们查看一些我上传的数据,例如 height_weight_2000 表,可以看到其所有者是 demo(一个虚构的电子邮件地址)。

我们还可以看到可用的列:indexheightweight

检查数据时一个很好的功能是,你可以为列添加注释。

例如,我们可以为 weight 列添加注释,说明其单位是磅(LBs)。

同样,我们也可以为 height 列添加注释,说明其单位是英寸(inches)。

这相当于添加了一种元数据,让我们以后能获取关于这些列的更多信息。

我们甚至可以添加其他信息,例如,我们不需要这个(指代某个操作)。

这使我们能够对表进行注释和检查。

我们同样可以再次查看样本数据、详细信息、历史记录等。

你甚至可以直接在表本身添加注释,例如:“这是合成的身高体重数据”。

因此,如果你想检查 Databricks Catalog 内部的情况,Catalog Explorer 是你的首选工具。你可以操作表、检查它、查看其周围的元数据、添加自己的元数据。

最后,如果你愿意,还可以直接进入查询笔记本,甚至创建仪表板。

如果我们快速查看这个笔记本,其中一个方便的功能是它会自动提供我们想要运行的查询语句,这实际上非常有用。

如果我们在这里连接到一个集群,其好处在于,如果你想快速获取一个表的大量信息,它可以成为一站式解决方案。

你可以从这里出发,转向不同的解决方案,例如,在实际的笔记本中开始查询,并围绕它启动 Spark 作业。


本节课中,我们一起学习了如何使用 Databricks 的 Catalog Explorer 来全面检查数据表。我们掌握了查看表的基本属性、列信息、样本数据和存储位置的方法,并学会了如何通过添加注释来丰富表的元数据。这些技能是进行有效数据管理和分析的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P124:23_01_07_使用Delta Lake构建可靠数据管道 🚀

在本节课中,我们将学习如何使用Delta Live Tables来构建和调度可靠的数据管道。Delta Live Tables是一种新的工作流调度方式,它集成了Delta Lake的高级功能,让复杂数据管道的构建变得简单直观。

创建新管道

首先,我们来看如何创建一个新的Delta Live Tables管道。创建过程非常直接,你只需选择“创建”即可。

以下是创建管道时需要配置的几个关键选项:

  • 管道名称:你需要为管道指定一个名称。
  • 产品类型:你可以选择产品类型,例如“高级版”、“核心版”或“专业版”。界面上通常会提供相关文档,帮助你做出选择。
  • 执行模式:你需要在“持续”模式和“触发”模式之间做出选择。两者的区别在于,持续模式会持续不断地处理到达的流式数据,而触发模式则是在特定事件发生时才会执行。
  • 源代码路径:你需要传入源代码的存储路径。例如,可以是你工作站上连接的代码仓库,这是一个存放源代码的好地方。
  • 目标目录:你可以选择目标目录,例如Unity Catalog。
  • 计算配置:你需要选择运行管道所需的计算集群类型。

管道演示与监控

我已经有一个正在运行的管道,让我们通过这个演示来深入了解。在这个Delta Live Tables的界面中,我们可以看到几个关键组件。

以下是当前管道中的数据流视图:

  • 一个名为customers的流式表。
  • 另一个流式表。
  • 这些数据经过一些ETL操作后,会流入一个名为sales_order_clean的合并表中。
  • 此外,还有两个物化视图。

这个界面的一个实用之处在于,我们可以切换视图并获取更多详细信息。

例如,我们可以查看以下信息:

  • 任务是否完全执行成功。
  • 实际运行的任务类型是什么,例如是否是流式任务。
  • 写入了多少条记录。
  • 是否有记录被丢弃。在处理来自互联网(如API)的数据时,可能会出现数据丢弃或失败的情况。

能够在一个视图中看到所有这些信息非常方便。同样,我们也可以直接定位源代码的位置,只需点击相应的链接即可。

如果我点击那个源代码链接,你会看到这里有一个笔记本,里面包含了所有的流式处理代码。我们也可以直接在这里对代码进行修改。这样就在实时代码和自动化管道之间建立了一个良好的交互界面。

模式切换与调度

最后,还有一点可能很重要,那就是你可以在不同模式之间切换。在开发模式下,你可以让一切正常运行并进行测试。之后,你可以切换到生产模式

最后,你还可以按一定的时间间隔来调度这个管道。因此,Delta Live Tables提供了许多功能,使得构建复杂的数据管道变得相当简单直接。

总结

本节课中,我们一起学习了Delta Live Tables的核心功能。我们了解了如何创建和配置一个新的管道,包括设置名称、产品类型、执行模式、源代码路径和目标。我们通过演示查看了管道的运行状态、数据流和监控信息,并了解了如何直接访问和修改源代码。最后,我们知道了可以在开发和生产模式间切换,并能按计划调度管道。这些特性共同使得Delta Live Tables成为构建可靠、复杂数据管道的强大工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P125:24_01_08_ACID事务

概述

在本节课中,我们将要学习ACID事务。ACID是数据库事务的四个关键特性的缩写,它确保了数据操作的可靠性和一致性。理解ACID对于在数据工程和LLM应用中维护高质量数据至关重要。

什么是ACID事务?

ACID代表原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这四个特性共同定义了一种独特的事务类型,旨在保证数据操作的完整性和可靠性。

ACID的四个核心特性

上一节我们介绍了ACID事务的基本概念,本节中我们来看看构成ACID的四个具体特性。

以下是ACID事务的四个核心组成部分:

  1. 原子性
    原子性确保一个事务中的所有操作作为一个不可分割的单元执行。这意味着所有操作要么全部成功,要么全部失败,不存在部分成功、部分失败的中间状态。这是一个“全有或全无”的操作。

    核心概念事务 = 全部成功 OR 全部失败

  2. 一致性
    任何ACID事务都会将数据库从一个有效状态转换到另一个有效状态。这确保了数据的内部规则和约束在事务前后都得到遵守。例如,在传统SQL系统中,相关数据(如表之间的外键关系)在事务完成后将保持一致。这与NoSQL数据库的“最终一致性”模型有显著区别。

  3. 隔离性
    隔离性意味着并发执行的事务和查询不会相互干扰。例如,一个事务在提交前的未提交更改或中间状态,对其他并发事务是不可见的。这些更改在提交前将保持隔离状态。

  4. 持久性
    持久性是指一旦一个事务被提交,其所做的更改就会被持久化地保存下来。这些更改能够经受住系统故障的考验,确保已提交的数据永远不会丢失。

ACID事务的优势与考量

了解了ACID的四个特性后,我们来看看采用ACID事务能带来哪些好处,以及需要考虑的方面。

以下是采用ACID事务的主要优势:

  • 数据完整性:保障批处理和流处理场景下的数据完整性。
  • 一致性查询:能够通过快照进行一致性查询。
  • 容错性:得益于持久化日志,系统具备容错能力。
  • 可靠的数据交付:确保数据交付的可靠性。

在数据质量方面,ACID事务被视为黄金标准。

然而,采用ACID事务也需要付出一些代价。例如,由于强一致性的要求,其在可扩展性方面会受到一定限制。

总结

本节课中,我们一起学习了ACID事务。我们详细探讨了其原子性、一致性、隔离性和持久性这四个核心特性,它们共同确保了数据库操作的可靠性和数据的高质量。虽然ACID事务可能在可扩展性上有所妥协,但它为需要强数据一致性和完整性的应用场景提供了坚实的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P126:Z-Order排序优化

概述

在本节课中,我们将要学习Delta Lake中一项重要的性能优化技术——Z-Order排序。这项技术通过优化数据的物理存储布局,可以显著提升查询效率并降低成本。

什么是Z-Order排序?🔍

Z-Order排序是Delta Lake中的一项重要技术。它的核心作用是将相关的信息整理到同一组文件中。

这种数据共位性会被Databricks上的Delta Lake数据跳过算法自动利用。这意味着,它可以极大地减少Databricks上的Delta Lake需要读取的数据量。

如何使用Z-Order排序?💻

以下是使用Z-Order排序的基本语法。你可以在ZORDER BY子句中指定要排序的列。

OPTIMIZE events WHERE date >= current_timestamp() - INTERVAL 1 DAY
ZORDER BY event_type

通过这个例子,我们可以看到Z-Order排序的强大之处。接下来,让我们深入了解它的工作原理和优势。

Z-Order排序的关键特性✨

上一节我们介绍了Z-Order的基本用法,本节中我们来看看它的核心特性。以下是Z-Order排序的几个关键优势:

1. 自动数据跳过

这意味着Delta Lake会在写入时收集最小值和最大值统计信息,以实现谓词下推。这个过程是透明的,无需额外配置,并且在查询时会自动跳过与查询无关的数据扫描。

2. 更好的数据局部性

这项特性意味着它将相关的列值共置于同一个数据文件中。这极大地提升了数据跳过的有效性。你可以通过ZORDER BY子句指定你想要优化的列。

3. 灵活的统计信息收集

Delta Lake提供了可配置的统计信息收集功能。默认情况下,它会收集表中前32列的统计信息。但你可以通过columns属性来自定义,从而避免对高基数的文本列进行不必要的统计。

4. 显著的查询加速

由于需要扫描的数据量大大减少,查询速度得到显著提升。这对于特定的、尤其是具有高选择性的查询特别有效。

5. 降低总体拥有成本

查询效率的提升直接转化为更低的计算资源消耗和总体拥有成本。

6. 增量式优化

Z-Order排序支持增量式重新优化。你可以在完成主要的数据回填后应用Z-Order排序,也可以在数据分布发生重大变化时重新运行它。你甚至可以测试查询来量化性能提升。

总结

本节课中,我们一起学习了Delta Lake中的Z-Order排序优化技术。我们了解到,它通过将相关数据共置来优化存储,并利用自动数据跳过机制来减少I/O,从而显著提升查询性能并降低成本。当你在Databricks平台上使用Delta Lake时,掌握这项技巧将非常有用。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P127:26_02_02_表文档化

在本节课中,我们将学习如何在Databricks中为数据表添加和更新文档。我们将探索两种主要方法:通过图形界面(Catalog Explorer)和通过编程方式(使用SQL语句)。掌握这些技能有助于维护清晰的数据资产文档。

通过Catalog Explorer添加文档

上一节我们介绍了课程概述,本节中我们来看看如何通过图形界面为数据表添加注释。

首先,我们打开Catalog Explorer。这里有一个名为“height_weight”的表格,其当前注释显示为“this is a table comment”。我们将修改这个注释。

以下是操作步骤:

  1. 在Catalog Explorer中找到目标数据表。
  2. 点击表格的注释区域进行编辑。
  3. 将注释内容修改为“synthetic data”。
  4. 保存更改。

通过上述步骤,我们成功更新了表格的注释信息。

通过SQL编程方式添加文档

虽然图形界面操作简便,但很多时候我们需要以编程方式与数据表进行交互。接下来,我们将学习如何使用SQL语句来实现相同的文档化目标。

我们可以在Databricks中创建一个SQL查询来修改表格属性。具体方法是使用 ALTER TABLE 语句来设置表格的注释属性。

以下是实现此操作的SQL代码示例:

ALTER TABLE catalog.schema.height_weight
SET TBLPROPERTIES ('comment' = 'synthetic data on height weight added by John');

在这段代码中,catalog.schema.height_weight 是目标表格的完整名称。SET TBLPROPERTIES 子句用于设置表格属性,我们将 comment 属性的值更新为新的描述文本。执行此查询后,表格的注释就被成功修改了。

验证文档更改

在通过编程方式更新了表格注释后,我们需要验证更改是否已生效。我们可以使用SQL命令来查看表格的详细信息。

为了查看更新后的表格属性,包括我们刚刚添加的注释,可以使用 DESCRIBE EXTENDED 命令。

以下是验证更改的SQL代码:

DESCRIBE EXTENDED catalog.schema.height_weight;

执行此命令后,返回的详细信息中会包含一个“Comment”字段,其中显示了我们通过 ALTER TABLE 语句设置的新注释内容。这证实了我们的更改已成功应用。

此外,我们也可以返回到Catalog Explorer界面,在图形化视图中直观地确认注释已被更新。

总结

本节课中我们一起学习了在Databricks中为数据表添加文档的两种方法。我们首先介绍了如何使用Catalog Explorer进行可视化操作,然后讲解了如何通过编写 ALTER TABLE SQL语句以编程方式更新表格注释,最后学习了如何使用 DESCRIBE EXTENDED 命令来验证更改。无论选择哪种方式,在Databricks中维护清晰的数据表文档都是一个直接且简单的过程。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P128:27_02_03_使用Delta Live Tables构建自动化管道 🚀

在本节课中,我们将学习如何使用Delta Live Tables来构建和管理自动化数据管道。Delta Live Tables是一种调度工作流的新方法,它集成了Delta Lake的高级特性,能够简化复杂数据管道的创建与运维。

创建新管道

上一节我们介绍了Delta Live Tables的概念,本节中我们来看看如何创建一个新的管道。

创建新管道时,只需选择“创建”选项。你需要为管道指定一个名称。接着,你可以选择产品类型,例如“高级版”、“核心版”或“专业版”。界面上通常会提供相关文档链接,帮助你做出合适的选择。

以下是创建管道时需要配置的几个关键选项:

  • 管道模式:你可以选择“持续”模式或“触发”模式。两者的区别在于,“持续”模式会持续不断地处理新到达的流式数据;而“触发”模式则基于特定事件来运行。
  • 源代码路径:你需要传入源代码的存储路径。这通常是你工作站连接的代码仓库,是存放源代码的理想位置。
  • 目标目录:你可以选择目标目录,例如Unity Catalog。
  • 计算配置:你需要选择运行管道所需的计算集群类型。

管道演示与监控

现在我们已经了解了如何创建管道,接下来通过一个演示来查看其运行状态。

在这个Delta Live Tables的演示视图中,我们可以看到多个组件。这里有一个名为customers的流式表,以及另一个流式表。这些数据经过一些ETL操作后,会流入一个名为sales_order_clean的合并表中。此外,视图中还展示了两个物化视图。

这个界面的实用之处在于,我们可以切换视图并获取更多详细信息。

以下是我们可以查看的一些关键信息:

  • 运行状态:检查任务是否完全成功完成。
  • 任务类型:确认正在运行的任务类型,例如是否为流式任务。
  • 记录统计:查看写入了多少条记录,以及是否有记录被丢弃。这在处理来自互联网(如API)的数据时尤为重要,因为可能会发生数据丢失或处理失败。
  • 源代码定位:通过选择相应链接,可以直接定位到源代码所在位置。

如果点击源代码链接,我们会跳转到一个笔记本,其中包含了所有的流式处理代码。我们也可以在此直接修改代码。这就在实时代码和自动化管道之间建立了一个良好的交互界面。

模式切换与调度

最后,我们来了解一下管道的模式切换与调度功能,这对于管道的生命周期管理至关重要。

在开发模式下让管道正常工作后,你可以将其切换到生产模式。此外,你还可以按一定的时间间隔来调度这个管道。

Delta Live Tables提供了丰富的功能,使得构建复杂的数据管道变得相当直观。以上内容概述了Delta Live Tables的基本特性。


本节课中,我们一起学习了如何使用Delta Live Tables构建自动化数据管道。我们涵盖了从创建管道、配置选项,到监控运行状态、查看源代码,再到切换开发/生产模式以及设置调度任务的全过程。这些功能共同使得在Databricks平台上管理数据工作流变得更加高效和可靠。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P129:28_02_04_Delta Live Tables组件解析 🧩

在本节课中,我们将要学习Delta Live Tables的核心组件。我们将通过一个架构图,了解如何从数据摄入的青铜层,逐步演进到具备自动化部署与运维能力的黄金层,并分析每一层的关键功能与业务价值。


上一节我们介绍了Delta Live Tables的整体演进路径,本节中我们来看看其具体的核心组件构成。

以下是Delta Live Tables的关键组件。可以看到,随着最佳实践的融入,数据管道可以从青铜层演进到白银层,最终到达黄金层。各层之间的区别在于:例如,在白银层,你能够在数据管道末端实现完整的可观测性;而在黄金层,你能够实现自动化的部署与运维,即MLOps或DataOps,并且能够编排你的数据管道。这最终会为SQL分析、BI、AI/ML以及数据共享带来更好的结果。


高效数据摄入 📥

首先,高效的数据摄入是Delta Live Tables的一个重要组成部分。AutoLoader组件支持增量数据着陆,这属于青铜层。它可以从云存储、变更数据捕获或消息总线等多种来源摄取数据。整个数据团队,从SQL用户到工程师,都能以非常简单的方式加载数据。

智能数据转换 ⚙️

接下来是智能数据转换。这意味着使用流表和视图来简化架构,并具备数据质量强制实施的能力。它支持灵活、持续或触发的管道执行,并且可以借助Spark结构化流处理的性能优化。

简化的管道管理 🛠️

第三步是简化的管道管理。这包括处理编排、监控、故障恢复、持续集成与持续交付、版本控制,以及通过基础设施即代码来自动扩展基础设施。它允许团队专注于业务逻辑,而非仅仅是运维操作。

湖仓平台集成 🏠

最后是湖仓平台集成。Unity Catalog可用于数据发现和治理,而Delta Lake则是可靠的存储层,可在多云环境中工作。在业务影响方面,你将能够获得更快的开发速度,轻松扩展以管理不断增长的数据量,并加速整个组织内的洞察获取时间。

本质上,这意味着你能够通过自动化来降低数据管道的总体拥有成本。这正是最终的黄金层所实现的目标。


本节课中我们一起学习了Delta Live Tables的四大核心组件:高效数据摄入、智能数据转换、简化管道管理以及湖仓平台集成。我们了解了数据管道如何从青铜层演进至具备自动化能力的黄金层,并理解了每一层为数据团队和业务带来的具体价值。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P130:29_02_05_持续管道与触发式管道对比

在本节课中,我们将要学习两种不同的Delta Live管道:持续管道与触发式管道。我们将探讨它们的工作原理、适用场景以及各自的优缺点,帮助你理解如何根据实际需求选择合适的管道类型。

持续管道 🔄

首先,我们来看看持续管道。持续管道的核心思想是,数据在到达源头时被持续不断地处理,即流式数据处理。

新插入和更新的数据会增量同步到目标表中。这种模式支持实时ETL(提取、转换、加载)和实时分析。

以下是持续管道的一些典型应用场景:

  • 指标仪表盘:例如,如果你希望按小时甚至实时了解收入生成情况,持续管道是理想选择。
  • 实时欺诈检测:如果你需要实时查看正在输入的虚假信用卡号码,可以通过持续管道构建欺诈检测系统。

触发式管道 ⏰

上一节我们介绍了持续管道,本节中我们来看看触发式管道。触发式管道与持续管道有所不同,其数据处理发生在预定的时间窗口内,而非持续进行。

这意味着,例如,你可以每天执行一次操作。这些时间窗口可以通过CRON调度来安排。这种方式允许以逻辑方式(如每小时、每天、每周)进行批处理或周期性处理。

以下是触发式管道的一些典型应用场景:

  • 聚合报告:生成每日或每周的汇总报告。
  • 机器学习模型训练:例如,每天获得数据更新后,重新运行一个小型机器学习模型,这个过程可以通过这种触发式窗口完成。

对比与选择 ⚖️

现在,我们来对比一下这两种管道。你可以认为持续管道具有更低的延迟,但需要更多的计算资源,因此成本可能更高。而对于基于批处理的工作负载,触发式管道则更具成本效益。

你可以根据观察到的数据消费模式来组合使用这两种方法。你也可以更新管道配置,尝试一种版本与另一种版本的对比。这两种都是优秀的技术,关键在于你如何根据最佳用例来应用它们,同时监控其对你组织的成本和效益。

本节课中我们一起学习了持续管道与触发式管道的核心区别。持续管道适用于需要低延迟和实时处理的场景,而触发式管道则更适合周期性的批处理任务,成本效益更高。理解它们的特点有助于你为不同的数据处理需求选择最合适的解决方案。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P131:30_02_06:配置自动加载器 🚀

在本节课中,我们将要学习如何配置自动加载器。自动加载器允许你安全地从外部位置摄取数据。我们将了解其核心配置、数据处理能力以及监控与调度功能。

核心概念与源配置 ⚙️

上一节我们介绍了自动加载器的基本作用,本节中我们来看看其核心配置项。自动加载器支持从多种源系统安全地摄取数据,前提是你拥有Unity Catalog。

以下是自动加载器源配置的关键点:

  • 支持多种云存储、数据库和消息系统
  • 支持多种数据格式,例如 JSONParquetCSV
  • 提供凭证管理功能,以确保连接的安全性。

增量数据加载与转换处理 🔄

了解了数据来源后,我们来看看如何处理数据流。增量数据加载是自动加载器的另一个重要特性,因为它会持久化每个数据源的游标状态。

这意味着:

  • 系统只会拉取最新的插入和更新数据
  • 对于需要全量加载的转换任务,这种方式更快速、更高效

在数据转换方面,自动加载器提供了强大的处理能力:

  • 你可以在源系统上执行查询
  • 可以应用过滤、聚合和转换操作。
  • 为了确保可靠性,还可以将数据转换为Delta格式

监控、调度与代码示例 📊

处理数据之后,确保管道健康运行至关重要。在监控方面,自动加载器提供了完善的工具:

  • 可以通过仪表板跟踪管道健康状况
  • 可以设置警报
  • 提供详细的调试日志以供排查问题。

在调度执行方面,自动加载器同样灵活:

  • 可以使用 cron表达式、触发器或连续执行模式来设置计划。
  • 具备跨作业的内置依赖关系管理功能。

构建这样的数据处理管道代码非常直观。以下是一个简单的Python代码示例,只需几行即可实现:

# 示例:使用自动加载器读取数据流
streaming_df = spark.readStream.format("cloudFiles") \
    .option("cloudFiles.format", "json") \
    .load("s3://your-source-path/")

通过这种方式,你就能利用Unity Catalog的高级功能来管理数据表。

总结 📝

本节课中我们一起学习了自动加载器的配置与使用。我们了解了其如何安全地从多种外部源摄取数据,支持增量加载以提高效率,并提供了数据转换、监控告警以及灵活调度的能力。通过简洁的代码,即可利用Unity Catalog高效地管理数据管道。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P132:31_02_07_查询管道事件

在本节课中,我们将学习如何通过API查询Delta Live Tables管道的事件,并了解Databricks文件系统(DBFS)相关的API操作。这些知识对于监控和管理数据管道至关重要。

查询管道事件API

上一节我们介绍了Delta Live Tables的基本概念,本节中我们来看看如何通过API与其进行交互。

Databricks为Delta Live Tables管道提供了完整的CRUD(创建、读取、更新、删除)API。要查询特定管道的事件,你需要向一个特定的API端点发送HTTP GET请求。

API请求格式示例:

GET /api/2.0/pipelines/{pipeline_id}/events

以下是该API支持的主要查询参数:

  • order_by: 用于指定事件返回的排序方式。
  • filter: 用于根据条件筛选特定事件。
  • max_results: 用于限制单次请求返回的最大事件数量。

API的响应是一个结构化的JSON负载,其中包含了管道的事件列表及相关元数据。

API的通用能力与DBFS操作

了解了管道事件查询后,我们来看看这些API共有的特性以及DBFS相关的API。

Databricks的API设计遵循了通用标准,具备以下核心能力:

  • 精细化的验证与错误处理:API会返回明确的状态码和错误信息。
  • 结构化的请求与响应:使用JSON格式,便于程序解析。
  • 标准的HTTP状态码:例如200表示成功,404表示资源未找到。
  • 通过令牌(Token)支持分页:便于处理大量数据的返回结果。

这些特性使得API能够轻松地与各种编程语言集成,并融入自定义的CI/CD工作流或自动化工具中。

对于Databricks文件系统(DBFS),其API模式与管道API相似,主要提供以下操作:

  • 基本的文件系统操作:如创建、读取、更新、删除文件和目录。
  • 文件上传与下载
  • 列出文件及目录内容
  • 设置访问控制列表(ACL)和权限
  • 从作业中编程访问DBFS

本节课中我们一起学习了如何通过API查询Delta Live Tables管道的事件,了解了相关查询参数和响应格式。同时,我们也认识了Databricks API的通用特性以及DBFS文件系统的基本API操作。掌握这些API是构建自动化监控和管理流程的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P133:32_02_08_Delta Live端到端示例

在本节课中,我们将通过一个端到端的示例,学习如何在Databricks工作流界面中使用Delta Live表。我们将重点关注其数据质量监控、管道可观测性以及调度功能。

工作流界面中的Delta Live表示例

上一节我们介绍了Delta Live表的基本概念,本节中我们来看看一个具体的运行示例。

这里展示的是一个在工作流界面中运行的Delta Live表端到端示例。请注意,界面上有一些初始组件,它们显示了管道当前正在执行的操作。

数据质量监控

以下是关于数据质量监控的详细信息。

在数据质量方面,我们可以看到代码执行率为100%。向下切换至下一部分,同样显示有4000个数据项,处理完成率也是100%。

我们也可以在此处查看数据质量详情,并观察数据期望值。虽然这里有一些数据下降的情况,但并没有出现失败记录。

管道可观测性与检查

一个集成化管道的优势在于,我们可以检查管道的每个部分,并获得细粒度的能力来审视数据质量、查看详细信息、检查数据模式、观察数据流,甚至可以在开发环境和生产环境之间进行切换。

我们同样可以从这个菜单中看到管道的状态。它会显示管道何时启动、何时运行、何时完成,并且我们也能看到更新信息。

因此,一个集成化的解决方案为管道提供了大量的监控和可观测性功能。当处理非常复杂的任务时,这可能是无价的。例如,管道中间部分可能出现问题,但有了这些监控,你就能知道它是否失败了。

与传统脚本方式的对比

这相对于将一堆脚本拼凑在一起的方式是一个改进,因为在纯脚本方式中,你无法清楚地知道正在发生什么。所以,数据管道的可观测性是Delta Live表的主要优势之一。

操作与调度

你不仅可以在界面内完成所有这些操作,还可以为管道安排未来的执行计划,或者根据需要随时手动启动它。

总结

本节课中我们一起学习了Delta Live表在工作流界面中的实际应用。我们重点探讨了其强大的数据质量监控面板、细粒度的管道可观测性功能,以及如何通过界面进行调度和按需启动。这些特性使得管理和维护复杂的数据管道变得更加清晰和可靠。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P134:33_02_09_Vacuum与垃圾回收 🧹

在本节课中,我们将要学习Delta Lake中的Vacuum(清理)与垃圾回收(Garbage Collection)操作。这些是管理Delta表、优化存储和性能的重要维护任务。


概述:Vacuum与垃圾回收

Delta Lake的Vacuum操作会根据保留策略,删除表中不再需要的旧版本数据,从而节省存储成本。此操作可以自动执行。垃圾回收则负责删除任何快照都不再引用的底层数据文件。这些操作的好处包括降低存储成本(因为删除了未使用的表版本和数据文件)以及提升性能。

上一节我们介绍了Delta Lake的基本特性,本节中我们来看看如何进行表维护。


识别Delta Lake表

首先,我们需要区分一个表是否为Delta Lake表。以下是如何在Databricks界面中进行识别。

观察一个非Delta Lake表的详细信息。其“类型”显示为“外部”。这表明它不具备Delta Lake的高级功能。

现在,观察一个已复制并转换为Delta Lake的表的详细信息。其“类型”显示为“托管”。默认情况下,托管表就是Delta Lake表。这意味着它拥有诸如时间旅行等高级功能,但也需要我们对其进行Vacuum和垃圾回收等管理操作。


将现有表转换为Delta Lake表

如果有一个现有的非Delta表,我们无法直接对其执行OPTIMIZEVACUUM命令。尝试对非Delta表运行OPTIMIZE命令会导致错误。

以下是将现有表转换为Delta Lake表的方法。我们可以创建一个新表作为原表的副本。

CREATE TABLE delta_table_height_weight_2k
USING DELTA
AS SELECT * FROM `/path/to/original/table`;

执行上述SQL语句后,我们就创建了一个Delta Lake表。之后,便可以对该表执行OPTIMIZEVACUUM等Delta Lake表操作。

以下是转换步骤的关键点:

  • 使用 CREATE TABLE ... USING DELTA AS SELECT ... 语句。
  • 源表路径需正确指定。
  • 新创建的表将具备所有Delta Lake功能。

执行维护操作

成功创建Delta Lake表后,就可以执行维护命令了。以下是两个核心操作:

  1. OPTIMIZE:此命令会进行垃圾回收,对小文件进行合并(Compaction),以优化查询性能。

    OPTIMIZE delta_table_height_weight_2k;
    
  2. VACUUM:此命令根据保留策略删除旧版本的数据文件。注意:默认保留期为7天,7天内的数据无法通过VACUUM删除,这是为了保障时间旅行功能。

    VACUUM delta_table_height_weight_2k;
    

    若要清理7天前的所有数据(谨慎使用),可以指定保留0小时:

    VACUUM delta_table_height_weight_2k RETAIN 0 HOURS;
    

总结

本节课中我们一起学习了Delta Lake的维护操作。我们首先了解了如何区分Delta表与非Delta表。接着,掌握了通过创建副本将现有表转换为Delta Lake表的方法。最后,我们学习了两个核心维护命令:OPTIMIZE用于优化性能和垃圾回收,VACUUM用于根据保留策略清理旧数据以节省存储空间。定期执行这些操作是管理Delta Lake表、保证其高效运行的重要环节。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P135:34_02_03_使用作业编排工作负载

在本节课中,我们将要学习如何在Databricks中使用作业功能来编排和自动化工作负载。我们将了解作业的典型用途、如何设置作业,以及作业可以执行的不同任务类型。

作业概述

上一节我们介绍了Databricks的基本概念,本节中我们来看看作业功能。作业是Databricks中用于编排和自动化工作负载的核心工具。

这里展示的是Databricks作业的概览界面。让我们来看一个典型作业的样子。

假设我需要与一个笔记本进行交互。这个笔记本可以执行多种任务。

例如,它可以执行ETL操作,或者创建一些新表或数据。

它甚至可以自动创建一个仪表板。虽然手动完成这些工作也不错,但如果能实现自动化,效果会更好。

这就是作业发挥作用的地方。我可以在这里设置一个新作业,然后将它与我已在源代码仓库中创建好的笔记本关联起来。

作业设置与最佳实践

以下是设置作业时需要考虑的关键步骤。

首先,注意这里我们有能力查看Databricks工作区。这是一个默认的位置。但我也可以将作业指向源代码仓库。

这将成为一项最佳实践。我会将那个笔记本签入源代码仓库。同样,这个笔记本可能会创建一些新表和数据,或许还会创建一个仪表板。

最后,我将安排这个作业按计划运行。例如,每天运行一次。这可能是向业务团队提供报告的绝佳方式。

计算资源配置

接下来需要做的是决定执行所有计算需要涉及什么样的集群。

这将是一个临时作业,它会在作业启动时创建一个集群,作业完成后,集群会自动关闭。

作业的多种任务类型

除了非常有用的笔记本之外,作业还可以执行其他类型的任务。

你可以将作业指向一个Python脚本。同样,这个脚本应该存放在源代码仓库中,但它也可以存放在Databricks工作区。

你还可以构建一个非常复杂的SQL查询,在组织中执行一系列不同的操作。同样,将其签入源代码仓库,或者直接指向Databricks工作区,你可以保存之前的SQL查询并指向它。

最后可以指出的一点是,你也可以使用一个JAR文件。Java具有可移植的运行时能力,你可以创建这个JAR文件,让它随时待命,并执行ETL操作。

总结与灵活性

因此,作业提供了极大的灵活性。在设置Databricks作业时,甚至还有超出这些目标的其他目标。但最棒的是,你能够将所有内容整合到一个统一且自动化的生态系统中。

这样,你就能查看作业运行时发生的一切,进行调试,按计划调度它,或者甚至在你想要启动某项任务或构建基于批处理的操作时,定期手动调度它。

本节课中我们一起学习了Databricks作业的核心功能。我们了解了作业如何将笔记本、脚本、SQL查询或JAR文件等任务自动化,并通过配置计算资源和调度,构建出一个统一、可管理的工作负载编排系统。这为实现数据工程的自动化流程奠定了坚实基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P136:35_02_04_Databricks作业演示 📊

在本节课中,我们将要学习如何在Databricks平台中创建和管理作业。作业是自动化执行任务(如运行笔记本或脚本)的核心工具,对于构建可靠的数据管道至关重要。

作业界面概览与创建 🚀

上一节我们介绍了Databricks的基本概念,本节中我们来看看如何创建一个新的Databricks作业。

我们首先进入主界面,然后导航到“工作流”部分。在工作流界面中,可以看到已经存在的多个作业。如果需要在上千甚至上万个作业中进行筛选,可以使用搜索功能。例如,输入“hello”可以快速定位相关作业。这对于大型组织管理海量作业非常有帮助。

要创建一个新作业,只需点击“创建作业”按钮。点击后,会进入一个新的配置界面。

配置作业任务 ⚙️

现在我们可以为作业命名,例如将其命名为“运行笔记本”。这个界面允许我们进行任务级的设置,可以创建初始任务,并链接第二个、第三个甚至更多任务。作业名称“运行笔记本”意味着我们将运行多个笔记本。

我们将第一个任务命名为“笔记本一”。接下来需要选择任务类型。在“类型”下拉菜单中,可以看到多种选项,包括:

  • 笔记本
  • Python脚本
  • Python wheel
  • SQL
  • Delta Live Tables管道
  • DBT
  • Jar
  • Sp提交
  • 运行作业
  • If Else条件

其中,If Else条件在需要等待特定资源或满足某些条件时非常有用。我们选择“笔记本”类型。

在“源”设置中,需要指定笔记本的来源。它可以是Git提供商(如GitLab、GitHub、Bitbucket、AWS CodeCommit),也可以直接位于Databricks工作空间内部。大多数成熟的组织倾向于指向Git提供商。

选定来源后,需要提供笔记本的路径。例如,可以选择一个数据科学笔记本或演示笔记本。我们这里选择一个演示笔记本。

配置计算集群与高级选项 🔧

接下来是集群配置。可以选择使用默认作业集群,也可以使用现有的通用集群。两者的区别在于:通用集群可能已经在运行数据分析任务,可以直接复用;而作业集群是临时性的,它会在任务启动时创建,任务完成后自动终止,这有助于控制成本。我们可以保留默认的作业集群设置。

此外,还可以添加其他配置,例如通知设置重试策略。在作业界面中工作时,有很多选项可供调整。

第一个任务创建完成后,可以继续添加第二个、第三个任务,并将它们依次链接起来。

作业详情、标签与调度 📅

现在,让我们看看作业的其他设置。在“作业详情”部分,可以为作业添加标签。例如,可以添加一个“团队”标签,值为“数据工程”;还可以添加一个“类型”标签等。这些标签在后续筛选和分类作业时非常有用。

也可以将作业配置与Git集成,确保复杂的调度配置被版本控制管理。

在“触发器类型”中,可以选择“计划”或“连续”触发。如果选择“计划”,可以使用Cron语法来设置具体的运行时间。这对于数据工程师构建定时运行的管道非常常见,例如每天在特定时间执行某些操作。

配置完成后,可以点击“立即运行”来手动触发作业。

监控与诊断历史作业运行 🔍

最后,我们来看看如何监控历史作业运行。进入“之前的作业运行”界面,可以看到所有作业运行的概览。在大型组织中,这里会显示大量运行记录。可以通过状态进行筛选,例如筛选出“失败”的作业。

如果我们查看一个失败的作业,可以深入分析原因。例如,界面可能显示“在等待就绪时被终止”,这可能是由于该作业的集群配额不足导致的。通过这个界面,我们可以诊断并解决问题。

这个界面不仅用于创建作业,还能查看历史作业,确保你了解哪些作业失败了、哪些被跳过了、哪些成功了。在大型组织中,需要一个这样的作业管理框架,以便可靠地编排数据管道的各个部分。如果没有作业工作流的自动化,完成任何任务都将极其困难。在更复杂的组织中,你既需要自动化和调度这些作业,也需要能够监控和观察其运行状态。

总结 📝

本节课中我们一起学习了Databricks作业的完整管理流程。我们了解了如何从主界面进入工作流并创建新作业,详细配置了作业的任务类型、源代码路径以及计算集群。我们还探讨了如何为作业添加标签、设置计划触发器,并最终通过运行历史界面来监控作业状态和诊断失败原因。掌握作业的创建、调度与监控,是构建自动化、可靠数据管道的关键技能。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P137:36_02_05_多任务工作流 📊

在本节课中,我们将要学习如何在Databricks工作流界面中设置和管理一个多任务工作流。我们将了解如何将复杂的数据处理流程分解为独立的、可调度的任务,并探讨这种架构的优势。

工作流界面概览

现在,我们正位于工作流界面中。可以看到,这里已经设置好了多个任务。

以下是当前配置的任务列表:

  • 数据摄取:负责获取原始数据。
  • 数据准备:对摄取的数据进行清洗和转换。
  • 数据分析:对准备好的数据执行分析操作。

目前共有三个不同的任务。如果需要,我们也可以在此添加更多任务。

任务调度设置

进入这个多任务界面后,另一项可以进行的操作是添加调度计划。

调度计划主要有两种类型:

  • 持续运行作业:这种作业会一直运行,通常用于仪表板或流式数据处理场景。
  • 周期性调度作业:可以按固定的时间间隔(例如每小时、每天)触发作业,并且可以在Cron语法和Databricks的简化调度器之间切换。

多任务架构的优势

多任务设置的主要优势在于,你可以将整个处理流程分解为多个独立的模块。

让我们以一个具体的任务为例来查看其配置。在这个任务中,我指向了我的Notebook文件所在的路径。接着,我将其指向了作业集群。此外,我还可以在这里切换不同的任务类型。

当前,我们使用的是 Notebook 类型。但任务类型也可以是:

  • Python脚本
  • Jar文件
  • Delta Live Tables管道

通过将复杂问题分解为多个独立的环节,无论是在运行时进行调试,还是在编写解决方案代码时,都会变得容易得多。

总结

本节课中,我们一起学习了Databricks多任务工作流的构建与管理。我们了解了如何在工作流界面中配置多个顺序执行的任务,如何为工作流设置不同的调度策略(持续运行或周期性运行),以及将流程模块化带来的调试和开发便利性。这种架构是构建健壮、可维护数据管道的关键实践。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P138:任务依赖关系 📊

在本节课中,我们将学习如何在工作流中管理多个任务之间的依赖关系。理解并正确配置任务依赖是构建可靠、自动化数据处理管道的关键。

概述

工作流通常包含多个按顺序执行的任务。每个任务的成功执行可能依赖于前一个任务的完成,也可能依赖于特定的运行环境,如软件库、集群配置或参数。本节将详细探讨这些依赖关系及其配置方法。

多步骤任务管道

上一节我们介绍了工作流的基本概念,本节中我们来看看如何构建一个包含多个步骤的任务管道。

我们有一个名为“songs”的工作流,它包含两个任务:“prepare songs data”(准备歌曲数据)和“analyze songs data”(分析歌曲数据)。这些任务之间存在明确的依赖关系。

以下是任务依赖的核心表现:

  • 顺序依赖:每个任务都依赖于其前一个任务的完成。例如,“analyze songs data”任务必须等待“prepare songs data”任务成功完成后才能开始执行。
  • 成功状态依赖:后续步骤仅在前驱步骤“成功完成”后才会被触发。如果前一个任务失败,依赖它的任务通常不会运行。

这种设计确保了数据处理的正确性和流程的完整性。

超越任务本身的依赖

除了任务之间的直接顺序依赖,我们还需要关注其他可能影响任务执行的关键依赖项。配置这些依赖项时需格外仔细,否则可能导致作业失败。

以下是几种常见的非直接任务依赖:

  • 库依赖:任务运行时可能需要特定的软件库。例如,你的代码可能需要加载一个名为 pandas 的库。这个库必须被预先安装并自动附加到运行集群上,否则任务会因找不到库而失败。在代码中,这通常表现为 import pandas 语句。
  • 参数依赖:任务可能需要接收外部传入的参数才能正确运行。这些参数可以在任务配置时添加,例如,一个控制数据处理范围的日期参数 date=‘2023-10-01’
  • 集群配置依赖:任务对运行环境有特定要求。集群本身可能就是一个重要的依赖项,它需要满足以下条件:
    • 硬件要求:例如,某些机器学习任务可能需要GPU来加速计算。
    • 软件运行时版本:任务代码可能依赖于特定版本的运行时环境,例如 Spark 3.5。如果集群配置的Spark版本不匹配,任务可能会报错或行为异常。

因此,在审查任务依赖时,必须深入检查任务本身、所需的库以及集群运行时环境等所有方面。

总结

本节课中我们一起学习了工作流中任务依赖关系的重要性与类型。我们了解到,构建稳健的管道不仅需要设置任务间的顺序依赖,还必须周全地考虑库依赖参数依赖集群配置依赖。忽略其中任何一点都可能导致作业失败。正确管理这些依赖是确保复杂数据处理流程自动化、可靠运行的基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P139:38_02_07_查看作业历史 📊

在本节课中,我们将学习如何在Databricks平台中监控和管理作业的运行历史。这对于识别和调试失败的作业至关重要。

概述

通过工作流界面,我们可以快速概览所有作业的最后一次运行状态。每个作业都会显示其最近一次执行是成功还是失败。

通过工作流界面查看作业状态

上一节我们介绍了作业监控的重要性,本节中我们来看看具体如何操作。首先,我们可以导航到“Workflows”(工作流)区域。在这里,所有已配置的作业都会列出,并直观地显示其最后一次运行的结果状态(成功或失败)。这个界面非常有用,我们可以快速浏览并定位出有问题的作业。

例如,在列表中,我们可能会发现一个作业因配额问题导致集群意外终止而失败。这提示我们需要进行调试。

使用“作业运行”界面进行深入分析

虽然工作流界面很方便,但“Job Runs”(作业运行)界面提供了更全面的视图。我们可以在此界面根据状态(如失败、活跃、已完成)来筛选和排序作业。这对于每天有数百个作业运行的大型组织尤其有用。

以下是查看作业运行状态的步骤:

  1. 导航到“Job Runs”界面。
  2. 利用状态筛选器(如 status == ‘FAILED’)来快速定位问题作业。
  3. 点击特定的作业运行,查看其详细日志和错误信息。

通过这种方式,我们可以高效地集中处理所有失败的作业,查看其失败日期和具体状态信息。

推荐的调试工作流程

结合以上两个界面,可以形成一个高效的作业监控与调试流程。

以下是推荐的步骤:

  1. 初步概览:首先在“Workflows”界面查看所有作业的“最后运行”状态,获得整体情况。
  2. 问题聚焦:当需要基于状态进行深入排查时,切换到“Job Runs”界面。
  3. 筛选排查:筛选出所有失败状态的作业。
  4. 深入调查:点击具体的失败作业,查看运行详情。
  5. 分析日志:仔细阅读状态信息或日志(例如,错误消息 Cluster terminated unexpectedly due to quota limit),定位根本原因。
  6. 解决问题并迭代:根据错误信息进行修复,然后继续处理下一个问题。

通过执行这些步骤,你可以系统地诊断问题并实施解决方案。

总结

本节课中我们一起学习了在Databricks中监控作业历史的两种主要方法:通过“Workflows”界面快速概览,以及通过“Job Runs”界面进行基于状态的深入分析和调试。掌握这些工具和方法,能帮助你有效地管理和维护自动化作业的稳定运行。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P140:39_02_08_使用仪表板 📊

在本节课中,我们将学习如何使用Databricks的仪表板功能来创建、分享和更新数据可视化报告。仪表板是数据分析和数据科学中一个强大的工具,它允许用户无需编写代码即可与数据进行交互,并获取最新的信息。

仪表板界面概览

我们这里展示的是“纽约市出租车行程分析仪表板”,它使用了Databricks提供的纽约市出租车行程样本数据集。

请注意,这个仪表板位于一个专门的界面中。接下来,我们将指出此类工具的一些优势。

仪表板的优势

如果你是一名数据分析师或数据科学家,需要与组织内的同事分享重要信息,那么分享这样的仪表板会非常方便。它的优点在于:

  • 提供最新信息:你可以为他人提供按你设定的任何时间间隔更新的最新信息。
  • 无需技术背景:用户无需了解SQL或任何编程知识,因为他们可以通过切换和搜索不同的日期范围或邮政编码来查看数据,这赋予了用户探索数据的能力。
  • 数据民主化:这极大地促进了数据科学和数据分析的民主化,让更多人能够接触和理解数据。

数据的实时性与调度

现在请注意这里显示“5分钟前更新”。仪表板在5分钟前被更新,原因是我选择了刷新。

如果我再次选择刷新,你会看到仪表板会立即更新。因此,你可以拥有不同的数据状态。是否获取最新更新完全取决于用户,他们可以随时点击刷新。

同样地,当你将其创建为定时任务时,你可以点击“添加计划”,并设置例如每小时更新一次,这对大多数人来说可能就足够了。

你还可以使用Cron语法来设置更复杂的调度。你甚至可以添加订阅者,仪表板的快照将会被发送给这些订阅者。这里提供了一个非常便捷的调度界面。

分享与编辑功能

显然,你可以分享这个仪表板。

最后,如果你点击这里的“刷新”按钮,它将刷新仪表板内的每一个窗口,这同样非常有用。你可以看到它正在刷新,并且显示“刚刚更新”。

如果你拥有管理员权限,你可以点击菜单并选择“编辑”。这意味着你可以实际添加新的内容,例如:

  • 添加一个文本框。
  • 添加一个过滤器(例如,这里已经有一个过滤器)。
  • 添加一个可视化图表。
  • 设置不同的颜色。

从仪表板中学习

我认为另一个非常有用的功能是,你也可以从这些仪表板中学到很多东西。

如果我选择这里的某个可视化图表,比如这个显示车费金额与行程距离关系的小图表,你可以看到它们之间存在线性关系。

但是,这个SQL查询是如何生成的呢?其实很容易弄清楚。我只需选择这个图表,然后就可以查看它背后的查询语句本身,这非常棒。当然,我也可以下载CSV文件,这可能会有用。

让我们继续查看这个查询。😊

查看与编辑底层查询

现在看看这个,我进入了一个查询编辑器,也就是SQL查询编辑器。我们可以看到它写着 use catalog samples; select ...,并且我们能够浏览所有不同的SQL查询。如果我愿意,我还可以修改它。

因此,这是一个绝佳的学习方式。当你的组织内有人为你创建了一个仪表板时,你可以通过查看其查询来学习。同时,如果你有相应的权限,也可以直接编辑它。

总结

本节课中,我们一起学习了Databricks仪表板界面的强大功能。仪表板不仅能够以直观的方式呈现最新数据,实现数据分析和探索的民主化,还提供了灵活的调度、分享和编辑选项。通过查看仪表板背后生成的SQL查询,用户还能从中学习并进一步定制分析。请务必充分利用Databricks这一强大的仪表板功能。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P141:故障处理 🐛

在本节课中,我们将学习如何在数据工程工作流中处理失败的作业运行。我们将探讨如何利用任务依赖和条件逻辑,以编程方式诊断问题、执行清理操作并发送通知,从而实现更健壮和自动化的故障处理流程。

调试失败的作业运行可能很棘手。在工作流界面中,我们看到这里有一个问题:这个作业在此处运行失败。

我们可以查看最后一次运行记录,尝试找出失败原因。界面会提供错误信息,我们可以深入查看更多细节。

然而,这并没有解决“接下来我该做什么”以及“我能否以编程方式解决此问题”的情况。

因此,如果我们回到作业本身,查看其任务,可以看到这个笔记本任务相当简单。但或许我们可以在这里添加一些逻辑来处理特定的失败条件。

我们可以添加另一个任务,这个任务可以是一个条件判断任务,例如处理失败情况。这个条件任务可以在依赖任务失败时运行。我们可能需要执行一些清理操作,或在这里进行其他处理。

具体来说,我们可以设置任务在“所有依赖项失败”时运行。这样,如果这个作业失败,我们就可以执行一些清理逻辑。

此外,我们还可以添加一个通知任务。这个通知可以发送到电子邮件、Teams、PagerDuty、Slack等渠道,告知相关人员作业已失败,并且已运行了清理作业,但需要他们知晓此事。

能够在任务级别进行自定义,是处理此类失败的一个绝佳方式。我们既可以处理失败条件,也可以处理成功条件。

如果我们创建了这个失败处理任务,我们还可以在此处添加另一个任务来处理成功情况。这样,我们就能基于这个作业界面深入管理,实现在失败时进行导航和清理,在成功时(例如)将数据加载到数据库,然后发送通知告知一切已成功加载。

总而言之,如果能够以编程方式解决问题,通常是最佳方案。通过灵活的任务编排,我们有许多不同的方法来处理工作流中可能出现的问题。

本节课中,我们一起学习了如何为数据工程作业配置故障处理逻辑。我们了解了如何利用条件任务在作业失败时自动执行清理或补救操作,以及如何设置通知来及时告警。掌握这些方法,能帮助我们构建更可靠、自动化程度更高的工作流系统。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P142:配置重试机制 🔄

在本节课中,我们将学习如何在数据处理任务中配置重试机制。重试机制是处理临时性故障(如网络错误或API超时)的重要策略,它能提高数据管道的鲁棒性,避免因偶发问题导致整个作业失败。

识别失败作业与重试需求

上一节我们介绍了作业监控,本节中我们来看看如何为失败的作业设置重试。

我们首先看到一个处于失败状态的作业。作业失败可能由多种问题导致。我们可以为作业启用重试功能。

以下是可配置的重试参数:

  • 最大重试次数 (max_retries):定义任务失败后尝试重新执行的最大次数。
  • 重试延迟 (retry_delay):定义两次重试尝试之间的最小等待间隔。
  • 触发重试:可以配置在特定条件下触发重试。
  • 重试监控:对重试行为进行监控和记录。

在任务中配置重试参数

接下来,我们进入具体的任务设置界面来配置这些参数。

在任务设置中,可以看到“重试尝试次数”和“尝试之间的最小间隔”选项。这用于在任务失败时控制重试行为。

如果我们选择启用,可以这样配置:将最大重试次数设置为3,因为可能存在网络错误或其他临时性问题。同时,将每次重试的间隔设置为15分钟。

确认设置后,我们可以看到配置生效:最多重试3次,每次间隔15分钟。这是一种处理潜在问题的有效方法,尤其适用于那些你无法控制的资源。

重试策略的应用场景与高级配置

上一节我们配置了基础的重试,本节中我们来看看更灵活的重试策略及其适用场景。

对于像外部API这类你无法控制的资源,配置重试可以避免临时性问题导致整个数据管道崩溃。通过重试,有机会让任务恢复正常工作。

另一个要点是,如果你对某个任务的运行有充分信心,且该任务需要频繁执行,你甚至可以选择“无限重试”选项。

例如,这可能是一个你想每小时运行一次的网页爬虫工具。网页爬虫本身具有不确定性且容易超时。在这种情况下,你可能希望任务在失败后无限次地重试,但需要在每次重试之间等待较长时间,并且即使在超时后也继续重试。

本节课中我们一起学习了如何为数据处理作业配置重试机制。我们了解了设置最大重试次数和重试延迟的方法,并探讨了针对不同场景(如调用外部API或执行网页爬虫)选择合适的重试策略。合理配置重试能显著增强数据管道对临时性故障的容错能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P143:42_02_02_使用Unity Catalog实现统一数据访问 🗂️

在本节课中,我们将学习Databricks Unity Catalog的核心概念与架构。Unity Catalog是一个统一的数据治理解决方案,它提供了跨多个Databricks工作区的集中式访问控制、审计、数据血缘和数据发现能力。

概述与核心价值

Databricks Unity Catalog提供了跨一个甚至多个Databricks工作区的集中式访问控制、审计、数据血缘和数据发现能力。

首先,让我们看看Unity Catalog的架构。它内部包含用户管理和元存储,并连接到多个Databricks工作区。这些工作区内有集群和SQL仓库。其核心理念是一次定义,处处安全。这实现了全面的数据治理。

此外,您可以拥有一个符合标准的安全模型。该模型基于ANSI SQL,允许管理员使用熟悉的语法在现有数据湖中授予权限。这意味着可以对目录、数据库、表和视图进行权限管理。

它还具有内置的审计和血缘功能,因此您可以捕获用户级审计日志。数据发现功能允许您标记事物、记录数据资产,甚至可以查看系统表,例如审计日志、计费使用情况等。

Unity Catalog对象模型

上一节我们介绍了Unity Catalog的核心价值,本节中我们来看看其对象模型的具体构成。

您可以看到,元存储是元数据的顶级容器。它公开了一个三级命名空间:目录 -> 模式 -> 表,用于组织数据。

在数据目录中,我们拥有对象层次结构的第一层,它用于组织数据资产。模式(在Databricks中也称为数据库)是对象层次结构的第二层,包含表和视图。当然,您可以使用SQL或Catalog Explorer来创建这些表和视图。

最后,在最低层级的表、视图和卷中,您可以对非表格数据进行治理。

总而言之,Unity Catalog的五个关键特性如下:

以下是Unity Catalog的五个关键特性:

  1. 集中式元数据存储:捕获技术元数据。
  2. 统一访问控制:允许您使用SQL设置细粒度的访问控制。
  3. 数据血缘跟踪:在查询时自动捕获端到端的血缘关系,实现数据治理。
  4. 发现与组织:提供可搜索的目录,便于数据发现,并支持浏览器和REST API。
  5. 多云友好:您甚至可以跨多个云供应商实现此功能,并进行联合以实现统一访问。

总结

本节课中我们一起学习了Databricks Unity Catalog。我们了解了它作为统一治理层,如何通过集中式元数据存储、基于SQL的细粒度访问控制、自动数据血缘跟踪以及强大的数据发现功能,实现跨工作区甚至跨云环境的安全、可审计和高效的数据管理。其核心对象模型(目录、模式、表/视图)为组织数据资产提供了清晰的结构。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P144:43_02_03_目录与元存储对比 📚

在本节课中,我们将学习Databricks Unity Catalog中的两个核心概念:元存储目录。我们将了解它们的定义、层级关系以及关键区别。


元存储概述 🗃️

首先,我们来介绍元存储。元存储是元数据的顶级逻辑容器。它存储有关数据资产(如表或模型)的信息,并定义目录的命名空间层级。同时,它还负责处理访问控制策略和审计。

元存储的核心功能可以概括为:

  • 元存储 = 元数据容器 + 命名空间定义器 + 治理层

目录概述 📂

上一节我们介绍了元存储,本节中我们来看看目录。目录是元存储内的第一级组织单元,用于对相关的数据资产(如表、视图等)进行分组。访问控制可以在目录级别进行定义。

目录的核心功能可以概括为:

  • 目录 = 数据资产分组单元

关键区别与关系 🔄

以下是元存储与目录之间的主要区别和关系:

  • 数量关系:一个元存储内可以包含多个目录,但每个Databricks部署只能有一个元存储。
  • 包含关系:元存储包含所有目录和数据资产的元数据。
  • 组织方式:目录帮助根据应用程序、团队等因素对数据对象进行分组和组织。

总而言之,元存储是Unity Catalog中总揽全局的元数据存储和根数据治理层,而目录则在元存储内部提供第一级的组织和边界划分。


本节课中我们一起学习了Databricks Unity Catalog中元存储与目录的概念、功能及它们之间的区别。理解元存储作为顶层容器和目录作为组织单元的角色,是有效使用Unity Catalog进行数据治理的基础。

Unity Catalog 快速入门(Python版):P145:44_02_04_Unity Catalog快速入门(Python版)

概述

在本节课程中,我们将学习如何在纯Python环境中快速开始使用Unity Catalog。我们将涵盖工作空间设置、目录创建、模式管理、表操作以及如何通过Pandas API on Spark与Unity Catalog进行交互。

工作空间设置

首先,您需要准备一个已启用Unity Catalog元存储的工作空间。该工作空间必须支持11.3或更高版本的运行时环境。

代码结构概览

以下是本教程将涵盖的核心步骤。您可以通过查看笔记本的目录来清晰地了解代码的组织结构,这对于包含多个单元格、内容复杂的笔记本尤其有用。

  • 创建目录
  • 创建托管模式(数据库)
  • 创建托管表
  • 在Spark的Pandas API中使用Unity Catalog

创建目录

上一节我们介绍了准备工作,本节中我们来看看如何创建目录。

以下是创建目录的代码步骤:

  1. 执行Spark SQL语句来创建目录(如果尚不存在)。
    CREATE CATALOG IF NOT EXISTS quick_start_catalog;
    
  2. 设置当前使用的目录。
  3. 显示所有可用的目录。
  4. 授予创建和使用该目录的权限。
  5. 验证权限设置是否生效。

创建与管理模式

目录创建完成后,接下来我们需要在目录中创建和管理模式(相当于数据库)。

以下是创建和管理模式的步骤:

  1. 在指定目录下创建模式(如果尚不存在)。
  2. 显示该目录下的所有模式。
  3. 授予在模式上创建表和读取数据的权限。

管理表

模式准备就绪后,我们可以在其中创建和管理表。

以下是管理表的操作步骤:

  1. 使用之前创建的模式。
  2. 显示当前数据库。
  3. 在目录中创建一个托管的Delta表。
  4. 授予对该表的读写权限。
  5. 显示该模式下的所有表。
  6. 向表中插入几行数据。
  7. 查询并显示表中的数据。
  8. 显示所有可用的表。

使用Pandas API on Spark

对于大多数Python程序员来说,最感兴趣的部分可能是如何通过熟悉的接口来使用Unity Catalog。幸运的是,Spark提供了Pandas API。

以下是使用Pandas API的步骤:

  1. 导入pyspark.pandas模块。
    import pyspark.pandas as ps
    
  2. 此API的使用方式与标准的Pandas库非常相似。
  3. 读取Unity Catalog中的表。
  4. 将数据写回Unity Catalog。
  5. 授予相应的权限。
  6. 展示表格数据。

总结

本节课中,我们一起学习了Unity Catalog的Python快速入门流程。我们从工作空间设置开始,逐步完成了目录、模式和表的创建与管理,最后演示了如何通过Spark的Pandas API与Unity Catalog进行交互。您可以在Databricks的官方文档中找到此快速入门指南,它是熟悉这些操作并在代码中切换关键步骤的绝佳方式。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P146:45_02_05_应用对象安全策略

在本节课中,我们将学习如何在Unity Catalog系统中应用对象安全的最佳实践。我们将重点了解访问控制列表(ACL)的作用、细粒度权限控制的重要性,以及“最小权限原则”的核心概念。

应用Unity Catalog对象安全最佳实践

应用Unity Catalog系统的对象安全最佳实践涉及几个关键特性。

上一节我们介绍了对象安全的重要性,本节中我们来看看具体如何实现。

利用访问控制列表(ACL)

首先,我们需要利用访问控制列表(ACL)。ACL允许对可安全对象(如表、视图等)上的特定用户和组授予或限制访问权限。它们还提供细粒度控制,因此您可以保护对敏感数据的访问。

实施细粒度访问控制

除了基本的ACL,您还可以对对象实施更细粒度的访问控制。这意味着您可以拥有数据库模式级别的权限,可以保护对单个表的访问,也可以保护对管道和工作流的访问,但所有这些权限都仅基于任务的实际需要。您甚至可以有针对性地控制读取、写入和管理权限。

遵循最小权限原则

最后,所有这些实践都归结为遵循“最小权限原则”。最小权限原则的核心思想是:只提供所需的最低限度访问权限。不要授予用户他们不需要的能力,因为这会造成安全漏洞。

以下是应用最小权限原则的几个关键点:

  • 按需授权:例如,如果某人只需要查看仪表板,您就不应授予他们修改或删除仪表板的权限。
  • 避免使用宽泛的组:除非有硬性要求,否则不要使用像“所有用户”这样的宽泛组。
  • 及时撤销权限:一旦目的达成,就应撤销访问权限,而不是让权限不断累积。
  • 定期审查策略:定期审查安全策略的相关性,确保它们仍然适用。

总结

本节课中我们一起学习了在Unity Catalog中应用对象安全最佳实践的核心方法。

总结来说,采用这种最佳实践技术的关键好处在于:

  1. 增强数据安全性和合规性
  2. 通过精确的ACL避免不必要的广泛访问
  3. 在凭据或策略泄露时控制影响范围。因为您只授予了人们必要的权限。如果您拥有管理员权限,并且每个人都拥有访问一切的权限,那么一旦出现问题,就可能引发巨大的安全问题。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P147:46_02_06_目录最佳实践

在本节课程中,我们将学习使用 Databricks Unity Catalog 系统时的目录最佳实践。这些实践旨在帮助您构建一个结构清晰、安全且易于管理的元数据架构。

概述

Databricks Unity Catalog 提供了一个统一的治理层。为了高效地使用它,遵循一些最佳实践至关重要。本节课我们将探讨如何通过创建独立的目录、映射业务域以及实施精细化的安全策略来优化您的目录结构。

目录最佳实践详解

上一部分我们介绍了 Unity Catalog 的基本概念,本节中我们来看看具体有哪些最佳实践可以遵循。

1. 创建独立目录以实现松耦合

首先,建议为不同的业务功能或团队创建独立的目录。这样做可以实现松耦合,意味着您可以在一个目录中进行更改,而无需担心对其他目录产生影响。同时,您可以在目录级别管理访问权限和合规性要求。

以下是实施此实践的具体好处:

  • 分离业务功能与团队:为每个业务单元或团队分配专用目录。
  • 集中管理访问权限:在目录层级设置和管理访问控制。
  • 独立合规性控制:针对每个目录实施特定的合规策略。
  • 变更影响隔离:修改一个目录的内容或结构不会波及其他目录。

2. 将目录映射到业务域

在创建了独立目录之后,下一步是合理地规划它们的边界。最佳做法是将目录的边界与业务域或具体应用程序对齐。

例如,您可以创建以下目录:

  • marketing_analytics:用于市场营销数据分析。
  • human_resources:用于人力资源相关数据。
  • pipeline_observability:用于监控数据管道的可观测性数据。

通过这种映射,您可以将安全策略、治理规则作为该目录的组成部分,从而能够深入特定业务域,精确管理其中发生的一切。

3. 实施基于目录的定制化安全策略

最后,安全是目录管理的核心。您需要为每个目录创建定制化的安全策略。

这意味着:

  • 创建特定的访问控制组和规则:针对每个目录定义谁可以访问。
  • 精细调整读写权限:独立地授予读取、写入等权限。在许多场景下,例如面向仪表板,您可能只想授予读取权限,而非修改权限。
  • 自定义设置:配置资源配额等设置。
  • 定期清理规则:在一定时间后清理过时的访问规则。

为每个目录实施精细化的策略是一项最佳实践,它能让您在获得最佳功能的同时,也享有最高级别的安全保障。

总结

本节课我们一起学习了 Databricks Unity Catalog 的目录管理最佳实践。我们主要探讨了三点:为松耦合创建独立目录将目录结构映射到业务域,以及为每个目录实施定制化的精细安全策略。遵循这些实践将帮助您构建一个组织清晰、安全可控且易于扩展的数据治理体系。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P148:47_02_07_连接配置最佳实践

在本节课中,我们将学习如何为大型语言模型(LLM)操作中的外部连接配置最佳实践。我们将重点探讨如何通过限制可见性、精细控制访问权限以及有效使用标签来确保连接的安全性和可管理性。

限制连接的可见性

上一节我们介绍了连接配置的重要性,本节中我们来看看如何限制连接的可见性。最佳实践的首要原则是限制外部连接的可见性。

这意味着你需要避免将连接密钥等秘密信息暴露给所有用户。你应当仅授予特定用户、组和角色访问权限。在许多场景下,设置最小权限原则,例如只读权限,就足够了。并非每个人都需要访问你所有的外部连接。

限制访问权限

在理解了限制可见性之后,接下来我们探讨如何从整体上限制访问权限。核心原则是仅向必要的用户和组提供访问权限。

以下是实现这一点的具体方法:

  • 你可以在连接上添加精细的访问控制列表(ACLs)。
  • 你可以确保只有预期的团队或作业能够使用那些外部资源。
  • 如果某个团队或组不再需要这些资源,你可以撤销他们的访问权限。

因此,密切关注团队的实际需求非常重要,确保不会授予他们不需要的外部资源访问权限。

为连接有效添加标签以便于发现

除了访问控制,有效管理连接的另一项关键实践是使用标签。这有助于按用途发现连接,并在整个组织范围内保持一致的可见性。

以下是有效的标签策略:

  • 使用诸如来源类别或数据分类等标签。
  • 允许按用例发现连接。
  • 为获得组织范围内的可见性而保持标签的一致性。

实施这些最佳实践能带来多重好处,包括通过限制暴露范围来增强安全性、防止非预期的数据访问或泄露,以及简化外部连接的发现和管理过程。

本节课中,我们一起学习了连接配置的三项核心最佳实践:限制连接的可见性、实施精细的访问控制,以及为连接有效添加标签。遵循这些原则将有助于你构建一个更安全、更易管理的外部连接环境。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P149:业务单元最佳实践 🏢

在本节课中,我们将学习Databricks Unity Catalog中关于业务单元的最佳实践。这些实践旨在帮助不同业务部门在保持独立性和安全性的同时,高效地协作和共享数据资源。


上一节我们介绍了业务单元管理的总体目标,本节中我们来看看具体的实施策略。

为每个业务单元提供专用沙箱 🏖️

首先,应为每个业务单元提供一个专用的沙箱环境。这包括为其分配一个独立的开发环境。此举的目的是允许业务单元在机器学习和数据领域进行安全的实验,同时防止不同工作流之间相互干扰。

以下是实施专用沙箱的几个关键考虑点:

  • 隔离安全参数:专用沙箱是理想选择,可以避免两个组织间混合不同的安全配置。
  • 适应不同需求:一个业务单元可能处理高度受限的数据,而另一个可能运行更开放的研究型环境。为每个单元提供独立的沙箱更为合适。

在确保了业务单元的独立实验空间后,我们需要考虑如何高效地共享核心数据资产。

集中管理可共享数据至生产目录 📂

在此场景下,目标是创建可复用的数据集(如客户和产品数据),并具备集中管理访问权限的能力,而非重复存储数据。因为数据规模可能迅速成为巨大的成本中心。同时,维护单一数据源对于保持一致性至关重要。

以下是集中共享模型的核心优势:

  • 避免数据冗余:集中管理可以防止因数据重复而导致的成本激增。
  • 确保一致性:这是集中共享模型的真正价值所在,它能避免关键表格在不同部门中出现多个略有差异的版本。

当数据资产被集中管理后,如何让不同部门的用户快速找到并理解它们就变得非常重要。

提升数据的可发现性 🔍

可发现性是另一个重要方面。你需要建立有意义的命名规范,例如使用数据术语表。同时,也应遵循元数据管理的最佳实践。

以下是提升数据可发现性的具体措施:

  • 逻辑化结构:这包括以逻辑方式组织目录、文件夹和资产,构建有意义的层级结构。
  • 促进协作:建立清晰的架构有助于促进不同单元之间的协作。

最后,我们将探讨如何打破数据孤岛,实现跨部门的无缝数据访问与分析。

利用联邦查询实现数据统一访问 🔗

通过湖仓一体架构,可以实现联邦查询。这将统一跨越数据孤岛的数据访问,通过合同和权限进行安全治理,并允许通过共享的自助服务访问来丰富本地数据。

联邦查询的一些关键益处包括:

  • 支持单元自治:通过数据域支持各业务单元的自主性。
  • 提高生产效率:通过资产复用提高整体生产效率。
  • 保持一致性:通过协作式治理来维持数据和处理流程的一致性。

本节课中我们一起学习了Databricks Unity Catalog中针对业务单元的四项核心最佳实践:为每个单元建立专用沙箱以确保隔离与安全实验;将可共享数据集中管理至生产目录以促进复用并保证一致性;通过有意义的命名和逻辑结构提升数据的可发现性;最后,利用联邦查询和湖仓一体架构打破数据孤岛,实现安全、统一的数据访问与协作治理。这些实践共同构成了一个支持业务单元既独立又协作的高效数据管理框架。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P150:利润分享概念解析 💰

在本节课中,我们将从社会和经济学的角度,深入探讨利润分享的不同模式及其影响。理解这些概念对于评估新技术(如生成式AI)的商业和社会影响至关重要。

利润分享的四种模式

从微观经济学的框架来看,利润分享主要可以分为四种模式。每种模式都有其优缺点,对消费者和公司的影响也各不相同。

以下是四种主要的利润分享模式:

  • 搭便车者:指那些享受产品或服务带来的好处,却无需支付任何费用的个体或群体。
  • 寻租者:指试图通过最小化自身努力,同时获取租金或支付的行为者。
  • 平台:作为连接供需双方的中间方,通过收取交易费用等方式获取利润。
  • 产品:指生产者直接将产品销售给最终客户,从而获得全部利润的理想模式。

搭便车者模式分析

上一节我们概述了四种模式,本节中我们首先来看看“搭便车者”模式。一个典型的例子是公共广播和电视。许多人每天收听公共广播,但从不支付订阅费,他们就是“搭便车者”——在不支付任何费用的情况下获得了收益。

如果足够多的人不为公共广播付费,公共广播将无法维持。软件盗版也是如此。如果一个软件包可以被免费下载,当足够多的人成为“搭便车者”时,软件将无利可图,开发者也就失去了继续开发的动力。

这种情况也可能发生在生成式AI领域。如果从报纸、电影到书籍和软件的所有内容都被免费消费,且没有利润分享机制,那么最终,无论是公共领域还是受版权保护的内容,其创作动机都可能降至零,导致所有创造性产出归零。当然,如果“搭便车者”只是少数,或许影响不大,但这仍然是一个需要警惕的问题。

寻租者模式分析

接下来,我们探讨“寻租者”模式。寻租行为并非绝对,而是一个梯度概念,其核心是希望以尽可能少的工作量,获取某种租金或报酬。

风险投资就是一个很好的例子。在某些情况下,一家风险投资公司可能投资100家公司,他们知道其中可能有95家会破产。那95家公司及其员工承担了巨大的风险,他们本可以在成熟公司获得更高的薪水和奖金,但实际获得的期望价值却更低。

期望价值公式期望价值 = 利润 × 事件发生概率

在这个案例中,成功概率可能只有5%。员工承担了大部分风险,而风险资本家则因为以一种对冲所有风险的方式进行投资而获取了利润。图书出版商在某些情况下也是如此,他们可能为作者做了很多,也可能做得很少,但在许多情况下却能获得图书收入的10%到15%,这也可以被视为一种寻租形式。

在这些场景中,通常伴随着高度的管理,因为资金掌握在他们手中。他们获取了大部分利润,并可能将其再投资回组织。至于这是否真正为社会或产品增加了价值,则需要具体情况具体分析。

平台与产品模式分析

在了解了寻租行为后,我们来看看更成熟的利润分享模式——平台与产品。以职业体育为例,UFC(终极格斗冠军赛)的利润分享比例较低,选手大约获得17%到20%的收益分成。而在更成熟的组织如NFL(美国国家橄榄球联盟)中,则达到了合伙人级别的分成,约50%的收入会返还给球员。篮球和棒球等联盟也有类似的利润分享机制。

这体现了一种合伙人均衡,其中的权衡开始对劳动者和所有者双方都有意义,这可能是一个值得考虑的“甜蜜点”。

至于平台模式,也存在一些好处。如果你能获得80%的利润,那对你非常有利。但如果存在无情的竞争,情况就不妙了。经济学中有一个表述:在完全竞争下,所有利润最终趋于零。这意味着,如果平台无法限制参与者加入,甚至无法区分优秀者与普通者,这确实可能导致利润被消除。当然,平台本身可能因为拥有大量竞争者并通过收取交易费而赚取很多钱。

最后的“产品”模式,对所有者而言近乎完美场景。例如,一个农民在路边直接向顾客销售水果,他获得了100%的利润,没有交易费,也没有中间商参与。当你直接将产品销售给客户时,就是这种情况。

总结与思考

本节课中,我们一起学习了利润分享的四种核心模式:搭便车者、寻租者、平台和产品。重要的是,每当你听到一个新的机会、新技术或思考新事物时,都要考虑到每种模式都存在权衡。搭便车者有得有失,寻租者、平台和产品模式也是如此。

以开放的眼光进入任何场景至关重要,同时也要从伦理角度思考:当你与采取其中某种行为的公司互动时,会对社会产生何种影响。

大型语言模型实践:P151:生成式AI的公共资源悲剧 🏞️

在本节课中,我们将探讨一个经典的经济学概念——“公共资源悲剧”,并分析其在生成式人工智能(AI)领域的体现。我们将理解当一项资源被无限制地共享时可能出现的问题,以及这些问题如何映射到生成式AI的开发与应用中。

公共资源悲剧概述

公共资源悲剧是一个经典案例,描述了当一项免费资源被几乎无限数量的人共享时可能发生的种种情况。

由于缺乏监管,不同的问题可能出现。例如,假设有一个公共公园,人们可能到处乱扔垃圾,仅凭乱扔垃圾这一项行为就足以破坏公园。公园也可能因为过度拥挤而被破坏。

再次假设没有监管,并且确实有大量人群不断涌入,最终公园会变得异常拥挤,导致你甚至无法参观公园。另一个例子是栖息地的破坏。

例如,如果你去一个国家公园,并开始破坏公园的某些特色景观或部分山体等,那么它将不再像以前那样美丽。或者,经典的例子是拥有不同牛群的公司。

一些牧场主会进入并相互竞争,看谁能消耗最多的草料,因为他们担心对方会比他们更快地消耗掉草料。

这本质上是一种“竞次”行为。然后,在你意识到之前,草料已被消耗殆尽,整个资源都被破坏了。这就是公共资源悲剧的经典案例。

事实上,根据各地的监管情况不同,你可以在世界各地的某些公共公园看到这种现象,包括在美国。

生成式AI的公共资源悲剧

生成式AI的公共资源悲剧具有一些类似的特征。

以下是生成式AI领域可能出现的具体问题:

  • 知识产权盗窃:生成式AI模型可能在未经授权的情况下,在受版权保护的作品上进行训练。涉及的作者或公司并未给予同意。这可能贬低原作品的价值,甚至削弱创作新内容的动力。如果你的财产将被窃取,你为何要创作更多?
  • 工作岗位替代:在生成式AI的案例中,存在人类创作者不再被需要的风险,这可能导致工作岗位被替代,并产生相关的负面外部效应。如果这些人无法再获得工作,社会就必须承担这种岗位替代的负担。
  • 质量控制问题:在输出作品方面,生成的作品可能因为质量低劣而贬低艺术家的价值,但这实际上是生成式AI在模仿艺术家。这可能导致整体的质量控制问题。
  • 缺乏认可或归属:创作者的作品可能在被窃取且未获补偿的情况下使用,他们甚至没有被认可为原作的真正创作者。这可能令人沮丧、不公平,并可能对该艺术家未来能否获得工作产生重大影响。
  • 伦理或道德权利担忧:作者可能不希望自己的形象与吸烟、饮酒或其他不良嗜好相关联,而你在使用其形象时并未征得其许可。

上一节我们概述了生成式AI可能引发的具体伦理问题,本节中我们来看看它与传统公共资源悲剧的关联。在生成式AI领域,传统的公共资源悲剧场景并非神奇地不存在,这些问题同样存在。

因此,我们需要同时审视其益处和负面影响。生成式AI有其强大的益处,例如总结、概述或协同创作。但也需要审视其负面外部效应:对社会的影响是什么?社会是否并未从某些方面受益?

例如,如果是一个商业模型,社会并未获得那份报酬,却必须承担成本。这再次类似于在公园乱扔垃圾、过度拥挤或破坏公园:你必须为他人滥用资源的行为付出代价。

总结

本节课中,我们一起学习了“公共资源悲剧”的概念及其在生成式AI伦理中的体现。我们认识到,在思考生成式AI的伦理时,考虑公共资源悲剧非常重要。这要求我们在享受技术红利的同时,也必须关注并设法解决其可能带来的知识产权、就业市场、作品质量和社会公平等挑战。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P152:生成式AI博弈论 🎲

在本节课中,我们将要学习博弈论的基本概念,并探讨它如何应用于生成式人工智能领域,帮助我们理解在技术竞争中可能出现的“囚徒困境”与“逐底竞争”现象。

博弈论简介

博弈论是一个数学框架,用于研究具有玩家、策略和收益的互动游戏,旨在找出最优策略或导致次优结果的主导策略。

在经典的“囚徒困境”问题中,自私的主导策略将导致对所有人都不利的次优结果。

囚徒困境案例

想象你是一名检察官,你逮捕了涉嫌犯罪的Sam和Helen,但缺乏定罪两人的证据。唯一获取所需证据的方法是让他们互相揭发。

以下是他们面临的收益矩阵:

  • 两人都保持沉默:每人仅被判入狱1年。
  • 一人坦白,另一人沉默:坦白者获释(0年),沉默者入狱20年。
  • 两人都坦白:每人入狱5年。

检察官通过分别向两人提供激励(“如果你坦白,你将获释,而你的同伙将入狱20年”),促使每个人都选择坦白。尽管如果两人能沟通合作,最优策略是都保持沉默(各判1年),但由于彼此不信任,最终导致了主导策略:两人都坦白,各判5年,刑期是合作情况下的五倍。

这是思考系统如何导致所有人皆输的经典方式,我们也可以从博弈论视角来看待生成式AI。

生成式AI中的博弈论应用

上一节我们介绍了经典的囚徒困境,本节中我们来看看博弈论在生成式AI领域的具体体现。

内容审核的“逐底竞争”

假设我们进入一个所有内容审核都由某个AI系统完成的世界。公司有强烈的动机确保其内容具有吸引力,因为如果参与度不足,公司将亏损。

因此,尽管平台上充斥着大量低质量的生成式AI内容,公司实际上会减少审核力度,因为这会影响公司的利润底线。一旦竞争对手意识到他们也开始亏损,他们也会改变内容审核策略。

以下是可能发生的连锁反应:

  1. 各平台不断降低审核标准。
  2. 平台上的审核越来越不严格。
  3. 最终,平台可能完全充斥着质量低劣、甚至包含有害内容的生成式AI内容。

这个过程可被称为 “逐底竞争”

知识产权盗用的困境

在生成式AI领域,你可能陷入另一种困境:假设你认为竞争对手或另一个国家/政府会盗用知识产权,因此你觉得也必须盗用相同的知识产权。

结果如下:

  1. 所有人都不再尊重知识产权。
  2. 每个人都开始盗用。
  3. 最终,知识产权的概念将不复存在。

这同样是一种 “逐底竞争”,因为你预判了对方会做坏事而采取了行动。

劣质创意作品的困境

这种情况直接映射了囚徒困境。如果你觉得竞争对手可能会开始使用通过简单提示生成的劣质AI作品,那么你也会做同样的事情。

其发展路径是:

  1. 双方都开始生产越来越差的艺术作品。
  2. 最终,你们生产的所有艺术品质量都很低劣。
  3. 结果是所有人皆输:客户输了,创作艺术的人也不再被雇佣。
  4. 从此再也没有真正优秀的艺术出现。

总结与启示

本节课中我们一起学习了博弈论的核心思想及其在生成式AI中的应用。可以看到,如果只从追求主导策略的角度思考问题,并且不进行迭代合作,只考虑单次博弈,就可能导致对游戏中所有玩家都不利的主导策略(次优结果)。

因此,在考虑像生成式AI这样的新技术时,一个非常重要的问题是:它的影响是什么?以及我们如何能创建一个迭代的合作策略,以避免陷入“逐底竞争”? 这需要行业参与者之间建立信任与协作机制,共同维护健康的发展生态。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P153:完全竞争市场

在本节课程中,我们将探讨经济学中的“完全竞争市场”概念,并将其类比到人工智能领域,特别是大型语言模型的商业模式。我们将分析在完全竞争条件下,利润如何趋于零,并思考这对企业AI战略的启示。

完全竞争市场的核心概念

在完全竞争市场中,所有经济利润最终会趋向于零。这具体意味着什么?

我们可以通过一个小镇餐馆的例子来理解。假设镇上有四家餐馆。起初,它们之间没有显著的竞争差异,直到一位才华横溢的厨师来到镇上。

现在,所有餐馆都必须竞争这位稀缺的厨师资源,因为他的才华能为餐馆吸引所有顾客。

餐馆们的行为是:它们不断相互竞价,支付越来越高的薪水,直到最终这位厨师拿走了所有的利润,因为厨师是一种有限或稀缺的资源。

这位厨师拥有稀有且需求旺盛的技能。许多餐馆竞相购买他的服务。最终,厨师将谈判获得极高的薪水,并攫取所有的经济利润。

经济利润的定义

那么,什么是经济利润?它指的是总收益减去总经济成本。这超出了正常的利润边际。

  • 正常利润是吸引投资所需的成本。
  • 经济利润是超出正常利润的部分。

本质上,这种完全竞争可能导致最终的破产,因为实际雇佣厨师的餐馆必须将所有利润都给厨师,并且无法通过其他方式竞争。

类比AI领域的竞争

同样,我们可以看一个可能发生类似情况的AI例子。

假设存在一个闭源模型,因其卓越的性能,所有人都必须使用它。那么,就像那位厨师一样,现在没有任何竞争优势了,因为每个人都必须使用同一个闭源模型。这些公司的所有利润都将流向API调用费用,就像餐馆例子中的厨师薪水一样。

另一方面,我们可能看到另一种情景:如果所有模型都是开源的,那么也无法盈利,因为你可以平等地使用任何模型。因此,训练模型的公司最终将倒闭,因为无法赚钱。

对AI战略的启示

这是一个假设性的情景,但在评估你的AI战略时,从经济学角度思考这一点非常重要。

  • 你认为全力投入闭源模型会给你带来竞争优势吗?
  • 还是认为,未来如果模型数量本质上无限,模型最终会变得像Linux一样,成为一种免费的商品,而你必须在其他形式的技术上进行竞争?

本节课中,我们一起学习了完全竞争市场的概念及其在AI领域的类比。我们了解到,当资源(如顶尖人才或核心技术)高度稀缺或完全普及时,市场竞争可能导致利润归零。这提醒我们,在制定AI战略时,需要深入思考技术路线的稀缺性、可替代性以及长期的竞争优势所在。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P154:53_03_06_负外部性

在本节课程中,我们将学习一个重要的经济学概念——负外部性,并探讨其在生成式人工智能技术部署中的现实意义。我们将理解负外部性的定义,分析其产生的原因,并思考如何在技术方案中负责任地评估和应对潜在的负外部性。

什么是负外部性?🤔

负外部性是指某些行为或产品在产生效益的同时,给未直接参与交易或活动的第三方带来了未获补偿的成本或损害。简单来说,就是“有人获利,却由他人买单”。

一个经典的公式化理解是:
社会总成本 = 私人成本 + 外部成本(负外部性)

当存在负外部性时,私人决策者(如公司)并未承担其行为的全部社会成本,这可能导致市场失灵,即从社会整体角度看,该行为被过度提供了。

一个极端的现实案例 🏭

为了更好地理解这个概念,让我们看一个基于真实事件的极端例子。

假设一个犯罪组织受某公司雇佣,将有毒废物(例如核废料或农药)非法倾倒入一个小镇。以下是该事件中各方的得失分析:

  • 犯罪组织:获得了100%的利润(雇佣金)。
  • 雇佣公司:以较低成本处理了废物,间接获利。
  • 小镇居民:未从倾倒行为中获得任何利润,却承担了全部代价。这些代价可能包括:
    • 居民健康受损,如罹患癌症或其他疾病。
    • 当地环境被污染,农业生产能力下降。
    • 财产价值贬损。

在这个案例中,倾倒有毒废物的行为产生了巨大的负外部性,全部由无辜的小镇居民承担,而犯罪组织和雇佣公司则获得了全部利益。

生成式AI中的潜在负外部性 🤖

上一节我们通过一个极端案例理解了负外部性的基本形态。现在,让我们将这一框架应用于生成式人工智能领域。

考虑一个商业公司通过API提供其生成式AI模型服务,并因此获得100%的利润。这看起来是成功的商业模式。然而,我们需要追问:是否存在潜在的负外部性?那些没有获得利润的人,是否会为AI生成的内容付出代价?

以下是生成式AI可能引发的一些负外部性场景:

  • 制造与传播虚假信息:AI生成的、看似真实的虚假内容(如模仿知名政治人物的语音)可能干扰选举结果。
  • 损害个人或组织声誉:针对特定个人或公司的AI生成不实信息,可能对其声誉或业务造成严重伤害。
  • 引发公共健康危机:关于医疗健康的AI生成错误建议,可能导致人们采取有害的行动。

在这些场景中,商业公司通过API调用获得了利润,但社会大众——即未直接参与交易的第三方——却可能承受谣言、社会信任度下降、健康风险等负外部性成本。

如何负责任地思考与应对 🛡️

认识到负外部性的存在,是负责任地开发和部署AI解决方案的第一步。这并不意味着所有技术都会产生极端的负面影响,但主动评估是不可或缺的。

在提出任何技术解决方案时,我们不仅要关注利润,还必须系统性地审视负外部性。你需要思考以下问题:

  • 你的技术可能对用户、社区或环境产生哪些意料之外的影响?
  • 即使这些影响是无意的,其实际后果是什么?
  • 如何设计机制来预防、减轻或补偿这些外部成本?

这种全面的评估框架,是将伦理和社会责任嵌入技术开发流程的负责任的做法。

总结 📚

本节课我们一起学习了负外部性这一核心概念。我们了解到,负外部性是指行为方获得收益,却由未参与的第三方承担成本的现象。我们通过非法倾倒有毒废物的案例加深了理解,并重点探讨了生成式AI技术可能带来的潜在负外部性,如制造虚假信息和损害公共利益。最后,我们强调,在部署AI解决方案时,采用包含负外部性评估的负责任框架至关重要,这要求我们在追求利润的同时,必须审视并尽力减少技术对社会的无意伤害。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P155:54_03_07_监管创业 🏛️

在本节课中,我们将要学习“监管创业”这一概念。这个概念由Paulllman和Barry在2017年提出,它描述了初创公司如何通过游走在法律灰色地带、快速扩张,最终反过来影响和改变法律法规的现象。我们将分析其核心策略、促成因素、社会影响,并探讨其在生成式AI等新兴领域的应用。

核心概念与定义

监管创业的本质是:通过违法或在法律灰色地带创建公司,随后再改变法律

这个策略的核心在于利用法律滞后于技术发展的特点,快速建立市场地位,形成“大到无法禁止”的局面,从而获得与监管机构谈判、甚至重塑规则的能力。

关键策略与促成因素

上一节我们介绍了监管创业的定义,本节中我们来看看实现这一目标通常采用哪些策略,以及哪些因素使其成为可能。

以下是监管创业公司常用的关键策略:

  • 识别法律灰色地带:寻找现有法律法规尚未明确覆盖或存在解释空间的商业领域。
  • 快速扩张:以极快的速度增长用户和市场规模,达到“大到无法禁止”的规模。
  • 动员用户获取政治支持:利用社交媒体和社区,将用户转化为政治游说力量,为自己的商业模式辩护。

以下是促成监管创业成功的主要因素:

  • 资金充足:获得大量风险投资,为快速扩张和应对潜在法律挑战提供资金。
  • 业务可扩展:商业模式具备高度的可扩展性,能迅速占领市场。
  • 公众吸引力:提供的服务或产品深受公众欢迎,容易获得舆论支持。
  • 瞄准地方性法规:优先挑战州或地方层面的法律,而非国家法律,因为前者阻力通常更小。
  • 诉讼的政治化:将法律诉讼视为一种政治和公关手段,而不仅仅是法律争端。

案例分析与社会影响

了解了策略和因素后,我们来看看几个典型案例,并分析其带来的社会影响。

以下是Airbnb、Uber、Draftkings和OpenAI的监管创业模式分析:

  • Airbnb:该公司获得了巨额利润和估值,为创始人和投资者带来了回报。但社会需要承担其带来的负外部性,即全球范围内可负担租赁住房单元的减少。
  • Uber:公司估值高达数百亿美元,风险投资者获得了回报。然而,社会,特别是像旧金山这样的城市,需要承担交通拥堵加剧和尾气排放增加带来的成本。这些污染和拥堵是强加给社会的负外部性,无人为此获得补偿。
  • Draftkings:它催生了一个价值数十亿美元的梦幻体育产业。但同时也导致了更多人赌博成瘾和个人破产案例增加。社会需要为此承担后果,例如,当一个人因赌博无法支付房贷导致家庭流离失所时,社会需要承担救助成本。
  • OpenAI与生成式AI:生成式AI带来了巨大的技术进步和商业利润。但同时也存在潜在损失:AI可能被用于破坏性用途;艺术家的版权作品在未经明确许可的情况下被用于模型训练,引发了版权争议。使用受版权保护的数据进行训练的成本,构成了社会需要承担的潜在损失。

总结与展望

本节课中我们一起学习了监管创业的概念、策略、案例及其社会影响。

监管创业现象已存在相当长的时间,在风险投资支持的科技公司中尤为常见。其典型模式包括:快速成长至巨大规模、要求巨额资金、业务高度可扩展,以及由能够游说国会的人士领导。

未来会如何发展?是出现更多监管,还是更少?这仍有待观察。但可以肯定的是,理解监管创业的模式,对于分析新兴技术公司(如生成式AI领域的企业)的发展路径、评估其创新价值与社会成本之间的平衡至关重要。

大型语言模型实践:P156:创建或强化偏见

概述

在本节课中,我们将要学习生成式人工智能中一个关键的伦理问题:偏见是如何被创建或强化的。我们将探讨偏见数据如何影响模型训练、推荐系统如何放大有害内容,以及这对社会造成的长期成本。


偏见问题的本质

生成式人工智能中的偏见创建或强化是一个必须解决的伦理问题。

这里有一个数据集,其中包含了一些固有的偏见。这些偏见可能涉及刻板印象、歧视,甚至仇恨言论。如果我们在训练模型时不处理这些信息,就会将其置入一个能够生成更多偏见的系统中,从而强化了偏见。

偏见强化的恶性循环

上一节我们介绍了偏见问题的本质,本节中我们来看看一个具体的恶性循环案例。

一个典型的例子是,生成式AI产生的内容被放入推荐引擎后,带有有害偏见的内容可能获得更高的参与度。这意味着,一个基于偏见数据训练的模型实际上能带来利润。这种利润甚至会被其传播的有害刻板印象和错误信息进一步放大,因为推荐引擎只以参与度这一指标为食。

因此,结果不仅是您最初创建了偏见,而且通过将其推荐给数百万甚至数十亿人,您还强化了这种偏见。这是一个现实问题,因为一方面社交媒体公司可以赚取这些利润,但另一方面,社会将为此付出代价。

以下是偏见强化可能带来的社会影响:

  • 可能导致进一步的歧视。
  • 可能引发仇恨犯罪。
  • 可能对社会产生各种负面影响。

偏见系统的运作机制

认识到偏见的危害后,我们需要理解它是如何运作的。让我们从源头开始分析。

假设您收集了一个与过去用户参与度相关的偏见数据集。这可能是由一些曾经发生过的有害行为导致的。接着,您优化模型以追求点击、分享和引发愤怒(这可能再次涉及有害内容)。这将创造一个“信息茧房”和有毒的个性化推荐,导致人们被吸引到这些有毒内容中。

这为公司带来了大量收入。因此,公司的利润通过煽动愤怒、传播错误信息和提升整体参与度而增长。用户在该网站上花费的时间越多,您就能展示更多广告,并可能卖出更高的价格(至少在短期内)。

短期收益与长期成本

上一节我们看到了偏见系统如何为公司带来短期收益,本节中我们来审视其长期的社会成本。

短期内,增长和利润的上升会让人觉得一切都在朝着正确的方向发展。但正如我们之前提到的,被传播数据带来的歧视和对边缘群体的刻板印象,这些成本必须由社会来承担。它可能进一步固化分歧,甚至削弱人们对复杂议题的理解。

长期来看,这可能导致极端主义、暴力和不稳定的加剧。简而言之,这不是一个理论问题,而是一个必须与生成式AI系统一起处理的现实问题。

解决方案与伦理考量

面对偏见带来的挑战,我们必须思考解决方案。您必须考虑对优化参与度算法进行监督,甚至改变要求以纳入伦理考量,同时进行政策改革以应对这些有毒的商业模式。

仅仅因为公司正在盈利,并不意味着这总是好事。利润的背后可能是有害的刻板印象。因此,社会必须处理其后果。

以下是几种可能的应对措施:

  • 税收:可以通过税收来解决这个问题。
  • 立法:可以通过立法来解决这个问题。
  • 伦理培训:可以通过伦理培训来解决这个问题。

事实上,所有这些措施结合起来,可能是我们开始认真思考的起点:超越单纯的利润,全面考虑构建人们使用的系统意味着什么,以及这些系统对社会产生的影响。


总结

本节课中我们一起学习了生成式AI中偏见创建与强化的全过程。我们了解到,基于偏见数据训练的模型会通过推荐系统放大有害内容,为公司带来短期利润,却让社会承担歧视、分裂和不稳定的长期成本。解决这一问题需要算法监督、伦理考量、政策改革等多方面的共同努力,以确保技术的发展服务于更广泛的社会福祉,而不仅仅是商业利益。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P157:56_03_02_Python实现ELO算法

在本节课中,我们将要学习ELO算法的原理及其在评估大型语言模型中的应用。我们将通过Python代码实现一个简单的ELO评分系统,并理解它如何超越简单的胜负记录,提供更准确的实力评估。

概述:ELO算法与模型评估

许多人关注聊天机器人竞技场,因为它是进行大型语言模型一对一测试的好方法。我们可以比较商业模型、开源模型和专有模型。其真正酷炫之处在于,我们可以从数值角度深入分析哪个模型更优。

我们能够进行这种分析的原因是ELO算法。ELO是一种“赛程强度”指标。它真正评分的是你相对于对手的表现,而不仅仅是你的得分。例如,如果你取得了20胜0负的战绩,但所有对手都是业余选手,这就不如一个可能有一些失利,但对手实力强劲的选手有说服力。ELO算法告诉我们的正是这种赛程强度。

Python实现ELO算法

上一节我们介绍了ELO算法的核心概念,本节中我们来看看如何用Python代码实现它。

以下是一个简单的“拳手”类实现,用于模拟ELO评分更新:

class Fighter:
    def __init__(self, name, rating=1500):
        self.name = name
        self.rating = rating

    def update_rating(self, opponent_rating, result, K=32):
        """
        根据比赛结果更新ELO评分。
        result: 1表示胜利,0表示失败。
        """
        expected_score = 1 / (1 + 10 ** ((opponent_rating - self.rating) / 400))
        self.rating += K * (result - expected_score)

在这个实现中,K值设为32。K是调整因子,我们可以根据比赛数量进行调整。例如,国际象棋比赛场次多,K=32是一个常用值;而UFC比赛场次少,K值可能需要设得更大一些。具体数值需要根据数据集的经验进行调整。

简而言之,该算法表示:如果你获胜,你的得分将取决于对手的评分作为权重的一部分;如果你失败,同样会考虑对手的评分作为计算组件。

模拟比赛与评分更新

以下是使用我们定义的Fighter类进行一场比赛模拟的步骤:

首先,我们创建两名拳手并打印赛前评分。

# 创建拳手
connor = Fighter("Connor McGregor", 1500)
khabib = Fighter("Khabib Nurmagomedov", 1500)

# 打印赛前评分
print(f"赛前评分: {connor.name}: {connor.rating}, {khabib.name}: {khabib.rating}")

接着,我们模拟比赛结果并更新他们的评分。假设Khabib获胜。

# 模拟Khabib获胜,result=1
khabib.update_rating(connor.rating, result=1)
# Connor失败,result=0
connor.update_rating(khabib.rating, result=0)

# 打印赛后评分
print(f"赛后评分: {connor.name}: {connor.rating}, {khabib.name}: {khabib.rating}")

运行这段代码,我们可以看到Connor的评分从1500下降到约1475,而Khabib的评分上升到约1525。通过多次迭代,我们可以得到一系列指标,这些指标基于对手的实力来展示谁是最佳的,而不仅仅是基于他们是否获胜。

交互式探索与总结

ELO算法的强大之处在于它是衡量竞争水平的绝佳方式。我们甚至可以在IPython等交互式环境中进一步探索。

例如,我们可以导入Fighter类,创建实例并进行实验。使用__dict__方法可以查看对象的内部状态,我们会发现它只是一个包含姓名和评分的字典。这说明ELO并非神秘的指标,自己编写代码实现相当简单。

本节课中我们一起学习了ELO评分算法的基本原理和Python实现。ELO是一个直观的评分系统,是判断大型语言模型(无论是开源还是专有模型)在真实场景中竞争表现的优秀指标。通过考虑对手强度而非单纯胜负,它能更公平地评估模型的真实能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P158:57_03_03_Rust实现ELO算法 🦀

在本节课中,我们将学习如何使用Rust编程语言实现ELO评分算法。ELO算法是一种用于比较两个竞争者相对水平的方法,广泛应用于棋类、电子竞技等比赛评分系统中。我们将通过一个简单的拳击手对战示例,来理解其核心逻辑和Rust的具体实现。

概述与数据结构

首先,我们定义一个表示拳击手的数据结构。这个结构体包含拳击手的名字和当前的ELO评分。

struct Fighter {
    name: String,
    rating: u16,
}

上一节我们定义了数据结构,本节中我们来看看如何为这个结构体实现相关的方法。

实现结构体方法

以下是Fighter结构体需要实现的方法,包括创建新拳击手和更新评分。

impl Fighter {
    // 创建一个新的拳击手实例
    fn new(name: String, rating: u16) -> Self {
        Fighter { name, rating }
    }

    // 根据比赛结果更新拳击手的评分
    fn update_rating(&mut self, opponent_rating: u16, result: f32) {
        // 核心ELO计算逻辑将在这里实现
    }
}

ELO评分更新逻辑

update_rating方法是整个ELO算法的核心。它根据比赛结果(胜、负、平)和对手的评分来更新当前拳击手的评分。

其核心公式如下:
新评分 = 旧评分 + K * (实际得分 - 预期胜率)

其中:

  • K值:是一个调节因子,决定评分变化的幅度。比赛频率低的项目(如拳击)使用较大的K值,频率高的项目使用较小的K值。
  • 预期胜率:表示当前拳击手战胜对手的概率,计算公式为:1.0 / (1.0 + 10.0.powf((对手评分 - 自身评分) / 400.0))
  • 实际得分:胜利为1.0,失败为0.0,平局为0.5。

以下是该方法的实现代码:

fn update_rating(&mut self, opponent_rating: u16, result: f32) {
    let k_factor = 32; // 设定K值
    let expected_score = 1.0 / (1.0 + 10.0_f32.powf(((opponent_rating as f32) - (self.rating as f32)) / 400.0));
    let rating_change = (k_factor as f32) * (result - expected_score);
    self.rating = (self.rating as f32 + rating_change).round() as u16;
}

主程序与实战模拟

理解了核心算法后,我们来看看如何在主函数中使用它来模拟一场比赛。

以下是主程序的步骤:

  1. 初始化两名拳击手,并赋予他们相同的初始评分(例如1500分)。
  2. 模拟一场比赛,调用update_rating方法更新双方的评分。
  3. 打印比赛后的评分结果。
fn main() {
    // 创建两名拳击手
    let mut fighter1 = Fighter::new(String::from("Conor McGregor"), 1500);
    let mut fighter2 = Fighter::new(String::from("Khabib Nurmagomedov"), 1500);

    // 模拟比赛:fighter1 战胜 fighter2
    fighter1.update_rating(fighter2.rating, 1.0); // fighter1 获胜,得分为1.0
    fighter2.update_rating(fighter1.rating, 0.0); // fighter2 失败,得分为0.0

    // 打印更新后的评分
    println!("{}: {}", fighter1.name, fighter1.rating);
    println!("{}: {}", fighter2.name, fighter2.rating);
}

在Rust中,如果要修改变量的值,必须使用mut关键字将其显式声明为可变的。同时,在向函数传递可变引用时,会涉及到“借用”的概念,这保证了内存安全。

运行与编译

现在,让我们来运行这个程序。首先确保代码格式正确,然后进行编译和运行。

以下是运行Rust项目的步骤:

  1. 使用 cargo fmt 命令格式化代码。
  2. 使用 cargo run 命令编译并运行程序。

运行后,输出结果可能如下:

Conor McGregor: 1516
Khabib Nurmagomedov: 1484

获胜者Conor的评分上升,失败者Khabib的评分下降,这符合ELO算法的预期。

cargo run会生成一个位于target/debug/目录下的可执行文件。你也可以直接运行这个二进制文件。Rust的强类型系统和编译器保证了代码的安全性,并且能生成高性能的可执行文件,非常适合用于需要大规模生成评估指标的生产环境,例如使用ELO算法来评估公司内部不同大型语言模型的性能。

总结

本节课中我们一起学习了如何使用Rust实现ELO评分算法。我们从定义Fighter结构体开始,逐步实现了创建实例和更新评分的方法,并深入探讨了ELO更新的核心公式。最后,我们通过一个主程序模拟了比赛过程,并了解了Rust项目的运行和编译步骤。Rust以其安全性和高性能,成为实现此类计算密集型算法的优秀选择。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P159:58_03_04_R语言实现ELO算法 🏆

在本节课中,我们将学习如何在Google Colab Pro环境中使用R语言来实现一个经典的ELO评分算法。ELO算法常用于评估游戏或比赛中选手的相对技能水平。

Colab Pro环境介绍

上一节我们介绍了课程背景,本节中我们来看看Colab Pro这个强大的工具。Colab Pro是一个托管的Jupyter笔记本环境,它提供了许多你可能不知道的有趣功能。

以下是Colab Pro的一些关键特性:

  • 托管运行时:运行时环境由平台管理,这意味着你无需担心软件包管理和依赖冲突问题。
  • 多语言支持:你可以在Colab中使用R语言进行编程。
  • 硬件加速:你可以选择使用CPU、A100 GPU、V100 GPU等传统NVIDIA GPU,或者使用Google自研的Tensor处理单元(TPU)。
  • 高内存模式:可以开启高内存模式,这对于处理大型数据集非常有用。

R语言是专为统计学设计的语言,在统计编程方面表现出色。在Colab Pro中使用R,可以让你更专注于算法和数据分析本身,而不是环境配置和库安装等问题。

ELO算法实现

了解了环境之后,我们来看看如何用R语言实现ELO算法。ELO是一种衡量选手相对实力的评分系统。

以下是用R语言定义ELO评分函数的代码:

elo_rating <- function(fighter1, fighter2, result, k_factor = 32) {
  # 默认评分
  if (missing(fighter1)) fighter1 <- 1500
  if (missing(fighter2)) fighter2 <- 1500

  # 期望得分函数
  expected_score <- function(rating_a, rating_b) {
    1 / (1 + 10^((rating_b - rating_a) / 400))
  }

  # 计算期望值
  expected1 <- expected_score(fighter1, fighter2)
  expected2 <- expected_score(fighter2, fighter1)

  # 根据结果更新评分
  if (result == 1) { # fighter1 获胜
    fighter1 <- fighter1 + k_factor * (1 - expected1)
    fighter2 <- fighter2 + k_factor * (0 - expected2)
  } else if (result == 0) { # fighter2 获胜
    fighter1 <- fighter1 + k_factor * (0 - expected1)
    fighter2 <- fighter2 + k_factor * (1 - expected2)
  } else { # 平局
    fighter1 <- fighter1 + k_factor * (0.5 - expected1)
    fighter2 <- fighter2 + k_factor * (0.5 - expected2)
  }

  # 返回更新后的评分
  return(c(fighter1, fighter2))
}

这个函数接收两个选手的当前评分(fighter1, fighter2)、比赛结果(result)以及一个K因子(k_factor,默认值为32)。其核心逻辑是:

  1. 通过expected_score函数计算每位选手的预期胜率。
  2. 根据实际比赛结果(1胜/0负/0.5平)与预期胜率的差值,结合K因子来更新选手的评分。
  3. 最后返回更新后的两位选手的评分。

运行ELO算法示例

定义好函数后,我们可以运行一个具体的例子。假设有两位选手“Connor”和“Khabib”,他们的初始评分均为1500。现在“Khabib”战胜了“Connor”。

以下是初始化选手并计算新评分的代码:

# 初始化选手评分
connor <- 1500
khabib <- 1500

# 假设Khabib获胜(result=0表示第二个参数fighter2获胜)
new_ratings <- elo_rating(connor, khabib, result = 0)

# 打印结果
print(paste("Connor的新评分:", round(new_ratings[1], 2)))
print(paste("Khabib的新评分:", round(new_ratings[2], 2)))

运行这段代码后,我们会看到输出结果:Connor的评分下降(例如1475),而Khabib的评分上升(例如1525)。这直观地反映了比赛结果对选手实力评估的影响。

总结

本节课中我们一起学习了在Google Colab Pro环境中使用R语言实现ELO评分算法。我们首先介绍了Colab Pro支持R语言编程的特性及其优势,然后逐步解析并编写了ELO算法的核心函数,最后通过一个实战例子演示了算法的运行过程。这展示了如何利用合适的工具(Colab Pro)和语言(R)来高效地完成统计编程任务。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P160:59_03_05_Julia实现ELO算法

在本节课程中,我们将学习如何使用Julia编程语言来实现ELO评分算法,并模拟两位UFC(终极格斗冠军赛)选手的赛程强度计算。我们将通过具体的代码示例,理解Julia语言在数据科学应用中的一些高级特性。

概述

ELO算法是一种用于评估选手相对技能水平的评分系统,广泛应用于国际象棋、电子竞技和体育赛事中。本节我们将使用Julia语言构建一个简单的模拟程序,计算两位UFC选手比赛后的ELO评分变化。我们将重点关注Julia语言的结构体定义、函数编写以及其类型系统和可变性控制等特性。

定义选手结构体

首先,我们需要定义一个数据结构来表示选手。在Julia中,我们使用struct来创建自定义类型。

以下是定义选手结构体的代码:

mutable struct Fighter
    name::String
    rating::Float64
end

我们定义了一个名为Fighter的可变结构体。它包含两个字段:name(选手姓名,字符串类型)和rating(ELO评分,浮点数类型)。mutable关键字允许我们在后续程序中更新这个结构体的字段值(例如更新评分)。这是Julia语言一个精妙的安全特性,也是许多现代编程语言共有的特点。它默认情况下数据是不可变的,这提供了内置的安全机制,即使Julia是一种脚本语言,也具备这种能力。

实现评分更新函数

定义了数据结构后,我们需要一个函数来根据比赛结果更新选手的ELO评分。

上一节我们定义了选手的结构体,本节中我们来看看如何实现更新评分的逻辑。

以下是实现update_rating函数的代码:

function update_rating(fighter::Fighter, opponent::Fighter, result::String)::String
    k = 50
    expected_score = 1 / (1 + 10^((opponent.rating - fighter.rating) / 400))
    fighter.rating = fighter.rating + k * (parse(Int, result) - expected_score)
    return "Rating updated for $(fighter.name)"
end

这个函数名为update_rating。它接收三个参数:fighter(待更新评分的选手)、opponent(对手选手)和result(比赛结果,例如“1”代表胜利,“0”代表失败)。函数末尾的::String指明了函数的返回类型是字符串。

函数内部,我们首先定义了一个常数k(通常称为K因子),这里设为50,它决定了评分调整的幅度。接着,我们计算了expected_score(期望得分),这是ELO算法的核心公式之一,用于预测选手获胜的概率。最后,我们根据实际结果和期望得分的差值,使用ELO公式更新了fighter的评分。parse(Int, result)将字符串形式的结果转换为整数进行计算。

这个update_rating方法会改变(mutate)传入的fighter对象的评分值。让我们运行一下看看效果。

模拟比赛与评分更新

现在,我们有了结构体和更新函数,可以创建选手实例并模拟一场比赛了。

以下是初始化选手并进行评分计算的示例:

# 创建两位选手,初始评分相同
fighter1 = Fighter("Conor McGregor", 1500.0)
fighter2 = Fighter("Khabib Nurmagomedov", 1500.0)

println("赛前评分:")
println("$(fighter1.name): $(fighter1.rating)")
println("$(fighter2.name): $(fighter2.rating)")

# 假设fighter1(Conor McGregor)输掉了比赛(result = “0”)
update_result = update_rating(fighter1, fighter2, "0")

println("\n$(update_result)")
println("\n赛后评分:")
println("$(fighter1.name): $(fighter1.rating)")
println("$(fighter2.name): $(fighter2.rating)")

在比赛开始前,我们为每位选手分配了一个默认的ELO评分(例如1500分)。这样,我们可以基于这次初始交锋来衡量胜利或失败的权重。

运行代码后,我们可以看到,在比赛前,康纳·麦格雷戈和哈比布·努尔马戈梅多夫的评分是相等的。但当我们应用ELO计算后(该计算基于对手的竞争水平来衡量选手能力),情况发生了变化。比赛后,输掉比赛的选手康纳·麦格雷戈的ELO评分降低了,而他的对手哈比布·努尔马戈梅多夫的评分则升高了。

Julia语言特性总结

通过这个简单的例子,我们可以看到Julia语言作为数据科学语言实际上非常精妙。

以下是一些值得注意的Julia语言特性:

  1. 可变与不可变结构体:通过mutable关键字控制,默认不可变,增强了代码安全性。
  2. 类型系统:函数和结构体可以指定参数和字段的类型,使代码意图更清晰,并能在编译期捕获一些错误。
  3. 简洁的语法:代码可读性高,例如上面的函数定义清晰明了,很容易理解发生了什么。
  4. 适合交互式开发:在Jupyter笔记本中使用Julia构建解决方案是一种非常合理的选择,便于快速原型设计和数据分析。

总结

本节课中我们一起学习了如何使用Julia语言实现ELO评分算法。我们从定义表示选手的可变结构体Fighter开始,然后实现了包含ELO核心公式的update_rating函数,最后模拟了一场UFC比赛并观察了评分的变化。通过这个实践,我们不仅理解了ELO算法的基本原理,也领略了Julia语言在类型安全、代码清晰度和交互式数据科学工作流方面的优势。在构建数据科学和机器学习解决方案时,Julia是一个强大而现代的工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P161:60_03_02_Lorax与SkyPilot入门指南

概述

在本节课中,我们将要学习如何部署大型语言模型。我们将重点介绍两个工具:Lorax(一个高性能推理服务器)和SkyPilot(一个云部署框架)。通过结合使用它们,你可以轻松地在云端部署开源大语言模型,并在不需要时停止服务以节省成本。


Lorax:一个简单高效的LLM部署方案

处理大型语言模型时,你面临的一个主要问题是如何部署它们。Lorax是解决这个问题的方案之一。

如果我们查看Perbase提供的文档,会发现它实际上非常简单。你可以运行一个包含基础大语言模型的容器,例如我们将要使用的mistral模型,然后选择GPU。这样,你就准备就绪了。文档中还提供了一些如何提示模型的示例。

这非常吸引人。Lorax的另一个优点是它使用Rust构建,具有出色的推理性能。


使用SkyPilot进行云端部署

我认为部署Lorax的一个更简单的方法是使用基于云的GPU。为此,我们可以使用SkyPilot。

我们访问SkyPilot,点击它,需要做的就是执行pip install安装,并确保环境准备就绪。接下来的步骤非常简单,因为你只需要粘贴一个YAML配置文件。

以下是Perbase团队提供的一个YAML配置示例,它展示了SkyPilot的强大之处:

resources:
  cloud: aws
  accelerators: A10G:1
  disk_size: 1024
  ports: 8000
setup: |
  pip install lorax
run: |
  lorax serve --model-id mistralai/Mistral-7B-Instruct-v0.1 --port 8000

我喜欢Perbase的一点是,他们在YAML文件方面做了大量出色的工作。例如,微调也可以使用YAML文件。但看看这个部署配置,它非常清晰:你可以看到AWS云服务、加速器类型、端口等设置,以及要加载的模型。

在我看来,这已经非常完善了。如果你已经设置好了AWS密钥,接下来需要做的就是启动Lorax任务。


实战演示:部署与查询

我将切换到我的已配置环境中进行演示。一旦服务启动,你可以看到服务器正在运行并输出日志,我们甚至能看到HTTP请求。

接下来,让我们按照官方文档来查询这个服务。首先,我们需要获取服务的状态和IP地址。我们可以在另一个窗口执行以下命令:

sky status --ip lorax-cluster

执行后,我们可以看到集群的IP地址。接下来,我们看看如何发送提示。这很简单,实际上就是执行一个curl命令。我们将把获取到的IP地址填入命令中。

我们可以并排运行这两个过程:在一边观察服务器输出,在另一边运行查询代码。我只需要复制文档中的curl命令示例,然后粘贴执行。

curl -X POST http://<YOUR_IP>:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"inputs": "请用Python写一个快速排序函数", "parameters": {"max_new_tokens": 100}}'

执行后,我们可以看到服务器收到了查询请求,并使用mistral模型生成了代码示例。


核心优势与成本控制

这个方案真正强大之处在于:我们获得了一个使用开源模型的高性能推理服务器。我们只需要一个基于YAML的配置就能完成部署。

更酷的是,当我们完成工作后,可以运行停止命令来关闭部署,这样就不会产生额外的费用。我们可以执行:

sky stop lorax-cluster

系统会询问是否确认,选择“是”即可。


总结

本节课中我们一起学习了如何部署大型语言模型。我认为,Lorax 结合 SkyPilot 是目前最引人注目的解决方案之一,尤其适用于部署开源大型语言模型。

我们看到了整个工作流程:从简单的YAML配置,到在云端一键启动高性能推理服务,再到方便地停止服务以控制成本。这对于考虑在生产环境中部署大语言模型的公司CTO或工程师来说,是一个非常具有吸引力的方案。在此,要向Perbase及其团队致敬,他们打造了一个令人印象深刻的工作流。

大型语言模型实践:P162:使用Ludwig微调Mistral-7B模型 🚀

在本节课中,我们将要学习如何使用Ludwig这一低代码框架来微调Mistral-7B大型语言模型。我们将了解其基于YAML配置文件的简洁工作流程,并演示如何在Colab Pro环境中执行微调任务。


Ludwig是一个用于大型语言模型的微调工具,它以低代码和配置驱动为特点,简化了模型训练过程。许多人对于训练大型语言模型并深入了解其生态系统非常感兴趣,而Ludwig是一个很好的选择。

上一节我们介绍了Ludwig的基本概念,本节中我们来看看它的具体特性和工作方式。

首先,Ludwig使用配置文件来定义训练任务,这是一个非常吸引人的特性。它提供了入门指南,例如针对当前热门的开源大模型Mistral进行微调的教程。其基于YAML的方法使得流程非常清晰,并且支持通过命令行直接进行训练。这使其具备了一些类似于DevOps工作流的特性,能够通过YAML文件简化操作。


现在,让我们看看如何在Colab Pro环境中使用Ludwig。Colab Pro是一个进行微调的不错选择,因为它提供了GPU访问。

以下是设置和运行环境的关键步骤:

  1. 选择运行时:在Colab Pro中,可以访问包含充足RAM和磁盘空间的环境。
  2. 配置GPU:通过运行时设置,可以切换不同类型的GPU。对于此类任务,一个性能良好的GPU就足够了,但也可以根据需要选择更高规格的GPU。

这个特定笔记本的目标是使用大型语言模型进行代码生成。数据集中包含英语指令和对应的代码。

以下是微调流程的核心步骤:

  1. 定义配置:使用一个YAML文件来指定模型的输入、输出以及基础模型。例如,基础模型可以设置为mistralai/Mistral-7B-v0.1
  2. 加载数据:微调的核心在于使用自定义数据来改进已有模型。需要加载代码生成数据集,该数据集通常包含指令(input)和期望的代码(output)。
  3. 数据预处理:在微调工作中,对数据进行一些处理是常规操作。
  4. 执行训练:加载整个项目配置后,微调过程开始。训练过程中会输出进度和指标,并显示所使用的GPU类型。

使用Ludwig可能是执行微调最简单的方式之一。它提供的示例笔记本使得整个过程非常直观。对于想要尝试微调最新大型语言模型的人来说,这或许是最简单的入门途径。


本节课中我们一起学习了如何使用Ludwig框架微调Mistral-7B模型。我们了解了其基于YAML配置的低代码优势,并逐步讲解了在Colab Pro中从环境设置、数据准备到执行训练的全过程。Ludwig通过简化的流程,降低了大型语言模型微调的技术门槛。

大型语言模型实践:P163:Llamafile入门教程 🚀

在本节课中,我们将学习如何使用Llamafile项目在本地运行大型语言模型。Llamafile由Mozilla开发,它可能是运行本地大语言模型最简单的方式。我们将了解其核心概念、优势以及具体的操作步骤。


项目概述与优势

许多人希望在本地运行大型语言模型,主要出于隐私考虑,并且如果使用自己的机器,它是免费的。Llamafile项目让你能够通过单个文件分发和运行LLM。

其核心在于使用了Cosmopolitan Libc库,能够将所有内容打包成一个名为llamafile的单一可执行文件。有趣的是,尽管名为Llamafile,但它并不绑定于任何特定的大语言模型。

本地运行模型主要有三大优势:

  1. 隐私性:你的数据不会被发送到你不了解其数据政策的公司。
  2. 性能:由于减少了网络延迟,性能通常优于调用外部API。
  3. 免费:使用自己的硬件资源,无需支付API调用费用。

获取与运行模型

上一节我们介绍了Llamafile项目的优势,本节中我们来看看如何具体获取和运行一个模型。

Llamafile支持多种模型。其中一个比较有趣的模型是Mistral。它是一个性能较好的开源模型,采用Apache 2.0许可证。模型文件大约为30GB,虽然下载体积较大,但运行起来非常简单。

以下是运行模型的基本步骤:

  1. 下载你选择的模型文件(例如Mistral的llamafile)。
  2. 在终端中,进入文件所在目录。
  3. 通过命令行执行该文件。

运行命令非常简单,只需在终端中输入:

./llamafile文件名

执行后,本地服务就会启动。你可以看到类似llama.cpp正在本地运行的提示。


使用方式:Web界面与API

模型运行起来后,我们可以通过多种方式与它交互。Llamafile提供了便捷的Web界面,同时也提供了兼容OpenAI的API。

启动服务后,通常可以在浏览器中访问一个本地地址(如 http://localhost:8080)来打开Web聊天界面。在界面中,你可以直接与模型对话。

例如,你可以输入以下指令:

请用Python写一个“Hello, World”函数。

模型会利用你本地的GPU资源(如果可用)快速生成响应代码。

更强大的是,Llamafile提供了一个Python API,它模仿了OpenAI的API格式。这意味着你可以轻松地将使用商业闭源模型(如GPT)的代码,迁移到使用这个本地开源模型上,只需更改API的端点地址即可。


实践示例与总结

让我们通过一个具体例子来巩固所学。假设我们已经在本地运行了Mistral模型的Llamafile。

首先,我们通过Web界面重置对话状态,然后将助手名称设置为“AI”。接着,我们可以要求它编写一个Python函数。

例如,输入请求:

构建一个将两个数字相加的Python函数。

模型会生成相应的代码。你可以继续提出更多请求,比如让它解释代码或进行修改。

本节课中我们一起学习了Llamafile的核心用法。总结来说,Llamafile使得在本地运行大语言模型变得非常直接。它的主要优点在于保护隐私、提升响应速度以及节省成本。这是一个非常值得尝试的项目,建议你亲自下载体验,探索其更多功能。

大型语言模型实践:P164:使用Llamafile监控本地系统指标 🖥️📊

在本节课中,我们将学习如何使用Llamafile工具来监控本地运行大型语言模型时的系统指标,特别是GPU的使用情况。通过观察这些指标,我们可以评估本地模型的性能表现。

监控系统指标的意义

上一节我们介绍了Llamafile的基本概念,本节中我们来看看如何利用它来监控系统性能。首先,我们可以从模型的Elo评分来了解其实际表现。这个评分反映了用户对模型能力的感知。

从评分可以看出,一些混合模型的表现与商业模型相差无几。这表明,只要本地模型的性能足够好,就会有大量用户有兴趣在本地运行它。那么,本地模型的性能究竟如何呢?让我们通过Llamafile项目来一探究竟。

观察Llamafile的运行状态

目前,我已在网页浏览器窗口中运行了Llamafile,并且可以在这里看到所有的监控指标。这些指标让我们能够清晰地了解系统正在发生什么。

以下是需要关注的关键指标:

  • GPU时间:这是首要关注的指标之一。
  • 所有核心:观察所有处理核心的利用率。
  • M2 Ultra GPU:以我使用的配备60个GPU核心的M2 Ultra为例,得益于Llamafile和Llama.cpp开发者的出色工作,它能够在Mac操作系统上充分利用所有这些GPU核心。

接下来,让我们具体查看一下。如果我向下滚动,可以看到一个Python函数的示例,我们将观察在此期间GPU的活动情况。

实际性能测试与分析

我们会看到GPU使用率在这里出现峰值,同时也能观察到GPU确实被dot a1.9这个进程所调用。

实际上,我们可以看到它再次运行。我们可以进行另一个测试,例如,要求模型“给我一个Python中递归函数的例子”。然后观察它的表现。

模型给出了一个Python递归函数的例子,同时我们也能看到,它确实使用了GPU。由此可见,其性能实际上非常出色。从历史GPU数据来看,它能够有效地利用硬件资源。

对于正在使用商业模型的用户来说,商业模型固然有其价值,但这无疑引发了一个长期问题:如果你可以下载一个性能足够好、表现惊人且完全免费的模型,那么长期来看,为什么还要使用商业模型呢?

因此,在你尝试使用Llamafile这类本地工具,或者考虑为大型语言模型签订商业协议之前,首先应该审视一下本地模型的真实性能。仔细观察各项系统指标,你会发现它的表现令人印象深刻。

课程总结

本节课中我们一起学习了如何使用Llamafile监控本地运行LLM时的系统指标。我们观察了GPU利用率等关键数据,并通过实际测试验证了本地模型能够有效利用硬件资源(如M2 Ultra的60个GPU核心),展现出足以媲美商业模型的性能。这为我们评估是否选择本地部署提供了重要的实践依据。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P165:64_04_04_Candle框架Hello World示例 🚀

在本节课中,我们将学习如何使用Rust的Candle框架创建一个简单的“Hello World”项目。我们将涵盖从环境设置到项目构建的完整流程,包括如何添加GPU(CUDA)支持。

概述

我们将分步演示如何在配置好的开发环境中,使用Cargo工具初始化一个Rust项目,并集成Candle框架。课程将展示如何构建一个基础版本的项目,以及如何通过添加CUDA功能来启用GPU加速。

环境准备与验证

首先,我们有一个已配置好GPU开发和Rust环境的Github Codespace。

我们可以输入 rustc --version 来验证Rust是否已安装。

我们也可以输入 make verify 命令。这个命令会显示计算能力,并确认CUDA编译器驱动已就位。

创建基础Rust项目

接下来,我将按照Hugging Face Rust Candle的文档进行操作。首先,使用 cargo new my_app 命令创建一个新的Rust项目。

创建完成后,我们进入项目目录 my_app

我喜欢将我自己的Makefile复制到项目中。这样我就可以使用所有预设的命令和快捷方式。

此时,我们可以直接运行 cargo build 来构建项目,使其准备就绪。

构建无GPU支持的项目

首先,让我们构建一个不支持GPU的版本。我们直接运行 cargo 命令。

我们只需要输入 cargo add candle-core,它就会为我们添加Candle接口。

添加完成后,如果我们查看源代码,会看到一个 main.rs 文件。

文件内容很简单,只是打印“Hello, world!”。这主要是为了验证安装是否成功。

然后,我们可以输入 make build 来构建项目,因为我需要将这个命令整合到Makefile中。

我们运行 make build,它实际上会执行 cargo build

构建成功后,我们还可以运行 make run 来验证一切是否正常工作。

至此,基础安装已成功完成。

创建支持CUDA的项目

现在,让我们再创建一个项目。这次我们将添加CUDA支持。

我们输入 cargo new my_cuda_app 创建一个新项目。

然后进入 my_cuda_app 目录,并再次复制Makefile,为项目提供一个便捷的脚手架。

唯一的区别是,我们需要添加CUDA功能。这操作起来非常直接。

我们输入命令添加该功能。

现在,我已经成功添加了名为 cuda 的特性。

如果我们查看这个项目的源代码,并检查 Cargo.toml 文件,会看到 candle-core 依赖项后面带有 features = [“cuda”] 的标记。

为了快速验证,我可以直接运行 cargo build,甚至可以直接运行 cargo run 来一次性完成构建和运行。这将实际验证CUDA是否正常工作。

至此,所有设置均已完成。

总结

本节课中,我们一起学习了Candle框架的入门实践。我们首先验证了开发环境,然后创建了一个基础的Rust项目并集成了Candle框架。接着,我们构建并运行了项目以验证安装。最后,我们创建了另一个项目,并通过在 Cargo.toml 中添加 features = [“cuda”] 为其启用了GPU加速支持。整个过程展示了使用Candle进行本地LLM开发的基本设置流程。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P166:探索StarCoder-Rust实现 🚀

在本节课中,我们将要学习如何探索和运行一个名为StarCoder的开源代码生成模型,并了解如何利用Rust语言和Hugging Face生态系统在本地环境中高效地使用它。

概述

StarCoder是一个开源的大型语言模型,专门用于代码生成。它拥有155亿参数,并在涵盖80种编程语言的“The Stack”数据集上进行训练。与Copilot等模型类似,但StarCoder是完全开源的,旨在促进生成式AI的民主化,而非仅由风险投资家掌控。

StarCoder模型简介

上一节我们介绍了StarCoder的基本定位,本节中我们来看看它的具体特点。

StarCoder是一个专注于代码生成的专用LLM。它由Hugging Face社区通过开放科学协作开发,旨在向研究人员和开发者发布数据、模型和实验成果。其核心优势在于开源和可访问性。

以下是该模型的一些关键参数:

  • 参数量155亿
  • 训练数据:基于包含80种编程语言的“The Stack”数据集。
  • 性质:完全开源。

环境准备与身份验证

了解了模型的基本信息后,我们需要准备运行环境。我们将使用一个基于Rust的极简机器学习推理项目——Hugging Face Candle来运行StarCoder。

首先,需要安装必要的工具并进行身份验证。

以下是设置步骤:

  1. 安装Hugging Face Hub工具包:pip install huggingface-hub
  2. 在终端中登录Hugging Face账户:执行 huggingface-cli login 命令。
  3. 验证登录状态:运行 huggingface-cli whoami,若显示用户名则表示认证成功。

为了获得最佳性能,本教程将在一个配备了AWS G5新一代GPU的远程Visual Studio Code环境中进行操作。在该环境中,我们可以使用 nvidia-smi -l 1 命令循环监控GPU的使用情况。

运行StarCoder模型进行代码生成

环境准备就绪后,现在我们来实际运行StarCoder模型并生成代码。

我们将通过一个Rust项目来执行模型。关键命令是 cargo run,但需要启用CUDA特性以利用GPU加速,从而获得优化性能。命令结构如下:

cargo run --features cuda --example bigcode --prompt “编写一个[Rust/Python/Ruby]函数,实现两个数字相加”

执行此命令的过程是:首先检索并加载模型(这大约需要2秒,是主要的耗时环节),然后启动推理循环。在推理过程中,可以观察到GPU使用率显著上升。

模型能够根据不同的编程语言提示,生成相应的代码建议。例如:

  • 对于“Rust函数”,它会生成Rust代码。
  • 对于“Python函数”,它会生成Python代码。
  • 对于“Ruby函数”,它会生成Ruby代码。

生成速度很快,文件检索在微秒级完成,推理本身也非常迅速。这展示了利用Rust和Hugging Face生态系统构建开源编码助手的巨大潜力。

总结

本节课中我们一起学习了如何探索和运行开源的StarCoder代码生成模型。我们了解了它的开源特性和技术参数,完成了Hugging Face环境设置与身份验证,并最终在支持CUDA的GPU环境中,使用Rust项目成功调用了模型,生成了不同编程语言的代码片段。这个过程证明了基于开源工具和模型构建个人编码辅助工具的可行性与高效性。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P167:使用Whisper-Candle进行语音转录 🎤

在本节课中,我们将要学习如何使用Whisper模型和Candle框架进行自动语音识别。我们将从基本概念开始,逐步深入到如何在实际环境中配置和运行一个语音转录任务。

自动语音识别领域的一个新兴方向是使用预训练模型。Whisper是一个无需微调即可使用的优秀示例。你可以查看其不同规模的参数配置,例如中等模型可能包含7.69亿个参数,而大型模型参数更多。使用此类工具时,关键问题是如何运行它。

环境与框架介绍 🛠️

上一节我们介绍了Whisper模型,本节中我们来看看运行它的框架。幸运的是,Hugging Face的Candle框架提供了一个极简且高性能的解决方案,它包含GPU支持。框架中甚至提供了使用Whisper的示例代码。

为了理解其工作原理,让我们深入查看一下源代码。查看main.rs文件,会发现它使用了clap命令行工具解析器。我们可以查看其中定义的常量参数和可传入的参数。通过研究代码,我们可以开始探索这个新兴工具。

配置运行环境 💻

了解了框架后,我们需要一个合适的运行环境。建议使用配备G5实例类型的EC2实例,这些实例搭载了较新的NVIDIA GPU。例如,一个拥有64个核心和高速GPU的强大实例。接下来,我们将通过Visual Studio Code Remote进入这个环境进行操作。

以下是检查环境是否就绪的步骤:

  • 在终端中运行 nvidia-smi 命令,可以查看GPU状态,确认环境准备完成。

运行示例与性能优化 ⚡

环境就绪后,我们首先通过一个示例来测试Candle与Whisper的接口。框架中提供了一个示例,我们可以使用以下命令运行:

cargo run --example whisper

首次运行可能会提示在CPU上运行,速度仍然很快,并且会下载一个示例音频文件。这没有问题。

但我们可以做得更好,通过启用GPU特性来加速计算。以下是优化步骤:

  1. 启用CUDA支持:在命令中添加 --features cuda 参数,允许程序使用GPU进行计算。编译时可以看到GPU利用率(例如达到48%),这显著提升了性能。
  2. 启用cuDNN优化:进一步添加 --features cudnn 参数。cuDNN是针对神经网络操作的CUDA加速库,能进行更深度的优化,使推理速度更快、效率更高。

处理自定义音频文件 🎵

运行基础示例后,我们来看看如何处理自定义格式和文件。假设在上一级目录中有一些音频文件(如WAV格式),我们可以通过传递自定义参数来运行转录任务。

以下是一个完整的命令示例,它结合了性能优化和自定义输入:

cargo run --profile release --features cuda,cudnn --example whisper -- --input ../four_score.wav --model medium --language en --task transcribe

这个命令会:

  • 以发布模式编译,优化性能。
  • 启用CUDA和cuDNN特性以利用GPU。
  • 指定输入音频文件路径(../four_score.wav)。
  • 指定使用中等规模的英文模型(medium)。
  • 指定任务为转录(transcribe)。

首次编译和运行可能需要一些时间。如果在CPU上运行感觉较慢,我们可以在强大的GPU机器上启用所有优化特性(包括移除调试信息)再次运行。此时观察GPU利用率,可能会达到70%左右,实现非常快速的推理。

实际应用场景 🌐

这种高效能的转录流程非常适合实际生产场景。例如,你可以使用AWS Batch服务启动一个计算集群,然后利用此方法转录海量音频数据,为其他数据处理系统提供输入。

本节课中我们一起学习了如何利用Whisper模型和Candle框架构建高效的自动语音识别流程。我们从环境配置开始,经历了运行示例、启用GPU加速、优化性能,最终实现了对自定义音频文件的转录。这套方法为处理大规模语音数据提供了强大的本地化解决方案。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P168:67_04_07:探索AWS远程开发环境 🚀

在本节课中,我们将学习如何利用AWS构建一个基于Rust和Hugging Face Candle库的异步开发与生产工作流。我们将重点探讨如何通过远程开发环境高效、低成本地进行大型语言模型的开发与部署。

开发环境配置 💻

上一节我们介绍了课程背景,本节中我们来看看如何配置一个强大的云端开发环境。

首先,你可以使用一个EC2 G5实例。这个实例的优势在于它具备执行现代GPU推理任务的能力。此外,你还可以使用Spot实例来节省成本。在开发阶段,你可以随时停止和启动这个实例。

你可以通过Visual Studio Code Remote连接到这个实例,这是一种非常高效的开发方式。你只需要安装相应的插件,你的笔记本电脑就可以访问这个强大的云端环境。这意味着你可以将代码开发工作转移到基于云的强大环境中,并按使用量付费,而无需购买昂贵的硬件,例如一台价值4万美元的GPU。

生产环境部署与数据管理 ⚙️

了解了开发环境后,我们来看看如何将其与生产环境优雅地结合。

以下是实现开发与生产协同的关键点:

  • 共享存储:你可以使用EFS进行协同开发。EFS的挂载点可以连接到你的开发机器,同时,这个相同的挂载点也可以用于生产环境。
  • 模型与权重管理:你可以将庞大的模型和权重文件(数据量可能达到数十GB)下载到EFS中。这个位置可以作为将数据准备并推送到生产环境的暂存区。
  • 高效部署:当你向AWS Batch部署任务时,它可以自动配置EC2 G5实例。这样,你就可以以一种非常高效、优雅且低成本的方式,在这些强大的GPU上执行基于Rust的现代推理任务。你不需要依赖Notebook,也不需要Python,可以纯粹使用Rust来完成。

架构扩展与成本优化 💡

现在,让我们思考一下这个架构的更多可能性。

另一个需要考虑的方面是,如果你将代码编译成同时兼容CPU的目标。那么你的AWS Lambda函数可以直接从EFS读取这个二进制文件,并同样将其作为生产实例提供服务。因此,我认为对于LLM Ops和MLOps而言,这是一个非常令人兴奋的、新兴的Rust技术栈故事。

这真正意味着你可以尝试新事物、新想法,并不断追求效率。对于许多希望部署LLM服务的公司来说,这种特定的架构是一个很好的起点。

总结 📝

本节课中我们一起学习了如何利用AWS EC2 G5实例和EFS构建一个远程开发工作流。我们探讨了如何通过VS Code Remote进行高效开发,如何利用EFS在开发与生产环境间共享数据和模型,以及如何通过AWS Batch和Lambda实现低成本、高效率的Rust推理服务部署。这套架构为追求效率与创新的LLM运维提供了强大的实践基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P169:68_04_01:LLM开发中的Rust应用

在本节课中,我们将要学习Rust编程语言在大型语言模型开发中的应用。我们将探讨Rust如何通过其独特的内存安全特性、模块化设计以及强大的工具链,为构建高性能、可靠的LLM组件提供支持。

Rust组件在LLM中的优势 🛡️

Rust组件非常适合用于大型语言模型。让我们逐步讨论这些特定的组件。

编译器与内存安全 🔒

在Rust编译器中,借用检查器可以防止数据竞争和不安全的内存访问错误。其所有权系统能够在对象离开作用域时自动释放内存,因此无需手动管理内存。编译时检查会在代码部署前发现错误,确保您在模块化组件方面拥有一个非常健壮的大型语言模型部署。

模块化组件设计 🧩

接下来,我们来看看LLM中的核心处理组件。以下是这些组件的功能:

  • 分词器:将文本转换为用于词嵌入的数值ID。
  • 嵌入层:将单词映射到高维密集向量。
  • 变换层:使用神经网络模型处理文本。

这种模块化设计允许Rust的特性来混合和匹配特定的组件。

并发与并行处理 ⚡

上一节我们介绍了核心处理组件,本节中我们来看看Rust如何利用现代多核CPU进行高效计算。轻量级的Rust线程允许并发和并行执行。通道可以安全地在线程之间传递数据,而没有数据竞争的风险。这使得能够利用多核CPU来实现性能和可扩展性。

Cargo包管理器 📦

在性能之外,项目的依赖管理和代码共享同样重要。Cargo是Rust内置的包管理器,它将管理应用程序的依赖关系。庞大的包生态系统允许您扩展功能,例如命令行工具或Web框架。您还可以轻松地在项目和团队之间共享代码,并且它强制执行语义化版本控制以确保稳定性。因此,这是调用大型语言模型的一种非常简便的方法,我们在Rust Candle中可以看到这一点。

您只需要运行以下命令:

cargo run --example

总结 📝

本节课中我们一起学习了Rust在大型语言模型开发中的关键应用。我们探讨了Rust编译器如何通过借用检查器和所有权系统确保内存安全与代码健壮性,了解了分词器、嵌入层和变换层等模块化组件的协作方式,认识了Rust轻量级线程和通道如何实现安全高效的并发处理,最后介绍了Cargo包管理器在依赖管理、生态扩展和团队协作中的重要作用。这些特性共同使Rust成为构建高性能、可靠LLM系统的有力工具。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P170:69_04_02_无服务器推理 🚀

在本节课中,我们将要学习如何为大型语言模型构建基于Rust的无服务器推理架构。我们将探讨其核心优势、工作原理以及如何实现成本效益和高可扩展性。

基于Rust的大型语言模型无服务器推理是一个令人兴奋的新兴领域,它展现出许多值得关注的新特性。

观察上图所示的架构图,我们可以发现,部署机器学习模型以实现可扩展性和成本效益,并利用无服务器架构进行推理是可行的。

架构概述与工作流程

上一节我们介绍了无服务器推理的基本概念,本节中我们来看看其具体的工作流程。

用户输入可以包含文本、图像或其他类型的数据,这些数据将被传递到例如AWS Lambda这样的无服务器函数中。

该函数内部将包含模型本身,以及用于运行量化模型的Rust Candle运行时。

模型量化:缩小尺寸与提升速度

接下来,我们来深入了解模型量化的概念。模型本身将被量化,这意味着它将使用降低精度的整数数据类型,而不是32位浮点数。

量化操作可以用以下公式表示:
量化值 = 四舍五入(浮点值 / 缩放因子) + 零点偏移

这可以使模型大小缩小多达四倍。同时,Candle运行时提供了类似Llama.cpp的优化操作,能够高效地运行量化模型。

无服务器函数的优势

了解了模型的处理方式后,我们来看看无服务器函数带来的核心优势。

无服务器函数能够自动扩展以处理任意数量的请求流量,确保快速的响应时间。

函数也可以缩容至零。因此,您只需为实际使用的资源付费。模型体积小且没有闲置资源,这使得该方案极具成本效益。

无服务器计费基于调用次数,而非持续运行的高昂GPU。量化后的整数模型运行速度更快,甚至在低端和移动CPU上也能良好运行,这真正开启了新的应用场景。

对于许多模型而言,不再需要那些昂贵的GPU。输出结果也能非常快速地返回给用户,自动扩缩容机制将延迟降至最低。

总结

本节课中我们一起学习了基于Rust和量化技术的大型语言模型无服务器推理架构。该架构使您能够高效、经济且大规模地将先进的机器学习模型部署到生产环境中,通过自动扩缩容、按需付费和优化的量化运行时,实现了高性能与低成本的结合。

大型语言模型实践:P171:使用Rust CLI实现推理

概述

在本节课中,我们将学习如何使用Rust编程语言构建一个命令行界面(CLI)工具,该工具能够加载Hugging Face上的预训练Transformer模型,并对用户输入的文本执行推理任务。我们将了解从模型下载到最终结果输出的完整流程。

构建与运行Rust CLI推理工具的流程

上一节我们概述了本课程的目标,本节中我们来看看构建一个Rust CLI推理工具的具体步骤。下图展示了从开始到结束的完整工作流。

以下是构建流程的详细步骤:

  1. 从Hugging Face Hub下载模型
    流程始于从Hugging Face Hub下载预训练的Transformer模型。你可以选择使用像BERT或GPT-2这样的模型。

  2. 在Rust中加载模型
    下载模型后,需要在Rust代码中加载它。这可以通过rust-berttransformers crate实现,它们为Hugging Face模型提供了Rust绑定。另一个选择是使用rust-candle接口。这一步使得模型能够在Rust代码中用于推理。

  3. 构建命令行界面(CLI)
    接下来是构建CLI。你可以使用clap crate来轻松解析命令行参数。这允许用户向CLI提供灵活的输入,你甚至可以定制提示词。例如,如果你想为每个提示词添加一个固定的前言以获得更好的结果,你可以将此逻辑加入代码中。

  4. 实现推理逻辑
    CLI构建完成后,需要实现推理逻辑。这部分代码负责接收用户输入,将其传递给之前加载的Hugging Face模型,并返回推理结果。rust-bert crate将通过处理数据转换和推理过程来简化这一步骤。

  5. 运行CLI执行推理
    最后,用户运行CLI并提供文本输入。该输入通过CLI传递给Hugging Face模型,推理过程在Rust中执行,最终结果将打印输出给用户。

总结

本节课中我们一起学习了使用Rust实现LLM推理的完整流程。简而言之,这个过程包括:从Hugging Face下载模型;使用模型相关的crate在Rust中加载模型;使用clap构建CLI;实现推理逻辑并将其与模型集成;最后运行CLI对用户输入执行推理。在许多方面,利用Rust及其丰富的crate生态系统是执行大型语言模型推理最高效的方式之一。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P172:71_04_04_Rust聊天推理系统

在本节课中,我们将学习如何使用Rust生态系统中一些即插即用的组件,来构建一个用于大型语言模型推理的Rust聊天机器人。

🦅 选择并加载模型

首先,我们可以考虑使用Falcon模型,这是一个很好的入门选择。该模型擅长处理自然语言对话。

我们可以使用像candle这样的Rust库将模型加载到Rust程序中。candle是一个Rust机器学习框架,可以访问Hugging Face上的模型。

以下是加载模型的核心代码概念:

// 伪代码示例:使用candle加载Hugging Face模型
let model = candle::hf::load_model("tiiuae/falcon-7b")?;

💬 构建聊天机器人界面

上一节我们介绍了如何加载模型,本节中我们来看看如何构建用户界面。我们可以使用cursive这样的库来构建一个基于终端的聊天机器人界面。这个界面可以接收用户输入并打印机器人的回复。

以下是构建界面的核心步骤:

  1. 初始化cursive终端界面。
  2. 创建输入框和输出显示区域。
  3. 设置事件循环以处理用户输入。

🔁 实现核心聊天逻辑

在构建好界面之后,我们需要实现核心的聊天逻辑循环。这个循环会持续提示用户输入,接收他们的输入文本,将其传递给之前加载的Hugging Face模型,然后打印模型的回复。

以下是实现聊天逻辑的关键点:

  1. 处理输入:从界面获取用户输入的文本。
  2. 调用模型:将文本传递给加载的模型进行推理。
  3. 生成回复:模型会处理所有自然语言处理任务,包括分析用户输入、生成连贯的回复,甚至考虑对话的上下文。
  4. 输出结果:将模型生成的回复显示在界面上。

Rust代码在这里的作用是促进这种交互。我们还可以添加额外的逻辑,例如情感分析,以使回复显得更自然。

🚀 扩展与展望

在完成这个原型之后,界面甚至可以适配成一个Web应用程序。

总而言之,我们想要做的事情可以概括为以下几个步骤:

  1. 从Hugging Face选择合适的模型(例如最新的Falcon模型)。
  2. 将其加载到Rust环境中。
  3. 构建聊天机器人用户界面。
  4. 结合Hugging Face模型实现聊天逻辑。
  5. 实现持续提示和生成回复的循环。

现在对开发者来说是一个激动人心的时代,因为我们可以将所有工具直接集成到像Rust这样对命令行友好的语言中。Rust的独特之处在于它在构建二进制程序方面拥有强大的能力。

📝 总结

本节课中我们一起学习了构建一个Rust聊天推理系统的完整流程。我们从选择并加载Hugging Face上的Falcon模型开始,然后使用cursive库构建了终端用户界面,最后实现了连接模型与界面的核心聊天逻辑循环。这个过程展示了如何利用Rust生态的高性能组件快速搭建一个可工作的LLM应用原型。

大型语言模型实践:P173:使用StarCoder构建自定义聊天循环

概述

在本节课中,我们将学习如何利用Hugging Face的StarCoder大型语言模型,结合Rust编程语言和Tokio异步运行时,构建一个属于你自己的、功能强大的代码助手聊天循环。整个过程无需支付任何费用,完全基于开源工具。

构建自定义代码助手聊天循环

使用大型语言模型构建聊天循环,最令人兴奋的应用之一就是创建你自己的代码助手。Hugging Face的StarCoder模型在此类任务中表现卓越,其性能甚至超越了OpenAI早期的模型或其他竞争解决方案。

下面,让我们通过一个具体示例,深入探讨如何构建一个自定义的对话式AI。

核心组件与工作流程

观察这个提示示例,我们的目标是让模型生成经过深思熟虑的响应。以下是实现这一目标的关键步骤和组件。

上一节我们介绍了构建代码助手的整体概念,本节中我们来看看实现它的具体技术栈和流程。

以下是构建聊天循环的核心步骤:

  1. 模型调用:向StarCoder模型发送请求。该模型可以部署在GPU实例上,例如AWS的G5实例。
  2. 异步请求:利用async请求实现非阻塞的异步通信。这使得聊天机器人能够轻松、快速地响应用户输入。
  3. 对话历史管理:将每一组用户消息和AI回复追加到对话历史记录中。这为AI提供了持续的上下文,使其能进行连贯的对话。
  4. 数据序列化:使用JSON格式进行简便的数据序列化与反序列化,便于在客户端和服务器之间传递消息。
  5. Rust语言优势:借助Rust强大的类型系统和内存安全性,我们可以确保构建出的聊天机器人既健壮又安全。
  6. 模型集成:利用Hugging Face的Candle推理引擎,轻松集成StarCoder大型语言模型。
  7. 聊天循环实现:基于Tokio异步运行时构建自定义的聊天循环。你可以看到,我们定义了一个pub async fn函数来实现聊天循环,它能够遍历并响应用户输入的消息。

代码结构示例

以下是一个简化的代码结构示意,展示了异步聊天循环的核心部分:

pub async fn chat_loop(mut conversation_history: Vec<Message>) -> Result<(), Error> {
    let model = load_starcoder_model()?; // 加载StarCoder模型
    let inference_engine = CandleInferenceEngine::new(model);

    loop {
        // 1. 接收用户输入
        let user_input = receive_user_input().await?;

        // 2. 将用户消息加入历史
        conversation_history.push(Message::User(user_input));

        // 3. 准备包含历史的提示
        let prompt = format_conversation_history(&conversation_history);

        // 4. 异步调用模型生成回复
        let ai_response = inference_engine.generate_async(prompt).await?;

        // 5. 将AI回复加入历史
        conversation_history.push(Message::Assistant(ai_response.clone()));

        // 6. 将回复返回给用户
        send_response_to_user(ai_response).await?;
    }
}

总结

本节课中,我们一起学习了如何整合多个强大的开源工具来构建自定义的代码助手聊天循环。我们从StarCoder模型出发,通过Hugging Face的推理引擎进行集成,并利用Rust和Tokio构建了高效、安全的异步聊天循环。最终,你无需依赖任何付费服务,就能拥有一个功能完整的编程辅助工具。这套方案清晰、直接,为开发者提供了强大的自主控制能力。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P174:73_04_06_AWS GPU上调用Rust Candle框架(上)🚀

在本节课中,我们将学习一个有趣的场景:如何使用Rust的包管理系统来调用大型语言模型。许多人都在讨论大型语言模型及其强大功能。你会看到人们构建复杂的应用和工作流,运行大型语言模型通常伴随着许多复杂性。然而,得益于Rust语言和Cargo包管理系统的优势,你无需进行复杂操作,可以直接使用Cargo系统来调用模型。我们将结合Hugging Face的Candle框架,并在AWS的GPU实例上完成这一操作。这是一个非常强大的GPU环境,让我们开始探索具体步骤。

概述:Rust Candle框架与AWS GPU的优势

上一节我们提到了使用Rust和Cargo调用LLM的便捷性。本节中,我们来看看如何具体实施。首先,让我们了解一下Hugging Face Candle。这是一个为Rust设计的极简机器学习框架。它的代码非常简单。最令人兴奋的一点,也是LLM Ops领域最激动人心的特性之一,就是你可以通过运行一行命令来运行所有这些大型语言模型。我不明白为什么没有更多人使用它,这确实非常令人兴奋。接下来,我们将学习如何自己运行它,这样你就不必付费让他人运行大型语言模型,也无需注册某些API服务。一切已准备就绪,你可以直接开始。

第一步:在AWS控制台配置GPU实例

那么,我们具体该如何操作呢?第一步,让我们查看AWS控制台。根据我的建议,你需要进入“实例”页面,然后选择“启动实例”。

此时,你需要选择一个基础AMI。例如,“Deep Learning Base AMI”是一个很好的起点,因为它没有预装你不需要的额外软件。很多时候,人们会查看“Deep Learning AMI”,但它预装了许多你不需要的“垃圾”软件。例如,如果我们使用Rust,就不需要像Hugging Face Hub这样的Python包管理工具。我只需要CUDA驱动程序和cuDNN(一个为神经网络优化的CUDA库)被安装。

因此,我真正需要做的就是选择“Ubuntu Deep Learning Base AMI”。选择之后,实例类型就变得至关重要。

以下是选择实例类型的关键步骤:

  • 在这个场景中,你需要选择基于NVIDIA的选项。
  • 我们可以查看“NVIDIA”或“加速计算”家族。
  • 例如,g5系列是我推荐的家族类型,它们已经预配置了NVIDIA环境。

现在我们已经了解了选择标准。我转到EC2控制台,可以看到一台正在运行的机器。这台机器已经包含了我们所需的一切。让我快速展示如何连接它。我进入“实例”页面,看到一台名为“LLM Ops”的机器正在运行。它是一台g5.16xlarge实例。我只需要点击“连接”,然后选择“使用EC2 Instance Connect连接”。这样,我甚至无需设置SSH密钥或任何其他配置,就可以直接访问它。

第二步:在实例上安装必要软件

连接成功后,你唯一需要做的另一件事就是安装Rust。实际上,这只需要一个命令:rustup

我已经安装了Rust,我们可以用 rustc --version 命令来验证。另一件需要做的事是克隆Hugging Face的Candle代码仓库。你需要进入代码页面,选择本地克隆,并通过HTTPS进行克隆。

总结

本节课中,我们一起学习了在AWS GPU实例上配置环境以运行Rust Candle框架的基础步骤。我们了解了选择合适的基础AMI和GPU实例类型的重要性,并演示了如何轻松连接到EC2实例以及安装Rust开发环境。这为下一节课实际使用Cargo调用大型语言模型打下了坚实基础。

大型语言模型实践(高级数据工程、AWS、Databricks和本地LLM):P175:74_04_07_AWS GPU上调用Rust Candle框架(下)

在本节课中,我们将学习如何在AWS GPU实例上,通过构建和运行Rust Candle框架的示例项目,来调用一个开源的大型语言模型。我们将以BigCode模型为例,演示从克隆代码到实际运行模型的完整流程。

上一节我们介绍了Rust Candle框架的基本概念和环境准备,本节中我们来看看如何具体构建和运行一个模型。

获取与更新项目代码

首先,你需要访问项目仓库并复制其地址。完成克隆操作后,即可获得项目代码。

我已经完成了克隆操作。此时,我可以执行 git pull 命令来获取项目的最新更新,因为该项目正在被积极开发。

更新完成后,就可以准备运行了。

运行模型的方法

现在,我们来看看如何实际运行这些大型语言模型。你可以查看项目中的说明文档来获取指引。

运行模型主要有两种方式。一种是直接运行,但另一种更好的方式是先构建项目,生成可执行文件,然后在目标目录中操作模型。

以BigCode模型为例

例如,BigCode本质上是GitHub Copilot的一个开源竞争对手。如果我们想运行它,具体该如何操作?

我们需要按照指引执行命令,但需要对其进行一些调整。

我们想执行 cargo build 命令,因为我们实际上需要构建一个可供我们操作的可执行二进制文件。

我们还需要添加 --features 参数,指定为 cuda

这个操作的作用是,让构建过程针对经过优化的CUDA神经网络驱动进行编译。

我们可以通过查看项目的 Cargo.toml 文件来验证这一点,其中定义了可用的特性。

使用这些特性将为我们构建项目。

构建与运行模型

我认为目前使用这种方法的人还不够多。因为大多数人都在注册每月20美元的昂贵服务。

但实际上,你可以直接启动自己的实例,并运行一个在多数情况下性能更优的大型语言模型。

构建完成后,进入目标目录。你会看到生成的可执行文件名为 bigcode

只需输入 ./bigcode 即可运行。这样,你就拥有了一个完整的大型语言模型编程助手。

现在,我可以输入 ./bigcode 并给出提示,例如:“构建一个将两个数字相加的Python函数”。

这非常不可思议,我无法相信没有更多人讨论这个。这再次展示了Rust的强大能力,让你能够轻松实现这类功能。

我们可以看到它的运行速度非常快。如果我想运行得更快,或者将其封装到bash脚本中,我完全可以做到,因为我拥有了自己的结对编程助手。我们还可以对它进行各种调整。

😊

总结

本节课中我们一起学习了在AWS GPU实例上使用Rust Candle框架的完整流程。我们从克隆和更新项目代码开始,探讨了构建与运行模型的两种方式,并以BigCode模型为例,详细演示了如何通过 cargo build --features cuda 命令构建项目,并运行生成的可执行文件来调用开源大模型。这种方法为我们提供了高性能、可定制的本地大模型部署方案。

开源大语言模型方案:P1:01_01_02:认识你的讲师阿尔弗雷多·德萨

概述

在本节课中,我们将认识本课程的讲师阿尔弗雷多·德萨,并了解本课程将要涵盖的核心内容与目标。

讲师介绍

大家好,我是阿尔弗雷多·德萨。

在本课程中,我们将深入探讨开源大语言模型的诸多方面。

课程内容概览

我们将学习如何与开源模型进行交互,以及如何寻找并使用它们。

以下是本课程将涉及的主要开源模型类型:

  • 我们将探索你可能希望与之交互的各种开源模型。
  • 我们将学习如何寻找这些模型。

我们将贯穿一些特定的场景或技术方案。

以下是本课程将实践的具体技术场景:

  • 在浏览器中使用JavaScript运行模型,我认为这非常不可思议。
  • 使用Python库与模型交互,这也是非常普遍的方式。
  • 使用Rust语言与模型交互。

我们将探讨Python和Rust之间的一些差异,以及你为何会选择其中一种而非另一种。

但课程的核心将集中在如何让这些技术变得易于理解和实现。

我们将力求使内容通俗易懂、简单明了。

在某些情况下,我们将使用开箱即用、可直接在本地运行的模型。

我们将构建有趣的项目,你将能够通过动手实践应用许多这些概念。

课程将包含大量实验和非常实用的示例,你可以亲自尝试我们在整个课程中将要实践的所有概念。

讲师背景

我拥有多年教授机器学习和Python的经验。

我曾是一名软件工程师和系统管理员。

我认为,我在演示这些示例、管理代码仓库以及所有课程内容时采用的方法,将使你能够在整个学习过程中,通过非常实用和直接的例子,获得一些相关的经验。

总结

本节课中,我们一起认识了讲师阿尔弗雷多·德萨,并了解了本课程的目标是帮助你深入理解如何与开源大语言模型协作,并最终能够将所学知识应用到你自己的项目和想法中。

开源大语言模型实践:1:引言

在本节课中,我们将学习如何寻找和获取开源的大型语言模型。我们将介绍主要的模型来源平台,并探索用于与这些模型交互的工具。

概述

开源大型语言模型可以从多个不同的来源和平台获取。除了了解模型存放的位置,我们还需要掌握与它们交互的工具。本节将重点介绍一些主要的平台和工具,特别是Hugging Face平台,并简要了解云平台上的模型资源以及小型语言模型的独特价值。

模型来源与平台

上一节我们概述了课程内容,本节中我们来看看具体的模型来源平台。我们可以从多个地方找到开源的大型语言模型。

以下是主要的模型来源类型:

  • 专门的开源模型平台:例如Hugging Face,它汇集了大量模型、数据集和演示空间。
  • 云服务平台:例如微软Azure AI模型目录,它提供了可部署在云端的模型集合。
  • 特定机构发布的模型:例如微软发布的Phi-2等小型语言模型。

Hugging Face平台介绍

接下来,我们将深入了解Hugging Face平台。这是一个非常流行的平台,我个人很喜欢它。

我们将看到Hugging Face平台是什么,以及如何在该平台上找到我们需要的模型。

云平台模型资源

除了专门的开源社区,云平台也提供了丰富的模型资源。现在,我们来看看如何在像Azure这样的云平台上寻找模型。

在Azure上,你可以像在Hugging Face上一样,通过模型类型、许可证等条件进行筛选,从而找到对你有用的模型。

小型语言模型示例:Phi-2

在探索了主流平台后,我们也将快速浏览一下小型语言模型,例如Phi-2。这个模型来自微软,它构建得非常小,但同时能力也很强。

我们将探讨为什么这类模型很有趣。其吸引力无疑在于小巧的尺寸强大的能力之间的平衡。

总结

本节课中,我们一起学习了开源大型语言模型的主要来源。我们介绍了Hugging Face和Azure等平台,并了解了像Phi-2这样的小型语言模型的特点。在接下来的课程中,我们将更深入地研究所有这些内容。

开源大语言模型方案:P3:03_01_03_Hugging Face平台上的开源模型

在本节课中,我们将要学习Hugging Face平台,这是一个专门托管和分享开源模型的重要场所。我们将了解平台的基本结构、核心功能以及如何利用它来探索和使用各种模型。

当我们谈论开源模型时,无疑会提到Hugging Face这家公司。

Hugging Face是一家专注于……的公司,但更准确地说,Hugging Face就像一个代码仓库,一个我们可以托管和分享模型的地方。许多公司,包括众多云服务提供商,都允许将他们的模型托管在这个平台上。

因此,Hugging Face不仅是一家公司,也是一个平台,许多开源模型都托管在这里。

那么这具体意味着什么呢?在平台的最顶部,你会看到许多不同的选项:我们有“模型”、“数据集”、“空间”。这些是什么呢?让我们快速进入“模型”部分看看。

点击“模型”后,你会看到即使是像微软这样的公司,实际上也将模型放在这里。需要注意的一点是,其中一些模型非常具体。例如,微软的Phi-2是一个专门用于文本生成的模型。这意味着它的主要任务、主要目的就是文本生成,其功能类似于我们之前看到的提供聊天服务的系统,如ChatGPT和其他服务提供商。这并非唯一的例子,你可以看到Mistral AI也有Mistral模型,同样用于文本生成。

那么Hugging Face在这里扮演什么角色?它与所有这些模型是什么关系?实际上,它是一个托管和存放这些模型的流行且优秀的服务平台。

例如,如果我们点击进入Phi-2模型,你会获得一些关于这个模型是什么以及它如何工作的信息。你会看到一些描述,比如如何使用它,以及一些关于如何实现它的说明。这非常棒,但我们还可以看到更多不同的东西。

我们可以查看如何使用它的代码示例,这里展示了一些Python代码。我们还可以浏览构成该模型的实际文件,例如一些配置文件以及分词器所需的一些文件(我们尚未深入探讨分词器)。所有这些文件共同构成了这个模型的功能。

你可以看到这里显示模型大小为564兆字节,这看起来是一个大文件。你实际上可以继续下载这些文件,或者甚至……

……立即试用它们。例如,如果我已登录,我将能够尝试那个文本生成功能。不过,该模型的API试用功能已被关闭,我们暂时不会尝试。所以我要完全返回到模型列表。

你可以看到还有其他功能的模型,所有这些模型都关联着不同类型的任务:计算机视觉、自然语言处理、音频处理等等,有各种各样不同的东西。

并非所有模型都完全是开源的。有些模型可能是闭源的。例如,我们来看看Mistral AI的模型,并尝试弄清楚它的许可证。你可以看到这里的许可证是Apache 2.0,这是一个非常宽松的许可证。但是,这些许可证会变化,并非所有模型都具有相同的许可证。

其中一些许可证允许你做更多事情,另一些则限制更多,或者约束更严格,例如仅允许用于研究。

因此,每当你听到Hugging Face,每当你听到开源模型时,请确保你理解Hugging Face只是一个你可以分享、上传、托管模型的地方,包括大多数开源模型。许多公司和许多人也在这里托管他们的模型。

本节课中我们一起学习了Hugging Face平台的核心概念。我们了解到它是一个集中托管和分享模型的中心,涵盖了从文本生成到计算机视觉等多种任务。重要的是,我们认识到模型的开源程度和许可协议各不相同,在使用前需要仔细检查。掌握这个平台是探索和利用开源大语言模型世界的关键第一步。

大型语言模型实践:P4:Hugging Face Hub 简介 🏠

在本节课中,我们将快速概览 Hugging Face Hub。Hub 是 Hugging Face 平台的核心,你可以在这里与模型、数据集、应用空间等多种资源进行交互。

概述

Hugging Face Hub 是一个中心化的平台,用于托管和共享机器学习资源。它类似于代码托管平台 GitHub,但专门为机器学习领域设计。通过 Hub,你可以轻松地发现、使用和贡献模型、数据集以及交互式演示应用。

Hub 的核心组件

Hub 主要包含以下几种类型的资源,你可以根据需求与它们交互:

  • 模型:预训练或微调好的机器学习模型。
  • 数据集:用于训练和评估模型的数据。
  • 空间:用于托管和分享交互式演示应用。
  • 组织:团队协作的群组空间。

接下来,我们将逐一探索这些组件。

创建与使用模型

上一节我们介绍了 Hub 的核心组件,本节中我们来看看如何创建和使用一个模型仓库。

模型在 Hub 上以 Git 仓库的形式存在。要创建一个新模型,可以点击页面上的 “New” 按钮,然后选择 “Model”。这个过程与在 GitHub 上创建新仓库非常相似。

以下是创建模型时需要填写的信息:

  • 所有者:选择模型的所有者,可以是个人账户或所属的组织。
  • 模型名称:为你的模型起一个独特的名字。
  • 许可证:为模型选择合适的开源许可证,例如 MIT
  • 可见性:选择模型是公开还是私有。

创建完成后,该模型仓库就可以从任何地方被访问和使用。你可以通过 Hugging Face 提供的库(如 transformersdatasets)来加载它,也可以直接在网页上查看其详情和文件。

管理数据集

与模型类似,数据集也是 Hub 上的重要资源。其创建和管理界面与模型仓库基本一致。

数据集同样以 Git 仓库的形式托管。你可以通过网页界面或命令行工具来上传和管理数据文件。所有仓库都支持标准的 Git 操作,如克隆、提交和拉取请求。

需要注意的是,由于数据集文件通常较大,克隆到本地时需要用到 Git LFS。较新版本的 Git 命令行工具可能已包含 LFS,如果没有,你需要单独安装它。克隆命令非常简单:

git clone https://huggingface.co/datasets/username/dataset_name

探索应用空间

除了静态的模型和数据集,Hub 还提供了一个强大的功能——空间。空间允许你托管一个交互式的机器学习应用演示。

当你创建一个新空间时,可以选择不同的框架来构建前端界面:

  • Gradio:快速创建友好的机器学习演示界面。
  • Streamlit:用于构建数据科学应用的工具。
  • 静态HTML:托管纯静态网页。

空间功能使得分享和测试模型变得非常直观和互动,是展示项目成果的理想方式。

理解组织协作

最后,我们来了解一下组织功能。组织适用于团队或公司协作的场景。

如果你在一个团队中工作,可以创建一个组织,然后将成员添加进来。这样,团队内的机器学习工程师就可以在同一个组织下协作开发模型、数据集和空间。其概念与 GitHub 的组织功能完全相同。

例如,许多知名公司如 Google、Facebook 都在 Hub 上拥有自己的组织,并在其下发布官方项目。

总结

本节课中,我们一起学习了 Hugging Face Hub 的核心概念与基本操作。我们了解到 Hub 是一个集模型、数据集、应用空间和组织协作于一体的平台。所有资源都以 Git 仓库的形式管理,支持版本控制和协作开发。通过网页界面或命令行工具,你可以轻松地上传、发现和使用这些资源,这为机器学习项目的开发、分享和部署提供了极大的便利。

开源大语言模型方案:P5:开源模型的库与工具 🛠️

在本节课中,我们将要学习用于与开源大语言模型交互的核心库与工具。这些工具极大地简化了模型的加载和使用过程,使得开发者能够快速构建应用。

概述

当我们谈论开源模型时,必须讨论我们将要使用的工具。Hugging Face 团队开发了大量工具,我们将探索其中一些,了解它们如何帮助我们轻松地与各种模型进行交互。

Hugging Face Transformers 库

上一节我们介绍了开源模型的重要性,本节中我们来看看最核心的工具库——Hugging Face 的 Transformers。这是一个抽象层,允许我们以动态方式轻松地与众多开源模型进行交互。

以下是 Transformers 库的核心优势:

  • 动态加载模型:无需预先下载模型文件,库会从 Hugging Face 平台动态获取。
  • 统一 API:无论底层框架是 PyTorch 还是 TensorFlow,都提供相似的调用接口。
  • 多模态支持:不仅支持文本,还支持音频、图像等多种任务。

其魔力在于,只需几行 Python 代码,你就能调用一个强大的模型。例如,使用 pipeline API 进行情感分析:

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
result = classifier("I love using transformers!")
print(result)  # 输出: [{'label': 'POSITIVE', 'score': 0.9998}]

上面的代码动态加载了默认的情感分析模型并执行了推理。你也可以指定具体的模型:

generator = pipeline("text-generation", model="gpt2")
result = generator("Once upon a time", max_length=50)
print(result[0]['generated_text'])

这种方式“民主化”了对这些先进模型的访问,开发者无需关心复杂的模型部署细节。

Transformers 的 JavaScript 版本

了解了 Python 版本后,我们来看看 Transformers 的 JavaScript 版本(@huggingface/transformers.js)。它允许你在浏览器或 Node.js 环境中直接运行机器学习模型。

其 API 设计与 Python 版本高度相似,同样支持模型的动态加载。这意味着你可以在 Web 应用中直接集成 AI 功能,而无需依赖后端服务器。以下是一个在浏览器中进行情感分析的示例:

import { pipeline } from '@huggingface/transformers';

const classifier = await pipeline('sentiment-analysis');
const result = await classifier('I love programming!');
console.log(result); // 输出: [{label: 'POSITIVE', score: 0.999}]

Rust 生态中的工具

除了 Python 和 JavaScript,Rust 生态也提供了高性能的模型交互工具。

Candle
首先是由 Hugging Face 开发的 Candle。这是一个基于 Rust 的极简机器学习框架,专注于性能与易用性。

  • 特点:可以编译成单个可执行文件,便于部署。支持 GPU 加速,能无缝运行如 Whisper、Llama 2 等大型模型。
  • 优势:Rust 的内存安全性和高性能,使得 Candle 特别适合需要高效推理的生产环境。

Rust Bert
另一个工具是 Rust Bert,它是 Hugging Face Transformers 库的 Rust 移植版。

  • 特点:支持使用 PyTorch 或 ONNX Runtime 作为后端。与原始库一样,它支持动态加载模型,并提供了丰富的任务接口。
  • 支持的任务:包括文本分类、翻译、摘要、情感分析和文本生成等。

以下是 Rust Bert 进行文本生成的简化示例:

use rust_bert::pipelines::text_generation::{TextGenerationModel, TextGenerationConfig};

let model = TextGenerationModel::new(Default::default())?;
let input = "The future of AI is";
let output = model.generate(&[input], Some(TextGenerationConfig::default()));
println!("{:?}", output);

本地模型运行工具

如果你想在本地计算机上完全自主地运行大型语言模型,以下两个工具非常有用。

Llama.cpp
这是一个用 C/C++ 编写的项目,旨在无需强大 GPU 的情况下高效地运行 LLaMA 模型。

  • 特点:量化模型以减小尺寸、提升推理速度。提供了简单的命令行接口和类 OpenAI 的 API 服务器。
  • 使用场景:适合在资源受限的环境(如个人电脑、树莓派)中运行模型。

Ollama
Ollama 是一个用户友好的工具,用于在本地运行、管理和与大型语言模型交互。

  • 特点:支持丰富的模型库(如 Llama 2、Mistral、Phi-2),一键下载和运行。提供了命令行和 REST API 两种交互方式。
  • 优势:极大简化了本地模型的管理和部署流程,对初学者非常友好。

使用 Ollama 运行模型就像在命令行中输入一样简单:

ollama run llama2

然后你就可以直接在终端与模型对话了。

总结

本节课中我们一起学习了与开源大语言模型交互的主要库和工具。我们从 Hugging Face Transformers 库及其 JavaScript 版本 开始,看到了它们如何通过统一的 API 动态加载模型。接着,我们探索了 Rust 生态中的高性能工具 CandleRust Bert。最后,我们介绍了用于在本地轻松运行模型的 Llama.cppOllama。这些工具共同构成了一个强大的生态系统,让开发者能够更便捷地利用开源大语言模型的能力进行创新和开发。

开源大语言模型方案:P6:06_01_06:在Hugging Face中寻找大语言模型 🔍

在本节课中,我们将学习如何在Hugging Face Hub中搜索和筛选大语言模型。我们将重点关注文本生成模型,并了解如何根据许可证等关键条件进行过滤,以找到适合我们需求的模型。

搜索与筛选模型

上一节我们介绍了Hugging Face平台的基本情况,本节中我们来看看如何具体地搜索和筛选模型。

首先,我们需要导航到Hugging Face Hub的模型板块。我们的目标是找到专门用于文本生成的大语言模型。在模型库中,我们可以根据模型的能力(即“任务”)进行筛选。文本生成正是我们要找的任务类型。

按任务类型筛选

以下是按任务类型筛选模型的步骤:

  1. 在Hugging Face Hub中,进入“Models”(模型)部分。
  2. 在任务筛选器中,开始输入“text generation”(文本生成)。
  3. 平台会实时进行模糊匹配,显示出“Text Generation”选项。
  4. 点击该选项后,页面右侧的模型列表将只显示具备文本生成能力的模型。

通过以上步骤,我们就能找到所有可用于文本生成的大语言模型。

按许可证筛选

找到文本生成模型后,下一步是根据使用需求考虑许可证问题。许可证决定了你可以如何使用这些模型,例如是否可以用于商业用途或产生盈利。

对于希望自由使用模型,甚至用于商业项目的用户,选择宽松的开源许可证(如Apache或MIT)是至关重要的。这些许可证通常允许你几乎任何形式的使用、修改和分发。

以下是按许可证筛选的操作:

  1. 在筛选条件中找到“License”(许可证)选项。
  2. 选择你需要的许可证类型,例如“Apache 2.0”或“MIT”。
  3. 选择后,模型列表会立即更新,只显示符合该许可证的模型。

例如,选择“Apache 2.0”许可证后,列表会过滤出所有采用该协议的模型。这能帮助你快速找到可以自由使用的模型。

查看模型详情与文件

筛选出候选模型后,我们需要仔细查看其详情页。详情页提供了丰富的信息,帮助我们做出最终决定。

以“Mixtral”模型为例,其详情页显示它上个月有超过一百万次下载,并且基于它有许多有趣的实现和应用。更重要的是,我们需要关注模型文件。

在“Files and versions”(文件和版本)选项卡中,可以查看模型的具体文件构成和大小。例如,某个模型文件可能显示为 12.1 GB,这是一个相当大的体积。了解文件大小对于评估存储和部署成本非常重要。

比较不同模型

我们可以通过更换筛选条件来比较不同模型。例如,将许可证从“Apache”换成“MIT”,可能会发现像微软的“Phi-2”这样的模型。

“Phi-2”的模型文件大小约为 5 GB,相比之前看到的12.1 GB要小很多。实际上,通过不同的打包方式,某些大语言模型的本地体积可以更小(例如Phi-2可能只有2-3 GB)。文件大小是选择模型时一个重要的实践考量因素。

总结

本节课中我们一起学习了在Hugging Face Hub中寻找开源大语言模型的完整流程。我们首先通过“文本生成”任务筛选出目标模型类型,然后根据预期的使用场景(尤其是商业用途)通过“许可证”进行二次过滤。最后,我们查看了模型详情,重点关注了下载量、社区应用以及关键的模型文件大小。掌握这些筛选技巧,就能高效地找到既开源、许可宽松又符合你技术需求(如对模型大小的要求)的合适模型。

开源大语言模型方案:P7:什么是小语言模型 🧠

在本节课中,我们将要学习什么是小语言模型。我们将探讨其定义、特点、优势以及它与大型语言模型的关键区别。通过了解小语言模型,你将明白在何种场景下选择小模型是更高效、更经济的方案。


上一节我们介绍了大型语言模型的基本概念,本节中我们来看看小语言模型。

小语言模型同样值得关注,并且你手边就有多种开源选项可供使用。这里我指的是 Phi-2,这是微软推出的下一代模型,它实际上就是一个小语言模型。

下图展示了该模型发布时的情况。我想向你说明的是,这是“下一代”模型,因为微软最初是从 Phi-1Phi-1.5 开始,然后才发展到 Phi-2 的。

那么,我们具体在讨论什么呢?关键在于下面这句话:

“Phi-1.5 是 Phi 模型的上一代版本,其性能可与体积大五倍的模型相媲美。”

这一点尤其有趣,因为我们讨论的是一个模型的能力,它试图以与体积庞大得多的模型相媲美的方式运行。

Phi-2 版本是一个拥有 27 亿参数 的模型。虽然这个参数数量听起来非常庞大,但你会看到,与一些其他可能大到其 25 倍 的模型相比,它就相形见绌了。

这实际上非常有意思,因为它拓展了你在“尺寸至关重要”且“所需输出类型不需要最前沿或最先进技术,也不必是庞然大物”的场景下所能做的事情的范围。


为了更直观地理解尺寸差异,我想带你看看 Llama 文件示例,在那里你可以实际下载一些模型文件。

以下是不同类型模型及其文件大小的对比:

从这里可以清楚地看到我们讨论的是哪种类型的模型,以及尺寸从何时开始变得重要。当你看到像 TinyLlamaRocketPhi-2 这样的模型时,你会发现它们的大小都小于 2 GB。其中,TinyLlama 甚至小于 1 GB,而 Phi-2 大约在 2 GB 以下。

相比之下,Mistral 8x7B 模型约为 30 GB,专用于 Python 的 CodeLlama 模型约为 22 GB30 GB 对比 2 GB,这意味着这些小语言模型的体积只有前者的约 1/15

那么,为什么这一点很重要呢?尺寸可能对你想要处理的工作负载类型至关重要。当需要部署模型时,部署像这样的小模型会更便宜、更容易使其良好运行。你可能并不需要大型语言模型提供的全部强大能力,但你仍然可以利用小模型提供的相似能力。


本节课中我们一起学习了小语言模型的核心概念。我们了解到,小语言模型如 Phi-2 虽然参数规模较小(例如 27 亿),但在特定任务上能实现与庞大模型相媲美的性能。其核心优势在于部署成本低、运行效率高,在不需要尖端能力但对资源敏感的场景下是理想选择。关键点在于根据实际需求(性能 vs. 资源)在“大模型”和“小模型”之间做出权衡。

开源大语言模型方案:P8:Azure中的大语言模型 🚀

在本节课中,我们将学习如何在微软Azure云平台上寻找和使用大型语言模型。我们将重点介绍Azure Machine Learning Studio中的模型目录,并了解如何浏览、筛选和部署模型。


大型语言模型同样可以在云平台中找到。接下来,我将以微软Azure为例进行展示。其他服务提供商(如AWS、GCP)也可能提供类似体验,但本节课我们将专注于Azure。

我将进入Azure Machine Learning,这是Azure中查找模型的默认入口之一。Azure也提供OpenAI服务,但在那里无法找到开源模型。

这里我有两个工作区。我将打开一个名为“demo ML”的新建工作区,并启动其Studio界面。这些界面的具体工作原理和细节并非本节课重点,我们的核心目标是查看可访问的模型。

进入后,你立刻就能看到一些生成式AI模型。例如,这里有Falcon、Mistral Large以及Mixtral 8x7B。这些是已经预置可供查看的模型。


上一节我们看到了初始界面中的模型,本节中我们来看看更完整的模型目录。

要查看更多可用模型,我们需要前往模型目录。在那里,你可以看到按“集合”分类的模型。这些集合功能类似于其他服务中的筛选器,允许你根据特定任务(如对话或摘要)来过滤模型。

例如,如果我想查看微软研究的模型,我可能会找到Phi或Phi-2。这里就列出了可供你使用的模型。我特别喜欢Phi-2,因为它是一个小型语言模型,这很有趣。

进入模型页面后,你不仅能看到详细的模型描述,还能立即进行部署。你可以非常轻松地点击创建实时端点或批量端点。同时,你也可以查看模型的许可证信息。

虽然这个特定模型的许可证信息尚未发布,但你可以看到它有不同的版本。有趣的是,Azure Machine Learning Studio提供了一个模型目录服务,让你能够浏览所有可用资源。

即使是新发布的Mistral Large模型,现在也已可用。技术的发展速度非常快。通过这个平台,你可以轻松地找到所有这些模型,并且只需付出很少的努力就能完成部署。


本节课中,我们一起学习了如何在Azure云平台中定位和探索大型语言模型。我们了解了通过Azure Machine Learning Studio访问模型目录、使用集合进行筛选、查看模型详情与许可证,并体验了一键部署的便捷性。这为在云端利用开源大语言模型提供了一个强大的起点。

开源大语言模型方案:P9:09_01_11_总结 📚

在本节课中,我们将总结如何寻找和筛选开源大语言模型,并理解选择合适模型的重要性。我们将回顾关键平台、筛选方法,并探讨小型语言模型的优势。


在掌握了从哪里寻找开源模型,以及如何根据任务能力进行筛选之后,你已经具备了选择合适模型的基础知识。

我们看到了在筛选阶段,你可以通过点击一些过滤器来缩小搜索结果,找到基础模型。这至关重要,因为它能让你有能力进行挑选,并清楚地了解哪些模型适合你想要执行的任务类型。

我还向你展示了一些小型语言模型,例如微软的 Phi-2。在这些情况下,模型的尺寸是一个重要考量因素。

正如你稍后将看到的,尝试判断是否能从一个小型语言模型中获得你所需的精确输出,这一点很重要。

公式/代码示例:模型选择考量

if (任务复杂度 高 and 资源充足):
    考虑大型模型
else:
    优先评估小型模型

与使用一个超大型模型相比,使用小型模型能让你更好地利用计算资源。

以下是选择小型模型的主要优势:

  • 成本更低:运行和部署的经济性更高。
  • 交互更快:响应速度和推理延迟更低。
  • 更易打包部署:模型体积小,便于集成到不同环境中进行推理。

因此,凭借这些关于在哪里寻找模型以及如何为任务选择正确模型的基础知识,你现在应该能够很好地开始使用开源大语言模型了。


本节课中,我们一起学习了寻找开源模型的平台、利用任务标签进行筛选的方法,并重点探讨了小型语言模型在成本、速度和部署便利性上的优势。掌握这些知识,是有效利用开源大语言模型进行项目开发的第一步。

开源大语言模型方案:P10:10_01_01:引言_2

概述

在本节课中,我们将要学习如何利用开源大型语言模型来创建合成数据。我们将探讨如何与大型语言模型交互,并基于现有数据来增强和生成新的数据。我们会了解这样做的目的、适用场景,并学习如何通过API编程化地应用这些技术来创建合成增强数据。

合成数据生成简介

上一节我们介绍了大型语言模型的基本应用,本节中我们来看看一个具体的用例:合成数据生成

利用大型语言模型的一种方式是创建合成数据。我们将研究如何与大型语言模型交互,并基于一些现有数据来增强和生成数据。

具体而言,我们会向大型语言模型提出请求:“你能否基于我们的数据,用人工制造的数据来增强这些内容?”我们将探讨为何需要这样做,以及在何种情况下可能需要采取此类操作。

为何需要合成数据?

以下是几个需要生成或增强数据的主要原因:

  1. 数据稀缺:当原始数据集样本数量不足时,合成数据可以扩充数据集,用于模型训练。
  2. 数据平衡:针对分类任务,合成数据可以帮助平衡不同类别的样本数量。
  3. 隐私保护:使用合成数据可以在不暴露真实敏感信息的情况下进行开发和测试。
  4. 边缘案例模拟:可以生成现实中罕见但重要的场景数据,以提高模型的鲁棒性。

技术实现途径

接下来,我们将了解如何通过编程方式实现这一过程。核心是连接并使用大型语言模型的API。

我们将学习如何通过API与模型交互,从而以编程方式应用这些技术来创建合成增强数据。这通常涉及以下步骤:

  1. 准备原始数据样本。
  2. 设计提示词(Prompt),指导模型生成所需格式和内容的增强数据。
  3. 调用模型API并处理返回结果。
  4. 对生成的合成数据进行验证和后处理。

一个简单的伪代码示例如下:

# 伪代码示例
original_data = load_data("your_data.csv")
prompt_template = "请基于以下文本,生成一个类似的例句:{text}"
augmented_data = []

for sample in original_data:
    prompt = prompt_template.format(text=sample)
    synthetic_sample = call_llm_api(prompt) # 调用LLM API
    augmented_data.append(synthetic_sample)

save_data(augmented_data, "augmented_data.csv")

总结

本节课中我们一起学习了如何利用开源大型语言模型进行合成数据生成。我们了解了其应用价值、常见场景以及通过API编程实现的基本流程。掌握这项技术能够帮助我们在数据不足或需要特定数据特性时,有效地扩充和增强数据集,为后续的模型训练和应用打下坚实基础。

开源大语言模型方案:P11:什么是合成数据集增强 🧪

在本节课中,我们将要学习合成数据集增强的概念。我们将探讨什么是合成数据、为什么需要它,以及如何利用大型语言模型来生成有意义的合成数据以解决数据不足的问题。

概述:什么是合成数据?

合成数据集,或通过生成合成数据来增强或创建更多数据,是合成数据的核心。这样做的原因可能各不相同。你可能面临数据不足的情况。

例如,这里可以看到一些世界青年锦标赛的结果,实际上包含许多不同年份的数据,如1998年等。这是准确的数据,是从真实结果中处理得到的真实数据。然而,你可能希望有更多的数据点,因为你想要执行一些机器学习或数据科学任务,并进行某种生成分析。

数据不足的挑战

在这种情况下,你有几个选择。如果你拥有的数据有限,并且希望看到运动员在长度、地点、身高和年份等方面呈现出不同的情况,你可能不得不求助于合成生成这些数据。

这意味着你需要利用大型语言模型来帮助你。这是一个数据示例,它非常有限。我们可以看到这里只有大约30或40个条目,这是一个很好的例子。

一个更具体的例子

现在,让我展示一个不同的例子。这是我之前构建的一个临时数据集,它有200行。这个数据集更全面,是一个基于葡萄酒的数据集,包含葡萄酒的名称、产区、品种、评分和一些品酒笔记。

这是一个完美的例子。例如,评分似乎从85到99不等。但假设你只想关注评分在97到99之间的葡萄酒。我可以进行筛选,但这当然需要一些时间。

这里的问题是,你可能没有足够的数据。这是一个非常典型的例子,说明现有数据可能不够好。你看到只有三个结果是不够的,这取决于你想要执行的任务类型。

合成数据生成的方法

你可能希望增强这些数据。有几种方法可以做到这一点:

  • 你可以随机生成数据。
  • 你可以编写一些代码,从一些著名产区中随机选取名称,放入品种信息,并生成一个97到99之间的随机数。

然而,当你希望生成一些有意义的品酒笔记时,事情就变得棘手了。这正是大型语言模型大显身手的地方。

总结与核心价值

本节课程中,我们一起学习了合成数据集增强。我们了解到,合成数据是为了弥补数据不足而人工生成的数据。通过一个葡萄酒数据集的例子,我们看到了数据过滤后可能面临样本量过小的问题。解决这个问题的方法包括随机生成或编写规则代码,但在需要生成符合语境和逻辑的文本内容(如品酒笔记)时,利用大型语言模型是更优的选择。这帮助我们理解了何时会遇到数据不足的问题,以及在尝试解决此问题时可能面临的一些挑战。

开源大语言模型方案:P12:12_01_04:增强应用程序概述 🚀

在本节课中,我们将学习如何使用大型语言模型来生成合成数据集。我们将保持方法简单,使用基于OpenAI的API来连接一个本地运行的大型语言模型。通过本教程,你将了解如何设置连接、发送请求并获取模型生成的合成数据。


连接本地大型语言模型

上一节我们介绍了课程目标,本节中我们来看看如何具体连接到本地运行的大型语言模型。我们将使用两种主要方式:Llamafile和Ollama。这两种方式在连接细节上略有不同。

以下是连接本地大语言模型的两个选项:

  1. 使用 Llamafile:Llamafile 默认在 localhost:8080 运行,并且其API端点需要包含 /v1。API密钥字段可以填写任意内容,因为它不是必需的。
  2. 使用 Ollama:如果你在系统中安装了Ollama,连接地址会稍有不同。同样,API密钥不是必需的,但需要根据后台使用的具体模型来调整连接时指定的模型名称。

无论选择哪种方式,第一步都是实例化一个客户端来建立连接。

与模型交互并生成数据

现在我们已经建立了连接,本节中我们来看看如何与模型进行交互以生成合成数据。核心是通过向模型发送包含系统指令和用户输入的消息来完成请求。

在代码中,我们使用 client.chat.completions.create 方法来与模型对话。关键在于构建 messages 参数。

以下是一个消息结构的示例:

messages = [
    {"role": "system", "content": "你是一个根据输入生成合成数据的专家。"},
    {"role": "user", "content": "用户提供的输入文本在这里..."}
]
  • 系统消息:用于指导模型的行为模式。在本例中,我们指示模型扮演一个合成数据生成专家的角色。
  • 用户消息:包含我们希望模型基于其生成数据的具体输入内容。

运行模型并获取结果

为了让整个流程工作,我们需要在本地运行一个大型语言模型实例。这通常通过在终端中启动相应的模型服务来完成。

启动服务后,我们回到代码编辑器,执行与模型交互的代码。生成结果可能需要几秒钟时间,具体取决于本地系统的性能。最终,模型将返回生成的合成数据条目。


本节课中我们一起学习了如何使用本地大型语言模型生成合成数据。我们涵盖了连接模型的两种方法(Llamafile和Ollama),学习了如何通过系统指令和用户输入构建请求消息,并完成了从启动本地模型到获取生成结果的完整流程。这是一个构建数据增强应用程序的快速入门概述。

开源大语言模型方案:P13:13_01_05:测试本地LLM进行数据增强 🧪

在本节课中,我们将要学习如何利用本地运行的大型语言模型来生成合成数据,以增强现有数据集。我们将重点探讨在生成过程中可能遇到的格式挑战,以及如何通过精心设计系统提示词来获得可直接使用的、格式规整的输出。

与本地LLM交互的挑战

上一节我们介绍了如何连接到本地或远程的大型语言模型。本节中我们来看看在实际生成合成数据时可能面临的具体问题。当我们与大型语言模型交互,要求其基于现有数据生成更多样本时,一个核心挑战在于确保输出的格式符合我们的要求。

例如,我们有一个关于葡萄酒的CSV文件,其列顺序固定为:nameregionvarietyratingnotesrating列使用浮点数,notes列包含描述性文本。如果我们简单地要求模型“基于输入生成10个合成示例”,其原始回复可能包含问候语、解释性文字、甚至重复的表头,这些内容无法被程序直接解析为有效的CSV数据。

优化系统提示词以获取规整输出

为了解决上述格式问题,关键在于修改给模型的“系统提示词”,明确约束其输出行为。通过调整提示词,我们可以将模型视为一个纯粹的“数据生成API”,而非一个会进行自由对话的助手。

以下是优化后的系统提示词核心要点:

  • 角色定义:明确指令模型“作为一个生成合成数据的API”。
  • 格式要求:严格规定输出必须为“CSV格式”。
  • 内容限制:禁止提供任何反馈、问题或其他非CSV有效的文本。
  • 数据细节:指示模型无需输出CSV表头,仅提供数据行。

通过应用这套优化的提示词,模型的输出将变得干净、规整,每一行都是有效的CSV数据,可以直接用于后续的数据增强流程。

实践:生成格式规整的合成数据

让我们看看应用优化提示词后的效果。模型生成的响应将直接是如下格式的数据行,没有任何多余的文本:

"Château Mirage","Bordeaux, France","Cabernet Sauvignon",4.7,"A bold wine with notes of dark cherry and oak."
"Sunrise Vineyards","Napa Valley, USA","Chardonnay",4.5,"Crisp and refreshing with hints of green apple."
...

你可以看到,生成的数据严格遵循了原始数据的格式:名称、产区、品种、评分(浮点数)和品酒笔记。这种输出可以直接被程序读取并追加到原始数据集中,从而实现高效、自动化的数据增强。

本节课中我们一起学习了如何通过优化系统提示词,引导本地大型语言模型生成格式规整的合成数据。关键在于将模型交互从“开放式对话”转变为“受控的API调用”,明确指定输出格式并禁止无关内容。这种方法能有效克服数据解析的挑战,使得利用LLM进行数据增强变得可行且高效。

开源大语言模型方案:P14:增强和验证增强后的数据集 🧪

在本节课中,我们将学习如何利用大型语言模型(LLM)生成合成数据,并将其持久化保存为一个新的CSV文件。我们将涵盖从生成数据到验证数据格式的完整流程。


生成合成数据

上一节我们介绍了如何通过提示词与LLM交互。本节中,我们来看看如何具体生成我们所需的合成数据。

我们已准备好将大型语言模型生成的合成数据持久化保存。我们已成功连接到大型语言模型。我是在本地运行的模型,但这与你使用其他方式(无论是本地模型还是托管API)并无本质区别。提示词传递了三个示例项目,并要求生成10个类似的新项目。

系统提示词指示大型语言模型扮演一个API的角色。这意味着响应中不会包含任何多余的描述性文字,只会专注于生成我们指定的内容,即CSV格式的输出。

正如我们之前所见,我们得到了完美的输出,它为我们提供了10个非常优质、可靠的示例。


持久化数据到CSV文件

现在,我们希望将这些数据持久化保存。我们将使用一点Python代码来实际写入并创建一个新的CSV文件。这将创建一个基于我们所得数据的新CSV文件。

我们之前已知的列名是:regionvarietyratingnote

以下是创建CSV文件的步骤:

我们将创建一个新的CSV文件,并使用Python内置的csv模块。如果你处理更复杂的数据,可能会考虑使用pandas,但对于写入一个普通的CSV文件,这不会造成问题,因此csv模块足够使用。

  1. 我们将把以单个字符串形式返回的输出按换行符进行分割。
  2. 我们将以写入模式('w')打开名为synthetic_data.csv的文件。
  3. 我们将创建一个csv.writer实例,并指定分隔符为逗号。
  4. 首先,我们将写入列名。
  5. 然后,对于输出中的每一行,如果该行不为空,我们将对其进行解析并写入文件。

代码示例:

import csv

# 假设 `llm_output` 是包含生成数据的字符串
lines = llm_output.split('\n')

with open('synthetic_data.csv', 'w', newline='') as file:
    writer = csv.writer(file, delimiter=',')
    writer.writerow(['region', 'variety', 'rating', 'note'])  # 写入列名

    for line in lines:
        if not line.strip():  # 跳过空行
            continue
        # 解析行内容,移除多余的引号,并按逗号分割(考虑引号内的逗号)
        # 这里假设生成的数据格式是 "值1","值2","值3","值4"
        parsed_row = [field.strip('"') for field in line.split('","')]
        writer.writerow(parsed_row)

运行此代码后,我们将得到synthetic_data.csv文件。打开文件,可以看到数据已正确格式化,这正是我们所期望的结果。


数据解析的重要性

之前提到解析是必要的。如果不进行解析,直接写入原始行,数据会是什么样子呢?

如果我们简单地写入原始行(即writer.writerow([line])),然后再次运行,生成的synthetic_data.csv文件看起来就不会很规整。数据可能会因为字段内包含逗号和引号而错位。虽然使用pandas处理这类问题可能更容易,但直接写入会破坏数据的结构。

因此,在处理持久化数据或创建此类文件时,必须考虑数据格式的解析。重新运行正确的解析代码后,一切数据又恢复了应有的格式。


生产环境考量

最后,我想说明,如果要在生产环境中编写此类代码,使其更加专业化,我可能会考虑以下几点:

  1. 将数据生成和写入功能封装成可调用的函数。
  2. 用于生成提示的三个示例,可以从现有数据中随机抽取,而不仅仅是固定的几个。
  3. 一旦LLM能够生成一些示例,我们或许可以要求它生成更多(例如超过10个)。
  4. 此外,还需要验证返回的数据(即我们得到的这些数据)是否是有效的CSV格式。


本节课中,我们一起学习了如何利用大型语言模型生成合成数据、将数据正确解析并持久化保存为CSV文件,以及在生产环境中需要考虑的优化和验证点。这就是你整合工具、利用大语言模型生成合成数据并增强数据集的完整方法。

开源大语言模型方案:P15:15_01_08_总结_1

在本节课中,我们将总结前面课程的核心内容,重点回顾如何通过API与大型语言模型进行有效交互,特别是系统提示词的使用、数据格式处理以及合成数据的生成与持久化。

🎯 核心概念回顾

上一节我们介绍了与大型语言模型交互的具体方法,本节中我们来总结其中的关键要点。

🤖 系统提示词的重要性

在这些课程中,我们演示了使用API的方式,这至关重要。你现在应该对如何通过系统提示词与大型语言模型进行实际交互有了清晰的认识。系统提示词非常重要,因为它能确保大型语言模型回复出我们所需的精确响应类型。

📊 数据格式处理

在本案例中,我们关注的是逗号分隔值(CSV)的处理。当大型语言模型在输出开头或结尾添加额外内容时,处理过程可能会有些棘手。因此,调整系统提示词以获得我们所需的确切输出,并持久化这些数据,是至关重要的步骤。

以下是数据处理流程的关键步骤:

  • 调整提示词:修改系统提示词以精确控制模型输出格式。
  • 解析输出:处理模型返回的文本,提取结构化的逗号分隔值。
  • 数据持久化:将处理后的数据保存到磁盘。

🔄 构建自动化流程

这确保了我们能够整合一个完整的流程,以创建合成数据并将其持久化到磁盘,并以此为基础,在我们最初构建的代码框架上进行扩展。

📝 总结

本节课中我们一起学习了与大型语言模型API交互的核心实践。我们重点回顾了系统提示词在引导模型生成特定格式响应中的关键作用,探讨了处理模型输出(如CSV格式)时可能遇到的挑战及解决方案,并总结了如何构建一个从生成、处理到持久化合成数据的完整工作流程。这些基础代码和概念为后续更复杂的应用奠定了坚实的基础。

开源大语言模型方案:P16:16_01_01:引言_3

在本节课中,我们将要学习如何为实际应用构建解决方案,并探讨与开源大语言模型交互所需的编程语言和工具。我们将重点比较Python和Rust两种语言,分析它们各自的优势,并了解如何使用Rust来构建能够解决实际问题的应用。

当我们准备开始构建真实世界的应用程序时,这些解决方案最终需要部署到生产环境中。毫无疑问,我们必须审视一些编程语言,并利用现有的工具来与模型(在本课程中特指开源模型)进行交互。

因此,我们将探讨如何使用这些工具。我们之前在某些环节已经少量使用了Python,但接下来我们将更深入地研究Rust。

我们将看看Python和Rust之间的一些区别,分析你可能选择其中一种而非另一种的原因。同时,我们也会了解一些可以与Rust配合使用的解决方案,以便我们能够通过这些方案与模型交互,并最终整合出一个能够有效解决实际问题的应用。

上一节我们介绍了构建应用的基本背景,本节中我们来看看具体的技术选型。

以下是Python与Rust的主要对比考量点:

  • Python:以其简洁的语法和丰富的库生态而闻名,特别适合快速原型开发和数据科学任务。
  • Rust:则强调内存安全并发性能和高执行效率,其核心优势在于能在编译时防止数据竞争等错误,适合构建高性能、高可靠性的系统。

本节课中我们一起学习了为生产环境构建LLM应用时对编程语言和工具的考量,比较了Python和Rust的适用场景,并引出了使用Rust与开源模型交互以构建解决方案的主题。

开源大语言模型方案:P17:17_01_03:考虑使用Rust替代Python 🦀

在本节课中,我们将探讨在大型语言模型相关项目中,为何可以考虑使用Rust替代Python。我们将重点分析几个关键原因,包括云部署成本、性能表现以及项目打包与分发的便捷性。

云部署成本考量 💰

上一节我们介绍了编程语言选择的一般背景,本节中我们来看看一个非常实际的问题:云部署成本。当你计划将应用程序部署到云端时,需要计算它将消耗多少内存和CPU资源,这直接决定了成本。

为了具体说明,我们以微软云Azure的容器应用定价为例。选择Rust而非Python,成本可能降低一个数量级,因为Rust应用的内存和CPU需求远低于Python。

以下是Azure消费计划的定价选项概览:

  • Rust应用示例:一个Rust Web API应用可以仅使用0.25个vCPU100 MB RAM进行部署。
  • 免费额度影响:Azure每月提供180,000 vCPU秒的免费额度。使用0.25个vCPU意味着你可以将免费额度效用提升四倍,因为你并非每秒都占用一整个vCPU。
  • 内存免费额度:每月360,000 GB秒的内存免费额度,使得低内存占用的Rust应用优势更明显。

通过简单的计算器对比,就能看出在云成本方面,Rust是一个极具说服力的选择。

性能与本地运行优势 ⚡

除了云成本,Rust还能带来纯粹的性能提升。无论是在云端发布项目,还是在本地运行,你都能获得更强的处理能力、更低的资源消耗以及卓越的运行效率。

项目打包与分发的复杂性 📦

现在,让我们转向项目分发和部署的挑战。Python在这方面的一个普遍问题是打包。当你想要分发Python项目时,如果涉及依赖管理,事情会变得复杂。

尽管Python打包生态已有积极改进,但仍存在一些棘手且难以理解的挑战。以下是Python打包流程中可能涉及的部分工具和概念:

  1. 包安装器:通常从pip开始,但它可能需要升级,且并非处理所有任务的唯一工具。
  2. 依赖定义文件:存在多种格式,如pyproject.tomlrequirements.txtsetup.py,缺乏一个强制的、单一的标准方式。
  3. 构建工具:可能需要单独安装build等工具来构建分发包。
  4. 虚拟环境:为了隔离包安装,通常需要使用虚拟环境。
  5. 发布工具:上传分发包到仓库可能需要另一个工具,例如twine

可以看到,仅打包环节就可能需要四到五种不同的工具,过程复杂且缺乏一个统一的、强约定的工作流。

Rust的Cargo工具链 🛠️

相比之下,Rust的主要优势之一是拥有Cargo。如果我们查看Cargo手册,它是Rust的包管理器,功能高度集成。

以下是Cargo作为单一工具所能完成的核心工作:

  • cargo build:构建项目。
  • cargo run:运行项目。
  • cargo test:运行测试。
  • cargo fmt:格式化代码。
  • cargo publish:发布包到crates.io。

Cargo使用Cargo.toml文件来定义项目元数据和依赖,其结构类似于pyproject.toml。这种简单且高度约定俗成的方式,避免了Python中多种工具碎片化带来的复杂性。

此外,当你使用Cargo构建一个二进制文件时,它会确保所有内容都被包含在单个可执行文件中。这个文件可以在具有相同CPU架构的任何系统上运行,使得应用的分发变得极其简单。

总结 📝

本节课中我们一起学习了考虑使用Rust替代Python的几个重要原因。

  1. 显著降低云部署成本:得益于更低的内存和CPU占用。
  2. 获得更优的运行时性能:无论是在云端还是本地。
  3. 极大简化项目打包与分发:通过Cargo这一单一、强大的工具链,实现从依赖管理、构建、测试到发布的统一流程,并生成易于分发的独立二进制文件。

对于关注效率、成本和部署便捷性的项目,尤其是资源敏感型的LLM应用部署场景,Rust提供了一个值得认真考虑的替代方案。

开源大语言模型方案:P18:18_01_04:使用Rust Candle 🕯️

在本节课中,我们将要学习如何使用 Rust Candle 库来运行大型语言模型。Candle 项目允许你将模型和所有依赖打包成一个独立的可执行文件,无需外部依赖,这为部署和使用模型提供了极大的便利。

概述

Candle 与其他工具(如 Rut Bt)不同,它让你拥有一个单一的可执行文件,无需任何其他外部依赖。这使你能够在一个二进制文件中运行模型,功能非常强大。

浏览Candle示例

接下来,我们将浏览 Candle 的示例代码。我们将具体使用一个执行翻译任务的示例。为此,我们将深入查看量化 T5 模型的示例。运行它并不复杂,但在运行和演示之前,我们先来看看代码。

代码结构分析

代码量较大,有 233 行。但不必担心,因为这是一个命令行工具,允许你运行从 T5-small 到 T5-extra-extra-large 等多种模型。因此,代码中包含了处理不同模型选项的逻辑。

你可以想象,较小的模型下载和执行所需资源较少,但能力可能较弱;而较大的模型可能具备更强的能力。

由于这是一个命令行工具,代码中包含了参数解析部分。你可以看到它尝试启用追踪、理解版本信息、处理权重和配置文件缓存。prompt 参数是你为模型提供输入的地方。

许多选项会从后台自动获取。我们之前讨论过 Hugging Face 平台可以托管所有这些模型。你可以看到量化 T5 模型就在 lmc 组织下。这允许你在运行时动态检索模型。

代码最后会与模型交互:读取输入,进行分词,然后将分词后的输入发送给模型进行处理。

终端演示

现在,让我们转到终端看看实际效果。

在我的终端中,我正在运行量化 T5 示例。我将输入以下文本进行翻译:
translate this text one of these days I'm going to run a marathon

运行后,你可以看到它生成了 18 个令牌,并以每秒 24.8 个令牌的速度运行。它成功地将文本翻译成了德语。虽然我的德语不好,但这个翻译过程非常快。

当我们使用 --release 标志运行时,意味着它将构建所需的一切。这很好。

如果我们执行 ls 命令查看 target 目录,你会看到 release 文件夹。让我们看看 release 里面有什么,并查看量化 T5 示例的最终文件大小。

执行 ls -lh 后,你可以看到文件大小为 9.8 MB。这非常令人印象深刻。不过,这个大小不包括模型本身,模型是预先单独下载的。

为了演示这一点,我将运行一个不同的示例。这次,我将运行 T5 模型,并使用其 v2 版本。我将输入一个有趣的提示:
write me a haiku about food

在后台,你可以看到它正在构建和下载模型。它下载了 537 MB 的数据,速度相当快。它同时下载了 safetensors 文件、分词器以及必需的索引文件。这需要几秒钟来完成。

下载完成后,你可以看到 T5 模型开始生成输出。这次速度没有那么快,我只能达到每秒 3.26 个令牌的速度。这一切都是动态发生的。

终端还提示我当前在 CPU 上运行,并提醒在 CPU 上运行会慢很多。这就是我们观察到性能下降的原因。

总结

本节课中,我们一起学习了如何使用 Rust Candle 库来运行和测试大型语言模型。我们了解了 Candle 如何将模型打包成单一可执行文件的优势,浏览了其示例代码的结构,并在终端中演示了运行量化 T5 模型进行翻译和生成俳句的过程。Candle 是一个非常有潜力的工具,希望你能尝试运行这些示例,并探索如何利用这些模型解决实际问题。

开源大语言模型方案:P19:使用Rust BERT进行命名实体识别

在本节课程中,我们将学习如何使用 Rust BERT 库来执行命名实体识别任务。我们将通过一个简单的 Rust 项目,了解如何加载预训练模型、处理输入文本并提取出文本中的人名、地名和组织机构名。


项目概述与依赖

我们将展示一个非常简单的项目,该项目使用 Rust BERT 库。我们将使用 Rust BERT 来执行命名实体识别。命名实体识别是一种使用模型来检测文本中特定名称(如人名、地名)的能力。

以下是项目的依赖项。我们只有一个 Rust 依赖项,名为 anyhow。它允许你在 Rust 中处理错误,但对于我们当前的目标来说,这个依赖项不是核心。我们在这里要重点介绍的是 Rust BERT 库。它让你能够获得与使用 Hugging Face 的 Transformers 库相似或相同的体验。

[dependencies]
anyhow = "1.0"
rust-bert = { version = "0.21", features = ["download-libtorch"] }

上一节我们介绍了项目的目标和依赖。接下来,让我们看看实际的代码文件。


代码解析

让我们来看一下实际的代码文件。这个文件并不大,总共只有 23 行。我们将逐行进行讲解。

首先,我们从这里开始。这里我们使用了一个预构建的、开箱即用的命名实体识别模型。NER 就代表命名实体识别。pipeline 意味着所有的抽象工作都已经为我们完成,我们只需要写很少的 Rust 代码就能得到有趣的结果。这就是它的作用。

我们的 main 函数首先会设置模型。我们将实例化、创建这个模型变量,并使用默认配置创建一个新实例。

use rust_bert::pipelines::ner::NERModel;

fn main() -> anyhow::Result<()> {
    // 设置模型
    let ner_model = NERModel::new(Default::default())?;

然后,我们在这里模拟输入。我们将传入三个短语或句子。

    // 模拟输入文本
    let input = [
        "My name is Alfredo. I was born in Peru.",
        "Portugal is great.",
        "I used to work in a small company called Shocu.",
    ];

接下来,我们将获取这个输入,并在模型中使用它。这个输入将传递到这里。

然后,这个命名实体识别模型有一个函数,叫做 predict_entities。它接收我们传入的输入。

    // 使用模型进行预测
    let output = ner_model.predict(&input);

之后,我们将对输出中的每一个项目进行循环处理。模型会生成多个项目,我们将遍历它们,并打印出模型识别出的内容。

    // 遍历并打印结果
    for (sentence, entities) in input.iter().zip(output.iter()) {
        println!("Sentence: {}", sentence);
        for entity in entities {
            println!("  Word: {:?}, Label: {:?}, Score: {:.4}", entity.word, entity.label, entity.score);
        }
        println!();
    }
    Ok(())
}

那么,这个循环是如何工作的呢?让我切换到终端。


运行与结果

现在终端已经打开,我将运行 cargo run 命令。当我执行 cargo run 时,它会在后台进行构建,然后运行生成的可执行文件。

你可以在这里看到,结果是一个一个输出的。第一个是 “Alfredo”,第二个是 “Portugal”,第三个是 “Shocu”。它正确地检测出第一个词 “Alfredo”,其标签是 “PER”,代表这是一个人名。

所以它正确地将其检测为一个真实的人名。它为你提供了一些信息。

然后它继续处理单词 “Peru”,并告诉你标签是 “LOC”,代表地点。它还精确地告诉你这个词在文本中的起始和结束位置,并给出了一个分数,代表模型对其正确性的确信程度。

因此,你可以处理置信度很低的例子,那些可能效果不佳。

接下来是 “Portugal”,标签是 “LOC”,与 “Peru” 类似,效果很好。

然后是 “Shocu”,标签是 “ORG”,代表组织机构,并带有一定的确信度。

效果非常好,非常简单和方便。


注意事项与总结

使用 Rust BERT 时需要注意的一个问题是,它要求你安装 PyTorch。如果你查看依赖项中的特性,你会看到 download-libtorch。这意味着在我安装时,它会自动为我下载 PyTorch。这是这个库的一个需要注意的要求。

否则,如果我们查看 target/debug 目录,你会看到可执行文件在那里。让我们检查一下你构建的可执行文件有多大,它有 31 MB。

这实际上是一个相当有说服力的理由,让你考虑使用像 Rust 这样的语言。使用 Rust BERT 可以让你以一种非常快速、简单的方式来处理模型,从而能够做像命名实体识别这样有趣的事情。

在本节课中,我们一起学习了如何使用 Rust BERT 库进行命名实体识别。我们从项目配置、代码编写到运行和结果分析,完成了一个完整的流程。你学会了如何利用预训练的 NER 模型快速从文本中提取关键实体信息,并了解了使用 Rust 进行此类任务的优势与注意事项。

开源大语言模型方案:P20:总结

在本节课中,我们总结了在大型语言模型(LLM)应用开发中,使用Rust编程语言作为替代方案的核心要点与优势。

概述

本节课我们一起回顾了Rust与Python在LLM项目中的对比,并探讨了Rust生态中可用的关键工具与框架。我们将理解为何在某些场景下Rust是一个值得考虑的选项。

Rust与Python的选择考量

上一节我们介绍了Rust生态中的具体工具,本节我们来总结一下语言选择的核心观点。

使用Python是完全可行的选择。然而,Rust具备多项优势,值得你在项目中认真考虑。

以下是Rust的一些主要优势点:

  • 性能与效率:Rust能提供更高的运行效率和更低的内存占用。
  • 安全性:其所有权系统可以在编译时避免内存错误和数据竞争。
  • 并发处理:为构建高并发、高性能的应用提供了坚实基础。

Rust生态中的工具与框架

我们探讨了如何利用Rust生态中现有的工具和框架,特别是Candle和Rust Burn。

这些框架各有特点,适用场景和难度也有所不同。例如,Rust Burn需要下载LibTorch,这增加了一些配置步骤,你可能需要根据是否愿意处理此类依赖来做决定。

另一方面,Candle框架也极具吸引力。它提供的开箱即用示例让开发者能更轻松地开始实验和探索各种解决方案。

总结

本节课中我们一起学习了在LLM操作中考虑使用Rust的缘由,以及如何开始利用Rust生态中的工具。现在,你应该对使用Rust解决问题有了一个良好的总体认识,并知道如何着手应用它。

开源大语言模型方案:P21:21_02_03_Mozilla的LlamaFile概述

概述

在本节课中,我们将要学习Mozilla推出的LlamaFile项目。该项目旨在让普通用户能够轻松地在个人电脑上使用开源大语言模型,而无需复杂的安装和配置过程。


项目背景与动机

上一节我们介绍了开源AI领域的现状,本节中我们来看看Mozilla创建LlamaFile的具体原因。

Mozilla在调研开源AI技术现状时发现,尽管该领域活动频繁,但许多技术对用户而言仍然过于复杂。用户首先面临海量模型的选择,选定模型后还需处理不同的模型格式。随着技术发展,这些格式也在不断变化。用户还需决定使用何种运行时环境来加载和运行模型以进行推理。

根据所选模型、平台和运行时方案,用户可能需要完成多项复杂操作。以下是可能遇到的典型步骤:

  • 用户可能需要编译C或C++代码,并确保安装了正确的工具链。
  • 用户可能需要安装和管理Python依赖项。
  • 在某些情况下,用户需要安装本地软件。

这些步骤组合在一起会变得非常复杂。Mozilla担心,使用开源AI的难度越高,开发者采用它的可能性就越低,或者采用速度就越慢。这可能会阻碍其发展,而Mozilla认为开源AI的演进至关重要。

Mozilla相信,让公众掌握具有竞争力的先进开源AI技术,对于防止AI最终被少数商业利益所主导至关重要,就像互联网的发展历程一样。作为Firefox的制造商,Mozilla非常关心网络生态,因此也必须关注AI,因为它已经在改变我们所有人使用网络和计算机的方式。


LlamaFile的构成

基于上述动机,Mozilla创建了LlamaFile。该项目通过一种独特的方式,将两个不同的开源项目结合在一起。

第一个项目是Llama.cpp。这是一个非常流行的开源项目,它使得在普通消费级硬件上运行量化后的开源模型成为可能。这些模型经过压缩,运行时所需内存更少。该软件本身是一个基于C++的高效推理引擎,可以在MacBook、Windows电脑或Linux机器等日常硬件上执行这些模型。

Mozilla将这个项目与另一个名为Cosmopolitan的项目相结合。

Cosmopolitan是由Justine Tunney创建的项目。它的功能是让C和C++程序能够以一种特殊方式编译,从而在几乎任何计算机上运行。这意味着无需为Windows、Linux、Mac等不同平台分别编译可执行文件。同一个编译后的文件可以在所有这些不同的平台上原样运行,甚至可以在树莓派上运行。这是一项相当了不起的技术。

Mozilla与Justine合作,将这两个项目结合在一起。


LlamaFile的工作原理与优势

上一节我们了解了LlamaFile的技术基础,本节中我们来看看它的具体工作方式和带来的好处。

这种结合使Mozilla能够获取任何采用GGUF格式的开源权重模型(这是当前一种流行的开源模型格式,你可以在Hugging Face等地方找到它们),然后将其封装进LlamaFile可执行代码中。

这种封装仅给一个原本数GB大小的文件增加约40到50MB,这基本上可以忽略不计。现在,这个文件可以被分发,无论用户使用何种类型的电脑,他们都可以下载它。当用户运行它时,它就能直接工作。

运行LlamaFile会启动用户的网页浏览器,显示一个基于Web、本地托管的聊天机器人界面。AI完全在用户的本地机器上运行。此时即使断开互联网连接,它也能继续工作,因此它是100%本地化的。它对用户而言是100%私密的,用户可以放心使用,无需担心数据被他人监听或利用。

如前所述,这几乎可以在任何电脑上运行。如果用户拥有可以加速大语言模型推理的图形处理单元(GPU),LlamaFile会自动检测并利用它,无论是NVIDIA还是AMD的GPU。这一点很重要,因为在AI和机器学习领域,AMD通常不像NVIDIA那样获得同等的软件支持,而LlamaFile也解决了这个问题。


资源与展望

在Mozilla的网站和GitHub代码仓库中,提供了许多可供下载和使用的示例LlamaFile文件。

在未来的视频中,可以进一步探讨如何创建你自己的LlamaFile,如何自己使用LlamaFile,以及作为开发者如何将其用作OpenAI API的简易替代方案。


总结

本节课中我们一起学习了Mozilla的LlamaFile项目。它通过将Llama.cpp推理引擎与Cosmopolitan跨平台编译技术相结合,将复杂的开源模型使用流程简化为一个下载即可运行的文件。这使得用户能够在自己的设备上轻松、私密地体验开源大语言模型,无需担心复杂的安装、配置或平台兼容性问题,从而有力地推动了开源AI技术的普及和应用。

开源大语言模型方案:P22:22_02_04_使用LlamaFile API 🚀

概述

在本节课中,我们将要学习如何使用LlamaFile的服务器模式及其提供的OpenAI兼容API。这将允许你将原本为OpenAI编写的代码无缝切换到本地运行的LlamaFile模型上。


LlamaFile的服务器模式与API

当你启动任何一个LlamaFile时,默认情况下它也会在后台启动一个服务器。这个服务器提供了一个与OpenAI兼容的API端点。这意味着它模仿了OpenAI API的签名,用于完成文本生成和其他功能,但背后使用的是你本地机器上运行的LlamaFile模型,而非OpenAI的服务。

上一节我们介绍了LlamaFile的基本概念,本节中我们来看看其API的具体应用。

代码兼容性与切换

这种设计的意义在于,你可以直接使用那些为OpenAI编写的代码,并将其与LlamaFile配合使用。这使你能够从一个商业化的集中式服务(如OpenAI)切换到一个由你控制的开源、免费可用的系统。

你可以选择在本地机器上运行,也可以将LlamaFile容器化(Dockerize)并在服务器上运行。这两种方式都有人使用。

Python示例

以下是一个使用OpenAI Python库的简单代码示例。我所做的唯一改动是将base_url指向我本地运行LlamaFile的主机地址。

import openai

client = openai.OpenAI(
    base_url="http://localhost:8080/v1", # 指向本地LlamaFile服务器
    api_key="not-needed" # 本地运行无需真实API密钥
)

completion = client.chat.completions.create(
    model="local-model", # 模型名称可自定义
    messages=[
        {"role": "system", "content": "你是一个乐于助人的助手。"},
        {"role": "user", "content": "请给我讲一个关于大语言模型的短故事。"}
    ]
)

print(completion.choices[0].message.content)

当我在控制台运行这段代码时,它会调用本地的API端点。代码以为自己在与OpenAI对话,但实际上是与运行在我本地机器上的模型交互。输出结果会被直接打印到控制台。

JavaScript示例

同样地,你也可以使用JavaScript来实现。以下是一段非常简单的JavaScript代码,它直接使用HTTP请求与相同的API签名进行通信,只是将请求目标从OpenAI改为了我的本地主机。

async function getStory() {
    const response = await fetch('http://localhost:8080/v1/chat/completions', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            model: 'local-model',
            messages: [
                { role: 'system', content: '你是一个乐于助人的助手。' },
                { role: 'user', content: '请给我讲一个关于大语言模型的短故事。' }
            ]
        })
    });
    const data = await response.json();
    console.log(data.choices[0].message.content);
}

这段代码在浏览器中运行,可以实现相同的功能。通过一个简单的网页界面提交问题,所有交互都通过JavaScript完成,并将原始的响应内容输出到控制台。

纯服务器模式与优化

LlamaFile的这一功能现已可用。当你创建自己的LlamaFile时,可以将其配置为仅运行在服务器模式。这意味着它不会启动任何Web用户界面,纯粹作为一个API服务器运行。如果你的使用场景只需要API,这样可以进行优化。

我们非常希望开发者能享受使用此功能的过程。我们的目标是让人们更容易地从集中的商业服务转向开源方案,因为我们相信这将有助于加速开源领域所期望看到的所有进展。


总结

本节课中我们一起学习了LlamaFile的服务器模式及其提供的OpenAI兼容API。我们了解了如何通过修改代码中的端点地址,将原本为OpenAI设计的应用程序无缝迁移到本地或自托管的LlamaFile模型上,并通过Python和JavaScript的实例演示了具体操作方法。这为利用开源大语言模型提供了极大的灵活性和控制权。

开源大语言模型方案:P23:23_02_05_创建LlamaFile 🦙

在本节课中,我们将学习如何使用 LlamaFile 工具,这是一个能够将开源大语言模型轻松打包成可执行文件的方案。我们将了解其基本用法、性能表现以及如何创建自定义的模型文件。


概述

LlamaFile 是一个便捷的工具,它允许用户下载或创建可直接运行的大型语言模型可执行文件。这些文件封装了模型权重和推理引擎,无需复杂的环境配置即可在本地运行,支持纯CPU和GPU加速两种模式。

获取与运行LlamaFile

要获取 LlamaFile,可以访问其官方网站或 GitHub 仓库。仓库的说明文件中提供了许多预构建的模型文件示例,这些文件托管在 Hugging Face 平台上。

以下是获取和运行 LlamaFile 的基本步骤:

  1. 访问资源:前往 LlamaFile 的官方网站或 GitHub 仓库。
  2. 下载文件:从提供的链接中下载所需的预构建模型可执行文件。
  3. 直接运行:将下载的文件作为普通可执行程序运行即可。

例如,运行 Mistral-7B 模型文件时,它会自动将模型加载到内存中,并启动一个交互式聊天界面。

./mistral-7b-model.llamafile

性能演示:CPU vs GPU

上一节我们介绍了如何运行一个模型。本节中,我们来看看在不同硬件下的性能差异。

首先,在仅使用CPU的情况下运行模型。虽然速度不及云端服务,但仍具备可用性。例如,在演示中获得了约 11.34 tokens/秒 的生成速度。

# 默认使用CPU运行
./mistral-7b-model.llamafile

接下来,通过添加命令行参数,可以指示 LlamaFile 尽可能将模型加载到GPU显存中,从而利用GPU进行加速。

# 使用GPU加速运行
./mistral-7b-model.llamafile --gpu

启用GPU加速后,性能得到显著提升。在演示中,生成速度达到了近 120 tokens/秒。这展示了GPU加速的强大能力,并且LlamaFile能够开箱即用地支持NVIDIA和AMD显卡。

多模态模型示例

除了纯文本模型,LlamaFile 也支持多模态模型。以下是使用 Lava 多模态模型的一个例子。

多模态模型意味着它可以接受图像和文本作为输入。运行对应的LlamaFile后,你可以上传一张图片并向模型提问。

例如,上传一张图片后提问:“这张图片里有什么?”。模型会分析图像内容并生成描述,展示了开源社区在 multimodal AI 方面的进展。

在资源受限环境中运行

LlamaFile 的优势之一是能在资源受限的设备上运行。以下是一个在小型设备上运行的例子。

Rocket-3B 模型为例,这是一个非常小的模型,专为受限环境设计。即使在没有GPU加速、仅使用CPU的树莓派(一款约35美元的信用卡大小电脑)上,它也能快速生成虽然简短但合理的回答。这证明了开源AI技术已变得非常易于获取和部署。

创建自定义LlamaFile

最后,我们来学习如何将自己的模型转换为 LlamaFile。这对于想要使用特定版本或自定义微调模型的用户非常有用。

LlamaFile 支持流行的 GGUF 格式模型权重文件。你可以在 Hugging Face 上找到成千上万不同量化级别的GGUF文件。

创建自定义 LlamaFile 的步骤如下:

  1. 准备GGUF文件:从 Hugging Face 或其他来源下载你需要的GGUF格式模型文件。
  2. 使用转换命令:通过一行命令将该数据文件转换为可执行的 .llamafile 文件。

转换命令的格式如下:

llamafile-convert [你的GGUF文件名]

例如,将一个4位量化的、经过微调的Mistral模型文件进行转换:

llamafile-convert mistral-7b-instruct-v0.2.Q4_K_M.gguf

转换完成后,会生成一个 .llamafile 文件。这个新文件就可以像我们之前演示的其他模型一样直接运行了。

总结

本节课中,我们一起学习了 LlamaFile 工具的核心用法。我们了解了如何获取和运行预构建的模型,对比了CPU与GPU模式下的性能差异,见识了多模态模型的能力,探索了在树莓派等受限设备上运行模型的可行性,并最终掌握了如何将任何GGUF格式的模型权重转换为自定义的可执行LlamaFile。这个工具极大地简化了开源大语言模型在本地部署和使用的流程。

开源大语言模型方案:P24:使用Cosmopolitan构建便携式二进制文件 🚀

在本节课中,我们将要学习一个名为Cosmopolitan的核心库。这个库是Lamaophil项目的核心,它使得构建便携式的大型语言模型成为可能。我们将通过实际操作,了解如何使用Cosmopolitan来创建“一次构建,到处运行”的二进制文件。


概述与核心概念

Cosmopolitan Libc是一个C语言库,其目标是实现类似Java的“一次构建,到处运行”(Build Once Run Anywhere)特性。这意味着你可以编译一个程序,然后在多种操作系统(如Linux、macOS、Windows)上直接运行,而无需重新编译。

它的核心是cosmocc编译器。使用它编译程序的基本命令格式是:

cosmocc -o [输出文件名] [源代码.c文件]

第一步:创建并编译“Hello World”程序

上一节我们介绍了Cosmopolitan的基本概念,本节中我们来看看如何用它编译一个最简单的程序。

首先,我们需要创建一个C语言源代码文件。

以下是创建和编辑hello.c文件的步骤:

  1. 使用touch命令创建文件:touch hello.c
  2. 打开hello.c文件,并输入以下代码:
    #include <stdio.h>
    
    int main() {
        printf("Hello World\n");
        return 0;
    }
    
    这段代码引入了标准输入输出库,并在main函数中打印“Hello World”。

文件创建好后,就可以使用Cosmopolitan编译器进行编译了。

使用cosmocc编译器编译hello.c文件的命令如下:

./bin/cosmocc -o hello hello.c

这个命令会生成一个名为hello的便携式二进制文件。

最后,运行编译生成的可执行文件:

./hello

如果一切顺利,终端将输出:Hello World


第二步:构建一个更复杂的程序(Marco Polo)

在成功运行了简单的“Hello World”程序后,我们可以尝试构建一个逻辑稍复杂的程序来加深理解。

接下来,我们将创建一个名为“Marco Polo”的程序。它会检查用户输入的命令行参数。

首先,创建源代码文件:touch marco_polo.c

然后,在marco_polo.c文件中输入以下代码:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc == 2 && strcmp(argv[1], "Marco") == 0) {
        printf("Polo\n");
    } else {
        printf("Usage: %s Marco\n", argv[0]);
    }
    return 0;
}

这段代码的逻辑是:如果用户运行程序时附带了一个参数,并且这个参数是字符串“Marco”,那么程序就打印“Polo”;否则,程序会打印使用说明。

代码编写完成后,同样使用cosmocc编译器进行编译。

编译marco_polo.c文件的命令如下:

./bin/cosmocc -o marco_polo marco_polo.c

这个命令会生成名为marco_polo的便携式二进制文件。

现在,让我们来测试这个程序的功能。

运行程序并传入参数“Marco”:

./marco_polo Marco

终端将输出:Polo

运行程序但不传入参数,或传入错误参数:

./marco_polo

终端将输出类似的使用说明:Usage: ./marco_polo Marco


总结与关联

本节课中我们一起学习了如何使用Cosmopolitan库来构建便携式二进制文件。我们从最简单的“Hello World”程序开始,逐步过渡到一个能处理命令行参数的“Marco Polo”程序,实践了编译和运行的全过程。

之所以要深入了解Cosmopolitan,是因为它是Lamaophil项目的核心。Lamaophil是一个用于运行和分发大型语言模型的工具。通过从底层原理入手,亲自体验其核心库的工作方式,我们能够更好地理解并欣赏Lamaophil在设计上的优雅与强大。掌握这个基础,将为后续学习和使用更高级的大型语言模型部署工具打下坚实的基础。

开源大语言模型方案:P25:LlamaFile入门指南 🚀

概述

在本节课中,我们将要学习如何使用LlamaFile项目,这是由Mozilla推出的一个极其简便的本地运行大型语言模型的方案。我们将了解其核心优势、基本结构以及如何实际操作。


项目简介与优势

LlamaFile项目可能是运行本地大型语言模型最简单的方式。许多人对此感兴趣,主要出于隐私保护的考虑,同时,使用自己的机器运行模型是完全免费的。

上一节我们介绍了本地运行大模型的动机,本节中我们来看看LlamaFile的具体实现。

LlamaFile允许你通过单个文件来分发和运行大型语言模型。其最吸引人的特点是,它使用了名为 cosmopolitan Lib C 的库,能够将所有组件压缩成一个名为 LlamaFile 的单一可执行文件。

尽管名字叫LlamaFile,但它并不局限于特定的某个大语言模型。项目页面上提供了多个模型示例。

以下是项目的一些核心优势:

  • 隐私性:你的数据不会被发送到任何公司。
  • 性能:由于没有网络延迟,本地调用的性能通常优于调用外部API。
  • 免费:使用自己的硬件,无需支付API调用费用。

模型选择与获取

项目提供了多种模型可供选择。其中一个例子是 Lava,它是一个能够读取图像内容的模型,非常有趣。

我个人认为比较有意思的是 Mixtral 模型。它是目前性能较好的开源模型之一,采用Apache2许可证。不过,它的文件大小约为30GB,下载量较大。

获取模型后,你只需要下载它,然后在终端中执行 ./run 命令即可启动。


核心功能与API

LlamaFile的一个很酷的功能是,它提供了一个模仿OpenAI API的Python API。这意味着你可以轻松地将代码从封闭的商业专有模型迁移到开源模型上。

此外,你还可以使用 curl 命令通过HTTP接口与模型进行交互。


实际操作演示

让我们来看看它是如何工作的。我已经在终端中下载并准备好了Mixtral模型。

运行模型非常简单,只需执行:

./run

这样,llama.cpp 就在本地运行起来了。

如果需要重置到某种默认状态,可以执行重置操作。

在实际使用中,我可以更改AI助手的名称,然后向它提问。例如,我可以要求它编写一个Python的“Hello, World!”函数。

发送请求后,模型会利用我Mac的GPU进行快速推理并返回结果。

围绕Mixtral的一些评测指标显示,它的性能与闭源的专有模型相当。我可以继续让它完成更多功能,比如编写一个将两个数字相加的Python函数。


总结

本节课中我们一起学习了LlamaFile项目。关键结论是,运行自己的本地模型实际上非常直接简单。使用LlamaFile的主要优势在于:保障了数据隐私、获得了更低的延迟和更好的性能,并且完全免费。这些是探索这个项目的显著优点。

我鼓励你去查看LlamaFile项目,并尝试使用它。

开源大语言模型方案:P26:26_02_04_LlamaFile本地系统指标

概述

在本节课中,我们将学习如何使用LlamaFile来监控本地运行大型语言模型时的系统指标。我们将了解如何查看GPU使用率、核心负载等关键性能数据,并评估本地模型的性能表现。


监控系统指标

上一节我们介绍了LlamaFile的基本使用,本节中我们来看看如何利用它来监控系统运行指标。

首先,我们可以从模型的Elo评分来观察其实际表现。这反映了用户对该模型能力的感知。如图所示,这个混合模型的表现与商业模型相差无几,这表明只要性能足够好,会有大量用户有兴趣在本地运行它。

那么,性能是否足够好呢?让我们来仔细看看这个LlamaFile项目。目前,它正运行在这个浏览器窗口中,并且旁边显示了所有的系统指标,让我们能够观察运行状态。

以下是需要关注的关键指标:

  • GPU时间:这是一个重要指标。
  • 所有核心:观察所有CPU核心的负载情况。
  • M2 Ultra GPU:我使用的这款拥有60个GPU核心。得益于LlamaFile和Llama.cpp开发者的出色工作,在Mac操作系统上能够充分利用所有这些GPU核心。

观察GPU使用情况

接下来,我们通过实际操作来观察GPU的使用情况。让我们运行一个Python函数来看看效果。

向下滚动,我们可以观察GPU指标的变化。实际上,我们会看到这里的GPU使用率出现峰值,同时这里也应该显示一些GPU活动。

我们可以看到,这个.a1.9进程确实在调用GPU。实际上,我们看到它再次运行。我们可以再试一次,例如,要求它“给我一个Python中递归函数的例子”。

然后看看它做了什么。看,它生成了一个Python递归函数,同时我们也能看到,它确实在使用GPU。


性能评估与思考

由此可见,其性能实际上非常出色。我们能看到历史GPU数据,证明它能够有效利用GPU资源。

对于正在使用商业模型的用户来说,商业模型显然有其价值。但这无疑引出了一个长期问题:如果你可以下载一个性能足够好、表现惊人且免费的模型,为什么还要使用商业模型呢?

因此,在你尝试使用LlamaFile,甚至考虑为大型语言模型签订商业协议之前,有两点值得思考:

  1. 首先,仔细看看本地模型的真实性能。
  2. 观察各项系统指标,你会发现它的表现非常令人印象深刻。

总结

本节课中,我们一起学习了如何使用LlamaFile监控本地运行大语言模型的系统指标。我们查看了GPU时间、核心负载等关键数据,并通过实际生成代码的例子观察了GPU的利用情况。最后,我们对比了本地模型与商业模型的性能,认识到本地部署在性能足够时是一个极具吸引力的选择。

开源大语言模型方案:P27:使用Whisper构建GenAI基础模块

在本节课中,我们将学习如何利用Whisper CPP转录库,为提示工程构建基础模块。我们将通过一个具体的应用场景——处理医疗音频记录,来演示如何将音频文件转换为文本,并整合到生成式人工智能工作流中,同时确保数据处理的本地化和安全性。

构建基础模块的流程概述

上图展示了一个利用Whisper CPP转录库为提示工程构建基础模块的流程图。这是一个重要但容易被忽略的细节。

假设你是一名医生,拥有大量患者档案或与患者会话的录音。你如何在生成式人工智能系统中实际应用这些资料?

第一步:音频格式转换 🎵

首先,你需要将视频或音频文件转换为WAV格式。以下是一段Bash脚本,它可以遍历一个包含大量不同患者录音文件的目录,并将它们批量转换为正确的格式。

# 示例:遍历目录并转换音频格式
for file in /path/to/patient/recordings/*.mp3; do
    ffmpeg -i "$file" "${file%.mp3}.wav"
done

第二步:使用Whisper CPP进行转录 📝

转换格式后,我们便可以使用Whisper CPP进行转录。Whisper CPP的优势在于其优化后的速度、丰富的模型选择(从微型模型到巨型模型)以及出色的转录性能。

我们可以再次使用脚本,遍历包含WAV文件的目录,为每个文件生成独立的转录文本。

# 示例:使用Whisper CPP转录WAV文件
for wav_file in /path/to/converted/*.wav; do
    ./whisper-cpp -m models/ggml-base.bin -f "$wav_file" -otxt
done

第三步:转录文本的后处理与整合 📄

转录完成后,我们可以选择就此停止,也可以进行后续的生成式AI处理。另一种常见做法是将所有独立的转录文本合并成一个主文档。这取决于我们处理的具体任务以及可用的大语言模型上下文窗口大小。

例如,我们可以将所有转录文本合并到一个名为 all_transcripts.txt 的文件中。

第四步:构建提示词并生成分析报告 🤖

现在,我们可以利用整合后的文本来构建提示词。假设我是一名放射科医生,希望从这些记录中寻找特定模式,以生成患者评估报告,判断哪些患者需要进一步检查。

我会将 all_transcripts.txt 的内容输入给一个大语言模型,并给出如下提示:

阅读这些转录文本,并为所有不同的患者生成一份患者评估报告。

关键点:这项工作可以使用本地部署的大语言模型完成。对于医疗转录等敏感数据,你可能担心将其上传到云端系统的法律风险。使用本地模型可以生成自动化的患者评估报告,而无需在数据安全上妥协。

核心价值与总结

使用开源工具的关键组成部分之一,就是利用这些基础模块,并结合人们已经使用了几十年的常规自动化技术。

以下是构建此类工作流时推荐使用的技术:

  • 使用Bash进行文件操作和批量处理。
  • 使用脚本语言(如Python)实现复杂逻辑。
  • 使用DevOps技术实现流程自动化。

你可以看到,这种非常简单的自动化形式,极大地赋能了生成式AI工作流。现在,你可以将所有的转录文本整合在一起,创建一个复杂的提示词,并且让整个流程在本地运行。这样,你在处理医疗转录等敏感事务时,就无需在合法性上做出妥协。

本节课中,我们一起学习了如何利用Whisper CPP将音频数据转换为文本,并通过自动化脚本将其整合,最终作为提示词输入给本地大语言模型,以构建安全、高效的生成式AI应用模块。这体现了将传统自动化与前沿AI技术结合的巨大潜力。

开源大语言模型方案:P28:28_02_05:使用Whisper CPP进行转录 🎤

在本节课中,我们将学习如何使用 Whisper.cpp 项目,这是一个将转录功能的大型语言模型封装在高效C++外壳中的工具。我们将了解其优势、如何获取与运行,并探讨其在构建生成式AI工作流中的应用。

项目概述与优势

Whisper.cpp 项目能够将现有的、用于转录的大型语言模型包装在一个高性能的 C++ 外壳中。

以下是该项目的主要优势:

  • 纯C++实现:没有任何外部依赖。
  • Apple芯片支持:在M系列芯片上运行良好。
  • 出色的GPU性能:在GPU上具有极高的性能表现。
  • 其他优秀特性:项目内部还包含许多其他优点。

快速开始指南

上一节我们介绍了Whisper.cpp的优势,本节中我们来看看如何开始使用它。要开始使用,你需要克隆项目仓库并下载转换为 GGML 格式的模型。

这里使用的是基础模型,但还有其他模型可供选择,例如稍后会展示的 tiny 模型,以及更大的模型。令人惊讶的是,tiny 模型实际上非常有效。

运行Tiny模型示例

接下来,让我们具体看看这个 tiny 模型能做什么。这里有一个沙盒环境,我已经编译好了Whisper.cpp。

在这个目录中,我编译了Whisper。要运行它,我只需执行 ./main -m 命令,然后在这里指定模型路径。例如,我会输入 models/ 并指定使用 tiny 模型。

我们可以查看一下这个模型的大小,以了解其体积。执行命令 du -sh 查看 tiny 模型的大小,可以看到它只有 74 MB。尽管体积小,它却能完成非常精确的转录任务。

因此,对于嵌入式设备或小型实验环境来说,这是一个非常有效的转录工具。

执行转录操作

我们下一步要做的是给它输入一个 WAV 音频文件。你可以复制多个此音频文件,上传不同的WAV文件等,以测试不同的工作流程。

核心思想是,你能够运行这个程序。即使在CPU上,它也能以相当不错的性能完成转录,并生成带时间戳的文本。在这个例子中,它处理了一段著名的GFK演讲,并成功输出了转录文字。

应用场景与总结

你可能会问,为什么要这样做?这是构建生成式AI工作流的基本要素。例如,你可以给它一个装满文件的目录,然后将所有这些文件合并成一个主要的转录文本,再输入提示词来获取更多灵感。

对于想要开始构建自己独立的生成式AI工作流的人来说,这是一个极好的起点。

本节课中我们一起学习了Whisper.cpp的安装、运行及其在音频转录中的应用。请查看 whisper.cpp 项目以获取更多信息。

开源大语言模型方案:P29:29_03_01:引言_4

概述

在本节课中,我们将要学习在浏览器中运行大型语言模型(LLM)的基本概念、优势以及实现方法。我们将重点介绍一个名为Transformers.js的JavaScript库,它能够帮助我们在浏览器环境中轻松地加载和使用来自Hugging Face等平台的模型。

在浏览器中使用模型的意义

在浏览器中直接使用模型是一个非常有趣的方法。这种方法可以解决一些需要交互性的有趣问题。将模型置于浏览器中,可以提供一个兼容层,让你能够直接将模型部署在浏览器里,而无需担心通常与模型交互相关的底层基础设施问题。

例如,你无需处理GPU或系统资源等复杂问题。这为开发者带来了极大的便利。

可实现的方案与工具

以下是我们可以通过浏览器模型实现的一些不同功能。我们将主要通过Transformers.js这个JavaScript库来探索其中的部分功能。

  • Transformers.js:这是一个JavaScript库,它提供了一个简洁的抽象层,使我们能够以编程或动态的方式轻松地从平台(如Hugging Face)获取模型。
  • 动态加载模型:通过Hugging Face这样的平台,我们可以挑选和选择所需的模型,并动态地将它们加载到浏览器中。
  • 与模型交互:加载模型后,我们便可以在浏览器环境中直接与这些模型进行交互。

总结

本节课中,我们一起学习了在浏览器中运行大型语言模型的核心概念。我们了解到,这种方法可以绕过复杂的后端基础设施,直接在客户端实现模型交互。我们还介绍了Transformers.js这一关键工具,它能够帮助我们便捷地从Hugging Face等平台动态加载模型并在浏览器中使用。

开源大语言模型方案:P30:30_03_03:什么是Transformers.js 🚀

在本节课中,我们将要学习一个名为Transformers.js的JavaScript库。这个库允许我们在浏览器中直接加载模型,并使用JavaScript与模型进行交互。这与我们之前需要依赖其他系统工具的运行方式完全不同。

概述

Transformers.js是一个基于浏览器的库,它让我们能够直接在网页环境中运行机器学习模型。这意味着用户无需安装任何额外的软件或依赖服务器端处理,所有计算都在本地浏览器中完成。

核心要求:ONNX运行时

上一节我们介绍了Transformers.js的基本概念,本节中我们来看看使用它的一个核心前提条件。Transformers.js要求我们使用ONNX运行时。这是一个实现细节,但至关重要。

核心公式/概念

Transformers.js 运行条件 = 模型必须基于 ONNX 格式

这意味着,任何我们想要在Transformers.js中交互的模型,都必须转换为ONNX格式。幸运的是,Hugging Face等平台使得这种转换变得非常容易。虽然存在多种转换方法,但将模型转换为ONNX是使用此库的必要步骤。

获取与使用模型

一旦决定使用Transformers.js,下一步就是引入你想要工作的模型。

以下是获取和使用模型的步骤:

  1. 选择模型:在Hugging Face等模型库中,寻找标有ONNX格式的模型。例如,课程中演示的“基于BERT的多语言情感分析”模型。
  2. 确认格式:在模型页面,确认其文件格式为ONNX,并且任务类型(如文本分类)被支持。
  3. 注意模型大小:由于模型将直接在浏览器中下载和加载,其文件大小是一个重要考量因素。例如,演示中的完整模型约为670MB,而其量化版本仅为169MB。量化是一种压缩技术,能在轻微影响精度的情况下显著减小模型体积。

功能与应用示例

Transformers.js的功能不仅限于文本分析。在官方文档和示例中,你可以找到丰富的演示。

以下是一些有趣的应用方向:

  • 语音识别
  • 浏览器内的文本补全
  • 以文搜图
  • 以及许多其他任务

你可以浏览这些在线演示,亲身体验Transformers.js的各种实现,这有助于激发你将此技术集成到自己项目中的灵感。

总结

本节课中我们一起学习了Transformers.js库。我们了解到它是一个纯浏览器端的JavaScript库,允许直接加载并与ONNX格式的模型进行交互。我们讨论了使用它的核心前提(ONNX运行时),查看了如何获取和选择模型,并特别提醒了需要注意的模型大小问题。最后,我们预览了该库广泛的应用可能性。掌握Transformers.js为在Web应用中便捷地部署AI功能打开了新的大门。

开源大语言模型方案:P31:什么是ONNX 🧠

在本节课中,我们将要学习ONNX(Open Neural Network Exchange)格式的基本概念,了解它如何帮助我们在不同框架和硬件架构之间部署机器学习模型。我们将重点介绍如何结合Hugging Face库使用ONNX,并探索相关的配置和模型库。


概述

ONNX是一种开放的模型格式,旨在实现不同机器学习框架(如PyTorch、TensorFlow)之间的互操作性。通过将模型导出为ONNX格式,我们可以将其部署到多种硬件和运行时环境中,而无需依赖原始的框架。本节课将引导你了解ONNX的核心概念、如何设置环境,以及如何开始使用Hugging Face的transformers库与ONNX进行交互。


环境设置与依赖安装

上一节我们介绍了ONNX的基本概念,本节中我们来看看如何设置工作环境。为了使用Hugging Face和ONNX,我们需要安装特定的依赖包。

以下是创建一个Conda环境所需的依赖项,它们被定义在一个YAML配置文件中:

name: onnx_env
channels:
  - pytorch
dependencies:
  - python=3.8
  - pytorch
  - transformers[onnx]
  - onnxruntime
  - ipykernel

这个环境文件指定了Python 3.8、从PyTorch渠道安装的PyTorch、带有ONNX额外功能的Hugging Face transformers库、ONNX运行时以及用于Jupyter Notebook的组件。安装这些依赖后,你就可以快速开始工作了。


验证安装与探索功能

环境设置完成后,我们需要验证所有组件是否安装正确,并探索可用的功能。

你可以通过命令行工具来验证transformers库的ONNX模块是否已成功安装。运行以下命令可以查看帮助菜单:

python -m transformers.onnx --help

这个命令的输出会显示可用的选项和参数。关键点包括:

  • 你可以指定从PyTorch或TensorFlow导出模型(本教程默认使用PyTorch)。
  • 你需要使用一个位置参数来指定输出ONNX模型的名称。

理解模型配置

在开始导出模型之前,理解模型的配置至关重要。Hugging Face为许多流行模型(如BERT、GPT-2、RoBERTa、T5)提供了预定义的配置。

以下是如何导入和查看RoBERTa模型配置的示例代码:

from transformers.models.roberta import RobertaConfig, RobertaOnnxConfig

# 查看可用的配置特性
config = RobertaOnnxConfig(RobertaConfig())
print(config)

这段代码允许你查看该模型可用于ONNX导出的不同特性和设置。选择合适的配置是成功导出模型的第一步。


ONNX模型库简介

除了自己导出模型,我们还可以利用现有的ONNX模型库。ONNX维护了一个官方的模型库,称为ONNX Model Zoo。

ONNX Model Zoo是一个GitHub仓库(onnx/models),其中存储了许多预训练的ONNX格式模型。例如,你可以找到用于机器阅读理解任务的RoBERTa模型。每个模型页面通常会提供以下信息:

  • 模型描述用途
  • 所需的依赖项
  • 支持的ONNX版本Opset版本(这是两个关键的技术细节)
  • 关于预处理预期输出的说明
  • 下载链接(模型通常使用Git LFS存储)

许多模型库中的模型本身就基于Hugging Face transformers构建,因此你可以轻松地使用熟悉的工具(如分词器)与之配合。


总结

本节课中我们一起学习了ONNX的核心价值——作为桥梁促进不同机器学习框架的模型互操作与部署。我们完成了从设置Python环境、安装必要的库(如transformers[onnx]onnxruntime),到验证安装并探索命令行工具的过程。我们还了解了如何利用Hugging Face提供的预配置来简化ONNX导出,并介绍了ONNX官方模型库(Model Zoo)作为获取预转换模型的资源。掌握这些概念是后续进行模型导出、优化和跨平台推理的基础。

开源大语言模型方案:P32:将模型导出为ONNX格式 🚀

在本节课中,我们将学习如何将Hugging Face上的预训练模型导出为ONNX格式。ONNX是一种开放的模型格式,旨在提高模型在不同框架和硬件平台之间的互操作性。通过将模型转换为ONNX,我们可以更灵活地部署和优化模型。


准备工作与环境配置

首先,确保你拥有正确的运行环境。在本示例中,我们使用一个已安装所有必要依赖的Conda环境内核。这是顺利进行后续操作的基础。

探索模型支持的任务特性

上一节我们介绍了环境配置,本节中我们来看看如何确定模型支持的任务类型。理解模型能处理的任务对于后续的导出操作至关重要。

我们需要从transformers.onnx模块中导入features模块,具体来说是导入一个FeaturesManager。通过它,我们可以查看特定模型(例如distilbert-base-cased)支持哪些功能特性。

# 示例:导入FeaturesManager
from transformers.onnx import FeaturesManager

运行上述代码后,我们可以查看该模型支持的任务。常见的任务包括:

  • 序列分类
  • 多项选择
  • 标记分类
  • 问答 - 这是我们将要使用的任务类型。

了解模型支持的任务之所以重要,是因为在导出模型时,我们需要明确指定目标用途。例如,如果我们只需要一个用于问答任务的模型,就可以在导出时精确指定,从而得到一个更精简、针对性更强的ONNX模型。

使用命令行工具导出模型

在明确了模型的任务特性后,我们现在开始进行实际的导出操作。我们将使用transformers.onnx模块作为命令行工具来完成这个步骤。

以下是导出命令的核心组成部分和步骤解析:

  1. 调用工具:使用python -m transformers.onnx来运行该模块。
  2. 指定模型:通过--model参数指明要导出的模型。在本例中,我们使用的是distilbert-base-cased-finetuned-sst-2-english
  3. 指定任务:通过--feature参数声明模型用途。这里我们选择question-answering(问答)。
  4. 指定输出路径:命令末尾的.点号表示将生成的ONNX模型文件保存在当前目录。你也可以指定一个具体的路径和文件名。

完整的导出命令示例如下:

python -m transformers.onnx --model=distilbert-base-cased-finetuned-sst-2-english --feature=question-answering .

执行此命令后,程序会首先下载指定的模型,然后开始转换过程。这个过程可能需要几秒钟时间。

验证导出结果

命令执行完成后,我们需要在输出信息中确认模型是否成功导出并验证通过。

请关注输出信息的末尾部分,寻找类似“All good, model saved at ...”和“Validating ONNX model...”的成功提示。这些信息表明模型已顺利通过验证并保存。

同时,输出中还会列出生成的ONNX模型文件的输入输出名称,这些信息在后续使用该ONNX模型时是必需的。

回到文件浏览器,你可以看到当前目录下新生成了一个.onnx文件,这就是我们成功导出的、可用于问答任务的ONNX格式模型。


本节课中我们一起学习了将Hugging Face模型导出为ONNX格式的完整流程。我们首先探索了模型的任务特性,然后使用命令行工具指定模型和任务进行导出,最后验证了导出结果。通过这种方式,我们可以将Transformer模型便捷地转换为更具部署灵活性的ONNX格式。

开源大语言模型方案:P33:在浏览器中使用Transformers.js 🚀

概述

在本节课中,我们将学习如何使用Transformers.js库在浏览器中直接运行机器学习模型。我们将通过一个具体的、可操作的示例——在Hugging Face平台上创建一个“Space”并部署一个物体检测应用——来演示整个过程。你将看到如何利用现成的模板快速构建一个无需后端服务器、完全在浏览器中运行的AI应用。


在Hugging Face平台创建演示空间

上一节我们介绍了Transformers.js的基本能力,本节中我们来看看如何将其付诸实践,创建一个可交互的在线演示。

通过Transformers.js,你可以在浏览器中运行模型。我们已经了解了一些它能做的事情,现在我将展示一个具体的操作。我们将基于官方文档中的示例,运行一个模板。

我滚动到文档页面的底部。你可以在这里创建一个新的“Space”。Hugging Face平台提供了这个非常棒的功能,他们称之为“Spaces”,你可以在浏览器中甚至配合后端应用来运行模型。但本次我们将专注于Transformers.js。

我将点击“Template”按钮。我已经登录了我的账户。界面会显示“Create a new space”。我将其命名为“demo-transformers”。

然后选择一个许可证,MIT许可证即可。可以看到,它已经自动选择了“Static Website”类型,并且正在使用Transformers.js,这非常好。

这样做的好处是,它已经由平台提供的硬件支持,并且因为我有账户,可以免费使用。你可以看到这是免费的,我不需要支付任何费用。这个仓库(或空间)将是公开的。我点击“Create Space”。

创建完成后,它会加载这个应用程序。


运行物体检测演示

那么这个演示具体会做什么呢?它将使用Transformers.js进行物体检测。

我可以上传一张图片,或者尝试一个已有的示例。这个应用已经在浏览器中准备就绪。我点击“Try an example”。现在它加载完成了,你可以看到Transformers.js及其背后的模型正在进行大量检测。

检测结果显示:这是一个交通信号灯、一盏灯、一个人、一辆自行车。这里有一个不准确的检测——它把一幅自行车的图画识别成了真实的自行车,但这没有问题。这有效地展示了它的运行方式,并且你拥有一个实时演示。


查看应用文件结构

现在我想展示一下文件结构。因为我放大了视图,你看不到它们,我会暂时缩小一下,然后展示文件。

当我查看文件时,这就是实际的应用。在这个案例中,所有的示例文件都已准备就绪,使我能够快速启动应用。

让我展示一下它的样子:这是index.html文件。你可以看到里面有一些HTML代码,那就是我们刚才看到的演示界面。而index.js文件则是所有魔法发生的地方。

index.js的代码中,我们导入了transformers库并启动它。我们实际使用的模型是EfficientDet (ResNet-50),这就是执行物体检测的模型。你可以看到这里的pipeline函数,它定义了我们要从这个模型执行的具体任务(物体检测),整个应用就是这样联系起来的。


总结

本节课中我们一起学习了如何利用Transformers.js在浏览器中运行AI模型。我们通过一个具体的物体检测示例,演示了如何在Hugging Face平台上快速创建和部署一个“Space”。这种方法非常快捷、简便,让你能够直接在浏览器中尝试各种模型,并且得益于Hugging Face平台提供的托管服务,整个过程运行顺畅且无需复杂的后端配置。

开源大语言模型方案:P34:34_03_08_总结_2

📚 概述

在本节课中,我们将总结在浏览器中直接运行大型语言模型的关键要点,特别是使用 Transformers.js 的方法与前提条件。我们将回顾核心概念,并了解如何轻松地开始实践。

🧠 核心要点总结

我们看到了如何直接在浏览器中使用这些模型,特别是通过 Transformers.js

但这里有一个关键要求,那就是使用 ONNX 格式。这些模型必须被转换并移植到 ONNX 格式上。我们还简要介绍了如何开始将一些现有模型转换为 ONNX 格式,以便在 ONNX 运行时上使用。

这正是 Transformers.js 能够在浏览器中使用模型的关键:它要求模型必须是 ONNX 格式。因为其底层技术依赖于浏览器中的 ONNX 运行时

现在,需要特别注意模型的大小,这一点非常重要。请务必意识到模型大小对浏览器端运行的影响。

🚀 快速入门演示

我也非常高兴地向大家展示,入门是多么简单。

Hugging Face 平台提供了 Spaces 解决方案,它允许我们上传一些文件并与模型交互,从而非常轻松、直接地构建应用,几乎不费吹灰之力。

✅ 总结

本节课中,我们一起学习了在浏览器中运行模型的核心要求——ONNX 格式,认识了 Transformers.js 的关键作用,并了解了通过 Hugging Face Spaces 可以如何快速、简便地开始实践。请记住,始终关注模型大小以确保良好的用户体验。

开源大语言模型方案:P35:使用Cosmopolitan构建短语生成器 🛠️

在本节课中,我们将学习如何使用Cosmopolitan可移植二进制框架来构建一个简单的短语生成器命令行工具。我们将了解其基本结构、编译过程以及如何运行生成的跨平台二进制文件。

概述

Cosmopolitan框架能帮助开发者构建可移植的二进制文件。本节将演示如何用它创建一个简单的短语生成器工具。该工具允许用户指定重复次数和短语,并能在Windows、Linux、Unix等多种操作系统上运行。

代码结构与解析

首先,我们来看一下构建此工具所需的C语言源代码的基本结构。

头文件引入

代码开头引入了必要的标准库头文件。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
  • stdio.h 用于输入输出操作。
  • string.h 用于字符串函数,例如字符串比较。
  • stdlib.h 用于声明工具函数,例如 atoi,它用于将字符串转换为整数。

核心功能函数

接下来,我们定义了一个核心函数,用于重复输出指定的短语。

void repeat_phrase(int count, const char* phrase) {
    for (int i = 0; i < count; i++) {
        printf("%s\n", phrase);
    }
}

这个 repeat_phrase 函数接受一个整数 count 和一个字符串指针 phrase 作为参数。它通过一个 for 循环,将短语打印输出指定的次数。

主函数逻辑

主函数 main 包含了程序的入口逻辑,负责解析命令行参数并调用相应的功能。

int main(int argc, char *argv[]) {
    int count = 1; // 默认重复次数
    const char* phrase = "Hello, World!"; // 默认短语

    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--count") == 0 || strcmp(argv[i], "-c") == 0) {
            if (i + 1 < argc) {
                count = atoi(argv[i + 1]);
                i++; // 跳过下一个参数(数值)
            }
        } else if (strcmp(argv[i], "--phrase") == 0 || strcmp(argv[i], "-p") == 0) {
            if (i + 1 < argc) {
                phrase = argv[i + 1];
                i++; // 跳过下一个参数(短语)
            }
        }
    }

    // 生成短语
    repeat_phrase(count, phrase);
    return 0;
}

程序逻辑如下:

  1. 设置默认的重复次数(count = 1)和默认短语("Hello, World!")。
  2. 遍历所有的命令行参数(argv)。
  3. 使用 strcmp 函数进行字符串比较,判断参数是 --count(或 -c)还是 --phrase(或 -p)。
  4. 根据参数类型,读取其后的值,并更新 countphrase 变量。
  5. 最后,调用 repeat_phrase 函数,根据解析得到的参数生成并输出短语。

编译与运行

上一节我们介绍了代码的结构,本节中我们来看看如何使用Cosmopolitan框架将其编译成可移植的二进制文件。

编译命令

Cosmopolitan框架自带编译器。我们使用以下命令进行编译:

bin/cosmo-cc -o phrase_gen phrase_gen.c
  • bin/cosmo-cc 是Cosmopolitan的C语言编译器。
  • -o phrase_gen 指定输出的可执行文件名为 phrase_gen
  • phrase_gen.c 是我们的源代码文件。

执行此命令后,会生成一个名为 phrase_gen 的二进制文件,以及一些其他构建产物。这个二进制文件具有跨平台的可移植性。

运行示例

生成二进制文件后,我们可以直接运行它。以下是几个运行示例:

  1. 使用默认参数运行(输出一次“Hello, World!”):

    ./phrase_gen
    
  2. 指定重复次数为5次:

    ./phrase_gen --count 5
    

    或使用短参数:

    ./phrase_gen -c 5
    
  3. 同时指定自定义短语和重复次数:

    ./phrase_gen --phrase "LLM Ops" --count 3
    

    或使用短参数组合:

    ./phrase_gen -p "AI is great" -c 7
    

你可以自由更改次数和短语内容进行测试。

优势与应用场景

短语生成器本身是一个简单的教学示例,但它清晰地展示了Cosmopolitan框架的核心价值:一次构建,多处运行

使用此框架构建的二进制文件,可以无需修改或重新编译,直接部署到Windows、Linux、macOS、FreeBSD等多种操作系统上。这对于需要广泛分发和部署的工具软件尤其具有吸引力。

在大型语言模型(LLM)领域,这种可移植性非常重要。例如,Llama.cpp等项目就利用类似技术来确保其工具能在各种用户环境中轻松运行,降低了部署和使用门槛。

总结

本节课中我们一起学习了如何使用Cosmopolitan可移植二进制框架。我们从代码结构解析开始,了解了如何编写一个简单的命令行短语生成器,包括参数解析和功能实现。接着,我们掌握了使用Cosmopolitan专用编译器将C源代码编译成跨平台二进制文件的方法。最后,我们探讨了这种“一次构建,多处运行”的技术在LLM等实际应用场景中的优势。通过这个实践,你可以将相同的思路应用于构建更复杂的静态网站生成器、AI工具或其他需要跨平台部署的命令行程序。

大型语言模型实践:P100:GPU配额与可用性 🎮

在本节课中,我们将学习在Azure平台上工作时,如何理解和处理GPU配额问题。这对于部署生成式AI模型至关重要。

概述

在Azure上部署生成式AI模型时,GPU配额是需要重点关注的资源限制。本节将演示如何在Azure AI机器学习工作室中检查配额,并介绍当配额不足时可能的处理方式。

配额检查与部署尝试

上一节我们介绍了配额的重要性,本节中我们来看看实际操作中会遇到什么情况。

在Azure AI机器学习工作室中,当你尝试部署某些生成式AI模型时,系统会检查你的配额。例如,我们尝试部署一个名为 Miralal AI 7b instruct Per1 的模型。

点击部署并选择创建实时端点后,系统通常会提示你可能没有足够的配额来创建虚拟机。

申请更多配额

以下是申请增加配额的标准流程,但需要注意,Azure的申请方式可能随时变化。

  1. 在配额页面,找到你需要的资源系列,例如 ND A100 v4 系列 专用GPU。
  2. 点击“请求增加配额”。
  3. 填写申请表格并提交。

然而,在本课程录制时,系统可能存在一个已知问题:提交申请后可能会报错。例如,错误信息可能显示“你的支持计划类型是免费的”,即使你使用的是付费订阅。这通常是临时的系统问题。

通过门户查看配额详情

如果标准申请路径遇到问题,我们可以返回Azure门户查看更详细的配额信息。

在门户中,导航到“配额”部分。配额不仅针对GPU,但对我们而言,重点是机器学习相关的配额。

  1. 在配额页面,选择“机器学习”。
  2. 页面会列出所有类型的配额。我们可以筛选出特定的GPU系列。例如,NCv3系列 对应的是NVIDIA Tesla V100 GPU。
  3. 使用筛选功能,输入“NC”进行搜索。

筛选后,你可以看到特定区域(如美国东部)的配额详情,例如“0 / 12”,表示该区域该类型GPU的已用量和总配额。

区域选择的重要性

从这里可以看出,区域是配额管理的关键。不同区域的GPU可用性完全不同。

如果你在某个区域配额不足,可以尝试切换到有可用配额的其他区域来创建Azure机器学习工作室资源。这能让你获得所需的计算资源类型。

配额调整的限制

需要注意的是,并非所有配额都能直接通过门户申请调整。有时,系统会提示你需要返回Azure机器学习工作室内提交申请。这体现了不同服务之间配额管理流程的差异。

总结

本节课中我们一起学习了:

  • 在Azure AI机器学习工作室部署模型时会触发配额检查。
  • 如何通过标准流程申请增加配额,并了解可能遇到的临时问题。
  • 如何通过Azure门户详细查看特定订阅特定区域下的机器学习与GPU配额。
  • 理解了区域选择对资源可用性的决定性影响。

掌握这些知识,你将能够更好地规划资源,并成功部署所需的生成式AI模型计算实例。

大型语言模型实践:P101:创建计算资源 💻

在本节中,我们将学习如何在Azure机器学习工作室中创建并配置一个计算实例。这个计算实例将作为我们后续部署和运行大型语言模型的基础计算资源。

概述

我们将逐步完成在Azure机器学习工作室中创建GPU计算实例的过程,包括选择机器类型、配置参数以及了解创建后的管理选项。这是运行计算密集型任务(如大型语言模型)的关键第一步。

创建计算实例

上一节我们介绍了Azure机器学习工作室的界面,本节中我们来看看如何创建一个具体的计算资源。

首先,在Azure机器学习工作室中,向下滚动到“管理”区域,然后点击“计算”选项。

点击后,将进入计算管理页面。为了运行后续任务,我需要创建一个正在运行的计算实例。因此,点击“新建”按钮来创建新的计算实例。

配置计算实例

以下是配置计算实例时需要设定的几个关键参数:

  1. 命名:可以为计算实例命名。通常可以使用像“GPU”这样的名称,以帮助识别所创建资源的用途。
  2. 选择虚拟机类型:将虚拟机类型选择为“GPU”。选择后,列表会被筛选,只显示可用的GPU选项。
  3. 选择具体规格:在可用选项中,选择“Standard_NC6s_v3”规格。虽然可能存在更便宜的选项(如Tesla B100),但可能受到配额限制。Standard_NC6s_v3 规格目前可用且合适。

在选择规格后,可以点击“查看并创建”来确认配置。

高级设置与资源配置

在创建前,可以查看和设置一些高级选项。

一个非常有用的功能是“空闲时自动关闭”。可以设置为在60分钟无活动后自动关闭实例以节省成本。当然,也可以根据需要更改此设置。

此外,还可以启用SSH访问,以便直接登录到虚拟机进行管理。

现在,让我们查看所选虚拟机的详细资源配置:

  • 核心数:6个vCPU
  • 内存:112 GB RAM
  • 存储:336 GB 存储空间

这是一个相当不错的入门级GPU配置,足以支持我们进行几次大型语言模型的部署和交互。

确认所有配置无误后,点击“创建”按钮。

等待创建完成

创建过程就像在云中启动任何常规虚拟机一样,需要几分钟时间。一旦创建完成,我们就可以使用这个计算实例来实际部署大型语言模型。

让我们稍等片刻,直到它完成创建。

管理已创建的计算实例

现在,虚拟机已经创建完毕并处于运行状态。界面中可能会显示一些可以在此机器上运行的应用程序,但目前我们不需要启动它们。

点击计算实例名称,可以查看和管理它。

在管理界面中,可以执行以下操作:

  • 监控任务:查看在此实例上运行的作业。目前没有任务,因为这是一个全新的实例。
  • 管理生命周期:可以停止、重启或删除该实例。
  • 查看成本与信息:可以看到该实例运行时的成本约为每小时4美元。同时,可以查看其内部IP地址和所关联的特定订阅信息。

这些信息对于资源管理和成本控制非常重要。

总结

本节课中我们一起学习了在Azure机器学习工作室中创建计算实例的完整流程。我们首先导航到计算管理页面,然后逐步配置了实例的名称、GPU类型和具体规格(Standard_NC6s_v3)。接着,我们查看了包括自动关机在内的可选设置,并确认了虚拟机的核心数、内存和存储配置。最后,我们创建了实例,并了解了创建后如何对其进行基本管理,如监控任务和查看成本。现在,这个配置了Tesla V100 GPU的计算实例已经准备就绪,可以用于后续部署大型语言模型的实际操作了。

大型语言模型实践:P102:部署模型 🚀

在本节课中,我们将学习如何在Azure机器学习工作室中,从模型目录直接部署一个预训练模型。我们将以部署Microsoft Research的Phi-2模型为例,创建一个实时推理端点,并了解部署完成后的关键信息。

从模型目录部署

上一节我们介绍了Azure机器学习工作室的基础环境。本节中我们来看看如何利用模型目录直接部署预训练模型。

在Azure机器学习工作室的模型目录中,除了之前部署的计算资源(可用于执行多种任务),还提供了直接部署模型的能力。这种部署方式与先创建计算资源再部署自定义模型不同,可以直接从目录中选择并部署。

以下是部署步骤:

  1. 在模型目录中,可以通过筛选功能快速定位目标模型。例如,选择“Microsoft Research”集合。
  2. 从结果中找到并点击目标模型,例如“Phi-2”。
  3. 点击“部署”按钮,开始配置。

配置实时端点

选择了模型后,下一步是配置部署细节,核心是创建一个实时推理端点。

点击部署后,选择“实时端点”作为部署类型。系统会检查配额,确保有足够的资源进行部署。例如,本次部署将使用NC6s_v3系列的计算核心。

配置端点时,需要创建一个新的端点,也可以选择附加到现有端点。端点名称必须是全局唯一的,这个名称将构成最终API地址的一部分,用于后续调用。

其他设置如推理数据收集和模型打包,可以根据需要选择是否启用。完成配置后,点击“部署”按钮,系统将开始部署流程,此过程需要一些时间。

验证与使用端点

部署成功后,我们可以在端点详情页验证其状态并获取使用信息。

部署状态显示为“成功”且状态为“实时”,表示端点已就绪。流量分配初始为0,因为尚未有请求发送。

端点的身份验证类型默认为密钥认证,也可以根据需要更改为基于令牌的认证。详情页提供了Swagger文档的URL,可用于查看API的详细说明。最重要的信息是REST端点URL,这就是我们与之交互的地址。

本节课中我们一起学习了在Azure机器学习工作室中从模型目录部署预训练模型的全过程,包括选择模型、配置实时端点以及部署成功后验证和获取调用信息。下一节,我们将学习如何实际调用这个端点来使用模型。

大型语言模型实践:P103:使用推理API

概述

在本节课中,我们将学习如何在Azure AI机器学习工作室中,对已部署的模型进行测试和消费。我们将了解如何检查部署状态、查看监控日志,并使用提供的代码示例通过推理API与模型进行交互。


回到Azure AI机器学习工作室,我们的模型已经部署了一段时间。

我们获得了实时流量位置,并且状态显示为绿色。获得这个绿色的勾选标记很重要,因为当它出现且预配状态显示为“成功”时,意味着我们实际上可以测试、消费、检查监控和日志。我已经对这些端点进行了一些尝试。如果我查看日志,你会看到虽然存在一些问题,比如这里看到的一些异常,但总体上已有一些成功的请求。

因此,监控非常有趣。你会看到我每分钟发出多个请求,虽然不算非常多,但你可以查看这里的一些信息。如果你想检查延迟和收到的请求数量,并希望获得更多细节,则需要在Azure监控中查看。我现在不打算深入做这件事,我们将重点看看测试部分。

测试已部署的模型

上一节我们确认了模型部署成功,本节中我们来看看如何进行测试。

部署选项就是我们唯一可用的这一个,这就是我们得到的结果。如果你只是想获取一些数据并测试它、获得一些结果,这样就可以了。

如果我们想以另一种不同的方式消费这个模型,我们可以实际查看这里,获取主密钥、次密钥以及实际的端点地址。这些信息都很好。

然而,当你拥有像这样的原始信息来通过API进行交互时,可能会遇到麻烦,因为你可能希望有更简单的方法进行测试。

幸运的是,我们这里有消费选项,并且提供了Python、C#和R的代码示例。

以下是Python消费示例的代码片段:

import requests
import json

# 设置端点URL和API密钥
url = "YOUR_ENDPOINT_URL"
api_key = "YOUR_API_KEY"  # 需要从部署页面获取并填入

headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {api_key}'
}

# 准备请求数据
data = {
    "input_data": {
        # 根据你的模型输入格式填写
    }
}

response = requests.post(url, headers=headers, data=json.dumps(data))
print(response.json())

让我们看看Python示例,这里已经有一个完整的脚本,我们可以复制并运行。脚本中包含了我们的URL,以及获取API密钥的能力。实际上,让我们看看这些密钥在哪里。

获取API密钥。让我快速看一下。API密钥……哦,对了。

在第27行,你可以看到这是一个空字符串。这意味着你可能需要硬编码你的API密钥,这个密钥来自页面顶部。

如果我们到这里查看主密钥,你可以使用主密钥或次密钥,都没有问题。

执行测试并理解结果

准备好脚本后,我们最终将尝试进行测试。但仅仅这样还不够。

如果我们像这样尝试测试,由于没有输入数据,我们将得到零个结果项。

让我们尝试粘贴一些我之前准备好的数据。也许这些实际上是模型参数,如果你想调整模型的话。我目前不想调整任何东西。

我将快速测试一下,然后我们会得到一些响应。

目前的响应并不相关。这只是为了向你提供一个如何实际测试的示例。

因此,当一切都已经部署并准备就绪后,你有几个不同的方面可以探索:如果你想测试,可以前往测试部分;如果你想输入一些数据,可以前往消费部分;如果你想编写脚本,可以根据你想要尝试的操作,使用多种不同类型的输入数据。

例如,我们可以尝试输入“name”,然后……嗯,这无效,因为我留下了一个逗号。再次测试,然后我们得到了结果……实际上没有生成任何有意义的内容。

好的,以上就是你如何开始消费一个从模型目录部署到机器学习工作室中的模型。

大型语言模型实践:P104:总结与部署要点

在本节课中,我们将总结在Azure平台上部署模型的关键步骤与注意事项。我们将回顾从创建资源到通过HTTP API调用模型的完整流程,并讨论在部署过程中可能遇到的资源配额与可用性挑战。

部署流程回顾

上一节我们介绍了Azure机器学习工作室的具体操作,本节中我们来总结核心的部署步骤。

以下是部署模型到Azure的主要步骤序列:

  1. 创建资源:在Azure机器学习工作室中初始化所需的工作区与计算资源。
  2. 选择模型:从模型库或上传的模型文件中选定需要部署的特定模型。
  3. 部署模型:将选定的模型部署到指定的计算目标(如Azure容器实例或Azure Kubernetes服务)。
  4. 使用HTTP API:模型部署成功后,获取评分终结点(Scoring Endpoint)并通过发送HTTP POST请求来调用模型。一个简单的Python请求示例如下:
    import requests
    import json
    
    url = ‘你的模型终结点URL’
    headers = {‘Content-Type’: ‘application/json’}
    data = {“input_data”: “你的输入数据”}
    
    response = requests.post(url, headers=headers, data=json.dumps(data))
    print(response.json())
    

部署挑战与应对策略

整个部署流程的实现,依赖于你是否拥有实际部署这些模型所需的配额。云环境,特别是Azure平台,变化迅速。对GPU资源的需求巨大,有时配额和资源可用性会成为棘手问题。

不过,我们探讨了一些可以缓解此问题的策略,这些策略能在你尝试部署模型时提供一定的灵活性。以下是关键应对措施:

  • 提前规划与申请:在项目开始前,评估所需GPU类型与数量,并通过Azure支持渠道提前申请增加配额。
  • 选择替代SKU:如果首选GPU虚拟机系列(如NCas_T4_v3)配额不足,可以尝试功能类似的其他系列(如NC_A100系列,若有配额)。
  • 利用不同区域:Azure各数据中心的资源可用性不同。尝试在多个区域创建资源,可能在某些区域有可用配额。
  • 考虑低优先级虚拟机:对于非紧急或可中断的工作负载,使用低优先级(Spot)虚拟机可以显著降低成本并可能提高资源获取成功率。

本节课中我们一起学习了在Azure上部署机器学习模型的完整流程,并重点讨论了因GPU高需求导致的配额与可用性挑战及其应对策略。理解这些步骤和潜在问题,将帮助您更顺利地在云平台上进行模型部署与集成。

大型语言模型实践:1:Azure OpenAI服务入门指南 🚀

在本节课中,我们将学习如何开始使用Azure OpenAI服务。我们将从获取服务访问权限开始,介绍创建服务资源的最简单方法,并尝试在Playground中部署模型。通过本教程,你将了解Playground是什么,以及如何与之交互。请注意,我们并非创建自己的模型,而是在Azure OpenAI服务中创建OpenAI模型的部署实例。


上一节我们介绍了本课程的目标,本节中我们来看看访问Azure OpenAI服务的具体步骤。

访问Azure OpenAI服务

要使用Azure OpenAI服务,首先需要获取访问权限。这通常涉及在Azure门户中创建相应的资源。

以下是创建Azure OpenAI服务资源的关键步骤:

  1. 登录到Azure门户。
  2. 在市场中搜索“Azure OpenAI”。
  3. 按照向导创建新的OpenAI服务资源。
  4. 在创建过程中,选择合适的地域和定价层。

创建完成后,你将获得访问服务所需的终结点和密钥。


了解了如何获取服务访问权限后,接下来我们看看如何部署模型。

部署模型与使用Playground

在Azure OpenAI服务中,你可以部署预训练的模型(如GPT系列)。部署后,可以通过Playground进行交互测试。

Playground是一个基于Web的界面,允许你以直观的方式配置模型参数、输入提示词并查看模型的生成结果。

以下是使用Playground的基本流程:

  1. 在Azure OpenAI服务资源页面,导航到“Playground”部分。
  2. 选择你想要部署和测试的模型,例如 gpt-35-turbo
  3. 调整参数,如 temperature(温度)和 max_tokens(最大生成长度)。
  4. 在输入框中键入提示词,例如:“请用中文解释人工智能。”
  5. 点击“生成”按钮,查看模型的回复。

通过Playground,你可以快速验证模型部署是否成功,并熟悉其基本功能。


本节课中我们一起学习了Azure OpenAI服务的入门知识。我们了解了如何获取服务访问权限、创建服务资源,以及如何在Playground中部署和测试模型。这些是开始利用Azure平台强大语言模型能力的基础步骤。

大型语言模型实践:P106:获取Azure OpenAI服务访问权限 🔑

在本节课中,我们将学习如何申请并获得Azure OpenAI服务的访问权限。由于目前该服务的访问权限受到一定限制,我们将详细介绍申请流程和所需步骤。

概述

Azure OpenAI服务提供了强大的语言模型能力。要使用它,首先需要申请访问权限。本节将引导你完成整个申请过程。

访问申请流程

上一节我们介绍了Azure OpenAI服务的背景,本节中我们来看看如何具体申请访问权限。

申请访问的主要入口是Microsoft Learn平台上的Azure OpenAI服务文档页面。该页面不仅是获取访问权限的起点,也包含了服务介绍、资源创建、嵌入功能使用以及OpenAI模型应用等所有必要信息,其中快速入门指南非常实用。

以下是申请访问权限的具体步骤:

  1. 访问Azure OpenAI服务官方文档页面。
  2. 在页面的“其他资源”部分找到访问申请链接。
  3. 点击链接进入申请页面。

需要注意的是,网站结构可能发生变化。如果找不到申请链接,一个更简单易记的方法是直接访问短链接:aka.ms/oai/access。这个链接会直接跳转到申请页面。

填写申请表单

进入“申请访问Azure OpenAI服务”页面后,请仔细阅读所有说明。

以下是填写申请表单时的关键注意事项:

  • 邮箱地址:请勿使用个人邮箱地址。申请需要使用与组织或公司相关的邮箱。
  • 所需信息:你需要准备并填写个人信息(如姓名)、Azure订阅ID、公司名称、公司地址等详细信息。
  • 信息用途:所有提供的信息将用于服务审核和开通。

填写完毕后,滚动到页面底部提交申请。提交后,需要等待一段时间审核才能获得访问权限。

服务访问说明

目前,Azure OpenAI服务的注册申请存在一定的流量控制或限制。这是当前申请过程中可能遇到的情况。

为了确保你遵循的流程是最新且准确的,最佳做法是始终通过Microsoft Learn平台,搜索并进入“Azure OpenAI服务”官方文档页面,以查看最新的申请指南和要求。

总结

本节课中我们一起学习了如何申请Azure OpenAI服务的访问权限。关键步骤包括:通过Microsoft Learn文档或短链接找到申请入口,使用公司邮箱填写详细的申请表单,并耐心等待审核结果。请务必通过官方渠道获取最新信息以确保流程正确。

大型语言模型实践:P107:创建Azure OpenAI服务资源

概述

在本节课中,我们将学习如何在Azure门户中创建并配置一个Azure OpenAI服务资源。这是使用Azure OpenAI服务的第一步,我们将了解创建过程中的关键步骤和注意事项。


创建资源

首先,我们需要访问Azure门户。你可以通过搜索找到它,或者像我一样,如果之前打开过,可以直接点击进入。为了创建一个新的资源,我们需要点击“创建”按钮。

点击“创建”后,一个表单将会出现,我们需要填写必要的信息。


填写基本信息

以下是创建Azure OpenAI服务资源时需要填写的基本信息列表:

  • 订阅:从你的订阅列表中选择一个。我将使用我的演示订阅。
  • 资源组:建议为演示创建一个专门的资源组,例如“demo-openai-alfredo”。这有助于资源管理和后续清理。
  • 名称:资源名称必须是全局唯一的。例如,输入“demo”可能无法通过,因为相关的子域名已被占用。我尝试使用“demo-alfredo”,这个名称通过了验证。
  • 定价层:选择“标准”层。你可以点击“查看完整定价详情”来了解更多信息,但本节课我们不做深入探讨。

填写完基本信息后,点击“下一步”。


配置网络与标签

接下来是网络配置。默认选项是允许所有网络(包括互联网)访问此资源。你也可以选择更严格的网络限制。本节课,我们选择允许所有网络访问。

标签部分是可选的,你可以根据需要添加标签来组织资源。本节课我们不添加任何标签。

配置完成后,系统会在后台进行验证。验证通过后,点击“创建”即可开始部署。


部署与访问

Azure OpenAI服务的部署速度通常很快。部署成功后,你可以点击“转到资源”按钮。

现在,资源“demo-alfredo”已经准备就绪。有一个关键点需要注意:当你准备使用服务的API端点时,你需要使用访问密钥。这些密钥不在Azure AI Studio或Azure OpenAI Studio中,而是在Azure门户的资源管理页面里,具体位置是“密钥和终结点”。

点击“密钥和终结点”,你就能找到API密钥和终结点URL(例如 https://demo-alfredo.openai.azure.com/)。这些信息在后续调用服务时至关重要。

最后,我们可以从概述页面点击“Azure OpenAI Studio”来启动该资源的管理界面。请注意,这个界面有时也被称为“Azure AI Studio”。在这里,你可以查看配额、与模型交互,并开始使用Azure OpenAI服务。


总结

本节课中,我们一起学习了如何在Azure门户中创建Azure OpenAI服务资源。我们完成了从选择订阅、设置资源组、命名资源、选择定价层,到配置网络和最终部署的完整流程。最重要的是,我们明确了API密钥和终结点URL的查找位置,这是后续实际调用服务的基础。现在,你的Azure OpenAI服务实例已经创建成功,可以开始下一步的探索和使用了。

大型语言模型实践:1.2:部署OpenAI模型 🚀

在本节课中,我们将学习如何在Azure AI Studio中部署一个OpenAI模型。我们将从了解配额设置开始,然后一步步完成GPT-3.5 Turbo模型的部署过程,并熟悉部署后的管理界面。


配额概览与设置

在开始部署模型之前,我们需要先了解Azure AI Studio中的配额系统。配额决定了我们使用模型资源的速率限制。

上一节我们介绍了Azure AI Studio的基本界面,本节中我们来看看如何管理配额。请注意,界面名称可能从“Azure OpenAI Studio”变更为“Azure AI Studio”,但核心功能一致。

在配额页面,你会发现配额的管理方式有所不同。与由服务预设配额不同,这里允许你设置自己的限制。例如,你可能会看到类似 240,000 tokens/分钟 的总限制。这个数值单位是千。

以下是配额设置的关键点:

  • 配额以每分钟处理的令牌数为单位进行设置。
  • 你可以看到一个百分比进度条,用于监控使用情况。
  • 如果需要更高的限制,可以申请提升配额(本教程不涉及此流程)。

了解配额设置后,我们就可以开始部署模型了。


部署GPT-3.5 Turbo模型

现在,我们进入“模型”页面,选择GPT-3.5 Turbo模型进行部署。

点击“部署”按钮后,系统会要求你进行一些配置。

模型配置选项

你需要为此次部署选择具体的模型版本并为其命名。

以下是部署配置步骤:

  1. 选择模型版本:从提供的几个选项中选择一个,例如 gpt-35-turbo-0613
  2. 命名部署:为此次部署起一个名字,例如 GPT-35-Demo

高级配额设置

点击“高级选项”,我们可以进一步调整配额。这是之前提到过的动态配额功能。

关键设置如下:

  • 可用配额:系统显示当前有 240,000 tokens/分钟 的配额可用于此部署。
  • 配额调整:你可以将此配额从最高值下调至最低 1,000 tokens/分钟
  • 优势:此动态配额机制让你能灵活利用可用容量,并且只在实际使用时产生费用。

我们保持启用此选项,然后点击“创建”。由于这是通过API操作,部署过程会非常迅速。很快,你会看到“成功创建部署 GPT-35-Demo”的提示。


管理已部署的模型

模型部署成功后,我们需要知道在哪里找到并管理它。

我们进入“部署”页面,在这里可以看到所有已创建的部署。状态显示为“成功”即表示模型已就绪。

部署详情与操作

点击我们刚刚创建的 GPT-35-Demo 部署,可以查看其详细信息。

部署详情页面提供了丰富的信息和操作入口:

  • 查看信息:可以查看模型的速率限制、令牌使用情况等。
  • 管理部署:你可以编辑部署配置、创建新部署或删除当前部署。
  • 快速测试:一个非常实用的功能是,你可以直接点击“在Playground中打开”或“前往聊天”,立即开始测试和使用这个刚部署好的模型。

点击“在Playground中打开”,便会进入一个交互式界面,你可以直接与模型对话。虽然我们现在不进行测试,但这是你后续使用模型的主要方式之一。

探索Azure AI Studio

让我们快速回到Azure AI Studio的主界面。这个仍处于预览模式的新界面整合了所有必要功能。

关键区域包括:

  • 浏览模型目录:在这里可以查找所有可用模型。
  • 试用Azure OpenAI:点击此入口,你会再次看到模型目录,方便你尝试不同的模型。

回到我们的 GPT-35-Demo,至此,模型部署的所有必要步骤已完成。我们将在后续学习API调用时,与这些已部署的模型进行交互。


本节课中我们一起学习了在Azure AI Studio中部署OpenAI模型的完整流程。我们从配额设置入手,逐步完成了GPT-3.5 Turbo模型的选择、配置和部署,并熟悉了部署后的管理界面。核心在于理解动态配额的优势,并掌握通过Playground快速验证模型部署成功的方法。这些操作为后续通过API集成和使用大语言模型打下了基础。

大型语言模型实践:第2章:使用Playground与API调用模型 🚀

在本节课中,我们将学习如何与已部署的Azure OpenAI模型进行交互。我们将通过两种主要方式来实现:使用Azure AI Studio中的Playground界面,以及通过命令行使用cURL直接调用API。这两种方法都能让你快速测试和验证模型的功能。


部署模型与Playground交互

上一节我们介绍了如何部署模型,本节中我们来看看如何实际使用它。首先,我们需要在Azure OpenAI服务中找到已部署的模型。

  1. 在Azure AI Studio中,导航到“部署”部分。
  2. 找到名为“G35 demo”的部署。
  3. 点击“在Playground中打开”选项。

进入Playground后,你将看到一个交互界面。以下是配置步骤:

  • 选择模板:界面提供了一些预设模板。我们将选择“空示例”来从头开始。
  • 设置系统消息:在系统消息框中输入:你是一位旅行助手,准备为世界各地的旅行者提供帮助。
  • 输入用户查询:在用户消息框中输入:我想在夏天去西班牙旅行。
  • 生成回复:点击“生成”按钮,模型将返回回复,例如:“这听起来是个很棒的主意!西班牙是一个拥有丰富历史和文化的美丽国家……”

通过Playground,你可以轻松地与模型对话,并实时调整参数,如“温度”和“最大响应长度”,以观察它们对输出结果的影响。


查看代码与API调用

除了使用图形界面,我们还可以直接通过代码调用API。Playground提供了“查看代码”功能,可以生成对应的调用示例。

在生成的Python代码中,核心部分是构建请求消息。一个基本的请求结构如下:

messages=[
    {"role": "system", "content": "你是一个AI助手,帮助人们查找信息。"},
    {"role": "user", "content": "讲个笑话"}
]

这段代码定义了一个系统角色(设定助手行为)和一个用户角色(提出请求)。


使用cURL进行命令行调用

如果你想在命令行中快速测试API,可以使用cURL工具。以下是调用步骤和关键参数说明:

  1. 准备信息:你需要从Azure OpenAI服务获取API密钥终结点URL。
  2. 构建cURL命令:以下是一个完整的命令示例。
curl $ENDPOINT \
  -H “Content-Type: application/json” \
  -H “api-key: $API_KEY” \
  -d ‘{
    “messages”: [
      {“role”: “system”, “content”: “你是一个AI助手,帮助人们查找信息。”},
      {“role”: “user”, “content”: “讲个笑话”}
    ],
    “max_tokens”: 100,
    “temperature”: 0.7
  }’ | jq

以下是命令中关键部分的解释:

  • -H:设置HTTP请求头。Content-Type指定数据格式为JSON,api-key用于身份验证。
  • -d:传递请求数据(正文)。其中包含消息列表和生成参数。
  • max_tokens:限制模型生成回复的最大长度(以令牌计)。
  • temperature:控制输出的随机性。值越高(如0.8),回复越多样、有创意;值越低(如0.2),回复越确定、保守。
  • jq:一个可选工具,用于将返回的JSON数据格式化输出,便于阅读。

执行命令后,你会收到一个JSON格式的响应。响应中通常包含:

  • choices[0].message.content:模型生成的回复内容(例如一个笑话)。
  • usage:本次调用消耗的令牌数量统计。
  • 内容安全过滤结果。

总结

本节课中我们一起学习了与已部署的Azure OpenAI模型交互的两种核心方法。首先,我们使用Playground界面进行直观的对话测试和参数调整。接着,我们探讨了如何通过查看代码功能获取编程示例,并详细演示了如何使用cURL命令在终端中直接调用API,包括如何设置请求头、构建消息体以及理解关键参数如max_tokenstemperature的作用。这两种方式为你提供了从快速原型验证到集成到应用程序中的灵活选择。

posted @ 2026-03-26 12:26  布客飞龙III  阅读(3)  评论(0)    收藏  举报