# Observabilidade com Langfuse ## O que é o Langfuse O [Langfuse](https://langfuse.com) é uma plataforma de observabilidade para aplicações LLM. No doc-processor ele é usado para rastrear cada chamada ao agente de IA, permitindo: - Visualizar o histórico completo de mensagens de cada execução (System, Human, AI, Tool calls). - Monitorar consumo de tokens (entrada e saída) por execução e por procedimento. - Medir latência das chamadas ao modelo. - Inspecionar as respostas brutas do agente para depuração. - Auditar decisões do sistema ao longo do tempo. --- ## Como está integrado no código ### Inicialização (`utils/langgraph_agent.py`) O cliente Langfuse é criado **uma única vez** na importação do módulo, usando as credenciais do Secrets Manager: ```python from langfuse import Langfuse from langfuse.langchain import CallbackHandler langfuse = Langfuse( secret_key=SECRETS["LANGFUSE-SECRET-KEY"], public_key=SECRETS["LANGFUSE-PUBLIC-KEY"], host=LANGFUSE_HOST, # padrão: https://cloud.langfuse.com ) ``` ### Rastreamento de execuções (`run_agent`) Para cada chamada ao agente, um `CallbackHandler` do Langfuse é instanciado e passado como callback ao LangGraph. Isso faz com que todas as mensagens trocadas durante a execução sejam enviadas automaticamente ao Langfuse: ```python langfuse_handler = CallbackHandler() config = {"callbacks": [langfuse_handler]} final_state = await agent.ainvoke(initial_state, config=config) ``` O `CallbackHandler` captura automaticamente: - O conteúdo do System Prompt e da mensagem Human enviados ao modelo. - Cada resposta do LLM (incluindo tool calls intermediárias). - As respostas das ferramentas (`ToolMessage`). - Tokens usados em cada step. ### Flush assíncrono Após cada execução do agente, o buffer do Langfuse é enviado ao servidor de forma assíncrona para garantir que nenhum trace seja perdido mesmo que o processo seja encerrado logo após: ```python await asyncio.to_thread(langfuse.flush) ``` > **Por que `to_thread`?** O método `flush()` do Langfuse é bloqueante. Executá-lo em uma thread separada evita que ele bloqueie o event loop do FastAPI enquanto aguarda a resposta da rede. --- ## Contagem de Tokens Além do rastreamento automático pelo Langfuse, o código também acumula os tokens manualmente a partir dos metadados das mensagens AI para retorná-los na resposta da API: ```python input_tokens = 0 output_tokens = 0 for msg in final_state["messages"]: usage = getattr(msg, "usage_metadata", None) if usage: input_tokens += usage.get("input_tokens", 0) output_tokens += usage.get("output_tokens", 0) ``` Os tokens são somados de **todas** as mensagens AI geradas durante a execução, incluindo chamadas intermediárias quando o agente usa a ferramenta `check`. Esses valores são retornados em cada `avaliacaoAgente`: ```json { "codigoServico": "40808130", "resultado": "Aprovado", "input_tokens": 1523, "output_tokens": 87 } ``` --- ## Criando uma Organização e um Projeto no Langfuse ### 1. Criar conta e organização 1. Acesse o ip do Ec2 via http na porta 3000, após liberar no security group para o ip desejado, e clique em **Sign Up**. 2. Após o login, o Langfuse pede para criar ou entrar em uma **organização**. A organização agrupa todos os projetos e membros da equipe. - Clique em **Create new organization**, preencha o nome e confirme. ### 2. Criar um projeto Dentro da organização: 1. Crie um novo projeto. 2. Nos passos iniciais tem um botão para criar as Api keys, copie os valores de Secret e Public. ### 3. Apontar o sistema para o novo projeto Atualize os segredos no AWS Secrets Manager (`doc-analyzer`) com os novos valores: Basta ir no Secrets manager, escolher o segredo doc-analyzer, ir em retrieve secret value e edit. Atualize com os novos valores. Após atualizar, talvez seja nescessário reiniciar o container/serviço para que ele carregue as novas credenciais: ```bash # ECS — forçar novo deploy aws ecs update-service \ --cluster \ --service \ --force-new-deployment ``` Nas próximas execuções, os traces aparecerão no novo projeto dentro da nova organização. --- ## Configuração ### Variável de Ambiente | Variável | Padrão | Descrição | |------------------|------------------------------|------------------------------------| | `LANGFUSE_HOST` | `http://13.59.214.47:3000/` | Endereço do servidor Langfuse. Pode ser uma instância self-hosted. | ### Segredos (AWS Secrets Manager — `doc-analyzer`) | Chave | Descrição | |-----------------------|------------------------------------| | `LANGFUSE-SECRET-KEY` | Chave secreta do projeto Langfuse | | `LANGFUSE-PUBLIC-KEY` | Chave pública do projeto Langfuse | As chaves são obtidas no painel do Langfuse em **Settings → API Keys**. ### Self-hosted Para usar uma instância própria do Langfuse (ex: rodando internamente), basta configurar (variável de ambiente do ecs): ```bash LANGFUSE_HOST=http://13.59.214.47:3000/ ``` E atualizar as chaves correspondentes no Secrets Manager. --- ## O que visualizar no painel Cada chamada ao `POST /process` gera uma ou mais **traces** no Langfuse (uma por serviço avaliado). Em cada trace é possível ver: 1. **Input**: JSON da guia + conteúdo OCR dos documentos enviados ao agente. 2. **System Prompt**: Critérios de auto-aprovação e documentação mínima do procedimento avaliado. 3. **Steps intermediários**: Se o agente chamou a ferramenta `check`, aparece como um step separado com o conteúdo retornado. 4. **Output**: JSON final com `status`, `criterio` e lista de `documentos`. 5. **Tokens e latência**: Custo estimado e tempo de resposta do modelo. --- ## Depuração Se as traces não aparecerem no painel: 1. Verifique se `LANGFUSE-SECRET-KEY` e `LANGFUSE-PUBLIC-KEY` estão corretos no Secrets Manager. 2. Confirme que `LANGFUSE_HOST` aponta para o servidor correto. 3. Verifique os logs do container — erros de conexão com o Langfuse são silenciosos por padrão (o `flush` falha sem derrubar o serviço). 4. Confirme que o container tem acesso de rede ao host do Langfuse.