microsoft--agent-lightning
85742ab165
Deploy Documentation / deploy (push) Has been cancelled
CPU Test / Test (Utilities, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (LLM proxy, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Others, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Store, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Utilities, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Weave, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (AgentOps, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (LLM proxy, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Others, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Weave, latest, Python 3.13) (push) Has been cancelled
Dashboard / Chromatic (push) Has been cancelled
CPU Test / Lint - fast (push) Has been cancelled
CPU Test / Lint - next (push) Has been cancelled
CPU Test / Lint - slow (push) Has been cancelled
CPU Test / Lint - JavaScript (push) Has been cancelled
CPU Test / Build documentation (push) Has been cancelled
CPU Test / Test (AgentOps, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (LLM proxy, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Others, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Store, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Weave, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (AgentOps, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Store, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Utilities, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Weave, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (AgentOps, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (LLM proxy, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Others, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Store, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Utilities, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (JavaScript) (push) Has been cancelled
329 行
12 KiB
Python
329 行
12 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
"""The training helper script for Calc-X agent with VERL algorithm.
|
|
|
|
Example usage:
|
|
|
|
```bash
|
|
python train_calc_agent.py --train-file data/train.parquet --val-file data/test.parquet --llm-proxy
|
|
```
|
|
|
|
To use an external store, run a store server first:
|
|
|
|
```bash
|
|
agl store --port 9999
|
|
```
|
|
|
|
Then run the training script with the external store address:
|
|
|
|
```bash
|
|
AGL_MANAGED_STORE=0 python train_calc_agent.py --external-store-address http://localhost:9999
|
|
```
|
|
|
|
Alternatively, you can also run algorithms and runners separately if needed:
|
|
|
|
```bash
|
|
AGL_MANAGED_STORE=0 AGL_CURRENT_ROLE=algorithm python train_calc_agent.py --external-store-address http://localhost:9999
|
|
AGL_MANAGED_STORE=0 AGL_CURRENT_ROLE=runner python train_calc_agent.py --external-store-address http://localhost:9999
|
|
```
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Dict, Optional, cast
|
|
|
|
from calc_agent import MathProblem, calc_agent
|
|
from datasets import Dataset as HuggingFaceDataset
|
|
|
|
import agentlightning as agl
|
|
from agentlightning.env_var import LightningEnvVar, resolve_bool_env_var, resolve_str_env_var
|
|
|
|
|
|
def verl_default_config() -> Dict[str, Any]:
|
|
config = {
|
|
"algorithm": {
|
|
"adv_estimator": "grpo",
|
|
"use_kl_in_reward": False,
|
|
},
|
|
"data": {
|
|
"train_batch_size": 32,
|
|
"max_prompt_length": 4096,
|
|
"max_response_length": 2048,
|
|
},
|
|
"actor_rollout_ref": {
|
|
"rollout": {
|
|
"tensor_model_parallel_size": 1,
|
|
"n": 4,
|
|
"log_prob_micro_batch_size_per_gpu": 4,
|
|
"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,
|
|
"ppo_micro_batch_size_per_gpu": 4,
|
|
"optim": {"lr": 1e-6},
|
|
"use_kl_loss": False,
|
|
"kl_loss_coef": 0.0,
|
|
"entropy_coeff": 0,
|
|
"clip_ratio_low": 0.2,
|
|
"clip_ratio_high": 0.3,
|
|
"fsdp_config": {
|
|
"param_offload": True,
|
|
"optimizer_offload": True,
|
|
},
|
|
},
|
|
"ref": {
|
|
"log_prob_micro_batch_size_per_gpu": 8,
|
|
"fsdp_config": {"param_offload": True},
|
|
},
|
|
"model": {
|
|
"path": "Qwen/Qwen2.5-1.5B-Instruct",
|
|
"use_remove_padding": True,
|
|
"enable_gradient_checkpointing": True,
|
|
},
|
|
},
|
|
"trainer": {
|
|
"n_gpus_per_node": 1,
|
|
"val_before_train": True,
|
|
"critic_warmup": 0,
|
|
"logger": ["console", "wandb"],
|
|
"project_name": "AgentLightning",
|
|
"experiment_name": "calc_x",
|
|
"nnodes": 1,
|
|
"save_freq": 64,
|
|
"test_freq": 32,
|
|
"total_epochs": 2,
|
|
},
|
|
}
|
|
return config
|
|
|
|
|
|
def train(
|
|
*,
|
|
train_file: str,
|
|
val_file: str,
|
|
model: Optional[str],
|
|
llm_proxy: bool,
|
|
ci: bool,
|
|
ci_fast: bool,
|
|
n_runners: int,
|
|
external_store_address: str,
|
|
lora: bool,
|
|
lora_rank: int,
|
|
lora_adapter_path: Optional[str],
|
|
trajectory_level: bool = False,
|
|
weave: bool,
|
|
mongo_uri: Optional[str],
|
|
):
|
|
"""The training entrypoint function for Calc-X agent with VERL algorithm.
|
|
|
|
Args:
|
|
train_file: The path to the training parquet file.
|
|
val_file: The path to the validation parquet file.
|
|
model: The HF model id or path to override the default model.
|
|
llm_proxy: Whether to enable LLM Proxy tracing/adapter.
|
|
ci: Whether to run a minimal CI-style training loop.
|
|
n_runners: The number of runners for the Trainer.
|
|
ci_fast: Whether to cap the training loop at a single step (implies CI toggles).
|
|
external_store_address: Connects to an external store instead of creating a new one in memory.
|
|
lora: Whether to enable LoRA training.
|
|
lora_rank: LoRA rank to use when LoRA is enabled.
|
|
lora_adapter_path: Optional path to a pre-trained LoRA adapter to load.
|
|
trajectory_level: Whether to enable trajectory level in trace aggregator.
|
|
weave: Whether to enable Weave tracing.
|
|
mongo_uri: MongoDB URI to use for the store.
|
|
"""
|
|
# Load datasets (respect CLI file paths)
|
|
train_dataset = cast(agl.Dataset[MathProblem], HuggingFaceDataset.from_parquet(train_file).to_list()) # type: ignore
|
|
val_dataset = cast(agl.Dataset[MathProblem], HuggingFaceDataset.from_parquet(val_file).to_list()) # type: ignore
|
|
|
|
print("First 5 rows of train dataset:")
|
|
print(train_dataset[:5]) # type: ignore
|
|
print("First 5 rows of val dataset:")
|
|
print(val_dataset[:5]) # type: ignore
|
|
|
|
config = verl_default_config()
|
|
|
|
if model:
|
|
config["actor_rollout_ref"]["model"]["path"] = model
|
|
|
|
# Enable LoRA configuration if requested
|
|
if lora:
|
|
config["actor_rollout_ref"]["model"]["lora_rank"] = lora_rank
|
|
print(f"LoRA enabled: lora_rank={lora_rank}")
|
|
if lora_adapter_path:
|
|
config["actor_rollout_ref"]["model"]["lora_adapter_path"] = lora_adapter_path
|
|
print(f"Loading LoRA adapter from: {lora_adapter_path}")
|
|
print("LoRA configuration will trigger verl to set ref_in_actor=True (LoRA mode)")
|
|
|
|
if trajectory_level:
|
|
config["agentlightning"] = {
|
|
"trace_aggregator": {
|
|
"level": "trajectory",
|
|
"trajectory_max_prompt_length": 2048,
|
|
"trajectory_max_response_length": 8192,
|
|
}
|
|
}
|
|
print("Trajectory level enabled in trace aggregator.")
|
|
|
|
# CI toggle keeps everything else the same but you can tweak the lightweight bits here if desired
|
|
if ci or ci_fast:
|
|
# Config the experiment name and project name so that they are available to CI
|
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
random_suffix = uuid.uuid4().hex[:8]
|
|
EXPERIMENT_NAME = f"calc_x_{timestamp}_{random_suffix}"
|
|
|
|
PROJECT_NAME = "AgentLightningCI"
|
|
|
|
# Skip this step if AGL_CURRENT_ROLE is runner
|
|
agl_current_role = resolve_str_env_var(LightningEnvVar.AGL_CURRENT_ROLE)
|
|
|
|
if agl_current_role != "runner":
|
|
# Simulate writing to $GITHUB_OUTPUT if it’s set
|
|
github_output = os.getenv("GITHUB_OUTPUT")
|
|
if github_output:
|
|
with open(github_output, "a") as f:
|
|
f.write(f"project_name={PROJECT_NAME}\n")
|
|
f.write(f"run_name={EXPERIMENT_NAME}\n")
|
|
|
|
print("Set environment variables:")
|
|
print(f"PROJECT_NAME={PROJECT_NAME}")
|
|
print(f"EXPERIMENT_NAME={EXPERIMENT_NAME}")
|
|
|
|
# Keep it tiny/light without adding new knobs
|
|
config["actor_rollout_ref"]["rollout"]["gpu_memory_utilization"] = 0.8
|
|
config["trainer"]["total_epochs"] = 1
|
|
config["trainer"]["total_training_steps"] = 20
|
|
config["trainer"]["test_freq"] = 20
|
|
config["trainer"]["experiment_name"] = EXPERIMENT_NAME
|
|
config["trainer"]["project_name"] = PROJECT_NAME
|
|
config["trainer"].pop("save_freq", None)
|
|
|
|
if ci_fast:
|
|
# Extra fast CI toggle for testing purposes.
|
|
config["actor_rollout_ref"]["rollout"]["gpu_memory_utilization"] = 0.6
|
|
config["trainer"]["total_training_steps"] = 1
|
|
config["trainer"]["test_freq"] = 1
|
|
|
|
algorithm = agl.VERL(config)
|
|
|
|
if external_store_address:
|
|
store: Optional[agl.LightningStore] = agl.LightningStoreClient(external_store_address)
|
|
elif mongo_uri:
|
|
from agentlightning.store.mongo import MongoLightningStore
|
|
|
|
store = MongoLightningStore(mongo_uri=mongo_uri)
|
|
else:
|
|
store = None
|
|
|
|
if llm_proxy:
|
|
tracer = agl.OtelTracer() # dummy tracer for LLM Proxy
|
|
adapter = agl.LlmProxyTraceToTriplet()
|
|
trainer = agl.Trainer(algorithm=algorithm, n_runners=n_runners, store=store, tracer=tracer, adapter=adapter)
|
|
elif weave:
|
|
# NOTE: Don't import WeaveTracer at the module level or in __init__.py files.
|
|
# Always import it lazily/conditionally (behind a feature flag) to avoid interfering
|
|
# with other libraries like LiteLLM/OpenTelemetry when weave is not explicitly enabled.
|
|
from agentlightning.tracer.weave import WeaveTracer
|
|
|
|
tracer = WeaveTracer()
|
|
trainer = agl.Trainer(algorithm=algorithm, n_runners=n_runners, store=store, tracer=tracer)
|
|
else:
|
|
trainer = agl.Trainer(algorithm=algorithm, n_runners=n_runners, store=store)
|
|
|
|
trainer.fit(calc_agent, train_dataset, val_dataset=val_dataset)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Train a math calc agent with Agent-lightning + VERL.")
|
|
parser.add_argument("--train-file", type=str, default="data/train.parquet", help="Path to train parquet file")
|
|
parser.add_argument("--val-file", type=str, default="data/test.parquet", help="Path to val parquet file")
|
|
parser.add_argument("--model", type=str, default=None, help="HF model id or path (optional)")
|
|
parser.add_argument("--llm-proxy", action="store_true", help="Enable LLM Proxy tracing/adapter")
|
|
parser.add_argument("--weave", action="store_true", help="Enable Weave tracing")
|
|
parser.add_argument("--ci", action="store_true", help="Run a minimal CI-style training loop")
|
|
parser.add_argument(
|
|
"--ci-fast", action="store_true", help="Limit the training loop to a single step (implies --ci)"
|
|
)
|
|
parser.add_argument("--n-runners", type=int, default=10, help="Number of runners for Trainer")
|
|
parser.add_argument(
|
|
"--external-store-address",
|
|
type=str,
|
|
default="",
|
|
help="Connect to an external store instead of creating a new one in memory",
|
|
)
|
|
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
|
|
parser.add_argument(
|
|
"--lora",
|
|
action="store_true",
|
|
help="Enable LoRA training. When enabled, the reference policy is computed by the actor rollout worker.",
|
|
)
|
|
parser.add_argument(
|
|
"--lora-rank",
|
|
type=int,
|
|
default=32,
|
|
help="LoRA rank to use when --lora is enabled (default: 32)",
|
|
)
|
|
parser.add_argument(
|
|
"--lora-adapter-path",
|
|
type=str,
|
|
default=None,
|
|
help="Optional path to a pre-trained LoRA adapter to load when --lora is enabled",
|
|
)
|
|
parser.add_argument(
|
|
"--trajectory-level",
|
|
action="store_true",
|
|
help="Enable trajectory level in trace aggregator.",
|
|
)
|
|
parser.add_argument(
|
|
"--mongo-uri",
|
|
type=str,
|
|
default=None,
|
|
help="MongoDB URI to use for the store.",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.external_store_address:
|
|
print(f"Connecting to external store at: {args.external_store_address}")
|
|
if resolve_bool_env_var(LightningEnvVar.AGL_MANAGED_STORE, fallback=True):
|
|
raise ValueError(
|
|
"When using an external store, please set the environment variable AGL_MANAGED_STORE=0. "
|
|
"Otherwise the trainer will still try to manage the store lifecycle for you!"
|
|
)
|
|
|
|
if args.ci_fast:
|
|
args.ci = True
|
|
|
|
agl.setup_logging("DEBUG" if args.debug else "INFO")
|
|
|
|
train(
|
|
train_file=args.train_file,
|
|
val_file=args.val_file,
|
|
model=args.model,
|
|
llm_proxy=args.llm_proxy,
|
|
ci=args.ci,
|
|
ci_fast=args.ci_fast,
|
|
n_runners=args.n_runners,
|
|
external_store_address=args.external_store_address,
|
|
lora=args.lora,
|
|
lora_rank=args.lora_rank,
|
|
lora_adapter_path=args.lora_adapter_path,
|
|
trajectory_level=args.trajectory_level,
|
|
weave=args.weave,
|
|
mongo_uri=args.mongo_uri,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|