O blog da AWS

Construa um serviço SaaS com controle de custo e uso para modelos de fundação no Amazon Bedrock

Por Hasan Poonawala, Bruno Pistone, Vikesh Pandey e Anastasia Tzeveleka

As empresas estão buscando liberar rapidamente o potencial da IA generativa, fornecendo acesso a modelos de fundação (FMs) para diferentes linhas de negócios (LOBs). As equipes de TI são responsáveis por ajudar o LOB a inovar com velocidade e agilidade, ao mesmo tempo em que fornecem governança e observabilidade centralizadas. Por exemplo, pode ser preciso monitorar o uso de FMs em todas as equipes, reduzir os custos e fornecer visibilidade ao centro de custos relevante no LOB. Além disso, talvez seja necessário regular o acesso a diferentes modelos por equipe. Por exemplo, se somente FMs específicos puderem ser aprovados para uso.

O Amazon Bedrock é um serviço totalmente gerenciado que oferece uma variedade de FMs de alto desempenho das principais empresas de IA, como AI21 Labs, Anthropic, Cohere, Meta, Stability AI e Amazon, por meio de uma única API, junto com um amplo conjunto de recursos para criar aplicativos de IA generativos com segurança, privacidade e IA responsável. Como o Amazon Bedrock é uma solução serverless, você não precisa gerenciar nenhuma infraestrutura e pode integrar e implantar com segurança recursos de IA Generativa em suas aplicações usando os serviços da AWS com os quais você já está familiarizado.

Uma camada de software como serviço (SaaS) para FMs pode fornecer uma interface simples e consistente para os usuários finais, mantendo a governança centralizada do acesso e do consumo. API Gateways podem fornecer um acoplamento flexível entre os consumidores do modelo e o serviço de endpoint do modelo, além de flexibilidade para se adaptar às mudanças de modelo, arquiteturas e métodos de invocação.

Neste post, mostramos como criar uma camada interna de SaaS para acessar FMs com o Amazon Bedrock em uma arquitetura multi tenant. Nós nos concentramos especificamente no controle de uso e custos por tenant e também em controles como limitação de uso por tenant. Descrevemos como a solução e os planos de consumo do Amazon Bedrock são mapeados para a estrutura geral da jornada de SaaS. O código da solução e um template do AWS Cloud Development Kit (AWS CDK) estão disponíveis no repositório do GitHub.

Desafios

Um administrador da plataforma de IA precisa fornecer acesso padronizado e fácil aos FMs para várias equipes de desenvolvimento.

A seguir estão alguns dos desafios para fornecer acesso governado aos FMs:

  • Rastreamento de custos e uso — Acompanhe e audite os custos individuais dos tenants e o uso de FMs, além de fornecer chargeback para centros de custo específicos
  • Controles de orçamento e uso — Gerencie a cota, o orçamento e os limites de uso da API para o uso permitido de FMs em uma frequência definida por tenant
  • Controle de acesso e governança de modelos — Defina controles de acesso para modelos específicos listados como permitidos por tenant
  • API padronizada para vários tenants — Forneça acesso consistente aos FMs com os padrões OpenAPI
  • Gerenciamento centralizado da API — Forneça uma única camada para gerenciar as chaves de API para acessar modelos
  • Versões e atualizações de modelos — Gerencie lançamentos de versões de modelos novos e atualizados

Visão geral da solução

Nesta solução, nos referimos a uma abordagem multi tenant. Um tenant aqui pode variar de um usuário individual, um projeto específico, uma equipe ou até mesmo um departamento inteiro. Ao discutirmos a abordagem, usamos o termo equipe, porque é o mais comum. Usamos chaves de API para restringir e monitorar o acesso das equipes à API. Cada equipe recebe uma chave de API para acessar os FMs. Pode haver diferentes mecanismos de autenticação e autorização de usuários implantados em uma organização. Para simplificar, não os incluímos nesta solução. Você também pode integrar provedores de identidade existentes a essa solução.

O diagrama a seguir resume a arquitetura da solução e os principais componentes. Equipes (tenants) atribuídas a centros de custo separados consomem os FMs do Amazon Bedrock por meio de um serviço de API. Para rastrear o consumo e o custo por equipe, a solução registra os dados de cada invocação individual, incluindo o modelo invocado, o número de tokens para modelos de geração de texto e as dimensões da imagem para modelos multimodais. Além disso, ele agrega as invocações por modelo e os custos de cada equipe.

Você pode implantar a solução em sua própria conta usando o AWS CDK. O AWS CDK é uma framework de desenvolvimento de software de código aberto para modelar e provisionar seus recursos de aplicações em nuvem usando linguagens de programação conhecidas. O código do AWS CDK está disponível no repositório do GitHub.

Nas seções a seguir, discutiremos os principais componentes da solução com mais detalhes.

Capturando o uso do modelo básico por equipe

O fluxo de trabalho para capturar o uso de FM por equipe consiste nas seguintes etapas (conforme numeradas no diagrama anterior):

  1. A aplicação de uma equipe envia uma requisição POST para o Amazon API Gateway com o modelo a ser invocado no parâmetro de consulta model_id e a solicitação do usuário no corpo da solicitação.
  2. O API Gateway encaminha a requisição para uma função do AWS Lambda (bedrock_invoke_model) que é responsável por registrar as informações de uso da equipe no Amazon CloudWatch e invocar o modelo no Amazon Bedrock.
  3. O Amazon Bedrock fornece um VPC endpoint baseado no AWS PrivateLink. Nessa solução, a função Lambda envia a requisição ao Amazon Bedrock usando o PrivateLink para estabelecer uma conexão privada entre a VPC em sua conta e a conta de serviço Amazon Bedrock. Para saber mais sobre o PrivateLink, consulte Usar o AWS PrivateLink para configurar o acesso privado ao Amazon Bedrock.
  4. Após a invocação do Amazon Bedrock, o AWS CloudTrail gera um evento do CloudTrail.
  5. Se a chamada do Amazon Bedrock for bem-sucedida, a função Lambda registrará as seguintes informações, dependendo do tipo de modelo invocado, e retornará a resposta gerada à aplicação:
    • team_id — O identificador exclusivo da equipe que está emitindo a requisição.
    • requestId — O identificador exclusivo da requisição.
    • model_id — O ID do modelo a ser invocado.
    • inputTokens — O número de tokens enviados ao modelo como parte do prompt (para geração de texto e modelos de embeddings).
    • outputTokens — O número máximo de tokens a serem gerados pelo modelo (para modelos de geração de texto).
    • height — A altura da imagem solicitada (para modelos multimodais e modelos de embeddings multimodais).
    • width — A largura da imagem solicitada (somente para modelos multimodais).
    • steps — As etapas solicitadas (para modelos da Stability AI).

Custos de rastreamento por equipe

Um fluxo diferente agrega as informações de uso e, em seguida, calcula e economiza os custos sob demanda por equipe diariamente. Ao ter um fluxo separado, garantimos que o rastreamento de custos não afete a latência e a taxa de transferência do fluxo de invocação do modelo. As etapas do fluxo de trabalho são as seguintes:

  1. Uma regra do Amazon EventBridge aciona uma função Lambda (bedrock_cost_tracking) diariamente.
  2. A função Lambda obtém as informações de uso do CloudWatch do dia anterior, calcula os custos associados e armazena os dados agregados por team_id e model_id no Amazon Simple Storage Service (Amazon S3) no formato CSV.

Para consultar e visualizar os dados armazenados no Amazon S3, você tem opções diferentes, incluindo S3 Select, Amazon Athena e Amazon QuickSight.

Controle do uso por equipe

Um plano de uso especifica quem pode acessar uma ou mais APIs implantadas e, opcionalmente, define a taxa de requisição alvo para começar a limitar as requisições. O plano usa chaves de API para identificar clientes de API que podem acessar a API associada para cada chave. Você pode usar os planos de uso do API Gateway para limitar requisições que excedam os limites predefinidos. Você também pode usar chaves de API e limites de cota, que permitem definir o número máximo de requisições por chave de API que cada equipe pode emitir dentro de um intervalo de tempo especificado. Isso é um acréscimo às cotas de serviço do Amazon Bedrock que são atribuídas somente no nível da conta.

Pré-requisitos

Antes de implantar a solução, verifique se você tem o seguinte:

Implante a pilha de CDK da AWS

Siga as instruções no arquivo README do repositório GitHub para configurar e implantar a pilha de CDK da AWS.

A pilha implanta os seguintes recursos:

  • Ambiente de rede privado (VPC, sub-redes privadas, grupo de segurança)
  • Função do IAM para controlar o acesso ao modelo
  • Lambda layers para os módulos Python necessários
  • Função lambda invoke_model
  • Função lambda list_foundation_models
  • Função lambda cost_tracking
  • API Rest (API Gateway)
  • Plano de uso do API Gateway
  • Chave de API associada ao plano de uso

Onboarding de uma nova equipe

Para fornecer acesso a novas equipes, você pode compartilhar a mesma chave de API entre equipes diferentes e acompanhar o consumo do modelo fornecendo um team_id diferente para a invocação da API ou criar chaves de API dedicadas usadas para acessar os recursos do Amazon Bedrock seguindo as instruções fornecidas no README.

A pilha implanta os seguintes recursos:

  • Plano de uso do API Gateway associado à API REST criada anteriormente
  • Chave de API associada ao plano de uso da nova equipe, com reserva de throttling e configuração de burst para a API

Para obter mais informações sobre as configurações de throttling e burst do API Gateway, consulte Throttling de requisições de API para obter uma melhor taxa de transferência.

Depois de implantar a pilha, você pode ver que a nova chave de API para a equipe-2 também foi criada.

Configurar o controle de acesso ao modelo

O administrador da plataforma pode permitir o acesso a FMs específicos editando a política do IAM associada à função invoke_model do Lambda.

As permissões do IAM são definidas no arquivo setup/stack_constructs/iam.py. Veja o código a seguir:

self.bedrock_policy = iam.Policy(
            scope=self,
            id=f"{self.id}_policy_bedrock",
            policy_name="BedrockPolicy",
            statements=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=[
                        "sts:AssumeRole",
                    ],
                    resources=["*"],
                ),
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=[
                        "bedrock:InvokeModel",
				“bedrock:ListFoundationModels",

                    ],
                    resources=[
  	"arn:aws:bedrock:*::foundation-model/anthropic.claude-v2.1",
	"arn:aws:bedrock:*::foundation-model/amazon.titan-text-express-v1",
	"arn:aws:bedrock:*::foundation-model/amazon.titan-embed-text-v1"
],
                )
            ],
        )

…

self.bedrock_policy.attach_to_role(self.lambda_role)

Invoque o serviço

Depois de implantar a solução, você pode invocar o serviço diretamente do seu código. O código abaixo é um exemplo em Python para consumir a API invoke_model para geração de texto por meio de uma requisição POST:

api_key=”abcd1234”

model_id = "amazon.titan-text-express-v1" #the model id for the Amazon Titan Express model
 
model_kwargs = { # inference configuration
    "maxTokenCount": 4096,
    "temperature": 0.2
}

prompt = "What is Amazon Bedrock?"

response = requests.post(
    f"{api_url}/invoke_model?model_id={model_id}",
    json={"inputs": prompt, "parameters": model_kwargs},
    headers={
        "x-api-key": api_key, #key for querying the API
        "team_id": team_id #unique tenant identifier 
    }
)

text = response.json()[0]["generated_text"]

print(text)

Resultado: Amazon Bedrock is an internal technology platform developed by Amazon to run and operate many of their services and products. Some key things about Bedrock …

Veja a seguir outro exemplo em Python para consumir a API invoke_model para geração de embeddings por meio de uma requisição POST:

model_id = "amazon.titan-embed-text-v1" #the model id for the Amazon Titan Embeddings Text model

prompt = "What is Amazon Bedrock?"

response = requests.post(
    f"{api_url}/invoke_model?model_id={model_id}",
    json={"inputs": prompt, "parameters": model_kwargs},
    headers={
        "x-api-key": api_key, #key for querying the API
        "team_id": team_id #unique tenant identifier,
	"embeddings": "true" #boolean value for the embeddings model 
    }
)

text = response.json()[0]["embedding"]

Resultado: 0,91796875, 0,45117188, 0,52734375, -0,18652344, 0,06982422, 0,65234375, -0,13085938, 0,056884766, 0,092285156, 0,06982422, 1,03125, 0,8515625, 0,16308594, 0,079589844, -0,033935547, 0,796875, -0,15429688, -0,29882812, -0,25585938, 0,45703125, 0,044921875, 0,34570312…

Acesso negado aos modelos da fundação

Veja a seguir um exemplo em Python para consumir a API invoke_model para geração de texto por meio de uma requisição POST com uma resposta de acesso negado:

model_id = " anthropic.claude-v1" #the model id for Anthropic Claude V1 model
 
model_kwargs = { # inference configuration
    "maxTokenCount": 4096,
    "temperature": 0.2
}

prompt = "What is Amazon Bedrock?"

response = requests.post(
    f"{api_url}/invoke_model?model_id={model_id}",
    json={"inputs": prompt, "parameters": model_kwargs},
    headers={
        "x-api-key": api_key, #key for querying the API
        "team_id": team_id #unique tenant identifier 
    }
)

print(response)
print(response.text)

<Response [500]> “Traceback (most recent call last):\n File \”/var/task/index.py\”, line 213, in lambda_handler\n response = _invoke_text(bedrock_client, model_id, body, model_kwargs)\n File \”/var/task/index.py\”, line 146, in _invoke_text\n raise e\n File \”/var/task/index.py\”, line 131, in _invoke_text\n response = bedrock_client.invoke_model(\n File \”/opt/python/botocore/client.py\”, line 535, in _api_call\n return self._make_api_call(operation_name, kwargs)\n File \”/opt/python/botocore/client.py\”, line 980, in _make_api_call\n raise error_class(parsed_response, operation_name)\nbotocore.errorfactory.AccessDeniedException: An error occurred (AccessDeniedException) when calling the InvokeModel operation: Your account is not authorized to invoke this API operation.\n

Exemplo de estimativa de custo

Ao invocar modelos Amazon Bedrock com preços sob demanda, o custo total é calculado como a soma dos custos de entrada e saída. Os custos de entrada são baseados no número de tokens de entrada enviados ao modelo e os custos de saída são baseados nos tokens gerados. Os preços são por 1.000 tokens de entrada e por 1.000 tokens de saída. Para obter mais detalhes e preços de modelos específicos, consulte os preços do Amazon Bedrock.

Vejamos um exemplo em que duas equipes, Equipe1 e Equipe2, acessam o Amazon Bedrock por meio da solução neste post. Os dados de uso e custo salvos no Amazon S3 em um único dia são mostrados na tabela a seguir.

As colunas input_tokens e output_tokens armazenam o total de tokens de entrada e saída nas invocações de modelo, por modelo e por equipe, respectivamente, em um determinado dia.

As colunas input_cost e output_cost armazenam os respectivos custos por modelo e por equipe. Eles são calculados usando as seguintes fórmulas:

input_cost = input_token_count * model_pricing["input_cost"] / 1000
output_cost = output_token_count * model_pricing["output_cost"] / 1000

team_id model_id input_tokens output_tokens invocations input_cost output_cost
Equipe1 amazon.titan-tg1-large 24000 2473 1000 0,0072 0,00099
Equipe1 anthropic.claude-v2 2448 4800 24 0,02698 0,15686
Equipe2 amazon.titan-tg1-large 35000 52500 350 0,0105 0,021
Equipe2 ai21.j2-grande-instruct 4590 9000 45 0,05738 0,1125
Equipe2 anthropic.claude-v2 1080 4400 20 0,0119 0,14379

Visão completa de um ambiente SaaS serverless e multitenant

Vamos entender como pode ser um ambiente SaaS serverless e multitenant de ponta a ponta. A seguir está um diagrama de arquitetura de referência.

Esse diagrama de arquitetura é uma versão ampliada do diagrama de arquitetura explicado anteriormente na postagem, onde o diagrama de arquitetura anterior explica os detalhes de um dos microsserviços mencionados (serviço de FMs). Esse diagrama explica que, além do serviço de FMs, você também precisa ter outros componentes em sua plataforma SaaS multitenant para implementar uma plataforma funcional e escalável.

Vamos examinar os detalhes da arquitetura.

Aplicações de tenants

As aplicações de tenants são as aplicações front-end que interagem com o ambiente. Aqui, mostramos vários tenants acessando de diferentes ambientes locais ou da AWS. As aplicações front-end podem ser estendidas para incluir uma página de registro para que novos tenants se registrem e um console administrativo para administradores da camada de serviço SaaS. Se as aplicações de tenants exigirem a implementação de uma lógica personalizada que precise de interação com o ambiente SaaS, elas poderão implementar as especificações do microsserviço do adaptador de aplicações. Cenários de exemplo podem incluir uma lógica de autorização personalizada, respeitando as especificações de autorização do ambiente SaaS.

Serviços compartilhados

A seguir estão os serviços compartilhados:

  • Serviços de gerenciamento de tenants e usuários — Esses serviços são responsáveis por registrar e gerenciar os tenants. Eles fornecem a funcionalidade transversal que é separada dos serviços de aplicações e compartilhada entre todos os tenants.
  • Serviço de modelo de fundação — O diagrama da arquitetura da solução explicado no início deste post representa esse microsserviço, onde a interação do API Gateway com as funções do Lambda está acontecendo dentro do escopo desse microsserviço. Todos os tenants usam esse microsserviço para invocar os modelos de fundação da Anthropic, AI21, Cohere, Stability, Meta e Amazon, bem como modelos com fine-tuning. Ele também captura as informações necessárias para o rastreamento de uso nos registros do CloudWatch.
  • Serviço de controle de custos — Esse serviço monitora o custo e o uso de cada tenant. Esse microsserviço é executado em um cronograma para consultar os logs do CloudWatch e gerar o rastreamento agregado de uso e o custo inferido para o armazenamento de dados. O serviço de rastreamento de custos pode ser estendido para criar mais relatórios e visualizações.

Serviço de adaptador de aplicações

Esse serviço apresenta um conjunto de especificações e APIs que um tenant pode implementar para integrar sua lógica personalizada ao ambiente SaaS. Com base na quantidade de integração personalizada necessária, esse componente pode ser opcional para tenants.

Armazenamento de dados multitenant

Os serviços compartilhados armazenam seus dados em uma única tabela compartilhada do Amazon DynamoDB com uma chave de particionamento de tenant que associa itens do DynamoDB a tenants individuais. O serviço compartilhado de rastreamento de custos gera os dados agregados de uso e rastreamento de custos para o Amazon S3. Com base no caso de uso, também pode haver um armazenamento de dados específico da aplicação.

Um ambiente SaaS multitenant pode ter muito mais componentes. Para obter mais informações, consulte Como criar uma solução SaaS multi tenant usando os serviços serverless da AWS.

Suporte para vários modelos de implantação

As estruturas SaaS geralmente descrevem dois modelos de implantação: pool e silo. Para o modelo de pool, todos os tenants acessam as FMs a partir de um ambiente compartilhado com infraestrutura comum de armazenamento e computação. No modelo de silo, cada tenant tem seu próprio conjunto de recursos dedicados. Você pode ler sobre modelos de isolamento no whitepaper SaaS Tenant Isolation Strategies.

A solução proposta pode ser adotada para ambos os modelos de implantação de SaaS. Na abordagem de pool, um ambiente centralizado da AWS hospeda os recursos de API, armazenamento e computação. No modo silo, cada equipe acessa APIs, armazenamento e recursos computacionais em um ambiente dedicado da AWS.

A solução também se encaixa nos planos de consumo disponíveis fornecidos pelo Amazon Bedrock. A AWS oferece uma opção de dois planos de consumo para inferência:

  • Sob demanda — Esse modo permite que você use FMs e pague conforme o uso, sem precisar assumir compromissos de prazo com base no tempo
  • Taxa de transferência provisionada — Esse modo permite que você provisione uma taxa de transferência suficiente para atender aos requisitos de desempenho da sua aplicação em troca de um compromisso de prazo baseado em tempo

Para obter mais informações sobre essas opções, consulte os preços do Amazon Bedrock.

A solução de referência SaaS serverless descrita nesta postagem pode aplicar os planos de consumo do Amazon Bedrock para fornecer opções de classificação por níveis básicos e premium aos usuários finais. O básico pode incluir o consumo de taxa de transferência sob demanda ou provisionada do Amazon Bedrock e pode incluir limites específicos de uso e orçamento. Os limites para tenants podem ser ativados com uso de throttling, tomando como base em requisições, tamanhos de tokens ou alocação de custos. Tenants de nível premium poderiam ter seus próprios recursos dedicados com o consumo de taxa de transferência provisionada do Amazon Bedrock. Esses tenants normalmente estariam associados a cargas de trabalho de produção que exigem alto rendimento e acesso de baixa latência aos FMs do Amazon Bedrock.

Conclusão

Neste post, discutimos como criar uma plataforma SaaS interna para acessar FMs com o Amazon Bedrock em uma configuração multi tenant com foco no rastreamento de custos e uso e na limitação por throttling para cada tenant. Outros tópicos a serem explorados incluem a integração de soluções de autenticação e autorização existentes na organização, o aprimoramento da camada de API para incluir web sockets para interações bidirecionais entre cliente e servidor, a adição de filtragem de conteúdo e outras barreiras de governança, o design de vários níveis de implantação, a integração de outros microsserviços na arquitetura SaaS e muito mais.

O código completo dessa solução está disponível no repositório do GitHub.

Para obter mais informações sobre estruturas baseadas em SaaS, consulte SaaS Journey Framework: Building a New SaaS Solution on AWS.


Sobre os autores

Hasan Poonawala é arquiteto sênior de soluções especializado em IA/ML na AWS, trabalhando com clientes da área de saúde e ciências biológicas. Hasan ajuda a projetar, implantar e escalar aplicativos generativos de IA e aprendizado de máquina na AWS. Ele tem mais de 15 anos de experiência profissional combinada em aprendizado de máquina, desenvolvimento de software e ciência de dados na nuvem. Em seu tempo livre, Hasan adora explorar a natureza e passar tempo com amigos e familiares.

Anastasia Tzeveleka é arquiteta sênior de soluções especialista em IA/ML na AWS. Como parte de seu trabalho, ela ajuda clientes em toda a EMEA a criar modelos de fundação e criar soluções generativas de IA e aprendizado de máquina escaláveis usando os serviços da AWS.

Bruno Pistone é arquiteto de soluções generativas especializado em IA e ML para a AWS, com sede em Milão. Ele trabalha com grandes clientes, ajudando-os a entender profundamente suas necessidades técnicas e a projetar soluções de IA e aprendizado de máquina que façam o melhor uso da nuvem da AWS e da pilha de aprendizado de máquina da Amazon. Sua experiência inclui: aprendizado de máquina de ponta a ponta, industrialização de aprendizado de máquina e IA generativa. Ele gosta de passar tempo com seus amigos e explorar novos lugares, além de viajar para novos destinos.

Vikesh Pandey é arquiteto de soluções generativas de IA/ML, especializado em serviços financeiros, onde ajuda clientes financeiros a criar e escalar plataformas e soluções generativas de IA/ML que podem ser escaladas para centenas ou até milhares de usuários. Em seu tempo livre, Vikesh gosta de escrever em vários fóruns de blogs e criar legos com seu filho.


Este conteúdo foi traduzido para Português do blog original em inglês (link aqui).

Tradutor: Cesar Augusto Kuehl, arquiteto de soluções – AWS Brasil

Revisor: Rafael Weffort, arquiteto de soluções – AWS Brasil