Técnicas práticas de observabilidade para aplicativos de IA generativa em Java

1. Visão geral

Os aplicativos de IA generativa exigem observabilidade como qualquer outro. Há técnicas de observabilidade especiais necessárias para a IA generativa?

Neste laboratório, você vai criar um aplicativo simples do Gen AI. Implante no Cloud Run. E instrumente com recursos essenciais de monitoramento e geração de registros usando os serviços e produtos de observabilidade do Google Cloud.

O que você vai aprender

  • Criar um aplicativo que usa a Vertex AI com o editor do Cloud Shell
  • Armazenar o código do aplicativo no GitHub
  • Use a CLI gcloud para implantar o código-fonte do seu aplicativo no Cloud Run
  • Adicionar recursos de monitoramento e registro ao seu aplicativo de IA generativa
  • Como usar métricas com base em registros
  • Implementar a geração de registros e o monitoramento com o SDK do Open Telemetry
  • Receba insights sobre o processamento responsável de dados de IA

2. Pré-requisitos

Se você ainda não tem uma Conta do Google, crie uma.

3. Configurar o projeto

  1. Faça login no Console do Google Cloud com sua Conta do Google.
  2. Crie um novo projeto ou escolha reutilizar um projeto atual. Anote o ID do projeto que você acabou de criar ou selecionar.
  3. Ative o faturamento do projeto.
    • A conclusão deste laboratório deve custar menos de US $5 em custos de faturamento.
    • Siga as etapas no final deste laboratório para excluir recursos e evitar cobranças.
    • Novos usuários estão qualificados para o teste sem custo financeiro de US$300.
  4. Confirme se o faturamento está ativado em Meus projetos no Cloud Billing
      .
    • Se o novo projeto mostrar Billing is disabled na coluna Billing account:
      1. Clique nos três pontos na coluna Actions.
      2. Clique em Mudar faturamento.
      3. Selecione a conta de faturamento que você quer usar.
    • Se você estiver participando de um evento ao vivo, a conta provavelmente será chamada de Conta de faturamento de teste do Google Cloud Platform.

4. Preparar o editor do Cloud Shell

  1. Acesse o editor do Cloud Shell. Se você receber a mensagem a seguir solicitando a autorização do Cloud Shell para chamar o gcloud com suas credenciais, clique em Autorizar para continuar.
    Clique para autorizar o Cloud Shell
  2. Abrir janela do terminal
    1. Clique no menu de navegação Ícone do menu de navegação.
    2. Clique em Terminal.
    3. Clique em Novo terminal
      Abrir um novo terminal no editor do Cloud Shell.
  3. No terminal, configure o ID do projeto:
    gcloud config set project [PROJECT_ID]
    
    Substitua [PROJECT_ID] pelo ID do seu projeto. Por exemplo, se o ID do projeto for lab-example-project, o comando será:
    gcloud config set project lab-project-id-example
    
    Se você receber a seguinte mensagem informando que o gcloud está solicitando suas credenciais para a API GCPI, clique em Autorizar para continuar.
    Clique para autorizar o Cloud Shell
    Se a execução for bem-sucedida, você verá a seguinte mensagem:
    Updated property [core/project].
    
    Se você receber uma WARNING e receber uma solicitação Do you want to continue (Y/N)?, provavelmente inseriu o ID do projeto incorretamente. Pressione N, pressione Enter e tente executar o comando gcloud config set project novamente depois de encontrar o ID do projeto correto.
  4. (Opcional) Se você tiver problemas para encontrar o ID do projeto, execute o comando a seguir para conferir o ID de todos os seus projetos classificados por data de criação em ordem decrescente:
    gcloud projects list \
         --format='value(projectId,createTime)' \
         --sort-by=~createTime
    

5. ative as APIs do Google

No terminal, ative as APIs do Google necessárias para este laboratório:

gcloud services enable \
     run.googleapis.com \
     cloudbuild.googleapis.com \
     aiplatform.googleapis.com \
     logging.googleapis.com \
     monitoring.googleapis.com \
     cloudtrace.googleapis.com

Esse comando leva algum tempo para ser concluído. Uma mensagem semelhante a esta vai aparecer:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

Se você receber uma mensagem de erro começando com ERROR: (gcloud.services.enable) HttpError accessing e contendo detalhes de erro como abaixo, tente novamente o comando após um atraso de um a dois minutos.

"error": {
  "code": 429,
  "message": "Quota exceeded for quota metric 'Mutate requests' and limit 'Mutate requests per minute' of service 'serviceusage.googleapis.com' ...",
  "status": "RESOURCE_EXHAUSTED",
  ...
}

6. Criar um app de IA generativa

Nesta etapa, você vai escrever um código do aplicativo simples baseado em solicitações que usa o modelo Gemini para mostrar 10 curiosidades sobre um animal de sua escolha. Siga as instruções para criar o código do aplicativo.

  1. No terminal, crie o diretório codelab-o11y:
    mkdir "${HOME}/codelab-o11y"
    
  2. Mude o diretório atual para codelab-o11y:
    cd "${HOME}/codelab-o11y"
    
  3. Faça o download do código de inicialização do aplicativo Java usando o framework starter do Spring:
    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=17 \
        -d type=maven-project \
        -d bootVersion=3.4.1 -o java-starter.zip
    
  4. Desarquive o código de inicialização na pasta atual:
    unzip java-starter.zip
    
  5. E remova o arquivo da pasta:
    rm java-starter.zip
    
  6. Crie um arquivo project.toml para definir a versão do ambiente de execução Java a ser usada ao implantar o código no Cloud Run:
    cat > "${HOME}/codelab-o11y/project.toml" << EOF
    [[build.env]]
        name = "GOOGLE_RUNTIME_VERSION"
        value = "17"
    EOF
    
  7. Adicione as dependências do SDK do Google Cloud ao arquivo pom.xml:
    1. Adicione o pacote Google Cloud Core:
      sed -i 's/<dependencies>/<dependencies>\
      \
              <dependency>\
                  <groupId>com.google.cloud<\/groupId>\
                  <artifactId>google-cloud-core<\/artifactId>\
                  <version>2.49.1<\/version>\
              <\/dependency>\
              /g' "${HOME}/codelab-o11y/pom.xml"
      
    2. Adicione o pacote da Vertex AI do Google Cloud:
      sed -i 's/<dependencies>/<dependencies>\
      \
              <dependency>\
                  <groupId>com.google.cloud<\/groupId>\
                  <artifactId>google-cloud-vertexai<\/artifactId>\
                  <version>1.16.0<\/version>\
              <\/dependency>\
              /g' "${HOME}/codelab-o11y/pom.xml"
      
  8. Abra o arquivo DemoApplication.java no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java"
    
    Um código-fonte esquemático do arquivo DemoApplication.java vai aparecer na janela do editor acima do terminal. O código-fonte do arquivo será semelhante a este:
    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
  9. Substitua o código no editor pela versão mostrada abaixo. Para substituir o código, exclua o conteúdo do arquivo e copie o código abaixo no editor:
    package com.example.demo;
    
    import java.io.IOException;
    import java.util.Collections;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.google.cloud.ServiceOptions;
    import com.google.cloud.vertexai.VertexAI;
    import com.google.cloud.vertexai.api.GenerateContentResponse;
    import com.google.cloud.vertexai.generativeai.GenerativeModel;
    import com.google.cloud.vertexai.generativeai.ResponseHandler;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            String port = System.getenv().getOrDefault("PORT", "8080");
            SpringApplication app = new SpringApplication(DemoApplication.class);
            app.setDefaultProperties(Collections.singletonMap("server.port", port));
            app.run(args);
        }
    }
    
    @RestController
    class HelloController {
        private final String projectId = ServiceOptions.getDefaultProjectId();
        private VertexAI vertexAI;
        private GenerativeModel model;
    
        @PostConstruct
        public void init() {
            vertexAI = new VertexAI(projectId, "us-central1");
            model = new GenerativeModel("gemini-1.5-flash", vertexAI);
        }
    
        @PreDestroy
        public void destroy() {
            vertexAI.close();
        }
    
        @GetMapping("/")
        public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException {
            String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks.";
            GenerateContentResponse response = model.generateContent(prompt);
            return ResponseHandler.getText(response);
        }
    }
    
    Depois de alguns segundos, o editor do Cloud Shell vai salvar o código automaticamente.

Implantar o código do aplicativo de IA generativa no Cloud Run

  1. Na janela do terminal, execute o comando para implantar o código-fonte do aplicativo no Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Se você receber uma mensagem como a abaixo, o comando vai criar um novo repositório. Clique em Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    O processo de implantação pode levar alguns minutos. Depois que o processo de implantação for concluído, você vai receber uma saída como esta:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Copie o URL do serviço do Cloud Run exibido para uma guia ou janela separada no navegador. Como alternativa, execute o comando a seguir no terminal para imprimir o URL do serviço e clique no URL mostrado enquanto pressiona a tecla Ctrl para abrir o URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Quando o URL é aberto, você pode receber um erro 500 ou a mensagem:
    Sorry, this is just a placeholder...
    
    Isso significa que os serviços não concluíram a implantação. Aguarde alguns instantes e atualize a página. No final, você vai encontrar um texto que começa com Curiosidades sobre cães e contém 10 curiosidades sobre cães.

Tente interagir com o aplicativo para conferir curiosidades sobre diferentes animais. Para fazer isso, anexe o parâmetro animal ao URL, como ?animal=[ANIMAL], em que [ANIMAL] é o nome de um animal. Por exemplo, adicione ?animal=cat para receber 10 curiosidades sobre gatos ou ?animal=sea turtle para receber 10 curiosidades sobre tartarugas marinhas.

7. Auditar suas chamadas da API Vertex

A auditoria das chamadas de API do Google responde a perguntas como "Quem chamou uma API específica, onde e quando?". A auditoria é importante quando você soluciona problemas no aplicativo, investiga o consumo de recursos ou realiza análises forenses de software.

Os registros de auditoria permitem acompanhar atividades administrativas e do sistema, além de registrar chamadas para operações de "leitura de dados" e "gravação de dados" da API. Para auditar solicitações da Vertex AI para gerar conteúdo, ative os registros de auditoria "Leitura de dados" no console do Cloud.

  1. Clique no botão abaixo para abrir a página "Registros de auditoria" no console do Cloud

  2. Verifique se a página tem o projeto que você criou para este laboratório selecionado. O projeto selecionado aparece no canto superior esquerdo da página, no menu de navegação:
    Menu suspenso de projetos do Console do Google Cloud
    Se necessário, selecione o projeto correto na caixa de combinação.
  3. Na tabela Configuração dos registros de auditoria de acesso a dados, na coluna "Serviço", encontre o serviço Vertex AI API e selecione-o marcando a caixa de seleção à esquerda do nome do serviço.
    Selecionar a API Vertex AI
  4. No painel de informações à direita, selecione o tipo de auditoria "Leitura de dados".
    Verificar os registros de leitura de dados
  5. Clique em Salvar.

Para gerar registros de auditoria, abra o URL do serviço. Atualize a página enquanto muda o valor do parâmetro ?animal= para obter resultados diferentes.

Acessar registros de auditoria

  1. Clique no botão abaixo para abrir a página do Logs Explorer no console do Cloud:

  2. Cole o filtro a seguir no painel "Consulta".
    LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND
    protoPayload.serviceName="aiplatform.googleapis.com"
    
    O painel "Query" é um editor localizado na parte de cima da página "Explorador de registros":
    Consultar registros de auditoria
  3. Clique em Executar consulta.
  4. Selecione uma das entradas do registro de auditoria e abra os campos para inspecionar as informações capturadas no registro.
    É possível conferir detalhes sobre a chamada da API Vertex, incluindo o método e o modelo usado. Você também pode conferir a identidade do invocador e quais permissões autorizaram a chamada.

8. Registrar interações com a IA generativa

Não é possível encontrar parâmetros de solicitação de API ou dados de resposta nos registros de auditoria. No entanto, essas informações podem ser importantes para solucionar problemas de análise de aplicativos e fluxos de trabalho. Nesta etapa, vamos preencher essa lacuna adicionando o registro do aplicativo.

A implementação usa o Logback com o Spring Boot para imprimir os registros do aplicativo na saída padrão. Esse método usa a capacidade do Cloud Run de capturar informações impressas na saída padrão e transferi-las automaticamente para o Cloud Logging. Para capturar informações como dados estruturados, os registros impressos precisam ser formatados de maneira adequada. Siga as instruções abaixo para adicionar recursos de geração de registros estruturados ao aplicativo.

  1. Volte para a janela (ou guia) do Cloud Shell no navegador.
  2. Crie e abra um novo arquivo LoggingEventGoogleCloudEncoder.java no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java"
    
  3. Copie e cole o código abaixo para implementar o codificador Logback, que codifica o registro como um JSON stringificado seguindo o formato de registro estruturado do Google Cloud:
    package com.example.demo;
    
    import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET;
    
    import java.time.Instant;
    import ch.qos.logback.core.encoder.EncoderBase;
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import java.util.HashMap;
    
    import com.google.gson.Gson;
    
    public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent>  {
        private static final byte[] EMPTY_BYTES = new byte[0];
        private final Gson gson = new Gson();
    
        @Override
        public byte[] headerBytes() {
            return EMPTY_BYTES;
        }
    
        @Override
        public byte[] encode(ILoggingEvent e) {
            var timestamp = Instant.ofEpochMilli(e.getTimeStamp());
            var fields = new HashMap<String, Object>() {
                {
                    put("timestamp", timestamp.toString());
                    put("severity", severityFor(e.getLevel()));
                    put("message", e.getMessage());
                }
            };
            var params = e.getKeyValuePairs();
            if (params != null && params.size() > 0) {
                params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value));
            }
            var data = gson.toJson(fields) + "\n";
            return data.getBytes(UTF_8_CHARSET);
        }
    
        @Override
        public byte[] footerBytes() {
            return EMPTY_BYTES;
        }
    
        private static String severityFor(Level level) {
            switch (level.toInt()) {
                case Level.TRACE_INT:
                return "DEBUG";
                case Level.DEBUG_INT:
                return "DEBUG";
                case Level.INFO_INT:
                return "INFO";
                case Level.WARN_INT:
                return "WARNING";
                case Level.ERROR_INT:
                return "ERROR";
                default:
                return "DEFAULT";
            }
        }
    }
    
  4. Crie e abra um novo arquivo logback.xml no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/resources/logback.xml"
    
  5. Copie e cole o XML a seguir para configurar o Logback para usar o codificador com o Logback appender que imprime registros na saída padrão:
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="true">
        <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="com.example.demo.LoggingEventGoogleCloudEncoder"/>
        </appender>
    
        <root level="info">
            <appender-ref ref="Console" />
        </root>
    </configuration>
    
  6. Abra novamente o arquivo DemoApplication.java no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java"
    
  7. Substitua o código no editor pela versão mostrada abaixo para registrar a solicitação e a resposta da IA generativa. Para substituir o código, exclua o conteúdo do arquivo e copie o código abaixo no editor:
    package com.example.demo;
    
    import java.io.IOException;
    import java.util.Collections;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.google.cloud.ServiceOptions;
    import com.google.cloud.vertexai.VertexAI;
    import com.google.cloud.vertexai.api.GenerateContentResponse;
    import com.google.cloud.vertexai.generativeai.GenerativeModel;
    import com.google.cloud.vertexai.generativeai.ResponseHandler;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            String port = System.getenv().getOrDefault("PORT", "8080");
            SpringApplication app = new SpringApplication(DemoApplication.class);
            app.setDefaultProperties(Collections.singletonMap("server.port", port));
            app.run(args);
        }
    }
    
    @RestController
    class HelloController {
        private final String projectId = ServiceOptions.getDefaultProjectId();
        private VertexAI vertexAI;
        private GenerativeModel model;
        private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class);
    
        @PostConstruct
        public void init() {
            vertexAI = new VertexAI(projectId, "us-central1");
            model = new GenerativeModel("gemini-1.5-flash", vertexAI);
        }
    
        @PreDestroy
        public void destroy() {
            vertexAI.close();
        }
    
        @GetMapping("/")
        public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException {
            String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks.";
            GenerateContentResponse response = model.generateContent(prompt);
            LOGGER.atInfo()
                    .addKeyValue("animal", animal)
                    .addKeyValue("prompt", prompt)
                    .addKeyValue("response", response)
                    .log("Content is generated");
            return ResponseHandler.getText(response);
        }
    }
    

Depois de alguns segundos, o editor do Cloud Shell salva suas alterações automaticamente.

Implantar o código do aplicativo de IA generativa no Cloud Run

  1. Na janela do terminal, execute o comando para implantar o código-fonte do aplicativo no Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Se você receber uma mensagem como a abaixo, o comando vai criar um novo repositório. Clique em Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    O processo de implantação pode levar alguns minutos. Depois que o processo de implantação for concluído, você vai receber uma saída como esta:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Copie o URL do serviço do Cloud Run exibido para uma guia ou janela separada no navegador. Como alternativa, execute o comando a seguir no terminal para imprimir o URL do serviço e clique no URL mostrado enquanto pressiona a tecla Ctrl para abrir o URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Quando o URL é aberto, você pode receber um erro 500 ou a mensagem:
    Sorry, this is just a placeholder...
    
    Isso significa que os serviços não concluíram a implantação. Aguarde alguns instantes e atualize a página. No final, você vai encontrar um texto que começa com Curiosidades sobre cães e contém 10 curiosidades sobre cães.

Para gerar registros do aplicativo, abra o URL do serviço. Atualize a página enquanto muda o valor do parâmetro ?animal= para obter resultados diferentes.
Para conferir os registros do aplicativo, faça o seguinte:

  1. Clique no botão abaixo para abrir a página do Logs Explorer no console do Cloud:

  2. Cole o seguinte filtro no painel de consulta (#2 na interface do Gerenciador de registros):
    LOG_ID("run.googleapis.com%2Fstdout") AND
    severity=DEBUG
    
  3. Clique em Executar consulta.

O resultado da consulta mostra registros com o comando e a resposta da Vertex AI, incluindo as classificações de segurança.

9. Contar interações com a IA generativa

O Cloud Run grava métricas gerenciadas que podem ser usadas para monitorar os serviços implantados. As métricas de monitoramento gerenciadas pelo usuário oferecem mais controle sobre os dados e a frequência da atualização da métrica. Para implementar essa métrica, é necessário escrever um código que colete dados e os grave no Cloud Monitoring. Consulte a próxima etapa (opcional) para saber como implementar usando o SDK do OpenTelemetry.

Esta etapa mostra uma alternativa para implementar a métrica do usuário no código: métricas com base em registros. As métricas com base em registros permitem gerar métricas de monitoramento com base nas entradas de registro que seu aplicativo grava no Cloud Logging. Vamos usar os registros do aplicativo que implementamos na etapa anterior para definir uma métrica com base em registros do contador de tipo. A métrica vai contar o número de chamadas bem-sucedidas para a API Vertex.

  1. Observe a janela do Explorador de registros que usamos na etapa anterior. No painel "Consulta", localize o menu suspenso Ações e clique nele para abrir. Consulte a captura de tela abaixo para encontrar o menu:
    Barra de ferramentas dos resultados da consulta com o menu suspenso &quot;Ações&quot;
  2. No menu aberto, selecione Criar métrica para abrir o painel Criar métrica com base em registros.
  3. Siga estas etapas para configurar uma nova métrica de contagem no painel Criar métrica com base em registros:
    1. Defina o Tipo de métrica: selecione Contador.
    2. Defina os seguintes campos na seção Detalhes:
      • Nome da métrica de registro: defina o nome como model_interaction_count. Algumas restrições de nomenclatura se aplicam. Consulte Solução de problemas para mais detalhes.
      • Descrição: insira uma descrição para a métrica. Por exemplo, Number of log entries capturing successful call to model inference.
      • Unidades: deixe em branco ou insira o dígito 1.
    3. Deixe os valores na seção Seleção de filtro. O campo Build filter tem o mesmo filtro que usamos para conferir os registros do aplicativo.
    4. (Opcional) Adicione um rótulo que ajude a contar o número de chamadas para cada animal. OBSERVAÇÃO: esse rótulo pode aumentar muito a cardinalidade da métrica e não é recomendado para uso na produção:
      1. Clique em Adicionar rótulo.
      2. Defina os seguintes campos na seção Rótulos:
        • Nome do rótulo: defina o nome como animal.
        • Descrição: insira a descrição do rótulo. Por exemplo, Animal parameter.
        • Tipo de rótulo: selecione STRING.
        • Nome do campo: digite jsonPayload.animal.
        • Expressão regular: deixe em branco.
      3. Clique em Concluir.
    5. Clique em Criar métrica para criá-la.

Também é possível criar uma métrica com base em registros na página Métricas com base em registros usando o comando CLI gcloud logging metrics create ou o recurso do Terraform google_logging_metric.

Para gerar dados de métrica, abra o URL do serviço. Atualize a página aberta várias vezes para fazer várias chamadas para o modelo. Como antes, tente usar animais diferentes no parâmetro.

Insira a consulta PromQL para pesquisar os dados de métrica com base em registros. Para inserir uma consulta em PromQL, faça o seguinte:

  1. Clique no botão abaixo para abrir a página do Metrics Explorer no console do Cloud:

  2. Na barra de ferramentas do painel do criador de consultas, selecione o botão < > MQL ou < > PromQL. Confira a imagem abaixo para ver a localização do botão.
    Local do botão MQL no Metrics Explorer
  3. Verifique se PromQL está selecionado no botão de alternância Idioma. A alternância de idiomas está na mesma barra de ferramentas que permite formatar sua consulta.
  4. Insira sua consulta no editor Consultas:
    sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
    
    Para mais informações sobre como usar o PromQL, consulte PromQL no Cloud Monitoring.
  5. Selecione Executar consulta. Você vai encontrar um gráfico de linhas semelhante a esta captura de tela:
    Mostrar métricas consultadas

    Observe que, quando a opção Execução automática está ativada, o botão Executar consulta não é exibido.

10. (Opcional) Usar a telemetria aberta para monitoramento e rastreamento

Como mencionado na etapa anterior, é possível implementar métricas usando o SDK do OpenTelemetry (Otel). O uso do OTel em arquiteturas multiserviço é uma prática recomendada. Esta etapa demonstra como adicionar a instrumentação do OTel a um aplicativo Spring Boot. Nesta etapa, você vai fazer o seguinte:

  • Instrumentar o aplicativo Spring Boot com recursos de rastreamento automático
  • Implementar uma métrica de contador para monitorar o número de chamadas de modelo bem-sucedidas
  • Correlacionar o rastreamento com os registros do aplicativo

A arquitetura recomendada para serviços no nível do produto é usar o OTel Collector para coletar e processar todos os dados de observabilidade de vários serviços. O código desta etapa não usa o coletor para simplificar. Em vez disso, ele usa exportações do OTel que gravam dados diretamente no Google Cloud.

Configurar o aplicativo Spring Boot com componentes OTel e rastreamento automático

  1. Volte para a janela (ou guia) do Cloud Shell no navegador.
  2. No terminal, atualize o arquivo application.permissions com outros parâmetros de configuração:
    cat >> "${HOME}/codelab-o11y/src/main/resources/application.properties" << EOF
    otel.logs.exporter=none
    otel.traces.exporter=google_cloud_trace
    otel.metrics.exporter=google_cloud_monitoring
    otel.resource.attributes.service.name=codelab-o11y-service
    otel.traces.sampler=always_on
    EOF
    
    Esses parâmetros definem a exportação de dados de observabilidade para o Cloud Trace e o Cloud Monitoring e aplicam a amostragem de todos os traces.
  3. Adicione as dependências necessárias do OpenTelemetry ao arquivo pom.xml:
    sed -i 's/<dependencies>/<dependencies>\
    \
            <dependency>\
                <groupId>io.opentelemetry.instrumentation<\/groupId>\
                <artifactId>opentelemetry-spring-boot-starter<\/artifactId>\
            <\/dependency>\
            <dependency>\
                <groupId>com.google.cloud.opentelemetry<\/groupId>\
                <artifactId>exporter-auto<\/artifactId>\
                <version>0.33.0-alpha<\/version>\
            <\/dependency>\
            <dependency>\
                <groupId>com.google.cloud.opentelemetry<\/groupId>\
                <artifactId>exporter-trace<\/artifactId>\
                <version>0.33.0<\/version>\
            <\/dependency>\
            <dependency>\
                <groupId>com.google.cloud.opentelemetry<\/groupId>\
                <artifactId>exporter-metrics<\/artifactId>\
                <version>0.33.0<\/version>\
            <\/dependency>\
    /g' "${HOME}/codelab-o11y/pom.xml"
    
  4. Adicione o BOM do OpenTelemetry ao arquivo pom.xml:
    sed -i 's/<\/properties>/<\/properties>\
        <dependencyManagement>\
            <dependencies>\
                <dependency>\
                    <groupId>io.opentelemetry.instrumentation<\/groupId>\
                    <artifactId>opentelemetry-instrumentation-bom<\/artifactId>\
                    <version>2.12.0<\/version>\
                    <type>pom<\/type>\
                    <scope>import<\/scope>\
                <\/dependency>\
            <\/dependencies>\
        <\/dependencyManagement>\
    /g' "${HOME}/codelab-o11y/pom.xml"
    
  5. Abra novamente o arquivo DemoApplication.java no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java"
    
  6. Substitua o código atual pela versão que incrementa uma métrica de desempenho. Para substituir o código, exclua o conteúdo do arquivo e copie o código abaixo no editor:
    package com.example.demo;
    
    import io.opentelemetry.api.common.AttributeKey;
    import io.opentelemetry.api.common.Attributes;
    import io.opentelemetry.api.OpenTelemetry;
    import io.opentelemetry.api.metrics.LongCounter;
    
    import java.io.IOException;
    import java.util.Collections;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.google.cloud.ServiceOptions;
    import com.google.cloud.vertexai.VertexAI;
    import com.google.cloud.vertexai.api.GenerateContentResponse;
    import com.google.cloud.vertexai.generativeai.GenerativeModel;
    import com.google.cloud.vertexai.generativeai.ResponseHandler;
    
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            String port = System.getenv().getOrDefault("PORT", "8080");
            SpringApplication app = new SpringApplication(DemoApplication.class);
            app.setDefaultProperties(Collections.singletonMap("server.port", port));
            app.run(args);
        }
    }
    
    @RestController
    class HelloController {
        private final String projectId = ServiceOptions.getDefaultProjectId();
        private VertexAI vertexAI;
        private GenerativeModel model;
        private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class);
        private static final String INSTRUMENTATION_NAME = "genai-o11y/java/workshop/example";
        private static final AttributeKey<String> ANIMAL = AttributeKey.stringKey("animal");
        private final LongCounter counter;
    
        public HelloController(OpenTelemetry openTelemetry) {
            this.counter = openTelemetry.getMeter(INSTRUMENTATION_NAME)
                    .counterBuilder("model_call_counter")
                    .setDescription("Number of successful model calls")
                    .build();
        }
    
        @PostConstruct
        public void init() {
            vertexAI = new VertexAI(projectId, "us-central1");
            model = new GenerativeModel("gemini-1.5-flash", vertexAI);
        }
    
        @PreDestroy
        public void destroy() {
            vertexAI.close();
        }
    
        @GetMapping("/")
        public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException {
            String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks.";
            GenerateContentResponse response = model.generateContent(prompt);
            LOGGER.atInfo()
                    .addKeyValue("animal", animal)
                    .addKeyValue("prompt", prompt)
                    .addKeyValue("response", response)
                    .log("Content is generated");
            counter.add(1, Attributes.of(ANIMAL, animal));
            return ResponseHandler.getText(response);
        }
    }
    
  7. Abra novamente o arquivo LoggingEventGoogleCloudEncoder.java no editor do Cloud Shell:
    cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java"
    
  8. Substitua o código atual pela versão que adiciona atributos de rastreamento aos registros escritos. A adição dos atributos permite que os registros sejam correlacionados com os intervalos de rastreamento corretos. Para substituir o código, exclua o conteúdo do arquivo e copie o código abaixo no editor:
    package com.example.demo;
    
    import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET;
    
    import java.time.Instant;
    import java.util.HashMap;
    
    import ch.qos.logback.core.encoder.EncoderBase;
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import com.google.cloud.ServiceOptions;
    import io.opentelemetry.api.trace.Span;
    import io.opentelemetry.api.trace.SpanContext;
    import io.opentelemetry.context.Context;
    
    import com.google.gson.Gson;
    
    
    public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent>  {
        private static final byte[] EMPTY_BYTES = new byte[0];
        private final Gson gson;
        private final String projectId;
        private final String tracePrefix;
    
    
        public LoggingEventGoogleCloudEncoder() {
            this.gson = new Gson();
            this.projectId = lookUpProjectId();
            this.tracePrefix = "projects/" + (projectId == null ? "" : projectId) + "/traces/";
        }
    
        private static String lookUpProjectId() {
            return ServiceOptions.getDefaultProjectId();
        }
    
        @Override
        public byte[] headerBytes() {
            return EMPTY_BYTES;
        }
    
        @Override
        public byte[] encode(ILoggingEvent e) {
            var timestamp = Instant.ofEpochMilli(e.getTimeStamp());
            var fields = new HashMap<String, Object>() {
                {
                    put("timestamp", timestamp.toString());
                    put("severity", severityFor(e.getLevel()));
                    put("message", e.getMessage());
                    SpanContext context = Span.fromContext(Context.current()).getSpanContext();
                    if (context.isValid()) {
                        put("logging.googleapis.com/trace", tracePrefix + context.getTraceId());
                        put("logging.googleapis.com/spanId", context.getSpanId());
                        put("logging.googleapis.com/trace_sampled", Boolean.toString(context.isSampled()));
                    }
                }
            };
            var params = e.getKeyValuePairs();
            if (params != null && params.size() > 0) {
                params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value));
            }
            var data = gson.toJson(fields) + "\n";
            return data.getBytes(UTF_8_CHARSET);
        }
    
        @Override
        public byte[] footerBytes() {
            return EMPTY_BYTES;
        }
    
        private static String severityFor(Level level) {
            switch (level.toInt()) {
                case Level.TRACE_INT:
                return "DEBUG";
                case Level.DEBUG_INT:
                return "DEBUG";
                case Level.INFO_INT:
                return "INFO";
                case Level.WARN_INT:
                return "WARNING";
                case Level.ERROR_INT:
                return "ERROR";
                default:
                return "DEFAULT";
            }
        }
    }
    

Depois de alguns segundos, o editor do Cloud Shell salva suas alterações automaticamente.

Implantar o código do aplicativo de IA generativa no Cloud Run

  1. Na janela do terminal, execute o comando para implantar o código-fonte do aplicativo no Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Se você receber uma mensagem como a abaixo, o comando vai criar um novo repositório. Clique em Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    O processo de implantação pode levar alguns minutos. Depois que o processo de implantação for concluído, você vai receber uma saída como esta:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Copie o URL do serviço do Cloud Run exibido para uma guia ou janela separada no navegador. Como alternativa, execute o comando a seguir no terminal para imprimir o URL do serviço e clique no URL mostrado enquanto pressiona a tecla Ctrl para abrir o URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Quando o URL é aberto, você pode receber um erro 500 ou a mensagem:
    Sorry, this is just a placeholder...
    
    Isso significa que os serviços não concluíram a implantação. Aguarde alguns instantes e atualize a página. No final, você vai encontrar um texto que começa com Curiosidades sobre cães e contém 10 curiosidades sobre cães.

Para gerar dados de telemetria, abra o URL do serviço. Atualize a página enquanto muda o valor do parâmetro ?animal= para obter resultados diferentes.

Analisar rastros de aplicativos

  1. Clique no botão abaixo para abrir a página do explorador de traces no console do Cloud:

  2. Selecione um dos rastros mais recentes. Você deve ver cinco ou seis spans que se parecem com a captura de tela abaixo.
    Visualização do período do app no explorador de Trace
  3. Encontre o período que rastreia a chamada para o manipulador de eventos (o método fun_facts). Será o último trecho com o nome /.
  4. No painel Detalhes do trace, selecione Registros e eventos. Você vai encontrar registros de aplicativos que se correlacionam a esse período específico. A correlação é detectada usando os IDs de trace e de período no trace e no registro. Você vai encontrar o registro do aplicativo que gravou a solicitação e a resposta da API Vertex.

Conhecer a métrica de contador

  1. Clique no botão abaixo para abrir a página do Metrics Explorer no console do Cloud:

  2. Na barra de ferramentas do painel do criador de consultas, selecione o botão < > MQL ou < > PromQL. Confira a imagem abaixo para ver a localização do botão.
    Local do botão MQL no Metrics Explorer
  3. Verifique se PromQL está selecionado no botão de alternância Idioma. A alternância de idiomas está na mesma barra de ferramentas que permite formatar sua consulta.
  4. Insira sua consulta no editor Consultas:
    sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
    
  5. Clique em Executar consulta.Quando a opção Execução automática está ativada, o botão Executar consulta não é mostrado.

11. (Opcional) Informações sensíveis ofuscadas dos registros

Na etapa 10, registramos informações sobre a interação do aplicativo com o modelo Gemini. Essas informações incluíam o nome do animal, o comando e a resposta do modelo. Embora o armazenamento dessas informações no registro seja seguro, isso não é necessário para muitos outros cenários. A solicitação pode incluir informações pessoais ou sensíveis que o usuário não quer que sejam armazenadas. Para resolver isso, você pode ofuscar os dados sensíveis gravados no Cloud Logging. Para minimizar as modificações no código, recomendamos a solução abaixo.

  1. Criar um tópico do Pub/Sub para armazenar entradas de registro recebidas
  2. Crie um coletor de registros que redirecione os registros ingeridos para o tópico do Pub/Sub.
  3. Crie um pipeline do Dataflow que modifique os registros redirecionados para o tópico do Pub/Sub seguindo estas etapas:
    1. Ler uma entrada de registro do tópico do PubSub
    2. Inspecione o payload da entrada em busca de informações sensíveis usando a API de inspeção de DLP.
    3. Edite as informações sensíveis no payload usando um dos métodos de edição da DLP.
    4. Gravar a entrada de registro ofuscada no Cloud Logging
  4. Implante o pipeline.

12. (Opcional) Limpar

Para evitar cobranças por recursos e APIs usados no codelab, é recomendável limpar o ambiente após o término do laboratório. A maneira mais fácil de evitar cobranças é excluindo o projeto criado para o codelab.

  1. Para excluir o projeto, execute o comando "delete project" no terminal:
    PROJECT_ID=$(gcloud config get-value project)
    gcloud projects delete ${PROJECT_ID} --quiet
    
    A exclusão do projeto do Cloud interrompe o faturamento de todos os recursos e APIs usados nele. Você vai receber esta mensagem, em que PROJECT_ID será o ID do projeto:
    Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID].
    
    You can undo this operation for a limited period by running the command below.
        $ gcloud projects undelete PROJECT_ID
    
    See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects.
    
  2. (Opcional) Se você receber um erro, consulte a etapa 5 para encontrar o ID do projeto que você usou durante o laboratório. Substitua-o pelo comando na primeira instrução. Por exemplo, se o ID do projeto for lab-example-project, o comando será:
    gcloud projects delete lab-project-id-example --quiet
    

13. Parabéns

Neste laboratório, você criou um aplicativo de IA generativa que usa o modelo Gemini para fazer previsões. E instrumentou o aplicativo com recursos essenciais de monitoramento e geração de registros. Você implantou o aplicativo e fez alterações do código-fonte para o Cloud Run. Em seguida, use os produtos do Google Cloud Observability para acompanhar a performance do aplicativo e garantir a confiabilidade dele.

Se você tem interesse em participar de um estudo de pesquisa de experiência do usuário (UX) para melhorar os produtos com que trabalha hoje, faça sua inscrição aqui.

Confira algumas opções para continuar aprendendo: