☰
OpenTelemetry Instrumentation for VoyageAI:为 Embedding 与 Rerank 调用接入可观测性
2026/10/15 15:18:49 网站建设 项目流程
  • LLMOps
  • 可观测性

【免费下载链接】openllmetry

Open-source observability for your GenAI or LLM application, based on OpenTelemetry

项目地址:https://gitcode.com/gh_mirrors/op/openllmetry
点击查看免费下载

这篇技术指南以 openllmetry 仓库中的 opentelemetry-instrumentation-voyageai 文档为主体,讲解如何通过 OpenTelemetry 对 Voyage AI 的 Embedding(文本向量化)与 Rerank(重排序)API 调用进行自动埋点追踪。读完本文,你将掌握该插件的安装方式、VoyageAIInstrumentor的启用方法、底层埋点机制与完整的 GenAI 语义约定(Semantic Conventions)属性清单,并学会结合源码与测试用例排查、验证追踪数据。

一、插件概览:为 Voyage AI 客户端自动生成 Span

opentelemetry-instrumentation-voyageai是一个基于 OpenTelemetry 的自动埋点库,用于追踪 Voyage AI Python 客户端发出的 Embedding 与 Rerank 请求。启用后,无需修改任何业务代码,插件会通过wrapt的wrap_function_wrapper包装客户端方法,在每次 API 调用前后自动创建、填充并结束 Span,从而将模型名、Token 用量、嵌入向量维度、输入文本等关键信息记录到链路中。

从 入口模块 的源码可见,插件包装的调用点共有四个:

客户端对象方法Span 名称gen_ai.operation.name
voyageai.Clientembedvoyageai.embedembeddings
voyageai.Clientrerankvoyageai.rerankrerank
voyageai.AsyncClientembedvoyageai.embedembeddings
voyageai.AsyncClientrerankvoyageai.rerankrerank

同步与异步客户端被同等对待,Span 的kind统一为SpanKind.CLIENT,gen_ai.system固定为"voyageai"。

二、安装与启用

1. 安装

pip install opentelemetry-instrumentation-voyageai

该插件的运行环境要求(来自 pyproject.toml):

  • Python>=3.10,<4
  • opentelemetry-api>=1.38.0,<2
  • opentelemetry-instrumentation>=0.59b0
  • opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0
  • 目标库voyageai>=0.3.0(见源码中的_instruments声明)

插件同时注册了opentelemetry_instrumentor入口点(指向VoyageAIInstrumentor),因此在配置好 OpenTelemetry 环境后,也可以借助opentelemetry-instrument命令行工具自动启用。

2. 初始化仪表化

from opentelemetry.instrumentation.voyageai import VoyageAIInstrumentor VoyageAIInstrumentor().instrument()

instrument()默认使用全局TracerProvider。若应用采用了自定义 Provider,可显式传入:

VoyageAIInstrumentor().instrument(tracer_provider=my_tracer_provider)

这与测试用例中的做法一致(见 conftest.py):测试通过VoyageAIInstrumentor().instrument(tracer_provider=tracer_provider)注入内存 Span Exporter 并断言输出。

三、快速上手:Embedding 与 Rerank 追踪

启用仪表化后,按常规方式使用 Voyage AI SDK 即可自动产生 Span。以下代码来自 README 原示例,补充了 API Key 与参数说明:

from opentelemetry.instrumentation.voyageai import VoyageAIInstrumentor VoyageAIInstrumentor().instrument() # 仪表化之后,正常使用 Voyage AI SDK 即可 import voyageai client = voyageai.Client(api_key="your-voyage-api-key") # Embeddings:文本向量化 result = client.embed(texts=["Hello, world!"], model="voyage-3") # Reranking:按相关性对文档重排序 result = client.rerank( query="What is the capital of France?", documents=["Paris is the capital of France.", "London is in England."], model="rerank-2.5", )

在启用后,每次embed/rerank调用都会生成一个 Span,采集请求模型、Token 用量等属性(详见下一节)。

仓库中的示例应用给出了更贴近生产的使用形态:在@workflow装饰的工作流中批量生成 Embedding、执行 Rerank,并打印向量维度与 Token 用量,可作为搭建完整可观测性链路的参考。

四、Semantic Conventions:完整属性清单与实现细节

插件遵循 OpenTelemetry GenAI 语义约定(opentelemetry-semantic-conventions-ai包,即 opentelemetry-semantic-conventions-ai 所定义的规范),以gen_ai.*前缀的属性记录调用信息。README 声明的基础属性如下:

属性含义取值/来源
gen_ai.systemAI 系统标识固定为"voyageai"
gen_ai.operation.name操作类型"embeddings"或"rerank"
gen_ai.request.model请求模型名来自kwargs.get("model")
gen_ai.usage.input_tokens输入 Token 数来自响应对象的total_tokens属性
gen_ai.embeddings.dimension.count嵌入向量维度(仅 embed)取响应中第一个向量的长度

除上述基础属性外,从 span_utils.py 的源码还可以确认两个由该插件扩展补充的属性:

  • gen_ai.request.top_k:仅 Rerank 请求,且仅在调用时显式传入了top_k才会写入(见 span_utils.py);
  • gen_ai.completion.{i}.role/gen_ai.completion.{i}.content:Rerank 响应中的每条结果,内容格式为Doc {index}, Score: {relevance_score}(若结果对象带document字段则追加原文)。

1. 请求属性如何写入

在 span_utils.py 中,set_span_request_attributes负责读取调用参数:

_set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_MODEL, kwargs.get("model")) if kwargs.get("top_k"): _set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_TOP_K, kwargs.get("top_k"))

_set_span_attribute会忽略None与空字符串,确保没有多余的空属性污染 Span。

2. 响应属性如何写入

set_span_response_attributes(span_utils.py)直接从响应对象读取数据:

  • total_tokens是 Voyage AI SDK 返回对象的直接属性,写入gen_ai.usage.input_tokens;
  • 对于 Embedding,取response.embeddings中第一个向量的长度作为gen_ai.embeddings.dimension.count。

之所以采用getattr(response, ...)的读取方式,是因为 Voyage AI 的响应是 Pydantic 模型对象而非字典,直接属性访问是最稳妥的取值路径。

五、输入与输出内容捕获:prompts 与 completions

当需要追溯"到底发送了什么文本、模型返回了什么"时,插件支持把输入输出内容记录到 Span 中。该能力受环境变量TRACELOOP_TRACE_CONTENT控制(默认"true"即开启),判断逻辑位于 utils.py:

def should_send_prompts(): return ( os.getenv(TRACELOOP_TRACE_CONTENT) or "true" ).lower() == "true" or context_api.get_value("override_enable_content_tracing")

若要关闭内容采集(例如出于隐私或成本考虑),可在启动应用前设置:

export TRACELOOP_TRACE_CONTENT=false

内容捕获遵循"以gen_ai.prompt.{i}.role/content记录输入、以gen_ai.completion.{i}.role/content记录输出"的约定(见 span_utils.py):

  • Embedding 输入:所有texts作为一条user消息,content为 JSON 数组[{"type": "text", "text": ...}, ...];
  • Rerank 输入:每个documents元素作为一条system消息(下标从 0 开始),query作为最后一条user消息;
  • Rerank 输出:每条结果写入gen_ai.completion.{i},role="assistant"。

需要说明的是,内容属性写入有前置条件:should_send_prompts()为真且未启用事件模式(should_emit_events(),即仍使用 legacy 属性时,详见下一节配置说明)。从源码结构看,这一设计是为了兼容旧版属性命名,同时为未来基于事件(Event)的日志模式预留切换空间。

六、可配置项:exception_logger 与 use_legacy_attributes

VoyageAIInstrumentor构造函数接受两个可选参数(见init.py 与 config.py):

参数默认值作用
exception_loggerNone自定义异常记录回调。埋点内部异常(如属性序列化失败)发生时会被调用,便于统一上报
use_legacy_attributesTrue是否使用 legacy 属性模式。为False时should_emit_events()返回True,内容捕获转而走事件路径(此时 prompt 内容不再写入 Span 属性)

示例:

VoyageAIInstrumentor( exception_logger=lambda e: print(f"tracing error: {e}"), use_legacy_attributes=False, ).instrument()

七、错误处理与抑制机制

1. 调用失败的 Span 状态

在 _wrap/_awrap 中,插件将业务调用包裹在try/except中:

  • 调用成功:写入响应属性、正常span.end();
  • 调用抛错:设置StatusCode.ERROR状态、调用span.record_exception(e)记录异常堆栈,span.end()后重新抛出异常——即追踪逻辑绝不吞掉业务异常,对应用行为零影响。

2. 双重抑制开关

如果上下文中存在 OpenTelemetry 的_SUPPRESS_INSTRUMENTATION_KEY或语义约定包提供的SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY,插件会直接跳过埋点、原样调用(见init.py)。这意味着你可以通过 Context 在局部关闭追踪,例如避免对内部重试或测试流量产生重复 Span。

3. 属性采集失败不影响主流程

所有属性填充函数都经过@dont_throw装饰(utils.py):即使响应对象结构异常导致属性提取失败,也只会记录 debug 日志(并调用exception_logger),而不会中断埋点或业务调用。

八、测试验证:如何确认追踪输出符合预期

该插件在 tests 目录下提供了基于pytest-recording(VCR)的用例,使用预录的cassettes(test_embed、test_rerank)离线重放 API 响应,无需真实调用 Voyage AI 即可验证:

  • test_embed.py:断言embedSpan 的名称、gen_ai.system、gen_ai.operation.name、模型名、prompt 内容 JSON 结构、Token 用量、向量维度,以及同步/异步(AsyncClient)两条路径;
  • test_rerank.py:断言rerankSpan 中 documents 以system角色、query 以user角色写入,以及每条结果以gen_ai.completion.{i}(assistant角色)记录Doc ... Score: ...格式的内容。

测试夹具 conftest.py 展示了标准的验证链路:InMemorySpanExporter→SimpleSpanProcessor→ 注入自定义TracerProvider→ 调用instrument(tracer_provider=...)→ 用span_exporter.get_finished_spans()断言。如果你要在自己的应用中做集成验证,完全可以复用这套模式:把 Exporter 换成 OTLP/Console Exporter,即可在 Jaeger、Tempo、Grafana Cloud 或 Traceloop 等后端中看到voyageai.embed/voyageai.rerank链路。

九、小结与延伸阅读

一句话总结:opentelemetry-instrumentation-voyageai用最小的侵入代价(一行instrument()),为 Voyage AI 的 Embedding 与 Rerank 调用补齐了标准化的 GenAI 可观测数据,覆盖模型、Token、向量维度、请求/响应内容与异常信息。

若需继续深入,可参阅仓库内相关资源:

  • 插件主文档:packages/opentelemetry-instrumentation-voyageai/README.md
  • 埋点实现:opentelemetry/instrumentation/voyageai/init.py
  • 属性填充与内容捕获:opentelemetry/instrumentation/voyageai/span_utils.py
  • GenAI 语义约定定义:opentelemetry-semantic-conventions-ai
  • 端到端示例:sample_app/voyageai_example.py
  • LLMOps
  • 可观测性

【免费下载链接】openllmetry

Open-source observability for your GenAI or LLM application, based on OpenTelemetry

项目地址:https://gitcode.com/gh_mirrors/op/openllmetry
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询