Skip to main content
The scripts are in the repository, not in the installed package. Clone it, then cd recipes/05-export/bedrock-import before running the commands below. Browse this recipe on GitHub.
Take a LoRA adapter you trained, merge it into its base, import the merged weights into your own AWS account with Bedrock Custom Model Import, and measure the served model on the same held-out tasks that scored it on vLLM. The point is the last step: a deployment is only done when the number survives the move. What you will learn: what Bedrock accepts (merged weights, not adapters), which API an imported model answers (InvokeModel, not Converse), what the cold start costs, and how to check the served weights against the training run with a paired interval. You need a Modal account, AWS credentials that can create an S3 bucket, an IAM role and a Bedrock import job, and the text-to-SQL recipe’s Postgres for the measurement. Merge and upload take about six minutes, the import about ten, the 560-sample measurement two.

Run it

The service role trusts Bedrock and reads the one bucket:

What you get

The published run (2026-09-20, us-east-1). The adapter is while-ai/text-to-sql-shop-nemotron-8b-r1, one GRPO round on Nemotron-Nano-8B from the text-to-SQL recipe; the vLLM rows are its eval-nemotron-8b-r1 and eval-nemotron-8b-base files on the Hub, checked in under rows/ so compare.py runs offline.
The served weights are the trained weights: the paired difference between Bedrock and vLLM on the same 140 tasks is five thousandths with an interval that covers zero, and the gain over the base reproduces the published +0.087 as +0.082 with an interval that excludes zero. The verifier was checked first: run locally on the published rows it agrees with every one of the 1,120 published rewards (compare.py --check-published).

What it cost and what to know

Three facts the AWS documentation states in scattered places, checked here:
  • Custom Model Import takes merged weights in the Hugging Face layout (safetensors, config.json, tokenizer files). A separate LoRA adapter is not accepted; merge_upload.py merges it first. Supported architectures include Llama 2 to 3.3, Mistral, Mixtral, Qwen2, Qwen2.5, Qwen3 (Qwen3ForCausalLM and the MoE), GPT-OSS. Regions: us-east-1, us-east-2, us-west-2, eu-central-1.
  • An imported model refuses Converse even on a Llama architecture (“This action doesn’t support the model that you provided”) and answers InvokeModel with the OpenAI chat-completion body. The SDK picks that route from the ARN, so bedrock:<arn>@<region> works anywhere a backend goes. Tool calling on imports is honored for GPT-OSS only.
  • An idle import is unloaded. The SDK waits through the restore (ten tries, fifteen seconds apart) and then says so in one sentence.

Next

  • Serve it to your users from While: register the ARN once and it answers at https://models.withwhile.com/v1 under your While key, from any OpenAI client or wai.Endpoint(name, url=..., api_key=...). The role it assumes is the WhileModelsInvoke shape in Your model and your key:
  • Delete the import when you are done measuring: aws bedrock delete-imported-model --model-identifier <name> --region us-east-1; storage is billed per unit per month.
  • A Qwen3 adapter (while-ai/airline-concise-4b on Qwen/Qwen3-4B-Instruct-2507) takes the same path; its measurement is wai.simulate on the airline tasks rather than rollout.py.
  • The same held-out set on the platform: push the graded rows with wai.export(..., push_to=) and the two runs sit side by side on the Runs page.
Last modified on September 21, 2026