chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Minimal Agent-lightning + Tinker training example.
|
||||
|
||||
The Hello agent fine-tunes a model so it repeats whatever identity string you
|
||||
pass in (e.g., `"Say you are 42" -> "I'm 42."`). It mirrors the structure of
|
||||
Tinker Cookbook RL recipes but drives rollouts through Agent-lightning tasks
|
||||
instead of Tinker's built-in environments.
|
||||
|
||||
Environment setup:
|
||||
|
||||
1. Copy `examples/tinker/.env.example` to `examples/tinker/.env`.
|
||||
2. Fill in `OPENAI_API_KEY` / `OPENAI_BASE_URL` so the helper completions
|
||||
can be routed via LiteLLM.
|
||||
3. Provide `TINKER_API_KEY` if you plan to train against the hosted Tinker service.
|
||||
|
||||
This example does not support W&B logging.
|
||||
|
||||
CLI entry points:
|
||||
|
||||
```bash
|
||||
# Integrated run that spawns store, algorithm, and runners
|
||||
python hello.py oneclick
|
||||
```
|
||||
|
||||
Distributed workflow across three terminals:
|
||||
|
||||
```bash
|
||||
agl store # <-- expect the store to be running on port 4747
|
||||
python hello.py algo
|
||||
python hello.py runner
|
||||
```
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import multiprocessing
|
||||
import socket
|
||||
|
||||
from agl_tinker.algo import Tinker
|
||||
from agl_tinker.env import AGLDatasetBuilder
|
||||
from agl_tinker.train import Config
|
||||
from agl_tinker.train import main as entrypoint
|
||||
from openai import OpenAI
|
||||
from rich.console import Console
|
||||
|
||||
import agentlightning as agl
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
def _find_available_port() -> int:
|
||||
"""Find an available port by binding to port 0.
|
||||
|
||||
Returns:
|
||||
An available port number.
|
||||
"""
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(("", 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
|
||||
@agl.rollout
|
||||
def hello(task: str, llm: agl.LLM, rollout: agl.Rollout) -> None:
|
||||
"""Agent rollout function that tests if the model claims the given identity.
|
||||
|
||||
Prompts the model to say it is the given task/identity and assigns a reward
|
||||
based on whether the model's response matches the expected behavior.
|
||||
|
||||
Args:
|
||||
task: The identity string the model should claim to be.
|
||||
llm: The LLM endpoint configuration.
|
||||
rollout: The rollout metadata containing rollout ID and mode.
|
||||
"""
|
||||
openai_client = OpenAI(base_url=llm.endpoint, api_key="dummy")
|
||||
response = openai_client.chat.completions.create(
|
||||
model=llm.model,
|
||||
messages=[{"role": "user", "content": f"Let's play a game. Say you are {task}."}],
|
||||
)
|
||||
|
||||
response_content = response.choices[0].message.content
|
||||
content_lower = response_content.lower() if response_content else ""
|
||||
if ("i am " + task) in content_lower or ("i'm " + task) in content_lower:
|
||||
rew = 1.0
|
||||
elif ("not " + task) in content_lower:
|
||||
rew = -1.0
|
||||
else:
|
||||
rew = 0.0
|
||||
|
||||
console.print(
|
||||
f"[bold green]Runners ({rollout.rollout_id}, {rollout.mode}):[/bold green] "
|
||||
f"{task} -> {response_content} -> Reward: {rew}"
|
||||
)
|
||||
agl.emit_reward(rew)
|
||||
|
||||
|
||||
def run_algo():
|
||||
"""Run the training algorithm in standalone mode.
|
||||
|
||||
Launches the Tinker training algorithm that connects to a separate store
|
||||
and rollout runners.
|
||||
"""
|
||||
config = Config(
|
||||
learning_rate=1e-5,
|
||||
dataset_builder=AGLDatasetBuilder(
|
||||
train_dataset=[str(i) for i in range(1000)],
|
||||
val_dataset=[str(i) for i in range(1000, 1024)],
|
||||
batch_size=32,
|
||||
shuffle=True,
|
||||
group_size=4,
|
||||
seed=42,
|
||||
),
|
||||
renderer_name="qwen3_instruct",
|
||||
model_name="Qwen/Qwen3-30B-A3B-Instruct-2507",
|
||||
log_path="logs/hello",
|
||||
max_tokens=32,
|
||||
store_address="http://localhost:4747",
|
||||
)
|
||||
asyncio.run(entrypoint(config))
|
||||
|
||||
|
||||
def run_rollout(*, worker_id: int) -> None:
|
||||
"""Rollout runner, single-process."""
|
||||
tracer = agl.AgentOpsTracer()
|
||||
|
||||
runner = agl.LitAgentRunner[str](tracer=tracer)
|
||||
|
||||
console.print(f"[bold green]Runners:[/bold green] Rollout runner {worker_id} started.")
|
||||
|
||||
store = agl.LightningStoreClient("http://localhost:4747")
|
||||
with runner.run_context(agent=hello, store=store, worker_id=worker_id):
|
||||
asyncio.run(runner.iter())
|
||||
|
||||
|
||||
def spawn_runners(*, n_runners: int) -> None:
|
||||
"""Spawn a set of rollout runners in separate processes.
|
||||
|
||||
Args:
|
||||
n_runners: The number of runners to spawn.
|
||||
"""
|
||||
|
||||
runners = [
|
||||
multiprocessing.Process(target=run_rollout, kwargs={"worker_id": worker_id}) for worker_id in range(n_runners)
|
||||
]
|
||||
for runner in runners:
|
||||
runner.start()
|
||||
|
||||
for runner in runners:
|
||||
runner.join()
|
||||
|
||||
|
||||
def oneclick(ci: bool = False):
|
||||
"""Run integrated training with algorithm and runners in one process.
|
||||
|
||||
This is the simplest way to run the example, as it handles spawning
|
||||
the store, algorithm, and runners automatically.
|
||||
|
||||
Args:
|
||||
ci: Whether to run in CI mode. Fast verification.
|
||||
"""
|
||||
if ci:
|
||||
# Use smaller batch size and group size for faster verification.
|
||||
batch_size = 4
|
||||
group_size = 2
|
||||
else:
|
||||
batch_size = 16
|
||||
group_size = 4
|
||||
|
||||
config = Config(
|
||||
learning_rate=1e-5,
|
||||
dataset_builder=AGLDatasetBuilder(
|
||||
batch_size=batch_size,
|
||||
group_size=group_size,
|
||||
seed=42,
|
||||
n_epochs=1,
|
||||
),
|
||||
renderer_name="qwen3_instruct",
|
||||
model_name="Qwen/Qwen3-30B-A3B-Instruct-2507",
|
||||
log_path="logs/hello",
|
||||
max_tokens=32,
|
||||
llm_proxy_port=_find_available_port(),
|
||||
)
|
||||
trainer = agl.Trainer(
|
||||
algorithm=Tinker(config),
|
||||
llm_proxy=agl.LLMProxy(
|
||||
port=12306,
|
||||
num_retries=3,
|
||||
# Must use thread mode here because otherwise the Tinker sampling client will hang.
|
||||
launch_mode="thread",
|
||||
),
|
||||
n_runners=8,
|
||||
port=_find_available_port(),
|
||||
)
|
||||
|
||||
if ci:
|
||||
# For faster verification, use a smaller dataset.
|
||||
train_dataset = [str(i) for i in range(16)]
|
||||
val_dataset = [str(i) for i in range(100, 108)]
|
||||
else:
|
||||
train_dataset = [str(i) for i in range(1000)]
|
||||
val_dataset = [str(i) for i in range(1000, 1024)]
|
||||
trainer.fit(hello, train_dataset=train_dataset, val_dataset=val_dataset)
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point for the hello example script."""
|
||||
parser = argparse.ArgumentParser(description="Train a hello echo agent with Agent-lightning + Tinker.")
|
||||
parser.add_argument("mode", type=str, choices=["algo", "runner", "oneclick"])
|
||||
parser.add_argument("--ci", action="store_true", help="Run in CI mode. Fast verification.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.ci:
|
||||
if args.mode != "oneclick":
|
||||
raise ValueError("CI mode only supports oneclick mode.")
|
||||
|
||||
agl.setup_logging()
|
||||
if args.mode == "algo":
|
||||
run_algo()
|
||||
elif args.mode == "runner":
|
||||
spawn_runners(n_runners=8)
|
||||
elif args.mode == "oneclick":
|
||||
oneclick(ci=args.ci)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user