题记与说明
条目 ID:knowledge-p5j2vm4l-4 | 阅读日期:2026-10-31 | 形式:主题研究(3-5 个来源群,在线检索并逐页精读)
说明:本笔记全部结论基于本次会话中实际抓取并阅读的 8 个官方文档页 / 仓库原文 / 第三方对比文,来源链接与原文引述均随文标注。未实际部署运行 Langfuse 或 Phoenix 实例,凡属文档声称而非实测之处均已注明。
一、核心问题(它在解决什么问题)
LLM 应用的五类遥测数据天然分散:token 用量在模型 API 响应里、延迟在客户端计时里、成本需要"token × 定价表"另行计算、质量(正确性/幻觉/相关性)根本不是运行时自动产生的信号、而请求链路(trace)又分散在各个 SDK 的私有格式里。主题要回答的问题是:能否用一套统一的数据模型/语义约定,把五类信号记录在同一个管道中,既可聚合分析,又不被单一厂商锁定?
三家对象在答案中处于三个不同层次:
| 层次 | 对象 | 角色 |
|---|---|---|
| 规范层 | OpenTelemetry GenAI Semantic Conventions(+ Arize 发起的 OpenInference) | 定义"字段叫什么、放哪",不是产品 |
| 管道层 | OTLP / OTel Collector | 统一传输协议,一次插桩多后端投递 |
| 应用层 | Langfuse、Phoenix | 存储、UI、定价表驱动的成本计算、质量评估对象 |
二、来源清单(本次实际精读)
- OpenTelemetry GenAI 语义约定仓库(规范层主来源)
- 仓库:https://github.com/open-telemetry/semantic-conventions-genai
- 本次全文下载精读:
docs/gen-ai/gen-ai-spans.md(68,689 字节)、docs/gen-ai/gen-ai-metrics.md(65,149 字节)、docs/gen-ai/gen-ai-token-metrics.md、docs/gen-ai/client-inference.md、README - 佐证:opentelemetry.io 上的旧页面(
/docs/specs/semconv/gen-ai/、gen-ai-spans/、gen-ai-metrics/)已全部返回"Moved"占位页,原文引用:"GenAI semantic conventions have moved to the OpenTelemetry GenAI semantic conventions repository. This page has moved and is no longer maintained in this repository." —— 说明约定正在迁移期。
- Langfuse — Observability Data Model:https://langfuse.com/docs/observability/data-model
- Langfuse — OpenTelemetry (OTEL) for LLM Observability(含完整属性映射表):https://langfuse.com/integrations/native/opentelemetry
- Langfuse — Scores / Evals:https://langfuse.com/docs/evaluation/scores/overview.md 与 https://langfuse.com/docs/scores/overview
- Arize Phoenix — Setup OTEL:https://arize.com/docs/phoenix/tracing/how-to-tracing/setup-tracing/setup-using-phoenix-otel
- Arize Phoenix — Cost Tracking:https://arize.com/docs/phoenix/tracing/how-to-tracing/cost-tracking
- Arize Phoenix — Evaluation:https://arize.com/docs/phoenix/evaluation
- Kosmoy — "Langfuse vs Arize (2026): LLM Observability Compared"(第三方对比,注意其竞争厂商立场):https://www.kosmoy.com/resources/blog/langfuse-vs-arize
三、逐家精读
3.1 OpenTelemetry GenAI:规范层管住 token 与延迟,不管成本与质量
Span 属性(trace 信号)。gen-ai-spans.md 的属性表中,唯一 Required 级别的是:
gen_ai.operation.name— Required — string — The name of the operation being performed.(示例值:chat、generate_content、text_completion)
gen_ai.provider.name、gen_ai.request.model(如 gpt-4)均为 Conditionally Required。工具调用有独立 span 形态:gen_ai.operation.name SHOULD be execute_tool,gen_ai.tool.name 为 Required。所有 gen_ai.* 属性都带 Development 稳定性徽章——整族约定仍是开发态。
Token 用量属性(client-inference.md):
gen_ai.usage.input_tokens— Recommended — int — The number of input tokens reported by the provider for this inference operation.gen_ai.usage.output_tokens— Recommended — int — The number of output tokens reported by the provider...
并向下细分到缓存与模态:gen_ai.usage.cache_read.input_tokens、gen_ai.usage.cache_write.input_tokens、gen_ai.usage.reasoning.output_tokens、gen_ai.usage.audio.*、gen_ai.usage.image.*、gen_ai.usage.text.*,且规定嵌套值 SHOULD 包含进总量(如 audio/input 计入 gen_ai.usage.input_tokens)。
延迟与用量指标(metrics 信号)。gen-ai-metrics.md 定义:
| 指标 | 类型 | 单位 | 含义 |
|---|---|---|---|
gen_ai.client.operation.duration | Histogram | s | GenAI operation duration |
gen_ai.server.request.duration | Histogram | s | time-to-last byte or last output token |
gen_ai.server.time_to_first_token | Histogram | s | Time to generate first token(TTFT) |
gen_ai.server.time_per_output_token | Histogram | s | 首 token 之后每输出 token 耗时(TPOT/解码速度) |
gen_ai.invoke_agent.duration / gen_ai.execute_tool.duration | Histogram | s | agent 端到端 / 工具单次执行耗时 |
gen_ai.client.inference.usage.input_tokens / output_tokens(见 gen-ai-token-metrics.md) | Counter | {token} | 按 gen_ai.token.modality 细分的用量计数器 |
关键空白:没有 cost,没有 quality。 我对四份约定全文做了 grep -i cost 检索:client-inference.md 零命中;gen-ai-spans.md 唯一一处命中是无关句子("storage costs, regulatory requirements...",指记忆存储的成本考量)。成本属性不在标准内;质量/评分信号同样完全缺位。这就是"统一记录"在规范层止步的地方——token、延迟、trace 三类有标准,成本、质量两类由应用层补。
3.2 Langfuse:数据模型四对象 + 可作 OTel Backend 的应用层
四对象数据模型(data-model 页原文):
"Langfuse organizes an application's data into three core concepts: observations, traces, and sessions."
加上 Score 即四类对象。Observation 是"LLM calls, tool calls, retrieval steps",可嵌套;trace 是"一个请求/操作"的全部 observation 的逻辑分组;session 再聚合多轮 trace。存储上的关键设计(原文):
"Conceptually, Langfuse stores one observations table, and each row holds the observation-level data plus a copy of the trace-level attributes. This keeps queries and aggregations fast."
Built on OpenTelemetry(原文):
"Langfuse is built on OpenTelemetry... This means you're not locked into using only Langfuse-specific SDKs. You can also send your traces to multiple destinations at once, like Langfuse for LLM observability and Datadog for infrastructure monitoring."
具体接入形态:Langfuse 可作为 OTel backend 接收 OTLP:
"Langfuse can receive traces on the /api/public/otel (OTLP) endpoint."约束与坑(原文摘录):
- "Langfuse currently supports OTLP over HTTP with both
HTTP/JSONandHTTP/protobuf.gRPCis not supported yet." - v4 直连 OTel 必须带
x-langfuse-ingestion-version: 4头,"Without this header, directly ingested OpenTelemetry data can be delayed by up to 10 minutes." - 短生命周期进程"must explicitly call
flush()before exiting",否则后台批量缓冲丢数据。
属性映射:gen_ai.* 如何变成 token/成本记录(OTEL 集成页映射表摘译):
| Langfuse 字段 | 映射自 OTel 属性 |
|---|---|
model | gen_ai.request.model / gen_ai.response.model / llm.model_name |
usage(token) | langfuse.observation.usage_details / gen_ai.usage.* / llm.token_count.* |
cost(USD) | langfuse.observation.cost_details / gen_ai.usage.cost(写入 total 键) |
input/output | langfuse.observation.input / gen_ai.prompt / gen_ai.completion / OpenInference 的 input.value/output.value |
同时明确承认规范在漂移(原文):
"As the Semantic Conventions for GenAI attributes on traces are still evolving, Langfuse maps the received OTel traces to the Langfuse data model and supports additional attributes that are popular in the OTel GenAI ecosystem."
以及命名空间优先级:"Langfuse uses attributes within the langfuse.* namespace to map OpenTelemetry span attributes directly to the Langfuse data model. These specific attributes always take precedence over the generic OpenTelemetry conventions."
聚合的前提:trace 级属性必须传播到每个 span。这是本次精读中最有工程价值的发现之一(原文):
"If you want to filter and aggregate byuserId,sessionId,metadata,version,release, ortags, you need to propagate these trace-level attributes to every span in the trace."
"Langfuse filters and aggregations increasingly operate across individual observations rather than only at the trace level."
推荐实现是 OTel Baggage + BaggageSpanProcessor,并附安全警告:"OpenTelemetry baggage is propagated across service boundaries and to third-party APIs. Do not include sensitive information... in baggage."
未映射的 OTel 属性会落入 metadata.attributes catch-all 且"not directly filterable",只有 langfuse.trace.metadata.* / langfuse.observation.metadata.* 前缀的键才进入一级可过滤 metadata。
质量:Score 对象。Langfuse 对 quality 的统一记录方式是独立于 trace/observation 的第四类对象(scores overview 原文):
"Every score has a name (like"correctness"or"helpfulness"), a value, and a data type. Scores also support an optional comment..."
四种数据类型:NUMERIC(连续判断)、CATEGORICAL(预定义类别,如 "correct"、"partially correct")、BOOLEAN(0/1,幻觉检测/格式校验)、TEXT。评分来源覆盖四条路:LLM-as-a-Judge 自动评估(可跑在线生产 trace 或实验)、人工标注(Annotation Queues)、终端用户反馈、代码评估器。选型口诀(原文):"if you already know the category at tracing time... use a tag. If you need to classify or evaluate traces later, use a score."
许可证与部署(第三方来源):Kosmoy 对比文:"Langfuse's core is MIT-licensed (OSI-approved) and unlimited when self-hosted, running the exact same codebase as its cloud with no scalability limits." 另提到 2026 年 1 月被 ClickHouse 收购但承诺许可不变。
3.3 Phoenix:OTel 原生优先 + 定价表驱动的成本引擎
接入即 OTel(Setup OTEL 页原文):
"The Phoenix OTEL SDK provides a lightweight wrapper around OpenTelemetry with sensible defaults for Phoenix."
register() 一个函数完成配置,auto_instrument=True 自动发现并激活环境中已安装的全部 OpenInference instrumentor("Phoenix automatically discovers and activates all OpenInference instrumentor packages installed in your Python environment—no additional code required")。协议支持 "grpc" 或 "http/protobuf" 两种(Python 端比 Langfuse 多一种 gRPC 选择)。Python 端默认 batch: False,TS 端默认 batch: true,官方同样警告进程退出前要 flush:"With batch: true, call shutdown() to explicitly flush before exit."
SDK 与服务器版本解耦(原文):"Any recent SDK version works with any Phoenix server version — you don't need to upgrade the server when you upgrade the SDK... The SDK sends traces over OTLP using OpenInference semantic conventions, both of which are backward compatible."
成本:Phoenix 侧自动计算(Cost Tracking 页原文):
"Phoenix allows you to track token-based costs for LLM runs automatically. The costs are calculated from token counts and model pricing data, then rolled up to the trace and project level for comprehensive cost analysis."
要点:
- 前提是 span 带 token 计数(OpenInference 语义约定),"ensure that your LLM spans include the OpenInference semantic conventions for token counts"。
- 内置定价表覆盖 OpenAI(GPT-3.5 至 GPT-5)、Anthropic Claude 全系、Google Gemini 1.x–3.x、Groq、Fireworks、Moonshot 等。
- 自定义定价支持 Name Pattern(regex 匹配模型名)、每 1M token 单价、生效日期;高级配置可按
cache_read、cache_write、reasoning、audio、image等细分 token 类型定价。 - 成本聚合五级:span → trace → session(多轮会话成本)→ experiment(数据集实验总成本与单次运行成本)→ project。
质量:评估结果回写为 span annotation(Evaluation 页原文):
"log evaluation results back to Phoenix as span annotations. Phoenix uses span identifiers to associate eval outputs with the correct execution."
即评估对象不是独立实体,而是挂在 span 上的 annotation。内置 judge 模板覆盖"relevance, correctness, faithfulness, summarization quality, and toxicity";SDK 侧批量跑(async_evaluate_dataframe(..., concurrency=10))后回写,评估结果在 UI 中与 trace 并排出现。
许可证(第三方来源,Kosmoy 原文):"Arize's Phoenix is under the Elastic License 2.0, which is not OSI-approved open source and restricts offering it as a managed service."
3.4 三家对照总表(本次精读综合)
| 维度 | OpenTelemetry GenAI | Langfuse | Phoenix |
|---|---|---|---|
| 本质 | 语义约定规范(Development 态) | 应用层平台,MIT 开源,可自托管 | 应用层平台,Elastic License 2.0 |
| trace | span/事件/实体模型(gen_ai.*) | Session→Trace→Observation;根 span 定 trace | Project→Trace→Span;OpenInference span kinds |
| token | gen_ai.usage.*(含 cache/reasoning/模态)+ Counter 指标 | 映射 gen_ai.usage.* 至 observation.usage | OpenInference token 属性;成本据此自动算 |
| 延迟 | Histogram:operation.duration、TTFT、time_per_output_token | span 起止时间戳 + completion_start_time(TTFT 映射) | 同 OTel 信号,UI 聚合 |
| 成本 | 无标准属性(grep 证实) | observation.cost;接受 gen_ai.usage.cost 扩展 | 内置定价表自动计算,支持 regex 自定义与 token 类型细分,五级聚合 |
| 质量 | 无信号 | Score 对象(NUMERIC/CATEGORICAL/BOOLEAN/TEXT),四来源 | span annotation 形式回写评估结果,内置 judge 模板 |
| 传输 | OTLP(gRPC/HTTP 均可,视实现) | 仅 OTLP/HTTP(不支持 gRPC) | gRPC 或 OTLP/http/protobuf |
| 锁定规避 | 规范本身即反锁定 | "built on OpenTelemetry",可多后端同时投递 | "lightweight wrapper around OpenTelemetry" |
四、主要主张(综合论点)
- "统一记录"在 2026 年的现实形态是分层而非单一标准:OTel GenAI 约定统一了 trace/token/延迟三类信号的命名与传输;成本与质量在规范层是空白,由 Langfuse(Score 对象 + cost 字段)与 Phoenix(定价表引擎 + span annotation)在应用层各自补齐。选型时真正的差异点在应用层的成本引擎与质量评估设计,而非插桩层。
- 插桩写在 OTel 层、后端可换:两家都原生吃 OTLP。Langfuse 明说可同时发 Langfuse 与 Datadog;Phoenix 的 SDK 只是"wrapper with sensible defaults"。把 instrumentor 选在 OTel GenAI / OpenInference 一侧,后端迁移成本最低。
- 聚合靠传播,不靠存储:无论哪家,user/session/tags 这类切片维度都必须复制到每个 span(Langfuse 用 BaggageSpanProcessor,Phoenix 用
using_session/using_user等 context manager)才能在观测表中聚合。"trace 是聚合键"是五元组统一的技术前提。 - 规范仍在漂移,要有兼容层心态:OTel GenAI 全族属性为 Development 态且刚迁至独立仓库;Langfuse 文档明确承认"still evolving"并保留
langfuse.*命名空间作为优先出口。生产系统应预期属性名变化,把映射集中在一处。
五、方法(本次如何研究)
- 在线检索定位来源群 → 对官方文档逐页抓取精读(web_reader 渲染 5 页:OTel 迁移页、Langfuse 数据模型、Langfuse OTEL、Phoenix Setup OTEL、Phoenix Cost Tracking)→ 对 OTel 约定用 GitHub API + raw 文件全文下载(
docs/gen-ai/下 4 份 + README),以 grep 精确核对属性必填级别、指标清单、cost 是否存在 → Langfuse scores 类型与 Phoenix 评估页用 WebFetch 定点提取引述 → 一篇第三方对比文交叉验证许可证与定位,并显式标注其厂商立场。 - 核实动作记录:
grep -i cost /tmp/genai-client-inference.md(零命中);grep -n "Metric:" /tmp/genai-metrics.md(9 个指标清单);wc -c确认全文下载完整性(spans 68,689 B / metrics 65,149 B)。
六、数据与证据(关键引述索引)
- OTel 迁移占位页原文:opentelemetry.io
/docs/specs/semconv/gen-ai/—— "GenAI semantic conventions have moved to the OpenTelemetry GenAI semantic conventions repository." gen_ai.operation.nameRequired、gen_ai.request.modelConditionally Required:gen-ai-spans.md 属性表(行 71/75)。- token 用量 Recommended 属性及缓存/模态细分:client-inference.md 行 103–116。
- 9 个 metrics(duration/TTFT/TPOT/agent/tool):gen-ai-metrics.md 目录行 12–24。
- cost 零命中的 grep 结果(本次执行);Langfuse 映射表中
gen_ai.usage.cost仅作为 Langfuse 接受的键出现。 - Langfuse 数据模型三概念 + observations 表设计 + "built on OpenTelemetry":langfuse.com/docs/observability/data-model。
- Langfuse OTLP 端点、无 gRPC、10 分钟延迟警告、BaggageSpanProcessor、属性映射表:langfuse.com/integrations/native/opentelemetry。
- Langfuse 四种 score 类型与 tag/score 选型口诀:langfuse.com/docs/evaluation/scores/overview.md。
- Phoenix "lightweight wrapper"、auto_instrument、batch/flush 警告、SDK 版本解耦:arize.com/docs/phoenix/.../setup-using-phoenix-otel。
- Phoenix 成本自动计算与五级聚合、regex 自定义定价:arize.com/docs/phoenix/tracing/how-to-tracing/cost-tracking。
- Phoenix "log evaluation results back... as span annotations":arize.com/docs/phoenix/evaluation。
- 许可证(MIT vs Elastic 2.0)、自托管与 air-gap 对比:kosmoy.com/resources/blog/langfuse-vs-arize(竞争厂商立场,radar 打分视为编辑观点)。
七、结论与效果
- 五元组(token/延迟/成本/质量/trace)的统一记录可行且已有成熟路径:OTel GenAI 约定 + OTLP 打底,Langfuse 或 Phoenix 做应用层。token 与延迟是唯一有跨厂商标准的两类;成本两家都能自动化(Phoenix 内置定价表更省事,Langfuse 走
gen_ai.usage.cost/cost_details属性直传);质量两端都落在"评估结果关联回 trace"上,实现方式不同(Langfuse 独立 Score 对象 vs Phoenix span annotation),语义等价。 - 统一的最大工程量不在插桩而在属性传播与映射:trace 级维度复制到每个 span、vendor 命名空间与通用约定的优先级、未映射属性的 catch-all 行为,都是踩坑点,文档已给出对应模式。
- 约定演进风险真实存在:规范刚迁移仓库、全族 Development 态、Langfuse 亲承"still evolving"。方案设计上应把属性映射集中、避免直接依赖单个
gen_ai.*属性名的稳定性。
八、局限
- 纯文档精读,无实测:本次未部署 Langfuse/Phoenix 验证映射表行为、成本计算精度与 UI 聚合;所有"支持/不支持"均为文档声称。
- OTel 约定为 Development 快照:属性表可能随后续版本变动;本文引用的是抓取当日(2026-10-31)仓库 main 分支状态。
- 对比文的厂商立场:Kosmoy 是竞争厂商,其 81/100、74/100 打分与 air-gap "undocumented" 等说法是编辑性判断,仅取其许可证与部署事实性内容并已标注。
- 版本时效:Langfuse v4 的 ingestion header 与 trace input/output 弃用等细节随版本变化快;Phoenix 文档站为 Mintlify 动态渲染,个别代码块(token 属性的具体键名)在抓取中未展开,笔记中该处以 OpenInference 语义约定的文字描述为准。
- 未覆盖 LangSmith、OpenLLMetry/OpenLIT 插桩细节、W&B Weave 等同类,仅在 Langfuse 文档的插桩库对比表中提及。
九、对我的启发
- 自建 agent/LLM 工作流时直接用
gen_ai.*属性打 span(gen_ai.operation.name、gen_ai.request.model、gen_ai.usage.input_tokens/output_tokens),后端今天接 Langfuse、明天换 Phoenix 或自建 ClickHouse 都不用改插桩——这是本次最可复用的决策。 - 成本记录自己维护一张"定价表 + token 计数"的最小实现(参考 Phoenix 的 regex 匹配 + 每 1M 单价 + 生效日期模型),因为规范层短期不会有 cost 标准。
- 质量信号挂 ID 不入 trace 流:eval 结果以 score/annotation 关联 trace_id/span_id 回写,保持运行时遥测与评估数据可分可合——与我此前精读的 RAGAS/TruLens 评估方法论(2026-10-29 条目)可以接上:评估器输出即 Score。
- trace_id/session_id/user_id 是五元组的聚合键,任何插桩先解决"这三个 ID 传播到每个 span",再做别的(Langfuse 的 BaggageSpanProcessor 是现成模式)。
- Windows 本地场景(延续本库本地推理/语音条目的视角):Phoenix 支持
uvx arize-phoenix serve一条命令本地起服务(默认 localhost:6006,无 API key),Langfuse v3.22+ 也有/api/public/otel本地端点——两者都可作为个人实验的可观测性后端,OTLP/HTTP 一条管道通吃。
十、本次学到什么
- 可观测性问题的本质是"命名统一 + 键传播":字段名统一(语义约定)决定数据能否跨工具流动,聚合键(trace/session/user)传播决定数据能否被切片分析;两者都比选平台更根本。
- 规范与产品分工:开源标准覆盖最容易达成共识的机械量(token、时间),把需要商业判断的部分(定价表、评估模板)留给产品层——这是技术生态常见的"标准管骨骼、产品管肌肉"分层。
- 读文档要读"否定句":本文最有信息量的三个事实都是文档里的否定/空白(gRPC not supported、cost 无标准属性、规范 still evolving),正面宣传不会告诉你边界在哪。
附:原文引述备查(未在正文展开)
- "In order to avoid slowing down your application, Langfuse doesn't send traces synchronously the moment they are created. Instead, Langfuse batches traces locally and sends them in the background."(Langfuse data-model)
- "Langfuse distinguishes between trace-level attributes and observation-level attributes... If Langfuse detects these attributes on a specific span, it will treat them as properties of the whole trace."(Langfuse OTEL)
- "Attribute keys that contain
__proto__,constructor, orprototypeas a path segment... are silently dropped during ingestion. This is a security measure to prevent prototype pollution."(Langfuse OTEL,摄取层安全细节) - "The
gen_ai.provider.nameattribute acts as a discriminator"(gen-ai-spans.md, provider 判别符设计) - "Evals give you a repeatable check of your LLM application's behavior. You replace guesswork with data, and catch regressions before you ship a change."(Langfuse /docs/scores/overview)
- "Phoenix handles the rest."(Phoenix Setup OTEL,形容 auto_instrument 的零代码插桩)