15.2 Agent Platform Pipelines with KFP: Components, Templates & Caching
Key Takeaways
- Agent Platform Pipelines runs pipelines defined with the Kubeflow Pipelines SDK v2.0 or later or the TFX SDK v0.30.0 or later, serverlessly.
- Execution caching reuses a step's outputs from ML Metadata when its inputs, output definitions, and component specification match a previous run of a pipeline with the same name.
- Pipelines default to the slow failure policy, which keeps running other tasks after one fails; the fast policy stops scheduling new tasks.
- Pipeline templates can be versioned in an Artifact Registry Kubeflow Pipelines repository and reused across teams.
- Pipeline runs can be scheduled with the scheduler API using cron expressions, or triggered by events such as Pub/Sub messages through Cloud Run functions.
The exam guide lists building and orchestrating pipelines using managed or unmanaged services and from templates or custom solutions (for example, Agent Platform Pipelines, Managed Service for Apache Airflow, and Ray on Gemini Enterprise Agent Platform). This section covers the managed ML-native option, Agent Platform Pipelines (formerly Vertex AI Pipelines). Chapter 16 covers Managed Airflow and Ray.
What a Pipeline Is
An ML pipeline is a directed acyclic graph (DAG) of containerized tasks connected by input-output dependencies. You define it in Python with the Kubeflow Pipelines (KFP) SDK v2+ or the TFX SDK v0.30+, compile it to a YAML intermediate representation, and run it serverlessly. Tasks run in parallel by default unless one depends on another's outputs.
| SDK | Choose when |
|---|---|
| KFP | Most workflows: any framework, custom components, Google Cloud Pipeline Components |
| TFX | TensorFlow workflows processing terabytes of structured or text data with TFX components |
Components
| Type | How you build it | Use when |
|---|---|---|
| Lightweight Python component | Decorate a function with @dsl.component(base_image=..., packages_to_install=[...]) | Small Python steps |
| Container component | Point at your own image with a command and arguments | Heavy dependencies, non-Python code, reused training images |
| Google Cloud Pipeline Components (GCPC) | Import prebuilt operators | Calling Google Cloud services without writing API code |
Useful GCPC operators
| Area | Operators |
|---|---|
| Data | BigqueryQueryJobOp, DataflowPythonJobOp, DataflowFlexTemplateJobOp, DataprocPySparkBatchOp (Managed Spark), TabularDatasetCreateOp, ImageDatasetCreateOp |
| Training | CustomTrainingJobOp, HyperparameterTuningJobRunOp, AutoMLTabularTrainingJobRunOp, AutoMLImageTrainingJobRunOp, BigqueryCreateModelJobOp |
| Evaluation | ModelBatchPredictOp, ModelEvaluationClassificationOp, ModelEvaluationRegressionOp, ModelEvaluationForecastingOp, BigqueryEvaluateModelJobOp |
| Registry and serving | ModelUploadOp, EndpointCreateOp, ModelDeployOp, ModelUndeployOp |
| Operations | VertexNotificationEmailOp, WaitGcpResourcesOp |
A Minimal Training Pipeline
from kfp import dsl, compiler
from google_cloud_pipeline_components.v1.custom_job import CustomTrainingJobOp
from google_cloud_pipeline_components.v1.model import ModelUploadOp
@dsl.component(base_image="python:3.11", packages_to_install=["google-cloud-bigquery"])
def check_row_count(table: str, min_rows: int) -> bool:
from google.cloud import bigquery
n = list(bigquery.Client().query(f"SELECT COUNT(*) n FROM `{table}`").result())[0].n
return n >= min_rows
@dsl.pipeline(name="churn-training")
def pipeline(project: str, table: str):
ok = check_row_count(table=table, min_rows=100000)
with dsl.If(ok.output == True):
train = CustomTrainingJobOp(project=project, display_name="churn-train",
worker_pool_specs=[...])
...
compiler.Compiler().compile(pipeline, "churn_pipeline.yaml")
Control flow includes dsl.If (conditions), dsl.ParallelFor (fan-out), and dsl.ExitHandler (always run a final step, such as a notification).
Running Pipelines
job = aiplatform.PipelineJob(
display_name="churn-training",
template_path="churn_pipeline.yaml",
pipeline_root="gs://ml-pipelines/churn",
parameter_values={"project": "p", "table": "ds.features"},
enable_caching=True,
failure_policy="fast")
job.submit(experiment="churn-experiments")
pipeline_rootis the Cloud Storage location for artifacts.- Run as a service account with least-privilege access to data and services.
- Tasks can request machine types and accelerators, use persistent resources, read Secret Manager secrets, and run over Private Service Connect networking.
- Adding the run to an experiment makes runs comparable (Chapter 6).
Execution Caching
Before running a step, the service checks ML Metadata for a previous execution with the same cache key:
- The step's inputs (parameter values and input artifact IDs)
- Its output definitions
- The component specification (image, command, arguments, environment variables)
Only pipelines with the same pipeline name share the cache. On a match, the step is skipped and its outputs reused. Cached results have no TTL. They last until the metadata entry is deleted.
- Turn caching off for a task with
task.set_caching_options(False), or for the whole run withenable_caching=False. - Components must be deterministic. A step that reads "latest data" through a fixed query string may be wrongly skipped, because its inputs look identical. Pass a date or snapshot parameter, or turn off caching for that step.
Failure Handling
| Setting | Behavior |
|---|---|
failure_policy="slow" (default) | Keep running other tasks after one fails, until all have been executed |
failure_policy="fast" | Stop scheduling new tasks after a failure. Running tasks finish |
| Task retries | Retry transient failures, such as quota or network errors |
dsl.ExitHandler | Always send a notification or clean up |
Templates and Reuse
A pipeline template publishes a compiled pipeline for reuse. Upload templates with the KFP registry client to an Artifact Registry Kubeflow Pipelines repository, with versions and tags. Teams then create runs from a template without seeing the source. The Template Gallery also offers Google-authored templates and components, such as AutoML for tabular classification and regression.
Scheduling and Triggers
| Trigger | Mechanism |
|---|---|
| Time-based | Scheduler API with cron expressions. Schedules can be ACTIVE, PAUSED (resume with optional catch-up of missed runs), or COMPLETED |
| New data in BigQuery | Eventarc trigger that starts a pipeline when a job inserts into a table |
| Pub/Sub message | A Cloud Run function triggered by Pub/Sub submits the PipelineJob |
| Code change | Cloud Build CI/CD (Chapter 17) |
| Monitoring alert | A drift or performance alert publishes to Pub/Sub, which triggers retraining (Chapter 17) |
Lineage, Logs, and Cost
- Every run records ML Metadata lineage automatically: artifacts, executions, and parameters.
- Task logs go to Cloud Logging. The console links each step to its underlying job.
- Pipeline costs include the orchestration charge per run plus the resources each task uses. Labels help attribute costs.
A daily pipeline's preprocessing step reads SELECT * FROM ds.events_latest with no changing parameters. After new data arrives, the step is skipped and yesterday's outputs are reused. Why?
A team wants a pipeline to stop scheduling new tasks immediately when any task fails, to avoid wasting resources. What should they set?
Several data science teams need to reuse a standardized, versioned training pipeline without copying its source code. What should the platform team do?