原文:towardsdatascience.com/advanced-prompt-engineering-chain-of-thought-cot-8d8b090bf699

与大型语言模型合作

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8764560ccf99d23fd12ce2a88d11c094.png

推理技术的一些形式 | 作者图片

_ 如果你不是会员但想阅读这篇文章,请点击这个朋友链接这里_

思维链(CoT)已经存在一段时间了,在技术上是一种高级提示工程,但即使是在它首次推出几年后,它仍然具有相关性。CoT 在其各种形式中,通常是一种迫使大型语言模型进行推理的努力。

在 OpenAI 于今年九月发布其模型 o1 的预览之后,我们看到了围绕 CoT 的炒作增加。

没有人完全知道 o1 是如何工作的(除了 OpenAI 之外),无论是组合系统,它使用过什么样的数据进行微调,它们是否使用强化学习,或者是否有多个模型协同工作。

可能有一个模型负责规划,另一个负责思考,第三个负责评估。但我们确实知道它们正在使用某种类型的逐步推理。

关于这一点,已经有很多公开的研究,你可能想深入研究。因此,对于这篇文章,我将介绍我所找到的内容,以便你知道可以使用什么。当然,我会测试不同的技术,看看我们是否能够实现任何真正的改进。

然后,如果你对进行一些技术性的工作感兴趣,我会帮助你构建一个系统,该系统会查看模型的内部置信度水平以生成答案。

研究内容

在过去两年中,已经发布了许多论文,我收集了我找到的很多论文这里

他们讨论的推理技术你将在下面的图片中看到。

大部分工作直接来自 DeepMind 或普林斯顿。对他们开源这么多工作表示赞赏。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/02615c0f5256854241dcf3b305111741.png

过去两年中讨论过的不同技术 | 作者图片

术语 CoT 是 DeepMind 在 2022 年提出的,仅用于提示,最新的论文探讨了带有蒙特卡洛搜索的三个思维(ToT)和无提示的 CoT。

对于这篇文章,我们将探讨简单的思维链(CoT)、CoT 链、贪婪解码、CoT-SC、解码 CoT 和蒙特卡洛树搜索中的三个思维(ToT)。

我们还将使用我们自己的数据集来了解我们在应用这些推理技术时可以取得的改进。

LLMs 的基线分数

为了了解我们如何提高 LLMs 的结果,我们首先需要建立一个基线分数。

当一个模型被引入时,它通常伴随着评估指标。有几个流行的指标,例如 MMLU(语言理解)、BigBench(推理)、HellaSwag(常识推理)等等。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e9db6d9179005af7c8b4e234cf35e46f.png

数据集的有趣插图(还有很多)| 作者图片

然而,你应该意识到,其中一些数据集相当过时,可能有些污染。

Hugging Face 在 12 月份引入了一个新的LLM 排行榜,它基于更新的数据集进行评估,你可以清楚地看到,大多数模型的分数比它们在原始数据集上的分数要低得多。

在这里做一些研究,了解在模型评估方面应该如何思考,以及你和你所在的组织应该基于什么标准进行评估,这是值得的。拥有一个内部私有数据集进行测试可能不是最糟糕的想法。

但无论如何,我从各种数据集中抽取了大约 350 个问题,以及我在网上找到的一些流行问题,以评估多达 11 个不同的模型。

我需要了解这些数据集看起来是什么样子,以及从 LLMs 生成的答案。

因此,我编写了自己的脚本来循环遍历问题,然后对每个问题使用 0 或 1 来评估 LLMs。

称我为完美主义者吧。你可以看到我找到的结果如下。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/90f93255ed38996314616577d4899046.png

你可以在这个Google 表格中找到整个数据集和结果。

这告诉我们什么?嗯,不多。

我使用了 Big Bench、MMLU、Putnam 的问题,以及像“Strawberry 中有多少个 r”这样的流行问题,但我们无法知道它们是否被这些问题所污染。此外,这是一个相当小的数据集。

然而,我们可以清楚地看到,更大的模型表现更好。

我们将看到的是,如果我们通过应用使模型在回答之前进行推理和“思考”的方法,我们是否可以提高这些分数。

思维链(CoT)

2022 年由 DeepMind 的 Brain Team 发表的论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》引入了思维链(CoT)提示。

因此,CoT(思维链)的概念我们已经有了相当长的时间。

然而,这篇第一篇论文是关于如何通过激活模型的内在推理能力,使用提示策略来强制模型对一个问题进行推理的研究。

在那时,人们只是通过要求模型‘逐步思考’,无论是通过零样本(不提供示例)还是少样本(提供几个示例)的方法,以正确的方式提示。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a7074957b15c28867b66b91805c99967.png

零样本与少样本——这关乎提示中的具体例子 | 作者图片

你可以通过在提示的末尾简单地添加‘让我们逐步思考’来为 Claude、ChatGPT 或其他各种模型做这件事。如果你想尝试少样本学习,你可以在提示中提供一些示例。

DeepMind 报告称,他们通过正确提示,可以验证地看到使用 CoT 技术有显著的改进。

从那时起,许多论文都基于这些技术,分支到越来越高级的路径。

构建推理链

这里有许多提示工程社区的人正在尝试 CoT 风格的技术。我收集了这里找到的大多数仓库,所以很容易找到。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1578d190f64ecb91ce0c55536c198c88.png

CoT 风格技术的几个实现,请在此查看。 | 作者图片

不久前,Benjamin Klieger 引人注目,他通过进一步分解思考过程,利用 Groq 和 Llama 3.1 70b 构建了一个提示风格的应用程序,以激发链式思考。

你可以在这里找到他的应用。

想法是让 LLM 将其思考分解成链,直到它对答案有信心为止。

系统将接着为链的每个部分生成 LLM 调用,而不是将整个思考过程放在一个响应中。

看看将这种方法应用于 Grok-Beta 的例子,问题是*‘Strawberry 中有多少个 R?’*

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/59a3099ead4737cf57c233f47eb9f65c.png

使用 Grok 对问题“Strawberry 中有多少个 R?”的 CoT 链 | 作者图片

模型本身正在设置每个部分,给它一个标题,并决定是否需要另一个‘思考’并继续,或者它已经达到了最终答案。

这仍然是一种 CoT 风格的技术,因为它线性,但它比简单地要求模型‘逐步思考’要先进一些。

我使用了他的一些代码来构建一个脚本来循环遍历我测试的一些 LLM 的基础问题,以查看这样的系统实际上能带来多少改进。我为 Claude 和 Grok 调整了脚本,以评估这种策略对它们的效果。

您将在下面看到百分比改进。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e630210708b01affd419c8fffe7795cf.png

您可以在这个Google 表格中找到整个数据集和结果。| 作者提供的图片

Llama 3.1 70B 在头三个类别中看到了最好的改进。Grok 在流行问题上的表现较差(Haiku 也是如此)。

Putnam 数据集是高级数学,很少有 LLM 能在这里做得好,所以当 Claude Sonnet 3.5 能够通过这些 CoT 链在 68.75%的准确率上优于 o1-preview 的 63%时,我感到非常惊讶。

总的来说,Sonnet 在高级数学中使用 CoT 实现了 81%的改进。

记住,我这里使用的是一个非常小的数据集,这只是为了了解它们在哪些方面做得好,以及我们是否可以提高分数。如果没有在更大的数据集上测试,它告诉我们的是不具体的。

然而,我也观察到,如果小模型在简单问题上开始过度分析,它们可能会产生更差的结果。这在 Grok-Beta 和 Haiku 在流行的“简单”问题上的表现中尤为明显。

简单的非数学问题可能无法获得 CoT 相同的益处。

我们还必须记住,我们可以推动模型在其能力范围内表现,但很少能超越它。如果它不知道答案,它就不知道。

理解能力微调

在继续之前,我想提到微调。

其中一个非常有趣的研究领域是尝试在 CoT 数据集上微调较小的模型,以提高它们的准确性,使其达到 1-2 倍更大的模型的水平。

我找到了多个此类资源,但遗憾的是,我没有找到从基础模型中显著改进的内容,以至于我认为值得进行适当的分析。

您将在下面看到我找到的开源模型。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cf34507a58548d694b3a3a6f32203dd1.png

此处是存储库的链接。| 作者提供的图片

您将在下面找到我也开源的 CoT 数据集。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/de85cabb3c23b1b8e4aaf37c166e4f27.png

此处是存储库的链接。| 作者提供的图片

这并不是说 CoT 的微调不起作用,只是需要构建更好的、有良好文档记录的模型。

如果您想尝试自己进行微调,可以去查看那些资源。我相信还有更多。

替代生成技术

我们所讨论的是思维链技术,但还有其他方法可以在不提示的情况下优化语言模型的输出准确性。

这涉及到那些我们通常在调用 LLM 时忽略的 采样设置,如温度、top_p 和 do_sample 等参数,这些参数可以在控制输出行为中发挥作用。

现在,我们并不总是能够访问所有这些设置的商业 API,但我们确实可以访问温度。从技术角度来说,温度意味着当我们将其设置为高时,我们可以调整 logits,从而增加低概率标记被选中的机会。

如果你刚接触 LLMs,这可能会让你感到困惑,但它并没有听起来那么复杂。

你可以在下面看到我关于随着温度升高,标记概率如何增加的笔记。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/ebcb54f191b3d595f1511a8180c4e0fe.png

温度是如何调整 logits 的上下限的?| 图片由作者提供

假设标记“mat”在开始时具有最高的初始 logits,但随着温度的增加,我们看到它开始降低,减少了概率。对于初始 logits 较低的相反情况也是如此。

这是什么意思?这意味着如果温度高,模型更有可能选择感觉不那么“安全”的单词。

大多数人称之为随机性或创造力。

对于 top_p,并非所有商业 API 都可能访问到,你可以根据设置的数字来限制或扩展标记池。

低分将限制候选池只包含高概率分数的标记,反之亦然——低分意味着只有 高概率标记 将在 候选池 中。

高 top_p 与高温度结合将产生更多创新和创造性的输出,因为会有更多的标记成为候选者。

do_sample 参数决定模型是否使用采样来生成下一个标记。这个设置你很少能够通过 API 商业模型来设置。

当 do_sample 设置为 True 时,模型将从候选池中进行采样,并拥有更多自由度(这是所有 API 中的默认行为)。当设置为 False 时,它只选择概率最高的标记(并完全忽略温度或 top_p)。

我们可以使用 do_sample 设置来强制模型产生更确定的输出,即在每个阶段选择概率最高的标记。

这被称为 贪婪解码

这是一种策略,其中模型在每个步骤中选择概率最高的标记,这可能会导致更准确的答案(如果它具有所需的基本知识)。

我使用 do_sample 对模型 Llama 3 8b (instruct) 进行了贪婪解码,以查看我们是否能提高基础问题的质量。

你将在下面看到结果。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7c1e0293c56d1394838cacc86cd3eee3.png

你可以在这个Google 表格中找到整个数据集和结果。| 图片由作者提供

我确实看到了 MMLU 和 Big-Bench 的一些改进,但对于高级数学来说改进非常有限。

现在,由于商业 API 无法访问 do_sample,为了在没有访问模型的情况下应用类似的东西,你可能会尝试将温度设置为 0 来模仿这种行为,但这并不保证。

那么,你现在可能有一个疑问,为什么我们总是使用贪婪解码,如果我们看到一些小的改进呢?

如果我们忽略输出中需要一些创造性的需求,你也会发现能力较弱的 LLM 在解决困难问题时可能会陷入重复的循环,比如反复说“颜色是蓝色蓝色蓝色蓝色”,因为“蓝色”似乎是最有可能的标记,所以它被重复使用。

高级 CoT

到目前为止,我们一直在研究线性技术,其中模型在一个线程或链中产生输出。

但是,在第一个 CoT 论文提出不久之后,DeepMind 又介绍了一种更先进的技术,称为带有自我一致性的思维链(CoT-SC)。

这种技术创建了几个推理路径,并使用某种方法在最后选择最一致的答案(或路径)。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/760665b238c7ee5d48456fcd8a432fe4.png

CoT-SC 演示 – 评估一致性 | 图片由作者提供

他们报告说,使用这种方法在算术推理中找到了大约 1-8%的改进。

今年刚刚介绍的一种新方法遵循了使用多个路径的类似想法,但没有使用任何提示。

记得我在上一节中提到的贪婪解码的概念吗?

这种方法类似,但不仅仅是强制使用最可能的标记,还查看整个响应的置信度分数。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/217b07261a2eac23a71f3a5cdcad4299.png

评估内部置信度分数 | 图片由作者提供

要做到这一点,系统首先启动一定数量的初始顶级标记 k,然后从每个标记生成路径。一旦生成答案,它通过分析不同路径中每个标记的概率(logits)来计算置信度分数。

返回概率最高的答案或路径。

这种方法被称为解码 CoT,由 DeepMind 提出。这种方法的想法是查看模型在返回的答案中的内部置信度。

但是,如果它没有内在的知识来回答问题怎么办?就像 CoT-SC 一样,这种方法会极大地依赖于模型最初就拥有正确的答案。

然而,这并不意味着我们不应该对其进行测试。

对于所有这些技术,都有人在开源不同的实际实现,这个也不例外。

因此,我很容易设置一个系统来测试这些方法,并比较在较小的开源模型 Llama 3 8b 上的表现。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/96a0a5648a59d5249d8547e98aea03dc.png

你可以在这个谷歌表格中找到整个数据集和结果。| 图片由作者提供

向 Codelion 致敬,他开源了他的实现,这使得我能够轻松复制。

观察上述结果,你可以看到,与熵或仅使用贪婪解码等其他方法相比,我们使用解码思维链(Decoding CoT)明显取得了最佳结果。

我们将在技术部分创建一个 API,它将使用这个解码思维链(Decoding CoT)系统,这样你就可以看到它是如何工作的。

新技术

跟上进度很难,但研究已经远远超过了在更高风险领域使用简单的思维链(CoT)进行推理。

我现在不会深入所有这些策略,因为那是一个另一个话题,但我确实想提到三种思维(ToT),特别是与蒙特卡洛搜索结合使用。

ToT 是由普林斯顿大学和 DeepMind 在 2023 年底引入的,但通常基于基于树的推理的先前方法。

三种思维(ToT)与自洽思维链(CoT-SC)略有不同。在生成多个路径并在生成后进行评估之前,ToT 会动态评估思维过程。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bf5a213e2bf863fe0e69a353044d023f.png

简单展示三种思维 | 图片由作者提供

想象一下,有 4 个人一起解决问题。在每一步,他们提出自己的想法,并集体评估哪些看起来最有希望。如果某人的推理看起来有缺陷,他们就会离开,其他人则继续通过他们的解决方案工作。

最后,那些一直在正确推理的人将能够提供他们的答案。

这允许模型动态修剪看起来无望的路径,专注于更有希望的线程,从而可能节省资源。

然而,有人可能会问,系统是如何决定哪个线程是正确或错误的?这是由模型本身决定的。

这也是为什么像蒙特卡洛树搜索(MCTS)这样的扩展被引入,以提供更多无偏评估机制。MCTS 允许反向传播,这意味着它可以根据新信息重新访问并改进早期步骤,而简单的思维链(ToT)只能向前移动。

在解决问题的 4 个人案例中,MCTS 允许人们即使思维不理想也能在游戏中停留更长的时间。评估方法将不同。

MCTS 可以模拟多个未来路径,评估它们的潜力,并回溯以改进早期决策。它引入了外部指标(奖励),而不是完全依赖模型。

像 UCB(上置信界)这样的统计方法使用这些奖励来决定探索哪些想法或重新访问。

MCTS 比简单的 ToT 复杂一些,可能应该是一篇单独的文章。

CoT 的经济效益

所以,到目前为止,你可能认为,嗯,我们有一些改进,为什么不总是使用更高级的思考链形式呢?

好吧,首先,成本(以及思考时间)。

对于我应用在不同模型上的链,我计算了平均推理步骤的数量。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e0a09fc5a259554b206c501416b15f96.png

你可以在本谷歌表格中找到整个数据集和结果。 | 图片由作者提供

看到这里,你可能会为每个问题支付平均高达 8 倍的费用。对于在高级数学问题上表现最佳的 Sonnet,你可能会为每 500 个问题支付高达 15 美元。

这可能看起来不多,但一旦你每天都在使用这个系统为客服或你的团队生成答案,你可能会看到每月数百甚至数千个。

在某些情况下,使用高级推理方法是有意义的,但并不总是如此。

现在可能存在对 CoT 进行微调的情况,基本上消除了产生多个调用的需要,但我还没有看到任何开源模型做得很好。

这里有一点权衡。我们希望增加思考时间,以便模型有足够的时间进行有效推理,但这样做也会增加用户的挫败感和成本。

构建智能系统

今年 9 月,发布了一篇题为“是否使用 CoT?”的论文论文,认为应用 CoT 的大部分改进主要在数学和复杂推理方面。

我们在这里也看到了这一点,简单的问题给我们带来的改进有限。

当我们应用这些链时,我们必须等待更长时间才能得到回应。这是否值得?但应注意的是,所有这些策略对于简单任务来说可能都是过度的。

这也是为什么你可能会在使用 OpenAI 的 o1 时感到沮丧,对于大多数问题,简单的答案通常已经足够好。

但如果你正在构建一个需要确保答案正确性的系统,那么采用某种形式的 CoT 或解码可能是个好主意。

可能值得使用一个模型根据问题的难度设置第一步,然后分析它是否自信能够首先回答它。然后让模型通过链进行推理,并在最后让另一个模型对回应进行评分。

备注

除了我这里介绍的那些框架,还有更多吗?绝对有,但我只介绍了我认为有趣理解的那几个。这让你了解我们取得了多远的进步,而信息并没有令人感到压倒。

大多数 AI 工程师对这些框架都很熟悉,但遗憾的是,这项研究并没有像预期的那样迅速传播到公众。

在构建 LLM 应用时,理解如何实现 CoT 应该是基础知识的一部分,即使你决定不使用它们。

技术工作

让我们将其付诸实践。

我们将使用开源模型 Llama 3.1 8b 实现解码 CoT 系统。

解码 CoT 的方法来自今年发布的论文,“无需提示的 Chain-of-Thought Reasoning”,该论文可在这里找到,实现是从 Codelion 抓取的,可在这里找到。我添加了一些功能,以便系统检查难度级别以决定路径数量(k)。

由于上次我使用了 Modal,这次我们可以使用Beam,也是一个无服务器 LLM 服务平台。他们提供 15 小时的免费层,所以这将免费。我们将使用的脚本你可以在这里找到。

如果你更愿意使用 Colab 进行测试,你可以在这里运行这个脚本

结果应该是一个 API 端点,让我们可以提出问题,它将评估难度,然后对问题执行解码 CoT 并返回如下响应。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b99be110829dcd534ba41fe4ffc1001a.png

使用新的 API 端点测试系统的 Postman 调用 | 图片由作者提供

你将看到对 LLM 的请求次数以及系统如何对问题进行分类。你还会注意到,由于系统正在生成多个答案以进行评估,所以它相当慢。

然而,如果我们尝试使用相同的 8b 模型进行 Groq,我们会发现它几乎无法正确回答问题。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/36492b59ab10624431dd80722fb85ce8.png

使用 Groq 通过 Llama 8b 测试相同问题 | 图片由作者提供

正确答案是 27.3,额外加分给额外燃料。

在最终答案方面,我将会指出,尽管如此,这样的小模型只能带我们走这么远。不幸的是,使用更大的模型需要更多的工作,因为我们需要将其存储在某处,这可能会很昂贵。

为了设置这个系统,我将占用你 5 分钟的时间。你可以按照下面的说明进行操作。

Hugging Face

我们将首先获取我们将要使用的模型。要使用 Llama 3 8b 模型,你需要通过Hugging Face获得对其的访问权限。

如果你已经有 Hugging Face 账户,这个过程通常相当快。如果没有,你可以免费创建一个,然后导航到模型卡片

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e34a19919f0a01ce92a676f432e2a162.png

Hugging Face 中的模型卡片 | 图片由作者提供

一旦我们进入模型卡片,我们不妨测试一下这个模型,以便我们可以用它来测试这个新系统。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/df67985c2e63296f77f1a75a1ca63bb4.png

测试模型的问题但未能回答 | 图片由作者提供

这是一个相当标准的问题,我之前在评估中已经使用过它,但标准的 Llama 3 8b 模型在这个问题上有点困难。

一旦你被授权访问,导航到“设置”以获取访问令牌。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/904b5dfc96c3a2e3b2a3caad25063eb4.png

获取访问令牌的 Hugging Face 设置 | 图片由作者提供

将此令牌保存在某处,因为我们将在 Beam 中设置它。

Beam.Cloud

如果你没有Beam账户,你需要创建一个(除非你选择直接使用Colab)。当然,你可以在不同的平台上构建自己的系统。

如果你决定使用 Beam,从他们的仪表板获取一个 API 密钥。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/715cbbae324e2ea2171624fba2b2c376.png

Beam Cloud 平台仪表板获取 API 密钥 | 图片由作者提供

设置环境

现在,我们可以开始了。打开一个新的终端,创建一个新的目录,然后 cd 进入它。

mkdir my-testing-dir
cd my-testing-dir

克隆我设置的仓库。

git clone https://github.com/ilsilfverskiold/decoding-cot-beam.git 

创建一个虚拟环境(你需要安装 python 才能完成此操作)。

python3 -m venv .venv && source .venv/bin/activate

安装 beam 并验证。

pip install beam-client
beam configure default --token "your_token_here"

确保你设置了之前从 Hugging Face 获取的 HF_TOKEN。

beam secret create HF_TOKEN

你可以直接从这里提供服务,但让我们先看看代码。

如果你对此不感兴趣,可以跳过下一部分。

代码

根目录下有三个 Python 文件。

│
├── app.py
├── question_classifier.py
└── cot_decoder.py 

app.py中,我们有来自 Beam 的代码,允许我们从 Hugging Face(在启动时)下载模型的权重,并通过卷积缓存它。这意味着第一次运行这个时,可能会有些笨拙和缓慢。

Beam 还允许我们在远程运行脚本时加载包。

这是app.py的起始部分,附有我的注释:

[...]
# This ensures that these packages are only loaded when the script is running remotely on Beam
if env.is_remote():
    import torch
    from transformers import AutoModelForCausalLM, AutoTokenizer
    from cot_decoder import cot_decode
    from question_classifier import get_k_value

# Model parameters & where to cache it in Volumes
MODEL_NAME = "meta-llama/Meta-Llama-3-8B-Instruct"
CACHE_PATH = "./cached_models2"

# Load the model and tokenizer
def load_models():
    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, cache_dir=CACHE_PATH)
    tokenizer.pad_token = tokenizer.eos_token
    model = AutoModelForCausalLM.from_pretrained(
        MODEL_NAME, device_map="auto", torch_dtype=torch.float16, cache_dir=CACHE_PATH
    )
    return model, tokenizer

# Define the endpoint
# You can specify CPU/Memory/GPU + the image
@endpoint(
    secrets=["HF_TOKEN"],
    on_start=load_models, # load the model on start to be cached
    name="meta-llama-3-8b-instruct",
    cpu=2,
    memory="32Gi",
    gpu="A100-40",
    image=Image(
        python_version="python3.9",
        python_packages=["torch", "transformers", "accelerate"],
    ),
    volumes=[Volume(name="cached_models2", mount_path=CACHE_PATH)],
)
[...]

我们定义了一个@endpoint,其中包含了我们想要的资源(A100 GPU 和 2 个 CPU 核心)。你也会看到我们在启动时加载模型。

一旦 API 调用到来,我们运行generate_text()函数。

[...]

def generate_text(context: Dict[str, Any], **inputs: Dict[str, Any]) -> Dict[str, Any]:
    # Retrieve model and tokenizer from on_start
    model, tokenizer = context.on_start_value

    # Get adaptive k value based on question complexity
    classification_type = None
    if k is None:
        k, classification_type = get_k_value(messages, context)

    try:
        output_text, confidence, llm_calls = cot_decode(
            model=model,
            tokenizer=tokenizer,
            messages=messages,
            k=k,  # Use adaptive k value
            **inputs  # Pass any additional parameters directly to cot_decode
        )

        # Return the output
        return {
            "output": output_text,
            "confidence": confidence,
            "complexity_info": {
                "k": k,
                "total_calls": llm_calls + 1,  # + classification call
                "classification": classification_type
            }
        }
    except Exception as e:
        return {"error": f"Error during generation: {str(e)}"}

我们有一个函数,首先使用get_k_value()根据复杂度计算 k。但这里的关键函数是cot_decode(),它将在我们的问题上执行解码思维链。

这个函数将接收消息、模型和分词器,并首次调用以预测具有最高 logits 的 k 个可能的下一个标记。

logits 是模型分配给每个可能的下一个标记的原始分数,让我们知道模型对每个选项的置信度分数。

这些将作为生成多个答案的潜在起点。对于这些起点或起始标记,我们生成完整的答案,然后整体评分。

记得我们讨论了贪婪解码,我们只生成具有高概率的下一个标记?这将相反地查看整个句子,而不仅仅是逐个标记,通过计算一个反映模型对完整答案确定性的置信度分数。

在我们获得置信度最高的路径后,它将与 k 值一起返回。

有一些额外的选项,例如当模型返回多个高置信度答案时添加aggregate_answers布尔值,但我们在这里没有使用它。

让我们运行它

简要解释了代码后,我们将运行它以查看其表现。

您应该能够简单地调用 serve。

beam serve app.py:generate_text

这是在一切设置正确的情况下。

您的第一次调用将花费相当长的时间,因为它将缓存模型。如果超时,请再次运行 serve,它正在为您缓存模型。

要查看模型存储的位置,您可以前往 Beam.Cloud 平台的

一旦它运行起来,您会看到下面这样的内容。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cc5ad4310b718d9eef994720837e17e0.png

一旦您服务了端点,它应该看起来像这样 | 作者图片

这意味着它已准备好进行测试。

您可以启动 Postman 或使用 cURL(这意味着您在终端窗口中运行对端点的调用)

curl -X POST 'https://app.beam.cloud/endpoint/id/[ENDPOINT-ID]' 
-H 'Connection: keep-alive' 
-H 'Content-Type: application/json' 
-H 'Authorization: Bearer [AUTH-TOKEN]' 
-d '{
    "messages": [
        {"role": "user", "content": "Give me three sentences that end in 'is'"}
    ]
}'

响应应该看起来像下面这样。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/88e79ce286a01f34a6cf7e82652d8070.png

测试我们从 Beam 获得的端点 | 作者图片

如您所见,它的表现可以更好一些。

如果您想部署模型,只需运行 deploy。

beam deploy app.py:generate_text

我只是用它来测试,所以现在可以关闭它了。


希望这既有趣又有教育意义,您学到了一些东西。

如果您想查看 LLM 和 CoT 技术的结果,可以查看这个表格以及您在这个仓库中找到的所有其他资源。

如果这有帮助,请留下评论并给我一些点赞。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐