Files
promptfoo--promptfoo/examples/provider-amazon-sagemaker/deploy-test-model.py
T
wehub-resource-sync 0d3cb498a3
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Waiting to run
Test and Publish Multi-arch Docker Image / test (push) Waiting to run
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Blocked by required conditions
Validate Renovate Config / Validate Renovate Configuration (push) Waiting to run
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

226 lines
7.0 KiB
Python

#!/usr/bin/env python3
"""
SageMaker Deployment Helper Script
This script helps deploy a test model on Amazon SageMaker for testing the promptfoo SageMaker provider.
It uses the Hugging Face integration with SageMaker to deploy models.
Prerequisites:
- AWS CLI configured
- Required Python packages: sagemaker, boto3
- SageMaker execution role with appropriate permissions
Usage:
python deploy-test-model.py --model-id meta-llama/Llama-2-7b-chat-hf --task text-generation
"""
import argparse
import json
import logging
import time
from datetime import datetime
import boto3
# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(description="Deploy a Hugging Face model to SageMaker")
parser.add_argument(
"--model-id",
required=True,
help="Hugging Face model ID (e.g., meta-llama/Llama-2-7b-chat-hf)",
)
parser.add_argument(
"--task",
default="text-generation",
help="Task of the model (default: text-generation)",
)
parser.add_argument(
"--instance-type",
default="ml.g5.2xlarge",
help="SageMaker instance type (default: ml.g5.2xlarge)",
)
parser.add_argument(
"--endpoint-name", help="Custom endpoint name (default: based on model name)"
)
parser.add_argument("--region", help="AWS region (default: from AWS CLI configuration)")
parser.add_argument(
"--role-name",
help="SageMaker execution IAM role name (if not specified, will try to find one)",
)
args = parser.parse_args()
# Get the AWS region
session = boto3.session.Session()
region = args.region or session.region_name
if not region:
logger.error("AWS region not specified and not found in AWS CLI configuration")
raise SystemExit(1)
# Generate endpoint name if not provided
if not args.endpoint_name:
# Extract model name from model ID and create a timestamp
model_name = args.model_id.split("/")[-1].lower()
timestamp = datetime.now().strftime("%m%d%H%M")
args.endpoint_name = f"promptfoo-test-{model_name}-{timestamp}"
# Connect to AWS services
iam = boto3.client("iam", region_name=region)
sagemaker_client = boto3.client("sagemaker", region_name=region)
# Find or get SageMaker execution role
def get_sagemaker_role() -> str:
"""Return the requested role ARN or discover a SageMaker execution role."""
if args.role_name:
try:
role = iam.get_role(RoleName=args.role_name)
return role["Role"]["Arn"]
except Exception as e:
logger.error(f"Error getting specified role: {e}")
raise SystemExit(1)
# Try to find a SageMaker execution role
try:
roles = iam.list_roles()
for role in roles["Roles"]:
if "AmazonSageMaker-ExecutionRole" in role["RoleName"]:
logger.info(f"Found SageMaker role: {role['RoleName']}")
return role["Arn"]
logger.error(
"No SageMaker execution role found. Please specify a role with --role-name"
)
raise SystemExit(1)
except Exception as e:
logger.error(f"Error finding SageMaker role: {e}")
raise SystemExit(1)
role_arn = get_sagemaker_role()
logger.info(f"Using role ARN: {role_arn}")
# Create model
try:
logger.info(f"Creating model: {args.model_id}")
# HuggingFace Container settings
# Find the latest container image for the region
transformers_version = "4.28.1"
pytorch_version = "2.0.0"
python_version = "py310"
hf_container = f"763104351884.dkr.ecr.{region}.amazonaws.com/huggingface-pytorch-tgi:{transformers_version}-transformers{pytorch_version}-cuda11.8-{python_version}"
# Create model
model_name = f"promptfoo-test-model-{int(time.time())}"
# Hub config for text generation interface
hub_config = {"HF_MODEL_ID": args.model_id, "HF_TASK": args.task}
# Generation parameters for text generation models
if args.task == "text-generation":
hub_config["PARAMETERS"] = {
"max_new_tokens": 256,
"temperature": 0.7,
"return_full_text": False,
}
# Create the model
create_model_response = sagemaker_client.create_model(
ModelName=model_name,
PrimaryContainer={
"Image": hf_container,
"Environment": {
"HF_MODEL_ID": args.model_id,
"HF_TASK": args.task,
"HF_MODEL_QUANTIZE": "bitsandbytes", # Optional: for quantization
"SM_NUM_GPUS": "1",
"MAX_INPUT_LENGTH": "2048",
"MAX_TOTAL_TOKENS": "4096",
"HF_HUB_CONFIG": json.dumps(hub_config),
},
},
ExecutionRoleArn=role_arn,
)
logger.info(f"Model created: {model_name}")
# Create endpoint configuration
endpoint_config_name = f"{args.endpoint_name}-config"
logger.info(f"Creating endpoint configuration: {endpoint_config_name}")
sagemaker_client.create_endpoint_config(
EndpointConfigName=endpoint_config_name,
ProductionVariants=[
{
"VariantName": "AllTraffic",
"ModelName": model_name,
"InstanceType": args.instance_type,
"InitialInstanceCount": 1,
}
],
)
# Create endpoint
logger.info(
f"Creating endpoint: {args.endpoint_name} (this will take several minutes)"
)
sagemaker_client.create_endpoint(
EndpointName=args.endpoint_name, EndpointConfigName=endpoint_config_name
)
# Wait for endpoint to be in service
logger.info("Waiting for endpoint to be in service...")
status = None
while status != "InService":
response = sagemaker_client.describe_endpoint(EndpointName=args.endpoint_name)
status = response["EndpointStatus"]
if status == "Failed":
logger.error(
f"Endpoint creation failed: {response.get('FailureReason', 'Unknown reason')}"
)
raise SystemExit(1)
if status != "InService":
logger.info(f"Endpoint status: {status}. Waiting...")
time.sleep(60)
logger.info(f"✅ Endpoint {args.endpoint_name} is now InService!")
logger.info("\nTest with promptfoo using:")
logger.info(
f"""
providers:
- id: sagemaker:{args.task.replace("-", ":")}:{args.endpoint_name}
config:
region: {region}
modelType: {"openai" if "llama" in args.model_id.lower() else "custom"}
maxTokens: 256
temperature: 0.7
"""
)
logger.info("\nOr use the test script:")
logger.info(
f"node test-sagemaker-provider.js --endpoint={args.endpoint_name} --region={region} --model-type={'openai' if 'llama' in args.model_id.lower() else 'custom'}"
)
logger.info(
"\nTo delete this endpoint when done testing (to avoid unnecessary charges):"
)
logger.info(
f"aws sagemaker delete-endpoint --endpoint-name {args.endpoint_name} --region {region}"
)
except Exception as e:
logger.error(f"Error deploying model: {e}")
raise SystemExit(1)