Use Bedrock R&D Profile
Quick reference for invoking Claude via an Ontopix-managed Bedrock application inference profile. Shared R&D only.
Audience: Engineers (primary) and AI agents (secondary) doing R&D or internal experimentation with Claude on AWS Bedrock.
Rule of thumb: If your code contains anthropic.claude-* as a Bedrock modelId, you are doing it wrong. Use an application inference profile ARN instead — always.
Why? See ADR-0007. Short version: raw model IDs bypass cost tagging, quota management, and EU cross-region routing. The Ontopix profiles fix all three for free.
1. Pick a profile
| Profile name | Model | When to use |
|---|---|---|
rd-haiku-45 | Claude Haiku 4.5 | Cheapest/fastest — classification, extraction, short replies |
rd-sonnet-46 | Claude Sonnet 4.6 | Recommended default — balanced quality + cost |
rd-opus-47 | Claude Opus 4.7 | Deep reasoning, agentic loops, long-context synthesis |
rd-sonnet-4 | Claude Sonnet 4.0 | Legacy — only if pinning to that specific release |
All use EU cross-region inference (eu-central-1 / eu-west-1 / eu-west-3). No traffic leaves the EU.
2. Get the ARN
ARNs are not published publicly (they leak the AWS account ID). Fetch them from the infra repo:
# Clone / cd into the infra repo, then:
task infra:output
# Look at the `bedrock_inference_profile_arns` output.
One-liner for a specific profile:
# From the infra repo root
AWS_PROFILE=ontopix-jmroca terraform -chdir=global output -json bedrock_inference_profile_arns \
| jq -r '."rd-sonnet-46"'
Or straight from Bedrock (any AWS profile that can call bedrock:ListInferenceProfiles):
aws bedrock list-inference-profiles --type-equals APPLICATION \
--region eu-central-1 \
--query 'inferenceProfileSummaries[?inferenceProfileName==`rd-sonnet-46`].inferenceProfileArn' \
--output text
Store the ARN as an env var in your service — never hardcode it:
BEDROCK_INFERENCE_PROFILE_ARN=arn:aws:bedrock:eu-central-1:<ACCOUNT_ID>:application-inference-profile/<PROFILE_ID>
3. Grant IAM permissions
The infra repo creates the profile. Your service grants its own invoke permissions on the role that will call Bedrock (Lambda execution role, ECS task role, etc.).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InvokeBedrockProfile",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:eu-central-1:<ACCOUNT_ID>:application-inference-profile/<PROFILE_ID>"
},
{
"Sid": "InvokeFoundationModel",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:*::foundation-model/<MODEL_ID>"
}
]
}
<ACCOUNT_ID>and<PROFILE_ID>come from the ARN in step 2.<MODEL_ID>is the model the profile copies from, e.g.anthropic.claude-sonnet-4-6. The wildcard region (*) is required because EU cross-region profiles route across three regions.- In Terraform, reference the output:
module.bedrock.inference_profile_arns["rd-sonnet-46"](within the infra repo) or read from SSM/env in consumer repos.
4. Call it
Pass the profile ARN as modelId. The Bedrock SDK treats it exactly like a model ID.
TypeScript (Converse API)
import {
BedrockRuntimeClient,
ConverseCommand,
} from "@aws-sdk/client-bedrock-runtime";
const client = new BedrockRuntimeClient({ region: "eu-central-1" });
const response = await client.send(
new ConverseCommand({
modelId: process.env.BEDROCK_INFERENCE_PROFILE_ARN!, // the full ARN
messages: [
{ role: "user", content: [{ text: "Summarise this in one line: ..." }] },
],
inferenceConfig: { maxTokens: 512, temperature: 0.2 },
}),
);
console.log(response.output?.message?.content?.[0]?.text);
Python (Converse API)
import os
import boto3
client = boto3.client("bedrock-runtime", region_name="eu-central-1")
response = client.converse(
modelId=os.environ["BEDROCK_INFERENCE_PROFILE_ARN"], # full ARN
messages=[{"role": "user", "content": [{"text": "Summarise this in one line: ..."}]}],
inferenceConfig={"maxTokens": 512, "temperature": 0.2},
)
print(response["output"]["message"]["content"][0]["text"])
Streaming
Both SDKs support ConverseStream — swap ConverseCommand for ConverseStreamCommand (TS) or converse_stream (Python). Same modelId.
5. Verify it worked
- Cost Explorer → filter by tag
billing-mode = rd— new spend should show up within ~24h tagged toName = rd-<profile>. - CloudWatch →
AWS/Bedrocknamespace, dimensionModelIdwill show the profile ARN.
FAQ
Can I use these profiles for production / client traffic?
No. billing-mode = rd means R&D only. Production and client workloads must define their own inference profile in their repo with the correct billing-mode (saas or client). See ADR-0007.
Can I use these from outside eu-central-1?
Yes for calls, no for routing. The profile is EU cross-region — requests from anywhere reach the profile, but it only routes to EU regions. For non-EU latency-sensitive workloads, ask the infra team for a US/APAC profile.
I need a model version that isn't listed.
Open a PR on ontopix/infra: add an entry to inference_profiles in global/main.tf, following the rd-{model-short} naming convention. Check which EU cross-region system profiles are ACTIVE with:
aws bedrock list-inference-profiles --type-equals SYSTEM_DEFINED \
--region eu-central-1 \
--query 'inferenceProfileSummaries[?starts_with(inferenceProfileId, `eu.anthropic`)].inferenceProfileId'
My call returns AccessDeniedException.
Either (a) your IAM policy is missing one of the two statements above, or (b) you passed a raw model ID instead of the profile ARN. Both are common.
How do I find the underlying model from a profile ARN?aws bedrock get-inference-profile --inference-profile-identifier <arn> --region eu-central-1