Close Menu
Código Simples .NETCódigo Simples .NET
    Facebook X (Twitter) Instagram
    Trending
    • Observabilidade de IA com OpenTelemetry: o que realmente deveria aparecer no trace?
    • Rate limiting não é só proteção contra abuso. É contrato de capacidade
    • Feature flag não é interruptor. É dívida operacional com prazo de validade
    • O modelo é infraestrutura: por que LLM deveria ser adapter, não o centro da sua arquitetura
    • O novo gargalo não é escrever código. É absorver mudança com qualidade
    • A próxima geração de arquitetura será julgada por tempo de entendimento, não só por tempo de resposta
    • A arquitetura virou sociotécnica de vez
    • Reduzir carga cognitiva é uma decisão arquitetural
    Facebook X (Twitter) Instagram
    Código Simples .NETCódigo Simples .NET
    Código Simples .NETCódigo Simples .NET
    Home»IA»Observabilidade de IA com OpenTelemetry: o que realmente deveria aparecer no trace?

    Observabilidade de IA com OpenTelemetry: o que realmente deveria aparecer no trace?

    Jhonathan SoaresBy Jhonathan Soares15 de julho de 202613 Mins Read IA
    Share
    Facebook Twitter LinkedIn WhatsApp Copy Link

    Instrumentar uma aplicação de IA com OpenTelemetry pode parecer simples. A requisição entra, a aplicação chama um modelo, recebe uma resposta e encerra o trace. No dashboard, vemos que uma chamada levou três segundos e terminou sem erro. Tecnicamente, o sistema está instrumentado. Na prática, ainda sabemos muito pouco sobre o que aconteceu.

    Uma resposta ruim pode ter sido causada pelo modelo, pelo contexto enviado, por um documento desatualizado, por uma ferramenta que retornou dados incompletos ou por um fallback acionado silenciosamente. Também é possível que a chamada tenha funcionado perfeitamente do ponto de vista técnico, mas a resposta tenha violado uma regra do negócio.

    Um trace tradicional costuma responder perguntas como: quanto tempo a requisição levou, quais serviços foram chamados e onde ocorreu uma exceção. Em aplicações de IA, precisamos responder algumas perguntas adicionais: qual modelo foi utilizado, qual versão do prompt estava ativa, que contexto foi recuperado, quais ferramentas participaram e se a resposta passou pelos critérios de qualidade esperados.

    Isso não significa registrar tudo. O trace não deveria virar uma cópia completa da conversa, dos documentos internos e dos argumentos enviados às ferramentas. O objetivo é registrar informações suficientes para explicar a execução sem transformar a plataforma de observabilidade em um novo risco de segurança.

    OpenTelemetry continua sendo OpenTelemetry

    OpenTelemetry não é uma ferramenta exclusiva para IA. Ele continua oferecendo os mesmos conceitos usados em sistemas distribuídos tradicionais: traces, spans, métricas e logs. O que muda é o tipo de operação que queremos representar.

    Em uma aplicação comum, um trace pode mostrar uma chamada HTTP, uma consulta ao banco e uma publicação em fila. Em uma aplicação de IA, o mesmo trace também pode mostrar:

    • a execução de um agente ou workflow;
    • a recuperação de contexto;
    • uma ou mais chamadas ao modelo;
    • o uso de ferramentas;
    • a aplicação de guardrails;
    • a avaliação da resposta;
    • um fallback para outro modelo ou para atendimento humano.

    A instrumentação automática ainda é importante. Ela mostra chamadas HTTP, acesso a banco, filas e dependências externas. Porém, essas operações não explicam sozinhas a intenção do sistema. Para isso, normalmente precisamos adicionar alguns spans de negócio.

    Um trace precisa contar a história da execução

    Imagine um assistente de atendimento que responde dúvidas sobre reembolso. Para produzir uma resposta, ele consulta uma política interna, chama um modelo, busca os dados do pedido e verifica se a resposta respeita as regras da empresa.

    Um trace útil poderia ser representado assim:

    POST /support/answer
    └── responder dúvida sobre reembolso
        ├── recuperar política de reembolso
        ├── chamar modelo
        ├── consultar pedido
        ├── chamar modelo novamente
        └── validar resposta

    Essa árvore é mais útil do que enxergar apenas:

    POST /support/answer
    └── POST /model

    No segundo caso, sabemos que o modelo foi chamado. No primeiro, conseguimos entender o caminho percorrido pela aplicação.

    O trace não precisa representar cada detalhe interno do algoritmo. Ele precisa destacar as etapas que ajudam alguém a investigar latência, custo, comportamento ou qualidade.

    O span principal deve representar a tarefa

    O span principal da execução deveria representar o que a aplicação está tentando fazer. Nomes genéricos como agent, llm-call ou ai-operation fornecem pouca informação.

    Alguns nomes mais úteis seriam:

    responder dúvida sobre reembolso
    analisar incidente de checkout
    revisar pull request
    extrair informações de contrato
    classificar solicitação de suporte

    Nesse span principal, podemos registrar informações estáveis sobre a tarefa:

    workflow.name: customer-support
    workflow.version: 3.2
    task.type: refund-question
    result: answered
    fallback.used: false
    human.review.required: false

    Esses atributos permitem comparar execuções sem registrar a pergunta completa do usuário. Também facilitam métricas como taxa de fallback por workflow, latência por tipo de tarefa e percentual de casos enviados para revisão humana.

    O que registrar na chamada ao modelo

    A chamada ao modelo é uma parte importante do trace, mas não deveria ser a única. Nesse span, o objetivo é registrar informações que ajudem a identificar mudanças de comportamento, custo e performance.

    As informações mais úteis normalmente são:

    InformaçãoPor que ajuda
    OperaçãoDiferencia chat, geração, embedding ou classificação
    ProviderMostra qual plataforma executou a chamada
    Modelo solicitadoIndica o modelo configurado pela aplicação
    Modelo utilizadoMostra a versão que realmente respondeu
    Versão do promptPermite relacionar regressões a uma mudança
    Tokens de entradaAjuda a entender contexto e custo
    Tokens de saídaAjuda a entender custo e tamanho da resposta
    DuraçãoMostra o tempo total da chamada
    Motivo de encerramentoIndica conclusão, limite de tokens, bloqueio ou erro
    Número da tentativaMostra retries
    FallbackIndica se o modelo era a primeira opção

    Um trace poderia mostrar:

    chamar modelo
      provider: provider-a
      requested.model: model-standard
      response.model: model-standard-2026-06
      prompt.name: answer-refund-policy
      prompt.version: 7
      input.tokens: 1840
      output.tokens: 220
      finish.reason: stop
      retry.count: 0

    Esse conjunto de metadados costuma ser suficiente para muitas investigações. O texto completo do prompt e da resposta não precisa estar presente em todas as execuções.

    Não confunda trace com histórico de conversa

    Um dos erros mais comuns em observabilidade de IA é armazenar o prompt completo, a pergunta do usuário, a resposta do modelo e todos os documentos recuperados dentro dos spans.

    Isso parece útil porque facilita o debugging. Porém, em produção, esse conteúdo pode incluir:

    • dados pessoais;
    • informações financeiras;
    • documentos internos;
    • código proprietário;
    • credenciais;
    • contratos;
    • mensagens de clientes;
    • argumentos sensíveis enviados a ferramentas.

    Além do risco de segurança, armazenar esse conteúdo aumenta o volume de telemetria e torna a consulta mais difícil.

    Uma alternativa mais segura é registrar referências e versões:

    prompt.name: answer-refund-policy
    prompt.version: 7
    context.source: refund-policies
    context.index.version: 2026-07
    context.documents.selected: 3

    Caso seja necessário investigar o conteúdo exato, ele pode estar disponível em um armazenamento separado, com acesso controlado e retenção específica. O trace aponta para a execução, mas não precisa carregar todo o conteúdo.

    Como observar o contexto recuperado

    Em aplicações com RAG, parte da resposta depende dos documentos encontrados. Quando a resposta está errada, o problema pode não estar no modelo. O sistema pode ter recuperado documentos irrelevantes, desatualizados ou sem permissão adequada.

    Um span de recuperação de contexto deveria mostrar informações como:

    recuperar política de reembolso
      source: customer-policies
      index.version: 2026-07-10
      documents.found: 8
      documents.selected: 3
      top.score: 0.91
      permission.filter: applied
      reranking.used: true

    O objetivo é permitir que alguém investigue se o contexto correto chegou ao modelo.

    Não é necessário colocar o conteúdo integral dos documentos no trace. Em muitos casos, quantidade, origem, versão do índice e scores já ajudam bastante. Identificadores de documentos podem ser registrados apenas quando forem realmente necessários e quando o acesso estiver protegido.

    Como observar ferramentas

    Quando um agente chama uma ferramenta, ele deixa de apenas produzir texto e passa a consultar ou alterar outros sistemas. Por isso, tool calls merecem spans próprios.

    Uma ferramenta pode consultar um pedido, buscar um documento, abrir um ticket ou executar uma alteração. O trace deveria deixar claro:

    • qual ferramenta foi chamada;
    • se a operação era de leitura ou escrita;
    • quanto tempo levou;
    • se a autorização foi aceita;
    • se houve retry;
    • se houve timeout;
    • se a operação exigia aprovação;
    • qual foi o resultado.

    Exemplo:

    consultar pedido
      tool.name: get-order
      tool.version: 2
      tool.access: read
      authorization.result: allowed
      approval.required: false
      result: success
      duration.ms: 120

    Para uma ferramenta de escrita:

    cancelar pedido
      tool.name: cancel-order
      tool.access: write
      authorization.result: allowed
      approval.required: true
      approval.result: approved
      result: success

    Essa distinção ajuda a separar uma simples consulta de uma operação capaz de produzir efeitos reais.

    Os argumentos completos da ferramenta também não deveriam ser registrados por padrão. Em vez de armazenar todo o payload, podemos registrar o tipo da operação, a quantidade de itens, o tamanho do payload ou um identificador protegido.

    Avaliação também faz parte do trace

    Em aplicações tradicionais, uma resposta HTTP 200 geralmente indica que a operação funcionou. Em aplicações de IA, uma chamada pode terminar sem erro técnico e ainda produzir uma resposta ruim.

    Por isso, a avaliação da resposta pode aparecer como uma etapa do trace:

    validar resposta
      evaluation.name: refund-policy-adherence
      evaluator.version: 2.1
      score: 0.94
      result: pass
      final.action: answer

    Em um caso reprovado:

    validar resposta
      evaluation.name: refund-policy-adherence
      score: 0.42
      result: fail
      final.action: human-review

    Esse detalhe ajuda a separar três resultados diferentes:

    1. A infraestrutura falhou.
    2. A chamada ao modelo funcionou, mas a qualidade foi insuficiente.
    3. A resposta foi produzida e aprovada.

    Sem essa separação, dashboards podem indicar 100% de sucesso enquanto usuários recebem respostas inadequadas.

    Fallbacks precisam estar visíveis

    Uma aplicação pode tentar um modelo principal e, em caso de timeout, usar um modelo alternativo. Também pode reduzir o contexto, usar uma resposta em cache ou encaminhar a tarefa para uma pessoa.

    Se o fallback não aparecer no trace, a resposta será analisada como se tivesse seguido o caminho normal.

    Um exemplo:

    chamar modelo principal
      result: timeout
    
    chamar modelo alternativo
      fallback.reason: primary-model-timeout
      fallback.position: 1
      result: success

    Isso permite responder perguntas importantes:

    • Qual modelo está falhando mais?
    • Quantas execuções usam fallback?
    • O fallback aumenta a latência?
    • A qualidade cai quando o modelo alternativo é utilizado?
    • O custo está sendo afetado por tentativas duplicadas?

    Fallback silencioso pode preservar a disponibilidade, mas esconder um problema operacional. Observabilidade deve tornar esse comportamento visível.

    Um exemplo simples em .NET

    Os conceitos são independentes de linguagem. Java, Python, Go, JavaScript e outras plataformas possuem bibliotecas para criar spans e adicionar atributos. Em .NET, esse trabalho normalmente é feito com ActivitySource.

    O exemplo abaixo cria um span para uma chamada ao modelo e registra apenas metadados:

    private static readonly ActivitySource Source =
        new("MyCompany.AI");
    
    public async Task<ModelResponse> GenerateAsync(
        ModelRequest request,
        CancellationToken cancellationToken)
    {
        using var activity = Source.StartActivity(
            "chamar modelo",
            ActivityKind.Client);
    
        activity?.SetTag("ai.provider", request.Provider);
        activity?.SetTag("ai.request.model", request.Model);
        activity?.SetTag("ai.prompt.name", request.PromptName);
        activity?.SetTag("ai.prompt.version", request.PromptVersion);
    
        try
        {
            var response = await _client.GenerateAsync(
                request,
                cancellationToken);
    
            activity?.SetTag("ai.response.model", response.Model);
            activity?.SetTag("ai.input.tokens", response.InputTokens);
            activity?.SetTag("ai.output.tokens", response.OutputTokens);
            activity?.SetTag("ai.finish.reason", response.FinishReason);
    
            return response;
        }
        catch (Exception exception)
        {
            activity?.SetStatus(
                ActivityStatusCode.Error,
                exception.Message);
    
            throw;
        }
    }

    Em outra linguagem, a estrutura seria praticamente a mesma:

    iniciar span "chamar modelo"
    
    adicionar provider
    adicionar modelo solicitado
    adicionar versão do prompt
    
    executar chamada
    
    adicionar modelo respondente
    adicionar tokens
    adicionar motivo de encerramento
    
    se houver erro:
        marcar span como erro
    
    encerrar span

    O ponto importante não é a API específica do .NET. É a decisão sobre quais informações pertencem ao span.

    Use instrumentação automática e manual juntas

    OpenTelemetry consegue instrumentar automaticamente várias operações, como:

    • chamadas HTTP;
    • acesso a banco;
    • filas;
    • caches;
    • frameworks web;
    • clientes de serviços externos.

    Essa instrumentação deve continuar existindo. Porém, ela não sabe necessariamente que uma consulta ao banco fazia parte de uma recuperação de contexto ou que uma chamada HTTP era uma ferramenta usada por um agente.

    Por isso, a combinação ideal costuma ser:

    span manual: recuperar contexto
    └── span automático: consulta ao vector database
    
    span manual: executar ferramenta
    └── span automático: HTTP GET /orders/123

    O span manual explica a intenção. O span automático explica a infraestrutura.

    Também é importante evitar duplicação. Se o framework do agente, o cliente MCP e a biblioteca HTTP criarem spans equivalentes para a mesma operação, o trace pode ficar difícil de ler. Cada span deveria representar uma etapa lógica ou uma fronteira técnica relevante.

    Traces, métricas e logs têm papéis diferentes

    Nem toda informação precisa estar em todos os traces.

    Traces são melhores para investigar uma execução específica. Eles mostram a sequência, as dependências e o ponto em que algo mudou.

    Métricas são melhores para acompanhar comportamento agregado, como:

    • latência por modelo;
    • tokens por workflow;
    • taxa de fallback;
    • erros por ferramenta;
    • avaliações reprovadas;
    • custo médio por tarefa.

    Logs são úteis para eventos operacionais, auditoria e mudanças de configuração, como:

    • publicação de uma nova versão do prompt;
    • ativação de um modelo;
    • mudança em uma política;
    • alteração de permissões de uma ferramenta.

    Um trace pode indicar que o prompt v7 foi usado. Uma métrica mostra a taxa de reprovação do v7. Um log de auditoria mostra quando o v7 foi publicado e por quem.

    Cuidado com cardinalidade

    Alguns atributos possuem poucos valores possíveis e são bons para dashboards:

    workflow.name
    model.name
    provider.name
    prompt.version
    tool.name
    evaluation.result

    Outros possuem milhões de valores diferentes:

    user.question
    document.content
    customer.id
    conversation.id
    tool.arguments
    model.response

    Atributos de alta cardinalidade aumentam custo e dificultam agregações. Eles não deveriam ser usados indiscriminadamente como dimensões de métricas.

    Uma boa regra é usar atributos estáveis para dashboards e deixar detalhes específicos apenas nos traces, quando realmente forem necessários. Mesmo no trace, conteúdo sensível e identificadores pessoais precisam de tratamento cuidadoso.

    Uma política simples de captura

    Uma estratégia prática é trabalhar com três níveis.

    Produção padrão

    Registra metadados sobre workflow, modelo, prompt, tokens, retrieval, ferramentas, avaliações e fallbacks. Não armazena conteúdo completo.

    Diagnóstico controlado

    Permite capturar uma pequena amostra com conteúdo mascarado, por tempo limitado, com acesso restrito e retenção curta.

    Desenvolvimento

    Pode registrar conteúdo mais detalhado, desde que sejam usados dados sintéticos ou anonimizados.

    Essa divisão evita que uma configuração temporária de debugging se transforme em captura permanente de informações sensíveis.

    Como começar sem instrumentar tudo

    Uma aplicação não precisa nascer com dezenas de atributos. Um caminho simples pode ser dividido em três etapas.

    Na primeira, crie spans para as principais partes da execução:

    workflow
    modelo
    retrieval
    ferramentas
    avaliação

    Na segunda, adicione os metadados mais úteis:

    modelo
    provider
    versão do prompt
    tokens
    resultado
    fallback

    Na terceira, evolua para informações de qualidade e governança:

    scores de avaliação
    versões de políticas
    controle de conteúdo
    sampling
    redaction
    retenção

    Essa evolução gradual reduz a chance de o time criar uma instrumentação enorme antes de saber quais perguntas realmente precisa responder.

    Como seria um trace útil

    Um trace de um assistente de atendimento poderia terminar assim:

    POST /support/answer
    
    └── responder dúvida sobre reembolso
        workflow.version: 3.2
        task.type: refund-question
    
        ├── recuperar política
        │   source: customer-policies
        │   index.version: 2026-07
        │   documents.selected: 3
        │
        ├── chamar modelo
        │   provider: provider-a
        │   request.model: model-standard
        │   prompt.version: 7
        │   input.tokens: 1840
        │   output.tokens: 96
        │   finish.reason: tool-call
        │
        ├── consultar pedido
        │   tool.name: get-order
        │   tool.access: read
        │   authorization.result: allowed
        │
        ├── chamar modelo
        │   input.tokens: 2130
        │   output.tokens: 248
        │   finish.reason: stop
        │
        └── validar resposta
            evaluation.name: refund-policy-adherence
            score: 0.94
            result: pass
            final.action: answer

    Esse trace não contém a pergunta do cliente, o conteúdo da política, os dados completos do pedido nem a resposta final. Mesmo assim, ele explica como o sistema chegou ao resultado.

    Caso a resposta esteja incorreta, o time pode começar a investigação sabendo:

    • qual workflow foi executado;
    • qual versão estava ativa;
    • qual contexto foi recuperado;
    • qual modelo respondeu;
    • qual ferramenta foi chamada;
    • quanto contexto foi consumido;
    • qual avaliação aprovou a resposta.

    Esse é o equilíbrio desejado entre utilidade e exposição.

    Fechando a ideia

    Observabilidade de IA não deveria começar pela captura de prompts e respostas. Ela deveria começar pela estrutura da execução.

    Um bom trace mostra qual tarefa estava sendo realizada, que modelo participou, qual versão do prompt estava ativa, que contexto foi recuperado, quais ferramentas foram chamadas, se houve fallback e como a resposta foi avaliada.

    OpenTelemetry oferece uma base comum para representar essas operações em diferentes linguagens e plataformas. O exemplo em .NET muda em Java, Python, Go ou JavaScript, mas o desenho permanece o mesmo: cada etapa importante vira um span, e cada span recebe apenas os metadados necessários para explicar seu comportamento.

    A maturidade não está em registrar tudo. Está em conseguir responder perguntas importantes sem transformar observabilidade em um depósito de conteúdo sensível.

    Porque um trace útil não precisa reproduzir toda a conversa. Ele precisa explicar o caminho que levou até a resposta.

    Share. Facebook Twitter LinkedIn Telegram WhatsApp Copy Link
    Jhonathan Soares
    • Website
    • Facebook
    • X (Twitter)
    • LinkedIn

    Criador do blog Código Simples e com mais 15 anos de experiência em TI, com títulos de MVP Microsoft na área de Visual Studio Development, Neo4j Top 50 Certificate, Scrum Master e MongoDB Evangelist.

    Posts Relacionados

    Reduzir carga cognitiva é uma decisão arquitetural

    Arquitetura IA 19 de maio de 202611 Mins Read

    Structured Prompt-Driven Development: quando o prompt deixa de ser conversa e vira artefato de engenharia

    Arquitetura IA 28 de abril de 202613 Mins Read

    Observabilidade para agentes: por que logs e traces tradicionais já não bastam

    Gestão & Produtividade IA 23 de abril de 202611 Mins Read
    Newsletter

    Digite seu endereço de e-mail para receber notificações de novas publicações por e-mail.

    Junte-se a 24mil outros assinantes
    Posts recentes
    • Observabilidade de IA com OpenTelemetry: o que realmente deveria aparecer no trace?
    • Rate limiting não é só proteção contra abuso. É contrato de capacidade
    • Feature flag não é interruptor. É dívida operacional com prazo de validade
    • O modelo é infraestrutura: por que LLM deveria ser adapter, não o centro da sua arquitetura
    • O novo gargalo não é escrever código. É absorver mudança com qualidade
    Categorias
    • Arquitetura (37)
      • Microsserviços (3)
      • Testes (3)
    • Asp.net (120)
      • C# (89)
      • Mvc (13)
    • Banco de dados (93)
      • NoSql (60)
      • Sql (38)
    • Boas práticas (37)
      • Gestão & Produtividade (6)
      • Metodologias Ágeis (6)
    • Cursos (53)
    • Dicas (108)
    • Front-End (92)
    • IA (11)
    • Linux (6)
    • NodeJS (4)
    • Post do Leitor (9)
    • Python (5)
    • Seo (12)
    • Tecnologia (30)
      • ITIL (1)
      • Padrões de Projeto (4)
    • Testes (2)

    VEJA TAMBÉM

    Cursos
    12 de fevereiro de 20166 Mins Read

    1000 livros gratuitos sobre programação!

    Olha que dica bacana! A pagina só com livros sobre programação é mantida no GitHub…

    Mais de 200 livros de programação gratuitos em português

    Código Simples no Facebook
    Código Simples no Facebook
    • Popular
    • Recente

    1000 livros gratuitos sobre programação!

    12 de fevereiro de 2016

    Google lança versão “invisível” do reCAPTCHA!

    10 de março de 2017

    Mini curso de HTML5 oferecido pela Microsoft

    30 de janeiro de 2014

    O que significa ( !important ) na declaração do CSS ?

    5 de fevereiro de 2014

    Programa para supercompactar arquivos. KGB Archiver.

    6 de fevereiro de 2014

    Observabilidade de IA com OpenTelemetry: o que realmente deveria aparecer no trace?

    15 de julho de 2026

    Rate limiting não é só proteção contra abuso. É contrato de capacidade

    29 de junho de 2026

    Feature flag não é interruptor. É dívida operacional com prazo de validade

    23 de junho de 2026

    O modelo é infraestrutura: por que LLM deveria ser adapter, não o centro da sua arquitetura

    15 de junho de 2026

    O novo gargalo não é escrever código. É absorver mudança com qualidade

    12 de junho de 2026
    Nosso Feed
    • RSS - Posts
    Fique por dentro

    Digite seu endereço de email para assinar este blog e receber notificações de novas publicações por email.

    Facebook X (Twitter) Instagram LinkedIn

    Type above and press Enter to search. Press Esc to cancel.

    Vá para versão mobile