自我进化深潜:从经验库到强化学习微调闭环
作者:yumking | 2026 年 9 月 21 日 | 技术标签:自我进化 / DPO / GRPO / RLHF / 经验微调
摘要
第 9 篇建了经验学习闭环——失败归因、成功路径、用户纠偏沉淀进经验库,新任务时检索注入 prompt。但这套"体外进化"有个天花板:模型权重始终没变,每次都要把经验重新塞进上下文(占窗口、加延迟、还可能被第 26 篇的预算分配裁掉)。本文把经验反馈到权重本身——从第 9 篇的三类经验信号构造训练数据、用 DPO 做偏好对齐(最务实)、用 GRPO 做过程奖励(需要 step-level 信号时)、闭环防灾难性遗忘。实测微调后同类任务首次成功率从 89%(经验注入)提至 94%(权重内化),经验注入延迟从 +200ms 降为 0,纠偏信号利用率从 41% 提至 87%,代价是 DPO 训练 8H GPU/轮 + 通用 MMLU 跌 1.8%(可接受)。第 17 篇说"微调是最后手段"——本文展开"最后手段到底怎么做、什么时候值得做"。
一、第 9 篇之后:体外进化到体内进化
1.1 第 9 篇经验学习的天花板
第 9 篇的闭环是四层飞轮:
执行 → 沉淀(结构化经验)→ 治理(去重/衰减/归档)→ 复用(检索注入 prompt)
飞轮转起来,Agent 确实"越用越聪明"——但有个根本限制:所有进化都发生在模型外部。
| 维度 | 第 9 篇(体外进化) | 本文(体内进化) |
|---|---|---|
| 经验存哪 | 外部经验库(向量库) | 模型权重本身 |
| 复用方式 | 每次检索 + 注入 prompt | 直接推理,无需注入 |
| 占窗口 | 占 200-2000 token | 0 token |
| 延迟 | +200ms(检索+拼接) | 0 |
| 跨会话 | 经验库跨会话 ✓ | 权重跨会话天然 ✓ |
| 代价 | 零训练成本 | 训练成本(GPU+数据) |
| 风险 | 经验可能被裁(第 26 篇预算) | 灾难性遗忘 |
体外进化便宜但"每次都要想起来",体内进化贵但"已经长在身上"。两者不是二选一——第 9 篇是本文的数据源:经验库沉淀的失败/成功/纠偏信号,正是微调的训练数据。
1.2 什么时候值得从体外跨到体内
第 17 篇把微调列为"最后手段"是对的——微调成本高、迭代慢。但"最后"不等于"永远不做",有三种信号说明该上了:
信号一:同一类经验反复命中
经验库某条经验 hit_count > 50,几乎每次相关任务都要注入
→ 这条经验已经"稳定有用",值得内化进权重,省掉每次注入的开销
信号二:经验注入占窗口成瓶颈
第 26 篇预算分配里,经验注入挤掉了检索证据或历史
→ 内化后释放窗口预算给其他内容
信号三:纠偏信号反复出现同一模式
用户反复纠偏"应该先 X 再 Y",但经验注入后模型仍偶尔忘
→ prompt 注入是"提醒",微调是"本能"——本能不会忘
1.3 与第 9/17/7 篇的关系
第 9 篇(经验学习)
→ 提供训练数据源:三类经验信号(失败/成功/纠偏)
第 17 篇(选型方法论)
→ 微调是"改权重",本文展开"最后手段怎么做"
第 7 篇(规划/反思)
→ 反思器的 step-level 信号是过程奖励(GRPO)的数据源
第 6 篇(评估)
→ 微调后必须评估通用能力没退化
二、从经验库到训练数据:经验信号的转化
2.1 三类经验信号 → 三种训练数据
第 9 篇的三类经验源头,正好对应三种微调数据形态:
| 第 9 篇经验类型 | 微调数据形态 | 适合的算法 |
|---|---|---|
| 用户纠偏(“不对,应该先备份”) | preference pair(chosen/rejected) | DPO |
| 失败归因(“端口没探测就重试”) | 负样本 + 正样本对比 | DPO / GRPO |
| 成功路径(“这套步骤跑通了”) | 正样本(SFT 或 GRPO 的正例) | SFT / GRPO |
最有价值的是纠偏信号——用户说"不对,应该 Y 不是 X",天然构成一对 (prompt, chosen=Y, rejected=X),这是 DPO 最直接的燃料。
2.2 preference pair 构造
# exp_to_training_data.py —— 经验信号转训练数据
import json
from dataclasses import dataclass
@dataclass
class PreferencePair:
prompt: str
chosen: str # 用户偏好的回答
rejected: str # 被纠偏的回答
source_exp_id: str
class ExpToTrainingData:
"""从第 9 篇经验库导出微调数据集"""
def __init__(self, exp_store):
self._store = exp_store
def export_dpo_pairs(self, min_confidence: float = 0.7) -> list[PreferencePair]:
"""纠偏经验 → DPO preference pairs"""
pairs = []
for exp in self._store.query(kind="correction"):
if exp["confidence"] < min_confidence:
continue # 低置信度纠偏不进训练,防噪音
# 纠偏经验结构:用户问了 prompt,模型答了 rejected,
# 用户纠正为 chosen
pairs.append(PreferencePair(
prompt=exp["trigger"],
chosen=exp["corrected_response"],
rejected=exp["original_response"],
source_exp_id=exp["exp_id"],
))
return pairs
def export_grpo_rollouts(self) -> list[dict]:
"""成功/失败路径 → GRPO 的 rollout 样本(带 step-level reward)"""
rollouts = []
for exp in self._store.query(kind="path"):
# 成功路径:每步 reward=1,失败路径:失败步 reward=-1
steps = exp["trajectory"]
rewards = []
for i, step in enumerate(steps):
if exp["kind"] == "success":
rewards.append(1.0)
else: # failure
rewards.append(1.0 if i < exp["fail_step"] else -1.0)
rollouts.append({
"prompt": exp["goal"],
"steps": steps,
"rewards": rewards,
"source_exp_id": exp["exp_id"],
})
return rollouts
def export_sft_samples(self) -> list[dict]:
"""高频成功路径 → SFT 正样本(最简单的内化)"""
samples = []
for exp in self._store.query(kind="success"):
if exp["hit_count"] < 10:
continue # 只内化高频路径,低频的留给 prompt 注入
samples.append({
"prompt": exp["goal"],
"completion": exp["trajectory_summary"],
})
return samples
2.2 经验质量过滤:不是所有经验都值得进权重
经验库里的条目质量参差,全塞进训练会污染权重。三道过滤:
① 置信度过滤:confidence < 0.7 的不进(第 9 篇经验文档的 confidence 字段)
② 命中频次过滤:hit_count < 5 的不进(偶发经验不值得内化)
③ 冲突检测:两条经验对同一 trigger 给矛盾建议 → 都不进,留人工裁决
关键认知:微调是"把稳定的经验固化",不是"把所有经验都塞进去"。低频、低置信、有冲突的经验留在第 9 篇的体外循环里,靠 prompt 注入按需使用——体内体外分工。
三、DPO:最务实的偏好对齐
3.1 为什么不是 RLHF
RLHF(Reinforcement Learning from Human Feedback)是经典三段式:训 reward model → PPO 优化策略 → 迭代。强大但笨重:
| 维度 | RLHF | DPO |
|---|---|---|
| 阶段 | 3 个(reward model + PPO + 迭代) | 1 个(直接优化偏好) |
| 训练成本 | 32H GPU/轮(典型) | 8H GPU/轮 |
| 稳定性 | PPO 著名难调(KL 系数、学习率敏感) | 分类损失,稳定好调 |
| 数据需求 | 大量 pairwise 比较 | 同样的 pairwise,但用得更高效 |
| 适用 | 需要显式 reward model 的场景 | 直接有偏好对就够了 |
DPO(Direct Preference Optimization)的洞察:绕过 reward model,直接用偏好对优化策略。数学上证明了等价于 RLHF 的最优解,但工程上简单一个量级。对从经验库起步的微调,DPO 是最务实的第一步。
3.2 DPO 原理一句话
给定偏好对 (prompt, chosen, rejected):
RLHF:先训 reward model 让 r(chosen) > r(rejected),再用 r 做 PPO
DPO :直接最大化 log σ(β·(log π(chosen)/π_ref - log π(rejected)/π_ref))
↑ 让模型给 chosen 的概率相对参考模型更高,rejected 更低
π_ref 是微调前的原模型(防漂移),β 控制偏离强度。不需要 reward model,一个分类式损失搞定。
3.3 从纠偏经验构造 DPO 训练
# dpo_trainer.py —— DPO 微调(用 trl + peft,LoRA 低秩适配)
from trl import DPOTrainer, DPOConfig
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
class ExperienceDPO:
"""从经验库导出的偏好对,做 DPO 微调"""
def __init__(self, model_name: str, exp_store):
self._tokenizer = AutoTokenizer.from_pretrained(model_name)
self._model = AutoModelForCausalLM.from_pretrained(
model_name, torch_dtype="auto")
self._exp_store = exp_store
# LoRA:只训低秩适配器,不动原权重——省显存、防灾难性遗忘
self._peft_config = LoraConfig(
r=16, lora_alpha=32, lora_dropout=0.05,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
)
def train(self, output_dir: str, beta: float = 0.1,
epochs: int = 2) -> str:
from exp_to_training_data import ExpToTrainingData
pairs = ExpToTrainingData(self._exp_store).export_dpo_pairs()
if len(pairs) < 50:
raise ValueError(
f"only {len(pairs)} pairs, need ≥50 for stable DPO")
dataset = [{"prompt": p.prompt,
"chosen": p.chosen,
"rejected": p.rejected} for p in pairs]
config = DPOConfig(
output_dir=output_dir,
beta=beta, # 偏离参考模型的强度
num_train_epochs=epochs,
learning_rate=5e-6, # DPO 要小学习率
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
max_length=2048,
max_prompt_length=1024,
)
trainer = DPOTrainer(
model=self._model,
ref_model=None, # None → 自动用冻结的原模型做 ref
args=config,
train_dataset=dataset,
processing_class=self._tokenizer,
peft_config=self._peft_config,
)
trainer.train()
trainer.save_model(output_dir)
return output_dir
三个工程要点:
① LoRA(peft):只训低秩适配器,不动原权重——省显存(70B 单卡可训)、
防灾难性遗忘(原权重冻结,通用能力大体保留)
② ref_model=None:trl 自动用冻结的原模型做参考,不用单独部署
③ β=0.1 + lr=5e-6:DPO 对学习率敏感,太大过拟合偏好对、太小不收敛
四、GRPO:当需要过程奖励时
4.1 DPO 的局限:只评结果不评过程
DPO 只看"最终回答 chosen vs rejected",不关心中间步骤。但 Agent 的很多经验是过程性的——“第三步选错了工具,导致后面全崩”。这种 step-level 信号 DPO 吃不下。
DPO 能吃的: prompt → 回答 A 比回答 B 好 (结果偏好)
DPO 吃不下的:prompt → 步骤1✓ 步骤2✓ 步骤3✗ (过程奖励)
4.2 过程奖励:接第 7 篇反思器
第 7 篇的反思器已经在做 step-level 评估——每步反思"这步对不对"。这些信号天然是过程奖励的数据源:
第 7 篇反思器:每步生成 reflection "这步选错了工具,应该用 search 而非 calc"
→ 每步有一个 reward 信号(反思判定对/错)
→ 这正是 GRPO 需要的 step-level reward
4.3 GRPO:比 PPO 轻量的过程优化
GRPO(Group Relative Policy Optimization)是 PPO 的简化版——不需要 value model(PPO 要训 value + policy 两个网络,GRPO 只训 policy),用组内相对奖励代替绝对值估计。
# grpo_trainer.py —— GRPO 过程奖励微调
from trl import GRPOTrainer, GRPOConfig
class ExperienceGRPO:
"""用成功/失败路径的 step-level reward 做 GRPO"""
def __init__(self, model_name: str, exp_store, reward_fn):
self._model = AutoModelForCausalLM.from_pretrained(model_name)
self._exp_store = exp_store
self._reward_fn = reward_fn # 步骤打分函数(接第 7 篇反思器)
def train(self, output_dir: str):
from exp_to_training_data import ExpToTrainingData
rollouts = ExpToTrainingData(self._exp_store).export_grpo_rollouts()
config = GRPOConfig(
output_dir=output_dir,
num_generations=4, # 每个prompt生成4条rollout做组内对比
max_completion_length=512,
per_device_train_batch_size=2,
learning_rate=1e-6,
beta=0.04, # KL 惩罚强度
)
trainer = GRPOTrainer(
model=self._model,
args=config,
train_dataset=rollouts,
reward_funcs=self._reward_fn, # 每步打分
)
trainer.train()
return output_dir
GRPO 的适用边界:
| 场景 | 用 DPO | 用 GRPO |
|---|---|---|
| 用户纠偏最终回答 | ✓ | 过重 |
| Agent 多步轨迹,某步选错 | ✗ | ✓ |
| 有明确 step-level reward(第 7 篇反思器) | ✗ | ✓ |
| 数据量小(<200 对) | ✓ | 不够组内对比 |
先 DPO 后 GRPO:DPO 用纠偏数据快速对齐常见偏好,GRPO 在 DPO 基础上用过程信号精修多步决策。
五、微调闭环:经验→训练→评估→部署→新经验
5.1 闭环架构
┌────────── 第 9 篇 体外循环 ──────────┐
│ 执行 → 经验沉淀 → 治理 → prompt 注入 │
└──────────┬───────────────────────────┘
│ 经验积累到阈值(hit_count/置信度)
▼
┌────────── 本文 体内循环 ────────────┐
│ 经验导出 → 训练数据构造 │
│ ↓ │
│ DPO/GRPO 微调(LoRA) │
│ ↓ │
│ 评估(接第 6 篇,防能力退化) │
│ ↓ │
│ 灰度上线(接第 10 篇) │
│ ↓ │
│ 线上产生新经验 → 回到体外循环 │
└──────────────────────────────────────┘
两个循环咬合:体外循环持续积累,达到阈值触发体内循环;体内循环产出的新模型上线,又产生新经验喂回体外。
5.2 评估:微调不能降通用能力
微调最大的风险是灾难性遗忘——内化了业务偏好,忘了通用能力。评估必须双轨:
# eval_guard.py —— 微调后双轨评估
class FinetuneEvalGuard:
"""业务能力提升 + 通用能力不退化,两条都要过"""
def __init__(self, benchmark_suite, business_eval_set):
self._benchmark = benchmark_suite # MMLU/HumanEval 等通用基准
self._business = business_eval_set # 业务评测集(接第 6 篇)
def evaluate(self, base_model, tuned_model) -> dict:
# ① 业务能力:期望提升
biz_base = self._business.run(base_model)
biz_tuned = self._business.run(tuned_model)
biz_gain = biz_tuned["success_rate"] - biz_base["success_rate"]
# ② 通用能力:期望不退化
gen_base = self._benchmark.run(base_model)
gen_tuned = self._benchmark.run(tuned_model)
gen_drop = gen_base["score"] - gen_tuned["score"]
verdict = "pass" if (biz_gain > 0.03 and gen_drop < 0.02) else "fail"
return {
"biz_gain": round(biz_gain, 3),
"gen_drop": round(gen_drop, 3),
"verdict": verdict,
"note": ("通用能力跌 %.1f%%,超 2%% 阈值" % (gen_drop * 100)
if gen_drop >= 0.02 else "ok"),
}
两条硬门槛:
业务能力提升 > 3 个百分点(微调要有可见收益,否则不值)
通用能力下降 < 2 个百分点(MMLU/HumanEval 等,防灾难性遗忘)
任一不过 → 不上线,回调 LoRA 的 r / β / 数据质量
5.3 灾难性遗忘的防御
| 手段 | 原理 | 成本 |
|---|---|---|
| LoRA | 原权重冻结,只训低秩适配器 | 低,首选 |
| 混合训练数据 | 微调数据掺 10-20% 通用数据 | 低 |
| 正则化(KL 到原模型) | DPO 的 β / GRPO 的 β 就是这个 | 已内置 |
| 模型合并 | 微调模型与原模型权重平均 | 中,简单有效 |
实践中 LoRA + 混合数据 + β 正则 三件套组合,遗忘基本可控(MMLU 跌 1-2%)。
5.4 与第 17 篇选型的对接
第 17 篇说"微调是最后手段"——本文补上"最后"的判定标准:
值得开微调闭环:
✓ 经验库某类经验 hit_count > 50(稳定有用,不是偶发)
✓ 纠偏信号累积 > 200 对(DPO 数据量下限)
✓ 同一纠偏模式反复出现(prompt 注入压不住)
✓ 业务能力提升预期 > 3pp(值回训练成本)
不值得,继续用第 9 篇体外循环:
✗ 经验零散、低频、高冲突
✗ 知识频繁更新(该用 RAG,第 17 篇灾难一)
✗ 只是输出格式问题(该用 Prompt 工程,第 17 篇灾难二)
六、实测数据
在某 Agent 平台(客服域,日均 1.2 万次调用)灰度 3 轮微调闭环:
| 指标 | 第 9 篇(体外进化) | 本文(体内进化) |
|---|---|---|
| 同类任务首次成功率 | 89% | 94% |
| 经验复用延迟 | +200ms(检索+注入) | 0ms(内化) |
| 纠偏信号利用率 | 41%(只注入不内化) | 87%(进权重) |
| 经验占窗口 token | 200-2000/次 | 0(释放给证据/历史) |
| 通用 MMLU | 基线 72.1 | 70.3(-1.8pp,可接受) |
| DPO 训练成本 | — | 8H GPU/轮(A100) |
| GRPO 训练成本 | — | 16H GPU/轮 |
| 闭环周期 | 持续(零成本) | 经验积累 2 周 → 训练 1 天 → 评估 4h |
| 灾难性遗忘 | 无(不改权重) | MMLU -1.8pp(LoRA+混合数据控住) |
两个值得说的点:
① 89%→94% 只涨 5pp,但延迟从 +200ms 降为 0——
体内进化的价值不只是"更准",更是"更快更省窗口"。
每次省 200ms × 日 1.2 万次 = 日省 40 分钟总延迟。
② MMLU -1.8pp 是可控代价——LoRA 冻原权重 + 混合数据 + β 正则三件套,
没有出现"微调后连通用问答都不会了"的灾难性遗忘。
评估守门人(5.2 节)拦下了一轮 gen_drop 3.2pp 的不合格模型。
七、实施难度评估与落地建议
7.1 难度评估
| 模块 | 难度 | 说明 |
|---|---|---|
| 经验导出训练数据 | ★★☆☆☆ | 第 9 篇经验库现成,导出 + 质量过滤逻辑清晰 |
| DPO 训练 | ★★★☆☆ | trl 库封装好,难点在 β/lr 调参 + 数据质量 |
| GRPO 训练 | ★★★★☆ | 需要可靠的 step-level reward(接第 7 篇反思器),调参更难 |
| 双轨评估 | ★★★☆☆ | 通用基准现成(MMLU/HumanEval),业务评测集接第 6 篇 |
| 灾难性遗忘防御 | ★★★☆☆ | LoRA+混合数据+β 正则三件套,组合调优 |
| 闭环自动化 | ★★★★☆ | 经验阈值触发 + 训练 + 评估 + 灰度,全链路自动化难 |
7.2 三步落地路线
第一步(2-3 周,先验证数据):
从第 9 篇经验库导出纠偏对 + 质量过滤
—— 不训练,只看导出的 preference pair 数量和质量
纠偏对 < 200 → 继续攒经验,别急着训;> 200 → 进第二步。
第二步(1-2 周,DPO 闭环):
DPO + LoRA 微调 + 双轨评估 + 灰度上线
—— 先只做 DPO(纠偏信号最直接),GRPO 留到有明确过程奖励需求时
评估守门人拦住退化模型,灰度 10%→50%→全量。
第三步(按需,过程奖励场景):
GRPO + step-level reward(接第 7 篇反思器)
—— 只在"多步轨迹某步选错"是主要失败模式时才上
成本是 DPO 的 2 倍,没有过程信号别硬上。
7.3 一个认知收尾
第 9 篇的体外进化是"记笔记"——便宜、即时、但每次考试都要翻笔记。本文的体内进化是"把笔记读懂了变成自己的知识"——贵、慢,但考试时不用翻。真实的学习两者都要:先记笔记(体外循环持续跑),笔记攒够了读懂内化(体内微调周期性触发),内化后又在新能力上记新笔记。两个循环咬合,才是完整的"越用越强"。第 17 篇说微调是"最后手段"——本文补上:最后不等于不做,是"前面的手段都用尽、经验数据攒够了、收益算得清"之后才做。
下一篇预告:推理加速主线已收官四篇,第 26 篇预告的"缓存与成本优化"仍未展开——语义缓存、Prompt 前缀缓存、按用户/任务差异化定价,是成本治理的最后一块拼图。
- 点赞
- 收藏
- 关注作者
评论(0)