事情的缘起是这样的,周末带着小孩子在图书馆看书,也没认识几个汉字的崽,不知从哪本书架上抽了一本书跟我说:爸爸,晚上我要睡前阅读看这这本。我定睛一看,这书的标题确实他是认识的:《计算机与人脑》。再一看作者,呀,祖师爷冯诺依曼写的。行吧,虽然知道你小家伙肯定听不懂,但祖师爷的书还是值得读一读的。
晚上睡前,我翻开书,开始念这本书,读到“一个符号,可以用十个不同的形式表现,以满足一组十进制数字的需要...”,小家伙就开始有问题了:“符号不是只有加减乘除吗?为什么会有十个符号?”是的,一方面是翻译的问题,在原版中使用的是 maker 这个词,被翻译成标记好像更合适一些?但这样又会引入一个新的概念。另外一方面,小孩子在学校老师教他们的是数字是数字,符号是符号,要怎么让他理解数字其实也是一种符号或标记呢?然后,我就合上书开始给他科普二进制和十进制,果不其然,成功地把小家伙给弄睡着了,睡前嘴里还念叨着1和0。这样我就有时间好好地看看这本祖师爷的书了。
不过这一看不得了,发现其实书中所探讨的内容,和我们当前提示词工程遇到的问题非常相似,冯诺依曼希望从人脑和计算机的比较中找到计算机模型的一些特性,而我们则似乎能从这个比较中找到大模型工程的一些关键点,大模型显然更接近人脑一些。
01 逻辑链与准确度
冯诺依曼在书中,主要先是通过模拟电路和数字电路的准确度比较,来明确数字电路类型的现代计算机。比较有意思的是,冯诺依曼所在的年代,大家对于计算机使用数字电路还是模拟电路有些犹豫,冯诺依曼在书中这样写道:
算术四则必须分解为基本的逻辑步骤,因为每一次运算本身都是一条很长的逻辑链子。但是,我们这里只需要谈谈算术深度的问题。
如果有很大量的算术运算,则每一次运算所出现的误差是叠加的。
我们可以看到,冯诺依曼认为真正应用于实际的计算,不会只有一次计算,而通常是有一条逻辑计算链。模拟电路虽然能计算微分方程,但在做复杂计算的时候却会导致误差叠加。
看到这里我们会想到了什么?是的,就是思维链。思维链的运作过程和计算有一定相似度,当推理过程中有一些幻觉信息的时候,确实也会导致准确度的进一步下降。所以是不是链式的思维链推理,适合准确度高的推理但不适合发散性的推理?我们带着这个问题继续往下看。
02记忆与 RAG
内存这个概念是在冯诺依曼架构中被提出,所以祖师爷在这本书中也重点讲了记忆与神经系统的这部分,还留下的这段文字:
必须注意,神经系统使用基本作用器官作为记忆元件,是不适宜的。这样的记忆,可以标注为「用基本作用器官组成的记忆」,它从各方面的意义来说,都是很浪费的。但是,现代的计算机技术却是从这样的装置开始的。
我能理解冯诺依曼当时写这段文字的初衷,他希望把存储的物理结构与主的计算结构区分开,历史也确实是沿着他的设想这样展开的,有了内存,有了硬盘。
而现在,历史似乎又到了一个类似的十字路口。大模型的记忆方案应该用什么?检索增强(RAG)还是微调还是什么?所以我们回看一下上面祖师爷的这段话:记忆的基础元件不需要和基本作用器官的元件相同。所以记忆这东西,是不是其实可以八仙过海各显神通,只要有办法记录下来就行。
我们可以以大脑为例,做个假设:大家知道被海马体有问题的人,可能长期记忆存在问题。但如果我们提供一个非常厉害的 VR 外设,可以记录他所有的事情,这样,虽然他无法通过海马体来获取长期记忆,但是 VR 外设能在他需要的记忆给召回,那么,这个人是否就能表现得和正常人一样?这样是否就说明记忆可以完全外挂在大脑外面。
这里有个非常有意思的小插曲,我在阅读的时候,顺带翻了一下豆瓣的评价,看到这么一个评价,他在吐槽 Memory 应该翻译成存储器,而不应该翻译成记忆,搞得像看科幻小说一样。
看看我们现在大模型方案中各种的记忆方案,我也无法做过多评价,哈哈。十年前的我们看看我们现在的在做的事情,可能真的像在看科幻小说一样。
03逻辑的语言
翻到倒数第二章的时候,我倒吸了一口冷气,为什么这个和我们当前在做大模型提示词工程时候碰到问题这么像,我摘出来给大家看看:
应该指出,正如前面讲过的,神经系统中所使用的信息系统,其本质是统计性质的。换句话说,它不是规定的符号、数字的精确位置的问题,而是信息出现的统计性质问题,即周期性或近似周期性的脉冲序列的频率问题等。
所以,看来神经系统所运用的记数系统,和我们所熟悉的一般的算术和数学系统根本不同。它不是一种准确的符号系统,在符号系统中,符号的记数位置、符号的出现或不出现等,对消息的意义具有决定性。它是一种另外的记数系统,消息的意义由消息的统计性质来传送。我们已经看到,这种办法怎样带来了较低的算术准确度水平,但却得到较高的逻辑可靠度水平。就是说算术上的恶化,换来了逻辑上的改进。
这让我们想到,在大模型工程中,我们常常会让大模型进行计算,但是很多时间大模型的计算却又容易在阴沟里面翻船:明明主体部分已经算完了,最后给单位的时候给错了。如果在推理之后再加个自省环节,有些时候也能将问题修正,只是这表现确实跟冯诺依曼笔下的人脑有点像。
冯诺依曼本身只是为了讲讲大脑神经系统的统计学特性,但却道出了大模型在做推理工程时的关键点:推理深度和计算准确度的平衡。如果让大模型能在合适的时机,使用工具进行准确计算,会比用大模型自行推理计算效果要好。
《计算机与人脑》的最后一章,我觉得更是惊艳,基本上可以形成提示词工程的一些纲领性的思考。
还应该指出,这里所说的神经系统中的语言,可能相当于我们前面讲过的短码,而不是相当于完全码。当我们讲到数学时,我们是讨论一种第二语言,它是建立在中央神经系统所真正使用的第一语言的基础之上的。
...我们现在已经积累了足够的证据,不论中央神经系统用什么语言,但是它的标志是:它比我们惯常的逻辑深度和算术深度都要小。...因此,中央神经系统中的逻辑学和算术方法,当我们把它作为语言来看时,它一定在结构上和我们日常经验中的语言有着本质上的不同。
在提示词的工程实践中,我们发现如果基于开发工具(Tool)+智能体(Agent)的方案,传统编程比起来,在初期,其实不太具有优势,为什么这么说呢?因为很多时候,工具开发完,可能问题已经大部分解决了,上面加一个思维链来调用工具的稳定性还不如直接用流程编排来调用。可能后面随着工具的增多,智能体方案会有一些优势,但总是比较有限,这到底是为什么呢?
因为定制化的工具较难举一反三,每个工具使用参数有些相似,但又有不同,你必须用大篇幅的提示词来告诉大模型怎么用。我们发现使用 DSL(领域特定语言)可以很好地解决这个问题,因为基本每种 DSL 大模型都会用,你根本不用提示词来教。举个例子,SQL 就是一种 DSL,你可以建一张学生表、一张成绩表,在学生表里有学生的学号、出生年月,在成绩表中有各科的成绩。将这些表结构告诉大模型之后,你可以进行提问,成绩最好的同学是什么星座?面对这样有点离谱的问题,大模型却一点都不会犯怵。一组 case when 就把星座映射上去了:
SELECT s.name AS student_name, s.birth_date, CASE WHEN MONTH(s.birth_date) = 1 AND DAY(s.birth_date) >= 20 OR MONTH(s.birth_date) = 2 AND DAY(s.birth_date) <= 18 THEN '水瓶座' WHEN MONTH(s.birth_date) = 2 AND DAY(s.birth_date) >= 19 OR MONTH(s.birth_date) = 3 AND DAY(s.birth_date) <= 20 THEN '双鱼座' WHEN MONTH(s.birth_date) = 3 AND DAY(s.birth_date) >= 21 OR MONTH(s.birth_date) = 4 AND DAY(s.birth_date) <= 19 THEN '白羊座' WHEN MONTH(s.birth_date) = 4 AND DAY(s.birth_date) >= 20 OR MONTH(s.birth_date) = 5 AND DAY(s.birth_date) <= 20 THEN '金牛座' WHEN MONTH(s.birth_date) = 5 AND DAY(s.birth_date) >= 21 OR MONTH(s.birth_date) = 6 AND DAY(s.birth_date) <= 21 THEN '双子座' WHEN MONTH(s.birth_date) = 6 AND DAY(s.birth_date) >= 22 OR MONTH(s.birth_date) = 7 AND DAY(s.birth_date) <= 22 THEN '巨蟹座' WHEN MONTH(s.birth_date) = 7 AND DAY(s.birth_date) >= 23 OR MONTH(s.birth_date) = 8 AND DAY(s.birth_date) <= 22 THEN '狮子座' WHEN MONTH(s.birth_date) = 8 AND DAY(s.birth_date) >= 23 OR MONTH(s.birth_date) = 9 AND DAY(s.birth_date) <= 22 THEN '处女座' WHEN MONTH(s.birth_date) = 9 AND DAY(s.birth_date) >= 23 OR MONTH(s.birth_date) = 10 AND DAY(s.birth_date) <= 23 THEN '天秤座' WHEN MONTH(s.birth_date) = 10 AND DAY(s.birth_date) >= 24 OR MONTH(s.birth_date) = 11 AND DAY(s.birth_date) <= 22 THEN '天蝎座' WHEN MONTH(s.birth_date) = 11 AND DAY(s.birth_date) >= 23 OR MONTH(s.birth_date) = 12 AND DAY(s.birth_date) <= 21 THEN '射手座' ELSE '摩羯座' END AS zodiac_sign FROM students s JOIN grades g ON s.student_id = g.student_id WHERE g.score = (SELECT MAX(score) FROM grades);
由此可见,通过 DSL(领域特定语言),大模型确实可以做出一些惊艳的逻辑推理表达。然后我们再回过头来看看冯诺依曼上面的这些论述,DSL 相比较真正的代码而言,似乎就具有这种冯诺依曼断言人脑的神经系统语言时的一些特征:
- 它需要是种语言,能清晰地表达推理逻辑,但又没有真正的自然语言那么灵活。
- 它同时也能有表达特定领域的计算逻辑,但又不需要像真正的计算公式那样完全。
我们可以列举一些我们平常能接触到 DSL,以及我们可以做到的一些大模型探索尝试:
- SQL:让大模型自行编写 SQL 来解决问题,并根据 SQL 报错自己调整 SQL
- 文件系统:树形的文件系统可以结构化地存放信息,向大模型表达。同时,大模型也可以基于树形结构,结构化地解决问题,比如调整文件目录等。现在比较火的 Cursor 也是在这个方向上的探索。
- PromQL:这个是 Prometheus 的查询语法,常用于时序数据的灵活查询,让大模型编写 promql,然后结合多模态的图片返回,就能让大模型真正学会像人一样去选时间、看指标、分析趋势或抓异常点。
04推理和计算
其实在构建大模型提示词工程的时候,一直有个问题困扰着我,就是如何处理逻辑推理和计算的关系?虽然我们在提示词中和大模型强调,不要自己用逻辑去算,要学会利用工具去做计算,但效果总没有那么理想。
直到我看到祖师爷的这段话的时候,突然得到了那么些启示:
继续追踪这个课题,使我们必须探讨语言的问题。我曾指出,神经系统是基于两种类型的通信方式的。一种是不包含有算术形式体系的,一种是算术形式体系的。这就是说:一种是指令的通信(逻辑的通信),一种是数字的通信(算术的通信),前者可以用语言叙述,而后者则是数学的叙述。
对于大模型的提示词工程来说,我们让大模型解决问题的时候,需要区分【推理】和【计算】这两种任务类型--但这两种类型事实上是非常难分解开来的,那么要怎么做呢?循着祖师爷的思路,我们尝试着对【推理】和【计算】来重新做个大模型工程下的定义和梳理:
- 什么是推理?它是一种语言叙述,类似苏格拉底反诘法,把一个复杂问题转化成若干个简单一点的问题(降维),推理过程中不追求答案,只需要将问题做分解即可。
- 什么是计算?它是一种数学叙述,能够利用现有的工具,求解获得答案。大模型的每次计算过程,可以用有限条思维链来进行落地。
- 什么时候选择用推理,什么时候选择用计算?当计算产生幻觉或者无法求解答案时,就转化成推理进行问题拆分(降维)
读到这里,我的心情有点复杂,这本书是根据冯诺依曼的未完成的讲稿而来的,可能很多思路在祖师爷的脑子里已经有了,但是我们永远也无法知晓了。冯诺依曼是从大脑和神经系统出发,思考的这些关键点居然和大模型提示词工程的关键点非常契合,确实有点神奇。
我意犹未尽地合上这本书,看了眼熟睡的孩子。晚安,我的宝贝,希望等你能够读懂这本书的时候,我们已经借助大模型搞清祖师爷给我们留的这些宝藏。/ END /