本文主要讨论大模型在处理简单任务时出现的问题,如计数r的数量和比较数字大小。文章解释了这些问题背后的技术原因,即大模型的Tokenization处理和预测下一个Token的原理。为解决这些问题,文章提出了使用CoT(思维链)方法来引导大模型进行逐步思考,并通过实验验证了这一方法的有效性。文章还探讨了为什么CoT方法有效,并认为限制大模型先输出理由再输出答案,可以提升其表现。最后,作者在实际项目中采用了“理由先行”的输出风格,并取得了良好效果。
本文将从两个常见的大模型翻车问题入手解析这些问题背后体现的大模型技术原理,并解释了为什么会导致这些问题,接着我们利用CoT(思维链)方法解决这些问题并基于上述原理试图剖析CoT方法起作用的可能原因,最后提出【理由先行】风格这一简单有效的Prompt Trick。
作为大模型落地相关的算法工程师,随着大模型能力的快速发展,Prompt工程成为了越发重要的一项技能。
在2023年下半年,我们遵循着Prompt调优—微调训练调优的方式进行着大模型落地的探索,也探索出了RAG/NL2SQL等多种较为适合大模型落地的场景;而到了2024年上半年,Agent从概念逐渐演变成了切实可行的落地场景,而在通用大模型能力的不断突破下,微调调优在算力、时间、精力上的重投入显得更不讨喜,尤其是大部分项目仍处于需要快速验证想法的POC阶段,由此我们改换成了Prompt调优—Agent工作流搭建的方式,可以迅速验证大模型在各行各业场景的效果。
显然,无论处于哪个阶段,Prompt工程都将是最初也最为重要的一个步骤,Prompt是你与大模型之间沟通的唯一桥梁,也是大模型带领你云游四海的船票。
所以,我想开设一个专题【Way To Prompt】,用于记录前沿学习、项目实践过程中接触到的Prompt方法、结构化框架以及各类Tricks,梳理各类在实际业务中可以发挥价值的Prompt及其背后的生效原理。
本文简述:本文将从两个常见的大模型翻车问题入手解析这些问题背后体现的大模型技术原理(Tokenization与预测下一个Token),并解释了为什么会导致这些问题,接着我们利用CoT(思维链)方法解决这些问题并基于上述原理试图剖析CoT方法起作用的可能原因,最后提出【理由先行】风格这一简单有效的Prompt Trick。
前段时间,我们经常能在互联网上看到有关大模型“翻车”的常见问题,其中最为典型的莫过于“Strawberry有几个r数不对”以及“9.9和9.11比大小”。
这些问题一度引发了互联网上大模型社区的广泛讨论,大家一定很好奇,为什么大模型可以完成个别复杂的推理任务,甚至可以在数学、法律等各类行业的高等级考试中获得优异成绩,却在如此简单的问题上接连翻车呢?
那么本篇文章便试着从这一角度入手,理解大模型为什么在该类任务上的表现不佳,以及基于这一原因所引发的思考与更适合的Prompt实践方式。
首先,我们来验证大模型是否真的无法解决上述的两个问题:
通义千问:
GPT-4o:
Claude3 Sonnet:
可以看到,截止到目前三者之间仅有Claude3回答正确,而GPT-4o和千问依旧无法数对r的数量,并且千问的解释也很奇怪,它明明可以看到rr里面有两个r,为什么却数不对呢?
并且值得一提的是,测试Claude3.5 Sonnet时我们发现它也数不对。
通义千问:
GPT-4o:
Claude3 Sonnet:
上一个问题Claude3答对了,而这个问题则是无一例外地全部翻车,那么大模型究竟为什么无法解决这些对于人类来说如此简单的问题呢?
这两类大模型会“犯蠢”的问题背后,实际上是大模型的技术原理天然带来的“副作用”,比如我们先从“Strawberry有几个r数不对”这一问题入手。
大家对这件事的普遍定论是,这是
文本的Tokenization处理所带来的问题。
所谓的Tokenization,即是将文本处理为Token的过程,很多时候也翻译为“分词”,不过需要注意的是,“分词”这一翻译本身具有一定的误导性,
这里分好的“词”并不能直接对应我们“人类视角”的【单词/短语/词组】,而是“大模型视角”的【Token】
,这一部分我会基于之前内部培训时我所制作的PPT进行说明。
由于大模型无法直接处理文本,因此需要将文本转化为大模型可以处理的数字,转换过程可以简化为以下几步:
输入文本序列,对序列进行切分成为Token序列,再构建词典将每个Token映射为整数型的index。
这一过程中,主要的难点在于,如何理想地对文本序列进行切分。如果我们切分的粒度太细,比如水果被切分为水和果,那么水果这一词语在大模型眼里就丧失了其作为一个词语的整体语义。如果我们切分的粒度太粗,比如我喜欢吃水果整体是一个token,那么这样切分所得到的字典规模可想而知是相当大的。所以一个好的切分应该是,使得文本中的每个Token都拥有正确的表义,且不会存在字典容易过大或在字典中找不到相应token的问题。
根据以上描述可知,“大模型视角”下的文本与我们“人类视角”并不一样。为了验证这一点,我们可以在DashScope提供的Token计算器页面观察“大模型视角”下的文本是如何拆解的。
以Strawberry为例,其被拆分为
【“str”, “aw”, “berry”】
,自然也就不难理解为什么通义千问对于这个问题的回答是“两个r”了,毕竟对于它来说,这三者均是作为一个整体存在的,而不是从字母维度切分的。
为了让人们更好地理解“大模型视角”与“人类视角”之间的差异,前OpenAI创始成员与研究科学家Karpathy在X上放出了一个脚本,用于将Token转换为Emoji表情,从而更加直观地向大家展示大模型眼中的文本是什么样的。
(脚本网址:
https://x.com/karpathy/status/1816637781659254908
)
这里依旧以“Strawberry里有几个r?”问题为例,可以看到在大模型的眼中,这个问题其实是这样的:
“数r”这一问题从人类视角显而易见,但在大模型视角却是有难度的。由此也就很容易理解,为什么大模型在缺乏引导的情况下无法完成“数r”这种对于人类来说无比简单的任务。
而另一个比大小问题,我们则要从大模型的生成原理角度去考虑。
我们知道,大模型(Large Language Model,LLM)的含义为大型语言模型。
“大型”很好理解,而所谓的“语言模型”,也就是
用于计算文本序列概率的模型,更通俗地说,用于计算一个文本序列是一句“人话”的概率。
那么换个角度来说,“语言模型”也就可以在给定上文的情况下,计算下一个Token取各种值的概率,所以大模型的生成过程本质上便是在“
根据上文预测下一个Token
”,而这个概率分布即是在模型训练过程中从大量的文本数据中学习到的,使得大模型学习到了语言的基本知识与模式。
在理解上述原理的基础上,“9.9和9.11比大小”翻车的原因也就容易理解了,若是训练时存在着许多版本号相关的数据,那么从版本号的角度来看,9.11确实要比9.9大,大模型也就很可能会根据这种概率分布得出“9.11比9.9要更大”的结论。
其实解决这两类问题的方法也并不复杂,只需要在Prompt中加入一定的引导就能获得理想答案,比如说我们可以利用CoT思维链的方式编写Prompt,引导大模型逐步思考并解决问题。
CoT为思维链(Chain-of-Thought)的缩写简称,是提示工程领域最为重要的提示方法之一,它的核心思路在于通过引导模型逐步展示其推理过程,从而提高其理解和解决复杂问题的能力。在Few-shot(少样本)设置下表现为 在提供的样例中解释推理过程,引导大模型回答时也解释推理过程;而在Zero-shot(零样本)设置下表现为 加入类似“让我们一步步思考(Let’s think step by step)”的引导话术。
而对于本文提到的两个翻车问题,我们可以尝试这样编写Prompt:
Strawberry里有几个r?请你先将单词拆分成一个个字母,再用0和1分别标记字母列表中非r和r的位置,数一下一共有几个r
请一步步思考,以逐级复杂的原则思考问题,最后才得到答案。9.9和9.11谁大?
可以看到,通过CoT方法编写Prompt后,可以引导大模型输出正确结果。
有趣的是,第二个问题的Prompt虽然可以帮助大模型获得正确的结果,但却不是始终有效的,多次尝试很可能会获得不同的结论。而将“9.9和9.11谁大?”切换成英文的“9.11 and 9.9, which is bigger?”时大模型更容易答对,这里本质上也体现了中英文训练数据的差别对概率分布的影响以及大模型预测下一个Token是一个采样过程。
然而随之而来的问题是,为什么这么做可以提升大模型的表现呢?这个问题想必大家也十分好奇,基于上面所述的大模型原理,其实也不难理解。
如果说,大模型每一次生成是在“根据上文预测下一个Token”的话,那么CoT的作用便在于,
它可以引导大模型先行生成有力的推理过程,比如引导其生成Strawberry拆解后的字母列表,或者数字的逐位比较,这样模型在生成最终结论的时候,会受到上文推理过程的影响,将下一个Token的概率分布限定在某个范围内,从而大大增加输出正确答案的概率。
可以将该过程想象成下图:
试想,当你遇到一个问题,随着你的不断思考,你为获得正确答案建立了更多的“论据”,从而不断地增加你对某一个答案的置信度;而这与你直接在脑中海量的答案池中进行一次选择或预测相比显然要更加可靠。