• 作者:老汪软件技巧
  • 发表时间:2024-10-30 04:01
  • 浏览量:

推理能力是大模型迈向AGI的必经之路。O1相比于其他模型,其本质上的区别是Reasoning,在回答问题之前,通过思维链拆解问题,反思步骤,多次决策。相比于之前通过惊人的数据量用Scaling Law创造奇迹,它借用思考过程,在训练过程中将原本的快思考与慢思考相结合,实现了推理能力惊人的模型。

然而,其高昂的价格让人望而却步。相比之下,大多数选择了传统的CoT方案。思维链全称Chain of Thought,就是把任务进行拆解,适用于各种推理任务,比如数学,逻辑判断等,思维链的优点就是不用对模型进行训练和微调。在思维链技术中,可能还会使用到零样本(zero-shot prompt)提示和少样本提示(few-shot prompt)等技术。在o1出现之前,CoT能力更多是一种Prompting技巧,是独立于LLM之外存在的,而o1的价值在于将思维链的能力内化到了LLM中。

对于普通人和普通公司而言,这么高质量的数据集和强大的计算平台难以取得。笔者甚至还未能体验到O1的API版本。但尽管如此,外置CoT依然是一个不错的选择,不管是效果还是用户体验,至少strawberry里有几个r它说对了。相比之下,O1-mini我真的是一言难尽~

本文,笔者将试着尽可能的用外置CoT的方式带你实现高仿O1。

分析O1

根据O1的使用体验分析,笔者很难评的发现,它的思考过程也会受到道德约束~(看到你误入歧途直接掐死,重新思考x

目前已经发现的思维模式:

问题拆解与规划不同策略的尝试与反思思考成熟自动结束思考,直接输出,与思考次数无关失败/误入歧途重试机制思考太久直接打断施法机制x

根据官方透露的图,我们可以发现它类似于一轮推理结束进行下一轮推理直至推理在适当时机结束,并且迭代过程中剪枝了Reasoning部分。

复刻O1精神内核

根据以上方式,我们结合CoT可以通过以下方法来复刻思维链。然后把思维链+输入交给模型,得出输出,从而制作出高仿O1。

为了更好的让模型在多轮迭代中自己控制思考的内容和思考结束的时机,我们可以借助模型JSON格式的输出和校验控制模型的思考迭代过程。同时,对于异常思考和过长思考,需人工施法打断。

那么在每轮思考中,模型需要做以下事情:

给一个标题来总结当前阶段思考的方向简短的内容描述思考的内容(可选)详细的深入的思考内容下一步行动:继续下一阶段思考/直接输出

根据以上过程,我们可以给出

输入:用户的提问+上一轮迭代的结果(可精简)

输出的JSON格式:

{
  "title": "Title of a step",
  "briefContent": "Short description of the thought in this step",
  "next_action": "step" 
}

很显然,我们这样就能够实现一个可自主反复思考迭代的机制。模型会不断思考,直到认为思考成熟,可以输出最终答案为止。

接着将用户的问题和整个思考过程(可精简)交给大模型,就能得到更高质量的回答了~

你以为这么简单?

事情还没完~

复刻O1华丽外衣

复刻O1不仅仅是精神内核上的东施效颦般复刻,也要将其技惊四座的华丽外表复刻过来。因为,相比于扎实的技术基础,外表本身才是最具噱头,最吸引人的。要不然,怎就是说5G全国都通了,我的网还是这么差呢~百度做了这么久AI搜索,大模型一出现,众人高呼百度搜索已死,AI搜索当道。

我们发现,相比于传统外置CoT大模型的各类产品比较,O1一个不一样的地方在于它整个都是流式输出的,包括思考过程。即使思考过程很长,没关系,它直接透露一部分思考过程给你,让你的等待有了耐心,这极大提升了用户体验。那目前的方案,采用了JSON格式输出,这是一种常于用Function Call的输出方式,对于稳定且易控制的Workflow和Agent制作有极大的便利。但是它仍然有个缺点,如果仅仅让它输出一些json字段,那完全没问题。

但是有实验研究表明,相比于直出JSON,让模型“深呼吸,一步一步来”,最后再给出JSON,效果更佳。更为致命的是,思考的过程意味着大量的Token输出,而为了能够从文本中解析出JSON往往需要等到完整的结果输出。这就会发现,有一个过长的等待时间。

不禁感叹,这或许就是OpenAI在明明有了一个Function Call的功能,又出了一个和它基本没啥区别的Json Mode的原因。

事实上,json mode相比于function call而言具有惊人的潜力,因为它能够流式输出。那有人就要问了,那不还是需要等所有结果输出完,才能正确解析JSON吗。NONO,千万不能被思维固化,它既然能流式输出,咱不就能直接流式解析嘛。先富带动后富,而不是等一个漫长的世纪大家一起突然变富~

流式解析

传统方法是将整个 JSON 文件或字符串一次性加载进内存,再逐个解析每一个部分,直到生成完整的数据结构。举个简单例子,就像我们在看一本书时,必须一次性读完整本书,然后才能说出书的主要内容。

流式解析是一种逐步解析的方式,它不需要等待整个 JSON 数据加载完成,而是边读边解析。这个方法尤其适合处理很大的 JSON 文件,也更适合实时接收和解析数据。我们可以将它理解成“流水作业”或“逐步读书”的方式。

流式解析会逐字符读取 JSON 数据,而不是一次性加载整个内容。每次解析一个字符,就判断它是什么类型,并决定接下来要怎么做。解析器会根据当前解析到的数据类型(比如对象、数组、字符串等),进入不同的“状态”,这些状态可以理解成“当前我们在干什么”。入栈和出栈就像我们在做数学题时的“步骤记录”,遇到一个新任务时,我们会把当前状态记录下来(入栈),任务完成后再回到之前的状态(出栈)。

比如:

每当解析器解析出一小段数据(如一个键或值),它会立刻触发一个事件,发送解析结果。这样就不需要等到整个 JSON 文件解析完成,而是可以边读边输出。例如,解析到某个键值对时,可以直接将这个键值对发送出去,接收方可以立刻处理它。如果遇到格式错误(比如少了逗号),解析器会尝试修复并继续解析,而不是直接报错终止。这样即使 JSON 不完整或略有问题,也能尽量解析出有用的数据。当解析完所有字符后,进入“结束”状态,发出一个完成的信号,表示数据解析已结束。

如果想更好的了解算法,可以报名FE Day2024,膜拜月影大佬的杰作~

那如果说解析方是后端,那么接收方的前端如何立即处理片段JSON,将他们优先处理,给用户展示呢。这里用到了一个jsonuri的技术:

在流式解析中,我们逐字符读取 JSON,并解析出各个片段(如键、值、对象、数组等)。由于流式解析是“分段进行”的,所以我们需要知道每个片段应该放在最终 JSON 的哪个位置。JSON URI 可以在每个解析出的片段前生成一个“路径标记”(URI),帮助我们明确这个片段在完整 JSON 中的位置。这种方式让流式解析器在解析过程中不迷路,确保最终拼出的 JSON 数据结构正确。

有了部分内容的JSON,对于前端而言就可以顺利展示了。后续无非就是在某个字段上接上新来的文字。

效果展示

基于以上的内容,我们其实就可以复刻出丐版的O1了。具体效果可看视频:

经过实际测试可以发现,其在推理上具有更好的效果,同时也平衡了稳定性、效果和用户体验。

理论上,只要是能够稳定输出json的模型,都能够在此方法的加持下,获得不错的效果提升。

开源地址

以下是开源代码,可以帮助大家更细致的了解具体过程和算法:

/MarleneJian…

如果觉得有帮助,可以来个star哦~

参考资料jsonuriling