Add and update existing vertex skills (#4467)

* Add and update existing vertex skills

- Add support for fine tuning for 1p gemini tuning
- Add support for deploying fine tuned model support
- Add support for running inference on MaaS models
- Add open model support for regions and cost estimating for 3p tuning

* fixing some of the commit errors

* updated scripts to use existing gemini 1.5 pro model

* swap gemini 1.5 pro to gemini 2.5 pro
This commit is contained in:
vincentkt-google
2026-03-11 19:45:42 +00:00
committed by GitHub
parent 8b4708c606
commit 86674effee
23 changed files with 2184 additions and 213 deletions
+301
View File
@@ -0,0 +1,301 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
---
name: Vertex AI Model Garden Deploy
description: Deploy open models or custom weights to Vertex AI endpoints.
---
# Vertex AI Model Garden Deploy Skill
This skill provides instructions for deploying Open Models from Vertex AI Model
Garden to endpoints, and subsequently undeploying them to clean up resources.
## 1. Prerequisites
Before deploying, ensure you have the correct project and region set. The
commands below use placeholder variables `PROJECT_ID` and `LOCATION_ID`.
Ensure you are authenticated:
```bash
gcloud auth login
gcloud auth application-default login
gcloud config set project $PROJECT_ID`
```
## 2. Discovering Deployable Models
You can list models available in Model Garden and check if they can be
self-deployed.
```bash
gcloud ai model-garden models list
```
To see what machine types and accelerators are supported for a specific model
(e.g., `google/gemma3@gemma-3-27b-it`):
```bash
gcloud ai model-garden models list-deployment-config \
--model="google/gemma3@gemma-3-27b-it"
```
> [!NOTE] Some models, especially Hugging Face models, might require a Hugging
> Face Access Token for deployment.
> [!TIP] **Model Recommendation Instructions:** If a user asks to deploy a model
> but **does not specify which one**, you should recommend a model based on
> their use case (e.g., Llama 3.3 70B for general purpose or Gemma 3 for
> lightweight tasks). * You **MUST** ensure you are recommending the **latest
> version** or **popular version** of the suggested model family. * You **MUST**
> verify the model is currently deployable using `gcloud ai model-garden models
> list` before suggesting it to the user.
## 3. Deploying a Model
> [!WARNING] Deploying models, especially large ones, consumes significant
> compute resources and incurs costs. 1. You **MUST** refer to
> [Vertex AI prediction pricing](https://cloud.google.com/vertex-ai/pricing#prediction-and-explanation)
> to calculate a rough cost estimation based on the requested `--machine-type`
> and `--accelerator-type` (and count). 2. You **MUST** present this cost
> estimation to the user and warn them that this is the **list price**, which
> may differ from their actual bill due to potential discounts or reservations.
> 3. You **MUST ALWAYS** request explicit confirmation from the user agreeing to
> the estimated cost before executing any `deploy` command.
To deploy a model, use the `deploy` command. It is highly recommended to use the
`--asynchronous` flag for long-running deployments, and then poll the status if
necessary.
### Example: Deploying Gemma 3
Here is a typical bash script to deploy a model. You can run this block
directly.
```bash
#!/bin/bash
# Example script to deploy a model from Model Garden
PROJECT_ID=$(gcloud config get-value project)
LOCATION_ID="us-central1" # Recommended default region
MODEL_ID="google/gemma3@gemma-3-27b-it" # Replace with your chosen model ID
echo "Deploying model $MODEL_ID to project $PROJECT_ID in $LOCATION_ID..."
# Model Garden can automatically select the required hardware based on the list-deployment-config if hardware params are omitted.
# Below is a comprehensive command with all supported parameters:
gcloud ai model-garden models deploy \
--project=$PROJECT_ID \
--region=$LOCATION_ID \
--model=$MODEL_ID \
--machine-type="g2-standard-48" \
--accelerator-type="NVIDIA_L4" \
--accelerator-count=4 \
--endpoint-display-name="my-gemma-deployment" \
--hugging-face-access-token="YOUR_HF_TOKEN" \
--reservation-affinity="reservation-affinity-type=specific-reservation,key=compute.googleapis.com/reservation-name,values=my-reservation" \
--asynchronous
echo "Deployment initiated asynchronously."
echo "Check the Google Cloud Console (Vertex AI -> Online Prediction) for status."
```
### Example: Deploying Custom Weights
To deploy a model using custom weights, you can use the exact same `deploy`
command. Instead of providing the model garden model ID, provide the Google
Cloud Storage (GCS) URI to your custom weights folder in the `--model` flag.
```bash
#!/bin/bash
# Example script to deploy a model with custom weights from a GCS bucket
PROJECT_ID=$(gcloud config get-value project)
LOCATION_ID="us-central1"
# Replace with the gs:// URI pointing to your custom weights
MODEL_GCS_URI="gs://your-bucket-name/path/to/custom-weights"
echo "Deploying custom model from $MODEL_GCS_URI to project $PROJECT_ID in $LOCATION_ID..."
gcloud ai model-garden models deploy \
--project=$PROJECT_ID \
--region=$LOCATION_ID \
--model=$MODEL_GCS_URI \
--machine-type="g2-standard-12" \
--accelerator-type="NVIDIA_L4" \
--endpoint-display-name="my-custom-model" \
--asynchronous
echo "Deployment initiated asynchronously."
```
## 4. Checking Deployment Status
When you deploy a model asynchronously using the `--asynchronous` flag, the
`deploy` command will return an operation ID. You can use this ID to check the
ongoing status of the deployment.
```bash
gcloud ai operations describe YOUR_OPERATION_ID \
--region=$LOCATION_ID
```
> [!NOTE] As an agent, you can also offer to check the status of a deployment
> for the user if they provide an operation ID or if they just initiated the
> deployment with you.
Alternatively, you can list your endpoints to see if it shows up and check the
Cloud Console under the "Online prediction" tab.
```bash
gcloud ai endpoints list \
--region=$LOCATION_ID
```
Note: Large models (like Llama 3.1 8B or Gemma 27B) may take 15-20 minutes to
fully deploy and start serving.
### Verifying Deployment
If the model is successfully deployed, verify by making a prediction call to
test. Because Model Garden models are often deployed to Dedicated Endpoints, you
shouldn't use `gcloud ai endpoints predict`. Instead, you must fetch the
endpoint's dedicated DNS name and send a `curl` request.
> [!TIP] Ask the user to try using their own prompt to see the results.
> Otherwise use the default.
Use the following script:
```bash
#!/bin/bash
PROJECT_ID=$(gcloud config get-value project)
LOCATION_ID="us-central1"
ENDPOINT_ID="YOUR_ENDPOINT_ID"
PROMPT=${1:-"Explain quantum computing in simple terms."}
echo "Fetching dedicated Endpoint DNS..."
ENDPOINT_URL=$(gcloud ai endpoints describe $ENDPOINT_ID --project=$PROJECT_ID --region=$LOCATION_ID --format="value(dedicatedEndpointDns)")
if [ -z "$ENDPOINT_URL" ]; then
echo "Error: Could not retrieve a dedicated endpoint URL. Verify your ENDPOINT_ID."
exit 1
fi
echo "Sending prediction request to $ENDPOINT_URL..."
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://${ENDPOINT_URL}/v1beta1/projects/${PROJECT_ID}/locations/${LOCATION_ID}/endpoints/${ENDPOINT_ID}/chat/completions" \
-d '{
"model": "'"$ENDPOINT_ID"'",
"messages": [
{
"role": "user",
"content": "'"$PROMPT"'"
}
]
}'
```
## 5. Undeploying and Cleaning Up
To stop incurring charges, you must undeploy the model from the endpoint. This
is a multi-step process if you don't already have the exact endpoint and
deployed model IDs.
### Example: Finding and Undeploying a Model
Here is a bash script demonstrating how to find the IDs and undeploy the model.
```bash
#!/bin/bash
# Example script to undeploy a model
PROJECT_ID=$(gcloud config get-value project)
LOCATION_ID="us-central1"
# The model ID used during deployment (without the provider prefix sometimes, or exactly as listed in describe)
# It's usually easier to find the specific ID via `gcloud ai models list`
# For this example, let's assume we know the exact Endpoint ID and Deployed Model ID.
# 1. Find the Endpoint ID
echo "Listing endpoints in $LOCATION_ID:"
gcloud ai endpoints list --project=$PROJECT_ID --region=$LOCATION_ID
# (Assuming you extracted ENDPOINT_ID from the above output)
# ENDPOINT_ID="your_endpoint_id"
# 2. Find the Deployed Model ID
echo "Listing models in $LOCATION_ID to find model description:"
gcloud ai models list --project=$PROJECT_ID --region=$LOCATION_ID
# (Assuming you found the specific MODEL_ID)
# MODEL_ID="your_model_id"
# gcloud ai models describe $MODEL_ID --project=$PROJECT_ID --region=$LOCATION_ID
# (Extract the deployedModelId from the output)
# DEPLOYED_MODEL_ID="your_deployed_model_id"
# 3. Undeploy
# Uncomment and replace the variables below to actually perform the undeployment
# echo "Undeploying model $DEPLOYED_MODEL_ID from endpoint $ENDPOINT_ID..."
# gcloud ai endpoints undeploy-model $ENDPOINT_ID \
# --project=$PROJECT_ID \
# --region=$LOCATION_ID \
# --deployed-model-id=$DEPLOYED_MODEL_ID
#
# echo "Model undeployed."
# 4. Delete Endpoint
# echo "Deleting endpoint $ENDPOINT_ID..."
# gcloud ai endpoints delete $ENDPOINT_ID \
# --project=$PROJECT_ID \
# --region=$LOCATION_ID \
# --quiet
# echo "Endpoint deleted."
# 5. Delete Model
# echo "Deleting model $MODEL_ID..."
# gcloud ai models delete $MODEL_ID \
# --project=$PROJECT_ID \
# --region=$LOCATION_ID \
# --quiet
# echo "Model deleted."
```
> [!WARNING] Failing to undeploy a model will result in continuous charges for
> the allocated compute resources, even if you are not sending prediction
> requests. Always clean up after testing.
## 6. Troubleshooting
### Deployment Failure: Quota or Resource Exhausted
If your deployment fails (or stays in an error state) due to `QUOTA_EXCEEDED` or
`RESOURCE_EXHAUSTED` errors, the specific hardware requested (e.g., `NVIDIA_L4`
or `g2-standard-24`) is either not available in your chosen region or exceeds
your project's quota limits.
**Solution:** Look closely at the error message returned. It will often
recommend an alternative region or machine type that currently has availability.
**Ask the user for confirmation** to retry the deployment using the suggested
`--region` or `--machine-type` parameters.
> [!WARNING] If the alternative suggestions involve changing the machine type or
> accelerator, you **MUST** recalculate the estimated cost using
> [Vertex AI prediction pricing](https://cloud.google.com/vertex-ai/pricing#prediction-and-explanation),
> warn the user about list prices versus actual billing, and get their explicit
> confirmation for the new cost before retrying the deployment.
+246
View File
@@ -0,0 +1,246 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
---
name: Vertex AI GenAI Inference
description: Instructions for connecting to and performing inference with Google Cloud Vertex AI GenAI models, including Gemini and OpenMaaS (Llama, DeepSeek, Qwen, etc.).
---
# Vertex AI GenAI Inference Skill
This skill provides instructions for authenticating and connecting to Google Cloud Vertex AI to use Generative AI models. It covers both First-Party (Gemini) and Third-Party (OpenMaaS) models.
> [!TIP]
> **Sample Scripts**: This skill includes fully functional sample scripts in the `scripts/` directory (e.g., `scripts/openmaas_openai_sdk.py`). When running these scripts, **ALWAYS** create and use a local virtual environment:
> ```bash
> python3 -m venv .venv && source .venv/bin/activate
> pip install -r scripts/requirements.txt
> ```
>
> **Verify All Scripts**: You can run all scripts at once to verify your setup:
> ```bash
> ./scripts/verify_all.sh
> ```
> [!IMPORTANT]
> **CRITICAL: Model IDs & Availability**
> * **Gemini Models**: See [Gemini Models](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/migrate) for valid Model IDs and Regions.
> * **OpenMaaS Models**: See [Use Open Models on Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/maas/use-open-models) for Llama, DeepSeek, Qwen, etc.
> * **Incomplete Lists**: The Model IDs listed in this skill are **examples only** and may be incomplete or outdated.
> * **Action**: Always verify the Model ID and Region using the links above before generating code.
## 1. Authentication (CRITICAL)
Before running any code, ensure you are authenticated with Application Default Credentials (ADC) and have the necessary API enabled.
1. **Login**:
```bash
gcloud auth application-default login
```
2. **Enable API** (if not already enabled):
```bash
gcloud services enable aiplatform.googleapis.com
```
## 2. Gemini Models
For Gemini models (e.g., `gemini-1.5-pro`, `gemini-2.0-flash`), the **GenAI SDK** (`google-genai`) is the **PREFERRED** method. The legacy `vertexai` SDK is still supported but GenAI SDK is recommended for new projects.
> [!IMPORTANT]
> **Preview Models (including Gemini 2.0)** are often **ONLY** available in the `global` region. Stable models are available in `us-central1` and other regions.
### Choosing the Right SDK
* **Gemini Models**: **GenAI SDK** (`google-genai`) is **PREFERRED**. Use OpenAI SDK for compatibility, or Legacy SDK (`vertexai`) if needed.
* **OpenMaaS Models**: **OpenAI SDK** is **HIGHLY RECOMMENDED**. Use GenAI SDK or Legacy SDK if you have specific infrastructure requirements.
### Installation
```bash
pip install google-genai
```
### Python Example (GenAI SDK - Preferred)
See [`scripts/gemini_genai_sdk.py`](scripts/gemini_genai_sdk.py) for the complete code.
### Alternative: OpenAI SDK (Chat Completions)
Use the standard OpenAI SDK with the Vertex AI endpoint. This is great for cross-compatibility.
See [`scripts/gemini_openai_sdk.py`](scripts/gemini_openai_sdk.py) for the complete code.
### Legacy: Vertex AI SDK
The legacy `vertexai` SDK is still widely used but `google-genai` is preferred for new Gemini projects.
See [`scripts/gemini_vertexai_sdk.py`](scripts/gemini_vertexai_sdk.py) for the complete code.
**Documentation**: [Google GenAI SDK](https://github.com/googleapis/python-genai)
**Documentation**: [Vertex AI Gemini Models](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models)
## 3. OpenMaaS Models (Llama, DeepSeek, Qwen, etc.)
For OpenMaaS (Model-as-a-Service) models, the **HIGHLY RECOMMENDED** approach is to use the standard **OpenAI SDK** with a specific Vertex AI endpoint.
> [!WARNING]
> While `GenerativeModel` *can* support some OpenMaaS models, it is **discouraged**. Use the OpenAI SDK for best compatibility (especially for Chat Completions).
### Installation
```bash
pip install openai google-auth
```
### Authentication for OpenAI SDK
You **MUST** use a Google Cloud OAuth access token as the API key for the OpenAI SDK.
```python
import google.auth
from google.auth.transport.requests import Request
def get_gcp_access_token():
creds, _ = google.auth.default()
creds.refresh(Request())
return creds.token
> [!NOTE]
> Google Cloud access tokens typically expire after 1 hour. The `get_gcp_access_token()` function above retrieves a *fresh* token at the time it is called.
> For long-running applications, you implement a refresh mechanism. See [Refresh the access token](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/openai-sdk-auth#refresh-token) for details.
```
### Configuration (Base URL)
- **Global Endpoint** (Recommended for most models requiring global availability):
`https://aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/global/endpoints/openapi`
- **Regional Endpoint**:
`https://{REGION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{REGION}/endpoints/openapi`
### Python Example (OpenMaaS - Chat Completions)
See [`scripts/openmaas_openai_sdk.py`](scripts/openmaas_openai_sdk.py) for the complete code.
> [!TIP]
> **Alternative: Environment Variables**
> You can set environment variables in your shell instead of updating the code.
> ```bash
> export OPENAI_BASE_URL="https://aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/global/endpoints/openapi"
> export OPENAI_API_KEY="$(gcloud auth print-access-token)"
> ```
> Then initialize the client without arguments: `client = OpenAI()`
### Python Example (OpenMaaS - Completions API)
The following models support the legacy Completions API: `zai-org/glm-5-maas`, `moonshotai/kimi-k2-thinking-maas`, `minimaxai/minimax-m2-maas`, `deepseek-ai/deepseek-v3.1-maas`, and `deepseek-ai/deepseek-v3.2-maas`.
```python
response = client.completions.create(
model="deepseek-ai/deepseek-v3.2-maas",
prompt="Once upon a time",
max_tokens=100
)
print(response.choices[0].text)
```
### Python Example (OpenMaaS - Embeddings)
```python
# Verify specific Embedding Model ID on Model Garden (e.g., intfloat/multilingual-e5-small)
response = client.embeddings.create(
model="intfloat/multilingual-e5-large-maas",
input="The quick brown fox jumps over the lazy dog",
)
print(response.data[0].embedding)
```
### Alternative: GenAI SDK
The `google-genai` SDK can also access OpenMaaS models via the `vertexai` backend.
See [`scripts/openmaas_genai_sdk.py`](scripts/openmaas_genai_sdk.py) for the complete code.
> [!IMPORTANT]
> **Model ID Format**: For GenAI SDK with OpenMaaS, you **MUST** use the full path: `publishers/PUBLISHER/models/MODEL` (e.g., `publishers/zai-org/models/glm-5-maas`).
### Legacy: Vertex AI SDK (OpenMaaS)
For OpenMaaS, you can also use `GenerativeModel` (if supported).
See [`scripts/openmaas_vertexai_sdk.py`](scripts/openmaas_vertexai_sdk.py) for the complete code.
> [!IMPORTANT]
> **Model ID Format**: For Vertex AI SDK with OpenMaaS, you **MUST** use the full path: `publishers/PUBLISHER/models/MODEL`.
### Model Reference & Availability
**Documentation**: [Use Open Models on Vertex AI](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/maas/use-open-models)
> [!TIP]
> **Self-Deployment for Control**: If you need **dedicated hardware** (GPUs/TPUs), **guaranteed capacity**, or **specific regional placement** not offered by MaaS, you can **Self-Deploy** these models to Vertex AI Endpoints. Search for the model in Model Garden and click "Deploy" to select your machine type.
> [!IMPORTANT]
> **Finding Inference Examples**: The list above is a starting point. For the **definitive** inference snippets (especially for Chat Completions payload structure):
> 1. Consult the [Use Open Models on Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/maas/use-open-models) list.
> 2. Click the link for your specific model (e.g., "DeepSeek-V3") to visit its **Model Garden** page.
> 3. Look for the **"Sample Code"** or **"Use this model"** button on the Model Garden page to get the exact `curl` or Python code for that specific model version.
> [!NOTE]
> This list is **INCOMPLETE**. See [Use Open Models on Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/maas/use-open-models) for the full list of supported models.
| Model Family | Model ID Examples | Location | Notes |
| :--- | :--- | :--- | :--- |
| **Llama 4** | `meta/llama-4-maverick-17b-128e-instruct-maas` | `us-east5` | |
| **Llama 4** | `meta/llama-4-scout-17b-16e-instruct-maas` | `us-east5` | |
| **Llama 3.3** | `meta/llama-3.3-70b-instruct-maas` | `us-central1` | |
| **DeepSeek** | `deepseek-ai/deepseek-v3.2-maas` | `global` | Global ONLY |
| **DeepSeek** | `deepseek-ai/deepseek-v3.1-maas` | `us-west2` | US-West2 ONLY |
| **DeepSeek** | `deepseek-ai/deepseek-r1-0528-maas` | `us-central1` | |
| **Qwen 3** | `qwen/qwen3-coder-480b-a35b-instruct-maas` | `global` | |
| **Qwen 3** | `qwen/qwen3-next-80b-a3b-instruct-maas` | `global` | |
| **Kimi** | `moonshotai/kimi-k2-thinking-maas` | `global` | |
| **MiniMax** | `minimaxai/minimax-m2-maas` | `global` | |
| **GLM** | `zai-org/glm-4.7-maas`, `zai-org/glm-5-maas` | `global` | |
## 4. Troubleshooting & Common Error Codes
### 429: Resource Exhausted
* **Cause**: OpenMaaS and Gemini models use **Dynamic Shared Quota (DSQ)**. Resources are pooled and allocated dynamically based on availability. A 429 error indicates the shared pool is temporarily exhausted, not necessarily that *your* specific project quota is hit (though it can be).
* **Solution**: Implement strict **exponential backoff and retry** strategies.
* **High Throughput**: For production workloads requiring high throughput or guaranteed capacity, consider **Provisioned Throughput (PT)**.
* **Important**: Quota increases through normal cloud processes (Cloud Console) are **NOT** applicable for DSQ constraints.
* **Documentation**: [Quotas and limits (DSQ)](https://cloud.google.com/vertex-ai/generative-ai/docs/quotas)
### 400: User Validation Error
* **Cause**: Invalid request format, unsupported parameter, or incorrect Model ID.
* **Action**: Double-check your request payload and parameters. Verify the Model ID and Region are correct.
### 404: Not Found / Model Not Available
* **Cause**: The model is not enabled, or not available in the specified project or region.
* **Action**:
1. **Check Location Availability**:
* **OpenMaaS**: Verify the model is available in your region. See [Model Availability by Location](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#genai-open-models).
* **Gemini**:
* **Source of Truth**: Always check [Gemini Model Locations](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#google-models) for the authoritative list.
* **Preview Models**: All Preview models (e.g., Gemini 2.0, experimental versions) are often **ONLY** available in the `us-central1` or `global` regions.
* **Stable Models**: (e.g., Gemini 1.5 Pro) Available in `us-central1`, `europe-west4`, and many other regions.
* **Important**: If you get a 404/400 error, try switching your client location to `us-central1` or `global`.
2. **Enable Llama Models**: For **Llama 3.3** and **Llama 4**, you **MUST** enable the model in Model Garden before use. Go to the [Model Garden](https://console.cloud.google.com/vertex-ai/model-garden), search for the model card (e.g., "Llama 3.3 API Service"), and click **Enable**. Only then can you make inference requests.
@@ -0,0 +1,28 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from google import genai
import google.auth
# Get default project ID from environment
_, project_id = google.auth.default()
# Initialize GenAI Client with Vertex AI backend
# Use location="global" for Preview models (Gemini 2.0)
client = genai.Client(vertexai=True, project=project_id, location="us-central1")
response = client.models.generate_content(
model="gemini-2.5-pro", contents="Why is the sky blue?"
)
print(response.text)
@@ -0,0 +1,38 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import google.auth
from google.auth.transport.requests import Request
from openai import OpenAI
def get_gcp_access_token():
creds, _ = google.auth.default()
creds.refresh(Request())
return creds.token
# Get default project ID from environment
_, project_id = google.auth.default()
client = OpenAI(
base_url=f"https://aiplatform.googleapis.com/v1/projects/{project_id}/locations/us-central1/endpoints/openapi",
api_key=get_gcp_access_token(),
)
response = client.chat.completions.create(
model="google/gemini-2.5-pro",
messages=[{"role": "user", "content": "Why is the sky blue?"}],
)
print(response.choices[0].message.content)
@@ -0,0 +1,26 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import google.auth
import vertexai
from vertexai.generative_models import GenerativeModel
# Get default project ID from environment
_, project_id = google.auth.default()
vertexai.init(project=project_id, location="us-central1")
model = GenerativeModel("gemini-2.5-pro")
response = model.generate_content("Why is the sky blue?")
print(response.text)
@@ -0,0 +1,32 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from google import genai
import google.auth
# Get default project ID from environment
_, project_id = google.auth.default()
client = genai.Client(
vertexai=True,
project=project_id,
location="global", # OpenMaaS models are often global
)
# Note: For GenAI SDK/Vertex with OpenMaaS, you MUST use the full path: `publishers/PUBLISHER/models/MODEL`
response = client.models.generate_content(
model="publishers/zai-org/models/glm-5-maas",
contents="Explain quantum computing in simple terms.",
)
print(response.text)
@@ -0,0 +1,45 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import google.auth
from google.auth.transport.requests import Request
from openai import OpenAI
def get_gcp_access_token():
creds, _ = google.auth.default()
creds.refresh(Request())
return creds.token
# Get default project ID from environment
_, project_id = google.auth.default()
client = OpenAI(
base_url=f"https://aiplatform.googleapis.com/v1/projects/{project_id}/locations/global/endpoints/openapi",
api_key=get_gcp_access_token(),
)
# NOTE: For OpenMaaS models, you MUST use the format: `publisher/model`
# Example: `deepseek-ai/deepseek-v3.2-maas`, `zai-org/glm-5-maas` etc.
response = client.chat.completions.create(
model="zai-org/glm-5-maas",
messages=[{
"role": "user",
"content": "Explain quantum computing in simple terms.",
}],
)
print(response.choices[0].message.content)
@@ -0,0 +1,27 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import google.auth
import vertexai
from vertexai.generative_models import GenerativeModel
# Get default project ID from environment
_, project_id = google.auth.default()
vertexai.init(project=project_id, location="global")
# Important: Use the full resource path: `publishers/PUBLISHER/models/MODEL`
model = GenerativeModel("publishers/zai-org/models/glm-5-maas")
response = model.generate_content("Explain quantum computing.")
print(response.text)
@@ -0,0 +1,4 @@
google-genai
google-cloud-aiplatform
openai
google-auth
+55
View File
@@ -0,0 +1,55 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash
set -e
# Create a temporary directory for the virtual environment
VENV_DIR=$(mktemp -d -t venv_verify.XXXXXX)
python3 -m venv "$VENV_DIR"
source "$VENV_DIR/bin/activate"
# Trap to ensure cleanup happens on exit
cleanup() {
echo "Cleaning up virtual environment..."
deactivate 2>/dev/null || true
rm -rf "$VENV_DIR"
}
trap cleanup EXIT
echo "Installing requirements..."
pip install -q -r scripts/requirements.txt
echo "Running verification tests..."
FAILED=0
# Iterate directly over the files in the scripts directory
for script in scripts/*.py; do
echo "Running $script..."
if python3 "$script" > /dev/null 2>&1; then
echo " PASS: $script"
else
echo " FAIL: $script"
python3 "$script" # Run again to show output
FAILED=1
fi
done
if [ $FAILED -eq 0 ]; then
echo "All scripts passed verification!"
exit 0
else
echo "Some scripts failed verification."
exit 1
fi
+72
View File
@@ -0,0 +1,72 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Vertex AI Model Tuning Skill
This skill allows agents to fine-tune Large Language Models (LLMs) using
Vertex AI's managed tuning service. It encapsulates the workflow for data
preparation, job submission, monitoring, and model deployment.
## Setup
### 1. Clone the repo
Add instruction here with the correct repo handle
> git clone repo-link
### 2. Installing Agent Skills
Install the skill to your favorite AI assisted coding tool.
- [Antigravity](https://antigravity.google/docs/skills#:~:text=and%20follows%20them.-,Where%20skills%20live,-Antigravity%20supports%20two)
- [Gemini CLI](https://geminicli.com/docs/cli/skills/#managing-skills)
- [Claude Code](https://code.claude.com/docs/en/skills#where-skills-live)
#### Verification
To confirm the installation was successful ask:
> "What skills do you have?"
The agent should respond with a list including your newly added skill
`vertex-tuning` alongside its default capabilities.
## Getting started
Try the following prompt to get started:
> "I want to fine-tune a Llama 3.1 8B model for text classification on Vertex.
Can you help me with this?"
## Features
* **Data Preparation**: Converts and validates datasets (JSONL format) for Vertex AI.
* **Model Tuning**: Submits tuning jobs for supported models (Llama, Gemma,
Qwen, etc.) with customizable hyperparameters (PEFT/Full).
* **Model Deployment**: Deploys tuned models to Vertex AI Endpoints for serving.
* **Guidance**: Provides recommendations for models and hyperparameters based on the task and dataset.
## Directory Structure
* `scripts/`: Python scripts for each stage of the workflow.
* `prepare_dataset.py`: Converts, splits, and validates datasets.
* `tune_model.py`: Submits the tuning job to Vertex AI.
* `deploy_model.py`: Deploys the tuned model to an endpoint.
* `references/`: Documentation and catalogs.
* `models.md`: Supported models, hardware requirements, and hyperparameter baselines.
* `data_prep.md`: Data formatting guidelines.
* `tuning_guide.md`: Detailed tuning advice.
+37 -200
View File
@@ -1,212 +1,49 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
---
name: vertex-tuning
description: >
Vertex AI Model Tuning. Use when you need to fine-tune models
using Vertex AI's infrastructure.
Vertex AI Model Tuning Router. Use this skill when the user wants to fine-tune
models using Vertex AI. This skill routes to either vertex-tuning-open-model
or vertex-tuning-gemini.
---
# Vertex AI Model Tuning
# Vertex AI Model Tuning (Router)
## Overview
This skill provides procedural knowledge for fine-tuning Large Language Models
(LLMs) using Vertex AI's tuning service. It covers the entire lifecycle from
environment setup and data preparation to job configuration, monitoring, and
deployment.
This skill acts as a router for Vertex AI tuning tasks. The tuning procedures
for Open Models and Gemini Models differ significantly. Your first step is to
determine which category the user intends to tune and then read the
corresponding sub-skill.
## Workflow Decision Tree
1. **Environment Check**: Has the environment (Auth, APIs, IAM, Venv) been
initialized?
1. **Model Category**: Has the user explicitly stated whether they want to tune
an **Open Model** or a **Gemini Model**?
- **No** → Go to [Phase 0: Environment & IAM Setup](#phase-0).
- **Yes** → Proceed.
2. **Dataset Status**: Is the dataset ready in JSONL format and uploaded to
GCS?
- **No** → Go to [Phase 1: Dataset Preparation & Upload](#phase-1).
- **Yes** → Proceed.
3. **Configuration**: Have the target model and hyperparameters been decided?
- **No** → Go to [Phase 2: Recommendations & Configuration](#phase-2).
- **Yes** → Proceed.
4. **Job Status**: Has the tuning job been submitted?
- **No** → Go to
[Phase 3: Tuning Job Execution](#phase-3-tuning-job-execution).
- **Yes** → Proceed.
5. **Job Completion**: Is the tuning job complete?
- **No** → Go to [Phase 4: Monitoring](#phase-4-monitoring).
- **Yes** → Proceed.
6. **Deployment**: Has the tuned model been deployed to an endpoint?
- **No** → Go to [Phase 5: Model Deployment](#phase-5-model-deployment).
- **Yes** → Task Complete.
--------------------------------------------------------------------------------
## Phase 0: Environment & IAM Setup {#phase-0}
Ensure the foundational environment is ready before proceeding.
### 0.1 Authentication & Project Context
- Check if `gcloud` CLI is installed. If it is not installed, prompt the user
for permission to install it before proceeding.
- Verify `gcloud auth list`. If not authenticated, run `gcloud auth login`.
- Ensure `project` and `location` are known. Use `gcloud config get project`
to retrieve the current project (and `gcloud config get compute/region` for
region).
- **CRITICAL: Ask for Confirmation.** You must prompt the user to confirm the
retrieved project and region before proceeding, in case they want to switch
to a different one.
### 0.2 Enable APIs
Ensure `aiplatform.googleapis.com` and `storage.googleapis.com` are enabled.
`bash gcloud services enable aiplatform.googleapis.com storage.googleapis.com
--project=YOUR_PROJECT`
### 0.3 IAM Permissions
Verify the following identities have the required roles.
- **Vertex AI Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com`
- **Managed OSS Fine Tuning Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-vertex-moss-ft.iam.gserviceaccount.com`
- **User Identity**: The account running the commands.
### 0.4 Virtual Environment
Create and use a virtual environment named `tuning_agent_venv` in the home
directory. Install dependencies from `references/requirements.txt`. `bash
python3 -m venv ~/tuning_agent_venv source ~/tuning_agent_venv/bin/activate pip
install -r references/requirements.txt`
--------------------------------------------------------------------------------
## Phase 1: Dataset Preparation & Upload {#phase-1}
Vertex AI requires valid JSONL format in GCS.
### 1.0 Dataset Discovery & Confirmation
- **Ask the User First:** Ask the user if they already have a dataset they
want to use.
- **Auto-Discovery:** If the user does not have a dataset, search the
authenticated project's GCS buckets to find if any existing file has a
reasonable dataset that can do the job the user prompted initially.
- **CRITICAL: Ask for Confirmation.** Do not proceed with dataset preparation
or upload until you present the found or provided dataset to the user and
they confirm the dataset to use.
### 1.1 Formatting & Validation
- **Conversion**: If data is in CSV or JSON, use `vertex-tuning/scripts/prepare_dataset.py`
to convert.
- **Validation Split Confirmation**: If the user only provides a training
dataset, **you must prompt the user** to seek permission to split the
training dataset 80/20 to form a validation dataset (using
`--validation_split 0.2`). If they agree, proceed with the split. If they
decline, just use the training dataset without a validation dataset.
- **Validation**: If data is already in JSONL, validate it before uploading:
`bash python3 vertex-tuning/scripts/prepare_dataset.py
\ --input my_data.jsonl \ --format messages \ --validate_only`
- Refer to [Data Preparation Guide](references/data_prep.md) for required
schemas.
### 1.2 Upload
Upload formatted `.jsonl` files to GCS using a unique directory (e.g., with a
datetime timestamp) to avoid overwriting outputs from different runs.
```bash
gcloud storage cp dataset.jsonl gs://YOUR_BUCKET/tuning_agent_job_<datetime>/dataset.jsonl
```
--------------------------------------------------------------------------------
## Phase 2: Recommendations & Configuration {#phase-2}
Help the user choose the best model and parameters. **Always seek user
confirmation before submitting the job.**
### 2.1 Model Selection
- If the user does not specify a model in their prompt, recommend a model
based on the user's prompt by referencing the
[Models Catalog](references/models.md).
- **Prompt for Confirmation:** Present the recommended model to the user and
ask for their confirmation.
### 2.2 Hyperparameters
- If the user does not specify hyperparameters, recommend `tuning_mode`,
`epochs`, `learning_rate`, and `adapter_size` based on the
[Tuning Guide](references/tuning_guide.md) and model-specific baselines in
the [Models Catalog](references/models.md).
- **Prompt for Confirmation:** Present the recommended hyperparameter
configuration to the user and ask for their approval before proceeding to
job submission.
--------------------------------------------------------------------------------
## Phase 3: Tuning Job Execution
Submit the job using `scripts/tune_model.py`.
```bash
python3 scripts/tune_model.py \
--project YOUR_PROJECT \
--location YOUR_LOCATION \
--bucket YOUR_STAGING_BUCKET \
--base_model BASE_MODEL_ID \
--train_dataset gs://YOUR_BUCKET/tuning_agent_job_<datetime>/dataset.jsonl \
--output_uri gs://YOUR_BUCKET/tuning_agent_job_<datetime>/output \
--epochs EPOCHS \
--learning_rate LR \
--tuning_mode MODE
```
--------------------------------------------------------------------------------
## Phase 4: Monitoring
Monitor the job via the Cloud Console link provided in the script output or by
polling the job status.
--------------------------------------------------------------------------------
## Phase 5: Model Deployment
Once the job is `SUCCEEDED`, deploy the model using `scripts/deploy_model.py`.
```bash
python3 vertex_tuning/scripts/deploy_model.py \
--project YOUR_PROJECT \
--location YOUR_LOCATION \
--artifacts_uri gs://YOUR_BUCKET/tuning_agent_job_<datetime>/output/postprocess/node-0/checkpoints/final \
--machine_type MACHINE_TYPE \
--accelerator_type ACCELERATOR_TYPE \
--accelerator_count COUNT
```
Refer to [Models Catalog](references/models.md) for hardware recommendations.
--------------------------------------------------------------------------------
## Resources
- [Data Preparation Guide](references/data_prep.md)
- [Models Catalog](references/models.md)
- [Tuning Guide](references/tuning_guide.md)
- `scripts/prepare_dataset.py`: Data conversion & validation.
- `scripts/tune_model.py`: Job submission.
- `scripts/deploy_model.py`: Model deployment.
- **No** → **STOP**. Ask the user if they want to tune an Open Model or a
Gemini Model. Do not proceed or recommend any specific models until this
is confirmed.
- **Yes** (Open Model) → The user wants to tune an Open Model. Stop
reading this file and IMMEDIATELY read the skill instructions located at
`open-model/SKILL.md`. Follow the instructions inside that skill to
complete the task.
- **Yes** (Gemini Model) → The user wants to tune a Gemini Model. Stop
reading this file and IMMEDIATELY read the skill instructions located at
`gemini/SKILL.md`. Follow the instructions inside that skill to complete
the task.
+207
View File
@@ -0,0 +1,207 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
---
name: vertex-tuning-gemini
description: >
Vertex AI Gemini Model Tuning. Use when you need to fine-tune Gemini models
using Vertex AI's infrastructure.
---
# Vertex AI Gemini Model Tuning
## Overview
This skill provides procedural knowledge for fine-tuning Gemini Large Language
Models using Vertex AI's tuning service. It covers the entire lifecycle from
environment setup and data preparation to job configuration, monitoring, and
deployment.
## Workflow Decision Tree
1. **Environment Check**: Has the environment (Auth, APIs, IAM, Venv) been
initialized?
- **No** → Go to [Phase 0: Environment & IAM Setup](#phase-0).
- **Yes** → Proceed.
2. **Dataset Status**: Is the dataset ready in JSONL format and uploaded to
GCS?
- **No** → Go to [Phase 1: Dataset Preparation & Upload](#phase-1).
- **Yes** → Proceed.
3. **Configuration**: Have the target Gemini model and hyperparameters been
decided?
- **No** → Go to
[Phase 2: Model Configuration & Recommendation](#phase-2).
- **Yes** → Proceed.
4. **Job Status**: Has the tuning job been submitted?
- **No** → Go to
[Phase 3: Tuning Job Execution](#phase-3-tuning-job-execution).
- **Yes** → Proceed.
5. **Job Completion**: Is the tuning job complete?
- **No** → Go to [Phase 4: Monitoring](#phase-4-monitoring).
- **Yes** → Proceed.
6. **Deployment**: Has the tuned model been deployed (if required)?
- **No** → Go to [Phase 5: Model Deployment](#phase-5-model-deployment).
- **Yes** → Task Complete.
--------------------------------------------------------------------------------
## Phase 0: Environment & IAM Setup {#phase-0}
Ensure the foundational environment is ready before proceeding.
### 0.1 Authentication & Project Context
- Check if `gcloud` CLI is installed. If it is not installed, prompt the user
for permission to install it before proceeding.
- Verify `gcloud auth list`. If not authenticated, run `gcloud auth login`.
- Ensure `project` and `location` are known. Use `gcloud config get project`
to retrieve the current project (and `gcloud config get compute/region` for
region).
- **CRITICAL: Ask for Confirmation.** You must prompt the user to confirm the
retrieved project and region before proceeding, in case they want to switch
to a different one.
### 0.2 Enable APIs
Ensure `aiplatform.googleapis.com` and `storage.googleapis.com` are enabled.
```bash
gcloud services enable aiplatform.googleapis.com storage.googleapis.com --project=YOUR_PROJECT
```
### 0.3 IAM Permissions
Verify the following identities have the required roles.
- **Vertex AI Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com`
- **Managed OSS Fine Tuning Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-vertex-moss-ft.iam.gserviceaccount.com`
- **User Identity**: The account running the commands.
### 0.4 Virtual Environment
Create and use a virtual environment named `tuning_agent_venv` in the home
directory. Install dependencies from `references/requirements.txt`.
```bash
python3 -m venv ~/tuning_agent_venv
source ~/tuning_agent_venv/bin/activate
pip install -r references/requirements.txt
```
--------------------------------------------------------------------------------
## Phase 1: Dataset Preparation & Upload {#phase-1}
Vertex AI requires valid JSONL format in GCS.
### 1.0 Dataset Discovery & Confirmation
- **Ask the User First:** Ask the user if they already have a dataset they
want to use.
- **Auto-Discovery:** If the user does not have a dataset, search the
authenticated project's GCS buckets to find if any existing file has a
reasonable dataset that can do the job the user prompted initially.
- **CRITICAL: Ask for Confirmation.** Do not proceed with dataset preparation
or upload until you present the found or provided dataset to the user and
they confirm the dataset to use.
### 1.1 Formatting & Validation
- **Conversion**: If data is in CSV or JSON, use `scripts/prepare_dataset.py`
to convert.
- **Validation**: If data is already in JSONL, validate it before uploading:
`bash python3 scripts/prepare_dataset.py \ --input my_data.jsonl \ --format
messages_gemini \ --validate_only`
- Refer to [Data Preparation Guide](references/data_prep.md) for required
schemas.
### 1.2 Upload
Upload formatted `.jsonl` files to GCS using a unique directory (e.g., with a
datetime timestamp) to avoid overwriting outputs from different runs.
```bash
gcloud storage cp dataset.jsonl gs://YOUR_BUCKET/tuning_agent_job_<datetime>/dataset.jsonl
```
--------------------------------------------------------------------------------
## Phase 2: Model Configuration & Recommendation {#phase-2}
Help the user choose the best Gemini model and parameters.
**Always seek user confirmation before submitting the job.**
- If the user does not specify a specific model in their prompt, calculate
recommendations based on the **Models Catalog**.
- **Prompt for Confirmation:** Present the recommended model to the user and
ask for their confirmation before configuring hyperparameters.
### 2.1 Configuration
- *Hyperparameter recommendation guidelines and options for Gemini models will
be populated here.*
- **Prompt for Confirmation:** Present the proposed configuration to the user
and ask for their approval before proceeding.
--------------------------------------------------------------------------------
## Phase 3: Tuning Job Execution {#phase-3-tuning-job-execution}
Submit the Gemini model tuning job using `scripts/tune_gemini_model.py`.
```bash
python3 scripts/tune_gemini_model.py
```
--------------------------------------------------------------------------------
## Phase 4: Monitoring {#phase-4-monitoring}
Monitor the job via the Cloud Console link provided in the script output or by
polling the job status.
--------------------------------------------------------------------------------
## Phase 5: Model Deployment {#phase-5-model-deployment}
Once the Gemini model tuning job is `SUCCEEDED`, deploy the model using
`scripts/deploy_gemini_model.py`.
```bash
python3 scripts/deploy_gemini_model.py
```
--------------------------------------------------------------------------------
## Resources
- [Data Preparation Guide](references/data_prep.md)
- [Models Catalog](references/models.md)
- [Tuning Guide](references/tuning_guide.md)
- `scripts/prepare_dataset.py`: Data conversion & validation.
- `scripts/tune_gemini_model.py`: Gemini model tuning job submission.
- `scripts/deploy_gemini_model.py`: Gemini model deployment.
+261
View File
@@ -0,0 +1,261 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
---
name: vertex-tuning-open-model
description: >
Vertex AI Open Model Tuning. Use when you need to fine-tune open models
using Vertex AI's infrastructure.
---
# Vertex AI Open Model Tuning
## Overview
This skill provides procedural knowledge for fine-tuning Open Large Language
Models (LLMs) using Vertex AI's tuning service. It covers the entire lifecycle
from environment setup and data preparation to job configuration, monitoring,
and deployment.
## Workflow Decision Tree
1. **Environment Check**: Has the environment (Auth, APIs, IAM, Venv) been
initialized?
- **No** → Go to [Phase 0: Environment & IAM Setup](#phase-0).
- **Yes** → Proceed.
2. **Dataset Status**: Is the dataset ready in JSONL format and uploaded to
GCS?
- **No** → Go to [Phase 1: Dataset Preparation & Upload](#phase-1).
- **Yes** → Proceed.
3. **Configuration**: Have the target open model and hyperparameters been
decided?
- **No** → Go to
[Phase 2: Model Configuration & Recommendation](#phase-2).
- **Yes** → Proceed.
4. **Job Status**: Has the tuning job been submitted?
- **No** → Go to
[Phase 3: Tuning Job Execution](#phase-3-tuning-job-execution).
- **Yes** → Proceed.
5. **Job Completion**: Is the tuning job complete?
- **No** → Go to [Phase 4: Monitoring](#phase-4-monitoring).
- **Yes** → Proceed.
6. **Deployment**: Has the tuned model been deployed (if required)?
- **No** → Go to [Phase 5: Model Deployment](#phase-5-model-deployment).
- **Yes** → Task Complete.
--------------------------------------------------------------------------------
## Phase 0: Environment & IAM Setup {#phase-0}
Ensure the foundational environment is ready before proceeding.
### 0.1 Authentication & Project Context
- Check if `gcloud` CLI is installed. If it is not installed, prompt the user
for permission to install it before proceeding.
- Verify `gcloud auth list`. If not authenticated, run `gcloud auth login`.
- Ensure `project` and `location` are known. Use `gcloud config get project`
to retrieve the current project (and `gcloud config get compute/region` for
region).
- **CRITICAL: Ask for Confirmation.** You must prompt the user to confirm the
retrieved project and region before proceeding, in case they want to switch
to a different one.
### 0.2 Possible Locations
The following locations are available for tuning:
- us-central1
- europe-west4
- us-west1
- us-east5
- asia-southeast1
No other values are supported for this section, ensure that the location is
listed above.
### 0.3 Enable APIs
Ensure `aiplatform.googleapis.com` and `storage.googleapis.com` are enabled.
```bash
gcloud services enable aiplatform.googleapis.com storage.googleapis.com --project=YOUR_PROJECT
```
### 0.4 IAM Permissions
Verify the following identities have the required roles.
- **Vertex AI Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com`
- **Managed OSS Fine Tuning Service Agent**:
`service-PROJECT_NUMBER@gcp-sa-vertex-moss-ft.iam.gserviceaccount.com`
- **User Identity**: The account running the commands.
### 0.5 Virtual Environment
Create and use a virtual environment named `tuning_agent_venv` in the home
directory. Install dependencies from `references/requirements.txt`.
```bash
python3 -m venv ~/tuning_agent_venv
source ~/tuning_agent_venv/bin/activate
pip install -r references/requirements.txt
```
--------------------------------------------------------------------------------
## Phase 1: Dataset Preparation & Upload {#phase-1}
Vertex AI requires valid JSONL format in GCS.
### 1.0 Dataset Discovery & Confirmation
- **Ask the User First:** Ask the user if they already have a dataset they
want to use.
- **Auto-Discovery:** If the user does not have a dataset, search the
authenticated project's GCS buckets to find if any existing file has a
reasonable dataset that can do the job the user prompted initially.
- **CRITICAL: Ask for Confirmation.** Do not proceed with dataset preparation
or upload until you present the found or provided dataset to the user and
they confirm the dataset to use.
### 1.1 Formatting & Validation
- **Conversion**: If data is in CSV or JSON, use `scripts/prepare_dataset.py`
to convert.
- **Validation Split Confirmation**: If the user only provides a training
dataset, **you must prompt the user** to seek permission to split the
training dataset 80/20 to form a validation dataset (using
`--validation_split 0.2`). If they agree, proceed with the split. If they
decline, just use the training dataset without a validation dataset.
- **Validation**: If data is already in JSONL, validate it before uploading:
`bash python3 scripts/prepare_dataset.py \ --input my_data.jsonl \ --format
messages \ --validate_only`
- Refer to [Data Preparation Guide](references/data_prep.md) for required
schemas.
### 1.2 Upload
Upload formatted `.jsonl` files to GCS using a unique directory (e.g., with a
datetime timestamp) to avoid overwriting outputs from different runs.
```bash
gcloud storage cp dataset.jsonl gs://YOUR_BUCKET/tuning_agent_job_<datetime>/dataset.jsonl
```
--------------------------------------------------------------------------------
## Phase 2: Model Configuration & Recommendation {#phase-2}
Help the user choose the best open model and parameters.
**Always seek user confirmation before submitting the job.**
- If the user does not specify a specific model in their prompt, calculate
recommendations based on the **Models Catalog**.
- **Prompt for Confirmation:** Present the recommended model to the user and
ask for their confirmation before configuring hyperparameters.
### 2.1 Configuration
- Recommend `tuning_mode`, `epochs`, `learning_rate`, and `adapter_size` based
on the [Tuning Guide](references/tuning_guide.md) and model-specific
baselines in the [Models Catalog](references/models.md).
### 2.2 Calculating Cost
- We can calculate a rough estimate of cost of tuning based on the dataset and
the selected model in the [Models Catalog](references/models.md):
```bash
python3 \
open-model/scripts/calculate_cost.py \
--input my_data.jsonl \
--model MODEL_NAME \
--tuning_mode TUNING_MODE \
--epochs EPOCHS
```
- **Prompt for Confirmation:** Present the recommended hyperparameter
configuration and estimated cost to the user and ask for their approval
before proceeding to job submission. Make sure to note that the estimated
cost is just an estimate and can vary from actual billing costs.
--------------------------------------------------------------------------------
## Phase 3: Tuning Job Execution {#phase-3-tuning-job-execution}
Submit the open model tuning job using `scripts/tune_open_model.py`. Identify
the model id using available models documentation at
[documentation](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/open-model-tuning#supported-models).
```bash
python3 scripts/tune_open_model.py \
--project YOUR_PROJECT \
--location YOUR_LOCATION \
--bucket YOUR_STAGING_BUCKET \
--base_model BASE_MODEL_ID \
--train_dataset gs://YOUR_BUCKET/tuning_agent_job_<datetime>/dataset.jsonl \
--output_uri gs://YOUR_BUCKET/tuning_agent_job_<datetime>/output \
--epochs EPOCHS \
--learning_rate LR \
--tuning_mode MODE
```
--------------------------------------------------------------------------------
## Phase 4: Monitoring {#phase-4-monitoring}
Monitor the job via the Cloud Console link provided in the script output or by
polling the job status.
--------------------------------------------------------------------------------
## Phase 5: Model Deployment {#phase-5-model-deployment}
Once the open model tuning job is `SUCCEEDED`, deploy the model using
`scripts/deploy_open_model.py`.
```bash
python3 scripts/deploy_open_model.py \
--project YOUR_PROJECT \
--location YOUR_LOCATION \
--artifacts_uri gs://YOUR_BUCKET/tuning_agent_job_<datetime>/output/postprocess/node-0/checkpoints/final \
--machine_type MACHINE_TYPE \
--accelerator_type ACCELERATOR_TYPE \
--accelerator_count COUNT
```
Refer to [Models Catalog](references/models.md) for hardware recommendations for
specific open models.
--------------------------------------------------------------------------------
## Resources
- [Data Preparation Guide](references/data_prep.md)
- [Models Catalog](references/models.md)
- [Tuning Guide](references/tuning_guide.md)
- `scripts/prepare_dataset.py`: Data conversion & validation.
- `scripts/tune_open_model.py`: Open model tuning job submission.
- `scripts/deploy_open_model.py`: Open model deployment.
@@ -0,0 +1,66 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Data Preparation for Vertex AI Model Tuning
Vertex AI Model Tuning requires training data in **JSON Lines (JSONL)** format
stored in Google Cloud Storage (GCS).
## Supported JSONL Formats for Open Models
### 1. Conversational (Messages) Format
Recommended for chat-based models (Llama 3.1/3.2/3.3 Chat, Gemma 3 IT, etc.).
```json
{
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."}
]
}
```
### 2. Instruction (Prompt/Completion) Format
Suitable for base models or simple completion tasks.
```json
{
"prompt": "Summarize the following text: [TEXT]",
"completion": "[SUMMARY]"
}
```
## Dataset Requirements
- **File Type**: Must be `.jsonl`.
- **Encoding**: UTF-8.
- **Location**: Must be in a GCS bucket (e.g., `gs://my-bucket/train.jsonl`).
- **Validation Split**: A separate validation file is optional but recommended. It must be no more than 25% of the training dataset size.
## Bucket Considerations
If a bucket does not exist, create one in the same region as your tuning job:
```bash
gcloud storage buckets create gs://YOUR_BUCKET_NAME --location=YOUR_LOCATION
```
## Formatting Best Practices
1. **Quality over Quantity**: 100 high-quality examples often outperform 1,000 noisy ones.
2. **Consistency**: Use consistent formatting for system prompts and instruction styles.
3. **No Empty Values**: Ensure every example has a valid prompt/user message and completion/assistant response. Use the [preparation script](../scripts/prepare_dataset.py) to validate this.
@@ -0,0 +1,76 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Vertex AI Supported Models and Recommendations
This reference catalog provides technical specifications, tuning
recommendations, and deployment hardware requirements for supported models in
Vertex AI.
## Supported Models Catalog
> [!WARNING] **CRITICAL AGENT INSTRUCTION**
> Do NOT use this catalog to recommend a specific model to the user until they
> have explicitly confirmed their **Model Category** as Open Model.
Available open models can be found in Google Cloud [documentation](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/open-model-tuning#supported-models).
This is the list of open models that are available for tuning; do not suggest
any other open models besides the one listed here.
Each model has some [limitations](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/open-model-tuning#limitations) for tuning.
## Model Selection Guidelines
**Identify Task**: Check a few samples from the dataset to identify the task.
Choose a model family based on your task type:
- **Qwen**: Best for code generation or complex math-based tasks.
- **Gemma**: Optimized for chat-based interactions, creative writing and multilingual tasks.
- **Llama (Instruct)**: Strong general-purpose chat/instruction models.
- **Llama (Base/Scout)**: Best for continuation tasks or building custom instruction-tuned models.
**Complexity Heuristics**:
- **Simple (QA, Extraction)**: 1B - 3B models.
- **Intermediate (Summarization, Reasoning)**: 8B - 17B models.
- **Complex (Multi-turn, Tool use, Deep reasoning)**: 27B - 70B models.
## Baseline Hyperparameter Recommendations
These values are starting points and should be adjusted based on your dataset
size.
| Model | Tuning Mode | Learning Rate | Epochs | Adapter Size (PEFT) |
| :--- | :--- | :--- | :--- | :--- |
| Gemma 3 1B IT | Full | 2.0E-5 | 3 | N/A |
| Gemma 3 4B IT | Full | 1.0E-5 | 3 | N/A |
| Gemma 3 12B IT | Full | 1.0E-5 | 3 | N/A |
| Gemma 3 27B IT | PEFT | 2.0E-4 | 3 | 32 |
| Gemma 3 27B IT | Full | 2.0E-4 | 3 | N/A |
| Llama 3.1 8B | PEFT | 2.0E-4 | 3 | 16 |
| Llama 3.1 8B | Full | 2.0E-4 | 3 | N/A |
| Llama 3.1 8B Instruct | PEFT | 2.0E-4 | 3 | 16 |
| Llama 3.1 8B Instruct | Full | 2.0E-4 | 3 | N/A |
| Llama 3.2 1B Instruct | Full | 1.5E-6 | 3 | N/A |
| Llama 3.2 3B Instruct | Full | 1.0E-7 | 3 | N/A |
| Llama 3.3 70B Instruct | PEFT | 5.0E-5 | 3 | 16 |
| Llama 3.3 70B Instruct | Full | 5.0E-5 | 3 | N/A |
| Llama 4 Scout 17B 16E | PEFT | 2.0E-5 | 3 | 16 |
| Qwen 3 4B | Full | 7.5e-5 | 3 | N/A |
| Qwen 3 8B | Full | 5e-5 | 3 | N/A |
| Qwen 3 14B | Full | 4e-5 | 3 | N/A |
| Qwen 3 32B | PEFT | 2.0E-4 | 3 | 16 |
| Qwen 3 32B | Full | 2.5e-5 | 3 | N/A |
@@ -0,0 +1,5 @@
google-cloud-aiplatform==1.138.0
numpy==2.4.2
pandas==3.0.1
datasets==2.18.0
smart_open[gcs]==7.5.1
@@ -0,0 +1,55 @@
<!--
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Vertex AI Model Tuning Heuristics and Concepts
This guide details the core concepts of fine-tuning and provides heuristics for
adjusting hyperparameters based on your specific dataset.
## Core Tuning Concepts
### Open Models Tuning Modes
- **FULL**: Updates all parameters of the model. Requires more GPU memory and a larger dataset to avoid catastrophic forgetting.
- **PEFT_ADAPTER**: Parameter-Efficient Fine-Tuning. Only a small set of "adapter" weights are trained. Faster, uses less memory, and is less prone to overfitting on small datasets.
### Hyperparameters
- **Epochs**: Number of times the model sees the entire dataset.
- **Learning Rate**: Step size for optimization. Too high can cause instability; too low can lead to very slow convergence.
- **Adapter Size (Rank)**: For PEFT, this determines the capacity of the adapters. Higher rank allows more complex learning but increases the risk of overfitting.
## Dataset Heuristics
The size and quality of your dataset should dictate your parameter choices. Refer to [Models Catalog](models.md) for baseline values, then adjust as follows:
### 1. Dataset Size Implications
| Dataset Size | Tuning Mode Recommendation | Learning Rate Adjustment | Epochs Recommendation |
| :--- | :--- | :--- | :--- |
| **< 100 examples** | PEFT_ADAPTER (Rank 8) | Lower than baseline | 1-2 |
| **100 - 1000 examples** | PEFT_ADAPTER (Rank 16/32) | Baseline | 3 |
| **> 1000 examples** | FULL or PEFT (Rank 32) | Higher than baseline | 3-5 |
### 2. General Best Practices
- **Overfitting**: If validation loss starts increasing while training loss decreases, you are overfitting. Reduce epochs or decrease the learning rate.
- **Underfitting**: If both training and validation loss remain high, increase the learning rate or use more epochs.
- **Validation**: Always use a validation set to monitor performance. If not provided, a 10-20% split is highly recommended.
- **Checkpoints**: The final model is always saved to `<output_uri>/postprocess/node-0/checkpoints/final`.
## Hardware and Limitations
For specific hardware recommendations and sequence length limits per model, please refer to the [Models Catalog](models.md).
@@ -0,0 +1,169 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Calculate tuning cost for a given dataset and model."""
import argparse
import json
import sys
import smart_open
# Data from
# https://docs.google.com/spreadsheets/d/1pOXzfQBSCaKJYcemvRKv4b30qmUBx3yG28yScH-pnVI/edit?resourcekey=0-0kJGshytd3yrxB41YM4OFg&gid=0#gid=0
MODEL_DATA = {
'Gemma 3 1B IT': {
'Full': {'tokens_per_character': 0.231, 'cost_per_1m_tokens': 0.47},
},
'Gemma 3 4B IT': {
'Full': {'tokens_per_character': 0.231, 'cost_per_1m_tokens': 1.14},
},
'Gemma 3 12B IT': {
'Full': {'tokens_per_character': 0.231, 'cost_per_1m_tokens': 1.82},
},
'Gemma 3 27B IT': {
'PEFT': {'tokens_per_character': 0.231, 'cost_per_1m_tokens': 6.83},
'Full': {'tokens_per_character': 0.231, 'cost_per_1m_tokens': 6.83},
},
'Llama 3.1 8B': {
'PEFT': {'tokens_per_character': 0.317, 'cost_per_1m_tokens': 0.67},
'Full': {'tokens_per_character': 0.247, 'cost_per_1m_tokens': 0.67},
},
'Llama 3.1 8B Instruct': {
'PEFT': {'tokens_per_character': 0.317, 'cost_per_1m_tokens': 0.67},
'Full': {'tokens_per_character': 0.247, 'cost_per_1m_tokens': 0.67},
},
'Llama 3.2 1B Instruct': {
'Full': {'tokens_per_character': 0.247, 'cost_per_1m_tokens': 0.28},
},
'Llama 3.2 3B Instruct': {
'Full': {'tokens_per_character': 0.247, 'cost_per_1m_tokens': 0.61},
},
'Llama 3.3 70B Instruct': {
'PEFT': {'tokens_per_character': 0.317, 'cost_per_1m_tokens': 6.72},
'Full': {'tokens_per_character': 0.247, 'cost_per_1m_tokens': 6.72},
},
'Llama 4 Scout 17B 16E': {
'PEFT': {'tokens_per_character': 0.295, 'cost_per_1m_tokens': 5.77},
},
'Qwen 3 4B': {
'Full': {'tokens_per_character': 0.246, 'cost_per_1m_tokens': 1.35},
},
'Qwen 3 8B': {
'Full': {'tokens_per_character': 0.246, 'cost_per_1m_tokens': 4.18},
},
'Qwen 3 14B': {
'Full': {'tokens_per_character': 0.246, 'cost_per_1m_tokens': 8.46},
},
'Qwen 3 32B': {
'PEFT': {'tokens_per_character': 0.246, 'cost_per_1m_tokens': 6.57},
'Full': {'tokens_per_character': 0.246, 'cost_per_1m_tokens': 6.57},
},
}
def count_characters(input_file: str) -> int:
"""Counts the characters in a jsonl dataset.
It is expected that each line in the jsonl file is a json object
with a "messages" key, which is a list of dictionaries. Each
dictionary in the "messages" list should have a "content" key.
This function counts the characters in the "content" field of each
dictionary in the "messages" list.
Args:
input_file: Path to the input jsonl file.
Returns:
Total character count.
"""
total_character_count = 0
if not input_file.startswith('gs://') and '://' in input_file:
raise ValueError(
f'Unsupported file path: {input_file}. '
'Only local paths and gs:// paths are supported.'
)
with smart_open.smart_open(input_file, 'r') as f:
for line in f:
data = json.loads(line)
for message in data['messages']:
content = message['content']
total_character_count += len(content)
return total_character_count
def calculate_cost(
count: int,
model: str,
tuning_mode: str,
epochs: int,
) -> float:
"""Calculates the tuning cost.
Args:
count: Total character count of the dataset.
model: Model to use for tuning.
tuning_mode: Tuning mode.
epochs: Number of epochs.
Returns:
Estimated tuning cost.
"""
model_data = MODEL_DATA[model][tuning_mode]
tokens_per_character = model_data['tokens_per_character']
cost_per_1m_tokens = model_data['cost_per_1m_tokens']
num_tokens = count * tokens_per_character * epochs
return (num_tokens / 1000000) * cost_per_1m_tokens
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Calculate tuning cost for a given dataset and model.'
)
parser.add_argument('--input_file', help='Input jsonl file.', required=True)
parser.add_argument(
'--model',
help='Model to use for tuning.',
required=True,
choices=MODEL_DATA.keys(),
)
parser.add_argument(
'--tuning_mode',
help='Tuning mode.',
required=True,
choices=['PEFT', 'Full'],
)
parser.add_argument(
'--epochs',
help='Number of epochs.',
required=True,
type=int,
)
args = parser.parse_args()
if (
args.model not in MODEL_DATA
or args.tuning_mode not in MODEL_DATA[args.model]
):
print(
f'Error: Tuning mode {args.tuning_mode} not supported for model'
f' {args.model}'
)
sys.exit(1)
character_count = count_characters(args.input_file)
cost = calculate_cost(
character_count, args.model, args.tuning_mode, args.epochs
)
print(f'Total character count: {character_count}')
print(f'Estimated tuning cost: ${cost:.2f}')
@@ -0,0 +1,64 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for deploying tuned models to Vertex AI endpoints."""
import argparse
import logging
import vertexai # type: ignore
from vertexai.preview import model_garden # type: ignore
def deploy_open_model(
project: str,
location: str,
artifacts_uri: str,
machine_type: str,
accelerator_type: str,
accelerator_count: int,
) -> vertexai.aiplatform.Endpoint:
"""Deploys a tuned model to a Vertex AI endpoint."""
vertexai.init(project=project, location=location)
logging.info("Deploying model from %s...", artifacts_uri)
tuned_model = model_garden.CustomModel(gcs_uri=artifacts_uri)
endpoint = tuned_model.deploy(
machine_type=machine_type,
accelerator_type=accelerator_type,
accelerator_count=accelerator_count,
)
logging.info("Model deployed to endpoint: %s", endpoint.resource_name)
return endpoint
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Deploy Tuned Model to Vertex Endpoint"
)
parser.add_argument("--project", required=True)
parser.add_argument("--location", required=True)
parser.add_argument(
"--artifacts_uri",
required=True,
help="GCS path to postprocess/node-0/checkpoints/final",
)
parser.add_argument("--machine_type", required=True)
parser.add_argument("--accelerator_type", required=True)
parser.add_argument("--accelerator_count", type=int, required=True)
args = parser.parse_args()
deploy_open_model(**vars(args))
+277
View File
@@ -0,0 +1,277 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for preparing and validating datasets for Vertex AI model tuning."""
import argparse
import json
import logging
import os
import sys
from typing import Any
import datasets
def _validate_example(example: dict[str, Any], format_type: str) -> bool:
"""Validates a single example against the expected format."""
if format_type == "messages":
if "messages" not in example or not isinstance(example["messages"], list):
return False
for msg in example["messages"]:
if not all(k in msg for k in ("role", "content")):
return False
if not msg["content"] or str(msg["content"]).strip().lower() == "nan":
return False
else:
if not all(k in example for k in ("prompt", "completion")):
return False
for k in ("prompt", "completion"):
if not example[k] or str(example[k]).strip().lower() == "nan":
return False
return True
def _format_row(
row, format_type: str, prompt_col: str, completion_col: str
) -> dict[str, Any]:
"""Formats a single row into the expected JSON structure."""
prompt_text = str(row[prompt_col])
completion_text = str(row[completion_col])
if format_type == "messages":
return {
"messages": [
{"role": "user", "content": prompt_text},
{"role": "assistant", "content": completion_text},
]
}
return {
"prompt": prompt_text,
"completion": completion_text,
}
def validate_jsonl(file_path: str, format_type: str) -> bool:
"""Validates an existing JSONL file."""
if not os.path.exists(file_path):
logging.error("File not found: %s", file_path)
return False
valid_count = 0
invalid_count = 0
with open(file_path, "r", encoding="utf-8") as f:
for i, line in enumerate(f):
try:
example = json.loads(line)
if _validate_example(example, format_type):
valid_count += 1
else:
invalid_count += 1
logging.warning("Invalid format/empty content at line %d", i + 1)
except json.JSONDecodeError:
invalid_count += 1
logging.warning("Invalid JSON at line %d", i + 1)
logging.info("Validation complete for %s", file_path)
logging.info("Valid: %d, Invalid: %d", valid_count, invalid_count)
return invalid_count == 0
def convert_to_jsonl(
input_file: str,
output_file: str,
format_type: str,
prompt_col: str,
completion_col: str,
validation_split: float | None = 0.2,
):
"""Converts a JSON or CSV file to JSONL format for Vertex AI tuning."""
if not os.path.exists(input_file):
logging.error("Input file not found: %s", input_file)
sys.exit(1)
try:
if input_file.endswith(".csv"):
dataset = datasets.load_dataset(
"csv", data_files=input_file, split="train"
)
elif input_file.endswith(".json"):
dataset = datasets.load_dataset(
"json", data_files=input_file, split="train"
)
elif input_file.endswith(".parquet"):
dataset = datasets.load_dataset(
"parquet", data_files=input_file, split="train"
)
else:
logging.error("Unsupported file format. Use .csv, .json, or .parquet")
sys.exit(1)
except Exception as e: # pylint: disable=broad-exception-caught
logging.exception("Failed to read input file: %s", e)
sys.exit(1)
for col in [prompt_col, completion_col]:
if col not in dataset.column_names:
logging.error(
"Column '%s' not found. Available columns: %s",
col,
dataset.column_names,
)
sys.exit(1)
# Remove rows with empty values in critical columns
def is_valid(example):
prompt_text = str(example[prompt_col]).strip().lower()
completion_text = str(example[completion_col]).strip().lower()
return (
len(prompt_text) > 0
and len(completion_text) > 0
and prompt_text != "nan"
and completion_text != "nan"
and prompt_text != "none"
and completion_text != "none"
)
initial_len = len(dataset)
dataset = dataset.filter(is_valid)
if len(dataset) < initial_len:
logging.warning(
"Dropped %d rows with empty or NaN values", initial_len - len(dataset)
)
def format_example(example):
prompt_text = str(example[prompt_col])
completion_text = str(example[completion_col])
if format_type == "messages":
return {
"messages": [
{"role": "user", "content": prompt_text},
{"role": "assistant", "content": completion_text},
]
}
else:
return {
"prompt": prompt_text,
"completion": completion_text,
}
formatted_dataset = dataset.map(
format_example, remove_columns=dataset.column_names
)
if validation_split and validation_split > 0:
if not (0 < validation_split < 1):
logging.error("validation_split must be between 0 and 1")
sys.exit(1)
# Use the datasets library to perform the split as requested
split_dict = formatted_dataset.train_test_split(
seed=42, test_size=validation_split
)
train_ds = split_dict["train"]
val_ds = split_dict["test"]
val_output_file = output_file.replace(".jsonl", "_validation.jsonl")
if val_output_file == output_file:
val_output_file = output_file + ".validation.jsonl"
train_ds.to_json(output_file, force_ascii=False, lines=True)
val_ds.to_json(val_output_file, force_ascii=False, lines=True)
logging.info(
"Successfully saved %d training examples to %s",
len(train_ds),
output_file,
)
logging.info(
"Successfully saved %d validation examples to %s",
len(val_ds),
val_output_file,
)
else:
formatted_dataset.to_json(output_file, force_ascii=False, lines=True)
logging.info(
"Successfully saved %d examples to %s",
len(formatted_dataset),
output_file,
)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
parser = argparse.ArgumentParser(
description="Prepare or Validate dataset for Vertex AI Model Tuning"
)
parser.add_argument(
"--input",
help="Input CSV, JSON, Parquet, or JSONL file",
)
parser.add_argument(
"--output",
default="tuning_dataset.jsonl",
help="Output JSONL file (only for conversion)",
)
parser.add_argument(
"--format",
choices=["messages", "prompt"],
default="messages",
help="Target format (messages or prompt/completion)",
)
parser.add_argument(
"--prompt_col",
help="Column name for prompt/user message (CSV/JSON/Parquet only)",
)
parser.add_argument(
"--completion_col",
help=(
"Column name for completion/assistant response (CSV/JSON/Parquet"
" only)"
),
)
parser.add_argument(
"--validation_split",
type=float,
default=0.2,
help="Fraction of data to use for validation (e.g. 0.2)",
)
parser.add_argument(
"--validate_only",
action="store_true",
help="Only validate the input JSONL file without converting",
)
args = parser.parse_args()
if args.validate_only:
if not args.input:
logging.error("--input is required for validation")
sys.exit(1)
success = validate_jsonl(args.input, args.format)
sys.exit(0 if success else 1)
else:
if not all([args.input, args.prompt_col, args.completion_col]):
logging.error(
"--input, --prompt_col, and --completion_col are required for"
" conversion"
)
sys.exit(1)
convert_to_jsonl(
args.input,
args.output,
args.format,
args.prompt_col,
args.completion_col,
args.validation_split,
)
+92
View File
@@ -0,0 +1,92 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for launching Vertex AI model tuning jobs."""
import argparse
import logging
import vertexai # type: ignore
from vertexai.tuning import sft # type: ignore
from vertexai.tuning import SourceModel # type: ignore
def tune_open_model(
project: str,
location: str,
bucket: str,
base_model: str,
train_dataset: str,
validation_dataset: str | None,
output_uri: str,
epochs: int,
learning_rate: float,
tuning_mode: str,
adapter_size: int | None = None,
) -> sft.SupervisedTuningJob:
"""Launches a Vertex AI model tuning job."""
vertexai.init(project=project, location=location, staging_bucket=bucket)
source_model = SourceModel(base_model=base_model)
tuning_job = sft.train(
source_model=source_model,
train_dataset=train_dataset,
validation_dataset=validation_dataset if validation_dataset else None,
epochs=epochs,
learning_rate=learning_rate,
tuning_mode=tuning_mode,
adapter_size=adapter_size,
output_uri=output_uri,
labels={"mg-source": "vertex-tuning-skill"},
)
logging.info("Tuning job launched: %s", tuning_job.resource_name)
logging.info(
"View job in console:"
" https://console.cloud.google.com/vertex-ai/locations/%s/tuning-jobs/%s?project=%s",
location,
tuning_job.name,
project,
)
return tuning_job
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Launch Vertex AI Model Tuning Job"
)
parser.add_argument("--project", required=True)
parser.add_argument("--location", required=True)
parser.add_argument("--bucket", required=True)
parser.add_argument("--base_model", required=True)
parser.add_argument("--train_dataset", required=True)
parser.add_argument(
"--validation_dataset", help="Optional validation dataset URI"
)
parser.add_argument("--output_uri", required=True)
parser.add_argument("--epochs", type=int, required=True)
parser.add_argument("--learning_rate", type=float, required=True)
parser.add_argument(
"--tuning_mode", choices=["FULL", "PEFT_ADAPTER"], required=True
)
parser.add_argument(
"--adapter_size",
type=int,
choices=[1, 4, 8, 16, 32],
help="Adapter size for PEFT",
)
args = parser.parse_args()
tune_open_model(**vars(args))
+1 -13
View File
@@ -75,16 +75,4 @@ if __name__ == "__main__":
)
args = parser.parse_args()
tune_model(
project=args.project,
location=args.location,
bucket=args.bucket,
base_model=args.base_model,
train_dataset=args.train_dataset,
validation_dataset=args.validation_dataset,
output_uri=args.output_uri,
epochs=args.epochs,
learning_rate=args.learning_rate,
tuning_mode=args.tuning_mode,
adapter_size=args.adapter_size,
)
tune_model(**vars(args))