跳到主要内容
版本:Dev

OTLP 链路参考

AISIX 将请求遥测导出为相互关联的 OTLP 跨度。该层级保留入站请求、逻辑上游操作和各次尝试,使运维人员能够排查重试、故障转移、服务提供方延迟和采集内容,而不会把一次请求重复计数。

请在可观测性导出器中配置目标、采样率和内容模式。本参考介绍到达 OTLP 目标的链路与属性。

了解 OTLP 链路结构​

对于每个产生 OTLP 遥测数据的请求,AISIX 会导出一个链路层级,而不是为每个用量事件导出彼此无关的跨度。模型请求到达上游时,层级如下:

跨度OTLP 类型范围
入站请求SERVER覆盖请求从到达开始,直到响应完成或调用方断开连接。有效的入站 traceparent 会成为此跨度的远程父级。
逻辑操作CLIENT覆盖网关执行的上游操作,包括所有重试和故障转移尝试。它是 SERVER 跨度的子级。
上游尝试CLIENT表示一次服务提供方分发。每次尝试都是逻辑操作的子级,并携带 aisix.attempt_index。

因此,重试和故障转移会显示为同一逻辑操作下的同级尝试跨度。对于每个用量事件,AISIX 会把完整属性和捕获内容放在当前最具体的跨度上:优先放在尝试跨度,其次放在逻辑操作跨度,最后放在 SERVER 跨度。其他跨度仅携带关联该层级所需的字段,不会重复整个事件。

并非每个请求都包含所有三个层级:

  • 缓存命中、输入安全护栏阻断或其他分发前结果只有 SERVER 跨度,因为 AISIX 没有调用上游。
  • 不采用逐次尝试追踪的 MCP、A2A、Realtime、任务和透传调用包含 SERVER 跨度,以及一个表示上游操作的 CLIENT 跨度。

统计导出链路时,请根据跨度类型和父子关系,而不要只根据跨度名称。筛选 SERVER 跨度可以统计已采样的请求链路。sample_rate 小于 1 时,未被选中的请求不会出现。部分身份认证和格式错误输入路径会在用量事件或 OTLP 跨度产生前拒绝请求,因此 SERVER 跨度不能完整表示入站请求数。网关请求量请使用请求指标。分析单次模型尝试时,请使用携带 aisix.attempt_index 的 CLIENT 跨度。

延续入站 W3C 链路​

请求中恰好包含一个有效的 traceparent 时,AISIX 会延续该链路,并让自己的 SERVER 跨度成为调用方跨度的子级。取值格式错误或存在多个 traceparent 时,AISIX 会忽略它们并启动本地链路,而不会拒绝请求。通过网关字符和长度检查的配套 tracestate 会记录在 SERVER 跨度上。

除非 forward_client_headers 精确点名,否则 AISIX 不会把调用方的 traceparent 或 tracestate 转发给模型服务提供方、透传目标、MCP 服务器或 A2A Agent;通配符模式永远不会匹配到它们。默认情况下,该上下文只用于建立调用方到网关的关系。转发边界参见上游请求头。

OTLP 跨度属性参考​

OTLP 跨度遵循 OpenTelemetry 生成式 AI 与 HTTP 语义约定(semantic-conventions v1.41.1 发布版本)。约定未定义的属性使用 aisix. 前缀。

相对 1.6.0 及更早版本的变更

针对 1.6.0 及更早版本网关编写的链路查询、看板和告警需要更新。除请求头采集外,导出器配置无需改动。

  • 移除 gen_ai.system,请改用 gen_ai.provider.name。
  • OTLP 跨度不再携带 gen_ai.prompt 和 gen_ai.completion。采集的内容改用采集内容中的属性。Datadog 和阿里云 SLS 导出器的内容字段也做了同样的变更,详见 Datadog 和 SLS 记录中的采集内容。
  • gen_ai.request.model 是发送给上游的模型名称。调用方请求的别名或模型组名称改由 aisix.requested_model 携带。
  • gen_ai.usage.input_tokens 包含缓存的输入 Token。对于以 Anthropic 形态上报的用量(缓存读取和缓存写入与输入 Token 分开计数),该值现在会把两者加到输入 Token 上。Datadog 导出器的 gen_ai.usage.input_tokens 同样变化。详见导出遥测中的 Token 计数。
  • 跨度名称变化:不再使用 chat.completions;SERVER 跨度以 HTTP 路由命名,例如 POST /v1/chat/completions;MCP 跨度命名为 tools/call <tool>,而不是 execute_tool <tool>。
  • 成功的跨度不再设置 OK 状态,而是保持未设置。4xx 响应不再把 SERVER 跨度标记为错误。
  • aisix.client_source_ip 和 aisix.client_user_agent 更名为 client.address 和 user_agent.original。它们以及 http.request.header.<name> 属性从操作跨度移到 SERVER 跨度。
  • SERVER 跨度和聚合各次尝试的逻辑跨度不再携带 gen_ai.* 属性,只有生成式 AI 操作跨度携带,因此把生成式 AI 跨度转换为模型调用的后端对每次调用只计一次。
  • 资源属性 service.name 取网关的 observability.service_name(默认为 aisix),而不再是固定值 aisix-dp。
  • 要记录的请求头改由每个导出器的 request_headers 选择,不再由网关的 observability.usage_event.request_headers 决定。参见导出遥测中的请求头与响应头。

跨度名称与状态​

链路层级中的每个跨度各有一个角色。生成式 AI 操作跨度是当前最具体的跨度:优先是尝试跨度,其次是逻辑跨度,最后是 SERVER 跨度。

跨度名称错误状态
SERVER{method} {route},例如 POST /v1/chat/completions。只有当请求路径本身就是网关的固定路由时才附加路由,因此透传路径或 /v1/videos/{id} 只以方法命名。非标准方法以 HTTP 代替方法名。仅 5xx 状态为 ERROR。4xx 或 499 保持状态未设置。
生成式 AI 操作{gen_ai.operation.name} {gen_ai.request.model},例如 chat gpt-4o。MCP 跨度为 tools/call {tool},A2A 跨度为 invoke_agent {agent},透传跨度为 passthrough {route}。目标为空或超过 64 字节,或请求由通配符模型处理时(该模型名由调用方选定),名称只包含操作名。状态码大于等于 400 时为 ERROR,499 除外,因为关闭请求的调用方是主动取消。
聚合各次尝试的逻辑跨度与生成式 AI 操作跨度相同。与生成式 AI 操作跨度相同。

状态为 ERROR 的跨度还携带 error.type,取值为网关的错误类别(aisix.error_class),没有时为状态码。成功的跨度保持状态未设置。

SERVER 跨度的类型为 SERVER,逻辑跨度和尝试跨度的类型为 CLIENT。只有 SERVER 跨度的请求(例如缓存命中)以该 SERVER 跨度作为生成式 AI 操作跨度。

生成式 AI 操作跨度属性​

生成式 AI 操作跨度携带用量事件:

属性取值
gen_ai.operation.name/v1/chat/completions、/v1/messages 和 /v1/responses 为 chat;/v1/completions 为 text_completion;/v1/embeddings 为 embeddings;A2A 为 invoke_agent;MCP 为 execute_tool。其他请求类型报告其 aisix.operation 值,例如 passthrough。
aisix.operation网关自己的请求类型,可区分 chat、messages 和 responses。
gen_ai.provider.name实际分发的上游服务提供方。使用 Amazon Bedrock、Google Vertex AI 或 Azure OpenAI 适配器的服务提供方 Key 分别报告 aws.bedrock、gcp.vertex_ai 或 azure.ai.openai。其他服务提供方 Key 对相应服务提供方报告 openai、anthropic、gcp.gemini、deepseek、x_ai、mistral_ai、groq、cohere、perplexity 或 ibm.watsonx.ai,其余服务提供方原样报告其小写 ID。透传跨度报告路由所用服务提供方 Key 的服务提供方,A2A 跨度报告 a2a。MCP 跨度不携带该属性。
gen_ai.request.model发送给上游的模型名称。对通配符模型,是代入模型模板后的具体名称。
aisix.requested_model调用方请求的模型别名或模型组名称。
aisix.requested_model_idaisix.requested_model 所指模型的 ID。该名称未解析到已配置的模型时不携带。参见按请求模型 ID 关联。
server.address 和 server.port请求所发往的基础 URL 的主机和端口。Amazon Bedrock、Google Vertex AI 和 Azure OpenAI 服务提供方 Key 仅在设置了 api_base 时报告。透传跨度报告路由 target_url 的主机,preserve_host 路由不报告。MCP 和 A2A 跨度报告 MCP 服务器或 Agent 的 URL。未到达上游的请求(例如缓存命中或拒绝)不报告。
gen_ai.response.model服务提供方上报的具体模型版本。
gen_ai.response.id服务提供方的响应 ID。
gen_ai.response.finish_reasons只含结束原因一个元素的数组。
aisix.service_tier上游报告其实际处理该次尝试时所用的服务档位,原样记录。上游未报告时省略。参见读取实际服务档位。
gen_ai.response.time_to_first_chunk流式响应中,从本次尝试分发到收到第一个上游帧的秒数。
http.response.status_code用量事件记录的状态。
error.type失败时设置,见上文。
http.response.header.<name>导出器 upstream_response_headers 中列出的上游响应头,取自本次尝试的上游响应。参见导出遥测中的请求头与响应头。

当网关无法确定上游时(例如在选出路由目标之前就失败的请求),不携带 gen_ai.provider.name、gen_ai.request.model 和 server.*。

还会附加各协议专属的属性:

  • MCP:值为 tools/call 的 mcp.method.name、gen_ai.tool.name 和 aisix.mcp.server_name。
  • A2A:gen_ai.agent.name、gen_ai.conversation.id(即 A2A 的上下文),以及 aisix.a2a.operation、aisix.a2a.method、aisix.a2a.protocol_version、aisix.a2a.task_id、aisix.a2a.task_state 和 aisix.a2a.stream_event_count。
  • 透传路由:aisix.passthrough.route_name;当路由的 identity_header 提取到最终用户身份时,还携带 aisix.client_identity。

该跨度还会保留网关自己的关联和归因属性(有值时):aisix.request_id、aisix.exporter_name、aisix.api_key_id、aisix.api_key_name、aisix.user_id、aisix.model_id、aisix.attempt_index、aisix.attempt_kind、aisix.attempt_model、aisix.error_class、aisix.error_message、aisix.upstream_ttft_ms、aisix.downstream_latency_ms、aisix.gateway_overhead_ms、aisix.upstream_tpot_ms、aisix.audio.duration_seconds、aisix.gateway_embedding_calls、aisix.gateway_embedding_calls_dropped、aisix.jwt_subject、aisix.jwt_provider 和 aisix.jwt_claim_mapping。

网关协议跨度​

A2A 或 MCP 调用不是模型推理,因此不会被编码成模型推理。按照 OpenTelemetry 生成式 AI 语义约定,每种协议有自己的跨度名称和操作名,并携带生成式 AI 操作跨度属性中列出的协议细节:

  • A2A 导出为 invoke_agent <agent>,gen_ai.operation.name 为 invoke_agent。
  • MCP 导出为 tools/call <tool>,gen_ai.operation.name 为 execute_tool,mcp.method.name 为 tools/call。1.6.0 及更早版本的网关将其命名为 execute_tool <tool>。
  • 透传路由导出为 passthrough <route>,gen_ai.operation.name 为 passthrough。

模型流量以操作名和上游模型命名,例如 chat gpt-4o,因此按 gen_ai.operation.name: chat 编写的链路查询只匹配模型流量。1.6.0 及更早版本的网关把所有模型跨度命名为 chat.completions。

请求参数​

在 /v1/chat/completions、/v1/messages、/v1/responses 和 /v1/completions 上,生成式 AI 操作跨度会记录调用方发送的参数,按请求自身的协议从请求体读取。同一请求的每次尝试都携带相同的值。

属性来源
gen_ai.request.max_tokensmax_completion_tokens 或 max_tokens;/v1/responses 上为 max_output_tokens。
gen_ai.request.temperature 和 gen_ai.request.top_ptemperature 和 top_p。
gen_ai.request.top_k聊天补全和 messages 上的 top_k。
gen_ai.request.stop_sequences聊天补全和 completions 上的 stop,或 messages 上的 stop_sequences。
gen_ai.request.frequency_penalty、gen_ai.request.presence_penalty 和 gen_ai.request.seed聊天补全和 completions 上的同名字段。
gen_ai.request.choice.count聊天补全和 completions 上的 n,仅在不为 1 时记录。
gen_ai.request.streamtrue,仅在请求为流式时记录。
gen_ai.output.typejson_object 或 json_schema 格式为 json,text 格式为 text,取自聊天补全的 response_format.type 或 responses 的 text.format.type。请求未指定格式时不记录。
openai.request.service_tierservice_tier(auto 除外),仅在 gen_ai.provider.name 为 openai 的跨度上记录。这是请求所要求的档位;上游实际处理请求的档位可能不同,记录在 aisix.service_tier 中。

在 /v1/embeddings 上,跨度从 encoding_format 记录 gen_ai.request.encoding_formats,从 dimensions 记录 gen_ai.embeddings.dimension.count。

Token 用量属性​

除 MCP 外,每个生成式 AI 操作跨度都携带用量:

属性取值
gen_ai.usage.input_tokens全部输入 Token,包括缓存部分:提示词 Token 加上上游在其之外单独上报的缓存创建和缓存读取 Token。始终存在。
gen_ai.usage.cache_read.input_tokens由服务提供方提示词缓存提供的输入 Token,两种计量形态均适用。大于零时存在。
gen_ai.usage.cache_creation.input_tokens写入服务提供方提示词缓存的输入 Token:Anthropic 的缓存创建计数,或 OpenAI 形态的 cache_write_tokens。缓存创建计数大于零或上游上报了 cache_write_tokens 时存在。
aisix.cache_creation_5m_tokens 和 aisix.cache_creation_1h_tokens上游报告了拆分时,缓存创建计数中以 5 分钟和 1 小时有效期写入的部分。二者同时出现或都不出现,参见按有效期拆分的缓存创建。
gen_ai.usage.output_tokens输出 Token,包含推理。向量嵌入跨度不携带。
gen_ai.usage.reasoning.output_tokens推理 Token。大于零时存在。
gen_ai.usage.audio.input_tokens 和 gen_ai.usage.image.input_tokens上游上报的音频和图像输入 Token。仅在上游上报了该计数时存在。
gen_ai.usage.audio.output_tokens 和 gen_ai.usage.image.output_tokens上游上报的音频和图像输出 Token。仅在上游上报了该计数时存在。向量嵌入跨度不携带。

这些值与记录的用量事件之间的关系,参见导出遥测中的 Token 计数;哪些上游会上报音频和图像计数,参见音频与图像 Token。

采集内容​

设置 content_mode: full 时,生成式 AI 操作跨度携带采集到的内容。对于 /v1/chat/completions、/v1/messages、/v1/responses 和 /v1/completions,一次消息交换会转换为约定定义的结构化属性,每个属性都是符合约定消息结构的 JSON 字符串:

  • gen_ai.input.messages 携带请求消息。completions 的提示词仅在为单个字符串时转换。
  • gen_ai.system_instructions 携带 Anthropic 的 system 字段或 Responses 的 instructions 字段。聊天补全中的 system 消息仍保留在 gen_ai.input.messages 中。
  • gen_ai.tool.definitions 携带每个已声明工具的 type、name、description 和 parameters。Anthropic 工具的 input_schema 作为 parameters 报告。
  • gen_ai.output.messages 携带一条 assistant 消息,其 parts 按调用方收到的顺序排列,并带有 finish_reason。

在 /v1/chat/completions、/v1/messages 和 /v1/responses 上,无论流式还是非流式,输出消息都包含三种 part 类型:

Part type字段采集来源
textcontent聊天补全的 content、Anthropic 的 text 块,以及 Responses message 中的输出文本。
reasoningcontent聊天补全的 reasoning_content 或 reasoning,或者 Mistral thinking 与 Databricks reasoning 内容部件、Anthropic 的 thinking 块,以及 Responses reasoning 条目中可读的摘要和文本。
tool_callid、name 和 arguments聊天补全的 tool_calls、Anthropic 的 tool_use 块,以及 Responses 的 function_call 条目。arguments 能解析为 JSON 时为解析后的值,否则为原始字符串。

这些 part 取自调用方实际收到的响应,因此会体现输出数据脱敏,原生处理的请求与从其他协议转换的请求也按同样方式采集。Responses 的 encrypted_content 永远不会导出。约定中没有精确对应 part 类型的输出不会写入该消息:Anthropic 的 redacted_thinking 块和服务端工具块、聊天补全的 refusal 和 audio,以及 Responses 的 refusal 内容和 function_call 以外的工具调用条目。在 /v1/completions 上,该消息以一个 text part 携带响应文本。

无论由哪种协议上报,输出消息的 finish_reason 都使用约定定义的取值:

finish_reason原始取值
tool_calltool_calls、tool_call、function_call 和 tool_use。
lengthlength、max_tokens、max_output_tokens 和 model_context_window_exceeded。
content_filtercontent_filter、content_filtered、refusal 和 guardrail_intervened,以及 Gemini 的 SAFETY、RECITATION、BLOCKLIST、PROHIBITED_CONTENT、SPII、IMAGE_SAFETY 和 LANGUAGE。
errorerror,以及 Gemini 的 MALFORMED_FUNCTION_CALL、UNEXPECTED_TOOL_CALL 和 TOO_MANY_TOOL_CALLS。
stop其他所有取值,包括 stop、end_turn、stop_sequence 和 STOP。

原始取值按不区分大小写匹配。gen_ai.response.finish_reasons 保留服务提供方上报的原始值。输出消息必须带有结束原因,因此事件没有结束原因时不携带输出消息,例如失败或被取消的 /v1/responses 请求。参见 Responses 结束原因。

MCP 工具调用使用 gen_ai.tool.call.arguments,调用成功时还使用 gen_ai.tool.call.result。

每个结构化属性都受导出器 content_max_bytes 的限制,提示词侧和响应侧分别判断。不属于消息交换的内容(例如向量嵌入输入、图片、音频、任务和 Agent 文本)以原始形式保留在 aisix.content.prompt 和 aisix.content.response 中。被采集截断、无法转换或转换后会超过上限的一侧同样如此,因此 gen_ai.* 内容属性永远不会是残缺的。aisix.content_truncated: true 标记内容被截断的记录。采集到的输出 part 超过 content_max_bytes 时,输出消息回落为以一个 text part 携带响应文本;如果该文本也被截断,则以原始形式保留在 aisix.content.response 中。

Datadog 和阿里云 SLS 导出器对同一事件携带相同的结构化内容,只是字段名各不相同。详见 Datadog 和 SLS 记录中的采集内容。

SERVER 跨度属性​

SERVER 跨度描述入站 HTTP 请求:

属性取值
http.request.method请求方法。非标准方法报告 _OTHER,方法本身记录在 http.request.method_original 中。
url.path请求路径,最多 512 字节。
url.schemeTLS 监听器上为 https,否则为 http。
http.route路由,仅当路径本身就是网关的固定路由时记录。
url.query请求带有查询字符串时记录,最多 1,024 字节。
http.response.status_code最终响应状态。
client.address解析出的调用方地址。
user_agent.original调用方的 User-Agent。
http.request.header.<name>导出器 request_headers 中列出的请求头。参见导出遥测中的请求头与响应头。
aisix.request_id、aisix.exporter_name 和 aisix.operation关联同一请求各跨度的键。

url.query 会把敏感参数的值替换为 REDACTED。参数名 AWSAccessKeyId、Signature、sig 和 X-Goog-Signature 区分大小写匹配,key、access_token、token、client_secret、password、api_key 和 apikey 不区分大小写匹配,参数名先做百分号解码再比较。其他值原样导出,因此如果 OTLP 目标不应收到其他密钥,就不要通过查询字符串把它们发送给网关。

聚合各次尝试的逻辑跨度只携带 aisix.request_id、aisix.exporter_name 和 aisix.operation。

资源属性​

每个导出请求都携带以下资源属性:

  • service.name:网关启动配置中的 observability.service_name,默认为 aisix。1.6.0 及更早版本的网关始终报告 aisix-dp。
  • service.version:网关的构建版本。

插桩范围为 aisix-obs.otlp_http_sink,版本为网关的构建版本。

网关不保留相应数据的属性不会导出,包括 openai.response.system_fingerprint、gen_ai.agent.id、mcp.session.id 和 jsonrpc.request.id。上游实际处理请求的服务档位以 aisix.service_tier 导出,而不是 openai.response.service_tier。

下一步​

请在可观测性导出器中配置采样、内容采集或其他目标。使用指标和用量事件对照跨度、网关指标和已存储的用量记录。