O blog da AWS

Crie uma base de conhecimento just-in-time com o Amazon Bedrock

Por Steven Warwick, arquiteto sênior de soluções na AWS.

Empresas que oferecem software como serviço (SaaS) com múltiplos clientes (tenants) enfrentam um desafio crucial: como extrair eficientemente insights relevantes de grandes volumes de documentos, mantendo os custos sob controle. As estratégias convencionais frequentemente resultam em desperdício de recursos de armazenamento e processamento não utilizados, comprometendo tanto a eficiência operacional quanto a rentabilidade. As organizações necessitam de soluções que dimensionem de forma inteligente seus recursos de processamento e armazenamento, baseando-se nos padrões reais de uso dos clientes, sempre preservando o isolamento dos dados. Os sistemas tradicionais de Recuperação Aumentada por Geração (RAG) consomem recursos valiosos ao processar e manter embeddings de documentos que podem nunca ser consultados, gerando custos desnecessários de armazenamento e diminuindo a eficiência do sistema. Sistemas desenvolvidos para gerenciar grandes quantidades de clientes de pequeno e médio porte podem ultrapassar a estrutura de custos e os limites da infraestrutura, ou podem requerer implementações isoladas para manter separados as informações e o uso de cada cliente. Soma-se a isso o fato de que muitos projetos são temporários, com atividades realizadas de forma intermitente, ocupando espaço em sistemas de base de conhecimento que poderia ser utilizado por outros clientes ativos.

Para enfrentar esses desafios, este post apresenta uma solução de base de conhecimento just-in-time que reduz o consumo não utilizado por meio do processamento inteligente de documentos. A solução processa documentos somente quando necessário e remove automaticamente os recursos não utilizados, para que as organizações possam escalar seus repositórios de documentos sem aumentar proporcionalmente os custos de infraestrutura.

Uma arquitetura multilocatária (multi-tenant) com limites configuráveis por cliente permite que os provedores de serviços ofereçam modelos de preços escalonados, mantendo um rigoroso isolamento de dados. Isso a torna ideal para aplicações SaaS que atendem diversos clientes com necessidades variadas. A expiração automática de documentos através do Time-to-Live (TTL) assegura que o sistema permaneça enxuto e focado em conteúdo relevante. Simultaneamente, a atualização do TTL para documentos frequentemente acessados mantém o desempenho ideal das informações cruciais. Esta arquitetura também possibilita limitar o número de arquivos que cada cliente pode inserir em um período específico, bem como a taxa na qual podem consultar um conjunto de arquivos. A solução utiliza tecnologias serverless para reduzir a sobrecarga operacional e proporcionar escalabilidade automática, permitindo que as equipes se concentrem na lógica de negócios em vez do gerenciamento de infraestrutura. Ao organizar documentos em grupos com filtragem baseada em metadados, o sistema viabiliza consultas contextuais que fornecem resultados mais pertinentes, sempre respeitando os limites de segurança entre os clientes. A flexibilidade da arquitetura suporta a personalização das configurações dos clientes, taxas de consulta e políticas de retenção de documentos. Isso a torna adaptável às necessidades de negócios em constante evolução, sem exigir uma reestruturação significativa.

Visão geral da solução

Essa arquitetura combina vários serviços da AWS para criar uma solução de base de conhecimento econômica e multilocatária que processa documentos sob demanda. Os principais componentes incluem:

  • Base de conhecimento baseada em vetores — usa o Amazon Bedrock e o Amazon OpenSearch Serverless para processamento e consulta eficientes de documentos
  • Ingestão de documentos sob demanda — implementa o processamento just-in-time usando o tipo de fonte de dados Amazon Bedrock CUSTOM
  • Gerenciamento de TTL — Fornece limpeza automática de documentos não utilizados usando o recurso TTL no Amazon DynamoDB
  • Isolamento de vários locatários — impõe a separação segura de dados entre usuários e organizações com limites de recursos configuráveis

A solução permite o controle granular por meio de filtragem baseada em metadados no nível do usuário, locatário e arquivo. O sistema de rastreamento TTL do DynamoDB oferece suporte a estruturas de preços em camadas, nas quais os locatários podem pagar por diferentes durações de TTL, limites de ingestão de documentos e taxas de consulta.

O diagrama a seguir ilustra os principais componentes e o fluxo de trabalho da solução.

O fluxo de trabalho consiste nas seguintes etapas:

  1. O usuário realiza login no sistema, que vincula um identificador (ID) de cliente ao usuário atual para as chamadas à base de conhecimento do Amazon Bedrock. Esta etapa de autenticação é fundamental, pois estabelece o contexto de segurança e garante que todas as interações subsequentes sejam corretamente associadas ao cliente correspondente. O ID do cliente torna-se o elemento central dos metadados, permitindo tanto o adequado isolamento entre múltiplos clientes quanto o gerenciamento eficiente de recursos em todo o fluxo de trabalho.
  2. Após a autenticação, o usuário cria um projeto que funcionará como um container para os arquivos que deseja consultar. Esta etapa estabelece a estrutura organizacional necessária para gerenciar conjuntos de documentos relacionados. O sistema gera os metadados apropriados e cria as entradas necessárias no banco de dados para monitorar a associação do projeto com o cliente específico. Isso permite um controle de acesso adequado e o gerenciamento eficiente de recursos no nível do projeto.
  3. Com um projeto estabelecido, o usuário pode começar a enviar arquivos. O sistema gerencia esse processo gerando URLs pré-assinados para upload seguro de arquivos. Conforme os arquivos são carregados, eles são armazenados no Amazon Simple Storage Service (Amazon S3), e o sistema cria automaticamente entradas no DynamoDB que associam cada arquivo ao projeto e ao locatário. Essa relação tripla (arquivo-projeto-cliente) é essencial para manter o isolamento adequado dos dados e permitir consultas eficientes posteriormente.
  4. Quando um usuário solicita a criação de um chat com uma base de conhecimento para um projeto específico, o sistema inicia a importação dos arquivos do projeto utilizando a fonte de dados PERSONALIZADA. Neste momento, começa o processamento just-in-time. Durante a importação, o sistema aplica um valor de TTL baseado no intervalo específico definido para o nível do cliente. O TTL assegura que os arquivos do projeto permaneçam disponíveis durante a sessão de chat, enquanto estabelece a estrutura para uma limpeza automática posterior. Esta etapa representa o núcleo da estratégia de processamento sob demanda, pois os arquivos são processados apenas quando necessários.
  5. Cada sessão de chat atualiza ativamente o TTL dos arquivos do projeto que estão sendo usados. Esse gerenciamento dinâmico de TTL garante que os arquivos acessados com frequência permaneçam na base de conhecimento, permitindo que arquivos raramente usados expirem naturalmente. O sistema atualiza continuamente os valores de TTL com base no uso real, criando um equilíbrio eficiente entre disponibilidade de recursos e otimização de custos. Essa abordagem mantém o desempenho ideal para conteúdo usado ativamente e, ao mesmo tempo, ajuda a evitar o desperdício de recursos em documentos não utilizados.
  6. Depois que a sessão de chat termina e o valor do TTL expira, o sistema remove automaticamente os arquivos da base de conhecimento. Esse processo de limpeza é acionado pelo Amazon DynamoDB Streams monitorando eventos de expiração de TTL, que ativam uma função do AWS

Lambda para remover os documentos expirados. Essa etapa final reduz a carga no cluster OpenSearch Serverless subjacente e otimiza os recursos do sistema, garantindo que a base de conhecimento permaneça enxuta e eficiente.

Pré-requisitos

Você precisa dos seguintes pré-requisitos antes de prosseguir com a solução. Para esta postagem, usamos a região us-east-1 da AWS.

• Uma conta ativa da AWS com permissões para criar recursos em us-east-1
• A interface de linha de comando da AWS (AWS CLI) instalada
• O AWS Cloud Development Kit (AWS CDK) instalado
• Git instalado para clonar o repositório

Implemente a solução

Conclua as etapas a seguir para implantar a solução:

1. Faça o download do projeto AWS CDK no repositório do GitHub.

2. Instale as dependências do projeto:

npm run install:all
Bash

3. Implante a solução:

npm run deploy
Bash

4. Crie um usuário e faça login no sistema após validar seu e-mail.

Valide a base de conhecimento e execute uma consulta

Antes de permitir que os usuários conversem com seus documentos, o sistema executa as seguintes etapas:

• Executa uma verificação de validação para determinar se os documentos precisam ser ingeridos. Esse processo acontece de forma transparente para o usuário e inclui a verificação do status do documento no DynamoDB e na base de conhecimento.
• Valida se os documentos necessários foram ingeridos com sucesso e indexados adequadamente antes de permitir consultas.
• Retorna as respostas geradas pela IA e as citações relevantes aos documentos de origem, mantendo a rastreabilidade e capacitando os usuários a verificar a precisão das respostas.

A captura de tela a seguir ilustra um exemplo de chat com os documentos.

Analisando o seguinte exemplo de método para ingestão de arquivos, observe como as informações do arquivo são armazenadas no DynamoDB com um valor TTL para expiração automática. A chamada de ingestão de documentos da base de conhecimento inclui metadados essenciais (ID do usuário, ID do cliente e projeto), permitindo a filtragem precisa dos arquivos desse cliente em operações subsequentes.

# Ingesting files with tenant-specific TTL values
def ingest_files(user_id, tenant_id, project_id, files):
    # Get tenant configuration and calculate TTL
    tenants = json.loads(os.environ.get('TENANTS'))['Tenants']
    tenant = find_tenant(tenant_id, tenants)
    ttl = int(time.time()) + (int(tenant['FilesTTLHours']) * 3600)
    
    # For each file, create a record with TTL and start ingestion
    for file in files:
        file_id = file['id']
        s3_key = file.get('s3Key')
        bucket = file.get('bucket')
        
        # Create a record in the knowledge base files table with TTL
        knowledge_base_files_table.put_item(
            Item={
                'id': file_id,
                'userId': user_id,
                'tenantId': tenant_id,
                'projectId': project_id,
                'documentStatus': 'ready',
                'createdAt': int(time.time()),
                'ttl': ttl  # TTL value for automatic expiration
            }
        )
        
        # Start the ingestion job with tenant, user, and project metadata for filtering
        bedrock_agent.ingest_knowledge_base_documents(
            knowledgeBaseId=KNOWLEDGE_BASE_ID,
            dataSourceId=DATA_SOURCE_ID,
            clientToken=str(uuid.uuid4()),
            documents=[
                {
                    'content': {
                        'dataSourceType': 'CUSTOM',
                        'custom': {
                            'customDocumentIdentifier': {
                                'id': file_id
                            },
                            's3Location': {
                                'uri': f"s3://{bucket}/{s3_key}"
                            },
                            'sourceType': 'S3_LOCATION'
                        }
                    },
                    'metadata': {
                        'type': 'IN_LINE_ATTRIBUTE',
                        'inlineAttributes': [
                            {'key': 'userId', 'value': {'stringValue': user_id, 'type': 'STRING'}},
                            {'key': 'tenantId', 'value': {'stringValue': tenant_id, 'type': 'STRING'}},
                            {'key': 'projectId', 'value': {'stringValue': project_id, 'type': 'STRING'}},
                            {'key': 'fileId', 'value': {'stringValue': file_id, 'type': 'STRING'}}
                        ]
                    }
                }
            ]
        )
Python

Durante uma consulta, você pode usar os metadados associados para criar parâmetros que garantam a recuperação somente de arquivos pertencentes a esse cliente específico. Por exemplo:

    filter_expression = {
        "andAll": [
            {
                "equals": {
                    "key": "tenantId",
                    "value": tenant_id
                }
            },
            {
                "equals": {
                    "key": "projectId",
                    "value": project_id
                }
            },
            {
                "in": {
                    "key": "fileId",
                    "value": file_ids
                }
            }
        ]
    }

    # Create base parameters for the API call retrieve_params = {
        'input': {
            'text': query
        }, 'retrieveAndGenerateConfiguration': {
            'type': 'KNOWLEDGE_BASE',
            'knowledgeBaseConfiguration': {
                'knowledgeBaseId': knowledge_base_id, 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-pro-v1:0', 'retrievalConfiguration': {
                    'vectorSearchConfiguration': {
                        'numberOfResults': limit,
                        'filter': filter_expression
                    }
                }
            }
        }
    }
    response = bedrock_agent_runtime.retrieve_and_generate(**retrieve_params)
CSS

Gerencie o ciclo de vida do documento com TTL

Para otimizar ainda mais o uso e os custos dos recursos, você pode implementar um sistema inteligente de gerenciamento do ciclo de vida de documentos usando o recurso DynamoDB (TTL). Isso consiste nas seguintes etapas:

  1. Quando um documento é inserido na base de conhecimento, um registro é criado com um valor TTL configurável.
  2. Esse TTL é atualizado quando o documento é acessado.
  3. O DynamoDB Streams com filtros específicos para eventos de expiração de TTL é usado para acionar uma função Lambda de limpeza.
  4. A função Lambda remove documentos expirados da base de conhecimento.

Veja o código a seguir:

# Lambda function triggered by DynamoDB Streams when TTL expires items
def lambda_handler(event, context):
    """ This function is triggered by DynamoDB Streams when TTL expires items. It removes expired documents from the knowledge base. """
    
    # Process each record in the event
    for record in event.get('Records', []):
        # Check if this is a TTL expiration event (REMOVE event from DynamoDB Stream)
        if record.get('eventName') == 'REMOVE':
            # Check if this is a TTL expiration
            user_identity = record.get('userIdentity', {})
            if user_identity.get('type') == 'Service' and user_identity.get('principalId') == 'dynamodb.amazonaws.com':
                # Extract the file ID and tenant ID from the record
                keys = record.get('dynamodb', {}).get('Keys', {})
                file_id = keys.get('id', {}).get('S')
                
                # Delete the document from the knowledge base
                bedrock_agent.delete_knowledge_base_documents(
                    clientToken=str(uuid.uuid4()),
                    knowledgeBaseId=knowledge_base_id,
                    dataSourceId=data_source_id,
                    documentIdentifiers=[
                        {
                            'custom': {
                                'id': file_id
                            },
                            'dataSourceType': 'CUSTOM'
                        }
                    ]
                )
Python

Isolamento de vários clientes com níveis de serviço hierárquicos

Nossa arquitetura permite um isolamento sofisticado de vários clientes com níveis de serviço hierárquicos:

  • Filtragem de documentos específicos do cliente — Cada consulta inclui filtros específicos de usuário, cliente e arquivo, permitindo que o sistema reduza o número de documentos consultados.
  • Valores de TTL configuráveis — diferentes níveis de clientes podem ter diferentes configurações de TTL. Por exemplo:
    • Nível gratuito: cinco documentos ingeridos com um TTL de 7 dias e cinco consultas por minuto.
    • Nível padrão: 100 documentos ingeridos com um TTL de 30 dias e 10 consultas por minuto.
    • Nível Premium: 1.000 documentos ingeridos com um TTL de 90 dias e 50 consultas por minuto.
    • Você pode configurar limites adicionais, como o total de consultas por mês ou o total de arquivos ingeridos por dia ou mês.

Limpe

Para limpar os recursos criados nesta publicação, execute o comando a seguir no mesmo local em que você executou a etapa de implantação:

npm run destroy
Bash

Conclusão

A arquitetura da base de conhecimento just-in-time apresentada nesta publicação transforma o gerenciamento de documentos em vários clientes, processando documentos somente quando consultados, reduzindo o consumo não utilizado dos sistemas RAG tradicionais. Essa implementação Serverless usa o Amazon Bedrock, o OpenSearch Serverless e o recurso TTL do DynamoDB para criar um sistema enxuto com gerenciamento inteligente do ciclo de vida de documentos, limites configuráveis de locatários e isolamento estrito de dados, o que é essencial para provedores de SaaS que oferecem modelos de preços hierárquicos.

Essa solução aborda diretamente a estrutura de custos e as limitações de infraestrutura dos sistemas tradicionais, especialmente para implantações que lidam com vários clientes de pequeno a médio porte com projetos transitórios. Essa arquitetura combina o processamento de documentos sob demanda com o gerenciamento automatizado do ciclo de vida, fornecendo um recurso econômico e escalável que permite que as organizações se concentrem em extrair insights em vez de gerenciar a infraestrutura, mantendo os limites de segurança entre os clientes.

Pronto para implementar essa arquitetura? O código de amostra completo está disponível no repositório do GitHub.

Este conteúdo foi traduzido da postagem original do blog, que pode ser encontrada aqui.

Sobre o autor

Steven Warwick é arquiteto sênior de soluções na AWS, onde lidera o engajamento de clientes para impulsionar a adoção bem-sucedida da nuvem e é especializado em arquiteturas SaaS e soluções de IA generativa. Ele produz conteúdo educacional, incluindo postagens em blogs e exemplos de código para ajudar os clientes a implementar as melhores práticas, e liderou programas sobre tópicos de GenAI para arquitetos de soluções. Steven traz décadas de experiência em tecnologia para sua função, ajudando clientes com análises arquitetônicas, otimização de custos e desenvolvimento de provas de conceito..

Sobre os tradutoes

Daniel Abib é Arquiteto de Soluções Sênior e Especialista em Amazon Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/

Rodrigo Faria é Especialista de Go-to-Market para IA na AWS, com mais de 10 anos de experiência em ciência de dados, machine learning e inteligência artificial. Ele trabalha com startups focando em IA generativa, escalando conhecimento técnico e direcionando a evolução de produtos com base no feedback do mercado.

https://www.linkedin.com/in/rodrigocfaria/