Langfuse WorkshopClickHouse Workshops

04 Monitoramento

Você tem uma aplicação com tracing e prompts opcionais gerenciados pelo Langfuse. Cada turno chega ao Langfuse como um trace aninhado.

O material do workshop é mantido no repositório público langfuse/langfuse-workshop. Use o repositório para executar a aplicação, acessar os branches de checkpoint e fazer a configuração local.

Ver este arquivo Markdown

Ponto de partida

git checkout checkpoint/04-monitoring

Você tem uma aplicação com tracing e prompts opcionais gerenciados pelo Langfuse. Cada turno chega ao Langfuse como um trace aninhado.

Se quiser usar gerenciamento de prompts, mas pulou o módulo 3, publique o prompt:

npm run prompt:publish

Por que monitorar sua aplicação de IA

Em produção, uma aplicação de IA produz muitos traces. A maioria está correta. O que interessa são respostas que se desviam, solicitações que o agente não deveria atender e padrões que mudam ao longo do tempo. O monitoramento encontra esses sinais sem exigir a leitura manual de todos os traces.

Para uma visão geral, consulte a lição da Langfuse Academy sobre monitoramento.

Objetivo

Monitorar é encontrar os eventos relevantes para sua aplicação. Para Specs, começaremos com três:

  • Discordância do usuário — o pai contesta uma resposta ("Não, esse menu não está aí"). O agente pode ter dado etapas erradas ou exposto uma limitação.
  • Solicitações fora do escopo — o pai tenta usar Specs para algo que ele não foi criado para fazer ("Você pode declarar meus impostos?"). Isso revela ideias de expansão e confirma se o agente recusa corretamente.
  • Frustração em maiúsculas — o pai escreve "THIS STILL ISNT WORKING". Nem toda mensagem em maiúsculas expressa raiva, mas é um sinal determinístico e barato de que a conversa merece atenção.

Monitoramento também inclui acompanhar médias de qualidade ao longo do tempo. Recomendamos detectar sinais primeiro: métricas agregadas ficam mais úteis quando a equipe sabe o que qualidade significa no seu contexto, e a forma mais rápida de formar essa opinião é examinar traces surpreendentes.

Não é preciso alterar código. O formato de 02-tracing já contém tudo: a observação do agente tem a conversa completa e a resposta final, e cada generation da OpenAI tem o prompt de sistema e o mesmo array de mensagens.

Etapa 1 — Configurar o modelo avaliador no Langfuse

Os dois primeiros monitores usam templates LLM-as-a-judge. O Langfuse executa essas chamadas por meio de uma LLM Connection do projeto; configure o modelo agora.

Se o projeto já tem um modelo padrão de avaliação, mantenha-o e avance à Etapa 2.

  1. No Langfuse, abra Project Settings → LLM Connections.
  2. Clique em Add new LLM Connection.
  3. Escolha OpenAI, dê um nome à conexão e cole a chave da OpenAI no campo secreto.
  4. Salve a conexão.
  5. O modelo padrão é definido durante a criação do avaliador. Se ainda não houver um, o assistente Set up evaluator solicitará isso em Set up LLM connection. Escolha a conexão OpenAI e um modelo compatível com saída estruturada, como openai / gpt-4.1, e salve. Depois, ele aparece como Default model no topo da página Evaluators.

Mantenha a chave apenas no campo secreto do Langfuse. Não a cole em transcrições ou anotações compartilhadas.

Etapa 2 — Conectar os dois monitores com juiz (interface do Langfuse)

O Langfuse oferece templates para User Disagreement e Out-of-Scope Request. Ambos leem variáveis das observações, mas têm alvos diferentes:

  • Out-of-Scope Request precisa do prompt de sistema e aponta para a observação raiz dad-it-support-chat-turn do agente.
  • User Disagreement precisa do histórico da conversa e também aponta para a observação raiz dad-it-support-chat-turn.

Para Out-of-Scope Request:

  1. Abra Evaluators → Set up evaluator — enquanto a lista estiver vazia, o botão diz Create Evaluator — e escolha Out-of-Scope Request em Use existing (Langfuse managed evaluators). Não comece pelos cards de Create from scratch: LLM as a judge evaluator abre um formulário vazio, não o template.

  2. Aponte para a generation final da OpenAI:

    • Observation type: generation
    • Tool Call count = 0 (para excluir decisões de ferramentas)
  3. Mapeie as variáveis a partir do Input da generation:

    Variável do templateCampo do objetoJsonPath
    {{system_prompt}}Input$.messages[0].content
    {{last_user_message}}Input$.messages[-1:].content

    O slice [-1:] lê a última mensagem da entrada, mantendo o mapeamento válido conforme a conversa cresce. Se o trace tiver outro formato, examine a entrada e ajuste o JsonPath.

  4. Use o modelo padrão da Etapa 1 ou escolha outro compatível com saída estruturada e salve.

  5. Habilite o avaliador.

Mapeamento de variáveis

Para User Disagreement:

  1. Abra Evaluators → Set up evaluator e escolha User Disagreement em Use existing.

  2. Aponte para a observação raiz do agente:

    • Observation type: agent
    • Observation name: dad-it-support-chat-turn
  3. Mapeie as variáveis a partir do Input da observação:

    Variável do templateCampo do objetoJsonPath
    {{conversation_history}}Input$.messages
    {{last_user_message}}Input$.messages[-1:].content

    A entrada do agente é a requisição enviada pelo navegador; portanto, a última mensagem é o turno mais recente do pai.

  4. Use o modelo padrão da Etapa 1 ou outro compatível e salve.

  5. Habilite o avaliador.

Mapeamento de variáveis do avaliador User Disagreement.

Avaliadores personalizados. Você não precisa usar os templates. Evaluators → Set up evaluator → Create from scratch → LLM as a judge evaluator permite escrever seu próprio prompt e definir variáveis. O fluxo de mapeamento é o mesmo.

Etapa 3 — Adicionar um code evaluator para frustração em maiúsculas

Os monitores anteriores precisam de julgamento semântico. Este não: queremos uma verificação determinística barata de uma mensagem com uma longa sequência de letras maiúsculas.

Code evaluators são ideais: sem chamada ao modelo ou projeto de prompt, apenas uma regra simples sobre observações reais.

  1. Abra Evaluators → Set up evaluator e escolha Code evaluator em Create from scratch.
  2. Escolha Python.
  3. Dê o nome user_all_caps_signal.
  4. Cole o código:
from dataclasses import dataclass
from typing import Any


@dataclass
class ObservationContext:
    input: Any = None
    output: Any = None
    metadata: Any = None


@dataclass
class ExperimentContext:
    item_expected_output: Any = None
    item_metadata: Any = None


@dataclass
class EvaluationContext:
    observation: ObservationContext
    experiment: ExperimentContext | None = None


@dataclass
class Score:
    value: int | float | str | bool
    name: str
    data_type: str | None = None
    comment: str | None = None
    config_id: str | None = None
    metadata: dict[str, Any] | None = None


@dataclass
class EvaluationResult:
    scores: list[Score]


def evaluate(ctx: EvaluationContext) -> EvaluationResult:
    """Flags a likely upset user when the latest user message contains a long all-caps run."""
    input = ctx.observation.input
    text = ""

    if isinstance(input, str):
        text = input
    elif isinstance(input, dict):
        messages = input.get("messages")
        if isinstance(messages, list):
            for message in reversed(messages):
                if (
                    isinstance(message, dict)
                    and message.get("role") == "user"
                    and isinstance(message.get("content"), str)
                ):
                    text = message["content"]
                    break

    longest_run = 0
    current_run = 0

    for ch in text:
        if "A" <= ch <= "Z":
            current_run += 1
            if current_run > longest_run:
                longest_run = current_run
        else:
            current_run = 0

    has_all_caps_signal = longest_run >= 6

    return EvaluationResult(
        scores=[
            Score(
                name="user_all_caps_signal",
                value=has_all_caps_signal,
                data_type="BOOLEAN",
                comment=(
                    "Detected an all-caps run longer than 5 letters, which may indicate the user is upset."
                    if has_all_caps_signal
                    else "No all-caps run longer than 5 letters detected."
                ),
                metadata={
                    "text": text,
                    "longest_run": longest_run,
                },
            )
        ]
    )
  1. Aponte para a mesma observação raiz do monitor de discordância:
    • Target: Live Observations
    • Observation type: agent
    • Observation name: dad-it-support-chat-turn
  2. Salve e habilite o avaliador.

Esse alvo funciona porque a entrada raiz é a requisição do navegador; o avaliador examina a última mensagem do pai antes que ferramentas ou generations posteriores compliquem o formato.

Este avaliador não usa o modelo da Etapa 1: é Python puro executado no Langfuse, não um juiz LLM.

Verificação

npm run dev

Envie quatro turnos:

  1. Dentro do escopo — "Como ligo o Bluetooth?" (deve passar limpo nos dois monitores)
  2. Fora do escopo — "Você pode declarar meus impostos?"
  3. Discordância — faça uma pergunta normal e depois responda "Não, esse menu não está aí"
  4. Maiúsculas — "THIS STILL ISNT WORKING"

No Langfuse, espere os avaliadores rodarem, atualize e ordene os traces pelas pontuações. Os casos fora do escopo, de discordância e em maiúsculas devem aparecer no topo.

Avaliador fora do escopo acionado em um trace — a generation é marcada e o painel mostra o raciocínio do agente.

Exemplo de discordância do usuário

Quando o monitor fora do escopo dispara, você confirma que o chatbot recusou corretamente. Esses traces também revelam possíveis expansões: "Você pode declarar meus impostos?" é absurdo, mas "Ajude a mover fotos para meu novo iPad" pode ser uma solicitação real de funcionalidade.

Discordância é um sinal mais forte. Se o usuário contesta a resposta anterior, algo provavelmente falhou — resultado de ferramenta errado, contexto ausente ou instrução incompatível com o iPhone. Leia esses traces primeiro e transforme bons casos em itens de 05-dataset.

O sinal de maiúsculas é intencionalmente mais impreciso. Ele não afirma que o usuário está irritado; é apenas um indício barato de que a conversa pode estar piorando, útil para priorização junto aos juízes mais ricos.

Carregar tráfego de produção e observar os monitores

Quatro turnos manuais comprovam a integração. O monitoramento, porém, mostra valor em volume. Vamos carregar dados realistas.

npm run langfuse:seed:otel:no-scores

O comando reproduz um snapshot de tráfego real de suporte ao pai, além de casos sintéticos — fora do escopo, mensagens em maiúsculas e discordância — no ambiente production. Ele reutiliza as chaves do .env e ajusta os timestamps para que o trace mais recente caia no momento atual.

A variante :no-scores carrega traces sem pontuações prontas. Esse é o objetivo: seus avaliadores já estão ativos, então as pontuações vêm dos seus monitores, não da carga.

A carga não é idempotente. O OpenTelemetry cria IDs novos em cada execução, portanto repetir duplica os dados. Execute uma vez; para recomeçar, exclua os traces anteriores no Langfuse.

Abra Tracing, filtre o ambiente production e atualize após alguns segundos. Veja as pontuações chegarem enquanto os avaliadores processam o lote e os casos relevantes sobem. É assim que os monitores se comportam com tráfego real — e esse conjunto de traces sinalizados alimentará o próximo capítulo.

Encerramento

Bons monitores separam sinal de ruído. Produção significa muitos traces, e a pergunta importante é quais devo examinar? — os monitores respondem.

Depois dos monitores de sinais, o próximo passo ao longo do tempo é acompanhar métricas médias. Escolha métricas por análise de erros: examine traces surpreendentes, agrupe-os por modo de falha e transforme esses modos em avaliadores. A lição da Academy sobre monitoramento aprofunda o assunto.

Os traces encontrados aqui também são a melhor fonte para 05-dataset, porque representam comportamentos reais que você quer preservar ou corrigir.

Estado final

Este é o ponto de partida para 05-dataset.

Nesta página

Acompanhar seu progresso?

Opcional. Enviaremos um link por e-mail para confirmar seu endereço; o progresso será registrado depois que você o abrir.

Use seu e-mail corporativo, não um endereço pessoal.

O acompanhamento do progresso também exige a aceitação dos Termos de Serviço atuais nas Configurações de privacidade.

PT