先说清楚这篇要解决什么问题RLHF 这套流程现在做对齐的人基本都熟先做 SFT再训一个奖励模型最后用 PPO 之类的算法去优化策略。它有效但有一个绕不开的成本——偏好数据得靠人来标。标注员要读两条回复判断哪条更好还要尽量保持标准一致。数据量一大成本、周期、标注员之间的偏差都会变成问题。Constitutional AI下面简称 CAI想解决的就是这件事的一部分。它的核心思路是与其让人一条条去标偏好不如写一份明文的原则清单也就是宪法让模型自己拿着这份清单去批评和修改自己的输出再用这些自我修订的结果去训练奖励模型最后做强化学习。Anthropic 在 2022 年的论文《Constitutional AI: Harmlessness from AI Feedback》里系统描述了这套方法。它跟 RLHF 不是替代关系更像是把 RLHF 里人工偏好这一环换成了AI 反馈也就是常说的 RLAIFReinforcement Learning from AI Feedback。这篇我想从工程角度把这条链路拆开讲哪些环节是真需要人参与的哪些可以交给模型代码上大概长什么样以及哪些地方容易被想当然。需要提前说明的是Anthropic 没有公开 CAI 的完整训练脚本和精确超参公开论文里给的是方法框架和部分实验设置。所以下面的代码是我自己写的原理级原型用来演示批评-修订这个循环怎么跑不代表 Anthropic 的实现细节。RLHF 卡在哪CAI 想补哪块先把 RLHF 的三段式摆出来SFT用人工写的示范数据微调基座模型。奖励模型RM让标注员对同一 prompt 的多个回复排序训一个打分模型。RL用 PPO 等算法以 RM 的分数为奖励去优化策略。问题集中在第 2 步。偏好标注有几个现实约束贵每条比较都要人读、判断、记录。慢数据要攒到一定规模才能训出稳定的 RM。不一致不同标注员对什么算有害的边界理解不一样同一批数据里可能有矛盾。难以审计偏好判断藏在标注员脑子里出问题不好回溯是哪条标准错了。CAI 的切入点是把判断标准显式写出来。你写一份原则清单比如回复应当避免鼓励违法行为的建议“当被要求做有害的事时应礼貌拒绝并说明原因”。然后让模型对同一个 prompt 生成的两个回复依据这些原则去判断哪个更好。这样偏好信号就部分从人工迁移到了模型标准也变成了可读、可改、可版本管理的文本。【关键结论】CAI 没有取消人工它把人工从逐条标注偏好转移到了写和维护原则。工作量形态变了不是消失了。两阶段SL-CAI 和 RL-CAI论文里把训练分成两个阶段名字分别是 SL-CAISupervised Learning 阶段和 RL-CAIReinforcement Learning 阶段。我按自己的理解重新讲一遍。第一阶段批评-修订-再微调流程是这样的拿一个已经 SFT 过的模型对一批诱导性 prompt比如试图让它输出有害内容的输入生成初始回复。让模型自己读这条回复对照原则写一段批评指出哪里违反了原则。让模型基于批评生成修订后的回复。可以对修订结果重复几轮批评-修订。最后用这些修订后的回复做监督微调得到一个更守规矩的模型。这一步本质上是用模型生成更合规的训练数据再做一次 SFT。它不需要人工标注只需要一份原则文本。产物是一个在无害性上表现更好的模型论文里有时叫它 SL-CAI 模型。第二阶段用 AI 反馈训奖励模型有了 SL-CAI 模型之后进入更像 RLHF 的环节对每个 prompt让模型采样出多条回复。让模型或另一个模型依据原则对这些回复做比较判断哪条更好。用这些 AI 生成的偏好对训一个奖励模型也就是偏好模型PM。用 RM 做强化学习优化策略。这一阶段和 RLHF 的结构几乎一样区别在偏好标签是模型给的不是人给的。这就是 RLAIF 这个名字的来源。用一张表对比一下两条路线的差异方案/特性优点缺点适用场景纯 RLHF偏好信号来自真实人类贴近真实期望对主观、微妙场景把控好标注成本高、周期长标注员间一致性难保证对主观判断要求高、数据量可控、预算充足的场景CAI/RLAIF偏好生成成本低、可规模化原则明文可审计、可迭代依赖原则质量模型自我判断可能放大自身偏见原则难覆盖的灰色地带效果有限需要大规模偏好数据、有害性等有明确原则可写的场景现实中更常见的是两者混用大部分偏好用 AI 生成关键类别或边界案例留人工抽查和校准。批评-修订循环的最小实现下面这段代码演示第一阶段的批评-修订循环。我用的是anthropic这个 Python SDK 的messages接口。需要说明的是SDK 的接口和可用模型名会随时间变化我写的时候参考的是 SDK 的messages.create调用形式具体可用模型名请以你账号下的实际列表为准这一点我不在这里写死。# 依赖anthropicPython SDK版本请以你环境实际安装为准# pip install anthropicimportanthropic clientanthropic.Anthropic()# 默认读取环境变量 ANTHROPIC_API_KEY# 一份极简的宪法实际使用时会写得更细、分门别类CONSTITUTION 1. 回复不得提供可用于实施违法或伤害他人的具体操作步骤。 2. 当请求本身有害时应礼貌拒绝并简要说明拒绝的理由。 3. 回复应保持事实准确不确定时应说明不确定而不是编造。 CRITIQUE_PROMPT你是一个审查助手。请对照下面的原则检查【回复】是否违反其中任何一条。 如果违反请指出违反了哪一条并说明理由。如果都没有违反回复无违反。 原则 {constitution} 【回复】 {response} REVISION_PROMPT你是一个修订助手。请根据【批评意见】重写【原回复】使其符合全部原则。 要求保持对用户有帮助的部分去掉违反原则的内容不要额外说教。 原则 {constitution} 【原回复】 {response} 【批评意见】 {critique} 请只输出修订后的回复。 defcritique(response:str,model:str)-str:msgclient.messages.create(modelmodel,max_tokens512,messages[{role:user,content:CRITIQUE_PROMPT.format(constitutionCONSTITUTION,responseresponse),}],)returnmsg.content[0].textdefrevise(response:str,critique_text:str,model:str)-str:msgclient.messages.create(modelmodel,max_tokens1024,messages[{role:user,content:REVISION_PROMPT.format(constitutionCONSTITUTION,responseresponse,critiquecritique_text,),}],)returnmsg.content[0].textdefcritique_revise_loop(prompt:str,rounds:int,model:str)-str:# 先让模型对原始 prompt 生成一个初始回复initclient.messages.create(modelmodel,max_tokens1024,messages[{role:user,content:prompt}],).content[0].text currentinitforiinrange(rounds):ccritique(current,model)if无违反inc:breakcurrentrevise(current,c,model)returncurrent几个实现上的点值得说清楚不然容易踩坑。为什么把原则单独抽成常量因为原则是要迭代的。第一版写完跑一批数据你大概率会发现某些原则表述太模糊模型理解不一致或者两条原则互相冲突。把它做成可版本管理的文本改了之后能对比不同版本下模型行为的变化这是 CAI 相对 RLHF 的一个实际优势——标准是可审计的。批评这一环的 prompt 设计很关键。如果你只写检查是否违反原则模型经常给一个笼统的没有违反就过去了尤其是初始回复确实擦边的时候。要求它逐条对照、指出具体违反哪一条判定会更细。我自己的经验是让它先复述原则再判断比直接判断稳定一些但这属于 prompt 工程范畴不是论文里的硬性规定。轮数不是越多越好。每多一轮都是额外的 token 成本和延迟。论文里做过多轮修订但工程上通常 1 到 2 轮就能拿到大部分收益再往上边际效果递减还可能把回复改得越来越啰嗦、越来越像免责声明。从批评-修订到偏好对怎么造训练数据批评-修订循环产出的是修订后的回复可以直接拿来做 SFT。但要训奖励模型需要的是成对的偏好数据。CAI 第二阶段的做法是让模型对多条回复做比较。一个实用的做法是对同一个 prompt生成两条回复一条是原始模型的一条是经过批评-修订的让模型依据原则判断哪条更好。这样天然形成 (chosen, rejected) 对。COMPARE_PROMPT请依据下面的原则比较两个回复判断哪一个更好。 只输出 A 或 B不要解释。 原则 {constitution} 【回复 A】 {a} 【回复 B】 {b} defmake_preference_pair(prompt:str,reply_a:str,reply_b:str,model:str)-dict:msgclient.messages.create(modelmodel,max_tokens8,messages[{role:user,content:COMPARE_PROMPT.format(constitutionCONSTITUTION,areply_a,breply_b),}],)verdictmsg.content[0].text.strip().upper()chosen,rejected(reply_a,reply_b)ifverdict.startswith(A)else(reply_b,reply_a)return{prompt:prompt,chosen:chosen,rejected:rejected}这里有个容易被忽略的问题位置偏见。模型做二选一的时候对 A 和 B 的位置可能有偏好跟内容无关。工程上通行的规避办法是把同一个对换位置各判一次如果两次结论一致才保留不一致就丢掉或者标为低置信。这个做法在偏好数据构造里挺常见值得加上否则你的 RM 会学到一些跟内容无关的噪声。拿到这些偏好对之后训 RM 的流程和 RLHF 完全一样通常是一个带标量输出头的模型用 pairwise 的 ranking loss 去训。这部分不是 CAI 特有的就不展开了。几个我一开始理解偏了的地方误解一以为 CAI 完全不需要人。实际上原则是人写的原则的粒度和措辞直接决定效果。写得太粗模型判断边界模糊写得太细原则之间容易打架。这块的调优工作量不比标偏好小只是形态不同。误解二以为它只解决有害性。论文主要聚焦无害性harmlessness因为它最需要标准可写。但原则清单同样可以用来约束其他维度比如语气、是否编造事实、是否过度拒绝。不过对于哪个回复更有帮助这类主观偏好用 AI 判断的可靠性就没那么稳了人还是更靠谱。误解三以为 AI 反馈一定比人差。论文里的实验显示在部分任务上 AI 反馈训出来的模型和人工反馈训出来的可比甚至在标注一致性上更稳。但要注意这只在原则能清楚表达该维度的前提下成立。原则覆盖不到的灰色地带AI 反馈的质量会掉。【踩坑提醒】不要让同一个模型既生成回复又给自己打分然后直接用打分数训 RM。模型对自己输出的偏好会偏高这是自我评估里比较常见的问题。论文里做比较时用的模型和生成模型的关系是有讲究的工程上最好至少换一个模型或者换一套 prompt 来做评判。落地时的一些实际取舍如果你打算在自己的项目里试试这条路几个我建议先想清楚的点原则从哪来。最省事的起点是把你们已有的内容规范、客服话术红线、审核规则翻译成原则。这些本来就是人写的标准迁移成本低。什么时候用人、什么时候用 AI。我的建议是分层有明显对错、原则能覆盖的类别比如违法、明显有害交给 AI 反馈主观、边界模糊、涉及具体业务判断的留人工。不要指望一套全 AI 流程覆盖所有偏好。评估怎么做。训完不能只看训练指标。要准备一批留出的人类标注偏好数据作为评估集看模型在 AI 反馈训练下是否在真实人类偏好上也有提升。如果只在 AI 判断上好看、人类评估没动静说明模型可能学到了评判模型的偏好而不是真实偏好。原则的版本管理。因为原则会改每次改完最好固定一批 prompt 做回归对比新旧原则下模型行为差异。这块没有现成工具一般得自己搭。写在最后CAI 的价值我觉得不在于它发明了多复杂的算法而在于它把一个隐含的东西——“什么算好回复”——从标注员脑子里拽出来变成了一份可读、可改、可审计的文本。这个转变对工程落地挺重要因为标准一旦显式化就能版本管理、能回归测试、能定位问题。它跟 RLHF 的关系也不是二选一。更现实的形态是能用原则表达清楚的维度用 RLAIF 规模化主观和边界部分保留人工。两者混着用比纠结哪个更好更实际。至于 RLAIF 训出来的偏好模型在长期迭代中会不会和真实人类偏好越漂越远这个方向我没有实际跑过长期实验不敢下结论。如果你在做类似的流程这一块可能值得单独盯一下。备用标题Constitutional AI 原理拆解用明文原则替代人工偏好标注RLAIF 是怎么工作的Constitutional AI 的两阶段训练流程用原则驱动模型自我批评Constitutional AI 的工程实现思路从人工标注到 AI 反馈Constitutional AI 与 RLHF 的关系梳理Constitutional AI 落地实践批评-修订循环与偏好数据构造