译者 | 朱先忠
审校 | 重楼
为什么要定制LLM?
大型语言模型是基于自监督学习预训练的深度学习模型,需要大量的训练数据资源、训练时间并保存大量参数。尤其是在过去2年里,LLM彻底改变了自然语言处理,在理解和生成类似人类的文本方面表现出色。然而,这些通用模型的开箱即用性能可能并不总是能满足特定的业务需求或领域要求。LLM本身无法回答依赖于专有公司数据或闭卷设置的问题;因此,LLM当前主要应用在一些相对通用的领域。
由于需要大量的训练数据和资源;所以,从头开始训练LLM模型对于中小型团队来说基本上是不可行的。因此,近年来开发了各种各样的LLM定制策略,以针对需要专业知识的各种场景调整模型。
定制策略大致可以分为两种类型:
- 使用冻结模型:这些技术不需要更新模型参数,通常通过情境学习或提示工程来实现。这样的定制策略具有明显的成本效益,因为它们可以改变模型的行为而无需大量的训练成本,因此在行业和学术界都得到了广泛的探索,每天都会发表新的研究论文。
- 更新模型参数:这是一种相对资源密集型的方法,需要使用为预期目的设计的自定义数据集来调整预训练的LLM。这包括微调和从人类反馈中进行强化学习(RLHF)等流行技术。这两种广泛的定制范式分支出各种专门的技术,包括LoRA微调、思想链、检索增强生成、ReAct和代理框架。每种技术在计算资源、实施复杂性和性能改进方面都有独特的优势和权衡。
如何选择LLM?
定制LLM的第一步是选择合适的基础模型作为基准。社区平台(例如“Huggingface”)提供了由顶级公司或社区贡献的各种开源预训练模型,例如Meta的Llama系列和Google的Gemini。Huggingface还提供排行榜,例如“Open LLM Leaderboard”,用于根据行业标准指标和任务(例如MMLU)比较LLM。云提供商(例如AWS)和AI公司(例如OpenAI和Anthropic)也提供对专有模型的访问权限,这些模型通常是付费服务且访问权限受限。以下因素是选择LLM时需要考虑的要点。
- 开源或专有模型:开源模型允许完全定制和自托管,但需要技术专长,而专有模型提供即时访问,并且通常提供更好的质量响应,但成本更高。
- 任务和指标:模型擅长于不同的任务,包括问答、总结、代码生成等。比较基准指标并在特定领域的任务上进行测试以确定合适的模型。
- 架构:一般来说,仅使用解码器的模型(GPT系列)在文本生成方面表现更好,而使用编码器-解码器的模型(T5)在翻译方面表现良好。越来越多的架构涌现并显示出颇有希望的结果,例如混合专家(MoE)模型“DeepSeek”。
- 参数数量和大小:较大的模型(70B-175B个参数)性能更好,但需要更多的计算能力。较小的模型(7B-13B)运行速度更快且更便宜,但功能可能会有所降低。确定基础LLM后,让我们来探索6种最常见的LLM定制策略,按资源消耗从少到多的顺序排列依次是:
- 提示工程
- 解码和采样策略
- 检索增强生成
- 代理
- 微调
- 根据人类反馈进行强化学习如果你更喜欢通过视频了解上述这些概念,请查看我的视频“简要解释6种常见的LLM定制策略”。
LLM定制技巧
1. 提示工程
提示是发送给LLM以引出AI生成的响应的输入文本,它可以由指令、上下文、输入数据和输出指示组成。
- 指令:这提供了模型应如何执行的任务描述或说明。
- 上下文:这是指导模型在一定范围内做出反应的外部信息。
- 输入数据:这是你想要响应的输入。
- 输出指示器:指定输出类型或格式。提示工程涉及战略性地设计这些提示组件以塑造和控制模型的响应。基本提示工程技术包括零次提示、一次提示和少量提示三种类型。用户可以在与LLM交互时直接实施基本提示工程技术,使其成为一种将模型行为与新目标对齐的有效方法。
由于提示工程的效率和有效性,人们探索和开发了更复杂的方法来推进提示的逻辑结构。 - 思维链(CoT):要求LLM将复杂的推理任务分解为逐步的思维过程,以提高解决多步骤问题的能力。每一步都明确地揭示其推理结果,作为其后续步骤的先导背景,直至得出答案。
- 思维树:从CoT延伸而来,通过考虑多个不同的推理分支和自我评估选择来决定下一步最佳行动。它对于涉及初步决策、未来战略和多种解决方案探索的任务更为有效。
- 自动推理和工具使用(ART):建立在CoT流程之上,它解构复杂的任务并允许模型使用预定义的外部工具(如搜索和代码生成)从任务库中选择少量样本。
- 协同推理和行动(ReAct):将推理轨迹与行动空间相结合,其中模型搜索行动空间并根据环境观察确定下一个最佳行动。CoT和ReAct等技术通常与Agentic工作流结合使用以增强其功能。这些技术将在下面的“代理”部分更详细地介绍。
2. 解码与采样策略
解码策略可以在模型推理时通过推理参数(例如温度、top p、top k)进行控制,从而确定模型响应的随机性和多样性。贪婪搜索、波束搜索和采样是自回归模型生成的三种常见解码策略。
在自回归生成过程中,LLM根据前一个符号所决定的候选符号的概率分布,一次输出一个符号。默认情况下,会应用贪婪搜索来生成具有最高概率的下一个符号。
相比之下,波束搜索解码会考虑次优标记的多个假设,并选择文本序列中所有标记中组合概率最高的假设。下面的代码片段使用转换库在模型生成过程中指定波束路径的数量(例如,num_beams=5考虑5个不同的假设)。
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(tokenizer_name)
inputs = tokenizer(prompt, return_tensors="pt")
model = AutoModelForCausalLM.from_pretrained(model_name)
outputs = model.generate(**inputs, num_beams=5)
采样策略是通过调整这些推理参数来控制模型响应随机性的第三种方法:
- 温度:降低温度可增加生成高概率单词的可能性并降低生成低概率单词的可能性,从而使概率分布更加清晰。当温度等于0时,它相当于贪婪搜索(最没有创造力);当温度等于1时,它会产生最具创造力的输出。
- 前K个采样:此方法筛选出K个最有可能的下一个标记,并在这些标记之间重新分配概率。然后,模型从这组筛选出的标记中进行采样。
- 前P采样:前P采样不是从K个最可能的标记中采样,而是从累积概率超过阈值p的最小可能标记集中进行选择。
下面的示例代码片段从前50个最可能的标记(top_k=50)中抽样,累积概率高于0.95(top_p=0.95):
sample_outputs = model.generate(
**model_inputs,
max_new_tokens=40,
do_sample=True,
top_k=50,
top_p=0.95,
num_return_sequences=3,
)
3. RAG
检索增强生成(RAG)最初在论文《知识密集型NLP任务的检索增强生成》中提出,已被证明是一种有前途的解决方案,它整合了外部知识,并在处理特定领域或专业查询时减少了常见的LLM“幻觉”问题。RAG允许从知识领域动态提取相关信息,并且通常不需要大量训练来更新LLM参数;因此,它是一种经济高效的策略,可将通用LLM应用于专业领域。
RAG系统可分解为检索和生成阶段。检索过程的目标是通过对外部知识进行分块、创建嵌入、索引和相似性搜索,在知识库中找到与用户查询密切相关的内容。
- 分块:将文档分成几个较小的段,每个段包含不同的信息单元。
- 创建嵌入:嵌入模型将每个信息块压缩为向量表示。用户查询也通过相同的向量化过程转换为其向量表示,以便可以在同一维空间中比较用户查询。
- 索引:此过程将这些文本块及其向量嵌入存储为键值对,从而实现高效且可扩展的搜索功能。对于超出内存容量的大型外部知识库,向量数据库可提供高效的长期存储。
- 相似性搜索:计算查询嵌入和文本块嵌入之间的相似度分数,用于搜索与用户查询高度相关的信息。
然后,RAG系统的生成过程将检索到的信息与用户查询相结合,形成增强查询,该查询被解析到LLM以生成上下文丰富的响应。
关键代码片断
在基于RAG系统的关键实现代码中,首先指定LLM和嵌入模型,然后执行将外部知识库分块为文档的集合的步骤。然后,从文档创建索引,基于索引定义查询引擎,并使用用户提示查询查询引擎。
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import VectorStoreIndex
Settings.llm = OpenAI(model="gpt-3.5-turbo")
Settings.embed_model="BAAI/bge-small-en-v1.5"
document = Document(text="\\n\\n".join([doc.text for doc in documents]))
index = VectorStoreIndex.from_documents([document])
query_engine = index.as_query_engine()
response = query_engine.query(
"Tell me about LLM customization strategies."
)
- 上面的例子展示了一个简单的RAG系统。高级RAG在此基础上进行了改进,引入了预检索和后检索策略,以减少诸如检索和生成过程之间协同作用有限等缺陷。例如,重新排序技术使用能够理解双向上下文的模型对检索到的信息进行重新排序,并与知识图谱集成以实现高级查询路由。
4. 代理
LLM代理(Agent)是2024年的热门话题,并且很可能在2025年继续成为GenAI领域的主要焦点。与RAG相比,Agent擅长创建查询路线和规划基于LLM的工作流程,具有以下优势:
- 维护先前模型生成的响应的记忆和状态。
- 根据特定标准利用各种工具。此工具使用功能使得代理有别于基本RAG系统,因为它赋予LLM对工具选择的独立控制权。
- 将复杂的任务分解为较小的步骤并规划一系列操作。
- 与其他代理协作以形成协调系统。
多种情境学习技术(例如CoT、ReAct)可通过Agentic框架实现,接下来我们将更详细地讨论ReAct。ReAct代表“语言模型中的协同推理和行动”,由三个关键元素组成——行动、想法和观察。该框架由普林斯顿大学的谷歌研究中心推出,建立在思想链的基础上,将推理步骤与行动空间相结合,从而实现工具使用和函数调用。此外,ReAct框架强调根据环境观察确定下一个最佳行动。
原始论文中的举例展示了ReAct的内部工作过程,其中LLM生成第一个想法并通过调用函数“Search [Apple Remote]”来采取行动,然后观察其第一个输出的反馈。第二个想法基于之前的观察,因此导致不同的动作“Search [Front Row]”。这个过程不断迭代直到达到目标。研究表明,ReAct通过与简单的维系百科API交互,克服了在思维链推理中经常观察到的幻觉和错误传播问题。此外,通过实施决策跟踪,ReAct框架还提高了模型的可解释性、可信度和可诊断性。
本示例来自论文《ReAct:语言模型中的协同推理和行动》(Yu等人,2022年)
关键代码片段
接下来的代码将演示使用基于ReAct的代理llamaindex的关键代码片段。首先,它定义了两个函数(multiply和add)。其次,将这两个函数封装为FunctionTool,形成代理的动作空间并根据其推理执行。
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
# 创建基本函数工具
def multiply(a: float, b: float) -> float:
return a * b
multiply_tool = FunctionTool.from_defaults(fn=multiply)
def add(a: float, b: float) -> float:
return a + b
add_tool = FunctionTool.from_defaults(fn=add)
agent = ReActAgent.from_tools([multiply_tool, add_tool], llm=llm, verbose=True)
代理工作流与自我反思或自我纠正相结合时,其优势更为显著。这是一个日益发展的领域,人们正在探索各种代理架构。例如,Reflexion框架通过提供来自环境的口头反馈摘要并将反馈存储在模型的内存中来促进迭代学习;CRITIC框架使冻结的LLM能够通过与外部工具(如代码解释器和API调用)交互来进行自我验证。
5. 微调
微调是输入小众和专业数据集来修改LLM,使其更符合某个目标的过程。它不同于提示工程和RAG,因为它可以更新LLM权重和参数。完全微调是指通过反向传播更新预训练LLM的所有权重,这需要大量内存来存储所有权重和参数,并且可能会显著降低其他任务的能力(即灾难性遗忘)。因此,PEFT(或参数高效微调)被更广泛地用于缓解这些问题,同时节省模型训练的时间和成本。PEFT方法有三类:
- 选择性:选择初始LLM参数的子集进行微调,与其他PEFT方法相比,这可能需要更多的计算。
- 重新参数化:通过训练低秩表示的权重来调整模型权重。例如,低秩自适应(LoRA)就属于此类,它通过使用两个较小的矩阵表示权重更新来加速微调。
- 附加:向模型添加额外的可训练层,包括适配器和软提示等技术。微调过程与深度学习训练过程类似,需要以下输入内容:
- 训练和评估数据集
- 训练参数定义超参数,例如学习率、优化器
- 预训练的LLM模型
- 计算算法应该优化的指标和目标函数
关键代码片段
下面是使用转换器Trainer实现微调的关键代码片段示例。
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
output_dir=output_dir,
learning_rate=1e-5,
eval_strategy="epoch"
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
compute_metrics=compute_metrics,
)
trainer.train()
微调具有广泛的使用场景。例如,指令微调通过对提示完成对进行训练来优化LLM的对话和遵循指令的能力。另一个例子是领域自适应,这是一种无监督微调方法,可帮助LLM专注于特定的知识领域。
6. RLHF
基于人类反馈的强化学习(RLHF)是一种基于人类偏好对LLM进行微调的强化学习技术。RLHF通过基于人类反馈训练奖励模型来运行,并使用该模型作为奖励函数通过PPO(近端策略优化)优化强化学习策略。该过程需要两组训练数据:用于训练奖励模型的偏好数据集和用于强化学习循环的提示数据集。
让我们将其分解为如下几个步骤:
- 收集由人工标注者标注的偏好数据集,人工标注者根据人类偏好对模型生成的不同完成情况进行评分。偏好数据集的一个示例格式为{input_text,candidate1,candidate2,human_preference},表示哪个候选答案是首选。
- 使用偏好数据集训练奖励模型,奖励模型本质上是一个回归模型,它输出一个标量,表示模型生成的响应的质量。奖励模型的目标是最大化获胜候选人和失败候选人之间的分数。
- 在强化学习循环中使用奖励模型来微调LLM。目标是更新策略,以便LLM可以生成响应,从而最大化奖励模型产生的奖励。此过程利用提示数据集,该数据集是格式为{prompt,response,rewards}的提示的集合。
关键代码片段
开源库Trlx在实现RLHF中被广泛应用,它们提供了一个展示基本RLHF设置的模板代码:
- 从预训练检查点初始化基础模型和标记器
- 配置PPO超参数PPOConfig,如学习率、时期和批次大小
- PPOTrainer通过组合模型、标记器和训练数据来创建PPO训练器
- 训练循环使用step()方法迭代更新模型,以优化从查询和模型响应计算出的回报:
# trl: 转换器强化学习库
from trl import PPOTrainer, PPOConfig, AutoModelForSeq2SeqLMWithValueHead
from trl import create_reference_model
from trl.core import LengthSampler
#启动预先训练好的模型和标记器
model = AutoModelForCausalLMWithValueHead.from_pretrained(config.model_name)
tokenizer = AutoTokenizer.from_pretrained(config.model_name)
#定义PPO算法的超参数
config = PPOConfig(
model_name=model_name,
learning_rate=learning_rate,
ppo_epochs=max_ppo_epochs,
mini_batch_size=mini_batch_size,
batch_size=batch_size
)
# 根据模型启动PPO训练师
ppo_trainer = PPOTrainer(
cnotallow=config,
model=ppo_model,
tokenizer=tokenizer,
dataset=dataset["train"],
data_collator=collator
)
# ppo_训练器通过奖励进行迭代更新
ppo_trainer.step(query_tensors, response_tensors, rewards)
RLHF被广泛用于将模型响应与人类偏好对齐。常见使用场景包括减少响应毒性和模型幻觉。然而,它的缺点是需要大量人工注释的数据以及与策略优化相关的计算成本。因此,引入了诸如AI反馈强化学习和直接偏好优化(DPO)之类的替代方案来缓解这些限制。
总结
本文简单介绍了六种基本的LLM定制策略,包括提示工程、解码策略、RAG、Agent、微调和RLHF。希望这对你理解每种策略的优缺点以及如何根据实际应用场景实施这些策略有所帮助。
译者介绍
朱先忠,51CTO社区编辑,51CTO专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。
原文标题:6 Common LLM Customization Strategies Briefly Explained,作者:Destin Gong