This article details a solution for granular cost attribution of generative AI usage in multi-tenant environments using Amazon Bedrock. By employing "inference profiles" as tagged wrappers around foundation models, organizations can track and allocate AI inference costs to specific departments or teams, even when a single application and IAM role are used for all invocations. This architectural approach enables accurate chargebacks and budget management for shared AI resources.
Read original on AWS Architecture BlogIn enterprises adopting generative AI, a common problem arises when multiple internal teams share a single foundation model, especially through services like Amazon Bedrock. Traditional AWS billing often aggregates usage under one account or IAM role, making it difficult to discern which department is consuming the most resources. This lack of granular visibility hinders accurate chargebacks, budget setting, and identification of high-spending units, which is crucial for financial governance and resource optimization.
The proposed solution leverages Amazon Bedrock's application inference profiles. An inference profile acts as a logical wrapper around a foundation model. The key architectural design is to associate each department or team with its own inference profile, which in turn is linked to specific AWS cost allocation tags (e.g., `Team=HR`). The application layer is responsible for identifying the user's department and routing their AI inference requests through the corresponding tagged inference profile. All profiles can point to the same underlying foundation model.
Key Architectural Concept
Instead of relying on IAM principals for cost attribution, which might be unified for a single application, inference profiles shift attribution to a logical construct (the profile itself) that can be individually tagged. This decouples the caller's identity from the cost center.
import boto3
from botocore.exceptions import ClientError
client = boto3.client('bedrock-runtime', region_name='us-east-1')
# Map departments to their respective inference profile ARNs
DEPARTMENT_PROFILES = {
'HR': 'arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/abc123',
'Accounting': 'arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/def456',
'IT': 'arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/ghi789',
}
# Function to determine user's department (e.g., from session, OIDC/SAML claim)
def get_department_from_user_session():
# Placeholder: Replace with actual logic to get the department
return 'HR'
department = get_department_from_user_session()
if department not in DEPARTMENT_PROFILES:
raise ValueError(f"Unknown department: {department}")
try:
response = client.converse(
modelId=DEPARTMENT_PROFILES[department], # Use inference profile ARN as modelId
messages=[{'role': 'user', 'content': [{'text': 'Your prompt here'}]}],
inferenceConfig={'maxTokens': 300}
)
print(response)
except ClientError as e:
print(f"Error invoking model: {e}")
raiseThis approach ensures that while the underlying AI model remains shared, the consumption metrics are disaggregated, providing a clear financial picture for each consuming team. The modification to the application is minimal, primarily involving passing the inference profile ARN instead of the raw model ID to the Bedrock API call.