Make a Langfuse trace worth opening: question, answer, session, no probe noise

This commit is contained in:
2026-08-21 14:45:32 +07:00
parent 53582b6030
commit f3eaab0948
16 changed files with 733 additions and 5 deletions
+21 -1
View File
@@ -1,11 +1,13 @@
from __future__ import annotations
from contextlib import nullcontext
from hmac import compare_digest
from time import perf_counter
from typing import Any
from fastapi import FastAPI, Request, Response
from adapters.langfuse_scores import LangfuseScoreClient
from adapters.postgres import PostgresTraceRepository
from bootstrap import build_runtime
from config import Settings, get_settings
@@ -38,6 +40,10 @@ def create_app(
app.state.conversational = conversational
app.state.trace_writer = trace_writer
app.state.metrics = metrics
# None unless Langfuse is fully configured; `/v1/rag/feedback` then skips
# mirroring the user's verdict there. Built from the same settings the
# span exporter reads, so the two can never point at different projects.
app.state.langfuse_scores = LangfuseScoreClient.from_settings(configured)
# The raw Qdrant retriever, not routed through RagAgent — Feature-List
# #4/#23's section-list and verbatim-section-text endpoints are plain
# payload-filtered reads with no LLM/generation step, so nothing about
@@ -51,8 +57,19 @@ def create_app(
method = request.method.upper()
started = perf_counter()
status_code = 500
# Kubernetes probes and the Prometheus scrape run every few seconds
# forever and carry no information a trace could show. Left traced they
# were ~90% of all spans within a day, burying the RAG turns anyone
# actually opens a trace viewer to read, and costing storage and
# ingestion for nothing. Their Prometheus counters below are untouched,
# which is the right place to watch probe health anyway.
span_context = (
nullcontext(None)
if route in _UNTRACED_ROUTES
else request_span(method, route, request.headers)
)
with correlation_context(request.headers.get("x-correlation-id")) as correlation_id:
with request_span(method, route, request.headers) as span:
with span_context as span:
try:
response = await call_next(request)
status_code = response.status_code
@@ -126,6 +143,9 @@ def create_app(
return app
_UNTRACED_ROUTES = frozenset({"/health", "/ready", "/metrics"})
def _route_label(path: str) -> str:
known = {
"/health", "/ready", "/metrics", "/v1/rag/query", "/v1/rag/suggest",