
1. 项目概述当大模型学会“主动提问”最近在折腾大语言模型LLM驱动的智能体Agent特别是那些需要处理多轮对话、从海量文档里找证据的复杂任务时发现一个普遍痛点模型太“被动”了。你给它一堆文档让它回答一个问题它要么一股脑儿把所有文档都“读”一遍计算成本爆炸要么就凭感觉随机选几篇看准确率堪忧。这就像让一个研究员去图书馆查资料但他没有检索策略只能漫无目的地翻书架效率极低。CIGPOContextual Information-Gain Policy Optimization这个框架就是为了解决这个核心问题而生的。它的目标很明确教会LLM Agent在每一轮与文档库的交互中学会问自己——“看哪篇文档能让我获得最大的信息增益” 这里的“信息增益”不是拍脑袋决定的而是根据当前已有的对话历史和已阅读的证据动态计算出来的。简单说CIGPO让Agent从一个被动的“读者”转变为一个主动的、有策略的“调查员”。这个思路在需要多步推理的问答场景如HotpotQA这类需要联系多个支持事实的问答数据集中尤其有价值。传统的微调方法比如标准的监督微调SFT或者近段时间热门的GRPOGroup Relative Policy Optimization更多是优化模型的最终输出答案的质量。而CIGPO则聚焦于优化模型寻找答案的过程——即它的“阅读策略”。它不直接告诉模型答案是什么而是通过强化学习奖励那些能高效、精准定位关键证据的阅读行为。我花了不少时间研读相关论文和代码也在一些简化任务上做了复现尝试。下面我就把自己对CIGPO的理解、它的核心设计、实操中的关键点以及一些踩过的坑系统地梳理出来。无论你是刚接触LLM Agent的新手还是已经在探索策略优化方向的研究者希望这篇深度拆解都能给你带来一些实在的启发。2. 核心思路拆解为什么是“信息增益”要理解CIGPO得先抛开代码从第一性原理去想一个完美的、多轮检索阅读的Agent应该怎么工作假设任务是用10篇文档回答一个复杂问题。最笨的方法是让Agent依次读完10篇。但显然读完第1篇后Agent对问题和答案已经有了部分认知第2篇的选择就应该基于第1篇的内容来决定。比如第1篇提到了“事件A发生在北京”那么第2篇Agent应该更倾向于选择能解释“事件A原因”或“北京相关细节”的文档而不是再去读一篇同样只讲“事件A发生在北京”的文档。后者带来的信息量几乎为零。这就是信息增益的核心思想在已有上下文Context的条件下选择能带来最大新增信息量的动作阅读哪篇文档。CIGPO将这个直觉形式化为一个强化学习问题。2.1 问题建模马尔可夫决策过程MDPCIGPO将多轮证据阅读过程定义为一个MDP状态State, s_t在时间步t状态包含初始问题Q以及到当前步为止所有已阅读过的文档内容集合 C_t {d_1, d_2, ..., d_t}。动作Action, a_t从剩余未读文档池中选择一篇文档 d_{t1} 进行阅读。状态转移执行动作a_t阅读文档d_{t1}后状态更新为 s_{t1}其上下文集合变为 C_{t1} C_t ∪ {d_{t1}}。奖励Reward, r_t这是关键。CIGPO设计了一个基于信息增益的即时奖励。阅读文档d_{t1}后奖励不是最终答案的对错而是这篇文档带来的信息价值。2.2 信息增益奖励的具体计算这是CIGPO最精巧的部分。它如何量化“信息价值”一种常见的方法是使用LLM本身作为“评判官”。具体计算可以分为两步预测答案分布的变化在状态s_t阅读当前文档前让LLM Agent基于已有上下文C_t对最终答案的可能性分布做一个预测。同样在状态s_{t1}阅读新文档后再让Agent基于新的上下文C_{t1}做一次预测。度量分布差异计算这两个预测分布之间的差异。差异越大说明新文档对Agent的“认知”改变越大即信息增益越高。常用的度量方式是KL散度Kullback-Leibler Divergence。用公式可以直观表示概念上信息增益 IG_t ≈ KL[ P(Answer | C_t ∪ {d_{t1}}, Q) || P(Answer | C_t, Q) ]这个值就是时间步t的即时奖励 r_t。它鼓励Agent选择那些能显著改变其答案信念的文档也就是最“有用”的文档。注意这里有一个重要的实操细节。直接让LLM输出答案的概率分布比较困难。在实际实现中往往通过采样多个答案或者利用模型输出logits经过softmax后的概率来近似。也有工作使用预测答案的熵Entropy变化来衡量。选择哪种近似方法需要平衡计算成本和准确性。2.3 与GRPO的对比与关联你可能会想到另一个热词——GRPO。这里需要厘清关系。GRPO是一种策略优化算法它属于强化学习从人类反馈RLHF范畴的一种高效变体通过分组比较来优化策略减少了传统PPO算法的复杂度。而CIGPO是一个特定的任务框架它定义了多轮阅读任务中的状态、动作和基于信息增益的奖励函数。在这个框架下你可以使用GRPO作为其内部的策略优化器来训练Agent的策略网络。打个比方GRPO是“发动机的调校技术”而CIGPO是“一辆赛车的整体设计蓝图”蓝图里指定了这辆车Agent应该如何根据赛道情况上下文选择最佳路线阅读文档而GRPO可以用来优化这辆车的驾驶AI策略网络使其更好地执行蓝图。所以网络热词中“verl如何配置微调grpo”可能是在探索如何用GRPO算法来优化类似CIGPO框架中的策略。3. 架构与实操要点解析理解了核心思想我们来看CIGPO系统具体怎么搭建。一个完整的实现通常包含以下几个核心模块。3.1 系统核心组件文档检索器Retriever这不是CIGPO的创新点但却是基础。给定一个问题Q首先需要一个检索器如基于稠密向量的DPR、ANCE或稀疏检索的BM25从一个大型知识库中召回一个相关的文档候选池例如Top-20。CIGPO的阅读策略将在这个候选池上运作。阅读策略网络Policy Network这就是我们要训练的核心——一个LLM。它的输入是当前状态s_t问题和已读文档输出是对剩余未读文档的概率分布即选择每篇文档作为下一个阅读目标的概率。这个网络通常基于一个预训练的LLM如LLaMA、Qwen等进行微调。环境模拟器Environment Simulator为了训练策略网络我们需要模拟多轮阅读的过程。环境模拟器负责维护当前状态已读文档集。接收策略网络选择的动作文档ID。返回新的状态加入新文档内容。计算并返回即时奖励即上文所述的信息增益。这是环境模拟器最关键、也最耗计算的部分。奖励计算器Reward Calculator实现信息增益计算逻辑的模块。它被环境模拟器调用内部会两次调用LLM或一个固定的奖励模型来获取阅读前后的答案分布并计算差异。策略优化器Policy Optimizer使用强化学习算法如GRPO、PPO来更新策略网络参数的模块。它收集策略与环境交互产生的轨迹状态、动作、奖励计算策略梯度并更新模型。3.2 训练流程拆解训练一个CIGPO Agent是一个迭代过程初始化加载预训练的LLM作为策略网络初始化优化器。数据准备对于训练集中的每个问题用检索器获取相关文档候选池。交互采样对于一个问题环境初始状态s_0只包含问题Q。策略网络根据s_0输出动作概率采样选择第一篇文档a_0。环境执行a_0将对应文档内容加入上下文形成新状态s_1同时奖励计算器算出即时奖励r_0。重复此过程直到达到预设的最大阅读轮数T如5轮或策略网络选择了一个特殊的“停止阅读”动作如果设计了的话。这样就产生了一条轨迹 (s_0, a_0, r_0, s_1, a_1, r_1, ..., s_T)。优势估计与优化收集一批轨迹后策略优化器如GRPO会计算每个动作的“优势”Advantage即这个动作相对于平均表现好多少。然后通过最大化优势 * 动作概率来更新策略网络的参数使其更倾向于选择能带来高信息增益即高奖励的动作。迭代重复步骤3-4直到策略收敛。3.3 关键超参数与设计选择在实际操作中以下几个选择至关重要最大阅读轮数T限制Agent的“预算”。T太小可能证据不足T太大训练和推理成本高。需要在效果和效率间权衡。HotpotQA任务上通常T3~5就能取得大部分收益。奖励计算模型是用被训练的策略网络本身来计算阅读前后的答案分布还是用一个固定的、更大的“教师模型”前者节省资源但可能不稳定因为策略在变化后者更稳定但计算成本高。一个折中方案是使用一个固定版本的策略网络在训练过程中定期更新作为奖励模型。基线Baseline在计算优势时需要估计状态的价值Value。这个价值基线可以用一个单独的价值网络Value Network来估计也可以简单地用轨迹上的奖励移动平均。GRPO算法通常简化了这部分直接使用分组内的相对比较。动作空间动作是直接输出文档ID的概率分布。对于候选池有K篇文档的情况动作空间大小就是K。这要求策略网络的输出层能适应不同的K。一种做法是将文档编码为向量然后让策略网络输出一个与文档向量做点积的权重向量通过softmax得到概率。4. 实操复现与核心代码逻辑由于完整的CIGPO实现代码量较大这里我勾勒出最核心部分的伪代码逻辑并解释关键步骤。假设我们使用GRPO作为优化器。# 伪代码展示核心训练循环逻辑 import torch from transformers import AutoModelForCausalLM, AutoTokenizer class CIGPOAgent: def __init__(self, model_name, retriever, max_turns5): self.policy_net AutoModelForCausalLM.from_pretrained(model_name) # 策略网络 self.tokenizer AutoTokenizer.from_pretrained(model_name) self.retriever retriever self.max_turns max_turns self.optimizer torch.optim.Adam(self.policy_net.parameters(), lr1e-5) # 可能还需要一个固定的“目标网络”用于奖励计算 def compute_information_gain(self, question, context_before, context_after): 计算阅读一篇文档前后的信息增益奖励。 这里用答案的负熵变化作为简化示例。 # 1. 构建提示词让模型基于上下文生成答案 prompt_before fContext: {context_before}\nQuestion: {question}\nAnswer: prompt_after fContext: {context_after}\nQuestion: {question}\nAnswer: # 2. 获取模型对答案的预测分布这里简化实际需处理完整序列 with torch.no_grad(): logits_before self._get_answer_logits(prompt_before) logits_after self._get_answer_logits(prompt_after) # 3. 计算分布例如对答案的起始token或特定词汇表子集 prob_before torch.softmax(logits_before, dim-1) prob_after torch.softmax(logits_after, dim-1) # 4. 计算熵 entropy_before -torch.sum(prob_before * torch.log(prob_before 1e-10)) entropy_after -torch.sum(prob_after * torch.log(prob_after 1e-10)) # 5. 信息增益 熵的减少量不确定性降低 # 也可以使用KL散度kl_div torch.sum(prob_after * torch.log(prob_after / prob_before)) info_gain entropy_before - entropy_after return info_gain.item() def _get_answer_logits(self, prompt): # 编码输入获取模型输出并提取答案相关位置的logits inputs self.tokenizer(prompt, return_tensorspt).to(device) outputs self.policy_net(**inputs, output_hidden_statesFalse, output_attentionsFalse) # 假设我们关注紧接“Answer:”后的第一个token的logits answer_start_idx ... # 需要根据tokenizer确定位置 logits outputs.logits[0, answer_start_idx, :] return logits def select_document(self, question, read_docs, candidate_docs): 策略网络根据当前状态问题已读文档选择下一文档。 返回选择文档的索引和对应的log概率用于GRPO损失计算。 # 构建状态描述 state_prompt self._build_state_prompt(question, read_docs) # 将候选文档编码为特征例如用另一个编码器或直接用策略网络编码其标题/片段 doc_features self._encode_docs(candidate_docs) # 策略网络处理状态并生成与文档特征相关的分数 state_inputs self.tokenizer(state_prompt, return_tensorspt).to(device) state_representation self.policy_net(**state_inputs, output_hidden_statesTrue).last_hidden_state[:, -1, :] # 取最后时刻的隐状态 # 计算文档分数例如点积 scores torch.matmul(state_representation, doc_features.T).squeeze() probs torch.softmax(scores, dim-1) # 采样动作 dist torch.distributions.Categorical(probs) action_idx dist.sample() log_prob dist.log_prob(action_idx) return action_idx.item(), log_prob, probs def train_on_batch(self, batch_questions): all_log_probs [] all_rewards [] all_entropies [] for question in batch_questions: candidate_docs self.retriever.retrieve(question, k20) read_docs [] trajectory_log_probs [] trajectory_rewards [] for turn in range(self.max_turns): # 1. 选择动作 action_idx, log_prob, probs self.select_document(question, read_docs, candidate_docs) selected_doc candidate_docs[action_idx] trajectory_log_probs.append(log_prob) # 记录策略的熵用于正则化 all_entropies.append(-torch.sum(probs * torch.log(probs 1e-10))) # 2. 执行动作获取新状态和奖励 context_before self._format_docs(read_docs) read_docs.append(selected_doc) context_after self._format_docs(read_docs) # 从候选池移除已读文档避免重复选择 candidate_docs.pop(action_idx) # 3. 计算即时奖励信息增益 reward self.compute_information_gain(question, context_before, context_after) trajectory_rewards.append(reward) # 可选判断是否提前停止例如模型输出停止符 # 对于GRPO通常需要计算每个步的优势这里简化使用蒙特卡洛回报 # 实际GRPO实现会更复杂涉及分组和归一化 returns [] R 0 for r in reversed(trajectory_rewards): R r 0.99 * R # 带折扣的累计回报 returns.insert(0, R) returns torch.tensor(returns).to(device) all_log_probs.extend(trajectory_log_probs) all_rewards.extend(returns) # GRPO核心优化步骤简化版思想 # 1. 将回报归一化减去均值除以标准差 normalized_returns (torch.stack(all_rewards) - torch.mean(torch.stack(all_rewards))) / (torch.std(torch.stack(all_rewards)) 1e-8) # 2. 计算策略梯度损失最大化 对数概率 * 优势 policy_loss -torch.mean(torch.stack(all_log_probs) * normalized_returns) # 3. 添加熵正则项鼓励探索 entropy_loss -torch.mean(torch.stack(all_entropies)) total_loss policy_loss - 0.01 * entropy_loss self.optimizer.zero_grad() total_loss.backward() torch.nn.utils.clip_grad_norm_(self.policy_net.parameters(), max_norm1.0) self.optimizer.step() return total_loss.item()实操心得上面的伪代码极大地简化了GRPO和奖励计算。真实实现中compute_information_gain函数是性能瓶颈和设计关键。为了稳定训练我建议使用一个固定的“目标网络”来计算奖励这个目标网络每隔几百步从当前策略网络同步一次参数。这能防止奖励信号随着策略剧烈变化而震荡。对奖励进行归一化如减去批次均值除以标准差这能稳定GRPO/PPO的训练。信息增益的计算可以异步进行。在环境模拟时可以将(context_before, context_after, question)三元组存入队列由另一个进程或线程中的奖励模型批量计算避免阻塞策略网络的前向传播。5. 常见问题与排查技巧实录在尝试复现和调优CIGPO这类框架时我遇到了不少典型问题。这里列出来并提供我的排查思路。5.1 奖励信号不稳定或始终为零现象训练初期计算出的信息增益奖励值非常小或者波动极大导致策略无法学习。可能原因与排查答案分布变化不敏感你的奖励计算模型可能是策略网络本身能力不足或者提示词设计不好导致它基于不同上下文生成的答案分布差异很小。排查手动检查几个例子。固定一个问题分别给模型提供一份弱相关文档和一份强相关文档看模型生成的答案文本或top-k token的概率是否有明显差异。如果没有需要优化提示词或考虑使用更强的模型作为奖励计算器。KL散度/熵的计算位置不对你可能在计算整个序列的分布差异而噪声太大。排查聚焦于答案的关键token。例如在多项选择题任务中只计算几个选项对应token的概率变化。在生成任务中可以计算答案首token或前几个token的分布差异。奖励尺度问题原始的信息增益值可能绝对值很小例如0.01~0.1。解决对奖励进行缩放乘以一个系数和归一化减去均值除以标准差使其落在[-1, 1]或[0, 1]的合理范围内。5.2 策略陷入局部最优或探索不足现象Agent很快学会总是选择某一类文档如第一篇检索结果无法学习更精细的策略最终效果提升有限。可能原因与排查熵正则化权重太低在损失函数中熵正则项entropy_loss的系数太小模型过早地“确信”某个选择。解决适当增大熵正则项的系数如从0.01调到0.05鼓励模型在训练初期保持探索。初始策略偏差如果你的策略网络是用SFT在问题黄金证据链数据上微调过的它可能会有很强的初始偏好。解决在强化学习训练初期可以设置一个较大的探索率例如在select_document时以一定概率随机选择文档随着训练进行再衰减。动作空间表示问题文档的向量表示doc_features可能无法区分其内容差异。排查检查不同文档的向量表示是否相似。尝试用更强大的编码器如Sentence-BERT来生成文档特征或者用文档的标题、首句等关键信息的拼接作为特征。5.3 训练速度慢内存占用高现象每一步都需要前向传播两次计算阅读前后分布来算奖励导致训练极其缓慢。优化策略奖励模型蒸馏训练一个小的、专用的奖励模型来近似信息增益的计算。这个奖励模型以问题当前上下文候选文档为输入直接输出一个标量奖励。用大模型如GPT-4生成一批奖励标签来训练它。训练时用小奖励模型代替大模型进行实时奖励计算。异步奖励计算如前所述将奖励计算与策略网络的前向传播解耦放到另一个进程中。梯度累积与更大批次由于强化学习样本效率低需要大量交互。在内存允许的情况下增大批次大小batch size能提高训练稳定性。如果单卡内存不够可以使用梯度累积模拟更大的批次。5.4 在HotpotQA等数据集上效果不明显现象相比简单的“阅读所有检索到的Top-K文档”的基线方法CIGPO训练后的Agent提升有限。深度排查检索质量是天花板如果检索器召回的Top-20文档里真正相关的只有1-2篇那么再好的阅读策略也无能为力。首先确保你的检索器在该数据集上的召回率Recall足够高。可以先用一个Oracle检索器直接返回黄金支持文档测试CIGPO框架的上限。任务复杂度与轮数T对于HotpotQA很多问题只需要2-3个支持文档。如果T设置得太大如10模型可能学会在前几轮找到关键文档后后面几轮随便选这会稀释奖励信号。尝试减小T或者设计一个“停止阅读”的智能动作让模型自己决定何时停止。评估指标最终你是用答案的F1/EM来评估吗确保你的评估流程正确。策略优化目标是最大化累计信息增益奖励但这个奖励与最终答案准确率的相关性需要对齐。有时需要在奖励中加入一个最终的、稀疏的“任务完成奖励”例如在最后一轮如果生成的答案正确则给予一个大的正奖励否则给予负奖励或零奖励。这能更好地将过程优化与最终目标对齐。6. 进阶思考与扩展方向CIGPO为我们打开了LLM Agent决策过程优化的一扇门。在实际项目中你可以从以下几个方向进行扩展混合奖励信号单纯的信息增益可能不是万能的。可以结合其他奖励如文档与当前问题的相关性分数来自检索器、答案的置信度、甚至人工反馈。设计一个多目标的奖励函数。分层策略阅读策略可以分层。高层策略决定下一步是“检索新文档”、“深入阅读当前文档的某一段落”还是“生成最终答案”。底层策略再执行具体操作。这适合更开放域的任务。与工具使用结合CIGPO的“阅读”动作可以泛化为“使用工具”。例如动作可以是“调用搜索引擎API”、“查询数据库”、“执行代码”等。奖励则定义为工具执行结果带来的信息增益或任务进度推进。这就构成了一个通用的工具学习Agent框架。离线强化学习上述方法是在线交互学习成本高。可以利用已有的问题文档序列答案数据集通过离线强化学习算法如IQL、CQL来训练阅读策略减少交互成本。我个人在实验中的体会是CIGPO这类方法最有魅力的地方在于它让模型的决策过程变得可解释、可优化。你不仅能得到一个更好的答案还能看到模型是如何一步步通过“思考”选择阅读材料得出这个答案的。这为构建更可靠、更可信的AI系统提供了新的思路。当然它的复杂性和计算成本也是实实在在的挑战需要根据具体应用场景仔细权衡投入产出比。如果你正准备在复杂问答、知识密集型对话或Agent决策领域深入花时间理解并实践CIGPO的思想绝对是值得的。