OpenTelemetry 入门:面向 AI 应用与 AI Agent 开发者的通俗指南
写在前面
刚开始开发 AI 应用时,你往往只关心“模型能不能回答”。系统进入真实环境后,问题会迅速变成:
- 这次请求为什么失败?
- 是检索、模型、工具还是数据库出了问题?
- Agent 为什么重复调用工具?
- 哪一步最慢、最贵?
- 一次用户任务跨越 API、队列和 Worker 后,怎样把整个过程串起来?
OpenTelemetry 就是为这类问题提供统一观测基础设施的开放标准与工具体系。
1. 一句话理解 OpenTelemetry
OpenTelemetry(简称 OTel)是一套用于产生、关联、处理和导出遥测数据的开放标准与工具链。
这里的“遥测数据(Telemetry)”就是程序运行时产生、用于理解系统状态的数据。OpenTelemetry 当前成熟度较高的核心信号是 Trace、Metric 和 Log;Baggage 用于跨服务传播上下文信息;Profile 则仍处于 Alpha 阶段:
- Trace:一次请求完整经历了什么;
- Metric:一段时间内系统整体表现如何;
- Log:某个时刻具体发生了什么事件;
- Baggage:哪些上下文信息需要随调用链传播;
- Profile:程序的 CPU、内存等资源具体消耗在哪里,目前仍在发展中。
OpenTelemetry 本身通常不负责长期存储、查询和展示数据。它更像一套统一的“采集规范、SDK 和运输系统”;Langfuse、LangSmith、Phoenix、Grafana Tempo、Prometheus、Loki、Datadog 等才是最终接收、存储、分析或展示数据的后端平台。
2. 用“快递系统”理解 OpenTelemetry
把一次 AI Agent 请求产生的观测数据想象成包裹:
| OpenTelemetry 概念 | 快递系统类比 | 实际作用 |
|---|---|---|
| Instrumentation(插桩) | 给商品打包并贴单 | 在程序中加入采集逻辑 |
| Trace / Metric / Log | 不同类型的包裹 | 不同类型的遥测信号 |
| API | 标准寄件接口 | 规定业务代码如何创建遥测数据 |
| SDK | 快递公司的实际执行系统 | 采样、处理、聚合并导出数据 |
| Exporter | 发货车辆 | 把数据发送出去 |
| OTLP | 运输协议 | 规定遥测数据如何编码和传输 |
| Collector | 分拣中心 | 接收、脱敏、过滤、采样、批处理和转发 |
| Backend | 仓库与控制台 | 存储、查询、可视化和分析 |
| Trace Context | 快递追踪号码 | 跨服务维持同一条调用链 |
| Resource | 寄件人信息 | 标识数据由哪个服务、版本和环境产生 |
| Semantic Conventions | 统一字段字典 | 统一属性和操作的命名方式 |
最重要的认知是:
OpenTelemetry 不是一个监控网页,也不是 Langfuse 的同类产品。它是连接应用和各种可观测后端的标准化中间层。
3. OpenTelemetry 在 AI Agent 架构中的位置
一个常见架构如下:
用户请求
↓
FastAPI / Web 服务
↓
AI Agent / RAG Pipeline
├── 查询改写
├── Retriever
├── Reranker
├── LLM
├── Tool Call
└── 数据库 / 外部 API
应用内部:
├── 自动插桩:HTTP、FastAPI、数据库、Redis 等
├── 手动插桩:Agent、RAG、LLM、Tool 等业务步骤
├── Metrics:请求量、延迟、错误率、Token 等
└── Structured Logs:结构化日志
↓ OTLP
OpenTelemetry Collector
├── 脱敏
├── 过滤
├── 采样
├── 批处理与重试
└── 多后端分发
├── Langfuse / LangSmith / Phoenix:AI Trace 与评估
├── Tempo / Datadog:通用分布式追踪
├── Prometheus / Grafana:指标与告警
└── Loki / 日志平台:日志查询
可以把它拆成两个平面:
- 插桩平面(Instrumentation Plane):位于应用内部,负责产生数据。
- 管道平面(Pipeline Plane):通常由 Collector 承担,负责搬运和处理数据。
4. 最容易混淆的核心组件
4.1 Specification:规范
规范是 OpenTelemetry 的“规则书”,定义 Trace、Metric、Log、Context、OTLP 等概念应当如何工作。它不是代码,而是各语言 SDK 和工具实现时应遵守的共同标准。
4.2 API:业务代码使用的接口
API 定义“怎样创建遥测数据”。例如:
tracer.start_as_current_span("rag.retrieve")
API 尽量稳定、轻量。一个库可以只依赖 API,而不决定数据最终发到哪里。
4.3 SDK:真正执行采集和导出的实现
SDK 负责把 API 产生的数据真正处理起来,包括:
- 创建 Provider;
- 采样;
- 聚合 Metric;
- 批处理;
- 调用 Exporter;
- 配置 Resource;
- 控制数据是否以及怎样导出。
可以理解为:
API:你用什么方法描述“我要记录数据”
SDK:这些数据如何被真正处理和发送
4.4 Instrumentation 与 Instrument 不是一回事
这是最容易混淆的一对术语。
Instrumentation(插桩):给代码加入观测能力的整个过程。
with tracer.start_as_current_span("tool.weather"):
result = call_weather_tool()
Instrument(指标工具):专属于 Metrics 的对象,例如 Counter、Histogram、ObservableGauge。
request_counter = meter.create_counter("agent.requests")
所以:
Instrumentation = 给程序加入观测逻辑
Instrument = 用于记录某类 Metric 的工具对象
4.5 Provider、Tracer 和 Meter
TracerProvider 是 Tracer 的总入口与配置中心;Tracer 用于创建 Span。
TracerProvider → Tracer → Span
MeterProvider 是 Meter 的总入口与配置中心;Meter 用于创建 Metric Instrument。
MeterProvider → Meter → Counter / Histogram / Gauge
Provider 通常在应用启动时初始化一次,而不是每个请求重新创建。
4.6 Exporter
Exporter 负责把遥测数据发送到外部,例如:
OTLP Exporter → Collector
Console Exporter → 终端
Prometheus Exporter → Prometheus 兼容端点
Exporter 是应用或 Collector 内部的“输出适配器”,不是存储系统。
4.7 OTLP
OTLP 是 OpenTelemetry Protocol,负责规定 Trace、Metric、Log 等数据怎样在应用、Collector 和后端之间传输。
应用 --OTLP--> Collector --OTLP/其他协议--> 后端
OTLP 是协议,不是服务,也不是数据库。
4.8 Collector
OpenTelemetry Collector 是一个独立运行的遥测数据服务。它的典型流水线是:
Receiver → Processor → Exporter
- Receiver:接收数据;
- Processor:批处理、过滤、采样、脱敏、补标签;
- Exporter:把数据发送给一个或多个后端。
Collector 还可以使用 Connector 连接不同管道,使用 Extension 提供健康检查、认证等辅助能力。
4.9 Backend
Backend 是最终保存、查询、展示或分析数据的平台。例如:
- Langfuse:AI/LLM/Agent Trace、成本、评估与数据集;
- LangSmith:Agent Tracing 与 Evaluation;
- Phoenix:AI Observability 与 Evaluation;
- Tempo:Trace 存储和查询;
- Prometheus:Metric 存储和查询;
- Loki:日志存储和查询。
OpenTelemetry 与这些平台的关系通常是:
OpenTelemetry 负责生成和运输
Backend 负责存储和使用
5. OpenTelemetry 的主要观测信号
5.1 Trace:一次请求的完整执行路径
Trace 用于回答:
“这一次具体请求,按什么顺序经过了哪些步骤?”
一次 AI Agent 任务可以表示为:
Trace: agent.run
├── Span: auth.check
├── Span: session.load
├── Span: rag.retrieve
│ ├── Span: embedding.create
│ └── Span: vector_db.search
├── Span: reranker.rank
├── Span: llm.plan
├── Span: tool.weather
├── Span: llm.answer
└── Span: result.persist
Span
Span 是 Trace 中的一个工作单元,例如一次数据库查询、模型调用或工具执行。
一个 Span 通常包含:
- name:步骤名称;
- start/end time:开始和结束时间;
- parent:父 Span;
- attributes:结构化属性;
- events:步骤内部的重要时间点;
- status:成功或错误状态;
- links:与其他 Trace/Span 的关联;
- trace_id / span_id:调用链身份。
Attribute
Attribute 是附加在 Span 上的键值信息:
gen_ai.agent.name = "support-agent"
gen_ai.request.model = "example-model"
gen_ai.tool.name = "search_orders"
app.tool.success = true
前三个字段来自当前仍在演进的 GenAI 语义约定;app.tool.success 是本文为了说明业务字段而使用的自定义属性。生产项目应为自定义字段使用稳定、明确的命名空间,不要让它们看起来像 OpenTelemetry 官方字段。
Span Event
Event 是 Span 生命周期内某个重要瞬间,例如:
retry_started
rate_limit_received
fallback_model_selected
Link
父子关系表达一次执行链中的直接延续。对于队列和异步任务,如果生产者 Context 能被消费者提取,消费者 Span 仍可延续同一条 Trace;当一个任务由多个上游共同触发、批处理合并多条消息,或不适合建立单一父子关系时,再使用 Link 表达因果关联。
Trace 适合什么场景
- 定位一次失败请求;
- 分析 Agent 循环;
- 查看工具选择和参数;
- 查看 RAG 检索与精排链路;
- 分析哪一步最慢;
- 串联 API、Worker、数据库和外部服务。
5.2 Metrics:大量请求聚合后的数值趋势
Metric 用于回答:
“系统最近整体表现怎么样?”
例如:
每分钟请求数
任务成功率
错误率
P95 延迟
LLM Token 总量
每次成功任务成本
当前队列长度
工具调用失败次数
Metric 的核心对象关系:
MeterProvider
↓
Meter
↓
Instrument
↓
Measurement
↓
聚合后的 Metric
Measurement
Measurement 是一次具体测量值。例如:
request_counter.add(1)
latency_histogram.record(850)
这里的 1 和 850 都是 Measurement。
常见 Instrument
| Instrument | 特点 | AI 应用示例 |
|---|---|---|
| Counter | 只能累计增加 | 请求总数、错误总数、Token 总数 |
| UpDownCounter | 可以增加或减少 | 当前正在运行的 Agent 数量 |
| Histogram | 记录数值分布 | 延迟、Token 数、文档大小 |
| ObservableGauge | 定期读取当前值 | 队列长度、当前内存、活跃任务数 |
Observation
Observation 是异步 Instrument 回调返回的一次观测值。它和 Python 的 async/await 不是一回事。
例如,OpenTelemetry 定期调用回调获取当前队列长度:
def observe_queue_size(options):
yield Observation(queue.qsize(), {"queue": "rag-ingestion"})
Metric 适合什么场景
- Dashboard;
- 趋势分析;
- SLO 和告警;
- 容量规划;
- 版本前后对比;
- 成本与吞吐监控。
Cardinality:必须理解的 Metric 风险
Cardinality 指标签值组合的数量。
不要把这些字段直接放进 Metric Attribute(在 Prometheus 等后端中通常表现为 Label):
user_id
session_id
trace_id
完整 URL
原始 Prompt
订单号
因为每个值几乎都不同,会产生海量时间序列,导致存储和查询成本失控。高基数字段适合放进 Trace 或 Log,而不是 Metric 标签。
5.3 Logs:某个时刻发生的具体事件
Log 是带时间戳的事件记录。推荐使用结构化日志:
{
"timestamp": "2026-07-16T12:00:00Z",
"level": "ERROR",
"event": "tool_call_failed",
"tool_name": "search_orders",
"error_type": "timeout",
"trace_id": "...",
"span_id": "..."
}
结构化日志的重点不是“看起来像 JSON”,而是字段命名和类型长期一致,便于机器查询。
Log 适合记录:
- 异常堆栈;
- 工具返回的错误详情;
- 业务审计事件;
- 状态变化;
- Collector 或 Worker 的运行信息。
Trace 与 Log 最好通过 trace_id、span_id 关联:先从 Metric 发现异常,再打开 Trace 定位步骤,最后查看对应 Log 的详细错误。
5.4 Profiles:代码具体把 CPU 和内存耗在哪里
Profile 用于回答:
“程序运行时,CPU 时间、内存分配或调用栈主要消耗在哪里?”
它更偏性能工程,而且 OpenTelemetry Profiles 规范目前仍为 Alpha,不是 AI Agent 第一阶段的优先项。对于刚入门的项目,先把 Trace、Metrics 和 Logs 做好即可。
6. 四类信号怎样协作
最实用的理解是:
Metrics:发现系统整体有问题
↓
Trace:定位某一次请求哪一步有问题
↓
Logs:查看该步骤具体错误细节
↓
Profiles:进一步分析代码级性能瓶颈
例如:
Metrics:P95 从 3 秒升到 12 秒
Trace:慢请求都卡在 reranker.rank
Logs:Reranker API 多次触发超时重试
Profile:本地预处理还存在 CPU 热点
它们不是互相替代,而是观察同一系统的不同角度。
7. Context Propagation:怎样把跨服务调用串成一条 Trace
AI 系统经常跨越:
FastAPI → Queue → Worker → LLM → Tool Service → Database
如果每个服务都各自创建 Trace,你只能看到很多不相关的片段。
Context Propagation 会把 trace_id 和当前 span_id 跨进程传播。HTTP 通常使用 W3C Trace Context,例如 traceparent Header;消息队列则需要把 Context 写入消息属性,再由消费者恢复。
Service A 创建 Trace
↓ 注入 traceparent
Service B 提取 Context
↓ 创建子 Span
Service C 继续传播
trace_id、session_id 和 request_id 的区别
trace_id:一次具体执行链
session_id:一段多轮对话
request_id:应用自己定义的一次 API 请求 ID
一个 Session 可以包含多条 Trace;不要用 session_id 代替 trace_id。
8. Resource、Semantic Conventions 与 Baggage
Resource
Resource 描述“谁产生了这批遥测数据”:
service.name = "rag-api"
service.version = "1.4.2"
deployment.environment.name = "production"
cloud.region = "asia-northeast1"
Resource 通常在应用启动时设置,并随该 Provider 产生的遥测数据导出。具体支持哪些信号取决于所使用语言的 SDK 和信号实现。
Semantic Conventions
Semantic Conventions 是统一字段命名规则。例如各团队都按照相同约定记录 HTTP、数据库、消息队列和 GenAI 属性,后端才能统一查询和展示。
可以理解为:
语义约定不是数据运输协议,而是遥测字段的“共同词典”。
OpenTelemetry 正在为 GenAI 客户端、Agent、MCP 和部分模型提供商建设专用语义约定。截至本文发布时,这些约定已迁移到独立的 GenAI 语义约定仓库,整体仍处于 Development 状态,字段和 Span 结构可能继续变化;实现时应固定所采用的语义约定版本。
Baggage
Baggage 是会随 Context 跨服务传播的业务键值信息,例如:
tenant.tier = "enterprise"
experiment.group = "prompt-v2"
它不会自动变成 Span Attribute,需要显式读取和使用。
不要把 API Key、个人信息、完整 Prompt 等敏感数据放进 Baggage,因为它可能传播到下游甚至第三方服务。
9. OpenTelemetry 在 AI 与 Agent 系统中的特殊价值
传统 Web 请求通常是比较固定的:
HTTP → Service → Database → Response
Agent 执行路径更动态:
用户问题
→ 模型规划
→ 检索
→ 工具 A
→ 模型再次判断
→ 工具 B
→ 重试或回退
→ 最终回答
因此 AI 可观测性需要同时记录:
- 模型与提供商;
- Prompt 或 Prompt 版本;
- 输入、输出和缓存 Token;
- 模型延迟和结束原因;
- Agent 节点与状态转换;
- Tool 名称、参数 Schema 和执行结果;
- Retriever、Reranker、Top K 与文档 ID;
- Guardrail;
- 重试、Fallback 和 Handoff;
- 成本与业务任务结果。
OpenTelemetry 负责把这些步骤放进统一的 Trace 体系,并与 HTTP、数据库、队列等传统基础设施调用串起来。
GenAI Semantic Conventions
OpenTelemetry 的 GenAI 语义约定定义 AI 客户端、Agent、MCP、模型调用等应怎样命名 Span、Metric 和 Event。它让不同框架产生的数据更容易被统一后端理解,但目前仍处于 Development 状态,不应被当成已经完全稳定的长期契约。
OpenInference
OpenInference 是建立在 OpenTelemetry 思路之上的 AI 专用约定与插桩插件生态,覆盖 OpenAI、Anthropic、LangChain、LlamaIndex、Google ADK、MCP 等框架。它适合在某些官方 OTel GenAI 插桩尚不方便时快速获得 AI 专用 Trace。
Langfuse、LangSmith 与 Phoenix
这些属于 AI 可观测与评估后端,而不是 OpenTelemetry 的替代品。它们可以直接或间接接收 OpenTelemetry Trace,并提供更适合 LLM/Agent 的界面、成本分析、Dataset、Experiment 和 Evaluation。
10. 可观测性与 Evaluation 不是同一件事
OpenTelemetry 主要回答:
“Agent 做了什么?”
Evaluation 主要回答:
“Agent 做得好不好?”
例如:
OpenTelemetry:
调用了 search_orders
参数是 order_id=123
耗时 800ms
最终未报错
Evaluation:
是否本来就应该调用这个工具
order_id 是否正确
用户的退款任务是否真的完成
回答是否忠实于工具结果
成熟系统通常把两者连接起来:
生产 Trace
→ 规则、用户反馈或 LLM Judge 打分
→ 失败样本加入 Dataset
→ 修改 Prompt / 模型 / Workflow
→ 离线 Experiment
→ CI 回归
→ 灰度发布
Trace 是评估的数据基础,但 Trace 本身不等于质量结论。
11. AI Agent 的推荐 Trace 设计
推荐原则:一次用户任务或一次 Agent Run 对应一条 Trace。
Trace: agent.run
├── request.validate
├── context.load
├── rag.retrieve
│ ├── query.embed
│ ├── dense.search
│ ├── sparse.search
│ ├── rrf.fuse
│ └── reranker.rank
├── llm.plan
├── tool.call
├── guardrail.check
├── llm.answer
└── result.persist
只为具有诊断价值的步骤创建 Span。不要把每个小函数都变成 Span,否则 Trace 会充满噪声并增加成本。
服务身份应优先放在 Resource 中,例如:
service.version
deployment.environment.name
Agent Run 的 Span 再记录与本次执行有关的信息。已有官方约定时使用官方字段;没有官方约定时使用应用自定义命名空间,例如:
gen_ai.agent.name
gen_ai.agent.version
gen_ai.conversation.id
app.release.git_sha
app.prompt.version
app.knowledge_base.version
模型 Span 建议记录:
gen_ai.provider.name
gen_ai.request.model / gen_ai.response.model
gen_ai.usage.input_tokens / gen_ai.usage.output_tokens
gen_ai.response.finish_reasons
error.type
app.retry_count
延迟通常由 Span 自身的起止时间表达;只有确有独立聚合需求时才额外记录 Metric。缓存 Token 等扩展字段是否可用,取决于所采用的语义约定版本和具体插桩实现。
工具 Span 建议记录:
gen_ai.tool.name
gen_ai.tool.type
error.type
app.tool.version
app.tool.success
RAG Span 建议记录:
app.rag.index.name
app.rag.index.version
app.rag.top_k
app.rag.retrieved_document_ids
app.rag.reranker.name
app.rag.result_count
这里的 app.rag.* 是示例性自定义属性,不是 OpenTelemetry 官方 RAG 语义约定。
不要默认记录完整 Prompt、用户文档、Tool 返回原文或隐藏思维链。
12. 推荐的生产架构
开发阶段
Python AI App
├── OpenTelemetry 自动插桩
├── 少量手动 Agent Span
├── JSON stdout Logs
└── OTLP Exporter
↓
Langfuse / Phoenix / LangSmith
适合快速验证,不一定需要 Collector。
准生产与生产阶段
Python AI App
↓ OTLP
OpenTelemetry Collector
├── memory_limiter
├── batch
├── redaction / transform
├── sampling
└── exporters(sending queue / retry)
├── Langfuse / LangSmith / Phoenix
├── Tempo / Datadog
├── Prometheus
└── Logs backend
Collector 带来的关键价值:
- 应用与厂商后端解耦;
- 集中脱敏;
- 集中采样;
- 批处理和重试;
- 一份数据发送多个平台;
- 后端变更时减少业务代码修改。
13. 生产最佳实践
13.1 自动插桩与手动插桩结合
自动插桩覆盖 FastAPI、HTTP 客户端、数据库、Redis 等通用调用;手动插桩补充 Agent 任务、RAG、Tool、Guardrail 和业务结果。
13.2 可观测系统故障不能拖垮业务
使用批处理和异步导出;Collector 在 Exporter 上配置 Sending Queue、退避重试以及按需启用的持久化。遥测后端短暂不可用时,AI 业务应尽量继续运行,同时必须监控队列容量、丢弃量和磁盘占用。
13.3 生产环境不要无条件记录完整输入输出
敏感内容应在应用离开前脱敏,Collector 再做第二层过滤。重点保护:
Authorization / Cookie / API Key
邮箱、电话、身份证件
用户私有文档
数据库返回的敏感字段
完整 Prompt 和模型输出
13.4 不记录隐藏思维链
记录可审计的结构化结果:
selected_tool
route
state_transition
validation_result
policy_decision
不要依赖或保存模型的隐藏 Chain-of-Thought。
13.5 控制 Metric Cardinality
Metric Attribute 只使用低基数字段,例如:
model_family
environment
status
tool_name
error_type
用户 ID、Trace ID、Prompt 等高基数字段放进 Trace 或 Log。
13.6 采样不要只做固定随机抽样
开发环境可以保留 100% Trace;生产环境可以随机保留部分正常请求,并使用 Tail Sampling 优先保留:
错误 Trace
慢 Trace
高成本 Trace
高风险工具操作
异常循环
Head Sampling 在请求开始时决定是否记录,成本低;Tail Sampling 在看到更多完整 Trace 信息后决定,策略更精确,但需要 Collector 保持状态,复杂度更高。用户点踩等请求结束后才到达的反馈通常不能直接影响已经完成的 Tail Sampling 决策,应通过 Trace ID 关联到后续评估数据或独立保留策略。
13.7 统一传播 Context
HTTP 自动传播通常较成熟;队列、定时任务和数据库任务需要显式注入与提取 Context。否则 Worker Trace 会与入口请求断开。
13.8 使用 Resource 与版本信息
至少设置:
service.name
service.version
deployment.environment.name
AI 应用还应记录 gen_ai.agent.version,并使用自定义命名空间记录 app.prompt.version、app.knowledge_base.version 和 app.release.git_sha,以便比较版本回归。
13.9 监控 Collector 自身
Collector 也会出现队列堆积、内存不足、导出失败和数据丢弃。生产环境必须监控它的接收量、发送失败、队列容量和丢弃数量。
14. 一个最小 Python Trace 示例
下面展示一个可以独立运行的最小示例。先安装依赖:
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
示例假设本机 4318 端口已有支持 OTLP/HTTP 的 Collector 或后端。实际项目通常还会加入自动插桩、Metric、日志关联与脱敏。
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
resource = Resource.create(
{
"service.name": "my-rag-agent",
"service.version": "1.0.0",
"deployment.environment.name": "development",
}
)
provider = TracerProvider(resource=resource)
provider.add_span_processor(
BatchSpanProcessor(
OTLPSpanExporter(
endpoint="http://localhost:4318/v1/traces",
)
)
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("my-rag-agent")
def retrieve(query: str) -> list[str]:
return [f"example document for: {query}"]
def generate_answer(query: str, documents: list[str]) -> str:
return f"answer based on {len(documents)} document(s)"
def run_agent(query: str) -> str:
with tracer.start_as_current_span("agent.run") as root:
root.set_attribute("gen_ai.agent.name", "rag-agent")
root.set_attribute("app.prompt.version", "answer-v3")
with tracer.start_as_current_span("rag.retrieve") as span:
documents = retrieve(query)
span.set_attribute("app.rag.result_count", len(documents))
with tracer.start_as_current_span("llm.generate") as span:
answer = generate_answer(query, documents)
span.set_attribute("gen_ai.request.model", "example-model")
return answer
if __name__ == "__main__":
print(run_agent("What is OpenTelemetry?"))
provider.force_flush()
这个例子产生:
agent.run
├── rag.retrieve
└── llm.generate
后续再逐步加入 FastAPI 自动插桩、HTTPX、数据库、队列 Context、Metrics 和日志关联即可。示例中的 agent.run、rag.retrieve、llm.generate 和 app.rag.result_count 是教学用的应用自定义命名;如果项目采用 GenAI 语义约定,应按所固定版本的 Span 命名和属性要求实现。
15. 初学者最常见的误解
“OpenTelemetry 就是监控平台”
错误。它主要负责标准化采集、关联、处理和导出;真正的 UI、存储和分析由后端平台完成。
“OTLP 就是 Collector”
错误。OTLP 是传输协议;Collector 是接收和处理数据的服务。
“Trace 和 Log 是同一种东西”
错误。Trace 展示一次请求的结构化执行链;Log 记录具体事件和细节。
“Metric 是很多 Trace 自动相加”
不完全正确。Metric 有独立的数据模型、Instrument 和聚合体系;可以从应用直接记录,也可以由其他数据转换而来。
“Instrument 就是插桩”
错误。Instrumentation 是插桩过程;Instrument 是 Metrics 里的 Counter、Histogram 等工具。
“Session 就是一条 Trace”
错误。一段多轮 Session 通常包含多条独立 Trace。
“有了 Trace 就完成了 Evaluation”
错误。Trace 记录执行事实;Evaluation 需要规则、Ground Truth、LLM Judge、人工反馈或真实业务结果来判断质量。
16. 建议的学习与落地顺序
第一阶段:只理解 Trace
实现:
一次 Agent Run = 一条 Trace
LLM、RAG、Tool = 子 Span
先学会在后端界面完整查看一次请求。
第二阶段:加入 Metrics 和结构化日志
添加:
请求数
错误率
延迟 Histogram
Token 和成本
JSON 日志 + trace_id/span_id
第三阶段:加入 Collector
集中实现:
批处理
脱敏
采样
重试
多后端分发
第四阶段:连接 Evaluation
把用户反馈、任务成功、工具正确率和 LLM Judge 分数关联到 Trace,并让失败案例进入 Dataset 和 CI 回归。
结语
对 AI 应用开发者来说,最重要的不是一次记住所有 OpenTelemetry 术语,而是先建立这条主线:
应用通过插桩产生 Trace、Metric 和 Log
↓
SDK 处理并通过 OTLP 导出
↓
Collector 统一接收、加工和分发
↓
Langfuse、Tempo、Prometheus 等后端负责存储、展示和分析
再用一句话区分三类核心信号:
Trace:这一次请求经历了什么
Metrics:系统整体最近表现如何
Logs:某个时刻具体发生了什么
在 AI Agent 中,OpenTelemetry 的核心价值是把模型、检索、工具、数据库、队列和外部服务放进同一条可追踪链路;而 Langfuse、LangSmith、Phoenix 等平台则在此基础上进一步提供 AI 专用的分析和评估能力。
真正成熟的方案不是“把所有数据全都记录下来”,而是:
记录有诊断价值的数据,使用统一语义,保护敏感信息,控制成本,并让可观测数据持续服务于评估和改进。
官方参考资料
- OpenTelemetry: What is OpenTelemetry?
- OpenTelemetry Signals
- OpenTelemetry Traces
- OpenTelemetry Metrics
- OpenTelemetry Logs
- OpenTelemetry Profiles
- OpenTelemetry Instrumentation
- OpenTelemetry Context Propagation
- OpenTelemetry Collector
- OpenTelemetry: Handling Sensitive Data
- OpenTelemetry Python Exporters
- OTLP Specification
- OpenTelemetry GenAI Semantic Conventions
- OpenInference
- Langfuse Tracing
- LangSmith OpenTelemetry Tracing
- OpenAI Agent Evaluations