Skip to main content
skill CX Codex

ai-pipeline-orchestration — Claude Code skill: AI/ML pipelines

A skill that helps the agent build pipelines for data ingestion, model training, batch inference and RAG indexing on Prefect, Airflow or Dagster.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill ai-pipeline-orchestration -a claude-code
Open on GitHub

What ai-pipeline-orchestration does

The skill covers repeatable, observable workflows for AI systems: document ingestion, batch LLM processing and nightly fine-tuning. It ships working code samples for three orchestrators. For Prefect there is a RAG ingestion flow with cached document fetching and retries around chunking and embeddings, plus a batch inference flow built on AsyncOpenAI with a concurrency limit on API calls. For Airflow there is a weekly fine-tuning DAG where training runs in a Kubernetes pod with GPUs, then evals run and the pipeline fails if quality drops below a threshold.

A selection table maps tools to jobs: Prefect for Python-first projects, Airflow for complex DAGs and larger teams, Dagster for asset-centric work with data lineage, Temporal for long-running workflows. Reach for it when you need to wire dependencies between data prep and model serving, or schedule recurring re-indexing of a knowledge base.

Running the samples needs the orchestrators themselves. Prefect installs with pip install prefect prefect-kubernetes; the Airflow example relies on the Kubernetes provider. The embedding sample pulls in sentence_transformers and the BAAI/bge-large-en-v1.5 model, upserts go to Qdrant, and batch inference calls OpenAI. Check that you have GPU node access and an API key before you copy anything, otherwise those parts will not run.

What it helps with

  • schedule daily re-indexing of documents into a vector store
  • run batch prompt processing through an LLM without hitting rate limits
  • launch weekly model fine-tuning in a Kubernetes pod with GPUs
  • add evals to a pipeline and stop it when quality drops
  • pick an orchestrator for the job: Prefect, Airflow, Dagster or Temporal

Example prompts for the agent

  • build a Prefect flow that re-indexes documents into Qdrant every night
  • I need an Airflow DAG for GPU fine-tuning with metric checks
  • set up batch inference through AsyncOpenAI with a concurrency limit

How to install ai-pipeline-orchestration

1Skills CLI (Vercel)

npx skills add BagelHole/DevOps-Security-Agent-Skills --skill ai-pipeline-orchestration -a claude-code

2Manually: put the files in place

~/.claude/skills/ai-pipeline-orchestration/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/ai-pipeline-orchestration/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about ai-pipeline-orchestration

How do I install ai-pipeline-orchestration in Claude?

Run npx skills add BagelHole/DevOps-Security-Agent-Skills --skill ai-pipeline-orchestration -a claude-code. The skill lands in ~/.claude/skills/ai-pipeline-orchestration/SKILL.md.

What does ai-pipeline-orchestration do?

It gives the agent samples and rules for building AI/ML pipelines: data ingestion, training, batch inference and RAG indexing on Prefect, Airflow or Dagster.

What do the skill's samples require?

Prefect with prefect-kubernetes, the Kubernetes provider for Airflow, sentence_transformers with the BAAI/bge-large-en-v1.5 model, Qdrant, and an OpenAI key for batch inference.

Source text

SKILL.md · MIT
---
name: ai-pipeline-orchestration
description: Orchestrate AI/ML pipelines for data ingestion, model training, batch inference, and RAG indexing using Prefect, Airflow, or Dagster. Build reliable, observable, and retriable workflows for production AI systems.
license: MIT
metadata:
  author: devops-skills
  version: "1.0"
---

# AI Pipeline Orchestration

Build reliable, observable AI workflows — from document ingestion to batch inference to model training pipelines.

## When to Use This Skill

Use this skill when:
- Scheduling recurring RAG document ingestion and re-indexing
- Orchestrating multi-step batch LLM processing workflows
- Running nightly model evaluation and fine-tuning jobs
- Building ETL pipelines that feed into AI models
- Managing dependencies between data preparation and model serving

## Tool Selection

| Tool | Best For | Complexity | GPU Jobs |
|------|----------|------------|----------|
| **Prefect** | Modern Python-first; easy to adopt | Low | Good |
| **Airflow** | Complex DAGs; large teams; existing usage | High | Good |
| **Dagster** | Asset-centric; strong data lineage | Medium | Excellent |
| **Temporal** | Long-running workflows; reliability-first | Medium | Good |

## Prefect — Quick Start

```bash
pip install prefect prefect-kubernetes

# Start Prefect server (or use Prefect Cloud)
prefect server start

# In another terminal
prefect worker start --pool default-agent-pool
```

## Prefect: RAG Ingestion Pipeline

```python
from prefect import flow, task, get_run_logger
from prefect.tasks import task_input_hash
from datetime import timedelta
import hashlib

@task(cache_key_fn=task_input_hash, cache_expiration=timedelta(hours=24))
def fetch_documents(source_url: str) -> list[dict]:
    """Fetch documents from source; cached to avoid re-fetching."""
    logger = get_run_logger()
    logger.info(f"Fetching from {source_url}")
    # ... fetch logic
    return documents

@task(retries=3, retry_delay_seconds=30)
def chunk_and_embed(documents: list[dict]) -> list[dict]:
    """Chunk documents and generate embeddings with retry on failure."""
    from sentence_transformers import SentenceTransformer
    model = SentenceTransformer("BAAI/bge-large-en-v1.5")
    chunks = []
    for doc in documents:
        doc_chunks = chunk_text(doc["content"])
        embeddings = model.encode(doc_chunks, batch_size=64)
        for chunk, emb in zip(doc_chunks, embeddings):
            chunks.append({"text": chunk, "embedding": emb.tolist(),
                           "source": doc["url"], "doc_hash": doc["hash"]})
    return chunks

@task(retries=2)
def upsert_to_vector_store(chunks: list[dict]) -> int:
    """Upsert embeddings to Qdrant, skip unchanged documents."""
    from qdrant_client import QdrantClient
    client = QdrantClient("http://qdrant:6333")
    client.upsert(collection_name="knowledge-base", points=[...])
    return len(chunks)

@flow(name="rag-ingestion", log_prints=True)
def rag_ingestion_pipeline(sources: list[str]):
    """Full RAG ingestion flow — runs daily."""
    logger = get_run_logger()
    total = 0
    for source in sources:
        docs = fetch_documents(source)
        chunks = chunk_and_embed(docs)
        count = upsert_to_vector_store(chunks)
        total += count
        logger.info(f"Ingested {count} chunks from {source}")
    logger.info(f"Pipeline complete: {total} total chunks indexed")

if __name__ == "__main__":
    rag_ingestion_pipeline.serve(
        name="daily-rag-ingestion",
        cron="0 2 * * *",          # 2 AM daily
        parameters={"sources": ["https://docs.myapp.com", "https://api.myapp.com/kb"]},
    )
```

## Prefect: Batch LLM Inference Pipeline

```python
from prefect import flow, task
from prefect.concurrency.sync import concurrency
import asyncio
from openai import AsyncOpenAI

@task(retries=3, retry_delay_seconds=60)
async def process_batch(items: list[dict], model: str = "gpt-4o-mini") -> list[dict]:
    """Process a batch of items through LLM with rate limit protection."""
    client = AsyncOpenAI()
    async with concurrency("openai-api", occupy=len(items)):  # rate limit
        tasks = [
            client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": item["prompt"]}],
                max_tokens=256,
            )
            for item in items
        ]
        responses = await asyncio.gather(*tasks, return_exceptions=True)

    results = []
    for item, response in zip(items, responses):
        if isinstance(response, Exception):
            results.append({**item, "error": str(response), "output": None})
        else:
            results.append({**item, "output": response.choices[0].message.content})
    return results

@flow(name="batch-llm-inference")
async def batch_inference_flow(input_file: str, output_file: str, batch_size: int = 50):
    import json
    items = [json.loads(line) for line in open(input_file)]
    batches = [items[i:i+batch_size] for i in range(0, len(items), batch_size)]

    all_results = []
    for batch in batches:
        results = await process_batch(batch)
        all_results.extend(results)

    with open(output_file, "w") as f:
        for result in all_results:
            f.write(json.dumps(result) + "\n")
    return len(all_results)
```

## Airflow: Model Training DAG

```python
from airflow.decorators import dag, task
from airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator
from datetime import datetime
from kubernetes.client import models as k8s

@dag(
    dag_id="llm_fine_tuning",
    schedule="@weekly",
    start_date=datetime(2025, 1, 1),
    catchup=False,
    tags=["ai", "training"],
)
def llm_fine_tuning_dag():

    @task
    def prepare_dataset() -> str:
        """Download and preprocess training data."""
        # ... data prep logic
        return "s3://my-bucket/training-data/2025-03-01/"

    train = KubernetesPodOperator(
        task_id="train_model",
        name="llm-training-job",
        namespace="ml",
        image="nvcr.io/nvidia/pytorch:24.05-py3",
        cmds=["accelerate", "launch", "-m", "axolotl.cli.train", "/config/config.yaml"],
        resources=k8s.V1ResourceRequirements(
            limits={"nvidia.com/gpu": "4", "memory": "320Gi"},
            requests={"nvidia.com/gpu": "4"},
        ),
        node_selector={"nvidia.com/gpu.product": "A100-SXM4-80GB"},
        volumes=[...],
        volume_mounts=[...],
        get_logs=True,
        is_delete_operator_pod=True,
    )

    @task
    def evaluate_model(dataset_path: str) -> dict:
        """Run evals; fail pipeline if quality drops."""
        metrics = run_evals()
        if metrics["accuracy"] < 0.85:
            raise ValueError(f"Model quality too low: {metrics}")
        return metrics

    @task
    def deploy_model(metrics: dict):
        """Push merged model to HF Hub and update vLLM config."""
        update_serving_config(new_model="org/fine-tuned-v2")

    dataset = prepare_dataset()
    train.set_upstream(dataset)
    eval_result = evaluate_model(dataset)
    eval_result.set_upstream(train)
    deploy_model(eval_result)

llm_fine_tuning_dag()
```

## Dagster: Asset-Based AI Pipeline

```python
from dagster import asset, AssetExecutionContext, define_asset_job, ScheduleDefinition

@asset(description="Raw documents fetched from knowledge sources")
def raw_documents(context: AssetExecutionContext) -> list[dict]:
    context.log.info("Fetching documents...")
    return fetch_all_documents()

@asset(
    deps=[raw_documents],
    description="Chunked and embedded document vectors",
)
def document_embeddings(context: AssetExecutionContext, raw_documents) -> int:
    chunks = process_and_embed(raw_documents)
    context.log.info(f"Generated {len(chunks)} embeddings")
    upsert_to_qdrant(chunks)
    return len(chunks)

@asset(
    deps=[document_embeddings],
    description="RAG system quality metrics",
)
def rag_quality_metrics(context: AssetExecutionContext) -> dict:
    metrics = evaluate_rag_system()
    context.add_output_metadata({"ragas_score": metrics["ragas_score"]})
    return metrics

# Schedule: refresh embeddings nightly
nightly_refresh = ScheduleDefinition(
    job=define_asset_job("rag_refresh_job", [raw_documents, document_embeddings]),
    cron_schedule="0 1 * * *",
)
```

## Best Practices

- Use task-level retries for API calls; use flow-level retries for transient infra failures.
- Cache expensive steps (embedding generation, data fetching) to speed up reruns.
- Emit custom metrics from pipelines (chunk count, error rate, cost) to your observability stack.
- Use `concurrency` limits in Prefect or `pool` slots in Airflow to respect external rate limits.
- Separate ingestion, training, and deployment pipelines — don't couple them in one giant DAG.

## Related Skills

- [rag-infrastructure](../../../infrastructure/local-ai/rag-infrastructure/) - RAG system setup
- [llm-fine-tuning](../../../infrastructure/local-ai/llm-fine-tuning/) - Training jobs
- [agent-observability](../agent-observability/) - Pipeline monitoring
- [kubernetes-ops](../../orchestration/kubernetes-ops/) - Running pipeline pods on K8s

© devops-skills · MIT · BagelHole/DevOps-Security-Agent-Skills

Similar skills

Everything for AI and ML →

From the same set127

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor