Рассматриваем варианты; конкретный driver — algo-hub (нет инструментации, BG-1429 followup), но решение задаёт pattern и для остальных сервисов где сейчас manual wrapping.

Контекст

/api/analyze-stream в algo-hub делает ~12 LLM-call’ов на одну patient analysis: один selection-call к algorithmSelectionAgent (242s) + по 3-4 multi-turn LLM-call’а на каждый calculator без hardcoded formula к computeAgent/fallbackAgent. В bifrost admin API эти 12 записей flat — без иерархии «analyze-stream → phase → calc → LLM call». Хочется чтобы Langfuse рендерил один trace tree с правильной структурой business → LLM, а не россыпь несвязанных generations.

Текущая инструментация в стеке — manual callback wrappers withTrace/withSpan/withGeneration в packages/analysis-core/src/lib/langfuse-wrapper.ts (используется в analysis-worker, b2c-dashboard). Они работают, но требуют:

  • import wrapper’а в каждом call-site
  • проброс parent: LangfuseTraceClient | LangfuseSpanClient через signature chain нижестоящих функций
  • обёртку каждого LLM-call’а в withGeneration(parent, ...) отдельно

Для algo-hub’а с 2 .generate() call-sites + Mastra agents под капотом — этот pattern добавляет signature-проп langfuseParent в selectAlgorithms, computeWithLLM, computeCalculatorSmart (3 функции × 5 LOC ≈ 15 LOC + изменение публичных контрактов).

Ищем менее инвазивный подход.

Рассматривали

1. Bifrost-only OTel plugin → Langfuse

Bifrost имеет встроенный OTel plugin (bifrost upstream docs/features/observability/otel.mdx); при включении пушит каждый LLM-call как OTLP span в Langfuse OTLP endpoint (https://hipaa.cloud.langfuse.com/api/public/otel/v1/traces). Trace-format genai_extension — OTel GenAI semantic conventions (model, tokens, cost, prompt, response в attributes). HTTP/protobuf, gRPC не поддерживается Langfuse.

Pros: zero кода в любом приложении. Покрывает все сервисы стека за одну config-правку в bifrost values.yaml. Тоже unblock’ает наш b2b-platform analytics dashboard который сейчас зависит от Langfuse-traces.

Cons: flat — каждый LLM-call отдельный trace, без иерархии. Когда у одного analyze-stream’а 12 LLM-вызовов, в Langfuse это 12 несвязанных traces, корреляция только по timestamp/user-id если их сами выставляем. Не даёт answer на «сколько времени из 281s — selection vs match vs compute».

2. Manual Langfuse SDK wrappers (текущий pattern)

withTrace({ traceId, spanName, input }, async (root) => { withSpan(root, ..., async (span) => ...) }) — callback-style. Каждый span сам делает .end() в try/catch + flushAsync() на выход из root.

Pros: уже work’ает в analysis-worker / b2c-dashboard. Известный pattern, документирован своим кодом. Полный контроль над тем что попадает в span.

Cons: signature change в нижних функциях (langfuseParent proapping). Каждый LLM-call отдельно оборачивается withGeneration (дубль информации, которую и так знает Mastra/bifrost). Verbose: один analyze-stream = ~25 LOC wrapping. Vendor-coupled (Langfuse-specific API).

3. Mastra OtelBridge + OTel NodeSDK

@mastra/otel-bridge — adapter который читает OTel ambient context (AsyncLocalStorage) и автоматически создаёт child spans для каждого agent.generate() call. Setup один раз в instrumentation.ts (Node SDK + OTLPTraceExporter на Langfuse) + один раз в Mastra-config (bridge: new OtelBridge()).

В business-коде — одна обёртка на route: tracer.startActiveSpan("analyze-stream", async () => { ...existing... }). Внутри все .generate() от трёх Mastra agents автоматически становятся children. Tool calls, multi-turn LLM responses — все вложены правильно через OTel ALS.

Pros: минимум кода (~30 LOC включая instrumentation.ts + helm values). Никаких signature changes в нижнем коде. Native vendor-neutral OTel pattern. Combines с bifrost OTel plugin через стандартный traceparent HTTP header — bifrost spans становятся children Mastra-spans автоматически (полный e2e tree от browser→app→bifrost→provider).

Cons: новые dependencies (5 OTel packages + 2 Mastra packages). Загрузка instrumentation.ts до Mastra code — Next.js 13+ native hook, но требует verify в проде. Compatibility @mastra/otel-bridge с Mastra 1.1.0 — TBD verify. Pattern шаг в сторону от существующего withTrace/withSpan в стеке — open вопрос про migration / coexistence.

4. Vercel AI SDK experimental_telemetry

@ai-sdk/openai (Mastra использует под капотом) поддерживает experimental_telemetry: { isEnabled: true, functionId: '...' } per-call. Эмитит OTel spans с model/tokens/prompt.

Pros: ещё один path к auto-tracing без Mastra-specific bridge.

Cons: per-call параметр (нужно проставлять в каждый generate-call → similar pain to manual wrappers). Mastra скрывает AI SDK call site — добавить telemetry означает либо patch Mastra либо forking. Менее clean чем OtelBridge для нашей ситуации.

Кандидат-направление

Комбинация #1 + #3: bifrost OTel plugin для baseline gateway-level coverage (zero app code, моментальная видимость), плюс Mastra OtelBridge в algo-hub для tree-структуры с business root span. Bifrost spans автоматически прицепляются как children через traceparent propagation (OTel HTTP instrumentation выставляет header при fetch к bifrost).

Этапы (порядок риска):

  • Шаг 1 (low risk): bifrost OTel plugin. Config-only change в argocd-applications/common/bifrost-proxy/values.yaml + 1Password секрет GCP_APP_BIFROST_LANGFUSE_AUTH. Сразу даёт flat coverage всех LLM-call’ов через bifrost для всех сервисов.
  • Шаг 2 (medium risk): algo-hub Mastra OtelBridge. ~30 LOC: instrumentation.ts + central Mastra instance с OtelBridge + 2-строки обёртка в /api/analyze-stream/route.ts. Даёт tree через AsyncLocalStorage propagation.
  • Шаг 3 (optional): добавить per-phase tracer.startActiveSpan("phase:select", ...) для ещё более чёткой группировки + business metadata (calc_id, etc.) через tracingOptions.tags.

Что нужно для разрешения

  • Verify @mastra/otel-bridge совместим с @mastra/core@1.1.0 (npm + changelog) — есть ли релиз; есть ли breaking-change между Mastra-versions
  • Понять текущую Mastra-init structure в algo-hub: агенты сейчас инстанцируются inline в select-algorithms.ts:203 и compute-with-llm.ts:230, без central new Mastra({...}) instance. Для OtelBridge нужен центральный instance. Refactor — sized
  • Решить про duplication. Если включён bifrost OTel и Mastra OtelBridge — каждый LLM-call от algo-hub потенциально создаст две generations в Langfuse: одна от Mastra (через ai-sdk side), одна от bifrost (server-side). Trace propagation должна их слинковать как parent-child (Mastra parent, bifrost child), но реальный shape зависит от того кто эмитит generation-attributes. Verify в Langfuse UI на test trace
  • Решить статус существующих withTrace/withSpan/withGeneration в analysis-worker / b2c-dashboard. Сосуществование с OtelBridge или гибридный pattern — TBD. Migration не блокирует первый roll-out
  • Назначить driver + window (Шаг 1 — quick, Шаг 2 — нужен PR review + test)

Следствия (если выберем кандидат-направление)

  • Algo-hub: новые dependencies (5 OTel + 2 Mastra packages); один instrumentation.ts; central Mastra instance (рефакторинг inline-agent definitions); 2-строки обёртка route. Нет правок в selectAlgorithms/computeWithLLM/computeCalculatorSmart/lib/model.ts.
  • Bifrost: enable OTel plugin в config.json; новый externalsecret LANGFUSE_AUTH. Все сервисы за bifrost получают per-call trace в Langfuse автоматически (включая b2c-dashboard / analysis-worker / b2b-api — даже хотя у них уже есть Langfuse SDK).
  • Существующие services с Langfuse SDK: дублирование generations. Либо acceptable (gateway level дополняет business level), либо требует обсуждения. Возможный путь — disable bifrost OTel для virtual_keys которые соответствуют сервисам с app-level SDK, или filter в OTel collector конфиге. TBD.
  • Wiki: llm-observability-stack нужно обновить — текущее «algo-hub не интегрирован» становится «через Mastra OtelBridge + bifrost OTel push». Visibility matrix меняется. App-side rejection blind spot частично закрывается per-Mastra agent generation.
  • Long-term: pattern переиспользуется для b2c-dashboard / analysis-worker / b2b-api. Migration от manual withTrace к OtelBridge — отдельный track, не блокирует.

Открытые вопросы

  • Compatibility @mastra/otel-bridge × Mastra 1.1.0 — TBD verify
  • Central Mastra instance в algo-hub — refactor scope?
  • Duplicate generations (bifrost OTel vs Mastra OtelBridge на одном LLM-call) — нужен реальный test trace в Langfuse, посмотреть как parent-child выстраивается. Гипотеза: stack ground truth = bifrost generation (с full input_history + tokens + cost), Mastra-level = wrapping span (timing + agent name + tool sequence)
  • Migration withTrace/withSpan → OtelBridge в analysis-worker / b2c-dashboard — нужно ли, когда, кто
  • Retention concerns. Bifrost SQLite уже ephemeral (llm-observability-stack §Retention) — push в Langfuse решает retention для трейсов; bifrost SQLite остаётся как local debug. Но Langfuse cost при scale — TBD measure
  • Authoring agent.generate metadata. Текущие Mastra agents в algo-hub не передают tracingOptions.tags — для бизнес-context (calc_id, phase) нужно добавить per-call. Это не блокирует baseline tree, но улучшает filtering / aggregation в Langfuse UI

Связано

  • llm-observability-stack — что-где-видно (parental concept page)
  • observability-stack — surface map; LLM-flow один из доменов
  • llm-resilience-stack — paired: transport reliability (что не сломалось)
  • bifrost — entity-page proxy: OTel plugin + admin API
  • langfuse — entity-page observability: cloud HIPAA region, OTLP endpoint
  • mastra — TS framework; agents в algo-hub
  • llm-call-failure-classes — таксономия сбоев; observability таксономии оршогональна но complement
  • no-self-rolled-queues — analogous principle: «не велосипедь то что фреймворк сам делает»; здесь параллель — не велосипедь span-management поверх Mastra-already-instrumented call site

Источники

Источники: 1 2 3.

Сноски

  1. Сессия ildar/772c82be, 2026-05-13 — `) — практический trigger: обнаружено что algo-hub без Langfuse.

  2. Mastra docs: [OTel Bridge](, accessed 2026-05-17, https://mastra.ai/docs/observability/tracing/bridges/otelOTLP Exporter.

  3. Langfuse OpenTelemetry integration [langfuse.com/integrations/native/opentelemetry](, accessed 2026-05-17, https://langfuse.com/integrations/native/opentelemetry — OTLP HTTP/protobuf поддержка, HIPAA endpoint.