1. 项目概述一个为长视野任务而生的LLM智能体强化学习框架如果你正在尝试用强化学习RL来训练大语言模型LLM智能体尤其是在那些需要几十步甚至上百步交互才能完成的长视野任务上你很可能已经遇到了一个核心瓶颈上下文爆炸。传统的做法比如直接把整个交互历史observation action拼接起来喂给模型在ALFWorld或WebShop这类任务中会让输入序列长度迅速膨胀很快触及模型的上下文窗口极限导致训练效率低下甚至无法进行。verl-agent正是为了解决这个问题而生的。它不是一个简单的RL工具包而是一个专门为多轮次、长视野LLM/VLM视觉语言模型智能体训练设计的框架。其核心创新在于提出了“步独立的多轮次展开机制”。简单来说它不再要求你把所有历史信息都塞进当前输入而是允许你为每一步交互完全自定义输入结构。你可以只放入最近几步的关键观察和动作或者一个动态生成的摘要甚至整合外部知识。这使得模型在每一步的输入都保持精简上下文长度几乎恒定从而能够优雅地扩展到超长任务序列。我最初接触这个项目是为了解决一个视觉推理智能体在Sokoban推箱子游戏中长期规划能力不足的问题。在尝试了PPO、GRPO等算法后发现它们在超过20步的规划中奖励信号变得极其稀疏和延迟智能体很难学到有效的策略。verl-agent框架特别是其内置的GiGPOGroup-in-Group Policy Optimization算法通过引入“组中组”的细粒度信用分配机制显著改善了这个问题。经过几轮实验我在6x6的Sokoban关卡上用Qwen2.5-VL-3B模型将成功率从不到40%提升到了80%以上。这个框架将环境交互、记忆管理、策略优化等复杂环节模块化让研究者能更专注于智能体策略本身的设计与调优。2. 核心设计思路为何“步独立”是长视野训练的关键在深入代码之前理解verl-agent的设计哲学至关重要。它的一切都围绕着如何高效、可扩展地处理智能体与环境的多步交互循环。2.1 与传统方法的根本区别在verl-agent出现之前常见的LLM智能体RL训练范式可以称为“历史拼接式”。以 Search-R1 或早期的 RAGEN 为例它们的流程大致是让智能体完成一个完整的多步任务轨迹。将这个轨迹中所有的状态或观察和智能体的响应拼接成一个超长的文本序列。将这个序列作为输入用于计算损失和更新模型。这种方法的弊端显而易见假设一个任务平均需要30步每步观察和动作平均消耗200个token那么一个轨迹的输入长度就高达6000 token。这已经接近或超过了许多中等规模模型的上下文限制。更糟糕的是随着训练进行你需要并行处理多个这样的轨迹对显存和计算都是巨大的挑战。verl-agent则采用了截然不同的“步独立”视角。它将一次多步交互视为一个动态的、逐步构建的过程。在每一步环境提供一个当前观察observation。记忆模块根据预设策略如最近K步、关键事件摘要从历史中提取相关信息。输入构建器将当前观察和记忆摘要连同任务指令、可用动作列表等组合成当前步的模型输入。模型基于这个固定且精简的上下文生成当前步的动作。这样做的好处是无论任务多长模型每一步看到的上下文长度都是可控的例如只包含最近3步的历史摘要彻底解决了上下文爆炸问题。2.2 框架的核心组件与数据流为了支撑“步独立”的设计verl-agent抽象出了几个关键组件它们共同构成了训练流水线环境管理器 (EnvironmentManager): 这是与具体环境如ALFWorld、WebShop交互的桥梁。它封装了环境的重置reset和步进step逻辑并将原始环境输出可能是文本、图像或结构化数据格式化为框架统一的观察格式。它支持并行化环境执行以加速数据收集并引入了“组环境”的概念用于需要从同一初始状态进行多次采样的算法如GRPO、GiGPO。记忆模块 (Memory): 这是实现灵活历史管理的核心。框架提供了一个基础的SimpleMemory类它默认保存完整的交互历史。但你可以轻松继承并重写它的get_memory_text方法。例如你可以实现一个WindowMemory只返回最近N步或者一个SummaryMemory调用另一个LLM实时生成历史摘要。这个模块在env_manager.py的build_text_obs函数中被调用用于构建每一步的文本观察。多轮次展开循环 (MultiTurnRollout): 这是驱动整个交互过程的引擎。它负责循环执行“观察-记忆检索-模型推理-环境执行”的流程直到任务终止成功、失败或达到最大步数。它会收集每一步的观察、动作、奖励、完成标志等信息最终整理成一个完整的轨迹数据供后续的RL算法使用。策略优化器 (Trainer): 这是各种RL算法的实现容器。verl-agent集成了从经典的PPO到最新的GiGPO等多种算法。它们接收从展开循环收集来的轨迹数据计算策略梯度或优势估计并更新模型参数。一个典型的数据流如下[并行环境] - [环境管理器] - (当前观察 记忆模块) - [格式化输入] - [LLM/VLM 模型] - [动作采样] ^ | | v | [环境执行获得奖励和下一观察] | | ---------------------------------------------------------------------------------------这个闭环会持续进行直到一个批次的轨迹被收集完毕然后交给训练器进行参数更新。3. 环境配置与实战安装指南理论说得再多不如亲手跑起来。verl-agent支持多种环境但它们的依赖可能冲突。我的第一条血泪教训务必为每个环境创建独立的conda环境下面我将以最复杂的两个环境——WebShop和Search-R1为例带你走通安装流程。3.1 基础框架与ALFWorld环境安装首先我们创建一个主环境用于安装框架核心和相对简单的环境如ALFWorld、Sokoban。# 创建并激活主环境 conda create -n verl-agent-main python3.12 -y conda activate verl-agent-main # 安装核心依赖注意flash-attn和vllm的版本兼容性 pip3 install torch2.6.0 torchvision0.21.0 torchaudio2.6.0 --index-url https://download.pytorch.org/whl/cu124 pip3 install vllm0.11.0 pip3 install flash-attn2.7.4.post1 --no-build-isolation --no-cache-dir # 从源码安装verl-agent框架 git clone https://github.com/langfengQ/verl-agent.git cd verl-agent pip install -e .接下来安装ALFWorld这是一个文本化的家庭任务模拟环境。pip3 install gymnasium0.29.1 pip3 install stable-baselines32.6.0 pip install alfworld # 下载必要的游戏文件和数据 alfworld-download -f如果下载速度慢可以尝试科学上网或寻找镜像源。安装完成后可以用alfworld-play-tw命令测试环境是否正常。3.2 WebShop环境Python版本隔离实战WebShop是一个在线购物网站模拟环境其原始代码对Python版本有要求3.10因此必须单独隔离。# 为WebShop创建专属环境 conda create -n verl-agent-webshop python3.10 -y conda activate verl-agent-webshop # 导航到框架内的WebShop包目录进行安装 cd /path/to/verl-agent/agent_system/environments/env_package/webshop/webshop # 执行安装脚本-d all表示下载所有数据 ./setup.sh -d all注意setup.sh脚本中会使用gdown从Google Drive下载模型文件。如果遇到下载失败通常是因为Google Drive的访问限制。你需要手动获取下载链接或Cookie。一个变通方法是查看脚本中gdown命令后的文件ID然后通过https://drive.google.com/uc?idFILE_ID这样的链接在浏览器中尝试下载或使用gdown --id FILE_ID命令并附上你的浏览器Cookie。安装完WebShop后不要退出这个conda环境我们需要在这个环境里安装verl-agent的核心包因为训练脚本会调用到这个环境下的模块。# 回到项目根目录 cd /path/to/verl-agent # 在当前环境verl-agent-webshop下安装框架 pip3 install -e . # 可能需要重新安装或调整一些依赖版本以适应Python 3.10 pip3 install vllm0.8.2 # 注意版本降级以兼容你会看到一些关于typer等包的警告通常可以忽略只要后续能成功导入模块即可。3.3 Search-R1环境构建本地检索服务器Search-R1是一个需要调用检索工具如搜索API的环境verl-agent为其实现了一个本地检索服务这需要另一个独立环境。# 创建检索服务专用环境 conda create -n retriever python3.10 -y conda activate retriever # 安装基础依赖注意faiss-gpu需要通过conda安装 conda install numpy1.26.4 -y pip install torch2.6.0 torchvision0.21.0 torchaudio2.6.0 --index-url https://download.pytorch.org/whl/cu124 pip install transformers datasets pyserini huggingface_hub conda install faiss-gpu1.8.0 -c pytorch -c nvidia -y pip install uvicorn fastapi然后准备数据和启动服务# 确保在 retriever 环境下 conda activate retriever # 下载检索索引和数据 local_dir~/data/searchR1 python examples/search/searchr1_download.py --local_dir $local_dir # 合并索引文件并解压数据 cat $local_dir/part_* $local_dir/e5_Flat.index gzip -d $local_dir/wiki-18.jsonl.gz # 启动检索服务器建议重定向输出到日志文件避免干扰 bash examples/search/retriever/retrieval_launch.sh retrieval_server.log 21 重要提醒这个检索服务会占用约6GB的GPU显存。在启动你的RL训练脚本前请确保GPU有足够空闲内存。3.4 其他环境安装要点Sokoban Gym Cards: 这两个环境相对简单可以在主环境 (verl-agent-main) 中直接安装。conda activate verl-agent-main pip install gym0.26.2 gym_sokoban0.0.6 matplotlib # Gym Cards 是自定义包从本地安装 pip install -e ./agent_system/environments/env_package/gym_cards/gym-cards/AppWorld (实验性): 同样建议创建独立环境 (appworld) 安装其服务端因为其依赖可能与主框架冲突。环境管理心得我习惯使用conda env list查看所有环境并用tmux或screen会话为每个长期运行的服务如检索服务器开一个单独的窗口这样管理起来非常清晰。4. 从零开始运行你的第一个GiGPO训练任务安装好环境后最激动人心的就是启动训练。verl-agent在examples/目录下为每个算法和环境都提供了开箱即用的脚本。我们以在ALFWorld上运行GiGPO为例。4.1 配置文件解析训练器的中枢神经在运行脚本前理解核心配置文件ppo_trainer.yaml虽然叫PPO但它是所有基于策略梯度算法的通用配置模板是至关重要的。它位于verl/trainer/config/目录下。我们挑几个关键参数详解# 模型相关配置 model: model_path: “Qwen/Qwen2.5-1.5B-Instruct” # 模型HF仓库ID或本地路径 use_lora: false # 是否使用LoRA进行轻量化训练 lora_r: 8 # LoRA的秩 lora_alpha: 16 # LoRA的缩放参数 # 环境与展开配置 env: name: “alfworld” # 环境名称对应 env_manager.py 中的注册名 rollout: n: 4 # 核心参数组大小 (group size)。对于GiGPO/GRPO这代表从同一初始状态采样的轨迹数。 batch_size: 2 # 并行环境数量 max_steps: 50 # 单个轨迹的最大步数 # 训练超参数 train: total_steps: 100000 # 总训练步数环境交互步数 num_epochs: 4 # 每次收集数据后参数更新的轮数 batch_size: 32 # 训练时用于梯度更新的batch size learning_rate: 5.0e-6 # 学习率 clip_range: 0.2 # PPO/GiGPO等算法中的策略梯度裁剪范围 # GiGPO特定参数 algorithm: name: “gigpo” gigpo: inner_group_size: 2 # 内组大小即step-level group的大小。必须满足 rollout.n % inner_group_size 0。 temperature: 0.1 # 用于计算策略概率的温度参数env.rollout.n: 这是理解“组”概念的关键。设为4意味着每次环境重置后会并行运行4个环境实例这些实例初始状态相同收集4条独立的轨迹。这4条轨迹构成一个“episode-level group”用于计算整个任务的回报差异。algorithm.gigpo.inner_group_size: 这是GiGPO的精华。假设rollout.n4,inner_group_size2。在训练时算法会在这4条轨迹中寻找那些在相同或相似状态下采取了不同动作的步骤对。它会将这样的步骤对例如轨迹1的第3步和轨迹3的第3步组成一个“step-level group”进而计算单个动作的相对优势。这实现了比GRPO更细粒度的信用分配。4.2 执行训练脚本与监控ALFWorld的GiGPO训练脚本examples/gigpo_trainer/run_alfworld.sh内容通常如下#!/bin/bash export CUDA_VISIBLE_DEVICES0,1 # 指定使用的GPU CONFIG_PATH“verl/trainer/config/ppo_trainer.yaml” OUTPUT_DIR“./output/alfworld_gigpo” python -m verl.trainer \ --config $CONFIG_PATH \ --output_dir $OUTPUT_DIR \ --model.model_path “Qwen/Qwen2.5-1.5B-Instruct” \ --env.name “alfworld” \ --algorithm.name “gigpo” \ --env.rollout.n 4 \ --algorithm.gigpo.inner_group_size 2 \ --train.total_steps 20000运行它conda activate verl-agent-main # 确保在正确的环境 bash examples/gigpo_trainer/run_alfworld.sh如何监控训练过程控制台输出关注reward回合奖励、ep_len回合平均长度、success_rate成功率等关键指标的变化趋势。WB / Tensorboard如果配置了WandB在配置文件中设置logger相关参数可以实时在网页上查看更丰富的曲线图包括损失函数、策略熵、价值估计等。检查点与日志训练过程中会在output_dir下保存模型检查点.pth和日志文件。定期查看日志可以了解更详细的运行时信息。4.3 实验管理经验分享显存估算训练一个7B模型不使用LoRArollout.n4batch_size32在2张H100上大约需要40GB显存。启用LoRA后显存需求可大幅下降。超参数调优起点learning_rate: 对于RLHF风格训练5e-6到1e-5是一个常见的稳定范围。clip_range: 通常保持在0.1到0.3之间0.2是个不错的默认值。rollout.n: 越大优势估计的方差越小但计算成本越高。对于GiGPO4或8是常用值。inner_group_size: 通常是rollout.n的约数2或4。你可以通过分析轨迹观察有多少轨迹会在同一步达到相似状态来调整这个值。任务难度与步数对于ALFWorldmax_steps设为50基本覆盖所有任务。对于更简单的任务可以设小一些以加速训练。5. 算法深度解析GiGPO为何效果出众verl-agent集成了众多RL算法但GiGPO是其招牌和灵魂。理解它你就能理解这个框架的设计深度。5.1 GRPO的局限与GiGPO的改进要懂GiGPO先要明白GRPOGroup Relative Policy Optimization在做什么。GRPO是一种无价值函数Critic-free的算法。它的核心思想是从同一个初始状态出发采样一组N条完整轨迹。由于初始状态相同这组轨迹最终获得的不同总回报G1, G2, ..., GN完全是由轨迹中每一步策略的差异导致的。GRPO利用这些回报的差异为整条轨迹计算一个相对优势然后使用这个优势来更新轨迹中所有步骤的策略。GRPO的问题它进行的是“轨迹级”的信用分配。一条轨迹成功了它里面的所有步骤无论关键与否都得到“奖励”失败了所有步骤都受到“惩罚”。这就像老师给一个小组项目只打一个总分组内每个成员的贡献是模糊的。在长视野任务中这会导致信用分配极其稀疏和延迟学习效率低下。GiGPO的革新GiGPO在GRPO的“组”episode-level group内部又引入了更细粒度的“内组”step-level group。算法会在这N条轨迹中自动识别那些在相同或相似状态s_t^i ≈ s_t^j下模型做出了不同动作选择a_t^i ≠ a_t^j的步骤。将这些“状态相似但动作不同”的步骤配对就形成了内组。对于内组中的每个动作GiGPO会计算一个更精细的“步骤级相对优势”。这个优势不仅考虑整个轨迹的回报还考虑了在相同状态下选择另一个动作的“机会成本”。这使得模型能更清晰地认识到“在状态S下选择动作A比选择动作B更好”即使两条轨迹的最终成败相同。5.2 GiGPO的优势与代价优势细粒度信用分配显著加速长视野任务的学习尤其是在需要多步推理的任务中。保持无价值函数和GRPO一样无需训练一个独立的价值网络Critic简化了训练流程避免了价值函数拟合不准带来的误差。计算开销不变内组的发现和优势计算是基于已有的轨迹数据不需要额外的环境交互或模型前向传播。因此其GPU内存占用和LLM推理成本与GRPO完全相同。代价与思考对探索的要求更高GiGPO依赖组内轨迹的多样性。如果所有轨迹在关键步骤都做出了相同的可能是次优的选择就无法形成有效的内组。因此需要确保策略有足够的探索性例如通过调节采样温度temperature。超参数敏感inner_group_size和判断状态“相似”的阈值在代码中可能体现为嵌入向量的余弦相似度需要根据具体任务进行调整。5.3 其他算法选型指南PPO最经典稳定的Actor-Critic算法。如果你追求训练稳定性或者任务奖励信号相对稠密、易于拟合价值函数PPO是个安全的选择。缺点是需额外训练Critic网络。GRPO如果你想要Critic-free的简洁性且任务视野不是特别长例如10步以内GRPO比GiGPO更简单更容易调试。RLOO/DAPO这些是GRPO的变体。RLOOLeave-One-Out通过排除自身来估计优势可能减少偏差。DAPO引入了动态采样和clip-higher技巧旨在提升样本效率。它们可以看作是介于GRPO和GiGPO之间的选择。何时选择GiGPO当你的任务具有长视野、稀疏奖励、且存在明显的关键决策点时GiGPO的优势最为明显。例如在ALFWorld中“寻找钥匙-打开抽屉-拿出苹果”这样的序列任务GiGPO能更好地将最终成功归因到“拿起钥匙”这个关键动作上。6. 高级功能与自定义开发当你跑通示例后下一步就是根据自己的需求定制框架。verl-agent的模块化设计让这变得可行。6.1 实现自定义记忆模块假设你想实现一个只保留最近3步交互并附带一个简单摘要的记忆模块。创建新文件在agent_system/memory/目录下创建my_window_memory.py。继承并实现from typing import List, Dict, Any from .memory import Memory class MyWindowMemory(Memory): def __init__(self, window_size: int 3): super().__init__() self.window_size window_size self.history: List[Dict[str, Any]] [] # 存储格式化的历史记录 def update(self, observation: str, action: str, reward: float, done: bool, info: Dict): # 将当前步信息存入历史 self.history.append({ “obs”: observation, “act”: action, “rew”: reward, “info”: info.get(‘step_summary’, ‘’) # 假设info里有步骤摘要 }) # 如果历史超过窗口大小移除最老的记录 if len(self.history) self.window_size: self.history.pop(0) def get_memory_text(self) - str: “”“返回格式化后的记忆文本”“” if not self.history: return “No previous steps.” memory_lines [] for i, record in enumerate(self.history): # 自定义格式化方式例如 memory_lines.append( f“Step -{len(self.history)-i}: Obs: {record[‘obs’][:50]}... | Act: {record[‘act’]} | Reward: {record[‘rew’]}” ) # 添加一个简单摘要这里只是示例实际可以用LLM生成 summary f“Recent {len(self.history)} steps focused on {self.history[-1].get(‘info’, ‘interaction’)}.” return summary “\n” “\n”.join(memory_lines) def reset(self): self.history.clear()在环境管理器中使用修改agent_system/environments/env_manager.py中对应环境的build_text_obs方法将默认的SimpleMemory替换为你的MyWindowMemory。6.2 添加一个新环境如果你想在一个自定义的Gym风格环境中训练智能体需要完成以下三步环境包在agent_system/environments/env_package/下创建你的环境目录例如my_env。实现标准的Gym接口reset(),step(action),render()等。确保step返回(observation, reward, done, truncated, info)五元组。提示词模板在agent_system/environments/prompts/下创建my_env.py定义一个函数返回用于构建每一步模型输入的提示词字符串。这个字符串可以包含占位符如{task_description},{current_observation},{memory}等。注册环境管理器在env_manager.py中仿照WebShopManager创建一个新的管理器类如MyEnvManager继承自EnvironmentManagerBase。你需要实现_setup_env初始化环境、_reset_env重置、_step_env执行动作等方法并重写build_text_obs方法来组合提示词、记忆和当前观察。最后在文件底部的ENV_REGISTRY字典中注册你的环境名和管理器类。6.3 使用LoRA进行轻量化训练对于大模型如7B、14B全参数训练成本高昂。verl-agent支持LoRA可以极大降低显存和计算需求。在配置文件中进行如下设置model: model_path: “Qwen/Qwen2.5-7B-Instruct” use_lora: true lora_r: 8 lora_alpha: 32 lora_dropout: 0.1 lora_target_modules: [“q_proj”, “k_proj”, “v_proj”, “o_proj”] # 通常作用于注意力层的投影矩阵训练完成后保存的检查点只包含LoRA权重。你可以使用peft库将其与基础模型合并得到完整的微调后模型。实操心得使用LoRA时学习率通常可以设得比全参数微调时稍高一点例如1e-5。同时由于可训练参数大幅减少模型可能更容易过拟合到当前的奖励函数上需要密切关注验证集上的表现。7. 常见问题排查与性能调优实录在实际使用中你一定会遇到各种问题。以下是我踩过的一些坑和解决方案。7.1 训练过程不稳定奖励曲线震荡剧烈可能原因1学习率过高。RL训练对学习率非常敏感。解决方案尝试将学习率降低一个数量级例如从5e-6降到5e-7并使用学习率预热warmup。可能原因2优势估计方差过大。这在GRPO/GiGPO中尤其常见因为优势估计依赖于组内轨迹回报的差异。解决方案增加env.rollout.n组大小例如从4增加到8或16。这能获得更稳定的回报分布降低方差。代价是每轮数据收集的计算量增加。可能原因3奖励尺度不合理。如果环境原始奖励值非常大如1000或非常小如0.001会导致梯度爆炸或消失。解决方案在环境管理器中对奖励进行归一化或缩放。例如在info中返回原始奖励但在step方法中返回一个缩放后的奖励给训练器。7.2 智能体策略没有改进成功率始终为零可能原因1探索不足。模型初始策略下智能体可能永远无法偶然触发获得正奖励的行为导致策略梯度始终为零。解决方案提高采样温度 (algorithm.gigpo.temperature或generation.temperature)例如从0.1提高到0.7让输出更多样。在训练初期混入一定比例的完全随机动作或基于规则的探索策略。使用课程学习Curriculum Learning从简单的任务变体开始训练。可能原因2任务指令或观察格式不对。模型无法理解环境在说什么。解决方案仔细检查build_text_obs方法构建的最终提示词。将其打印出来手动阅读看是否符合模型的指令遵循格式如Qwen的|im_start|system...。你可以在配置中设置log_level: DEBUG来查看每一步的输入输出。可能原因3最大步数 (max_steps) 设置过短。智能体还没执行到关键步骤就被强制终止了。解决方案分析任务合理设置max_steps。可以先运行一些随机策略的轨迹观察平均完成步数。7.3 显存溢出OOM可能原因1批次过大或序列过长。解决方案减小env.rollout.batch_size并行环境数和train.batch_size。检查记忆模块是否添加了过多历史导致输入序列过长。优化你的get_memory_text方法使其更精简。启用梯度累积 (gradient_accumulation_steps)在保持有效批次大小的同时减少瞬时显存。可能原因2未使用LoRA训练大模型。解决方案对7B及以上模型强烈建议开启LoRA训练。可能原因3VLM视觉语言模型输入图像分辨率过高。解决方案在环境管理器中对图像观察进行下采样例如将输入图像尺寸固定为224x224。7.4 训练速度慢瓶颈分析使用nvtop或nvidia-smi监控GPU利用率。如果利用率低瓶颈可能在CPU端环境模拟或数据加载。环境瓶颈如果环境模拟很慢如某些物理仿真增加env.rollout.batch_size可能不会提速反而会拖慢。解决方案尝试优化环境代码或使用更高效的环境实现。确保环境支持向量化操作。模型加载与通信如果使用多卡训练检查数据在CPU和GPU之间、GPU之间的传输是否成为瓶颈。解决方案确保数据预处理在GPU上进行或使用pin_memory加速数据加载。7.5 复现论文结果论文中的结果是在特定版本和环境下得到的。如果你无法复现请严格对照版本使用项目Release中与论文对应的代码版本、环境依赖版本和模型版本。检查随机种子在配置文件中设置固定的随机种子 (seed) 以保证可复现性。注意硬件差异即使是相同的随机种子在不同架构的GPU上如A100 vs H100由于浮点运算的细微差异也可能导致结果略有不同。这属于正常现象。这个框架的魅力在于它将前沿研究GiGPO与工程实践紧密结合提供了一个既可用于快速实验验证又具备足够灵活性进行深度定制的研究平台。从理解其“步独立”的设计思想开始到熟练配置各种环境再到根据任务特性调整算法和记忆模块每一步都充满了挑战和收获。希望这篇详尽的指南能帮助你绕过我踩过的那些坑更高效地探索LLM智能体强化学习的广阔天地。记住关键不是盲目跑代码而是理解数据在框架中的流动以及每个超参数背后所控制的权衡。