跳到主要内容

OpenLLMetry 是什么 · 全景与阅读地图

30 秒导读: OpenLLMetry 是 Traceloop 出品、Apache-2.0 许可的一套开源库,它建在 OpenTelemetry(业界标准的可观测性框架,简称 OTel)之上,专门给 LLM 应用做可观测性。你只加一行 Traceloop.init(),它就把你对 OpenAI / Anthropic / LangChain / 向量库等的调用自动变成标准的 OTel trace(调用链路),并能直接送进你已有的 Datadog、Honeycomb 等后端。


1. 这是什么(零基础也能懂)

1.1 一句话定义

OpenLLMetry = 「给 LLM 应用装的一层自动录像机」,录出来的带子(trace)是 OpenTelemetry 标准格式,所以任何认识 OTel 的后端都能直接播放。

名词先点破:

  • 可观测性(Observability):让你在线上能看清「程序此刻在干什么、慢在哪、错在哪」的能力。
  • OpenTelemetry / OTel:一套开放标准 + SDK,规定了 trace(一次请求的调用链)、span(链上的每一段)、metrics、logs 长什么样、怎么导出。是这个领域的「普通话」。
  • trace / span:一次请求是一条 trace;trace 里每一步(一次 OpenAI 调用、一次向量检索、一段你的业务函数)是一个 span,span 之间有父子关系,拼成一棵树。

1.2 解决什么问题 / 给谁用

假设你写了个 RAG 或 agent 应用:用户提问 → 你查向量库 → 拼 prompt → 调 OpenAI → 返回。上线后老板问「为什么这次回答花了 8 秒、花了多少 token、prompt 到底发了什么」——你两眼一抹黑,因为这些调用都藏在第三方 SDK 内部。

OpenLLMetry 就是来解决这个「LLM 调用是黑盒」的问题:

  • 给谁用:写 LLM / agent 应用、需要在生产环境看清每次模型调用的工程师。
  • 它替你自动记下:调了哪个模型、prompt 和 completion 内容、input/output token 数、耗时、报错、以及这次调用挂在整条请求链的哪个位置。

1.3 它能做什么(功能)

  • 自动埋点:装好即用,无需改动你调 OpenAI / Anthropic / LangChain 等的业务代码。
  • 标准输出:产出的是原味 OpenTelemetry 数据,不锁定厂商。
  • 接现有后端:Datadog、Honeycomb、Grafana、New Relic、Traceloop 自家平台等 20+ 目的地(见 README「Supported destinations」)。
  • 手动埋点:用 @workflow / @task / @agent / @tool 装饰器给你自己的业务函数也画上 span。
  • 评测与护栏:SDK 里还带了 evaluator / guardrail / datasets / experiment 等平台层能力(第 5 章讲)。

1.4 用起来什么样(最小示例)

README 给的上手就两步——装包,然后一行 init。(真实出处:README.md:68-78

# 1) 安装 SDK(终端)
# pip install traceloop-sdk

# 2) 在你的应用启动处加一行
from traceloop.sdk import Traceloop

Traceloop.init() # 就这一行:装好 OTel、并自动 instrument 所有已安装的 LLM 库

# 之后你照常写业务代码,OpenAI 调用会被自动录成 span
import openai
openai.chat.completions.create(model="gpt-4o", messages=[{"role": "user", "content": "hi"}])

本地调试想立刻看到 trace(不攒批)就传 disable_batch=TrueREADME.md:83-85)。就这样,你的代码已经在被 OpenLLMetry 追踪了。

1.5 一句话直觉/类比

把 OpenTelemetry 当成「录像机的通用磁带格式」,OpenLLMetry 就是「专门对准 LLM 调用的那台自动摄像机 + 一堆预装好的镜头」。 你不用自己布线,插上电(init())它就开始录,录出来的带子谁都能放。

本节不涉及底层代码。完全没接触过的人读到这里,应该已经能回答「OpenLLMetry 是干嘛的」。


2. 顶层全景(它大概怎么转)

2.1 一张顶层结构图:monorepo 的两大半

这是一个用 Nx 管理的 monorepopackages/ 下 35 个包)。抓大放小,它其实就分两半

OpenLLMetry monorepo (packages/)

┌─────────────────────────┴─────────────────────────┐
│ │
(a) 自动埋点包 ×32 (b) 装配层 + 语义约定
opentelemetry-instrumentation-* traceloop-sdk
│ opentelemetry-semantic-conventions-ai
每个第三方库一个「镜头」: │
┌──────────────┬──────────────┐ ┌──────────────┬───────────────┐
│ openai │ anthropic │ │ 装配管道 │ 手动装饰器 │
│ langchain │ bedrock ... │ │ (init 流水线)│ @workflow/... │
│ pinecone │ chromadb ... │ ├──────────────┼───────────────┤
│ crewai/mcp.. │ (LLM+向量库+ │ │ 语义约定常量 │ 评测/护栏平台 │
│ │ 框架) │ │ (span 字段名)│ eval/guardrail│
└──────────────┴──────────────┘ └──────────────┴───────────────┘
用 wrapt 猴补丁拦住每一次调用 把上面这些「装好、串起来、送出去」

怎么读这张图: 左半 (a) 是一堆独立的 pip 包,每个只负责「拦住某一个库并生成 span」;右半 (b) 的 traceloop-sdk总装厂——它把 OTel 的 provider/exporter 装好、把 (a) 里的镜头一次性 instrument(),并额外提供手动装饰器和评测平台。两半都依赖中间的 semantic-conventions-ai(规定 span 上字段叫什么)。

2.2 部件一句话职责

部件干什么在哪个 package
自动埋点(instrumentation)用 wrapt 猴补丁包住第三方库的调用点,把每次调用录成 spanpackages/opentelemetry-instrumentation-*(32 个,如 -openai -anthropic -langchain -pinecone
语义约定(semantic conventions)定义 span 上字段的标准名字(如 gen_ai.promptgen_ai.request.model)和枚举值packages/opentelemetry-semantic-conventions-ai(模块 opentelemetry.semconv_ai
SDK 装配管道Traceloop.init():建 TracerProvider、挂 processor + exporter、把所有 instrumentation 打开packages/traceloop-sdktraceloop/sdk/__init__.pytracing/tracing.py
手动装饰器@workflow/@task/@agent/@tool 给你自己的业务函数画 span 并传播上下文packages/traceloop-sdktraceloop/sdk/decorators/
评测护栏平台evaluator / guardrail / datasets / experiment:从「可观测」延伸到「可评估、可拦截」packages/traceloop-sdktraceloop/sdk/evaluator/guardrail/datasets/experiment/

2.3 主线走一遍(高层,不进代码)

从「你写 Traceloop.init()」到「一条 span 被送出去」,主线是这样流的:

① 用户代码
Traceloop.init()


② 装配(init 一次性做完)
建 TracerProvider ──▶ 挂 SpanProcessor ──▶ 挂 Exporter(OTLP/自定义)
│ (送去 Traceloop/Datadog/...)
└──▶ init_instrumentations(): 把 32 个库逐个 instrument()(wrapt 猴补丁上线)


③ 运行时(你照常调 openai.chat.completions.create(...))
wrapt 包装函数被触发 ──▶ 开一个 span,按「语义约定」写入
gen_ai.request.model / gen_ai.prompt / ... ──▶ 调真库拿结果
──▶ 写 gen_ai.completion / token 数 ──▶ 结束 span


④ 富化 + 导出
span on_start 时被 processor 富化(补 workflow/entity 等属性)
──▶ 批量(BatchSpanProcessor)导出到后端
  • ② 装配Traceloop.init()packages/traceloop-sdk/traceloop/sdk/__init__.py:50)读配置、建 TracerWrappertracing/tracing.py:75__new__),后者挂好 processor/exporter 并调 init_instrumentationstracing/tracing.py:495)逐库 instrument()
  • ③ 运行时:每个 instrumentation 用 wrap_function_wrapper 替换真库的方法(如 openai:packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/v1/__init__.py:68),调用发生时先开 span 再放行。
  • ④ 富化:span 起始时经 default_span_processor_on_starttracing/tracing.py:369)补上 workflow/entity 等关联属性,再批量导出。

目标:看懂「大盘」。每条主线在后续章节都有专章深挖(见下方阅读地图)。


3. nx workspace / packages 布局

packages/ 下共 35 个包(32 个 instrumentation + 1 语义约定 + traceloop-sdk + sample-app)。Nx 负责跨包跑测试/lint、算依赖影响面。

  • 工作区声明:package.json:11-13"workspaces": ["packages/*"])+ nx.jsonextends: nx/presets/npm.json,插件 @nxlv/python)。
  • 包管理器是 uv、语言是 Python(≥3.10),每个包自带 pyproject.toml

结构骨架:

openllmetry/
├── package.json # nx workspace: workspaces = packages/*
├── nx.json # @nxlv/python 插件
├── README.md # 上手示例(pip install + Traceloop.init)
└── packages/
├── traceloop-sdk/ # ← 装配层 + 装饰器 + 评测平台
│ └── traceloop/sdk/
│ ├── __init__.py # Traceloop.init() 入口
│ ├── tracing/tracing.py # TracerWrapper / init_instrumentations
│ ├── decorators/ # @workflow/@task/@agent/@tool
│ ├── evaluator/ guardrail/ datasets/ experiment/ # 平台层
│ └── metrics/ logging/ client/ ...
├── opentelemetry-semantic-conventions-ai/ # ← span 字段名/枚举 (semconv_ai)
│ └── opentelemetry/semconv_ai/__init__.py
├── opentelemetry-instrumentation-openai/ # ← 自动埋点包(32 个之一)
│ └── opentelemetry/instrumentation/openai/{__init__.py, v0/, v1/, shared/}
├── opentelemetry-instrumentation-anthropic/
├── opentelemetry-instrumentation-langchain/
├── ... (共 32 个 opentelemetry-instrumentation-*)
└── sample-app/ # 示例应用

traceloop-sdk 通过 pyproject.toml 依赖把全部 32 个 instrumentation 包声明为自己的依赖packages/traceloop-sdk/pyproject.toml:25 起的 opentelemetry-instrumentation-* 列表),所以「装一个 traceloop-sdk = 装好全套镜头」,这正是「一行 init 就全自动」的物质基础。


4. 巧妙之处(先记住,细节在后续章节)

这几点是 OpenLLMetry 设计上值得带走的「精华」,本页只点破,具体源码走读留给对应章节:

  • 不发明轮子,只做扩展。 它不自造 trace/span/exporter,全用 OTel 现成的;自己只贡献「LLM 专属的镜头 + 字段命名」。好处:产出是标准数据,天然接入一切 OTel 后端(README.md:54 明说)。→ 细节见 01
  • 一行 init 打开一切,靠「声明式依赖 + 逐库探测」。 init_instrumentations 遍历所有已知库,装了才 instrument()、没装就跳过(tracing/tracing.py:495),配合 pyproject 把 32 个包设为依赖,实现「零配置全覆盖」。→ 见 01
  • 用 wrapt 猴补丁「无侵入」拦调用。 不要求你改一行业务代码,运行时用 wrap_function_wrapper 替换真库方法(.../openai/v1/__init__.py:68)。→ 见 02
  • 字段名集中定义、对齐官方 GenAI 语义约定。 SpanAttributesopentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py:66)把 gen_ai.prompt/gen_ai.completion/gen_ai.request.model 等常量收一处,32 个 instrumentation 共用,保证跨库一致。→ 见 03
  • span 起始即富化。 processor 的 on_starttracing/tracing.py:369 default_span_processor_on_start)在 span 刚建时就补上 workflow/entity 关联,让自动 span 和你手动画的业务 span 拼成一棵有意义的树。→ 见 02 / 04
  • 装饰器把「业务语义」叠加到「技术 trace」上。 @workflow/@task/@agent/@tooldecorators/__init__.py:73-130)复用同一套 entity_method/entity_class,只是 tlp_span_kind 不同,用 traceloop.span.kind 标注(枚举见 semconv_ai/__init__.py:373)。→ 见 04

5. 代码地图(导航索引)

主题文件路径符号名
SDK 入口 / 一行 initpackages/traceloop-sdk/traceloop/sdk/__init__.py:50Traceloop.init
默认 processor 工厂packages/traceloop-sdk/traceloop/sdk/__init__.py:256Traceloop.get_default_span_processor
装配核心(建 provider/挂 processor/exporter)packages/traceloop-sdk/traceloop/sdk/tracing/tracing.py:75TracerWrapper.__new__
逐库打开自动埋点packages/traceloop-sdk/traceloop/sdk/tracing/tracing.py:495init_instrumentations
单个库的初始化范式packages/traceloop-sdk/traceloop/sdk/tracing/tracing.py:644init_openai_instrumentor
span 起始富化packages/traceloop-sdk/traceloop/sdk/tracing/tracing.py:369default_span_processor_on_start
OTLP span exporter 构建packages/traceloop-sdk/traceloop/sdk/tracing/tracing.py:327init_spans_exporter
自动埋点范式(wrapt 猴补丁)packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/v1/__init__.py:68wrap_function_wrapper
Instrumentor 骨架packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/__init__.py:12OpenAIInstrumentor
span 字段名常量packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py:66SpanAttributes
手动埋点装饰器packages/traceloop-sdk/traceloop/sdk/decorators/__init__.py:73task / workflow / agent / tool
装饰器底座(建业务 span)packages/traceloop-sdk/traceloop/sdk/decorators/base.pyentity_method / entity_class
span kind 枚举packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py:373TraceloopSpanKindValues
护栏装饰器packages/traceloop-sdk/traceloop/sdk/decorators/__init__.py:218guardrail
评测 / 数据集 / 实验packages/traceloop-sdk/traceloop/sdk/{evaluator,datasets,experiment}/Evaluator / Datasets / Experiment

6. 后续 5 章建议阅读顺序

按「装配 → 拦截 → 记什么 → 手动叠加 → 平台层」由浅入深读:

  1. 01-sdk-bootstrap-pipeline.md — SDK 启动与 OTel 导出管道。看懂 init() 那一行背后:怎么建 provider、挂 processor/exporter、逐库打开埋点。先读这章,它是全局骨架。
  2. 02-auto-instrumentation.md — 自动埋点机制。wrapt 猴补丁如何在运行时拦住每一次 LLM 调用、开 span、放行。
  3. 03-semantic-conventions.md — GenAI 语义约定。span 上到底记了哪些字段、叫什么名、对齐官方 OTel GenAI 规范到什么程度。
  4. 04-manual-decorators.md — 手动埋点。@workflow/@task/@agent/@tool 怎么给业务函数画 span、怎么通过上下文把自动 span 和业务 span 串成一棵树。
  5. 05-eval-guardrail-platform.md — 评测与护栏。从「看得见」升级到「评得了、拦得住」:evaluator / guardrail / datasets / experiment。

只想快速上手:读完本页 + 01 即可跑起来。想深挖原理或排查 span 不对:加读 02 + 03。做 agent / 想自定义业务 trace:直奔 04。关注质量与安全闭环:看 05