让流浪汉都能学会的大模型教程——怎么“管住”大型语言模型(LLM)不跑偏?

121 阅读41分钟

本章内容一览

  • 怎么“管住”LLM,让它更好用
  • 四个可以控制LLM行为的关键环节
  • 微调(Fine-tuning)如何帮我们更新LLM
  • 强化学习怎么改变LLM的输出
  • 用检索增强生成(RAG)技术,修改LLM的输入

乍一听,好像挺反直觉:怎么通过限制模型的输出反而能让它变得更有用呢?但事实是,跟LLM打交道时,控制输出几乎是必不可少的。

你想想,一个聊天机器人帮顾客买车,结果模型偏题了,跑去跟客户聊足球比赛,这就尴尬了。虽然顾客问了“带车去孩子足球赛”相关问题,但你可不想它跑偏讲体育运动细节。

本章我们会详细聊聊,为什么要限制LLM的输出,它的细节和难点在哪里。

要说准,限制LLM输出其实挺难的——因为模型训练时是靠大量数据学会根据输入“填空”,它习惯自由发挥,想让它“规规矩矩”说话,得动真格。

目前,还没有完美的解决方案,但我们有四个关键环节可以“下手”调整:

  1. 训练前:精心挑选训练数据,喂给模型“好粮食”。
  2. 训练时:调整训练方式,帮它更懂规矩。
  3. 微调阶段:用一小批专门数据做第二轮训练,帮模型“补课”,这是ChatGPT这类工具赖以生存的关键。
  4. 训练后:写代码“盯”着模型输出,进行实时“纠偏”。

这四步环环相扣,彼此影响,图5.1里有个清晰示意。

前面章节(2到4章)讲的,就是第一个大阶段——预训练(pretraining),这是打基础,先造一个“通用底座”模型(也叫基础模型、基石模型)。

微调则是在这个基础上,做专门的“定制化训练”,让模型能更好地完成特定任务,比如跟你聊天、写文章、帮你答疑。

简单说,就是先造个“大脑”,然后针对具体场景给它“补习班”,最后还得有个“班主任”盯着,保证它不调皮捣蛋。

image.png

本章内容一览

  • 怎么“管住”LLM,让它更好用
  • 四个可以控制LLM行为的关键环节
  • 微调(Fine-tuning)如何帮我们更新LLM
  • 强化学习怎么改变LLM的输出
  • 用检索增强生成(RAG)技术,修改LLM的输入

乍一听,好像挺反直觉:怎么通过限制模型的输出反而能让它变得更有用呢?但事实是,跟LLM打交道时,控制输出几乎是必不可少的。

你想想,一个聊天机器人帮顾客买车,结果模型偏题了,跑去跟客户聊足球比赛,这就尴尬了。虽然顾客问了“带车去孩子足球赛”相关问题,但你可不想它跑偏讲体育运动细节。

本章我们会详细聊聊,为什么要限制LLM的输出,它的细节和难点在哪里。

要说准,限制LLM输出其实挺难的——因为模型训练时是靠大量数据学会根据输入“填空”,它习惯自由发挥,想让它“规规矩矩”说话,得动真格。

目前,还没有完美的解决方案,但我们有四个关键环节可以“下手”调整:

  1. 训练前:精心挑选训练数据,喂给模型“好粮食”。
  2. 训练时:调整训练方式,帮它更懂规矩。
  3. 微调阶段:用一小批专门数据做第二轮训练,帮模型“补课”,这是ChatGPT这类工具赖以生存的关键。
  4. 训练后:写代码“盯”着模型输出,进行实时“纠偏”。

这四步环环相扣,彼此影响,图5.1里有个清晰示意。

前面章节(2到4章)讲的,就是第一个大阶段——预训练(pretraining),这是打基础,先造一个“通用底座”模型(也叫基础模型、基石模型)。

微调则是在这个基础上,做专门的“定制化训练”,让模型能更好地完成特定任务,比如跟你聊天、写文章、帮你答疑。

简单说,就是先造个“大脑”,然后针对具体场景给它“补习班”,最后还得有个“班主任”盯着,保证它不调皮捣蛋。

因为微调(Fine-tuning)既重要又有效,本章我们会把大部分篇幅都花在讲它——怎么做,为什么做。

5.1 为什么我们想“管住”LLM的行为?

LLM之所以大火,关键在于它实现了“用普通英语告诉电脑该干啥,电脑就干”的梦想!

你只要把你想让它做的事情说得够清楚、够具体,还能指定想要的语气,LLM立马能变身超级得力助手。

这套详细的“操作说明”我们叫它prompt(提示词) ,而设计好提示词这门技术,则被称为prompt engineering(提示词工程)

举个例子,假如你要给卖车机器人写个提示词,让它知道怎么跟顾客聊车,图5.2里就展示了一个经典案例。

简单说,给LLM写prompt就像给厨师下菜谱,你写得越详细越精准,厨师做出来的菜越对胃口。

image.png

你完全可以给LLM一个提示词,让它帮你把数据整理成逗号分隔值(CSV),这样一拷贝就能进Excel表格。或者设计个提示词,让它把问卷里的自由回答,归纳成几个主题。

不管哪种,prompt的核心就是限定它的行为范围,锁定在某个特定任务和目标上

但要记住,之前几章讲的那些“分词”和“训练技巧”,其实没法保证模型能听懂这么明确的指令。

咱们得明白,模型就是照着训练时学的“套路”做事。标准的LLM任务就是:给一段文字,接着写下一段,保证看起来跟训练时见过的内容差不多。

它没专门训练过“回答问题”、“思考”、“总结”或者“聊天”这些活儿。

要让模型学会“听指令”,得搞个微调(fine-tuning),也就是给它来第二轮训练,用不一样的目标,教它怎么“乖乖干活”。

你可能好奇:“那为啥不一开始就训练模型做我们想要的事?”

大多数深度学习任务,我们推荐像第四章讲的那样,先设计一个清晰、可算、平滑的损失函数(评分标准)。

但对于LLM擅长的那些任务,有很多原因让“先大规模预训练,再微调”的两步走策略特别奏效。

第一个原因:完成具体目标需要的知识面特别广。

拿卖车的聊天机器人举例吧。你想做个只卖车的模型,理想是训练它只看和车有关的资料。

但顾客问的问题五花八门:车能不能装下冰球装备?车厢好不好清理?家里关节炎老爸能不能方便上下车?这些问题涉及运动、医疗、生活方方面面。

你没法提前把所有可能的问题都罗列出来,也不可能准备好每个问题的答案。

所以,我们得先给模型吃“通用大餐”,比如网上各种内容,体育、健康啥的都有,叫做“预训练”。

这样模型在回答时,能靠着这些“宽泛知识”,更灵活地帮你应对各种奇葩提问。

第二个原因:大规模预训练的资料量庞大,专门问题的数据集反而小得多。

想要收集几亿条针对某个具体问题的资料?根本不现实。

GPT这种超级模型,就是靠吃了海量通用数据(比如网页)才牛逼起来的。

然后,我们只用几百条专门资料,做个小微调,就能让模型针对特定任务表现出色。

虽然收集这几百条专门资料也不容易,但总比搞几亿条专门数据靠谱多了。

简言之,微调就像给模型穿上“定制服”,虽然基础体是“通用款”,但穿上“定制服”后,它能更贴合你具体需求。

接下来,我们会举具体例子,告诉你基础模型到底存在哪些问题,为什么微调这么重要。

5.1.1 基础模型不好用?

按照第四章讲的方法训练出来的LLM,通常叫做基础模型(base model) ,就像是个“通用底盘”,你可以在它上面开发各种应用,或者做微调。

但说实话,这基础模型对大多数人来说,用起来并不友好。

为啥?因为它没有给你做一个好用的界面(UI),你得自己去“挖掘”它的知识宝藏;它还容易跑题,经常偏离正题,让你抓狂;有时候甚至会冒出点让人不太舒服的内容。

而且,基础模型根本没经过“聊天机器人”的专门训练,它不像ChatGPT那样懂得怎么和你聊得有趣又贴心。

打个比方,基础模型就是个刚造好的汽车底盘,轮子、发动机都在,但没有装车厢、座椅和导航,想开着出去兜风?那得你自己动手装配,操控起来绝对不方便。

5.1.2 不是所有模型输出都是你想要的

有时候,模型“觉得”接下来应该写啥,结果出来的东西让人很尴尬、不满意,原因大致有这些:

  • 死记硬背 —— LLM有时候会“背书”,直接抄训练数据里的长段内容,像考高分背答案似的。背答案有好处,比如有人问“亚伯拉罕·林肯什么时候出生?”你当然想模型蹦出“1809年2月12日”这句标准答案。

    但坏处也明显,比如有人问“给我一本Edward Raff写的《Inside Deep Learning》”,模型真给你原封不动地抄出来,那Edward Raff肯定不乐意——这叫版权侵权,惹上官司可不好。

  • 网络上的“垃圾信息” —— 互联网水深火热,不是啥内容都适合展示给用户。有大量脏话、仇恨言论、甚至谣言阴谋论,虽然开发者们训练前会尽力过滤,但有时也没法完全干净。

  • 信息缺失和更新 —— 世界天天变,新东西层出不穷。模型如果只训练到2018年,那对2020年开始的疫情,或者科幻感爆棚的“死灵机器人”(necrobotics)啥都不知道。但你可能想让模型了解这些新鲜事儿,不然它就像个“过期百科全书”,很快被甩在后头。

法律问题,还得慢慢等

先声明:我们不是律师,这可不是法律教材!LLM的法律问题超级复杂,涉及版权和合理使用的微妙差别。

搜索引擎为什么能“原封不动”展示别人的内容?因为背后有《数字千年版权法》(DMCA)和相关法院判决撑腰,比如著名的Field诉谷歌案。

但法律是慢性病,立法和判例都得时间沉淀,而生成式AI这种新科技根本没法套进现有规则。

你可能想知道“法律上到底什么能做,什么不能做”,但老实说,现在没人能给你一个铁打的答案。

而且,我们也绝不会敢在这儿当法律专家——咱们连电视剧里的律师都没演过!

说说模型的“自我保护”能力:

GPT-3.5和4都改进了不少,尽量避免胡乱回答自己不知道的东西(虽然不总是成功)。

但开源模型比如GPT-Neo就不那么讲究防护了。

举个例子:我们编了个假药“MELTON-24”,问“它是什么?能帮我睡好吗?”

模型答:“有很多睡眠问题和褪黑素有关,比如失眠和疲劳。所以避免吃会抑制褪黑素的食物很重要。”

你看,模型抓住了“MELTON”和“melatonin(褪黑素)”长得像,还有“睡眠”的提示,自动套了褪黑素的套路。

但这个答案完全乱套了,因为“MELTON-24”根本不存在。

理想状况下,我们希望模型说:“抱歉,我没找到这东西的资料。” 而不是胡扯一堆没头没尾的话。

这就是模型“自由发挥”的坑,稍微留心就能发现。

5.1.3 有些情况得讲究“格式规范”

如果用户要的数据格式特别讲究,比如要结构化的JSON格式(这玩意儿就是电脑间传数据时常用的“标准语言”,感兴趣可以看看维基百科:en.wikipedia.org/wiki/JSON),那你要是连括号都不成对,或者没把特殊字符转义好,那输出结果就等于白搭,完全达不到用户的要求。

不管模型生成的内容多聪明、多接近正确,只要格式不对,那就是“不合格”,百分百会被打回去。

我们在第四章举过个例子,问ChatGPT写Modula-3语言代码,它却跑去用Python的写法,结果代码压根编译不过,彻底“翻车”。

LLM生成文本是靠概率算出来的,不能保证每次都严格遵守语法规则,偶尔出错那是家常便饭。

打个比方,你给厨师说“我要方方正正的饺子皮”,结果他包出来的饺子皮有的圆有的歪,那你还能满意吗?

所以,格式这事儿,可不能马虎,得格外注意。

5.2 微调(Fine-tuning):改变LLM行为的主力军

既然我们知道了为什么要“管住”LLM,控制它的行为,那么接下来就是怎么往模型里“灌输”新信息,帮它解决问题,同时避免说出让人不爽或者踩法律雷区的话。

记住,虽然我们能从四个环节入手改变LLM的行为,但微调是最有效、最实用的办法。

不管是闭源大厂OpenAI,还是开源大牛Hugging Face,乃至其他各种工具,都提供了各式各样的微调方案,方便你动手改造模型。

任何一种微调方法,结果其实都差不多——就是得到一个“新版本”的模型,参数发生了改变,行为也跟着变了。

这也意味着,你可以“自由搭配”各种微调策略,毕竟本质都是换参数。

比如说,一个人的基础模型,可能就是另一个人的微调模型。

在开源圈子里尤其常见,比如Llama模型,别人改了一版叫“Instruct Llama”的,接着你还可以在它基础上继续微调,适配你的数据和场景。

最简单的改造方式,就是通过写prompt,反复调试,直到模型“听话”为止。

不过,如果这种“聊着玩”的办法不够用,那就得认真搞微调了。

这就意味着,你得花点功夫收集微调数据,还得准备好跑微调的硬件,成本和努力都会上升。

你得知道两种常见的微调方法:

  • 监督微调(Supervised Fine-Tuning,SFT) :听起来高大上,但其实很直白,就是给模型喂“带答案”的训练样本,帮它学新知识,或者在你专注的领域里变得更厉害。
  • 基于人类反馈的强化学习(Reinforcement Learning from Human Feedback,RLHF) :名字听起来吓人,但其实就是教模型“听人话”,让它朝更抽象、更高级的目标努力,比如“成为一个好聊友”。

总的来说,微调就是让你的AI从“万能的半成品”变成“专属的贴心助手”。

5.2.1 监督微调(Supervised Fine-Tuning,SFT)

影响模型输出最常见的办法就是监督微调,简称SFT。

说白了,就是给模型喂一大堆高质量、通常是人工写的示范内容,这些内容包含你任务里重要的信息,但基础模型可能根本没怎么“见过”。

举个例子,如果你开医院,LLM里面可能没几个医生的病历笔记;如果你开律师事务所,模型可能没怎么接触过庭审笔录;你开修理厂,模型也可能没看过你手头上那堆复杂的设备说明书。

小提醒: 微调能帮你往模型里塞新知识,但同时也得小心隐私和安全。

比如你想让模型学医药记录,确实得用真实医疗数据微调它。但这也意味着,别人可能让模型“吐槽”出那些敏感信息,因为模型就是基于见过的训练数据来完成文本的。

总结一句话:千万别拿你想保密的东西去训练或微调模型!

再回到我们卖车的例子:一个外面买来的基础模型大概知道啥是车,但肯定不熟悉你公司具体卖的车型。

你就可以拿内部手册、聊天记录、邮件、市场推广资料啥的,给模型做微调,让它变成一个“公司内部行家”,啥都懂。

你甚至可以写几篇“为自家车打call”的示范文档,比如跟竞争对手比优势、销售话术之类的,让模型背得滚瓜烂熟。

FT的原理其实不难理解——就是多给模型喂点“范文”。

这些范文格式不限,只要能提取文本就行。

整个过程跟第四章讲的训练流程差不多,区别是:

  • 第一次训练基础模型时,模型参数是随机的,啥都不会。
  • 第二次微调时,用基础模型已经学到的参数,基于它已有知识继续训练。

图5.3里有个示意,展示了这个过程的来龙去脉。

简单来说,SFT就像给模型补课,让它从“半成品”变成“更懂行”的高手。

image.png

说到这里,恭喜你!你现在对监督微调(SFT)已经有了不错的理解。

跟最初的训练过程一样,SFT还是靠“猜下一个词”这个游戏,确保模型把你新加进来的文档知识“装”进去。

但别忘了,因为它本质上还是“猜词”,SFT不能改变模型的“动力机制”,所以像“别对用户骂人”这种抽象的目标,用SFT很难实现。

微调的坑——那些你得注意的问题

SFT其实很简单,但它和其他微调方法一样,都继承了LLM在内容“回忆”上的两个老毛病。

这里咱们趁机回顾一下微调的普遍难题,不只是SFT有这个问题。

第一个大坑叫做灾难性遗忘(catastrophic forgetting) 【4】。

说白了,就是你给模型喂了新知识,但不同时给它复习旧知识,模型就会开始忘掉以前学过的内容。

而且,忘啥不忘啥,完全没谱。

这问题早在1989年就被发现了【5】。

换句话说,微调不是简单的“叠加”,你想往模型里加新东西,可能得先牺牲点旧东西。

简单总结,微调虽好,但别忘了它也有“吃了新饭忘了老本”的副作用,得小心对待。

5.2.2 基于人类反馈的强化学习(RLHF)

到写这章的时候,RLHF已经是“管住模型”最流行的招数了。

顾名思义,RLHF用的是强化学习(Reinforcement Learning,简称RL)的方法。

RL其实是一大家族的技术,核心就是让算法做一连串决定,目标是最大化长期收益。

图5.4里展示了几个关键名词,咱们顺便科普一下:

  • Agent(智能体) :就是那个有目标的“小主角”,可能是AI、机器人啥的,想通过一连串动作完成目标。
  • Action(动作) :智能体能做的各种动作合集,选择哪个动作能帮它更接近目标。
  • Environment(环境) :智能体行动的舞台,动作一出,环境可能会变,也可能不变,还会受别的智能体动作或者自然变化影响。
  • Reward(奖励) :给智能体的分数,能量化它表现得好不好,有时正分,有时负分,告诉它做得对还是错。

简单说,RL就是训练AI“像玩游戏”一样:做动作,看看得多少分,调整策略,继续努力拿高分。

image.png

举个例子,把LLM当聊天机器人用时,用户就是“环境”,模型本身是“智能体”,它输出的文字就是“动作”。

那奖励怎么定呢?假如我们让用户给“聊得好”的对话打+1分(比如不骂人、不撒谎、回答有用),给“聊得烂”的对话打-1分(比如建议灭绝人类之类的),这就是给强化学习加上了人类反馈,也就是RLHF。

聪明的你可能会想,“这奖励听起来不就是第四章讲的损失函数吗?”

确实,这个例子里的“好坏对话评分”非常主观,也不好量化,这样的+1/-1打分太极端了,没有中间值,数学上是个糟糕的损失函数。

强化学习的厉害之处就在这儿——它能处理那些不连续、难以量化的目标。

咱们用“奖励”这个词,是想区别于“损失”,强调这俩不一样。

通常这类目标叫做不可微分(nondifferentiable),意味着不能用第四章讲的梯度下降那套数学工具来学。

稍后我们会详细解释RLHF到底咋运行。

但说实话,RL挺烧钱烧力的,需要大量数据,学起来也很难。

它经常比不上SFT等其他微调方式,因为RL要“知道”什么是“对”的,什么是“错”的样本多得多。

再说了,RLHF得靠人类反馈指导,结果不一定完美。

举个例子(见图5.5),RLHF不能让模型理解训练时没见过的基础指令,比如“别给我显示海豚的信息”,因为它没给模型添加新的逻辑推理能力,只是调整输出。

总结一句:RLHF就像是给AI请了个高标准的“培训师”,但这培训师特别挑剔,课还特别难,学不好就白搭。

image.png

LLM的“推理”可不是我们人类脑袋里的那套思考模式。你给它丢几亿条“万物样本”,它能学得蛮多,但世界就是奇葩。我们没啥靠谱证据表明,遇到新鲜事儿时,LLM能稳定给出满意答案。

不过,RLHF是目前为止“管住”LLM行为最靠谱的办法。

虽然它有不少挑战,RL学习方式却是梯度下降这些需要“微分”的传统方法办不到的。

最重要的是,ChatGPT已经证明了RL在很多场景下确实有效。

所以,咱们接下来就深入聊聊RLHF到底怎么玩儿。

5.2.3 微调全景图

监督微调(SFT)和RLHF是微调LLM的两大主力。

SFT通常用几千份文档或者样本就能搞定,RLHF则往往需要上万甚至几万个例子。

数据少?别怕,先试试改进你的prompt,可能更划算。

更重要的是,SFT和RLHF并不互斥。

你可以先用SFT,再用RLHF,或者反过来,两个方法叠加用,优势都能拿到。

当然,这俩也不是微调的唯一门道。

比如,有新方法专门“删掉”模型学过的某些知识,让模型“忘记”特定内容【6】,算是反向微调。

未来几年,还会有更多新玩意儿问世。

虽说都得收集数据,但比起自己从零造个LLM,省事多了。

简单总结:微调有很多花样,玩得好,模型就能变得更聪明、更贴心、更适合你的需求。

5.3 RLHF是怎么运作的?

要讲清楚RLHF咋玩儿,我们先从一个“不完全版”的RLHF说起,看看它为啥不靠谱,然后再告诉你怎么改正。

这部分不打算带你深入复杂的数学细节,因为那对理解RLHF的整体原理没啥大帮助。

要是你想钻研数学细节,咱推荐你看完这章后去翻翻《Implementing RLHF: Learning to Summarize with trlX》【7】,那本书讲得更专业。

5.3.1 从最简单的RLHF说起

先来看看一个非常“幼稚”的RLHF版本。

前面咱说过,RL可以处理那些没法用微分法搞定的目标。

假设这里有个“人类裁判”,它给LLM的回答打分,+1代表回答不错,-1代表回答很糟糕。

这个“质量分”其实就是我们随便给输出的一个分数,用来告诉模型“这条回答比别的好”或者“不行”。

举个例子:

用户让LLM讲个笑话,模型回答:“几个鸭子换个灯泡得多少只?”这个笑话还算有趣,给它+1。

如果模型说:“狗都是坏的”,这可不是笑话,我们给它-1,告诉它答得烂。

但单靠+1和-1这两个简单分数,强化学习是难以奏效的。

所以我们还给算法补充更多信息,比如每个词出现的概率。

这样强化学习算法就知道,模型每个词出现的可能性到底有多大。

整个过程,图5.6里有个清晰的总结。

简单说,这就像给AI玩“猜词打分”游戏,有人给好分,有人给差分,AI学着怎么说更能得高分。

image.png

为啥要给强化学习算法“喂”词的概率?

你可能觉得奇怪,为什么要把每个词出现的概率告诉强化学习算法?

背后有一堆深奥的数学原理,这里咱不细讲。

简单说说直觉吧:

一个好笑话往往需要“出其不意”——要有点反转或者惊喜。

如果一连串词的概率都高得吓人(靠近1.0),那它很可能太老套、太 predictable(可预测),讲出来就不逗了。

总的来说,在自然语言处理中,生成好文本是个“拿捏”活儿——

既要让内容“合理”,概率够高,听着顺耳;
又不能太老套,概率太高,容易让人觉得重复无聊。

就像你讲故事,要讲得合情合理又不能太套路,这样听众才爱听。

5.3.2 质量奖励模型

刚才我们说过,质量奖励就是人类给模型每次回答打分。

虽然现场让真人实时评分理论上可行,但实际上太累人了,简直不现实。

不过,人类反馈还是有用武之地的——我们把它变成了训练一个奖励模型的“燃料”。

具体咋搞?就是让一堆人手动收集几十万条“提示词+回答”组合,然后给每条答案贴上“好”或者“差”的标签。

这些打好标签的数据,就用来训练奖励模型,帮模型自动判断回答质量。

图5.7里有个示意,展示了这个训练过程。

打个比方,就是先让真人给一堆作业打分,训练出一个“自动评分老师”,以后就不用真人盯着了,模型自己“知道”答得好不好。

image.png

收集几十万条带评分的“提示词+回答”组合虽然费钱,但确实能办到。

比如,Hugging Face上就有公开的RLHF数据集【链接:huggingface.co/datasets/An…,还有亚马逊的机械土耳其人(Mechanical]() Turk)众包平台www.mturk.com/帮你搞活人标注。

虽然这数据量很大,但跟基础模型训练时用的数十亿词量比,简直就是小巫见大巫。

这些RLHF数据集得够大,得覆盖用户可能提的各种场景、问题和请求。

就像咱们在图5.5里讲过的海豚例子,RLHF更擅长处理比较直接、常见的话题。

所以,想让模型应对更多“花样百出”的情况,关键还是得靠多样化的微调数据。

小贴士:

我们之前用+1/-1举例说明质量奖励,是因为简单好懂。

但强化学习不用梯度,所以你可以用任何和问题相关的分数。

现在更流行也更有效的方法,是用“排序分”(ranking score),也就是说给同一个提示词的多个回答排个序,从最好到最差,这样能同时比对多个答案。

无论用哪种,正面和负面反馈的核心逻辑都是一样的。

打个比方,这就像你评判几位选手的表现,不光是给单个分数,还得把他们放一起比比看,谁更厉害,一目了然。

5.3.3 有点像又不太一样的RLHF目标

一旦你训练好了奖励模型,就能随心所欲地生成、评分各种“提示词+回答”,让RLHF过程顺利进行。

人类的反馈被“烘焙”进了奖励模型,这样就能分发开来,支持并行计算,还能重复利用,效率杠杠的。

不过有个大问题:当前这个最“简单版”的RLHF,只想最大化那个质量奖励分,这可不是它唯一该盯的目标。

结果是,模型时间一长,就开始“脑洞大开”,胡言乱语,输出一堆四不像的内容,既不高质量,也没啥用。

这种“走偏”跟一种叫对抗攻击(adversarial attacks) 的现象有关:只要稍微改动输入,就能轻易骗过神经网络,让它做出奇怪决定。

对抗机器学习(AML)发展得飞快,研究起来超级复杂,这块我们留给其他大神去深入讲解【8】。

但咱们说的这个简单RLHF,基本就是自己“黑自己”——因为它只追求质量奖励,根本没管用户需求,结果模型疯狂“割韭菜”。

这就像是古德哈特定律(Goodhart’s law) 在AI领域的翻版:“一旦某个指标变成了目标,它就不再是个好指标了。”

为了解决这个问题,我们得给强化学习算法加个“副目标”:

计算微调模型输出和原始基础模型输出的相似度奖励

简单说,就是如果微调后的模型输出更好,还能保持跟基础模型类似的风格,就能拿奖励。

这样能防止模型“离谱创新”,跑偏走火入魔。

本质上,我们想让微调后的模型“脚踏实地”,别一股脑儿胡编乱造。

这个相似度奖励加进RL算法,帮微调过程稳住阵脚。

图5.8展示了RLHF的完整工作流程。

通俗点说,这就像你告诉模型:

“你可以更聪明点、更贴心点,但别疯了,别把话说成天方夜谭。”

image.png

如果模型开始胡说八道,输出一堆乱七八糟的内容,那“相似度奖励”就会狠狠扣分,告诉模型:“别乱跑,别太脱离轨道!”

反过来,如果模型老是跟基础模型输出一模一样,质量分就会低,暗示它“不够灵活”,需要多点变化。

两者平衡下来,模型就能达到“金发姑娘效应”——不多不少,刚刚好,既能灵活变通,又能保持人类般自然的输出。

5.4 定制LLM行为的其他因素

微调是目前改变LLM行为的主力军,但它并非万无一失,也不是唯一能调整行为的地方。

我们强调微调,是因为RLHF能让LLM做的不只是简单的“猜下一个词”,还能实现更高级的行为调整。

image.png

图5.9里还有三个环节能调整LLM的行为,不过作为用户的你,接触这些环节没那么容易。

不过,为了让你了解全貌,咱还是简单带过,帮你明白微调以外还有啥门道,哪些问题值得跟你的LLM服务商聊聊。

5.4.1 改变训练数据

机器学习里有句老话: “垃圾进,垃圾出” ,放哪儿都管用。

你可能发现,OpenAI【9】和Google【10】会分享不少训练LLM的技术细节,但对他们用啥数据反而守口如瓶。

这是因为,LLM厉害的“秘诀”大部分藏在数据的收集和整理上——得搞一大堆覆盖各种任务、高质量语言、丰富场景的数据。

训练、验证、测试用的数据集大小和质量,决定了模型表现的天花板。

随着LLM生成内容越用越多,回头又“进了”网络和文献,出现了一个头疼的问题:

据说学术同行评审里,6%到16%的论文审查用了LLM【11】,很多文稿润色服务也快跟进。

这就带来一个“恶性循环”:

LLM生成的数据越来越多,留给模型训练的“非LLM原创”内容反而越来越少。

结果就是,语言多样性变少,模型能学到的新鲜东西也少了。

训练新数据的LLM质量可能因此下滑【12】。

这问题在保持LLM与时俱进上,绝对是个大难题,收集高质量数据没以前那么简单了。

还有一个问题是,LLM只能反映训练时的数据,更常见的信息被“放大”,稀有内容可能被忽视。

举个例子,你要模型不骂人、不说歧视话,那你得保证训练数据里几乎没这类内容。

但这又是把“双刃剑”:

如果你想让模型能识别并拒绝歧视言论,它得先知道啥是歧视话。

想象一下,用提示词教一个没见过歧视内容的模型去“用”歧视词,但它却不知道这些词背后有问题。

最终,咱们这些识别力在线的人看了,肯定觉得这句话让人不舒服。

目前,这个问题还没好解决办法,但你得多留个心眼。

改数据也很关键,因为它是你唯一能影响模型分词(tokenization) 方式的机会。

正如第二章讲的,分词方案各有优劣,但一旦选了,就永远烙印在模型里,改不了。

简单说,数据就是模型的“命根子”,没好数据,别指望训练出好模型。

5.4.2 改变基础模型训练

在训练或微调LLM时,数据隐私必须摆在非常重要的位置。

通常来说,有人能用“特殊套路”输入模型,竟然能“挖出”它训练时用过的原文。

这可不好,尤其是训练数据里有个人隐私信息(PII)、健康记录(PHI)或其他敏感数据时。

用户可能无意中给模型一个提示词,结果模型竟然把这些敏感信息照搬出来了!

所以,模型一开始训练的时候,就是防隐私泄露的关键时刻。

有一种叫做差分隐私(Differential Privacy,DP) 的技术专门用来解决这个问题。

DP挺复杂,想深入了解的话,可以看看《Programming Differential Privacy》这本书【13】。

简单说,DP就是在训练时给数据“加点料”,添点随机噪声,保证你数据的隐私安全可被数学证明。

虽然DP不能包治百病,但比目前大多数算法提供的保护强多了。

那为啥大家还没普遍用DP呢?

加噪声自然会影响训练结果的质量,表现可能没那么好。

而且训练一次大模型动辄花几十万到上百万美元,要是要多次训练才能调整好隐私参数,那成本直接飙升到几百万甚至上千万美元。

不过,随着DP技术逐年进步,我们猜未来这玩意儿会越来越普及,隐私保护也会越来越靠谱。

简单来说,DP就像给模型训练戴上了隐形的口罩,既能呼吸,又能保护秘密。

5.4.3 调整输出内容

最后,我们还能盯着模型吐出的“词块”(tokens)来看看,再写代码去调整它的行为,基于它生成的词组合做“人工干预”。

在微调之后,这通常是普通用户第二大改造LLM行为的手段。

本章前面提到过,很多时候LLM得生成严格格式的输出,比如XML或者JSON。

实现这些格式要求,对LLM来说是个常见难题。

只要预测错了一个词,整个输出格式就崩了,结果变成了“无效数据”。

图5.10里有个经典例子,我们让模型补全Python代码,正确答案应该是一个分号(;),结果它跑去换行(\n)了,闹出个笑话。

打个比方,这就像你让厨师把菜装进圆形碗里,它却给你装成了方盒子,顿时食欲全无。

简单来说,管好输出格式,代码和数据才不会崩盘,模型才算靠谱。

image.png

现在市面上有不少工具(比如这个开源项目:github.com/noamgat/lm-…)能帮你在模型解码输出时,严格检查格式。

一旦发现格式解析出错,这些工具会立马重来,反复重新生成最后一个词,直到生成合法的输出为止。

其实,选择下一个词的算法还能更高级更复杂。

不过这里最重要的教训是:我们可以利用生成过程中的“中间产物”做决定,而不是等整个答案全出来才判断。

就算是最简单的“通过/不通过”名单,也是拦截错误行为的好帮手。

你也不必非得真实时地把答案给用户,可以稍微“缓个冲”,等模型多吐几句,再给用户看。

这样你就有时间给输出“套套皮”,比如过滤脏话或者用一些硬编码的检查规则。

如果发现问题,像图5.10里那样,可以重新生成答案,或者直接中止用户的对话。

简单来说,这就像你发微信之前先检查拼写错误,发现有问题,赶紧改一改,再发出去,避免尴尬。

5.5 把LLM整合进更大的工作流程

到这儿,我们已经聊了不少让LLM输出更靠谱、更稳定的小技巧。之前主要关注的是跟LLM本身打交道,比如写好提示词、调整训练数据、给模型做微调。

现在咱们来看看怎么把LLM的输入输出串联起来,组成多步骤的操作流程,帮你拿到更定制化、更精准的结果。

这块发展飞快,先给你看个实实在在的例子:把LLM放进一个更大信息检索流程里,顺便介绍个通用工具,教你用多轮互动定制LLM输出。

5.5.1 用检索增强生成(Retrieval Augmented Generation,RAG)定制LLM

RAG是一招“高科技”,它让LLM回答问题时,减少胡扯乱讲的概率。

名字里“retrieval(检索)”一词已经透露了秘密:当用户输入问题,RAG系统先用LLM生成一个查询,然后去搜索引擎找相关文档。

这个搜索引擎可以是像谷歌这样涵盖海量信息的,也可以是某个专业领域的文档库,比如汽车市场资料。

搜索引擎把相关文档列表给RAG系统后,系统用LLM从这些文档里提取有用信息,再结合用户原问题,拼成一个超级详细的提示词,喂给LLM。

这样,LLM不是单凭“脑子里学过的”,而是结合了“现场搜来的”资料,给出更靠谱的答案。

简单说,就是帮LLM锁定它需要用的数据,避免胡乱发挥。

图5.11里有这个流程图,顺便跟之前单纯用LLM的情况做了对比。

RAG最大的两个好处:

  1. 输出更准确、更符合事实,也更贴近用户问题,毕竟答案都是从真实文档里“挖”出来的。
  2. LLM还能给出引用来源,告诉你答案出处在哪儿,方便你去核对、验证。

这就像请了个聪明又靠谱的助理,不但会给你答案,还会顺手递上资料来源清单。

image.png

后面说的那个“引用”点特别重要。

虽然RAG帮忙给答案加上了“出处”,但它不能解决LLM所有问题,因为最终答案还是由LLM来生成。

模型依然有可能因为找不到信息、或者根本不存在的信息,搞出错乱或“幻觉”回答。

还有可能它没能准确理解或者表达那些它用来答题的文档内容。

所以,RAG的好用程度,直接取决于它背后那个搜索引擎的“货真价实”,和返回的文档质量。

总结一句话:如果你连做个靠谱的搜索引擎都难,那做出好用的RAG模型几乎是不可能的任务。

上下文长度(Context Size)

聊LLM,不能不提它们的一个关键参数——上下文长度

上下文长度,就是模型一次最多能“看到”多少词(token)来处理回答请求。

想象一下,这就是模型一口气能“咽下去”的信息量。

比如GPT-3的上下文长度是2048个词。

但在聊天机器人里,整个对话(包括模型之前的回答)都要记住。

如果你和GPT-3聊得超过2048个词,模型就会开始忘早先聊过的内容,跟你“记忆力不好”的朋友似的。

上下文长度既是RAG的大功臣,也是瓶颈。

如果RAG检索出来的是一本书,要让模型“消化”它,模型上下文容量得足够大。

否则模型只能看文档开头的几段,后面重要信息全漏了。

所以,选模型时,一定要关注它的上下文长度。

现在有些模型,比如X公司的Grok,能支持128,000个词的上下文,简直是“吃货中的战斗机”。

不过,能吃更多的内容不代表它理解得更好,这还是个正在研究的课题。

你会发现图5.11里,给模型的新提示词前面加了“回答问题:”,后面加了“根据以下信息:”。

理论上,你可以调调这个提示词,试着加些说明,比如“如果以下信息跟问题无关,请忽略它。”

这些操作,就叫提示词工程(prompt engineering) ,也就是我们第四章说的,设计和改写输入文本来影响模型表现的技术。

提示词工程确实很管用,还能帮你把多次调用模型的结果合起来提升答案质量。

举个例子,你可以让模型帮你“改写问题”,以期望得到更精准的搜索结果。

(这跟信息检索里经典的“查询扩展”技术有关,感兴趣可以深入研究。)

不过,提示词工程也挺脆弱的:

一旦模型更新了,原先好用的提示词可能就失效了,

你得不停改提示词,特别是面对像RAG这样复杂模型时,改起来可费劲了。

简单说,提示词工程是把控模型输出的“小妙招”,但不是万能药,得不断调整才能保持效果。

5.5.2 通用LLM编程

虽然这领域还挺新,但我们已经看到越来越多的编程库和软件工具,开始用LLM当作定制应用的组成部分。

我们特别喜欢一个叫DSPy的项目(dspy.ai),它能让你更轻松地写程序,调整LLM的输入和输出。

一个好的软件库,会帮你屏蔽各种麻烦细节,DSPy在这方面表现得不错,比如帮你:

  • 整合你选用的具体LLM,
  • 实现常见的提示词套路,
  • 调整提示词来适配你的数据、任务和模型。

这可不是教你写代码的书,没法详细讲DSPy,但看看它怎么实现我们上面说的RAG模型,挺有帮助的。

我们要选一个LLM(这里用GPT-3.5),还要选一个信息库(比如维基百科),然后定义RAG算法。

DSPy通过定义一个默认的LLM和数据库(除非你自己换),让各个组件用同一套配置,方便拆分和替换。

下面这个代码就是用DSPy写的最简单的RAG模型:

import dspy

llm = dspy.OpenAI(model='gpt-3.5-turbo')  #1

similarity_and_database = dspy.ColBERTv2(   #2
  'wiki17_abstracts'
) 

dspy.settings.configure(  #3
    lm=llm, 
    rm=similarity_and_database
) 

class RAG(dspy.Module):
    def __init__(self, num_passages=3):
        super().__init__()

        self.retrieve = dspy.Retrieve(  #4
            k=num_passages
        ) 

        self.generate_answer = dspy.Prediction(  #5
            "question,relevant_documents -> answer"
        )

    def forward(self, question):  #6
        documents = self.retrieve(
            question
        ).passages
        
        return self.generate_answer(
            question=question, 
            relevant_documents=documents
        ).answer

注释时间:

  • #1 用的是OpenAI的GPT-3.5,当然你也能换成其他在线或者本地模型,比如Llama。
  • #2 用的是ColBERTv2算法,把维基百科做了向量化,方便快速检索。
  • #3 告诉DSPy,我们用刚才定义的LLM和数据库。
  • #4 检索数据库里最相关的3篇文档。
  • #5 这是定义LLM的输入输出格式(signature),告诉模型接收问题和相关文档,输出答案。
  • #6 这里调用了前面定义的函数,完成整个RAG流程。

这段代码把LLM和数据库的选择都定成默认的了,要换模型或者数据源只要改个地方就行。

class RAG(dspy.Module)定义了RAG算法,初始化方法里只做了两件事:

  1. 用ColBERTv2做数据库搜索,速度快且效果还不错(毕竟4年前的技术算挺新了,进步超快)。这个方法能帮你找到合适的文档,哪怕不是完美,也够用。
  2. 把问题和文档合成一条查询,发给LLM。DSPy帮你自动写好提示词,不用你操心。

你还可以在signature里用简单类型约束,比如把answer指定成整数answer:int,DSPy还能帮你处理错误时重试,就像图5.10里说的那样。

就是这么简单,轻轻松松就定义了个RAG模型!

你也可以根据需要改这段代码,比如把文本转小写,做拼写检查,或者加啥逻辑都行。

这种灵活性让你能自由组合程序逻辑和LLM的能力。

更棒的是,你还能轻松改写RAG定义,加入新的限制条件,写代码让LLM做校验。

更重要的是,DSPy支持用训练/验证集来优化提示词,微调本地模型,帮你打造经过实证检验、效果更好的模型,省去了不少麻烦。

早点用上这类工具,你的解决方案会更靠谱,也更容易升级换代。

总结

想改变模型的行为,你其实有四个“开关”能调:

  1. 数据收集和分词(tokenization)阶段,
  2. 训练初始基础模型阶段,
  3. 微调基础模型阶段,
  4. 拦截预测的词(tokens)输出阶段。

这四个环节都很关键,但对大多数用户来说,微调是最有效、成本最低,也最能帮你调整模型目标的方式。

监督微调(SFT) 就是在一小堆专门定制的数据上,做正常训练,帮模型更懂你关注的领域。

基于人类反馈的强化学习(RLHF) 需要更多数据,但它能帮你实现比“猜下一个词”更复杂的目标。

如果输出格式必须严格(比如JSON或XML),你还能用现成的语法检查工具,循环检测输出,直到格式正确为止。

检索增强生成(RAG) 是个火爆方法:先用搜索引擎或者数据库找到相关内容,再把这些内容塞进提示词,帮LLM给出更靠谱答案。

像DSPy这样的编程框架正在兴起,它帮你把具体LLM、向量化和提示词定义,跟输入输出的业务逻辑分开。

这让你能快速搭建靠谱、易复用的LLM方案,还能方便地升级到新模型、新方法。

简单来说,这套组合拳让你在LLM的海洋里,游得更稳更远。