As limitações da pesquisa SCIM

Pesquisar usuários em uma organização Okta de grande porte não é tão fácil quanto parece. Caso eu deseje encontrar todos os prestadores de serviços de vendas em Los Angeles, preciso acertar a sintaxe SCIM exata ou não conseguirei os resultados esperados. Para encontrar usuários por atributos de perfil, por exemplo, seria necessário algo como:

profile.department eq "Sales" and profile.city eq "Los Angeles" and profile.userType eq "Contractor"

Essa sintaxe é desafiadora para muitos usuários porque:

  • É necessário conhecer a sintaxe específica.
  • Como a pesquisa é baseada em palavras-chave, uma consulta como “my direct reports” (meus subordinados diretos) não encontrará a lista de usuários que se reportam ao administrador atual. O console de administração da Okta permite a filtragem por ID de gerente, mas a pesquisa usual não entende que “my direct reports” deve ser convertido para profile.managerId igual ao ID do próprio administrador.
  • Um pequeno erro de digitação pode gerar resultados nulos ou inesperados. 

Em um hackathon interno recente, tentamos responder a uma pergunta simples: e se os administradores da Okta pudessem simplesmente digitar o que queriam dizer em inglês claro e deixar o sistema descobrir os detalhes do SCIM? Então:

Em vez de

Podemos usar

search=profile.department eq "Sales" and profile.title eq "Manager"

Encontre os gerentes e diretores de vendas para mim

profile.managerId eq "00u1ab2c3d4e"

Mostre-me todos os meus subordinados diretos

Para responder a isso, construímos um protótipo: um mecanismo de pesquisa semântica com tecnologia de IA que interpreta a linguagem natural, a associa aos recursos da Okta e retorna usuários e aplicativos relevantes sem exigir que o administrador utilize qualquer sintaxe SCIM. No restante deste artigo, vou explicar como montamos o protótipo e apresentar a visão para uma futura implementação pronta para produção.

Fluxo de trabalho de alto nível

Quando um administrador da Okta digita uma consulta em linguagem natural na barra de pesquisa global, o back-end Java da Okta intercepta as chamadas da API (/api/internal/admin/search e /api/v1/internal/apps). Em vez de executar uma consulta SCIM padrão imediatamente, ele faz uma chamada de API para o serviço de IA Python com a consulta bruta do usuário.

O serviço Python executa seu pipeline de pesquisa em vários estágios e retorna uma lista classificada de IDs de usuários e apps relevantes. O back-end Java pega esses IDs, recupera os objetos de recurso completos da camada de dados existente da Okta e constrói a resposta JSON final para ser exibida na interface do usuário. 

Arquitetura de serviço de IA Python

Camada de dados: para o protótipo, o serviço utiliza um processo de indexação offline. Ele busca usuários e aplicativos de uma organização Okta de demonstração, converte esses recursos em snapshots JSON locais e, em seguida, cria uma representação de texto para incorporação downstream.

Camada de inteligência da IA:

  • Serviço de incorporação: usamos modelos de incorporação AWS Bedrock (como Cohere Embed, Amazon Titan) para mapear cada documento de texto em um vetor. Esses vetores são armazenados em um índice FAISS (biblioteca de Pesquisa de Similaridade de IA do Facebook).
  • Processamento de linguagem natural: usamos LLMs como o Anthropic Claude 4.5 para interpretar consultas e gerar filtros SCIM.
  • Entendimento da consulta: um pequeno serviço heurístico extrai atributos estruturados (como department, city e managerId) da consulta em linguagem natural para refinar os resultados da pesquisa.

Pipeline de pesquisa avançada:

  • Processamento de consulta: a consulta recebida é analisada, expandida com sinônimos e convertida em um vetor.
  • Recuperação de candidatos: pesquisamos os vetores mais próximos no índice FAISS e atribuímos uma pontuação híbrida a cada correspondência.
  • Refinamento dos resultados: por fim, enviamos os principais candidatos para um modelo Cohere Rerank a fim de reordená-los antes de devolver a lista final de IDs de recursos.

Com o uso do índice de vetor FAISS nesse pipeline, reduzimos o espaço de busca de milhares de usuários e apps a um pequeno conjunto de candidatos. Isso diminui o tamanho do contexto passado para o modelo final de Rerank, reduzindo os custos operacionais e a latência.

Conjunto de dados construído com segurança

Utilizamos uma organização Okta de demonstração para evitar o contato com dados PII. Também geramos perfis aleatórios de usuários e aplicativos para preencher essa organização com dados realistas. Todos os dados foram criados por scripts Python personalizados e então exportados para arquivos JSON locais. Isso permitiu que o sistema fosse executado offline em relação às capturas de tela.

Conversão de objetos Okta em texto pesquisável

Perfis brutos de usuários e aplicativos não são suficientes para uma boa pesquisa semântica. Também precisamos capturar todo o contexto e a intenção deles. Nosso mecanismo de indexação offline realiza essa preparação de dados antes da criação de qualquer vetor. Para os objetos da Okta, os principais campos de texto são inicialmente combinados em um único documento de texto para garantir que o modelo de incorporação receba uma única descrição para interpretar.

As limitações conhecidas nos dados são abordadas em seguida com o objetivo de enriquecer tais documentos. Para os usuários, isso significa criar documentos com expansões de sinônimos para atributos populares e, para os aplicativos, incluir palavras-chave geradas heuristicamente com base nas propriedades do app (como adicionar "expense" (despesa) se o app for o Concur).

Camada de incorporação no Amazon Bedrock

A camada de incorporação Cohere inclui lógica de repetição e recorre ao modelo Titan em determinados cenários. Os vetores resultantes codificam o significado do documento em formato numérico e são normalizados para o comprimento da unidade antes do armazenamento. Assim, podem ser utilizados com a pesquisa do índice FAISS.

Classificação híbrida

Nosso método de pesquisa híbrida combina o sinal semântico da pesquisa vetorial com a correspondência de atributos mais tradicional. Para cada consulta, a etapa de compreensão heurística extrai dicas do texto fornecido pelo usuário (como o departamento ou a cidade). Na etapa de recuperação de candidatos, o índice FAISS é consultado para encontrar os vetores mais semelhantes. Em seguida, uma pontuação híbrida, que combina a similaridade vetorial com a presença de atributos extraídos, é atribuída aos resultados. Por fim, os principais candidatos são passados para o modelo Cohere Rerank, que faz a reordenação final.

Aprimoramentos futuros com LLMs e hooks de evento

Nosso protótipo do hackathon foi executado em um snapshot estático de dados. No entanto, para torná-lo um sistema pronto para produção, seriam necessárias duas melhorias: dados em tempo real e um método de pesquisa híbrido utilizando consultas dinâmicas.

Para manter o índice atualizado, substituiríamos os snapshots periódicos por uma arquitetura orientada por eventos usando os hooks de evento da Okta. Uma função serverless monitoraria os eventos do syslog da Okta e atualizaria o banco de dados vetorial, garantindo que o índice de pesquisa estivesse apenas alguns segundos atrás dos dados em tempo real.

Depois, utilizaríamos LLMs (como GPT ou Claude) para interpretar a consulta do usuário e gerar um filtro SCIM preciso, que seria executado diretamente na API Okta em tempo real. Isso garante que os resultados sejam recentes e precisos. 

Conclusão

A pesquisa semântica da Okta começou com uma pergunta simples: "E se os administradores não precisassem escrever outro filtro SCIM manualmente?" Ao montar um pipeline de IA (indexação de vetores, LLMs e pontuação híbrida), desenvolvemos um protótipo funcional que permite que os administradores pesquisem recursos da Okta em linguagem natural.

Se você é desenvolvedor e quer criar sistemas de IA para resolver problemas de identidade do mundo real, confira as oportunidades de carreira na página de carreiras da Okta ou inicie seus próprios projetos.

Continue sua jornada de identidade