Add support for verl 0.6.0 (#246)

This commit is contained in:
Zhiyuan He
2025-10-31 15:30:38 +08:00
committed by GitHub
parent 496e793f0b
commit a02e1b91d9
11 changed files with 217 additions and 40 deletions
+4
View File
@@ -54,6 +54,10 @@ jobs:
run: |
uv sync --frozen --no-default-groups --extra apo --extra verl \
--group dev --group experiment --group agents --group torch-gpu-${{ matrix.setup-script }}
- name: Override VERL (stable)
run: |
uv pip install verl==0.5.0
if: matrix.setup-script == 'stable'
- name: Freeze dependencies
run: |
set -ex
@@ -99,6 +99,8 @@ class VERL(Algorithm):
# Merge your dict overrides
override_conf = OmegaConf.create(config)
# Allow adding new fields
OmegaConf.set_struct(base_cfg, False)
self.config = OmegaConf.merge(base_cfg, override_conf)
def run(
+11 -14
View File
@@ -28,6 +28,12 @@ _original_handle_chat_attributes: Callable[..., Any] | None = None
_original_handle_response: Callable[..., Any] | None = None
def _unwrap_legacy_response(response: Any) -> Any:
if hasattr(response, "parse") and callable(response.parse):
return response.parse()
return response
def _patch_new_agentops():
import agentops.instrumentation.providers.openai.stream_wrapper
import agentops.instrumentation.providers.openai.wrappers.chat
@@ -44,6 +50,11 @@ def _patch_new_agentops():
@no_type_check
def _handle_chat_attributes_with_tokens(args=None, kwargs=None, return_value=None, **kws): # type: ignore
attributes = _original_handle_chat_attributes(args=args, kwargs=kwargs, return_value=return_value, **kws)
# In some cases, response is a openai._legacy_response.LegacyAPIResponse (e.g., LiteLLM, or LangChain),
# This is created by client.with_raw_response.create()
return_value = _unwrap_legacy_response(return_value)
if (
return_value is not None
and hasattr(return_value, "prompt_token_ids")
@@ -89,20 +100,6 @@ def _patch_new_agentops():
[logprob.model_dump() for logprob in first_choice.logprobs.refusal]
)
# For LiteLLM, response is a openai._legacy_response.LegacyAPIResponse
if (
return_value is not None
and hasattr(return_value, "http_response")
and return_value.http_response is not None
and hasattr(return_value.http_response, "json")
):
json_data = return_value.http_response.json()
if isinstance(json_data, dict):
if json_data.get("prompt_token_ids") is not None:
attributes["prompt_token_ids"] = list(json_data["prompt_token_ids"])
if json_data.get("response_token_ids") is not None:
attributes["response_token_ids"] = list(json_data["response_token_ids"][0])
return attributes
agentops.instrumentation.providers.openai.wrappers.chat.handle_chat_attributes = _handle_chat_attributes_with_tokens
+9 -1
View File
@@ -2,10 +2,12 @@
# type: ignore
from importlib.metadata import version
from typing import Any
import hydra
import ray
from packaging import version as packaging_version
from verl.trainer.main_ppo import create_rl_sampler
from verl.trainer.ppo.reward import load_reward_manager
@@ -39,11 +41,17 @@ def run_ppo(
) -> None:
if not ray.is_initialized():
# this is for local ray cluster
try:
# verl >= 0.6.0
num_cpus = config.ray_kwargs.ray_init.num_cpus
except AttributeError:
# verl < 0.6.0
num_cpus = config.ray_init.num_cpus
ray.init(
runtime_env={
"env_vars": {"TOKENIZERS_PARALLELISM": "true", "NCCL_DEBUG": "WARN", "VLLM_LOGGING_LEVEL": "WARN"}
},
num_cpus=config.ray_init.num_cpus,
num_cpus=num_cpus,
)
runner = TaskRunner.remote()
+1 -1
View File
@@ -32,7 +32,7 @@ pip install agentlightning[verl]
!!! note
The resource type created by [VERL][agentlightning.algorithm.verl.VERL] is actually a [ProxyLLM][agentlightning.ProxyLLM], a subclass of the [LLM][agentlightning.LLM] type. This object contains a **URL template** provided by [VERL][agentlightning.algorithm.verl.VERL], with placeholders for rollout and attempt IDs. When a rollout begins on the agent side, the framework uses the current `rollout_id` and `attempt_id` to format this template, generating a final, unique endpoint URL. This URL points to [VERL][agentlightning.algorithm.verl.VERL]'s internal proxy, allowing it to intercept and log all traffic for that specific attempt, for tracing and load balancing purposes. For agents created with the `@rollout` decorator, this resolution of the template is handled automatically ("auto-stripped"). Class-based agents will need to manually resolve the `ProxyLLM` using the rollout context.
The resource type created by [VERL][agentlightning.algorithm.verl.VERL] is actually a [ProxyLLM][agentlightning.ProxyLLM], a subclass of the [LLM][agentlightning.LLM] type. This object contains a **URL template** provided by [VERL][agentlightning.algorithm.verl.VERL], with placeholders for rollout and attempt IDs. When a rollout begins on the agent side, the framework uses the current `rollout_id` and `attempt_id` to format this template, generating a final, unique endpoint URL. This URL points to [VERL][agentlightning.algorithm.verl.VERL]'s internal proxy, allowing it to intercept and log all traffic for that specific attempt, for tracing and load balancing purposes. For agents created with the `@rollout` decorator, this resolution of the template is handled automatically ("auto-stripped"). Class-based agents will need to manually resolve the [`ProxyLLM`][agentlightning.ProxyLLM] using the rollout context.
```python
proxy_llm = resources["main_llm"]
+1 -1
View File
@@ -264,7 +264,7 @@ dev_data = pd.read_parquet("data/test_dev_500.parquet").to_dict("records")[:10]
trainer.dev(agent, dev_dataset=dev_data)
```
Run this in a Python session or adapt your script to include a `--dev` flag. Once the spans appear healthy and the rewards are non-zero, switch back to [`trainer.fit(...)`][agentlightning.Trainer.fit] for full RL training.
Run this in a Python session or adapt your script to include a `--dev` flag. Once the spans appear healthy and the rewards are non-zero, switch back to [`trainer.fit(...)`][agentlightning.Trainer.fit] for full RL training. See the [debugging tutorial](../tutorials/debug.md) for more tips on how to debug the agent.
## Running the Sample Code
+42
View File
@@ -66,6 +66,48 @@ Swap in an [`AgentOpsTracer`][agentlightning.AgentOpsTracer] instead of [`OtelTr
You can also call [`Runner.step`][agentlightning.Runner.step] to inject ad-hoc rollouts into a running store being used by another algorithm, so that the rollouts can be consumed by the algorithms. This is very recently known as the paradigm of ["online RL"](https://cursor.com/blog/tab-rl). At the moment, no algorithm in the [algorithm zoo](../algorithm-zoo/index.md) consumes externally generated rollouts, but the data flow is available there if you need it.
## Debug with LLM Proxy
If you are dealing with LLM optimization like Reinforcement Learning, we generally recommend using an online stable LLM service for your debugging purposes, like `openai/gpt-4.1-nano`. After the debugging is done, you can switch to a local training endpoint.
However, if you want to use a local LLM features like [getting the token IDs](../deep-dive/serving-llm.md), you can also manually start a local vLLM server by:
```bash
vllm serve Qwen/Qwen2.5-0.5B-Instruct --port 8080
```
Then start the LLM proxy via the following script:
```python
import agentlightning as agl
llm_proxy = agl.LLMProxy(
port=8081,
model_list=[
{
"model_name": "Qwen/Qwen2.5-0.5B-Instruct",
"litellm_params": {
"model": "hosted_vllm/Qwen/Qwen2.5-0.5B-Instruct",
"api_base": "http://localhost:8080/v1",
},
}
],
store=agl.InMemoryLightningStore(),
)
llm_proxy.start()
time.sleep(1000000)
```
You can now use the LLM proxy by specifying environment variables:
```bash
export OPENAI_API_BASE=http://localhost:8081/v1
export OPENAI_API_KEY=dummy
```
You might see warnings about `Missing or invalid rollout_id, attempt_id, or sequence_id` in the LLM proxy logs. This is fine because you don't have a rollout and attempt yet when you are debugging. When you started the training, the algorithm will create the rollouts for you and the warnings will go away.
## Hook into Runner's Lifecycle
[`Runner.run_context`][agentlightning.Runner.run_context] accepts a `hooks` argument so you can observe or augment lifecycle events without editing your agent. Hooks subclass [`Hook`][agentlightning.Hook] and can respond to four asynchronous callbacks: [`on_trace_start`][agentlightning.Hook.on_trace_start], [`on_rollout_start`][agentlightning.Hook.on_rollout_start], [`on_rollout_end`][agentlightning.Hook.on_rollout_end], and [`on_trace_end`][agentlightning.Hook.on_trace_end]. This is useful for:
+8 -1
View File
@@ -40,7 +40,7 @@ import agentlightning as agl
def verl_default_config() -> Dict[str, Any]:
return {
config = {
"algorithm": {
"adv_estimator": "grpo",
"use_kl_in_reward": False,
@@ -58,6 +58,12 @@ def verl_default_config() -> Dict[str, Any]:
"multi_turn": {"format": "hermes"},
"name": "vllm",
"gpu_memory_utilization": 0.6,
"engine_kwargs": {
"vllm": {
"enable_auto_tool_choice": True,
"tool_call_parser": "hermes",
}
},
},
"actor": {
"ppo_mini_batch_size": 32,
@@ -96,6 +102,7 @@ def verl_default_config() -> Dict[str, Any]:
"total_epochs": 2,
},
}
return config
def train(
+7
View File
@@ -52,6 +52,12 @@ RL_TRAINING_CONFIG: Dict[str, Any] = {
"multi_turn": {"format": "hermes"},
"name": "vllm",
"gpu_memory_utilization": 0.8,
"engine_kwargs": {
"vllm": {
"enable_auto_tool_choice": True,
"tool_call_parser": "hermes",
}
},
},
"actor": {
"ppo_mini_batch_size": 32,
@@ -139,6 +145,7 @@ def config_train_llama() -> Dict[str, Any]:
config = deepcopy(RL_TRAINING_CONFIG)
config["actor_rollout_ref"]["rollout"]["multi_turn"]["format"] = "llama3_json"
config["actor_rollout_ref"]["rollout"]["engine_kwargs"]["vllm"]["tool_call_parser"] = "llama3_json"
config["actor_rollout_ref"]["model"]["path"] = "meta-llama/Llama-3.2-1B-Instruct"
return config
+4 -2
View File
@@ -30,8 +30,8 @@ apo = [
# It's not recommended to use agentlightning[verl] to install VERL and its dependencies.
# though it's listed here for completeness.
verl = [
"verl>=0.5.0,<0.6.0",
"vllm>=0.8.4,<0.11.0",
"verl>=0.5.0",
"vllm>=0.8.4,<0.11.0", # Due to interface change of ExternalZeroMQDistributedExecutor
]
[project.scripts]
@@ -112,12 +112,14 @@ torch-gpu-stable = [
{include-group = "torch-cu128"},
"flash-attn>=2.8.3",
"tensordict>=0.9.1",
"verl>=0.6.0",
]
# Use this instead of --group torch-legacy --group torch-gpu
torch-gpu-legacy = [
{include-group = "torch-legacy"},
{include-group = "torch-cu128"},
"flash-attn==2.8.1",
"verl==0.5.0",
]
# For the TRL/Unsloth example.
Generated
+128 -20
View File
File diff suppressed because one or more lines are too long