agentcore-rl-toolkit 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentcore_rl_toolkit-0.1.3/.gitignore +31 -0
- agentcore_rl_toolkit-0.1.2/README.md → agentcore_rl_toolkit-0.1.3/PKG-INFO +95 -24
- agentcore_rl_toolkit-0.1.2/PKG-INFO → agentcore_rl_toolkit-0.1.3/README.md +52 -52
- agentcore_rl_toolkit-0.1.3/docs/site/src/assets/houston.webp +0 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/backends/slime/patches.md +68 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/backends/slime/runner.md +150 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/app.md +85 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/client.md +412 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/reward.md +45 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/index.md +20 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/index.mdx +29 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-appworld-agent.md +50 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-math-agent.md +42 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-migration-agent.md +57 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-officebench-agent.md +72 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/agent-adaptation.mdx +183 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/overview.mdx +179 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/rllm-backend-setup.md +101 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/slime-backend-setup.md +128 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/verl-backend-setup.md +159 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/index.mdx +116 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/rllm.md +14 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/slime.md +72 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/verl.md +14 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/content.config.ts +7 -0
- agentcore_rl_toolkit-0.1.3/docs/site/src/styles/custom.css +585 -0
- agentcore_rl_toolkit-0.1.3/pyproject.toml +112 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/app.py +20 -14
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/__init__.py +0 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/SETUP.md +312 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/__init__.py +12 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/.wandb.env.example +23 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/config.yaml.example +21 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/eval.sh +175 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/train.py +22 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/train.sh +120 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/__init__.py +0 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/gateway.py +130 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/rewards.py +102 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/rollout.py +383 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/traces.py +127 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/__init__.py +0 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/sglang_token_ids.py +696 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/verify_sglang_token_ids.py +539 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/runner.py +314 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/__init__.py +44 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/config/agentcore_grpo.yaml +71 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/config.py +64 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/dataset.py +26 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/examples/math_agent/preprocess_gsm8k.py +58 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/examples/math_agent/run_agentcore_grpo.sh +89 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/llm_server.py +164 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/loop_manager.py +556 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/main.py +132 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/scripts/install_megatron.sh +41 -0
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/trainer.py +681 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/client.py +99 -34
- agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/logging.py +58 -0
- agentcore_rl_toolkit-0.1.2/.gitignore +0 -23
- agentcore_rl_toolkit-0.1.2/pyproject.toml +0 -57
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/LICENSE +0 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/NOTICE +0 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/__init__.py +0 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/frameworks/strands/__init__.py +0 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/frameworks/strands/vllm_model.py +0 -0
- {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/reward_function.py +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Virtual environments
|
|
2
|
+
.venv/
|
|
3
|
+
.venv-*/
|
|
4
|
+
|
|
5
|
+
# Python cache
|
|
6
|
+
__pycache__/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
|
|
9
|
+
# Build artifacts
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
|
|
14
|
+
# Environment variables
|
|
15
|
+
.env
|
|
16
|
+
.wandb.env
|
|
17
|
+
|
|
18
|
+
# Local slime backend config (contains ARN/bucket; commit config.yaml.example only)
|
|
19
|
+
src/agentcore_rl_toolkit/backends/slime/examples/**/config.yaml
|
|
20
|
+
|
|
21
|
+
# Config files
|
|
22
|
+
config.toml
|
|
23
|
+
|
|
24
|
+
# Claude Code configuration: ignore everything by default,
|
|
25
|
+
# allowlist only skills meant to ship with the repo.
|
|
26
|
+
.claude/*
|
|
27
|
+
!.claude/skills/
|
|
28
|
+
.claude/skills/*
|
|
29
|
+
!.claude/skills/check-cloudwatch-session-logs/
|
|
30
|
+
|
|
31
|
+
.bedrock_agentcore.yaml
|
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentcore-rl-toolkit
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Toolkit for Seamlessly Enabling RL Training with Bedrock AgentCore.
|
|
5
|
+
Project-URL: Homepage, https://github.com/awslabs/agentcore-rl-toolkit
|
|
6
|
+
Author-email: Amazon Web Services - Labs <opensource@amazon.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: NOTICE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: bedrock-agentcore-starter-toolkit>=0.2.0
|
|
19
|
+
Requires-Dist: bedrock-agentcore>=1.0.3
|
|
20
|
+
Requires-Dist: boto3>=1.40.55
|
|
21
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pre-commit>=3.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
27
|
+
Provides-Extra: rllm
|
|
28
|
+
Requires-Dist: rllm; extra == 'rllm'
|
|
29
|
+
Provides-Extra: slime
|
|
30
|
+
Requires-Dist: rllm-model-gateway>=0.1.0; extra == 'slime'
|
|
31
|
+
Provides-Extra: verl
|
|
32
|
+
Requires-Dist: flash-attn==2.8.3; extra == 'verl'
|
|
33
|
+
Requires-Dist: numpy; extra == 'verl'
|
|
34
|
+
Requires-Dist: qwen-vl-utils; extra == 'verl'
|
|
35
|
+
Requires-Dist: ray; extra == 'verl'
|
|
36
|
+
Requires-Dist: rllm-model-gateway>=0.1.0; extra == 'verl'
|
|
37
|
+
Requires-Dist: torch>=2.10.0; extra == 'verl'
|
|
38
|
+
Requires-Dist: torchvision>=0.23.0; extra == 'verl'
|
|
39
|
+
Requires-Dist: transformers>=5.5.3; extra == 'verl'
|
|
40
|
+
Requires-Dist: verl==0.8.0; extra == 'verl'
|
|
41
|
+
Requires-Dist: vllm==0.21.0; extra == 'verl'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
1
44
|
|
|
2
45
|
# AgentCore RL Toolkit (ART)
|
|
3
46
|
|
|
@@ -5,12 +48,12 @@ Toolkit to Seamlessly Enable RL Training on Any Agent with Bedrock AgentCore.
|
|
|
5
48
|
|
|
6
49
|
## Overview
|
|
7
50
|
|
|
8
|
-
**AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for
|
|
51
|
+
**AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
|
|
9
52
|
|
|
10
53
|
LLM agent rollouts are long-running — an agent may run for minutes or hours making tool calls. The toolkit manages this with an async-first design:
|
|
11
54
|
|
|
12
|
-
- **Agent Adaptation** (`AgentCoreRLApp`, `
|
|
13
|
-
- **
|
|
55
|
+
- **Agent Adaptation** (`AgentCoreRLApp`, `@rollout_entrypoint`): A decorator swap turns your production agent into an async, fire-and-forget service — the agent runs in the background and saves results to S3. Return any JSON-serializable artifacts: rewards for RL training, evaluation metrics, conversation history, or custom data.
|
|
56
|
+
- **Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
|
|
14
57
|
|
|
15
58
|
Both components use S3 as their data layer, but the complexity is fully abstracted — your code never reads from or writes to S3 directly.
|
|
16
59
|
|
|
@@ -40,8 +83,8 @@ While session routing is valuable for multi-turn production agents, RL rollouts
|
|
|
40
83
|
|
|
41
84
|
## Key Features
|
|
42
85
|
|
|
43
|
-
- **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`)
|
|
44
|
-
- **
|
|
86
|
+
- **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) — most of your agent code stays the same
|
|
87
|
+
- **No custom model wrappers**: Your agent uses standard framework models (e.g., `OpenAIModel`). Token capture for RL training is handled at the infrastructure layer, not in your agent code
|
|
45
88
|
- **Async end-to-end**: Fire-and-forget server + future-based client — no long-lived TCP connections needed for long-running agent rollouts
|
|
46
89
|
- **Simplified rollout collection**: `RolloutClient` manages concurrency, rate limiting, and S3 result polling out of the box for both training loops and batch evaluation
|
|
47
90
|
- **Production parity**: Direct code reuse from production agents ensures training behavior matches real deployment
|
|
@@ -79,8 +122,8 @@ if __name__ == "__main__":
|
|
|
79
122
|
Starting from a deployment-ready agent like above, here are the changes needed for RL training (see [`rl_app.py`](examples/strands_math_agent/rl_app.py) for full example):
|
|
80
123
|
```python
|
|
81
124
|
from agentcore_rl_toolkit import AgentCoreRLApp
|
|
82
|
-
from agentcore_rl_toolkit.frameworks.strands.vllm_model import vLLMModel
|
|
83
125
|
from strands import Agent
|
|
126
|
+
from strands.models.openai import OpenAIModel
|
|
84
127
|
|
|
85
128
|
app = AgentCoreRLApp()
|
|
86
129
|
reward_fn = GSM8KReward() # user-defined reward function
|
|
@@ -89,24 +132,46 @@ reward_fn = GSM8KReward() # user-defined reward function
|
|
|
89
132
|
def invoke_agent(payload: dict):
|
|
90
133
|
base_url = payload["_rollout"]["base_url"]
|
|
91
134
|
model_id = payload["_rollout"]["model_id"]
|
|
92
|
-
model =
|
|
135
|
+
model = OpenAIModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
|
|
93
136
|
agent = Agent(model=model, tools=[...], system_prompt="...")
|
|
94
137
|
|
|
95
138
|
response = agent(payload.get("prompt"))
|
|
96
|
-
rollout_data = model.get_token_data()
|
|
97
139
|
rewards = reward_fn(response_text=response.message["content"][0]["text"], ground_truth=payload.get("answer"))
|
|
98
|
-
return {"
|
|
140
|
+
return {"rewards": rewards}
|
|
99
141
|
```
|
|
100
142
|
|
|
101
143
|
**Key changes:**
|
|
102
144
|
1. `BedrockAgentCoreApp` → `AgentCoreRLApp` (framework-agnostic)
|
|
103
|
-
2. `BedrockModel` → `
|
|
145
|
+
2. `BedrockModel` → `OpenAIModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
|
|
104
146
|
3. `@app.entrypoint` → `@app.rollout_entrypoint`
|
|
105
|
-
4.
|
|
106
|
-
|
|
147
|
+
4. Return a dict instead of text (`rewards` key required for training)
|
|
148
|
+
|
|
149
|
+
> **Note:** The return value is flexible — any JSON-serializable dict works. This example returns rewards for training, but for evaluation you might return rewards, conversation history, or other artifacts. You can also persist raw data to S3 and run evaluation logic client-side.
|
|
107
150
|
|
|
108
151
|
**Why create model and agent inside the entrypoint?** During RL training, the training engine can pass runtime configuration—such as inference server address, sampling parameters, and system prompt—via the `_rollout` payload, giving flexibility to accommodate different learning scenarios. This is safe because RL rollouts are single-invocation: the agent doesn't need persistent conversation history across requests, so there's no need to define model and agent as global variables.
|
|
109
152
|
|
|
153
|
+
### Background: Token Capture for RL Training
|
|
154
|
+
|
|
155
|
+
> **Note:** This section is background knowledge — you don't need to configure any of this yourself. Token capture is managed by the training infrastructure.
|
|
156
|
+
|
|
157
|
+
RL for LLMs trains on token sequences, so trainers need the exact token IDs sampled by the model. But agents communicate via OpenAI-compatible APIs that return text, not tokens. Re-tokenizing that text back into IDs causes **retokenization drift** — the reconstructed IDs may differ from what the model actually generated, leading to off-policy updates that destabilize training. This drift has [three common sources](https://vllm.ai/blog/agent-lightning): (1) non-unique tokenization (e.g., `H`+`AVING` retokenizes as `HAV`+`ING`), (2) tool-call serialization changes (whitespace/formatting shifts during parsing and re-rendering), and (3) chat template misalignment across frameworks.
|
|
158
|
+
|
|
159
|
+
The solution is to capture token IDs directly from the inference server, avoiding retokenization entirely. [rllm-model-gateway](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) does this as a transparent HTTP proxy between agents and the inference server:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Agent ──► rllm-model-gateway ──► Inference Server (vLLM/SGLang)
|
|
163
|
+
│
|
|
164
|
+
└─► captures token IDs + logprobs, scoped by session
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The gateway intercepts OpenAI-compatible API responses and extracts token data directly from the server. Crucially, it scopes captured data by session ID — so when hundreds of concurrent agent sessions hit the same gateway, each rollout's token trace is correctly associated with its trajectory. Agents use a standard `OpenAIModel` and are completely unaware of the capture.
|
|
168
|
+
|
|
169
|
+
In practice, this is infrastructure managed by the training framework:
|
|
170
|
+
- **During training**: the training engine points `base_url` through the gateway automatically
|
|
171
|
+
- **During evaluation**: `base_url` points directly to any OpenAI-compatible endpoint (vLLM, SGLang, LiteLLM, etc.), or you can use `BedrockModel` via the Bedrock API — no gateway involved
|
|
172
|
+
|
|
173
|
+
The gateway is [available on PyPI](https://pypi.org/project/rllm-model-gateway/) (`pip install rllm-model-gateway`). See the [rllm-model-gateway repo](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) for details.
|
|
174
|
+
|
|
110
175
|
## Client-Side: Invoking Agents and Collecting Results
|
|
111
176
|
|
|
112
177
|
LLM agent rollouts are long-running and asynchronous — an agent may run for minutes or even hours as it reasons and makes tool calls. Both sides of this toolkit are designed around that constraint:
|
|
@@ -149,8 +214,8 @@ for f in futures:
|
|
|
149
214
|
|
|
150
215
|
**How the future lifecycle works:**
|
|
151
216
|
- **`client.invoke()`** sends the request to ACR and returns a `RolloutFuture` immediately — this means ACR has received the request and a background agent session is processing it.
|
|
152
|
-
- **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the
|
|
153
|
-
- **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled — no manual cleanup needed.
|
|
217
|
+
- **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the result (rewards, metrics, etc.) once the agent finishes and writes to S3.
|
|
218
|
+
- **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled to avoid wasteful idle time — no manual cleanup needed.
|
|
154
219
|
|
|
155
220
|
### Batch Evaluation (`run_batch()`)
|
|
156
221
|
|
|
@@ -207,10 +272,14 @@ The training architecture follows a **decoupled design** where agent rollouts an
|
|
|
207
272
|
│ │ (e.g., veRL) │ │ (vLLM/SGLang) │ │
|
|
208
273
|
│ └───────┬─────────────┘ └───────▲─────────────┘ │
|
|
209
274
|
│ │ │ │
|
|
275
|
+
│ │ ┌───────┴─────────────┐ │
|
|
276
|
+
│ │ │ rllm-model-gateway │ │
|
|
277
|
+
│ │ │ (token capture) │ │
|
|
278
|
+
│ │ └───────▲─────────────┘ │
|
|
210
279
|
└───────────────┼──────────────────────────┼─────────────────────┘
|
|
211
280
|
│ 1. Submit N prompts │ ◄── ART Client-Side (1): RolloutClient
|
|
212
|
-
│ to ACR │ 2. Model inference
|
|
213
|
-
▼ │
|
|
281
|
+
│ to ACR │ 2. Model inference
|
|
282
|
+
▼ │ via standard OpenAI API
|
|
214
283
|
┌────────────────────────────────────────────────────────────────┐
|
|
215
284
|
│ AWS Bedrock AgentCore Runtime │
|
|
216
285
|
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
|
|
@@ -219,28 +288,30 @@ The training architecture follows a **decoupled design** where agent rollouts an
|
|
|
219
288
|
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
|
|
220
289
|
│ │ │ │ │
|
|
221
290
|
│ └──────────────┴───────────────────┘ │
|
|
222
|
-
│ │ 3. Save
|
|
291
|
+
│ │ 3. Save rewards to S3 │ ◄── ART Agent-Side (3): @rollout_entrypoint
|
|
223
292
|
│ ▼ │
|
|
224
293
|
│ ┌───────────────────┐ │
|
|
225
|
-
│ │
|
|
294
|
+
│ │ S3 (results) │ │
|
|
226
295
|
│ └─────────┬─────────┘ │
|
|
227
296
|
└─────────────────────────────┼──────────────────────────────────┘
|
|
228
297
|
│ 4. Poll S3 HEAD for results ◄── ART Client-Side (4): RolloutFuture
|
|
229
298
|
▼
|
|
230
|
-
Training Engine
|
|
231
|
-
|
|
299
|
+
Training Engine reads tokens
|
|
300
|
+
from gateway + rewards from S3
|
|
301
|
+
for policy update
|
|
232
302
|
```
|
|
233
303
|
|
|
234
304
|
**Workflow:**
|
|
235
305
|
1. **Prompt submission**: Training engine uses `RolloutClient` to submit N prompts to ACR — it injects rollout configs (`input_id`, `s3_bucket`, etc.) and handles rate limiting and concurrency, while ACR auto-scales N parallel agent sessions
|
|
236
|
-
2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via
|
|
237
|
-
3. **
|
|
238
|
-
4. **Policy update**: Training engine
|
|
306
|
+
2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via standard OpenAI-compatible API (through the gateway during training)
|
|
307
|
+
3. **Result collection**: When the agent finishes, `@rollout_entrypoint` saves rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
|
|
308
|
+
4. **Policy update**: Training engine collects token data from the gateway and rewards from S3 to update the model
|
|
239
309
|
|
|
240
310
|
This architecture enables parallel and highly efficient rollouts with secure execution during RL training. The decoupled design means training libraries only need the agent's container image to start training—agent code and dependencies stay completely separate from the training library.
|
|
241
311
|
|
|
242
312
|
**Supported Training Libraries:**
|
|
243
|
-
-
|
|
313
|
+
- [rLLM](https://github.com/rllm-org/rllm) — supports multiple backends (veRL, Tinker, and more)
|
|
314
|
+
- [Math Agent](examples/strands_math_agent/): [Tinker](https://github.com/rllm-org/rllm/blob/main/examples/agentcore_math/train_agentcore_math_tinker.sh)
|
|
244
315
|
|
|
245
316
|
### Prepare Your Agent Container
|
|
246
317
|
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: agentcore-rl-toolkit
|
|
3
|
-
Version: 0.1.2
|
|
4
|
-
Summary: Toolkit for Seamlessly Enabling RL Training with Bedrock AgentCore.
|
|
5
|
-
Project-URL: Homepage, https://github.com/awslabs/agentcore-rl-toolkit
|
|
6
|
-
Author-email: Amazon Web Services - Labs <opensource@amazon.com>
|
|
7
|
-
License-Expression: Apache-2.0
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
License-File: NOTICE
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
-
Requires-Python: >=3.10
|
|
18
|
-
Requires-Dist: bedrock-agentcore-starter-toolkit>=0.2.0
|
|
19
|
-
Requires-Dist: bedrock-agentcore>=1.0.3
|
|
20
|
-
Requires-Dist: boto3>=1.40.55
|
|
21
|
-
Requires-Dist: python-dotenv>=1.0.0
|
|
22
|
-
Provides-Extra: dev
|
|
23
|
-
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
24
|
-
Requires-Dist: pre-commit>=3.0; extra == 'dev'
|
|
25
|
-
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
26
|
-
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
27
|
-
Description-Content-Type: text/markdown
|
|
28
|
-
|
|
29
1
|
|
|
30
2
|
# AgentCore RL Toolkit (ART)
|
|
31
3
|
|
|
@@ -33,12 +5,12 @@ Toolkit to Seamlessly Enable RL Training on Any Agent with Bedrock AgentCore.
|
|
|
33
5
|
|
|
34
6
|
## Overview
|
|
35
7
|
|
|
36
|
-
**AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for
|
|
8
|
+
**AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
|
|
37
9
|
|
|
38
10
|
LLM agent rollouts are long-running — an agent may run for minutes or hours making tool calls. The toolkit manages this with an async-first design:
|
|
39
11
|
|
|
40
|
-
- **Agent Adaptation** (`AgentCoreRLApp`, `
|
|
41
|
-
- **
|
|
12
|
+
- **Agent Adaptation** (`AgentCoreRLApp`, `@rollout_entrypoint`): A decorator swap turns your production agent into an async, fire-and-forget service — the agent runs in the background and saves results to S3. Return any JSON-serializable artifacts: rewards for RL training, evaluation metrics, conversation history, or custom data.
|
|
13
|
+
- **Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
|
|
42
14
|
|
|
43
15
|
Both components use S3 as their data layer, but the complexity is fully abstracted — your code never reads from or writes to S3 directly.
|
|
44
16
|
|
|
@@ -68,8 +40,8 @@ While session routing is valuable for multi-turn production agents, RL rollouts
|
|
|
68
40
|
|
|
69
41
|
## Key Features
|
|
70
42
|
|
|
71
|
-
- **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`)
|
|
72
|
-
- **
|
|
43
|
+
- **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) — most of your agent code stays the same
|
|
44
|
+
- **No custom model wrappers**: Your agent uses standard framework models (e.g., `OpenAIModel`). Token capture for RL training is handled at the infrastructure layer, not in your agent code
|
|
73
45
|
- **Async end-to-end**: Fire-and-forget server + future-based client — no long-lived TCP connections needed for long-running agent rollouts
|
|
74
46
|
- **Simplified rollout collection**: `RolloutClient` manages concurrency, rate limiting, and S3 result polling out of the box for both training loops and batch evaluation
|
|
75
47
|
- **Production parity**: Direct code reuse from production agents ensures training behavior matches real deployment
|
|
@@ -107,8 +79,8 @@ if __name__ == "__main__":
|
|
|
107
79
|
Starting from a deployment-ready agent like above, here are the changes needed for RL training (see [`rl_app.py`](examples/strands_math_agent/rl_app.py) for full example):
|
|
108
80
|
```python
|
|
109
81
|
from agentcore_rl_toolkit import AgentCoreRLApp
|
|
110
|
-
from agentcore_rl_toolkit.frameworks.strands.vllm_model import vLLMModel
|
|
111
82
|
from strands import Agent
|
|
83
|
+
from strands.models.openai import OpenAIModel
|
|
112
84
|
|
|
113
85
|
app = AgentCoreRLApp()
|
|
114
86
|
reward_fn = GSM8KReward() # user-defined reward function
|
|
@@ -117,24 +89,46 @@ reward_fn = GSM8KReward() # user-defined reward function
|
|
|
117
89
|
def invoke_agent(payload: dict):
|
|
118
90
|
base_url = payload["_rollout"]["base_url"]
|
|
119
91
|
model_id = payload["_rollout"]["model_id"]
|
|
120
|
-
model =
|
|
92
|
+
model = OpenAIModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
|
|
121
93
|
agent = Agent(model=model, tools=[...], system_prompt="...")
|
|
122
94
|
|
|
123
95
|
response = agent(payload.get("prompt"))
|
|
124
|
-
rollout_data = model.get_token_data()
|
|
125
96
|
rewards = reward_fn(response_text=response.message["content"][0]["text"], ground_truth=payload.get("answer"))
|
|
126
|
-
return {"
|
|
97
|
+
return {"rewards": rewards}
|
|
127
98
|
```
|
|
128
99
|
|
|
129
100
|
**Key changes:**
|
|
130
101
|
1. `BedrockAgentCoreApp` → `AgentCoreRLApp` (framework-agnostic)
|
|
131
|
-
2. `BedrockModel` → `
|
|
102
|
+
2. `BedrockModel` → `OpenAIModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
|
|
132
103
|
3. `@app.entrypoint` → `@app.rollout_entrypoint`
|
|
133
|
-
4.
|
|
134
|
-
|
|
104
|
+
4. Return a dict instead of text (`rewards` key required for training)
|
|
105
|
+
|
|
106
|
+
> **Note:** The return value is flexible — any JSON-serializable dict works. This example returns rewards for training, but for evaluation you might return rewards, conversation history, or other artifacts. You can also persist raw data to S3 and run evaluation logic client-side.
|
|
135
107
|
|
|
136
108
|
**Why create model and agent inside the entrypoint?** During RL training, the training engine can pass runtime configuration—such as inference server address, sampling parameters, and system prompt—via the `_rollout` payload, giving flexibility to accommodate different learning scenarios. This is safe because RL rollouts are single-invocation: the agent doesn't need persistent conversation history across requests, so there's no need to define model and agent as global variables.
|
|
137
109
|
|
|
110
|
+
### Background: Token Capture for RL Training
|
|
111
|
+
|
|
112
|
+
> **Note:** This section is background knowledge — you don't need to configure any of this yourself. Token capture is managed by the training infrastructure.
|
|
113
|
+
|
|
114
|
+
RL for LLMs trains on token sequences, so trainers need the exact token IDs sampled by the model. But agents communicate via OpenAI-compatible APIs that return text, not tokens. Re-tokenizing that text back into IDs causes **retokenization drift** — the reconstructed IDs may differ from what the model actually generated, leading to off-policy updates that destabilize training. This drift has [three common sources](https://vllm.ai/blog/agent-lightning): (1) non-unique tokenization (e.g., `H`+`AVING` retokenizes as `HAV`+`ING`), (2) tool-call serialization changes (whitespace/formatting shifts during parsing and re-rendering), and (3) chat template misalignment across frameworks.
|
|
115
|
+
|
|
116
|
+
The solution is to capture token IDs directly from the inference server, avoiding retokenization entirely. [rllm-model-gateway](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) does this as a transparent HTTP proxy between agents and the inference server:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Agent ──► rllm-model-gateway ──► Inference Server (vLLM/SGLang)
|
|
120
|
+
│
|
|
121
|
+
└─► captures token IDs + logprobs, scoped by session
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The gateway intercepts OpenAI-compatible API responses and extracts token data directly from the server. Crucially, it scopes captured data by session ID — so when hundreds of concurrent agent sessions hit the same gateway, each rollout's token trace is correctly associated with its trajectory. Agents use a standard `OpenAIModel` and are completely unaware of the capture.
|
|
125
|
+
|
|
126
|
+
In practice, this is infrastructure managed by the training framework:
|
|
127
|
+
- **During training**: the training engine points `base_url` through the gateway automatically
|
|
128
|
+
- **During evaluation**: `base_url` points directly to any OpenAI-compatible endpoint (vLLM, SGLang, LiteLLM, etc.), or you can use `BedrockModel` via the Bedrock API — no gateway involved
|
|
129
|
+
|
|
130
|
+
The gateway is [available on PyPI](https://pypi.org/project/rllm-model-gateway/) (`pip install rllm-model-gateway`). See the [rllm-model-gateway repo](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) for details.
|
|
131
|
+
|
|
138
132
|
## Client-Side: Invoking Agents and Collecting Results
|
|
139
133
|
|
|
140
134
|
LLM agent rollouts are long-running and asynchronous — an agent may run for minutes or even hours as it reasons and makes tool calls. Both sides of this toolkit are designed around that constraint:
|
|
@@ -177,8 +171,8 @@ for f in futures:
|
|
|
177
171
|
|
|
178
172
|
**How the future lifecycle works:**
|
|
179
173
|
- **`client.invoke()`** sends the request to ACR and returns a `RolloutFuture` immediately — this means ACR has received the request and a background agent session is processing it.
|
|
180
|
-
- **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the
|
|
181
|
-
- **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled — no manual cleanup needed.
|
|
174
|
+
- **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the result (rewards, metrics, etc.) once the agent finishes and writes to S3.
|
|
175
|
+
- **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled to avoid wasteful idle time — no manual cleanup needed.
|
|
182
176
|
|
|
183
177
|
### Batch Evaluation (`run_batch()`)
|
|
184
178
|
|
|
@@ -235,10 +229,14 @@ The training architecture follows a **decoupled design** where agent rollouts an
|
|
|
235
229
|
│ │ (e.g., veRL) │ │ (vLLM/SGLang) │ │
|
|
236
230
|
│ └───────┬─────────────┘ └───────▲─────────────┘ │
|
|
237
231
|
│ │ │ │
|
|
232
|
+
│ │ ┌───────┴─────────────┐ │
|
|
233
|
+
│ │ │ rllm-model-gateway │ │
|
|
234
|
+
│ │ │ (token capture) │ │
|
|
235
|
+
│ │ └───────▲─────────────┘ │
|
|
238
236
|
└───────────────┼──────────────────────────┼─────────────────────┘
|
|
239
237
|
│ 1. Submit N prompts │ ◄── ART Client-Side (1): RolloutClient
|
|
240
|
-
│ to ACR │ 2. Model inference
|
|
241
|
-
▼ │
|
|
238
|
+
│ to ACR │ 2. Model inference
|
|
239
|
+
▼ │ via standard OpenAI API
|
|
242
240
|
┌────────────────────────────────────────────────────────────────┐
|
|
243
241
|
│ AWS Bedrock AgentCore Runtime │
|
|
244
242
|
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
|
|
@@ -247,28 +245,30 @@ The training architecture follows a **decoupled design** where agent rollouts an
|
|
|
247
245
|
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
|
|
248
246
|
│ │ │ │ │
|
|
249
247
|
│ └──────────────┴───────────────────┘ │
|
|
250
|
-
│ │ 3. Save
|
|
248
|
+
│ │ 3. Save rewards to S3 │ ◄── ART Agent-Side (3): @rollout_entrypoint
|
|
251
249
|
│ ▼ │
|
|
252
250
|
│ ┌───────────────────┐ │
|
|
253
|
-
│ │
|
|
251
|
+
│ │ S3 (results) │ │
|
|
254
252
|
│ └─────────┬─────────┘ │
|
|
255
253
|
└─────────────────────────────┼──────────────────────────────────┘
|
|
256
254
|
│ 4. Poll S3 HEAD for results ◄── ART Client-Side (4): RolloutFuture
|
|
257
255
|
▼
|
|
258
|
-
Training Engine
|
|
259
|
-
|
|
256
|
+
Training Engine reads tokens
|
|
257
|
+
from gateway + rewards from S3
|
|
258
|
+
for policy update
|
|
260
259
|
```
|
|
261
260
|
|
|
262
261
|
**Workflow:**
|
|
263
262
|
1. **Prompt submission**: Training engine uses `RolloutClient` to submit N prompts to ACR — it injects rollout configs (`input_id`, `s3_bucket`, etc.) and handles rate limiting and concurrency, while ACR auto-scales N parallel agent sessions
|
|
264
|
-
2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via
|
|
265
|
-
3. **
|
|
266
|
-
4. **Policy update**: Training engine
|
|
263
|
+
2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via standard OpenAI-compatible API (through the gateway during training)
|
|
264
|
+
3. **Result collection**: When the agent finishes, `@rollout_entrypoint` saves rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
|
|
265
|
+
4. **Policy update**: Training engine collects token data from the gateway and rewards from S3 to update the model
|
|
267
266
|
|
|
268
267
|
This architecture enables parallel and highly efficient rollouts with secure execution during RL training. The decoupled design means training libraries only need the agent's container image to start training—agent code and dependencies stay completely separate from the training library.
|
|
269
268
|
|
|
270
269
|
**Supported Training Libraries:**
|
|
271
|
-
-
|
|
270
|
+
- [rLLM](https://github.com/rllm-org/rllm) — supports multiple backends (veRL, Tinker, and more)
|
|
271
|
+
- [Math Agent](examples/strands_math_agent/): [Tinker](https://github.com/rllm-org/rllm/blob/main/examples/agentcore_math/train_agentcore_math_tinker.sh)
|
|
272
272
|
|
|
273
273
|
### Prepare Your Agent Container
|
|
274
274
|
|
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SGLang patches
|
|
3
|
+
description: Apply + verify the SGLang token-IDs patch used by the slime backend.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## `agentcore_rl_toolkit.backends.slime.patches.sglang_token_ids`
|
|
10
|
+
|
|
11
|
+
Apply SGLang v0.5.9 patch to expose prompt/completion token IDs in chat completions.
|
|
12
|
+
|
|
13
|
+
SGLang's /v1/chat/completions endpoint does not include tokenized prompt or
|
|
14
|
+
completion IDs in the response. This patch adds four fields to the Pydantic
|
|
15
|
+
models and populates them from the engine's `output_ids` (always available)
|
|
16
|
+
and `adapted_request.input_ids`:
|
|
17
|
+
|
|
18
|
+
| Mode | Model | Field added |
|
|
19
|
+
|----------------|----------------------------------------------|----------------------|
|
|
20
|
+
| Non-streaming | ChatCompletionResponse | prompt_token_ids |
|
|
21
|
+
| Non-streaming | ChatCompletionResponseChoice | token_ids |
|
|
22
|
+
| Streaming | ChatCompletionStreamResponse (first chunk) | prompt_token_ids |
|
|
23
|
+
| Streaming | ChatCompletionResponseStreamChoice | token_ids (delta) |
|
|
24
|
+
|
|
25
|
+
Each Pydantic field is wrapped with a `@model_serializer` that drops the key
|
|
26
|
+
when None, so vanilla OpenAI clients see wire-identical responses.
|
|
27
|
+
|
|
28
|
+
For streaming, the patch handles three subtleties:
|
|
29
|
+
|
|
30
|
+
1. `output_ids` is cumulative when `server_args.stream_output=False` (the
|
|
31
|
+
default); we slice past a per-index watermark to get the delta.
|
|
32
|
+
2. The tool-call parser may yield 0, 1, or multiple chunks per engine yield,
|
|
33
|
+
so delta token IDs are buffered in `_pending_token_ids` and flushed onto
|
|
34
|
+
the first yielded chunk. If the parser yields nothing (partial JSON), the
|
|
35
|
+
IDs are re-buffered for the next iteration.
|
|
36
|
+
3. When the detokenizer holds back text at word boundaries (empty `delta`),
|
|
37
|
+
or when the final token is EOS (empty `delta`), the buffer is preserved
|
|
38
|
+
and flushed onto the finish-reason chunk at stream end.
|
|
39
|
+
|
|
40
|
+
This enables rllm-model-gateway to capture exact RL-training trace data
|
|
41
|
+
without any gateway modifications and without requiring `logprobs=True`.
|
|
42
|
+
|
|
43
|
+
## `apply_patch() -> bool`
|
|
44
|
+
|
|
45
|
+
Patch the installed SGLang package.
|
|
46
|
+
|
|
47
|
+
Returns True if either file was patched, False if both were already
|
|
48
|
+
patched, SGLang wasn't found, or patching failed.
|
|
49
|
+
|
|
50
|
+
## `agentcore_rl_toolkit.backends.slime.patches.verify_sglang_token_ids`
|
|
51
|
+
|
|
52
|
+
Verify the SGLang v0.5.9 token_ids patch.
|
|
53
|
+
|
|
54
|
+
Launches a local SGLang server with the given model, issues greedy-decoded
|
|
55
|
+
chat completion requests in both streaming and non-streaming modes, and
|
|
56
|
+
checks that:
|
|
57
|
+
|
|
58
|
+
1. Non-streaming responses expose prompt_token_ids (on the response) and
|
|
59
|
+
token_ids (per choice), and decoding token_ids matches the content.
|
|
60
|
+
2. Streaming responses expose prompt_token_ids on the first chunk and
|
|
61
|
+
token_ids on content chunks, and decoding the concatenation matches
|
|
62
|
+
the concatenated deltas.
|
|
63
|
+
3. Under greedy decoding, the prompt and completion token sequences are
|
|
64
|
+
identical between streaming and non-streaming modes.
|
|
65
|
+
4. Streaming with tools active yields the same completion token sequence
|
|
66
|
+
as streaming without tools, validating the _pending_token_ids buffering.
|
|
67
|
+
|
|
68
|
+
## `main(argv: Optional[list[str]] = None) -> int`
|