B2BB2B LLM
商业洞察

如何使用 OpenTelemetry 构建提供商中立的 LLM 可观察性

在多模型 API 网关层检测 LLM 可观测性的实用实施指南,包括跨度设计、GenAI 属性、隐私控制、尾部采样、仪表板和合约测试。

当每个申请团队都以自己的格式记录提供商响应时,LLM 可观察性就会崩溃。在事件期间,平台团队需要回答具体问题:哪个团队发出了请求、使用了哪个 API 键范围、请求了哪个模型、哪个提供者实际提供了服务、是否发生重试或回退、消耗了多少令牌、哪个延迟存储桶发生了变化以及导致失败的错误类别。他们还需要这些答案,而无需将原始提示、补全、提供商密钥或客户标识符复制到通用日志存储中。

实际的答案是将多模型 API 网关作为可观察性控制点。应用程序级跟踪仍然很重要,但网关是在遥测到达下游工具之前可以规范化提供商选择、重试、回退、使用情况统计、请求所有权和隐私执行的地方。对于运营企业 LLM API 的团队来说,这成为分散的调试数据和提供商中立的运营模型之间的区别。

首先定义可观察性合同

从书面属性合同开始,而不是仪表板屏幕截图。合约应定义每个 LLM 请求必须发出的最少元数据、哪些字段允许离开网关、哪些字段受到限制以及哪些字段永远不会导出。

有用的基准合约包括所有权、路由、模型、使用情况、延迟和结果元数据。所有权属性标识组织、团队、环境、工作负载、应用程序和 API 键范围。路由属性标识网关路由、策略版本、请求的提供程序、请求的模型、选定的提供程序、选定的模型、重试计数、回退计数以及是否使用流式传输。使用属性捕获输入令牌、输出令牌、缓存的输入令牌、可用的推理令牌、请求计数和估计成本类别。结果属性捕获状态、安全时的提供商错误代码、规范化错误类、验证结果、超时状态和最终响应模型。

保持合同提供商中立。特定于提供程序的错误(例如速率限制响应、过载模型响应、架构验证失败、安全拒绝、超时或上下文窗口错误)应映射到仪表板可以跨提供程序进行分组的规范化错误类。原始提供商错误代码可能有用,但应将其视为受限诊断数据,而不是主要仪表板维度。

使用以网关为中心的跨度模型

清晰的跟踪结构可防止 LLM 遥测变成一堆扁平的跨度。使用一个入站应用程序请求范围、一个逻辑 LLM 操作范围和用于网关执行工作的子范围。

典型的层次结构如下所示:

inbound.http_request
  llm.operation
    llm.provider_attempt
    llm.provider_attempt.retry
    llm.provider_attempt.fallback
    retrieval.query
    tool.call
    output.validation

入站请求范围代表调用者对网关的请求。逻辑 LLM 操作范围代表用户可见的 LLM 任务,即使网关进行多次提供商尝试也是如此。提供程序尝试跨度捕获对上游模型 API 的每个实际调用。当检索、工具和验证范围是生成最终响应的一部分时,它们应该是逻辑操作的子项。

这种分离在事件发生期间很重要。如果请求从一个模型回退到另一个模型,则逻辑操作可能会成功,而第一个提供程序尝试会失败。如果最终输出未通过架构验证,则提供程序尝试可能在技术上成功,但逻辑操作失败。如果没有单独的跨度,仪表板要么将提供程序故障隐藏在成功的最终用户响应后面,要么夸大已成功恢复的故障。

在内部映射器后面映射 OpenTelemetry GenAI 属性

存在 OpenTelemetry 语义约定,因此遥测生产者可以跨代码库、库和平台使用通用名称和属性。OpenTelemetry 项目现在将生成式 AI 约定指向单独的 GenAI 存储库,这些约定定义模型请求和响应属性,例如提供程序名称、请求的模型、响应模型、输入令牌、输出令牌、推理令牌和缓存的输入令牌。

在合适的地方使用这些 GenAI 属性,但不要将原始属性名称分散在整个网关代码中。将它们包裹在小型遥测映射器后面。该映射器应接受内部请求记录并生成标准化跨度属性。

record LlmTelemetryContext {
  organization_id
  team_id
  environment
  api_key_scope
  route_name
  route_policy_version
  workload_class
  provider_requested
  model_requested
  provider_selected
  model_response
  input_tokens
  output_tokens
  cached_input_tokens
  reasoning_tokens
  retry_count
  fallback_count
  normalized_error_class
}

映射器可以为标准字段发出 OpenTelemetry GenAI 属性,并为业务上下文发出私有网关属性。将私有属性保留在受控命名空间下,例如 llm_gateway.organization_id、llm_gateway.team_id、llm_gateway.key_scope、llm_gateway.route_policy 和 llm_gateway.workload_class。

此设计为您提供供应商中立的遥测,同时保护代码库免遭改动。 GenAI 约定仍在不断发展,因此映射器可以更改名称,而无需编辑每个处理程序、重试模块、流式传输适配器和验证组件。

将元数据与敏感内容分离

LLM 跟踪异常敏感,因为最有用的调试数据可能是不应该广泛保留的相同数据:提示、检索到的文档、工具参数、完成信息、用户标识符、客户标识符和原始提供商凭据。默认状态应该是元数据优先的可观察性。

建议的默认字段包括提示哈希、提示模板 ID、提示版本、架构 ID、工具名称、检索集合、路由名称、令牌计数、延迟、标准化错误类别和验证状态。这些字段无需导出原始内容即可回答许多操作问题。

原始提示和完成捕获应在导出前选择加入、有时间限制、访问控制并经过编辑。不要将其作为便利功能全局启用。当生产事件需要捕获内容时,请将调试标志附加到一小部分请求,将这些跟踪路由到受限制的后端,并设置较短的保留窗口。

哈希标识符不会自动匿名。如果输入空间较小或可预测,则可以通过猜测来反转哈希值。对于敏感的客户或用户标识符,请考虑删除、代理 ID、分桶、截断或具有严格密钥控制的密钥散列。使用哈希主要是为了在了解风险时保持稳定的关联性,而不是作为一揽子隐私解决方案。

在收集器中实施隐私

OpenTelemetry 指南指出应在导出之前处理敏感数据。收集器可以使用属性、过滤器、编辑和转换等处理器来删除、散列、过滤、编辑或转换遥测属性。这使得收集器成为继网关检测本身之后的第二道防线。

实用的收集器管道应使用低风险属性的允许列表、默认删除原始提示和响应字段、匹配阻止模式的掩码值,并在显式启用内容捕获时单独路由较高敏感度的跟踪。 OpenTelemetry Collector 属性处理器支持删除和散列等操作。密文处理器旨在删除不在许可名单上的属性以及与阻止的模式匹配的掩码值。

例如,网关可以默认避免发出原始内容,而收集器仍会删除 llm.prompt.raw、llm.completion.raw、provider.api_key、authorization 和 cookie 等属性(如果这些属性因错误或库集成而出现)。将此视为深度防御控制,而不是随意发出不安全数据的原因。

分别进行仪器重试、回退和验证

重试和回退通常在聚合 API 指标中不可见。这种不可见性会导致两个操作问题。首先,延迟可能会降低,因为成功的响应可能会隐藏多次失败的尝试。其次,成本可能会上升,因为单个用户请求可能会创建多个上游模型调用。

每个提供程序尝试范围应包括尝试次数、重试原因、所选提供程序、所选模型、超时预算、延迟、可用令牌使用情况以及结果。如果发生回退,回退范围应标识原始路由策略、回退原因以及最终响应实际使用的模型。

结构化输出验证应是其自己的范围或事件。捕获架构 ID、架构版本、验证结果、修复尝试计数和最终状态。默认情况下不存储完整的无效输出。验证失败在操作上与提供商传输错误不同,仪表板不应将它们混淆在一起。

围绕问题而不是提供商构建仪表板

提供商中立的可观察性应直接回答操作问题。有用的仪表板包括按模型、提供商、团队、环境和工作负载类别划分的 p95 和 p99 延迟;按团队和路线划分的代币使用情况;按标准化错误类别划分的故障率;通过路由策略进行重试放大;按请求模型确定的回退频率;提示模板的上下文窗口错误;按模式划分的结构化输出验证失败;并对失败、昂贵或缓慢的请求进行采样跟踪示例。

不要在采样跟踪中包含计费和总使用情况报告。尾部采样对于调试很有用,但它可能会扭曲总数。令牌总数、请求计数和成本分类账应来自未抽样的计数器、请求分类账或计费对账系统。跟踪应该解释为什么发生昂贵或缓慢的请求;它们不应该是财务真相的唯一来源。

使用尾部采样进行高价值跟踪

OpenTelemetry Collector 尾部采样处理器可以在跨度完成后做出采样决策,包括基于属性和数值的策略。这对于 LLM 流量很有用,因为您通常只有在响应完成后才知道跟踪是否有价值。

保留提供程序错误、验证失败、非常高的延迟、异常昂贵的令牌使用、上下文窗口故障、回退尝试和手动调试标记请求的跟踪。以较低的速率对例行成功流量进行采样。这样可以保留最有可能解释事件的跟踪,同时控制存储量。

合理的策略模型很简单:始终保留错误、始终将请求保持在延迟或令牌阈值之上、始终保留带有调试标记的跟踪,并对普通成功请求进行概率采样。随着流量变化重新访问阈值。一旦生产流量增长,在早期采用期间有用的阈值可能会太低。

为遥测添加合约测试

遥测应像 API 合约一样进行测试,因为下游仪表板、警报、成本控制和事件工作流程都依赖于它。添加运行代表性网关请求的测试,并断言已发出所需的范围和属性。

测试应验证成功的请求是否发出逻辑 LLM 操作范围、提供程序尝试范围、请求的模型、响应模型、提供程序名称、可用的令牌计数、团队或关键范围元数据、路由策略版本和最终状态。重试测试应断言尝试计数和重试原因。回退测试应该断言失败的尝试和最终成功的提供者尝试。验证测试应断言架构 ID、验证状态和修复尝试计数。

安全测试同样重要。断言导出的遥测数据中不存在原始提供商密钥、授权标头、cookie、原始提示、原始完成和未经批准的客户标识符。当开发人员添加新的 Span 属性而不对其进行分类时,这些测试应该会失败。

实施清单

  • 属性协定: 定义必需、可选、受限和禁止的属性。
  • Span 层次结构:单独的入站请求、逻辑 LLM 操作、提供程序尝试、重试、回退、检索调用、工具调用和验证。
  • 语义映射: 使用合适的 OpenTelemetry GenAI 属性以及所有权和路由上下文的私有网关属性。
  • 隐私政策: 默认使用哈希值、模板 ID、架构 ID、工具名称、令牌计数、延迟和错误类,而不是原始值内容。
  • 收集器处理器:删除禁止字段、编辑被阻止的模式、将低风险属性列入白名单,并单独路由敏感跟踪。
  • 采样策略:对高价值跟踪进行尾部采样并保持聚合指标不采样。
  • 仪表板:构建视图有关延迟、使用情况、故障、重试、回退、验证和成本驱动因素的信息。
  • 警报:有关规范化错误类、p99 延迟变化、重试放大、回退尖峰、验证失败和令牌异常的警报。
  • 合同测试:断言存在所需的遥测且存在敏感遥测不存在。

明确决策的权衡

网关级检测可以快速提供一致的元数据,但可能会错过特定于应用程序的上下文,除非团队传递结构化请求元数据(例如租户、工作流程、提示模板和功能名称)。将该元数据作为网关请求合同的一部分,而不是依赖自由格式的日志。

完整内容捕获可以改进调试和评估,但会增加隐私、安全、保留和访问控制负担。许多团队应该只从哈希值、模板 ID、架构 ID 和经过编辑的摘录开始。

与提供商无关的错误类使仪表板可跨多个模型 API 使用,但它们会压缩特定于提供商的详细信息。仅在安全时保留原始提供程序错误代码,并限制对它们的访问。

OpenTelemetry GenAI 约定减少了锁定,但约定将继续发展。内部映射器为您提供标准化的好处,而不会让不稳定的属性名称通过代码库泄漏。

结论

提供者中立的 LLM 可观察性不仅仅是跟踪添加到模型调用中的。它是网关层的操作合约:一致的跨度、规范化模型和提供程序元数据、所有权上下文、令牌使用、重试和回退可见性、隐私控制、采样规则以及防止敏感数据泄漏的测试。

从网关开始,因为它已经看到了最重要的决策:谁发出了请求、哪个策略路由了该请求、哪个提供程序提供了服务、令牌成本是多少、花费了多长时间、恢复逻辑是否运行以及失败的情况。一旦基础稳定,应用团队就可以添加更丰富的工作流上下文,而无需每个团队发明自己的 LLM 可观测系统。

相关阅读

FAQ

常见问题

LLM 可观察性应该从应用程序代码开始还是从 API 网关开始?
从共享合约的网关开始:提供者、模型、路由策略、密钥范围、令牌使用、重试、回退、延迟和标准化错误。然后,应用程序团队可以添加特定于工作流的上下文,例如功能名称、租户、提示模板或业务流程。
提示和完成是否应该存储在跟踪中?
默认情况下不是。首先存储提示哈希、模板 ID、模式 ID、工具名称、令牌计数、延迟和错误类。原始内容捕获应该是选择加入、有时间限制的、访问控制的,并且在导出之前进行编辑。
抽样跟踪可以用于 LLM 成本报告吗?
采样跟踪对于调试昂贵或失败的请求很有用,但它们不应该是总数的唯一来源。令牌使用和计费指标应来自未采样的计数器、请求分类账或提供商计费对账。
为什么使用 OpenTelemetry GenAI 语义约定?
它们为模型请求和响应提供通用属性名称,包括提供者、请求的模型、响应模型和令牌计数。通过内部映射器使用它们,因此约定更改不需要跨整个网关进行编辑。