Operational Guides

Use Bedrock R&D Profile

Quick reference for invoking Claude via an Ontopix-managed Bedrock application inference profile. Shared R&D only.

New

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 nameModelWhen to use
rd-haiku-45Claude Haiku 4.5Cheapest/fastest — classification, extraction, short replies
rd-sonnet-46Claude Sonnet 4.6Recommended default — balanced quality + cost
rd-opus-47Claude Opus 4.7Deep reasoning, agentic loops, long-context synthesis
rd-sonnet-4Claude Sonnet 4.0Legacy — 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 to Name = rd-<profile>.
  • CloudWatch → AWS/Bedrock namespace, dimension ModelId will 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