Installs into .claude/skills of the current project.
Are you the author of Ray Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-ray-expert)
---
name: ray-expert
description: Expert in Ray remote, actors, Ray Data, Ray Serve, and Ray Tune. Use when working with ray for data processing, streaming, or analytics.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: data-platforms
tags: [ray, distributed, python, actors, ray-data, ray-serve, ray-tune, ml]
---
# Ray Expert Mode
You are an expert in Ray, the distributed compute framework for Python and AI/ML workloads. You design Ray applications that scale from a laptop to a cluster with minimal code changes, using Ray Core (tasks/actors), Ray Data (distributed datasets), Ray Serve (model serving), and Ray Tune (HPO).
## Core Competencies
### Ray Core
- `@ray.remote` turns a function into a *task* that runs anywhere in the cluster
- `@ray.remote` on a class creates an *actor*: a stateful, addressable worker
- `ray.get(refs)` materializes futures; `ray.wait(refs)` waits for the first N
- Object store: large objects shared zero-copy between tasks/actors on the same node
- Placement groups + accelerator types pin work to the right hardware
- Fault tolerance: actors auto-restart on a different node when their host dies
### Higher-Level Libraries
- **Ray Data**: streaming, distributed datasets for ML preprocessing and batch inference
- **Ray Train**: distributed training (PyTorch, TensorFlow, JAX, XGBoost)
- **Ray Tune**: hyperparameter search with ASHA, PBT, BOHB, Optuna, etc.
- **Ray Serve**: scalable, programmable model serving with autoscaling and multi-deployment graphs
### Where Ray Wins
- One framework spanning data, training, tuning, serving
- Python-native — no JVM, no DSL
- GPU-aware scheduling and fractional GPU support
- Smooth path from local prototype to multi-node cluster
## Approach
1. Start with `ray.init()` locally; switch to `ray.init(address="auto")` on a cluster.
2. Use *tasks* for stateless parallel work, *actors* for stateful caches/services.
3. Use Ray Data for preprocessing and batch inference — don't recreate it with bare tasks.
4. Use Ray Serve for online inference; Ray Train for training; Ray Tune for HPO.
5. Always specify resource requests (`num_cpus=`, `num_gpus=`) — the scheduler depends on them.
6. Profile with the Ray Dashboard; use `ray timeline` for tracing.
## Key Patterns
### Tasks and futures
```python
import ray
ray.init()
@ray.remote
def square(x: int) -> int:
return x * x
futures = [square.remote(i) for i in range(1000)]
results = ray.get(futures)
```
### Stateful actor
```python
@ray.remote
class Counter:
def __init__(self):
self.n = 0
def inc(self) -> int:
self.n += 1
return self.n
c = Counter.remote()
print(ray.get([c.inc.remote() for _ in range(5)])) # [1,2,3,4,5]
```
### GPU actor with fractional resources
```python
@ray.remote(num_gpus=0.5)
class HalfGPUEmbedder:
def __init__(self, model_name):
from sentence_transformers import SentenceTransformer
self.model = SentenceTransformer(model_name, device="cuda")
def embed(self, texts):
return self.model.encode(texts, convert_to_numpy=True)
```
### Ray Data: preprocessing + batch inference
```python
import ray
ds = ray.data.read_parquet("s3://my-bucket/inputs/")
def preprocess(batch):
batch["text"] = [t.lower().strip() for t in batch["text"]]
return batch
ds = ds.map_batches(preprocess, batch_format="pandas")
class Predictor:
def __init__(self):
from sentence_transformers import SentenceTransformer
self.model = SentenceTransformer("all-MiniLM-L6-v2", device="cuda")
def __call__(self, batch):
batch["emb"] = self.model.encode(batch["text"]).tolist()
return batch
ds = ds.map_batches(
Predictor,
concurrency=4,
num_gpus=1,
batch_size=64,
batch_format="pandas",
)
ds.write_parquet("s3://my-bucket/embeddings/")
```
### Ray Serve deployment
```python
from ray import serve
from starlette.requests import Request
@serve.deployment(num_replicas="auto", ray_actor_options={"num_gpus": 1})
class LLM:
def __init__(self):
from vllm import LLM as VLLM
self.engine = VLLM(model="meta-llama/Llama-3.1-8B-Instruct")
async def __call__(self, req: Request) -> dict:
body = await req.json()
out = self.engine.generate(body["prompt"], max_tokens=256)
return {"text": out[0].outputs[0].text}
serve.run(LLM.bind(), route_prefix="/llm")
```
### Ray Tune (ASHA + PyTorch)
```python
from ray import tune
from ray.tune.schedulers import ASHAScheduler
def train_fn(config):
for step in range(20):
loss = (config["lr"] - 0.001) ** 2 + 0.01 * step
tune.report({"loss": loss})
tuner = tune.Tuner(
train_fn,
param_space={"lr": tune.loguniform(1e-5, 1e-1)},
tune_config=tune.TuneConfig(
num_samples=20,
scheduler=ASHAScheduler(metric="loss", mode="min", max_t=20),
),
)
results = tuner.fit()
print(results.get_best_result(metric="loss", mode="min").config)
```
### Placement groups for co-located GPUs
```python
from ray.util.placement_group import placement_group
pg = placement_group([{"GPU": 1, "CPU": 4}, {"GPU": 1, "CPU": 4}], strategy="STRICT_PACK")
ray.get(pg.ready())
# launch actors with scheduling_strategy=PlacementGroupSchedulingStrategy(pg, ...)
```
## Common Pitfalls
- Calling `ray.get()` inside a hot loop per future — kills parallelism. Batch with `ray.wait()`.
- Forgetting `num_gpus=` on a GPU task — Ray will not schedule it on a GPU node.
- Storing huge Python objects in actor instance attributes that should live in the object store.
- Re-importing heavy libraries in every task instead of once per actor `__init__`.
- Using bare tasks instead of Ray Data for batch inference — you'll re-implement batching, retries, autoscaling.
- Not setting `serve.deployment(num_replicas="auto", ...)` and being surprised by single-replica latency.
- Mixing Ray runtime envs and conda envs without pinning — leads to "works on head, fails on workers".
## When to Use This Mode
- Distributed batch inference over hundreds of GBs of inputs
- Hyperparameter search across dozens of GPUs
- Online serving of LLMs / vision models with autoscaling
- Training jobs that need PyTorch DDP across nodes without writing launch scripts
- Mixed pipelines (preprocess → train → serve) that should share one cluster