Skip to content

Supplement: Benchmarks and Case Studies

Agent training produces failures that a reward curve alone cannot explain: unstable updates, format collapse, unsupported claims, and context loss. Each failure needs a measurable diagnosis before the next training run can address it. This chapter therefore connects industrial training practice with evaluation, monitoring, failure attribution, and regression testing.

We begin with failure modes observed in production training systems. The second half turns those observations into benchmark choices, task-specific rubrics, and an evaluation pipeline.

Industrial Practice: Common Failure Modes and Fix Patterns

Agentic RL inherits the familiar problems of variance, exploration, and reward hacking. Tool calls and multi-turn interaction add more failure points because an early incorrect state can alter every later action.

Between 2025 and 2026, teams including Alibaba Tongyi, Moonshot, LinkedIn, and Bespoke Labs published lessons from agent training systems. The sections below organize those reports by failure scenario so that each observation leads to a concrete diagnostic and response.

Key point: Algorithm choice cannot compensate for inconsistent environments or unreliable data. Establish reproducibility and training stability before comparing RL objectives.

Scenario A: Data Collection and Environment Construction

Agent training begins with a stable, replayable interaction environment. Without one, two identical actions can produce different observations and rewards, so changes in the training curve cannot be attributed to the policy update.

Live APIs are not reproducible

If you train against a live search engine or a live external API, the same query can return different outputs over time. This breaks reproducibility and makes RL unstable because the mapping from action to observation to reward is no longer consistent across runs.

Moonshot AI noted during Kimi-Researcher training that the environment an agent faces is dynamic -- even with the same query, a search engine may return different results. They primarily used the REINFORCE algorithm in training and emphasized the importance of strictly on-policy data generation for training stability.

Controlled / synthetic environments

A viable alternative is building deterministic synthetic environments for controlled training.

Alibaba Tongyi (Tongyi DeepResearch) abandoned noisy, uncontrollable online APIs and built a synthetic training environment centered on an offline Wikipedia database and stable tool sandboxes.

Their approach included:

  1. Data and environment synthesis (WebShaper & AgentFounder): Since real web pages change frequently, causing inconsistent search results for the same query over time (which severely undermines the MDP assumptions of RL), they developed WebShaper to convert massive Wikipedia data into a static, structured offline search environment; and AgentFounder to automatically generate highly difficult (PhD-level) synthetic queries with reference answers. The determinism of this synthetic environment ensures that the action-to-reward mapping is absolutely stable across multiple rollouts.
  2. Asynchronous compute architecture (rLLM): The rollout phase of Agentic RL (interacting with the environment to generate action trajectories of dozens of steps) is extremely time-consuming. Using a traditional synchronous RL architecture (training and inference alternating on the same GPU pool) would leave training nodes (GPUs) idle for long periods due to environment interaction latency. Their rLLM (Ray-based LLM) asynchronous rollout service physically isolates inference from training: multiple worker nodes use high-throughput inference engines (like vLLM) to continuously interact with the environment, generate trajectories, and store them in a shared replay buffer, while dedicated trainer nodes (based on Megatron/FSDP) continuously sample from the buffer, compute gradients, and update the model.

Experiments proved that RL in a highly controlled, noise-free synthetic environment produces models whose generalization ability on the real internet comprehensively surpasses models trained with noisy human expert annotation data. The root cause: what the model truly needs to learn during RL is the general decision logic of "how to search, how to reflect and retry based on results," not overfitting to specific search results. Stable environment signals are the cornerstone of RL convergence.

Effectiveness of small-scale data

For researchers with limited resources, high-quality small-scale data can also achieve significant results.

Amazon Science verified the feasibility of "few-shot customization" on the complex AppWorld benchmark: instead of blindly collecting tens of thousands of noisy human interaction trajectories, they carefully constructed only 72 high-quality training samples (covering core tool-call patterns, dependencies, and retry logic for API errors). Through RL training, they successfully improved Qwen-2.5-32B's task completion rate from 39.2% to 72%, surpassing the then-strongest closed-source models Claude Sonnet 3.7/4.0.

This counterintuitive result reveals a core insight of modern Agentic RL: for base models with 32B+ parameters, they already possess strong world knowledge and logical reasoning capabilities from pre-training. At this point, RL's role is not "injecting new knowledge into the model" but "activating and aligning" the model's interaction paradigms and tool syntax for specific environments. As long as these 72 high-quality samples serve as "primers" that successfully trigger effective exploration, RL algorithms (like PPO/GRPO) can refine the policy through reward signals from environmental feedback during tens of thousands of self-play iterations. This proves that on models with adequate baseline capabilities, RL has extremely high data efficiency -- "small, high-quality data + RL self-exploration" far surpasses massive low-quality SFT data.

Scenario B: Gradient Explosion

After resolving data and environment preparation, gradient explosion at training startup is another common issue. Before investigating hyperparameters, first check the correctness of the underlying implementation.

Implementation differences between inference and training engines

Agentic RL training involves two phases: inference (Rollout) generates action sequences, and training (Backward) updates model weights. These phases are typically handled by different engines, and implementation differences between engines can cause gradient computation inconsistencies.

LinkedIn encountered gradient explosion and non-increasing rewards during RL training with GPT-OSS (an MoE architecture open-source model). Investigation revealed the root cause: Attention Sink parameter backward propagation was not implemented in the training framework. The inference engine (SGLang's Triton kernel) supported forward computation with Attention Sinks, but the training framework (FSDP's FlashAttention-v2) completely lacked corresponding support. They obtained the forward implementation from vLLM's FlashAttention branch and wrote custom backward propagation code for computing Sink parameter gradients. After fixing this issue, training stabilized.

Practical advice: When using complex model architectures, first validate the training pipeline on simple single-turn tasks (e.g., GSM8K) to confirm loss decreases normally before switching to multi-turn agent tasks.

Scenario C: Output Length Explosion and Format Collapse

This is one of the most common issues in Agentic RL training: instead of learning to use tools correctly, the model starts generating massive amounts of meaningless tokens, eventually degrading into repetitive garbage output. This phenomenon is called Format Collapse:

json
// Expected output format:
{"action": "search", "query": "AAPL stock"}

// After format collapse:
{"action": "searchsearchAAPL stockAAAAA"

Cause 1: Overly complex reward function design

Intuitively, researchers might design multi-dimensional reward signals: +1 for successful tool calls, +1 for correct output format, +5 for correct final answer. However, this fine-grained reward design can backfire.

Reward Hacking is the core issue. When the reward function includes multiple sub-items that the model can optimize independently, the model may find strategies that only satisfy some conditions while achieving high reward.

Bespoke Labs experiments showed that a composite reward function including tool-call count reward, format check reward, and correctness reward actually decreased training stability, likely due to reward hacking. They also observed continuously inflating output length that eventually degraded into meaningless garbage characters. Their final approach: keep only "was the task completed" as a single binary reward signal (1 if passing BFCL evaluation, 0 otherwise), removing all intermediate process reward items. Training stability significantly improved.

The logic behind this finding: binary outcome reward provides no "shortcuts" at intermediate steps -- the model must complete the overall task to receive positive reward, thus preventing opportunistic behavior targeting individual reward items.

Cause 2: Improper negative sample handling

Not all samples that fail the task are of equal quality. For example, a model may be truncated by the environment after reaching the maximum interaction steps without producing a final answer, but the preceding outputs may have been reasonable. Treating such samples indiscriminately as negative samples with penalties can damage the model's already-learned output capabilities.

Alibaba Tongyi observed that indiscriminately treating all failed trajectories as negative samples for penalty, after prolonged training, led to severe format collapse -- to avoid the overall penalty from task failure, the model started producing garbage or completely refusing to use tools (because doing more leads to more errors).

To address this long-horizon credit assignment challenge, they implemented two core designs in their customized On-policy GRPO algorithm:

  1. Token-level loss with Leave-one-out advantage estimation: Compared to traditional PPO which averages the entire trajectory's reward across every action, GRPO generates multiple candidate trajectories within a group and computes each action's relative advantage compared to other actions in the group, applying more fine-grained gradient updates at the token level, which significantly reduces reward estimation variance.
  2. Conservative negative filtering: Agent actions have strong causal sequentiality. In interactions spanning 30 steps, many trajectories ultimately fail (e.g., timeout or reaching maximum step truncation) often only because the last few steps had incorrect logical judgments, while the first 20 steps' chain-of-thought and tool-call formats were completely correct. If such truncated samples are forcefully given global negative rewards (e.g., -1), the RL optimizer "throws the baby out with the bathwater," incorrectly penalizing originally correct format outputs. Therefore, they selectively mask out such truncated samples from loss computation so they do not contribute negative gradients. This strategy effectively preserves the model's basic alignment capabilities and maintains long-term format output stability.

Cause 3: Improper KL divergence constraint configuration

In RLHF/GRPO, a KL penalty term is typically used to limit how far the current policy model deviates from the initial reference model. The purpose is to prevent the policy from straying too far during training, thus maintaining basic output quality.

This constraint needs to balance "allowing policy exploration" and "maintaining stability":

  • KL penalty too small: Insufficient constraint, policy may stray too far, leading to quality degradation.
  • KL penalty too large: Over-constraining, policy cannot learn new behaviors, limiting training effectiveness.

Bespoke Labs found during Qwen2.5-7B-Instruct training that setting KL penalty to 0 led to output degradation after about 300 steps. Their approach:

  1. Set a minimal KL weight (e.g., 0.001) to provide minimal constraint.
  2. Periodically update the reference model: Every certain number of steps (e.g., 100), copy the current policy model as the new reference model. This way, the KL constraint target dynamically adjusts with training progress, preventing the policy from being "anchored" to a distant initial state.

Output length control: Gamma-decay reward

To encourage the model to complete tasks in fewer steps, a step-decay-based reward mechanism can be introduced.

Moonshot proposed Gamma-decay Reward. When the model correctly completes a task, the reward decays exponentially with steps used:

where is total steps and is the current step. This means: for the same task, using fewer steps yields higher reward, guiding the model to learn more efficient execution.

Scenario D: Context Management in Long-Horizon Interactions

A key difference between Agentic RL and traditional RL is that interaction rounds can be very long. In literature search, code writing, debugging, and other complex tasks, interaction rounds may exceed 50, at which point the context window fills with historical information and the model may lose focus on the original task.

Moonshot's Kimi-Researcher introduced Context Management, a key engineering practice for addressing attention dilution and "Lost in the Middle" issues in long-horizon tasks.

In agent interactions spanning dozens of rounds, without control, redundant HTML tags from web pages and hundreds of lines of code execution logs would rapidly fill the model's context window of hundreds of thousands of tokens. As context length increases dramatically, the LLM's signal-to-noise ratio decreases significantly, causing the model to "forget" the original user requirement from round 1 when it reaches round 40.

Kimi introduced an independent context_manager mechanism. After each step, the system dynamically evaluates and compresses context:

  1. Preserve core logic (Working Memory): Keep the model's own chain-of-thought, historical actions, and key facts extracted from web pages in the core context area.
  2. Summarize or discard noise: Replace lengthy raw web pages with one-to-two-sentence summaries, or directly discard invalid search records that have proven to be dead ends.

Ablation experiments showed that enabling this mechanism not only avoided catastrophic forgetting but also extended safe interaction rounds per rollout to 50+, enabling the model to gather more clues and ultimately achieve significantly higher scores on complex research tasks.

Hallucinations and Factuality

After resolving training stability and output format issues, another concern is Agent Hallucination: the model may cite non-existent literature in search results, use incorrect API parameters, yet display inappropriate "confidence" in subsequent reasoning. Hallucinations in agent scenarios are more complex than in pure conversation because the model generates not only text but also actions.

Four types of Agent Hallucination

Tool selection hallucination. The model calls a non-existent tool, or forces a tool call when it should not. For example, when asked about weather information, the model calls execute_sql.

Parameter hallucination. Tool selection is correct, but parameters are wrong -- fabricating non-existent API endpoints, misspelling database names, or using incorrectly formatted parameter values. Most notably: parameter formats may look "reasonable" but actual values are fabricated.

Result hallucination. This is the most insidious type. The model calls the correct tool and receives real results, but introduces bias when interpreting results -- treating irrelevant information from search results as evidence supporting its argument, or ignoring content that contradicts its hypothesis.

Citation hallucination. The model claims "according to [literature/website]" to reach a conclusion, but the citation does not actually exist, or the cited content does not match the original. This is especially common in Deep Research Agents -- the model may fabricate paper titles, URLs, and statistics to make the output "look well-sourced."

Cascading Effects of Agent Hallucination

In pure dialogue, the consequence of hallucination is usually limited to providing wrong information. In agent scenarios, hallucinations can cascade across multiple turns and reinforce themselves:

  1. Turn 3: the model hallucinates a parameter and calls a nonexistent API parameter -> the call fails.
  2. Turn 4: the model fails to recognize the hallucination, instead assuming "this API is flawed" -> it switches to another tool.
  3. Turn 5: the new tool lacks a key capability -> the model fabricates a seemingly plausible conclusion.
  4. Final output: a report that looks complete on the surface but is built on hallucinated premises.

If the reward only measures the final output, a plausible fabrication may score higher than an honest expression of uncertainty. Training can then reinforce the fabrication. This is a design risk inferred from the reward objective; the industrial reports surveyed here do not yet establish its prevalence.

RL Training for Hallucination Penalty

Citation-aware scoring reward. CaRR[1] designs a fine-grained reward mechanism to guide the model in correctly citing evidence. The core idea is decomposing multi-hop questions into atomic fact statements (Rubrics), then computing reward through a three-step process: (1) check whether the model output identifies key entities; (2) extract URLs from the output, fetch web content, and judge whether each Rubric is supported by cited content; (3) verify through graph BFS whether Rubrics are logically connected to the final answer. The final reward is the ratio of satisfied and logically connected Rubrics to total Rubrics.

Tool result fidelity reward. Encourage the model to faithfully interpret tool-returned results. If the model's summary deviates from what the tool actually returned (detected via NLI models or cross-validation), apply penalty.

Uncertainty reward. Encourage the model to proactively express "need more information" or "this result is uncertain" when unsure, rather than fabricating answers.

A simplified reward can combine these checks while preserving the separate diagnostics:

python
def hallucination_aware_reward(answer, tool_results, citations):
    """Score fidelity to tool results and cited evidence."""
    claims = extract_atomic_claims(answer)
    supported = sum(
        claim_supported(claim, tool_results, citations)
        for claim in claims
    )
    unsupported = len(claims) - supported

    return {
        "reward": supported / max(len(claims), 1) - 0.5 * unsupported,
        "supported_claims": supported,
        "unsupported_claims": unsupported,
    }

Keeping the component counts is important. A single total reward cannot show whether a regression came from tool misuse, unsupported claims, or broken citations.

Verification-Based Hallucination Filtering

Besides penalizing hallucinations in the reward function, we can also filter them during inference through verification.

Self-RAG[2] proposes an adaptive retrieval plus self-evaluation framework. Unlike traditional RAG, which retrieves for every query, Self-RAG lets the model decide whether external retrieval is needed before generating each text segment by using special reflection tokens. If retrieval is needed, it retrieves relevant passages, generates continuations for each passage, scores the candidates with reflection tokens such as relevance, support, and usefulness, and then uses segmented beam search to select the best overall output.

CRITIC[3] proposes tool-assisted correction. After the model generates an initial answer, it actively calls external tools such as search engines or code executors to verify key claims, then produces structured critique from tool feedback. If the critique indicates that the answer is flawed, the model regenerates a corrected answer. This verify -> revise -> verify loop can iterate multiple times until the answer passes verification or reaches the maximum iteration count.

Multi-Tool Collaboration

Beyond the common scenarios above, using specific model architectures (like MoE) or training on smaller parameter models introduces additional issues.

MoE model routing uncertainty

MoE models (like Mixtral, DeepSeek-V3) are notable for lower inference costs, but their routing mechanism can undermine basic RL training assumptions.

Algorithms like PPO assume the model generating current data is the same model being trained (on-policy), which mathematically means the importance sampling ratio equals 1.

LinkedIn found during RL training with GPT-OSS that MoE models' gating network may select different experts for the same token across two forward passes, causing , breaking the on-policy assumption. During debugging, they attempted to force-align the two probabilities via old_log_prob = log_prob.detach() to verify this hypothesis. It should be noted that while this routing inconsistency is real, it was not the root cause of gradient explosion in their debugging -- the root cause was the missing Attention Sink backward propagation discussed above.

MoE load balancing

MoE models face not only routing consistency issues but also unbalanced expert loads leading to low GPU utilization. Different tokens may concentrate on a few "hot" experts, making the GPUs responsible for those experts bottlenecks while other GPUs remain idle.

Salesforce proposed Pipelined Synchronous RL in their SFR-RL system: all GPUs alternate between Rollout and Training phases rather than being permanently assigned to one phase. Additionally, for MoE models, they introduced Least-Loaded Expert Parallelism to optimize expert load balancing. The overall system improved memory efficiency by approximately 250x compared to VERL (FSDP + Context Parallelism), requiring only 16 H200 GPUs to train a 120B-parameter MoE model.

Reasoning capability ceiling of small models

RL's essence is eliciting existing model capabilities rather than injecting new knowledge. The model's baseline capability determines the upper bound of what RL can achieve.

Amazon Science's experiments showed: 32B parameter models benefited significantly from RL because the model itself could generate high-quality interaction trajectories (rollouts), forming a positive feedback loop. But smaller models face fundamental reasoning capability limitations, such as being unable to recognize unanswerable questions or extract answers from relevant context -- these capability gaps are difficult for RL training to compensate. For small models with insufficient baseline capabilities, the recommendation is to acquire capabilities through distillation from stronger models rather than simply increasing RL training intensity.

Phased training pipelines

Considering characteristics of different model scales, a more robust training strategy is to adopt a phased pipeline rather than direct RL training.

The industry currently has two parallel training paradigms regarding whether SFT is needed: SFT-RL paradigm and Pure-RL paradigm.

SFT-RL paradigm (mainstream path): Alibaba Tongyi designed a CPT -> SFT -> RL three-stage training pipeline for Tongyi DeepResearch. During pre-training (CPT), tool-call trajectories are incorporated as text; during SFT, human or high-quality synthetic data cultivates the model's basic reasoning and tool-use capabilities; finally, RL performs exploration and optimization. The core insight: for non-reasoning alignment scenarios (like complex API calls, long-horizon exploration), SFT/RM remains the most effective means for reducing exploration space and overcoming cold-start difficulty. If the model lacks basic tool-use formatting at the outset, direct RL training often gets lost in an enormous action space.

Pure-RL paradigm: DeepSeek-R1-Zero showed that a base model can be trained directly with large-scale RL when feedback is objectively verifiable, as in mathematics and executable code. The trained model developed longer reasoning traces, self-verification, and self-correction without an SFT cold start. This route reduces dependence on demonstration data, but it requires reliable rewards and an environment that resists reward hacking.

These two paradigms are not mutually exclusive in Agentic RL; researchers should choose the appropriate pipeline based on whether the environment provides fully deterministic objective rewards.

Practice Summary

The following table summarizes solutions for each issue:

IssueSolutionSource
Non-reproducible training environmentBuild deterministic synthetic environmentsAlibaba
Small-scale data customizationHigh-quality small data (e.g., 72 samples) combined with RL achieves significant resultsAmazon
Gradient explosion at training startCheck inference/training engine implementation consistency (e.g., Attention Sink backward)LinkedIn
Output degrades to repetitive garbageUse minimalist reward design (only reward task success/failure); filter overly long outputsBespoke Labs
Policy drifts from initial modelSet small KL penalty (e.g., 0.001); periodically set current model as new reference modelBespoke Labs
Low output efficiency (too many steps)Use Gamma-decay reward to encourage task completion in fewer stepsMoonshot
Format collapseUse conservative negative sample handling, exclude trajectories truncated without final answersAlibaba
Context overflow in long tasksIntroduce context management, proactively summarize or discard useless historyMoonshot
Low MoE training resource utilizationPipelined synchronous RL + Expert Parallelism; 16 H200s can train 120B MoESalesforce
MoE routing inconsistencyBe aware MoE routing non-determinism may break on-policy assumption; distinguish root cause from symptoms during debuggingLinkedIn
Poor small model training resultsImprove baseline capabilities through distillation before RL; use CPT -> SFT -> RL three-stage pipelineAmazon / Alibaba

References


This section covered common engineering issues in Agentic RL training and industrial solutions. Next, we move to the evaluation system: how to determine whether these training changes actually improved the agent.


Agentic Evaluation System and Benchmark Overview

Standard LLM evaluation is simple: give the model a question, it provides an answer, correct answers score points. MMLU tests common knowledge, GSM8K tests math, HumanEval tests code. The evaluation process is a "question -> answer -> judge" three-step cycle.

Agent evaluation is different. When you ask an agent to "help me fix this GitHub issue," it does not give you a direct answer. It reads code, locates the problem, writes a patch, runs tests, discovers test failures, revises the patch, and runs tests again. This is a multi-step, multi-tool, multi-turn interaction process. Evaluation must look not only at "is the final result correct" but also "is the intermediate process reasonable."

The gap between training metrics and real capability is also much larger than in standard LLMs. In standard RLHF, a rising reward curve usually means the model is improving. In Agentic RL, rising reward may only mean the model learned to hardcode test cases, pick the longest paragraphs from search results, or repeatedly call the same tool to farm points. These strategies all game high reward but have no practical value.

Evaluation in Agentic RL is therefore not a post-training wrap-up activity, but a feedback loop running throughout training. This section addresses three questions: what benchmarks measure agent capabilities, how to build automated evaluation pipelines, and how to feed evaluation results back into training to close the loop.

Evaluation Dimensions: Agent "Goodness" Is Not a Single Number

In standard LLM evaluation, whether a model is "good" can usually be summarized as a single score -- MMLU score, HumanEval pass@1, MT-Bench win rate. But agent behavior is multi-layered; a single score cannot capture everything.

Consider a concrete scenario. Ask an agent to "investigate a company's financial condition and write a report." Evaluating task completion quality requires examining at least three aspects:

  • Did it choose the right tools? Search when it should search, read PDFs when it should read PDFs, rather than using only one tool throughout.
  • Is its search strategy efficient? Did it find key information in 3 search rounds, or wander aimlessly for 20 rounds.
  • Is the final report's conclusion correct, data accurate, and citations reliable.

These three aspects correspond to three core dimensions of agentic evaluation:

DimensionWhat it evaluatesRepresentative benchmarks
Tool callingCan the model correctly call APIs/toolsBFCL, ACEBench, API-Bank
Task completionCan the agent complete end-to-end tasksSWE-bench, WebArena, tau-bench
General capabilityGeneral intelligent assistant levelGAIA, Toolathlon

Tool Calling Benchmarks

BFCL

BFCL (Berkeley Function Calling Leaderboard) is currently the most authoritative tool calling leaderboard, maintained by UC Berkeley's Gorilla team. It evaluates models' ability to correctly call functions in various scenarios -- simple functions, multi-function combinations, RESTful APIs, Java functions, etc. BFCL v3 contains 2,000+ test cases covering scenarios from single-tool to multi-tool, from simple parameters to nested objects.

BFCL evaluates in pure text: given function signatures and user requests, the model outputs structured function call JSON. No sandbox environment needed; low cost, suitable for rapid verification.

ACEBench

ACEBench evaluates tool-use capability at finer granularity. Evaluation is divided into three categories: Normal (basic calling), Special (advanced scenarios like parallel calling, long context), and Agent (multi-agent collaboration). ACEBench was accepted at EMNLP 2025 Findings and is one of the most comprehensive tool-use evaluations.

API-Bank

API-Bank provides 53 common API tools and 314 tool-use dialogues, focusing on evaluating the complete capability chain of API planning, retrieval, and invocation. Unlike BFCL's "given function signature, call it" approach, API-Bank is closer to real scenarios: the model needs to first find the correct API, then decide how to call it.

End-to-End Task Benchmarks

SWE-bench

SWE-bench evaluates code agents' ability to solve real GitHub issues. Given an open-source project's issue description, the agent must understand the codebase, locate the problem, and write a fix patch. The entire process has no human intervention. The agent decides which files to read, which code to modify, and which tests to run.

This is one of the hardest code agent evaluations. Top models (like Claude Opus) achieve only about 50% resolution rate. The complexity of real software engineering tasks far exceeds single-file code generation.

The current leaderboard is available at swebench.com.

WebArena

WebArena provides a real web environment for agents to perform tasks -- shopping on e-commerce sites, posting on forums, managing code repositories on GitLab. The agent needs to understand web page visual layout and DOM structure, executing click, input, and navigation operations.

WebArena's difficulty lies in the environment's dynamism and uncertainty. BFCL's function signatures are fixed, SWE-bench's codebase is at least static, but WebArena's web pages may change at any time.

tau-bench

tau-bench evaluates conversational agents' ability to collaborate with users to complete domain tasks. It simulates real scenarios like airline booking and e-commerce customer service. The agent must guide users to provide information, query databases, and execute operations.

The challenge lies in state maintenance and uncertainty handling. Users may give vague information ("I want a ticket to Shanghai" -- which day? which airport?), and the agent must progressively clarify, update state, and complete the task across multiple conversation rounds.

Comprehensive Capability Benchmarks

GAIA

GAIA (General AI Assistants Benchmark) is one of the most challenging general AI assistant evaluations, containing 450 questions requiring reasoning, multimodal understanding, tool use, web search, and other capabilities. GAIA is divided into three difficulty levels:

  • Level 1: No tools needed, pure reasoning suffices
  • Level 2: One to two tools needed
  • Level 3: Multi-step reasoning + multiple tools working together

Even top models perform far from saturation on Level 3.

See the GAIA leaderboard for current results.

Toolathlon

Toolathlon focuses on multi-tool, long-workflow evaluation, containing 108 hand-selected complex tasks, each averaging 20+ tool interactions. It evaluates not just "can you use tools" but "can you orchestrate complex workflows" -- coordinating state across multiple tools, handling dependencies, and recovering from failures.

Scenario-Specific Evaluation

The three dimensions above cover general agentic capability. Different types of agents also have their own evaluation standards. For a Deep Research Agent, for example, "good" means far more than final-answer correctness.

A Deep Research result needs to satisfy four layers at once:

LayerMeaningEvaluation method
Answer correctnessWhether the final conclusion is correctCompare with gold answer (Exact Match/F1)
Citation reliabilityWhether every claim is traceableURL reachability + content relevance
Process rigorWhether the reasoning chain is coherentStep-level PRM scoring
Execution efficiencyWhether the task is completed with few stepsNumber of interaction turns

Mainstream benchmarks include GAIA for real-world complex QA, Humanity's Last Exam for expert-level multidisciplinary questions, WebArena/Mind2Web for web operation success rate, and BFCL for tool/API call accuracy. See Deep Research Evaluation for more detail.

How to Choose Benchmarks?

Facing so many benchmarks, running all of them is neither realistic nor necessary. A practical selection path:

What do you want to evaluate?             Recommended Benchmark
|-- Basic function calling ability        -> BFCL
|-- Multi-scenario tool use               -> ACEBench
|-- Code fix ability                      -> SWE-bench
|-- Web operation ability                 -> WebArena
|-- Multi-turn conversation collaboration -> tau-bench
|-- General intelligent assistant level   -> GAIA / Toolathlon

Start with BFCL. It is the easiest to get started with, lowest evaluation cost (pure text evaluation, no sandbox needed), and can quickly verify the agent's basic tool-calling ability. If BFCL scores are not satisfactory, more complex benchmarks are pointless. Tool calling is the foundation of all agent capabilities.

Once basic capabilities meet the bar, use SWE-bench or WebArena to evaluate end-to-end task completion.

Building Your Own Evaluation

Existing benchmarks cover general capabilities. If your agent targets a specific domain -- legal consulting, medical diagnosis, financial analysis -- you may not find ready-made benchmarks. Then you need to build your own evaluation set.

Outcome Evaluation vs Process Evaluation

Standard LLM evaluation only looks at outcomes. Math answers correct gets points, code runs passes. But agent tasks are typically multi-step; looking only at the final result misses much information.

Outcome evaluation checks whether the final deliverable meets requirements. Process evaluation checks whether each step's decisions during task completion were reasonable.

Process evaluation is not an optional refinement. Berkeley RDI showed that mainstream agentic benchmarks can often be gamed to near-perfect scores without completing the intended task.[4] Without process evaluation, a benchmark may measure shortcut discovery instead of capability.

Breaking "Quality" into Quantifiable Dimensions

"Quality" itself is not quantifiable. But any agent task's quality can be decomposed into several quantifiable dimensions.

Quality DimensionCode AgentWeb AgentResearch Agent
CorrectnessPatch passes testsOperation results match expectationsCore conclusions match facts
CompletenessCovers all relevant filesCompletes all sub-stepsReport covers key information points
EfficiencyTotal interaction roundsOperation step countSearch count / total rounds
RobustnessHandles edge casesRecovers from page errorsCross-validation of conflicting info
Citations----Every claim has traceable source

Designing a Scoring Function

Combine the above dimensions into a scoring function. The simplest approach is weighted sum:

python
def evaluate_trajectory(trajectory, task):
    """Score an agent trajectory"""
    scores = {}

    # Correctness: automatic verification
    scores["correctness"] = verify_result(
        trajectory.final_answer, task["expected"]
    )

    # Efficiency: count interaction rounds
    max_turns = task.get("max_turns", 20)
    scores["efficiency"] = 1.0 - (trajectory.num_turns / max_turns)

    # Completeness: check key information point coverage
    scores["completeness"] = check_coverage(
        trajectory.final_answer, task["key_points"]
    )

    # Process quality: tool selection appropriateness per step
    scores["process"] = evaluate_process(trajectory.steps, task)

    # Weighted sum
    weights = {
        "correctness": 0.4,
        "completeness": 0.2,
        "efficiency": 0.15,
        "process": 0.25
    }

    total = sum(scores[k] * weights[k] for k in weights)
    return total, scores

Weight allocation reflects your emphasis on different dimensions. Code agents may weight correctness higher (0.5). Research agents may weight completeness and citations higher (0.25 each). The weights may also change as the policy improves: DR Tulu adjusts rubric weights so evaluation continues to target the model's current weaknesses.[5]

Process Evaluation Methods

Process evaluation is the key difference between agent evaluation and standard LLM evaluation. There are three common approaches, ordered from lowest cost to highest precision.

Statistics. Count total interaction turns, tool-call count, repeated action ratio, and similar metrics. This does not judge whether each step is "right," but it catches obvious inefficiency such as searching the same query five times.

python
def process_stats(trajectory):
    """Summarize observable properties of one trajectory."""
    tool_steps = [step for step in trajectory.steps if step.is_tool_call]
    return {
        "total_turns": len(trajectory.steps),
        "tool_calls": len(tool_steps),
        "repeat_actions": count_repeats(trajectory.steps),
        "distinct_tools": len({step.tool_name for step in tool_steps}),
    }

Step-level rule checks. Define process rules for the task and check whether the agent violates them. Examples include forbidding three identical tool calls in a row, requiring search results to be used within a few steps, or requiring at least one search before final answering in a research task.

python
def check_process_rules(trajectory, rules):
    """Return the names of violated process rules."""
    return [rule.name for rule in rules if not rule.check(trajectory)]

Step-level LLM scoring. Use an LLM to evaluate whether each trajectory step is reasonable. This is essentially the evaluation-side counterpart of a Process Reward Model: during training, PRM provides learning signals; during evaluation, it provides quality assessment.

The judge should see the task, the state before the action, the available tools, and the action itself. A useful rubric asks whether the step advances the task, whether the tool and arguments are appropriate, and whether a safer or more efficient action was available. The score should cite evidence from the trajectory rather than rely on a general impression.

Agent-as-a-Judge[6] extends this idea by giving the evaluator its own tools. If the evaluated agent claims that a URL supports a fact, the judge can open the URL instead of rating the prose alone. This is more expensive than static LLM scoring but can verify claims that depend on external state.

Where Do Tasks Come From?

The scoring method answers "how do we judge quality," but an evaluation set also needs good tasks. A survey of 78 agentic benchmarks found ambiguity and evaluation flaws serious enough to overstate capability; its Agentic Benchmark Checklist provides a useful design review.[7] A practical approach is to extract tasks from real user needs: user feedback, support tickets, failure logs, and production traces, as Anthropic recommends.[8] These tasks have ecological validity because they come from scenarios users actually care about.

Another direction is automatic task synthesis. TaskCraft[9] starts from simple, verifiable atomic tasks, then increases depth by adding steps and breadth by adding tools and constraints. APIGen-MT[10] instead simulates multi-turn interaction between an agent and a user. In both cases, each generated task must be validated so that it remains solvable rather than becoming an ambiguous prompt.

A second useful source is failure-driven synthesis. HardGen[11] runs a baseline agent, collects failed trajectories, and extracts the tool dependencies that caused trouble. New tasks then instantiate those dependency patterns with different parameters. Evol-Instruct[12] provides operators for deepening, broadening, and constraining instructions; Tag-Evol[13] adds explicit domain, difficulty, and skill tags. Executing each generated task in the environment closes the loop: unsolvable or incorrectly specified tasks are discarded before they enter the evaluation set.

Web tutorials offer another source of successful trajectories. AgentTrek[14] extracts ordered action sequences from tutorials and replays them in the target environment. Firefly[15] grounds tool-use data in real APIs, while WebShaper[16] builds a reproducible offline search environment. Only successful, reproducible executions should become evaluation tasks.

How to Evaluate Open-Ended Tasks?

Many agent tasks are open-ended: writing a report, doing research, or giving advice. These tasks do not have a single correct answer.

A practical strategy is hybrid scoring: deterministic checks for daily regression, LLM-as-Judge for periodic quality evaluation, and manual spot-checking for final acceptance.[8:1] JADE[17] makes open-ended evaluation more explicit by first activating task-specific expert skills and then verifying concrete claims. It is also useful to maintain two evaluation sets: a capability set with hard tasks that the model does not need to pass completely, and a regression set with basic tasks that the model should pass consistently.

Example: Building an Evaluation for a Frontend Page-Generation Agent

Suppose you train a frontend page-generation agent. Given a requirement such as "build a login page supporting phone and email login," the agent must plan the page structure, choose components, write HTML/CSS/JS, and deliver a runnable page.

There is no single gold answer. The same login-page requirement can be satisfied by many designs. A useful evaluation decomposes quality into functional correctness, visual match, code quality, responsiveness, accessibility, and performance. Functional correctness can be checked with Playwright tests; responsiveness can be checked with screenshots at multiple viewports; accessibility can use Lighthouse or axe; visual quality often needs LLM-as-Judge plus human spot checks.

Define the Task Contract

An open-ended task still needs explicit acceptance criteria. The contract below does not prescribe one visual design; it states which user-visible behaviors must exist.

python
task = {
    "id": "frontend_001",
    "prompt": (
        "Build a login page with phone and email login, "
        "a forgot-password link, and a registration link."
    ),
    "difficulty": "medium",
    "checklist": [
        "phone input is present",
        "email input is present",
        "password input is present",
        "login button responds to a click",
        "forgot-password link is present",
        "registration link is present",
    ],
    "style_reference": "light background with a blue primary color",
    "max_turns": 15,
}

The task set should cover a difficulty ladder. A static landing page is a simple task; an interactive form is an intermediate task; a dashboard with nested components, filtering, and responsive behavior is harder. A first evaluation set might contain 20–30 tasks at each level.

Evaluate the Result in Layers

The first two layers should be deterministic. If the page does not load or the required interaction fails, visual polish should not compensate for it.

python
class FrontendEvalPipeline:
    """Evaluate a generated page from executable checks to judgment."""

    def __init__(self, judge):
        self.judge = judge

    def evaluate(self, task, trajectory):
        code = trajectory.final_answer
        screenshot = take_screenshot(code)

        scores = {
            "runnable": check_page_loads(code),
            "functionality": run_playwright_checks(
                code, task["checklist"]
            ),
            "visual": self.judge.score(
                task["prompt"], screenshot, VISUAL_RUBRIC
            ),
            "code_quality": 0.5 * run_eslint(code)
            + 0.5 * self.judge.score(code, CODE_RUBRIC),
            "process": evaluate_frontend_process(trajectory, task),
        }
        return aggregate(scores), scores

This produces five separate measurements:

  • Runnable: the browser loads the page without a JavaScript error.
  • Functionality: Playwright can complete each required interaction.
  • Visual quality: the rendered page matches the stated layout and style.
  • Code quality: static checks and a rubric assess maintainability.
  • Process quality: the trajectory uses planning, preview, and incremental repair effectively.

The aggregate score is useful for ranking checkpoints, but the component scores are the evidence needed for diagnosis.

Make Visual Evaluation Reproducible

A single prompt asking whether a page “looks good” is unstable. Design2Code[18] separates page structure, text, position, color, and semantic similarity instead of collapsing them into one opaque score. When a reference image is available, compare several measurable properties:

python
def visual_metrics(generated, reference):
    """Return diagnostic visual metrics, not one opaque score."""
    return {
        "block_match": compute_block_match(generated, reference),
        "position": compute_position_alignment(generated, reference),
        "color": compute_ciede2000(generated, reference),
        "semantic": clip_image_similarity(generated, reference),
    }

The metrics answer different questions. Block matching checks page regions, position alignment checks geometry, CIEDE2000 checks perceptual color difference, and CLIP checks broad visual semantics. Reporting them separately reveals whether a page has the right structure but the wrong colors, or the right theme but missing content.

When no reference image exists, replace a continuous beauty score with a checklist:

text
For each item, return PASS or FAIL and cite visible evidence.

1. The form is placed at a clear visual focus.
2. Phone, email, and password controls are distinguishable.
3. At least one primary action button is visible.
4. Text and controls do not overlap.
5. Inputs and buttons have visible boundaries and labels.
6. The layout remains usable at 390 px and 1440 px widths.

Discrete checks reduce judge variance and make disagreements easier to review. This calibration matters: Omni-I2C found that pixel metrics correlate weakly with human judgment, while an LMM judge correlates more strongly but still disagrees on a meaningful fraction of cases.[19] FullFront likewise shows a large gap between model and human accuracy on webpage perception.[20] A small sample should therefore still be scored by humans periodically. If judge–human agreement falls below the release threshold, revise the rubric before comparing more checkpoints.

Evaluate How the Agent Worked

Two agents can produce the same runnable page through very different trajectories. One may plan, build a skeleton, preview, and repair a local error. Another may replace the entire file repeatedly until one attempt happens to pass. Outcome checks treat them equally, but the second process is slower and less reliable.

Start with observable statistics:

python
def frontend_process_stats(trajectory):
    """Measure editing and verification behavior."""
    rewrites = count_full_rewrites(trajectory)
    edits = count_incremental_edits(trajectory)
    return {
        "turns": len(trajectory.steps),
        "full_rewrites": rewrites,
        "incremental_edits": edits,
        "previews": count_tool_calls(trajectory, "browser_preview"),
        "rewrite_ratio": rewrites / max(rewrites + edits, 1),
    }

A high rewrite ratio indicates that the agent is replacing work instead of locating the failing component. It is a diagnostic signal rather than proof of a bad solution, so it should be combined with explicit process rules:

python
FRONTEND_PROCESS_RULES = [
    Rule("plan_before_large_edit", plan_precedes_first_large_edit),
    Rule("preview_after_edit", preview_within_three_steps),
    Rule("no_rewrite_loop", no_consecutive_full_rewrites),
    Rule("reasonable_size", generated_code_within_task_budget),
]

Rules catch known failure patterns cheaply. For deeper diagnosis, a judge can inspect the state before and after each step and ask whether the action advanced a checklist item, targeted the observed error, or introduced a regression.

AgentPRM frames step quality through promise and progress signals.[21] A deterministic approximation of progress is the change in passed checks:

python
def step_progress(trajectory, checks):
    deltas = []
    for index in range(len(trajectory.steps)):
        before = count_passed(checks, trajectory.code_at(index))
        after = count_passed(checks, trajectory.code_at(index + 1))
        deltas.append(after - before)

    return {
        "net_progress": sum(deltas),
        "wasted_steps": sum(delta <= 0 for delta in deltas),
        "per_step": deltas,
    }

This measure is imperfect: a refactor may enable later progress without immediately passing a new check. It is most useful for finding trajectories that make no observable progress for many consecutive steps.

Check for Evaluation Exploits

An agent can satisfy a naive DOM check without producing a usable page. For example, it may add invisible required elements or hard-code values from the test fixture. Add explicit exploit checks before trusting a high score:

python
FRONTEND_EXPLOIT_RULES = [
    Rule("no_invisible_required_elements", no_hidden_required_controls),
    Rule("no_hardcoded_fixture_data", no_test_fixture_literals),
    Rule("no_suspicious_css_overrides", no_hidden_or_offscreen_content),
]

Process scores should remain secondary to executable outcomes. AdaRubric shows why the process dimensions should depend on the task rather than use one fixed checklist.[22] A practical weighting gives runnable behavior and functional checks most of the score, while process metrics explain failures and contribute a smaller fraction. Iterative reward-calibration results warn that a poorly calibrated dense reward can underperform a sparse outcome reward.[23]

The exploit rules can also be monitored as a separate signal. METR reports strong reward-hacking detection from a dedicated monitor; the corresponding engineering lesson is to keep exploit detection outside the policy's main reward whenever possible.[24] Visual differences may also become a training signal: VisRefiner uses rendered screenshot differences to train screenshot-to-code generation.[25]

Calibrate and Freeze a Regression Set

Run the initial task set with the untrained or pre-RL baseline. If more than 90% of simple tasks already pass, raise their interaction requirements. If fewer than 10% of hard tasks even load, split them into smaller tasks before using them to compare training runs.

Select a subset of tasks that the baseline reliably passes and freeze it as the regression set. Run deterministic layers on every checkpoint, visual and judge-based layers periodically, and human review before release. A new checkpoint should improve the capability set without losing tasks in the regression set.

Evaluation System Design

Pipeline Architecture

A complete agent evaluation pipeline contains five components:

Mermaid diagram

The task set is a JSON configuration file where each task specifies prompt, expected answer, verification method, and environment initialization parameters. Environment initialization creates an independent sandbox for each task.

python
class AgentEvaluationPipeline:
    """Agent evaluation pipeline"""

    def __init__(self, sandbox, judge_model):
        self.sandbox = sandbox      # Docker sandbox
        self.judge = judge_model    # LLM-as-Judge

    def run_evaluation(self, agent, task_set):
        """Run complete evaluation"""
        results = []

        for task in task_set:
            env = self.sandbox.create_isolated_env(task.get("setup", {}))
            trajectory = agent.run(
                task["prompt"], env,
                max_turns=task.get("max_turns", 20)
            )

            if task.get("verify_type") == "exact_match":
                passed = (
                    trajectory.final_answer.strip()
                    == task["expected_answer"].strip()
                )
            elif task.get("verify_type") == "execution":
                passed = env.execute(
                    task["verify_script"], trajectory.final_answer
                )
            elif task.get("verify_type") == "llm_judge":
                passed = self.judge.evaluate(
                    task["prompt"], trajectory.final_answer,
                    task["rubric"]
                )
            else:
                passed = False

            results.append({
                "task_id": task["id"],
                "passed": passed,
                "turns": trajectory.num_turns,
                "tool_calls": trajectory.tool_calls,
                "final_answer": trajectory.final_answer
            })

        return results

Regression Testing

Agent capabilities are interrelated. Fixing one bug may introduce new regressions: the model learns better search strategies for code tasks but forgets how to handle simple function calls. Every evaluation needs comparison against baseline.

python
def regression_test(self, agent, baseline_results, task_set):
    """Regression test: new model cannot regress on old capabilities"""
    new_results = self.run_evaluation(agent, task_set)

    regressions = []
    for old, new in zip(baseline_results, new_results):
        if old["passed"] and not new["passed"]:
            regressions.append({
                "task_id": old["task_id"],
                "old_answer": old["final_answer"],
                "new_answer": new["final_answer"]
            })

    if regressions:
        print(f"Found {len(regressions)} regressions!")
    return regressions

LLM-as-Judge and Rubrics

For tasks that cannot be verified with rules, such as open-ended QA, report quality, or dialogue naturalness, LLM-as-Judge is often necessary. The key is designing reproducible rubrics:

  • Separate dimensions instead of asking for one overall score.
  • Define what each score level means.
  • Require evidence from the output or trajectory.
  • Keep the judge prompt stable across checkpoints.
  • Use deterministic checks whenever they are available.

In practice, the three verification methods are combined. Deterministic checks run frequently for regression. LLM-as-Judge runs periodically for broader quality assessment. Manual review is reserved for final acceptance before release.

Evaluation-Driven Training Improvement

The ultimate purpose of evaluation is not just scoring, but feeding evaluation results back into the training loop to form a continuous improvement cycle:

Use a concrete example. Suppose your Code Agent's pass rate on SWE-bench is stuck at 35%.

Collect failure cases. From SWE-bench's 65% failed tasks, stratified sample 100 by error type.

Attribution analysis. Examine each failure case and classify by error cause. You might find: 40% are "located wrong file," 30% are "patch syntax errors," 30% are "misunderstood requirements." This distribution directly tells you what to do next.

Targeted synthesis. For the most common error type, use trajectory synthesis methods to generate "correctly locating" training data. The synthetic data reinforces "understanding code structure -> locating relevant files" capability.

Training improvement. Use the new data for a round of GRPO/PPO training.

Regression verification. Re-run SWE-bench, confirming two things: whether pass rate improved (expected increase from 35%), and whether previously passing cases regressed.

Thought question: If your agent scores 95 on BFCL but only 15% on SWE-bench, what does this indicate?

This indicates the agent's basic tool-calling skills are fine, but it lacks end-to-end task planning and execution capability. BFCL tests "given explicit function signatures and user requests, can you output the correct call," while SWE-bench tests "given a vague issue description, can you plan your own approach, understand the codebase, locate the problem, and write a fix." The former is mechanical operation; the latter requires planning, reasoning, and code understanding.

Improvement direction: Don't keep spending effort on tool calling; instead, strengthen the agent's planning capability and code understanding. Attribution analysis from evaluation will point directly to these directions.

References


References
  1. Zhang J, Lv X, Feng L, Hou L, Li J. "Chaining the Evidence: Robust Reinforcement Learning for Deep Search Agents with Citation-Aware Rubric Rewards." 2026. ↩︎

  2. Asai A, et al. "Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection." ICLR 2024. ↩︎

  3. Gou Z, et al. "CRITIC: Large Language Models Can Self-Correct with Tool-Interactive Critiquing." ICLR 2024. ↩︎

  4. Berkeley RDI. "Trustworthy Benchmarks for Contamination." 2025. ↩︎

  5. Allen AI. "DR Tulu: Reinforcement Learning with Evolving Rubrics." 2025. ↩︎

  6. Zhuge M, et al. "Agent-as-a-Judge: Evaluate Agents with Agents." ICML 2025. ↩︎

  7. Zhu J, et al. "Establishing Best Practices for Building Rigorous Agentic Benchmarks." NeurIPS 2025. ↩︎

  8. Anthropic Engineering. "Demystifying Evals for AI Agents." 2025. ↩︎ ↩︎

  9. Shi D, Cao J, Chen Q, et al. "TaskCraft: Automated Generation of Agentic Tasks." ICLR 2026. ↩︎

  10. Prabhakar A, Liu Z, Zhu M, et al. "Agentic Pipeline for Multi-Turn Data Generation." NeurIPS 2025. ↩︎

  11. Hao B, et al. "From Failure to Mastery: Generating Hard Samples for Tool-use Agents." 2026. ↩︎

  12. Xu C, et al. "WizardLM: Empowering Large Language Models to Follow Complex Instructions." ICLR 2024. ↩︎

  13. Wang Y, Zhou S, Guo C, Zhu Q. "Tag-Evol: Achieving Efficient Instruction Evolving via Tag Injection." 2025. ↩︎

  14. Xu Y, Lu D, Shen Z, et al. "AgentTrek: Agent Trajectory Synthesis via Guiding Replay with Web Tutorials." ICLR 2025 Spotlight. ↩︎

  15. Lu Y, et al. "Firefly: Illuminating Large-Scale Verified Tool-Call Data Generation from Real APIs." 2026. ↩︎

  16. Tao Z, et al. "WebShaper: Agentically Data Synthesizing via Information-Seeking Formalization." 2025. ↩︎

  17. Lin L, Liu J, Yang T, et al. "JADE: Expert-Grounded Dynamic Evaluation." 2026. ↩︎

  18. Si C, et al. "Design2Code: How Far Are We from Automating Front-End Engineering?." NAACL 2025. ↩︎

  19. Zhou J, Zhang C, Feng X, et al. "Omni-I2C: A Holistic Benchmark for Image-to-Code." 2026. ↩︎

  20. Sun H, Wang H W, Gu J, Li L, Cheng Y. "FullFront: Benchmarking MLLMs Across the Full Front-End Engineering Workflow." 2025. ↩︎

  21. Xi Z, et al. "AgentPRM: Process Reward Models for LLM Agents via Step-Wise Promise and Progress." 2025. ↩︎

  22. Ding L. "AdaRubric: Task-Adaptive Rubrics for LLM Agent Evaluation." 2026. ↩︎

  23. Modecrua W, et al. "Iterative Reward Calibration for Multi-Turn Agent RL." 2026. ↩︎

  24. METR. "MALT: Monitoring Agents for Reward Hacking." 2025. ↩︎

  25. Deng J, Yao K, Zhang L. "VisRefiner: Learning from Visual Differences for Screenshot-to-Code Generation." 2026. ↩︎

Hands-on Modern Reinforcement Learning