王路在隐身

我怎样教AI学阿毗达磨?——强化学习在特殊领域的奖励函数设计

之前的文章说过,想让AI学会阿毗达磨,得先给它的分词器小小捯饬一下,把阿毗达磨的高频词放进词汇表,让它们都有独立的token。这项工作比较简单。

然后是微调。因为阿毗达磨的数据太少了,高质量数据也就200万字,加上中等质量数据,撑死也就1000万字。所以,微调不会显著地改进模型的表现,只会让它装腔作势。什么叫装腔作势呢?就是看着好像是那么回事,实际上啥也不懂。——我觉得做佛教AI的一定要警惕这种情况。不要把AI搞成佛油子。碳基社会有佛油子就算了,你把硅基社会也高出一大批佛油子,这……——可能真的是硅基难以超越碳基的一大能力。说白了就是“忽悠瘸”的能力。

举个例子。河北有个大寺,大寺有个大殿,大殿门口理所当然要挂个大牌匾,上面写着四个大字:三摩妙地。

“三摩妙地”是什么概念?英国有个摇滚乐队,1960年代在利物浦,约翰列侬——披头勇士。——这就是“三摩妙地”。你讲出去,英国人不知道,英国人只知道“披头士”,The Beatles嘛,那“披头勇士”是啥?只能是beat youth。“三摩妙地”也是这个道理,“三摩地”还不够妙,要让它更妙,三摩妙地。

人类社会很多这种东西。装模作样发表个文章,出版个报告,装订得齐齐整整,参考文献列了一大堆,懂行的翻开一看,都是“三摩妙地”。——微调后的AI,哪怕是3B模型,都足以生成“三摩妙地”了。如果你不说,让它排好版,拿出去,有人还真以为是阿毗达磨专家。但是,问一句“色界无漏缘惑有哪些”,立马现出原形。但这已经是微调的极限,困惑度降到低得不能再低表现还是这熊样子。下一步,就该上强化学习了。

AI针对阿毗达磨的强化学习策略,就是这篇文章要聊的。

强化学习通常能显著提升AI在未经专门训练的领域的表现。但是,阿毗达磨方面的强化学习,对我来说,有一个现实的考验:数据集的构建。

微调阶段,我也没有用jsonl格式的数据,而是直接让它学习文本。这是因为:没钱,没时间。你让AI搞,就算目前grok3这种去生成问答对,质量都不理想(如果理想,我再搞这些就是吃太饱了)。我自己去搞问答对,是能把我搞残的。阿毗达磨不像数学那样有奥赛题库、中学题库。在微调阶段,直接让它吃TXT文本就算了,强化学习,你要设定奖励函数,它答对了,答得好,奖励,答不好,惩罚。——那怎么才算答得对、答得好呢?

“答得好”很容易设计,比如借鉴deepseek的思路,让它按照固定格式输出,格式对了就奖励。或者,不要让它输出太短,以及产生无意义的重复。——这些都好办。问题是,判断它是否答得对,你是不是得先有题目和答案?你没有答案,怎么判断呢?而我又不可能自己去写题目和答案。又没有现成的题库拿来用。

好就好在,有个东西叫《俱舍论颂》。三年前,我们的“尊重毗昙”群刚建立的时候,我会在群里发一些思考题。后来,我经常在题目结尾注上“引颂回答”。就是说,你在回答一道阿毗达磨问题的时候,先把相关的颂列出来。列不出来颂,就是瞎回答。好比做高考物理题,先把公式列出来。一道题目用到哪几个公式,齐刷刷列出来,列对,再代入数值去计算。把公式都列对,就可以得到一半的分了。我们在教AI学阿毗达磨的时候,完全可以借鉴这个思路。

我一上来想到的就是这个。《大毗婆沙论》,是阿毗达磨的经典。“我多以此释对法”。《俱舍论》,是阿毗达磨史上的一大杰作。它的杰出之处不在于探讨得深(实际上没有《婆沙》《正理》深),而在于它充分借鉴了《心论》《杂心论》的形式,把阿毗达磨的核心问题用601个颂给摄住了。就像你有一兜子散铜钱,你要么拿绳子把它串起来,要么用麻袋把它们装起来,要么换成一张整钞票。——我们翻开《婆沙》,任选一段,你能不能说出它对应的《俱舍论》颂是什么?可能不止一个,但一般都能对应上一两个。

这就可以成为设定奖励函数的起点。

我一开始就是奔着这个方向去的。随机从文本中任选连贯的256字,让模型找601个颂中和它最相关的一个(当然,也可以设计成找两个三个,设计成一个是为了简单,先跑通简单的,再上难度)。问题是,它找得对不对?人类验证吗?不可能的。你让它同一段文本互不干扰地找两次,就行了。就像我们做数学题,做完检查一遍,检查数学和检查语文不一样,检查语文可能就是看看,检查数学往往要你再算一遍,两遍算的过程和结果一模一样,正确几率就大很多。哪怕两次掉到同一个坑里,至少不是完全不会。

所以,我让AI在每一回合,针对一段256字的阿毗达磨文本,找和它最相关的颂,独立找两次,如果找到的是同一个颂,就奖励。但这个规则是有漏洞的。比如AI一滑头,学会了每次都选第1个,你不管问它任何文本,它都说,最相关的是“有漏无漏法,除道余有为”,你怎么办?再加上grok告诉我(grok是帮我写代码的AI,不是要训练的),每次从601个颂里面选1个,开销太大了。我就想,干脆每回合先随机选30个颂,让AI从这30个里面选最相关的。它就不可能每回合都选一样的颂。

这是我的第一个实验。完全失败。失败的原因是,AI几乎在20秒内,就做到了把正确率提升到接近100%。我一看就知道,完蛋了。如果AI能在20秒内学会,那它就啥也没学会。grok给我预估的训练时长是5小时,实际上,模型只训练了不到3分钟,就完成了10万步。

我反省原因,重新设计实验。这次,不是让它在30个里面选,而是让它在300个里面选;更重要的,不是每一回合随机生成300,让它两次在固定的300里面选,而是每一回合两次随机生成300,这样,基本上可以保证第二次选的时候不受第一次的干扰了(之前30选1的时候,虽然我一再告诉grok,不要让模型后一次选择受前一次的影响,但我并不确定grok给我的代码能不能做到这一点,因为我看不懂代码)。两个300按概率说,平均有150的交集。这就相当于整个颂集的四分之一。我想看看效果。

结果,AI每1000步的平均得分是0.01,也就是说,和瞎蒙的一样。

grok建议我,把300减小到100,这样可以提高模型答对的次数。我告诉grok,你说错了,不是应该减小到100,而是应该增加到500。因为,30的时候之所以得分率高,主要因为两次选择的集合是固定的,这和每次从601的全集中选,是类似的。我们要保证两次选择的集合有大部分重叠,又不完全一样,以防止AI作弊。要在极难和极易之间找到一个平衡点。那个平衡点我认为可能更像是500而不是100,因为两次随机选择100,它们的交集非常小。grok听了,连连表示人类英明。我还放大了奖励额度,从得1分到10分又到100分,希望促进收敛。

结果呢?完全没有改观。AI答对的概率还是和瞎蒙一样。

我和grok探讨原因。最后整明白了:其实AI根本没有读懂文本。它的选择是在完全不理解语义的情况下做出的。——就是瞎蒙。

这让我明白,上面所有的设计思路,都破产了。

就像高中生刷题,如果你刷第一套卷子是20分,刷到第100套同等难度的卷子还是20分,那这些题目都白刷了。刷题的必要前提是记住公式,公式都记不住,刷题不是瞎刷吗?

所以,我得转换思路。不能让AI直接去选择,要让它先根据prompt生成内容,再由它所生成的内容来奖励或者惩罚。就好比,你可以瞎蒙选择题,但后面的大题你没法蒙。

prompt仍然不能是我来写,还是要自动生成;答案,也是要自动生成。怎么生成呢?我还是借鉴了之前失败的教训(失败不代表它里面就没有可取的):让模型随机选一个颂,根据颂检索到相关文本——比如抽到的颂是“从生眼等根,三和前六处”,就去数据库里检索前5个字“从生眼等根”,截取随后的100个字(截取多了4090的显存吃不消,费钱),也就是,给它颂,给它参考的长行,让它翻译解释颂。等它解释完,用解释的内容作为第二次prompt,返回给它,问它内容和哪个颂最相关。

这种设计也有bug。bug就是,它看不懂,就把要翻译的颂抄一遍。你的prompt是什么,他的输出就是什么。拿这个输出去601个颂里比对,自然能比对出来,因为原文就在里面——这就有点像人类了:有些人类写论文,要引用古文,自己读不懂,怎么办?读不懂的时候就引原文,读懂的时候就换成自己的表述。

又失败。

grok和Claude都多次告诉我,为什么不用余弦相似度去匹配?我说,那不行,你不能用余弦相似度去匹配两个方式是不是等价,或者一道数学题是不是正确。这些时候,你肯定不能听AI的建议。使用AI的时候,得知道哪些建议是可听的,哪些是坚决不能听的。它不理解阿毗达磨的特殊性。

我就想:你不能给它看颂,但是,又要让它的输出和颂相关,而且是强相关。——这也有办法。我们都知道,和颂强相关的就是长行。《俱舍》每一个颂,底下都有对应的解释。我最初想到的是,比如抽到“从生眼等根”这个颂,让它从颂后面截取100个字,但是不截取颂本身,那么,后面的基本就是颂对应的长行,让它去翻译长行,然后返回翻译和601个颂比对相关度。——思路不难想,但问题出在“基本”两个字上。

《俱舍》颂的排布,不是有规律的。有些时候,1个颂,底下是长行;有些时候,连着2个、3个颂,底下才是长行;有些时候,半个颂,甚至四分之一个颂,底下就是长行。用这种方式截取,极其粗糙。你截到的可能不是长行,而是后面紧跟着的颂。那它自然就翻译成后面颂的意思了。

所以,哪怕大体上思路不难想到,但具体处理起来,细节上的坑非常多。一个个小问题等着你去解决。

这一点,后来我也解决了。给大家看我给grok写的一个prompt。

【

现在,写一个代码,要求:

从apdm2_processed.txt中找每一个【頌曰】,看看【頌曰】之后的第一个【論曰】和之前的【頌曰】之间字数是否不超过125(如果否,则忽略,去找下一个【頌曰】),如果是,则把【頌曰】【(之间的内容,即颂)】【論曰】【(論曰到下一个頌曰之前的内容,即论,如果该内容不超过100字)或者(論曰后100字的内容,如果論曰后100字中没有【頌曰】)】,把这四部分分为四行输出。

例如,对文本:

【頌曰色者唯五根五境及無表論曰言五根者所謂眼耳鼻舌身根言五境者即是眼等五根境界所謂色聲香味所觸及無表者謂無表色唯依此量立色蘊名此中先應說五根相頌曰彼識依淨色名眼等五根論曰彼謂前說色等五境識即色聲香味觸識彼識所依五種淨……】

输出为:

頌曰

色者唯五根五境及無表

論曰

言五根者所謂眼耳鼻舌身根言五境者即是眼等五根境界所謂色聲香味所觸及無表者謂無表色唯依此量立色蘊名此中先應說五根相

頌曰

彼識依淨色名眼等五根

論曰

彼謂前說色等五境識即色聲香味觸識彼識所依五種淨……(等100字,如果100字中没有頌曰)

——以上不含任何标点和编号。我不知道你是否清楚了我的意思?

如果清楚,请给我代码,将输出内容保存为songlun.txt。

】

和grok这么聪明的AI交流是有快感的。——它能听懂你复杂的表示。大多数人类是没有耐心去听你很复杂的表达,而且没有能力。但是强大的AI,到grok3这个程度,它在80%的时候都遵循得很好。之前我用deepseek不是因为deepseek是国产,而是因为deepseek刚出来那会儿,确实在写文章上比所有市面上的AI都好。但是上周,grok3出来,我就很少再用deepseek了。这几天Claude 3.7 sonnet也出来了。所以现在我基本上用grok3,偶尔用3.7 sonnet。

我跟grok介绍我的设计,让它出代码,经常会有1条prompt写上大几百字的时候,这还不包括复制的内容,不包括改代码中的错误。有时候上下文太长,只能换页面,你又不得不重新告诉它一遍项目的各种情况细节。

如果读者有兴趣看完我上面那条prompt,大概就知道我想干什么。如果还有耐心,我就请你再看一条:

【

谢谢。我想对微调过的模型做强化学习RL。1、【root@autodl-container-3ec549bc14-d2ce1eec:~/autodl-tmp/Qwen2___5-3B-Instruct# ls

LICENSE                      configuration.json                token_id_results_debug.txt

README.md                    generation_config.json            token_id_results_debug_v2.txt

added_tokens.json            merges.txt                        token_id_results_debug_v3.txt

check_token_ids.py           model-00001-of-00002.safetensors  tokenizer.json

check_token_ids_debug.py     model-00002-of-00002.safetensors  tokenizer_config.json

check_token_ids_debug_v2.py  model.safetensors.index.json      vocab.json

check_token_ids_debug_v3.py  special_tokens_map.json

config.json                  token_id_results.txt】【autodl-tmp/full_finetuned_new/global_step2166/mp_rank_00_model_states.pt】——请你记住模型文件的内容以及RL需要加载的检查点路径。2、请你熟悉songandlun.txt的形式,就是你刚才生成的,第4n+1行是【頌曰】,第4n+2行是颂;第4n+3行是【論曰】,第4n+4行是论。例如:【

頌曰

內十二眼等色等六為外

論曰

六根六識十二名內外謂所餘色等六境我依名內外謂此餘我體既無內外何有非無淨戒有淨戒依經主此中作如是釋我執依止故假說心為我故契經說由善調伏我智者得生天世尊餘處說調伏心如契經言應善調伏心心調能引樂故但於心假說

頌曰

法同分餘二作不作自業

論曰

法同分者謂一法界唯是同分今應先辨境同分相若境與識定為所緣且如法界與彼意識為定所緣是不共故識於其中已生生法此所緣境說名同分意能遍緣一切境故於三世境及非世中無一法界不於其中已正當生無邊意識二念意識即能普緣】3、我希望随机选择一段论(songandlun.txt中第4n+4行),作为prompt给模型:【请翻译以下内容:(论,最长100字)】;得到模型的输出之后,根据模型的输出去songandlun.txt中匹配最接近的2个颂(而不是论),即第4n+2行,注意,要找两个匹配的n值。如果其中有1个n和所选择的论的n值一致,就得15分。

——不知道你是否理解我的思路?先不用写代码,先说说你的理解。另外,我用的是4090的GPU。我们后续要注意不出现OOM的问题。

】

grok问我,怎么变成了songandlun.txt?不应该是它刚才生成的songlun.txt吗?是不是我笔误了?我说不是,因为之前用的文本中有换行,导致生成的论所在的行数并不必然是4的倍数,我拉到文本最底下一看,最后一行的行数是奇数,就知道有问题了。于是又重新把《婆沙》等数据换成取消换行版,再重新执行程序保存。

上面,就是我设计的第一个可运行的强化学习的奖励函数。主要是,它是自动的。根据阿毗达磨文献的特殊性,自动生成题目和判定标准。

为什么当前的AI在阿毗达磨上表现拉胯?

入群标准,以及手搓阿毗达磨AI的小目标