技术

Agent与软件开发 提升Agent能力——上下文工程 llm评测 rl微调 分布式Agent与A2A deepresearch梳理 mcp学习 SSE 和 WebSocket 是什么? AutoGen学习 Python ioc 从0到1构建一个db 上下文记忆 线性RAG的进化——agentic rag 图数据库的一些考量 推理LLM梳理 Agent演进 LLM预训练 向量数据库的一些考量 fastapi+sqlalchemy进行项目开发 LLM微调实践 Python协程实现 Agent Functon Calling LLamaIndex入门 另一种微服务架构Multi-Agent Python虚拟机 LangGraph工作流编排 Python实践 增强型 LLM——Agent 激发LLM涌现——提示工程 LLM微调理论 大佬谈LLM LLM外挂知识库 LLMOps 多模态LLM Python一些比较有意思的库 Transformers源码学习 LangChain源码学习 通用分布式计算引擎Ray Python并发 go依赖注入 go collection gc的基本原理 golang性能分析及优化 数据湖 高性能计算与存储 Linux2.1.13网络源代码学习 《大数据经典论文解读》 三驾马车学习 Spark 内存管理及调优 Yarn学习 从Spark部署模式开始讲源码分析 容器狂占内存资源怎么办? 多角度理解一致性 golang io使用及优化模式 Flink学习 c++学习 学习ebpf go设计哲学 ceph学习 学习mesh kvm虚拟化 学习MQ go编译器以及defer实现 学习go 为什么要有堆栈 汇编语言 计算机组成原理 运行时和库 Prometheus client mysql 事务 mysql 事务的隔离级别 mysql 索引 坏味道 学习分布式 学习网络 学习Linux go堆内存分配 golang 系统调用与阻塞处理 Goroutine 调度过程 重新认识cpu mosn有的没的 负载均衡泛谈 单元测试的新解读 《Redis核心技术与实现》笔记 《Prometheus监控实战》笔记 Prometheus 告警学习 calico源码分析 对容器云平台的理解 Prometheus 源码分析 并发的成本 基础设施优化 hashicorp raft源码学习 docker 架构 mosn细节 与微服务框架整合 Java动态代理 编程范式 并发通信模型 《网络是怎样连接的》笔记 go channel codereview gc分析 jvm 线程实现 go打包机制 go interface及反射 如何学习Kubernetes 《编译原理之美》笔记——后端部分 《编译原理之美》笔记——前端部分 Pilot MCP协议分析 go gc 内存管理玩法汇总 软件机制 istio流量管理 Pilot源码分析 golang io 学习Spring mosn源码浅析 MOSN简介 《datacenter as a computer》笔记 学习JVM Tomcat源码分析 Linux可观测性 学习存储 学计算 Gotty源码分析 kubernetes operator kaggle泰坦尼克问题实践 kubernetes扩缩容 神经网络模型优化 直觉上理解深度学习 如何学习机器学习 TIDB源码分析 什么是云原生 Alibaba Java诊断工具Arthas TIDB存储——TIKV 《Apache Kafka源码分析》——简介 netty中的线程池 guava cache 源码分析 Springboot 启动过程分析 Spring 创建Bean的年代变迁 Linux内存管理 自定义CNI IPAM 共识算法 spring redis 源码分析 kafka实践 spring kafka 源码分析 Linux进程调度 让kafka支持优先级队列 Codis源码分析 Redis源码分析 C语言学习 《趣谈Linux操作系统》笔记 docker和k8s安全访问机制 jvm crash分析 Prometheus 学习 Kubernetes监控 Kubernetes 控制器模型 容器日志采集 容器狂占资源怎么办? Kubernetes资源调度——scheduler 时序性数据库介绍及对比 influxdb入门 maven的基本概念 《Apache Kafka源码分析》——server Kubernetes类型系统 源码分析体会 《数据结构与算法之美》——算法新解 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 ansible学习 Kubernetes源码分析——从kubectl开始 jib源码分析之Step实现 线程排队 jib源码分析之细节 跨主机容器通信 jib源码分析及应用 为容器选择一个合适的entrypoint kubernetes yaml配置 《持续交付36讲》笔记 mybatis学习 程序猿应该知道的 无锁数据结构和算法 CNI——容器网络是如何打通的 为什么很多业务程序猿觉得数据结构和算法没用? 串一串一致性协议 当我在说PaaS时,我在说什么 《数据结构与算法之美》——数据结构笔记 PouchContainer技术分享体会 harbor学习 用groovy 来动态化你的代码 精简代码的利器——lombok 学习 《深入剖析kubernetes》笔记 编程语言那些事儿 rxjava3——背压 rxjava2——线程切换 spring cloud 初识 《深入拆解java 虚拟机》笔记 《how tomcat works》笔记 hystrix 学习 rxjava1——概念 Redis 学习 TIDB 学习 如何分发计算 Storm 学习 AQS1——论文学习 Unsafe Spark Stream 学习 linux vfs轮廓 《自己动手写docker》笔记 java8 实践 中本聪比特币白皮书 细读 区块链泛谈 比特币 大杂烩 总纲——如何学习分布式系统 hbase 泛谈 forkjoin 泛谈 看不见摸不着的cdn是啥 《jdk8 in action》笔记 程序猿视角看网络 bgp初识 calico学习 AQS——粗略的代码分析 我们能用反射做什么 web 跨域问题 《clean code》笔记 《Elasticsearch权威指南》笔记 mockito简介及源码分析 2017软件开发小结—— 从做功能到做系统 《Apache Kafka源码分析》——clients dns隐藏的一个坑 《mysql技术内幕》笔记 log4j学习 为什么netty比较难懂? 递归、回溯、动态规划 apollo client源码分析及看待面向对象设计 学习并发 docker运行java项目的常见问题 OpenTSDB 入门 spring事务小结 分布式事务 javascript应用在哪里 《netty in action》读书笔记 netty对http2协议的解析 ssl证书是什么东西 http那些事 苹果APNs推送框架pushy apple 推送那些事儿 编写java框架的几大利器 java内存模型和jvm内存布局 java exception Linux IO学习 netty内存管理 测试环境docker化实践 netty在框架中的使用套路 Nginx简单使用 《Linux内核设计的艺术》小结 Go并发机制及语言层工具 Linux网络源代码学习——数据包的发送与接收 《docker源码分析》小结 docker namespace和cgroup zookeeper三重奏 数据库的一些知识 Spark 泛谈 链式处理的那些套路 netty回顾 Thrift基本原理与实践(二) Thrift基本原理与实践(一) 回调 异步执行抽象——Executor与Future Docker0.1.0源码分析 java gc Jedis源码分析 深度学习泛谈 Linux网络命令操作 JTA与TCC 换个角度看待设计模式 Scala初识 向Hadoop学习NIO的使用 以新的角度看数据结构 并发控制相关的硬件与内核支持 systemd 简介 quartz 源码分析 基于docker搭建测试环境(二) spring aop 实现原理简述 自己动手写spring(八) 支持AOP 自己动手写spring(七) 类结构设计调整 分析log日志 自己动手写spring(六) 支持FactoryBean 自己动手写spring(九) 总结 自己动手写spring(五) bean的生命周期管理 自己动手写spring(四) 整合xml与注解方式 自己动手写spring(三) 支持注解方式 自己动手写spring(二) 创建一个bean工厂 自己动手写spring(一) 使用digester varnish 简单使用 关于docker image的那点事儿 基于docker搭建测试环境 分布式配置系统 JVM执行 git maven/ant/gradle/make使用 再看tcp kv系统 java nio的多线程扩展 《Concurrency Models》笔记 回头看Spring IOC IntelliJ IDEA使用 Java泛型 vagrant 使用 Go常用的一些库 Python初学 Goroutine 调度模型 虚拟网络 《程序员的自我修养》小结 Kubernetes存储 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件 Go基础 JVM类加载 硬币和扑克牌问题 LRU实现 virtualbox 使用 ThreadLocal小结 docker快速入门

架构

rl与sft 大模型infra OpenTelemetry及生态 大模型可观测性 grpo演进 rlhf演进 agent框架 reward演进 大模型RLHF框架 rl框架 GPU与CUDA RL闲谈 MCTS与LLM rl从Policy Gradient(策略梯度)到PPO到GRPO 从Transformer到DeepSeek bert rerank微调 大模型推理tips RAG向量检索与微调 dddfirework源码分析 RAG与知识图谱 大模型推理服务框架vLLM 大模型推理服务框架 模型服务化(未完成) 大模型Post-Training 大模型训练 大模型推理 从Attention到Transformer k8s设备管理 ddd从理念到代码 如何应用LLM 小鼠如何驾驭大象(LLM)? 多类型负载协调员Koordinator controller-runtime细节分析 finops学习 kubevela多集群 kubevela中cue的应用 基于k8s的工作流 kubevela源码分析 容器和CPU那些事儿 数据集管理fluid 应用管理平台kubevela karmada支持crd 多集群管理 AutoML和AutoDL 特征平台 实时训练 分布式链路追踪 K8S YAML 资源清单管理方案 tensorflow原理——python层分析 如何学习tensorflow 数据并行——allreduce 数据并行——ps 推荐系统embedding原理及实践 机器学习中的python调用c 机器学习训练框架概述 tensornet源码分析 大模型训练和推理 X的生成——特征工程 tvm tensorflow原理——core层分析 模型演变 《深度学习推荐系统实战》笔记 keras 和 Estimator tensorflow分布式训练 分布式训练的一些问题 基于Volcano的弹性训练 图神经网络 pytorch弹性分布式训练 从混部到统一调度 从RNN到Attention pytorch分布式训练 CNN 《动手学深度学习》笔记 pytorch与线性回归 多活 volcano特性源码分析 推理服务 kubebuilder 学习 mpi 学习pytorch client-go学习 提高gpu 利用率 GPU与容器的结合 GPU入门 AI云平台梳理 tensorflow学习 tf-operator源码分析 k8s批处理调度/Job调度 喜马拉雅容器化实践 Kubernetes 实践 学习rpc BFF openkruise学习 可观察性和监控系统 基于Kubernetes选主及应用 《许式伟的架构课》笔记 Admission Controller 与 Admission Webhook 发布平台系统设计 k8s水平扩缩容 Scheduler如何给Node打分 Scheduler扩展 深入controller openkruise cloneset学习 controller-runtime源码分析 pv与pvc实现 csi学习 client-go informer源码分析 kubelet 组件分析 调度实践 Pod是如何被创建出来的? 《软件设计之美》笔记 mecha 架构学习 Kubernetes events学习及应用 CRI——kubelet与容器引擎之间的接口 资源调度泛谈 业务系统设计原则 grpc学习 元编程 以应用为中心 istio学习 下一代微服务Service Mesh 《实现领域驱动设计》笔记 概率论 serverless 泛谈 《架构整洁之道》笔记 处理复杂性 那些年追过的并发 服务器端编程 网络通信协议 架构大杂烩 如何学习架构 《反应式设计模式》笔记 项目的演化特点 反应式架构摸索 函数式编程的设计模式 服务化 ddd反模式——CRUD的败笔 研发效能平台 重新看面向对象设计 业务系统设计的一些体会 函数式编程 《左耳听风》笔记 业务程序猿眼中的微服务管理 DDD实践——CQRS 项目隔离——案例研究 《编程的本质》笔记 系统故障排查汇总及教训 平台支持类系统的几个点 代码腾挪的艺术 abtest 系统设计汇总 《从0开始学架构》笔记 初级权限系统设计 领域驱动理念 现有上传协议分析 移动网络下的文件上传要注意的几个问题 推送系统的几个基本问题 做配置中心要想好的几个基本问题 不同层面的异步 分层那些事儿 用户认证问题 资源的分配与回收——池 消息/任务队列

标签

k8s设备管理 多类型负载协调员Koordinator controller-runtime细节分析 finops学习 kubevela多集群 kubevela中cue的应用 基于k8s的工作流 kubevela源码分析 容器和CPU那些事儿 数据集管理fluid 应用管理平台kubevela karmada支持crd 多集群管理 K8S YAML 资源清单管理方案 从混部到统一调度 volcano特性源码分析 kubebuilder 学习 client-go学习 tf-operator源码分析 k8s批处理调度/Job调度 喜马拉雅容器化实践 Kubernetes 实践 openkruise学习 基于Kubernetes选主及应用 Admission Controller 与 Admission Webhook k8s水平扩缩容 Scheduler如何给Node打分 Scheduler扩展 深入controller openkruise cloneset学习 controller-runtime源码分析 pv与pvc实现 csi学习 client-go informer源码分析 kubelet 组件分析 调度实践 Pod是如何被创建出来的? Kubernetes events学习及应用 CRI——kubelet与容器引擎之间的接口 资源调度泛谈 如何学习Kubernetes 以应用为中心 kubernetes operator kubernetes扩缩容 serverless 泛谈 什么是云原生 自定义CNI IPAM docker和k8s安全访问机制 Kubernetes监控 Kubernetes 控制器模型 Kubernetes资源调度——scheduler Kubernetes类型系统 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 Kubernetes源码分析——从kubectl开始 kubernetes yaml配置 CNI——容器网络是如何打通的 当我在说PaaS时,我在说什么 《深入剖析kubernetes》笔记 Kubernetes存储 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件
rl与sft Agent与软件开发 大模型infra 提升Agent能力——上下文工程 llm评测 大模型可观测性 rl微调 grpo演进 rlhf演进 agent框架 分布式Agent与A2A reward演进 deepresearch梳理 mcp学习 大模型RLHF框架 rl框架 GPU与CUDA RL闲谈 MCTS与LLM rl从Policy Gradient(策略梯度)到PPO到GRPO AutoGen学习 从Transformer到DeepSeek 上下文记忆 线性RAG的进化——agentic rag bert rerank微调 大模型推理tips 推理LLM梳理 Agent演进 LLM预训练 RAG向量检索与微调 LLM微调实践 RAG与知识图谱 大模型推理服务框架vLLM Agent Functon Calling LLamaIndex入门 另一种微服务架构Multi-Agent LangGraph工作流编排 大模型推理服务框架 模型服务化(未完成) 大模型Post-Training 大模型训练 大模型推理 从Attention到Transformer 增强型 LLM——Agent 激发LLM涌现——提示工程 LLM微调理论 大佬谈LLM LLM外挂知识库 LLMOps 多模态LLM Transformers源码学习 LangChain源码学习 如何应用LLM 小鼠如何驾驭大象(LLM)? AutoML和AutoDL 特征平台 实时训练 tensorflow原理——python层分析 如何学习tensorflow 数据并行——allreduce 数据并行——ps 推荐系统embedding原理及实践 机器学习中的python调用c 机器学习训练框架概述 tensornet源码分析 大模型训练和推理 X的生成——特征工程 tvm tensorflow原理——core层分析 模型演变 《深度学习推荐系统实战》笔记 keras 和 Estimator tensorflow分布式训练 分布式训练的一些问题 基于Volcano的弹性训练 图神经网络 pytorch弹性分布式训练 从RNN到Attention pytorch分布式训练 CNN 《动手学深度学习》笔记 pytorch与线性回归 推理服务 mpi 学习pytorch 提高gpu 利用率 GPU与容器的结合 GPU入门 AI云平台梳理 tensorflow学习 kaggle泰坦尼克问题实践 神经网络模型优化 概率论 直觉上理解深度学习 如何学习机器学习 深度学习泛谈

rl与sft

2025年07月21日

简介

在传统认知中,RL 与 SFT 的区别主要体现在两个方面:

  1. 负样本的利用。SFT只是模仿学习正例,SFT+DPO需要大量的标注数据来cover bad case。而RL不仅对好的样本奖励,也要对坏的样本惩罚。无论是简单的策略梯度,还是GRPO、Reinforce、PPO这些算法,原理都是一致的,本质上只是在设计不同的奖励/惩罚的粒度(token/macro action/seq等等)和力度(需不需要引入baseline,要不要考虑KL限制,要不要clip等等)
  2. (样本的多样性)。rl允许使用当前模型在线产出的样本训练自身(仅on-policy模式)。SFT一般学习的都是人工标注或者其他模型生成的样本(即蒸馏),SFT阶段的Rejection Sampling技术也是自己采样训练自己,很像是RL,只不过没有惩罚信号(也可以引入负例进一步做DPO)。而RL允许当前模型实时采样样本,并依据这些样本训练自身。

​在标准的LLM训练流程中,通常包含三个阶段:Pre-training、SFT和RL。Pre-training阶段采用自回归的方式在海量数据上完成预训练,为后续的Post-training奠定基础。Post-training通常分为SFT和RL,这两个阶段均需要一个多样性丰富的prompt集合D

  1. 在该阶段对于prompt $x~D$,会采用专家撰写、人工合成或者强模型蒸馏的方法来构造高质量的响应。
  2. ​RL通常在SFT阶段后进行。在On-Policy的设定下,对于prompt $x~D$,通常会从当前策略$\pi_theta$中采样响应y。GRPO是PPO的一种无critic模型的变种,针对同一个prompt x,会同时采样G个响应 ${y_i}_{i=1}^G$,每个响应 $y_i$ 对应于一个标量奖励 $R_i$。在标准的PPO中需要critic模型来辅助计算优势,GRPO则采用组内标准化实现优势的近似计算 $A(i,t)= \frac{R_i−mean([R_1,…,R_G])}{std([R_1,…,R_G])}$,这里 $A(i,t)$是指第i个响应的第t个token的优势。

SFT不足

对模型自我进化的思考与设计

  1. SFT不擅长理解和遵循『不要做什么』指令:和传统的分类任务不同,语言模型的SFT是一个生成任务,不具备很强的排他性。在传统的分类任务中,优化模型使得目标类的概率变大,很容易导致其他类别的概率变小。而在语言模型的SFT中,输出往往不是唯一的,同时为了保留语言模型的知识,优化正例时并不会将正例的概率优化成1而将其他可能的回复的概率优化变成0。换句话说,SFT只是告诉了模型训练数据中的回复是可行的,但模型无法像普通分类任务那样利用排他性确定哪些输出是不可行(对于排他性比较好的任务,语言模型的分布本身就有较好的排他性,提升SFT训练样本的概率会大幅降低其他回复的概率)。因此,对于一些回复多样性较高的任务,SFT很难避免模型生成不恰当的回复。从排他性角度来看,SFT擅长『要做什么』指令,但不擅长『不要做什么』指令,尤其是在输出灵活性很高的任务上如创作、摘要。例如对于『生成一篇100字以内的文章』这一指令,其隐含的『不要做什么』的指令是『文章不要超过100字』。对于这一指令,SFT阶段会给模型一个100字以内的文章,但这并不足以让模型确定超过100字的回复是不可行的或者说概率是极小的。如果一定要用SFT来解决这类问题,那么只能不断增加正例数量,挤压负例的概率。但因为这类任务下的正例排他性非常低,这样做的效率也是非常低的。因此,不建议依赖SFT来提升模型对于『不要做什么』指令的理解和遵循能力。
  2. SFT不应该追求统一的输出形式,而应该追求多元的输出形式:在预定义输出标准的指导下,不少同学追求在SFT阶段对齐用户(或产品、RD)的偏好,固化模型的输出形式;或者选择一种初始模型表现较好的形式作为模型的默认回复形式,比如推理任务下默认使用CoT形式进行回复,信息抽取任务中默认不给解释。这样的做法会给模型的能力升级带来很大的困难:
    1. 不利于后期输出形式的调整:随着新老用户的交替以及用户对模型需求的变化,模型的期望输出形式也会发生改变。如果在SFT阶段就固化了模型的输出形式,后期调整模型输出形式需要对SFT进行大规模的改动——大量输出形式不再合适的数据的存在使得增加少量具有新输出形式的SFT数据很难起作用,须先对已有数据进行大规模的退场。
    2. 不利于对不同尺寸模型的适配:不同模型的能力是不同的,大模型可能可以使用简洁的方式回复给定问题,而小模型可能需要更复杂的输出方式。如果只给定一种回复模式,那么注定很难同时满足多个不同的模型:为大模型建设的SFT数据可能无法很好地调教小模型,而为小模型构建的SFT数据对大模型而言过于累赘低效。
    3. 不利于实现千人千面、千题千面:从用户层面来看,不同的用户对回复的倾向是不同的。ToB用户可能更喜欢简洁的回复,而ToC更喜欢具备详细解释的回复。统一的输出形式很难满足不同用户的需求,也无法充分挖掘用户的偏好反馈为将来的千人千面做储备。从任务层面来看,即使是同一个任务,不同case的难易程度及其恰当的回复形式也是不同的。对于比较难的case,模型可能需要使用CoT或者更复杂的Agent模式进行回复;而对于简单的case,模型可以直接回复答案。一致性地采用复杂的输出模式会造成资源的浪费,而一致性地采用简单的回复模式又可能导致模型在一些复杂cases上犯错。SFT阶段固化输出形式无法实现不同能力的兼容,会导致顾此失彼(比如有些平台需要两套不同的接口来区分Agent和非Agent)
    4. 不利于模型自我进化:一个比较理想的模型能力进化路径是从复杂输出模式出发,不断强化模型简单输出模式下的能力,不断形成正确性和简洁性的新平衡。而如果在SFT阶段固化模型的输出形式,限制了模型的探索能力,不利于模型在PPO阶段通过大规模探索自动实现能力的进化。
    5. 不利于形成护城河:因为模型输出的模式化,其他平台可以大规模抓取我方模型的输出,快速对齐我方模型。又因为没有及时引入用户信息,导致无法有效形成用户越多-效果越好-用户越多的飞轮。
    6. 不利于争取其他平台的用户:这主要是不同平台的输出标准不同,固化SFT的输出标准会增加用户从其他平台迁移到我方平台的成本和难度。

因此,SFT阶段应该尽可能避免做形式偏好(既包括展示形式,也包括得到输出的路径)的对齐,而是将其放到RM、PPO阶段去完成(后面会介绍如何在RM系统中引入用户偏好来避免上述问题)。SFT更多的是让模型知道给定指令情况下可能可以怎么回复,提高潜在可行回复的采样概率,尽可能保留模型输出的多样性,以便于后期高效调整偏好(比如对于可回答的问题在SFT阶段也可以引入据答)。

PPO擅长学习『不要做什么』。得益于RM评估的高效性,PPO阶段可以对回复进行大规模采样和评估,此时不仅可以告诉模型什么样的回复是可行的,还可以告诉模型什么样的回复是不可行的(SFT阶段正例样本较少,引入负例容易让模型过拟合负例,将负例中的一些正确pattern的概率也给错误地降低了)。因此,相较于SFT,PPO更擅长学习『不要做什么』,在这个阶段,应加强否定指令的建设。PPO阶段除了引入用户偏好收敛输出形式外还有一个重要任务是实现能力的进化。典型的Online PPO是从SFT模型的输出空间中筛选出RM得分更高的子空间,所以其最终能力是受限于SFT模型的。当SFT能力覆盖了期望进化方向时,比如期望方向是越简洁越好,同时给定一个query,模型能生成各种复杂度,或正确或错误的输出,此时模型能通过对应的RM模型实现在该方向上能力的进化。而当SFT能力没有覆盖期望的进化方向时,比如模型很难生成既简单又正确的输出,普通的Online PPO无法有效采样出目标方向更好的输出,此时模型进化能力会受限。这种情况下,最直接的方式是先用SFT扩展模型能力边界。但其实也可以直接在PPO过程中扩展模型的能力边界——在PPO阶段引入offline数据,比如从繁琐但正确的回复出发,自动合成简洁且正确的回复,然后用importance sampling的学习方式将该样本引入到PPO的采样集合并进行学习。

与sft 对比

强化学习发展这十年随着这两年强化学习的大力发展,强化学习衍生出了许许多多的子课题方向,除了最经典的online RL以外,例如offline model-free RL,model-based RL,RLHF,multi-agent,risk-sensitive,inverse RL等等,要给这些子课题找共性非常困难。而在传统教科书中,强化学习的标准制定时由于这些子课题还未广泛引入关注,导致定义早已过时。举个例子,例如强化学习强调智能体跟环境交互,而offline RL方向偏说我就不跟环境交互。再例如强化学习强调无需人类标签还是采用奖励信号,RLHF说我就不是这样。最开始,人们对强化学习应用的要求也非常严格,在强化学习应用的论文描述里必须有以下内容:

  1. 非常准确的状态空间和动作空间定义
  2. 必须存在状态转移函数,不允许单步决策,也就是一个动作就gameover
  3. 必须有过程奖励,且需要存在牺牲短期的过程奖励而获取最大累计回报的case案例 说个开玩笑的话,如果DS的文章放到几年前RL的审稿人手里,他大概率会得到这样的回复:这只是采用了策略梯度的方式将不可导的损失/奖励函数用于优化神经网络参数而已,请不要说自己使用了强化学习。这导致像作者这样的old school,在看到最新的强化学习应用文章时,总会试图问文章作者几个基础的问题,状态是啥,动作是啥,奖励是啥。但其实现在很多文章已经不考虑这些问题了。

RL for LLM本质理解为更清晰地理解 RL(强化学习),我们可以从它与监督学习的联系入手。监督学习(SFT)的损失函数可以表达为:

\[L = -\mathbb{E}_{x \sim p(x)} \mathbb{E}_{y \sim \pi^*(\cdot \mid x)} \left[ \log \pi(y \mid x) \right]\]

其中,$x$ 是提示(prompt),$y$ 是模型的生成内容,$\pi^*$ 是代表人类专家答案的真实分布,$\pi$ 是模型的输出策略分布。其目标是最小化模型分布与专家分布之间的差异。

RL 的损失函数则可视为一种加权监督学习:

\[L = -\mathbb{E}_{x \sim p(x)} \mathbb{E}_{y \sim \pi(\cdot \mid x)} \left[ \omega(x, y) \log \pi(y \mid x) \right]\]

核心区别

  • 引入了权重项 $\omega(x, y)$
  • 代表人类专家答案的真实分布被替换为模型自己的输出策略分布

可能有人想说,既然只是加权的监督学习,那 RL 有什么特别的呢?RL的特殊性在于其权重 $\omega(x, y)$ 的设计以及训练数据的来源,这使其区别于旨在调整样本重要性的传统加权学习:

  1. 权重可为负值,实现“趋利避害”:传统加权学习的权重通常为非负,用于强调重要样本。而RL中的权重可以为负。负权重指导模型“避免”生成特定的行为,而不仅仅是“模仿”期望的行为。这种“惩罚”机制是模型能够快速抛弃失败策略、探索未知但可能更优策略空间(Exploration)的关键,也是其能力超越训练数据限制的根本原因。PS:sft 只是提高期望输出的概率,而rl 可以降低非期望输出的概率
  2. 数据来源与权重结合,形成自洽的优化闭环:RL用于学习的数据由模型自身生成。这一特点与上述的奖惩机制相结合,形成了一个强大的自优化循环:模型生成行为 -> 获得带有正或负权重的反馈 -> 调整策略以增加高权重行为、减少低权重行为 -> 生成更高质量的新行为。通过这一循环,只要权重(以及背后的reward)设计得当,模型便有潜力实现持续的自我迭代与能力攀升,最终达到超越人类的性能水平。

在上述框架下,当前RL for LLM的研究主要围绕以下几个核心问题展开:

  1. 如何从“用于验证的弱监督信号(reward)”推导出每个样本的权重$\omega(x, y)$ ? 例如,PPO中学习的价值函数(value function),以及DeepSeek GRPO中从批次数据中估计的优势函数(advantage function),都是对该问题的不同解法。
  2. 承接上一点,如何高效、准确地获取“用于验证的弱监督信号(reward)”? 从RLHF可学习的reward model,到DeepSeek的rule-based reward,都是在解决这个问题
  3. RL的两个核心步骤 ——a.基于加权监督学习的模型更新 与 b.新样本的生成——二者的交互节奏是怎样的?是生成一个样本就更新一次(完全在线),还是生成N个样本后更新一次或N次?先前批次生成的样本在后续迭代中是否应该被舍弃(on-policy vs. off-policy的权衡)?PPO/GRPO算法中的修正比值、clip参数、生成批次大小、更新的epoch数目等,都与这个核心节奏问题紧密相关。
  4. RL训练应选择怎样的提示(prompt)分布 p(x)? 以数学问题为例,如何设计一个问题序列(课程),才能最大化模型的学习效率?
  5. 进行RL训练前,基础模型(base model)需要具备哪些先决能力,才能有效支撑后续的强化学习过程? 以上几点构成了当前RL for LLM研究的基本蓝图。对这些问题的不断探索和解答,将持续推动大型语言模型向着更高级的智能形态迈进。

rl 与sft 融合

为什么要融合SFT和RL RL虽然能够有效提升模型的推理能力,但一个重要的前提是基础模型本身具备了一定的相关能力。在RL训练中,通过多次rollout能够采样到正确的轨迹,这样通过RL才能进一步提升。这无疑限制了RL的探索空间。因此,主流的方式是通过SFT赋予模型一些基础能力,然后在进一步利用RL来提升相关能力。但是一些研究认为两阶段的方式并不是最优的。PS: 建议细读,对理解sft 与rl ,以及多阶段post-train 很有帮助

rl与base

Reasoning LLM(五):熵缩过程与能力边界RL在当前形式下不足以激励LLMs超越基础模型的推理能力。通过多次采样(k次)模型的输出,在数学、代码、视觉问题上,RLVR训练的模型在小k值(如k=1)时表现优于基础模型,但在大k值时,基础模型的pass@k分数与RL模型相当甚至更高。这表明基础模型在大量采样下能够解决RL模型解决的问题,且RL训练并未引入新的推理模式,而是通过偏向高奖励的路径来提高采样效率。

“熵坍缩”:即在 RL 训练中策略熵在早期训练阶段急剧下降,导致策略模型过于自信,进而导致探索能力的减弱与策略性能的饱和。模型在特定领域的表现提升与其熵缩是同时发生的,甚至二者之间都可以通过公式近似拟合出来。如果对 Token 熵进行模式分析,可以发现,在 CoT 推理中,大多数 token 的熵很低,而少数 token 的熵很高。这些高熵的 token 通常作为推理路径中的“分叉点”(forks),引导模型走向不同的推理路径。例如,高熵 token 常见于逻辑连接词(如“Thus”、“perhaps”等),而低熵 token 则多为单词后缀或数学表达式的组成部分。通过仅对高熵 token 进行策略梯度更新,可以显著提高模型的推理性能,且这种方法在更大模型上效果更明显。

也有工作研究了正负样本对 RL 的训练结果的影响,实验发现,仅使用负样本进行训练(NSR)在Pass@k的整个范围内都能显著提升模型性能,甚至在某些情况下超过了PPO和GRPO等常用强化学习算法。与NSR相反,仅使用正样本进行训练(PSR)虽然能提高Pass@1,但在较大的k值下性能下降,导致输出多样性降低。通过跟踪模型的熵,发现NSR在整个训练过程中保持了较高的熵,而PSR则迅速降低了熵。这表明NSR在训练过程中保持了模型的输出多样性。通过分析可知,PSR通过增加正确响应的logit值,同时降低其他所有token的logit值,导致输出分布变得过于集中,减少了多样性。NSR通过降低错误响应的logit值,并将概率质量重新分配给其他候选token,这种重新分配是基于模型先验的,有助于保持多样性。NSR通过抑制错误响应和根据模型先验重新分配概率质量,有效地细化了模型的现有知识,而不是引入全新的行为。