03 - Langfuse — open-source standard
TL;DR
Langfuse virou referência OSS em LLM observability em 2026 — licença MIT, adoção significativa em times de produção, com SDK em múltiplas linguagens. Arquitetura é PostgreSQL (metadados) + ClickHouse (traces de alto volume) + Next.js (UI), tudo open. Dois jeitos de rodar: Cloud (
cloud.langfuse.com, free tier generoso, pago acima de 50k observações/mês) ou self-hosted (Docker Compose em 5 min; Helm pra produção). O API surface é mínimo: decorator@observe()em Python ou wrappers em JS/TS/integrações com LangChain/LlamaIndex/Vercel AI SDK. Features além de tracing: prompt management versionado, datasets pra eval offline, evaluators built-in (LLM-as-judge). Escolha Langfuse quando quer OSS sério, time de 3+ pessoas, e quer manter dados (self-host) ou quer começar rápido sem trocar de stack depois (Cloud é o mesmo produto).
Qual é a diferença prática entre usar Langfuse Cloud e self-host — e quando a migração vale?
O produto é idêntico: o mesmo binário roda nos dois modos. Cloud poupa infra no começo; self-host dá controle total de dados (compliance, PII, custo de volume alto). A migração é direta porque não há formatos proprietários: traces estão no Postgres/ClickHouse que você já conhece. Regra prática: começa no Cloud, auto-hospeda quando o custo de observações ultrapassa ~$200/mês ou quando compliance exige dado no seu VPC.
Por que Langfuse virou referência
O ecossistema de LLM observability está maduro o suficiente pra ter um “padrão de fato” emergindo — e em 2026 Langfuse é o candidato mais sólido no espaço OSS. Por quê?
Três fatores empilhados:
- Licença MIT real — código todo OSS, sem “open-core” escondendo features críticas. Self-host roda a mesma coisa do Cloud.
- Cobertura horizontal — tracing + prompts + datasets + evals em uma plataforma. Substitui 3-4 ferramentas separadas em times menores.
- Integrações maduras — Python decorator + JS/TS wrapper + integrações OOTB com LangChain, LlamaIndex, Vercel AI SDK, OpenAI/Anthropic/Google. Curva de adoção curta.
Helicone é friction-light (integra mudando base_url), mas é proxy-only — não cobre prompt management e eval no mesmo produto. LangSmith é mais polido, mas closed source e proprietário. Phoenix é OSS puro mas mais focado em eval. Langfuse fica no meio: OSS, completo, com SDKs sólidos. (O ecossistema muda rápido — confira a trajetória atual de cada player antes de cravar a escolha.)
Arquitetura
+---------------------+
Client SDK --> | Langfuse API server | --> ClickHouse (traces, observations)
(Python/JS) | (Next.js + tRPC) | --> PostgreSQL (prompts, datasets,
+---------------------+ users, projects)
^
|
+---------+---------+
| Next.js UI / API |
| (dashboards, |
| prompt mgmt, |
| evals) |
+-------------------+
- PostgreSQL pra dados relacionais (users, projects, prompts, datasets, configurações de eval)
- ClickHouse pra colunas — traces e observations chegam em volume alto, ClickHouse é o que aguenta queries analíticas em bilhões de linhas
- API server + UI num único monólito Next.js — simplifica deploy
Self-host mínimo: docker compose up puxa os 4 serviços e roda. Para produção, o Helm chart oficial adiciona réplicas, PVCs separados para Postgres e ClickHouse, e ingress configurável. A separação de bancos é intencional: Postgres lida com transações (prompts, projetos, usuários) enquanto ClickHouse aguentar o volume de append-only de traces sem degradar queries transacionais.
Uma nota sobre versões: Langfuse tem releases mensais frequentes. O SDK Python v3 (from langfuse import observe) quebrou compatibilidade com v2 (from langfuse.decorators import observe) — ao atualizar, verifique o changelog antes de rodar pip upgrade em produção.
Cloud vs self-host — decisão
| Critério | Cloud | Self-host |
|---|---|---|
| Tempo até primeiro trace | 2 minutos | 30 minutos (Docker) / horas (Helm prod) |
| Custo inicial | Free até 50k observations/mês | Custo de infra (uns $50-200/mês pra começar) |
| Dados onde | Cloud Langfuse (EU ou US, escolhível) | Sua infra |
| PII compliance | Depende do contrato + DPA | Você controla 100% |
| Upgrades | Automático | Você gerencia (versões mensais) |
| Quando faz sentido | MVP, time pequeno, sem restrição de dado | Enterprise, dado regulado, alto volume |
Caminho comum: começar no Cloud, migrar pra self-host quando volume passa de ~100k observations/mês ou quando compliance bate. Migração é direta porque o produto é o mesmo binário.
SDK — decorator @observe() em Python
Exemplo concreto, ponta a ponta:
import os
from anthropic import Anthropic
from langfuse import Langfuse, observe # v3 SDK; em v2 era `from langfuse.decorators import observe`
from langfuse.decorators import langfuse_context
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..."
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..."
os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # ou seu self-host
langfuse = Langfuse()
client = Anthropic()
@observe(name="research-agent.synthesize")
def synthesize(question: str, context: list[str]) -> str:
# Captura input/contexto no span atual
langfuse_context.update_current_observation(
input={"question": question, "n_sources": len(context)},
metadata={"feature": "research-agent", "version": "v2.3"},
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2000,
system="Você sintetiza fontes em resposta clara e citada.",
messages=[{
"role": "user",
"content": f"Pergunta: {question}\n\nFontes:\n" + "\n---\n".join(context),
}],
)
answer = response.content[0].text
langfuse_context.update_current_observation(
output=answer,
usage={
"input": response.usage.input_tokens,
"output": response.usage.output_tokens,
},
)
return answer
@observe(name="research-agent")
def research(question: str) -> str:
# Span pai — `synthesize` vira span filho automaticamente
sources = retrieve(question) # outra função decorada — vira span irmão
return synthesize(question, sources)
answer = research("o que é melhor em 2026 — RAG ou long context?")
langfuse.flush() # garantir envio antes do script terminarO que acontece atrás do decorator:
@observecria um span quando a função entra, comname= nome do decorator- Pega
trace_idambiente (ou cria novo se for a raiz) - Captura
input(args),output(return),latency,error(se exception) - Em chamadas filhas decoradas, vincula
parent_span_idautomaticamente - Envia em batch async pra não bloquear hot path
Integrações sem mexer no código de chamada
Pra LangChain ou LlamaIndex, integração é callback handler:
from langfuse.callback import CallbackHandler
handler = CallbackHandler()
# LangChain
chain.invoke({"question": q}, config={"callbacks": [handler]})
# LlamaIndex
from llama_index.core import Settings
from langfuse.llama_index import LlamaIndexCallbackHandler
Settings.callback_manager = CallbackManager([LlamaIndexCallbackHandler()])Pro Vercel AI SDK e Anthropic SDK direto, há wrappers que substituem o cliente — instrumenta automaticamente cada messages.create().
Prompts versionados
A feature que diferencia Langfuse de “só observability” é o registry de prompts. Cada prompt vira artefato versionado, acessível por nome + label.
# Buscar prompt em produção
prompt = langfuse.get_prompt("research-system", label="production")
# Compilar com variáveis
system = prompt.compile(topic="LLM trends 2026")
response = client.messages.create(
model="claude-sonnet-4-6",
system=system,
messages=[...],
# Linka o prompt_version ao span automaticamente:
extra_body={"langfuse_prompt": prompt},
)Cuidados:
- Cache:
get_promptfaz cache local (default 60s) — não bate na API a cada chamada - Labels:
production,staging,latest, ou custom — versão pode ser promovida entre labels via UI ou API - Fallback: se falhar buscar, use
fallback="..."pra não derrubar o sistema
Detalhe importante: o prompt_version usado em cada call vai automaticamente como atributo do span — viabiliza filtrar dashboard por versão, comparar v2.3 vs v2.4 lado a lado. É o link que 05 - Versionamento de prompts aprofunda.
Evals built-in
Langfuse roda LLM-as-judge nas próprias traces:
- Define um evaluator (rubrica + judge model) na UI
- Roda automaticamente em sample de traces de produção (1%, 10%, 100% — escolha)
- Score vira atributo do span — fica searchable, plotável, alertável
Útil pra detectar regressão em tempo real: se score médio cai 10% após deploy de novo prompt, dashboard pisca antes do usuário reclamar. Detalhes em 04 - LLM-as-judge — quando e como.
Datasets pra eval offline
Trace em produção vira candidato a dataset:
- Marca trace interessante na UI → vira item de dataset
- Roda nova versão do prompt contra o dataset todo → compara scores
- CI/CD integration: rodar dataset eval em cada PR (07 - Eval em CI-CD)
Loop completo: produção → trace → dataset → eval → nova versão de prompt → deploy → produção.
O ponto crítico é que dataset e eval vivem no mesmo produto que o tracing — sem exportar CSV nem integrar APIs diferentes. Isso encurta o ciclo de experimentação de dias pra horas.
Monitorando custo e uso no dashboard
Além de qualidade, Langfuse agrega custo por modelo automaticamente se você passar usage.input e usage.output nos spans (ou usar integrações que fazem isso de graça).
O dashboard mostra:
- Custo total por período (diário/semanal/mensal)
- Custo por model — detecta se um Claude Opus escapou quando deveria ser Sonnet
- Custo por usuário/sessão — identifica uso anômalo
- Latência p50/p95/p99 por endpoint instrumentado
Pra funcionar bem, o usage precisa ter preço por token configurado. Langfuse mantém preços de LLMs conhecidos (OpenAI, Anthropic, Google) atualizados na UI — modelos customizados ou self-hosted precisam de cadastro manual.
langfuse_context.update_current_observation(
usage={
"input": response.usage.input_tokens,
"output": response.usage.output_tokens,
"unit": "TOKENS", # default, pode omitir
"total_cost": 0.003, # opcional: se você calculou fora
}
)Se a feature de custo automático não ativar, verifique se o model do span bate exatamente com o nome que Langfuse registra (ex: claude-sonnet-4-6, não claude-sonnet).
Quando escolher Langfuse — e quando não
A decisão não é só técnica: é sobre onde está o gargalo da equipe. Se o gargalo é velocidade de experimentação de prompt, prompt management integrado poupa mais do que qualquer otimização de infra. Se o gargalo é compliance de dado, self-host é o desbloqueador.
Aplica:
- Time de 2+ engenheiros de IA — features de eval/prompt mgmt pagam custo de setup
- Sistemas com agents ou pipelines multi-step — hierarquia de span aparece de forma natural
- Quer OSS — self-host como opção real, sem feature crippling
- Vai precisar de eval contínua — integração trace ↔ dataset ↔ eval em um produto só
Não aplica (ou tem alternativa melhor):
- Dev solo com Claude Code — overkill; ccusage + planilha basta
- Quer só proxy “drop in” — Helicone resolve com mudança de
base_url; OpenLLMetry resolve com OTel direto - Já tem stack OTel madura (Datadog, Honeycomb) — OpenLLMetry exporta pra eles direto, sem trazer outro backend
Armadilhas comuns
Usar
langfuse.flush()só em scripts de linha — e esquecer em workers de longa duraçãoO decorator
@observe()envia spans em batch assíncrono. Num script curto que termina logo, o processo encerra antes do batch ir — e você perde todos os traces.langfuse.flush()no final do script resolve. Em workers de longa duração (FastAPI, Lambda quente), o flush automático por timeout cuida disso — forçar flush manual em cada request gera latência desnecessária. Saiba em qual contexto você está antes de copiar o exemplo.
Confundir
scorede eval built-in com métrica de negócioO LLM-as-judge do Langfuse gera um
scorede 0–1 configurável — útil pra detectar regressão de qualidade. Mas esse score é tão bom quanto a rubrica que você definiu. Times iniciantes configuram um avaliador genérico (“esta resposta é boa?”) e passam a tratar o score como KPI de produto. Se a rubrica não está alinhada com o que o usuário valoriza, o score vai se movimentar independentemente da satisfação real. Calibre o rubric com exemplos reais antes de alertar sobre ele.
Subir PII nos atributos principais do span em vez de span events
Langfuse indexa atributos principais (input, output, metadata) pra filtros e buscas — o que significa que chegam ao ClickHouse em claro e aparecem em dashboards. Se o input contém nome, CPF ou e-mail do usuário, vai poluir a UI e pode violar compliance. A prática correta é tratar PII antes de logar, ou mandar o dado bruto como span event (não indexado como coluna) e só indexar metadados anônimos. Veja 08 - Privacy e PII em logs para o padrão de mascaramento.
Como explicar em inglês
Interview quote: “We use Langfuse as our central observability backend — it gives us trace hierarchies, prompt versioning, and offline eval datasets in a single MIT-licensed product we can self-host when compliance requires it.”
| Português | Inglês |
|---|---|
| Decorator de observabilidade | Observability decorator |
| Span filho vinculado automaticamente | Automatically linked child span |
| Prompt versionado | Versioned prompt |
| Eval offline com datasets | Offline eval with datasets |
| Avaliador built-in (LLM-as-judge) | Built-in evaluator (LLM-as-judge) |
| Self-hosted (própria infra) | Self-hosted (your own infrastructure) |
| Flush assíncrono de batch | Async batch flush |
| Migrar do Cloud pro self-host | Migrate from Cloud to self-hosted |
O que vem a seguir
Com Langfuse configurado, você tem tracing, prompt versioning e eval num produto só.
Langfuse é OSS e o mais completo — mas não é o único player. A nota 04 apresenta as alternativas: Helicone (proxy friction-light), Phoenix (foco em eval), e OpenLLMetry (camada de instrumentação OTel que exporta pra qualquer backend). Entender onde cada um se encaixa evita troca de stack custosa depois que o volume cresce.
Fontes
- Langfuse — Documentação · Tracing · Prompt Management · Self-hosting.
- Langfuse — GitHub langfuse/langfuse. Repo principal, licença MIT.
- Langfuse — SDK Python — decorator
@observe()documentado.
Veja também
- 02 - Anatomia de um trace LLM — a hierarquia que Langfuse materializa
- 04 - Helicone, Phoenix, OpenLLMetry — alternativas — quando outras ferramentas cabem melhor
- 05 - Versionamento de prompts — como o registry de prompts do Langfuse encaixa
- Evaluation — Langfuse evals como parte do loop
- Dicionário: Langfuse