mcpField
O
observability-llm-obs

observability-llm-obs

github.com/elastic云与 DevOps6023.9k 次安装今天更新
代码仓库

关于 observability-llm-obs

用于分析已采集的 LLM 和 Agent 数据的 Elastic 可观测性技能。它帮助运维人员调查性能、Token 用量、已埋点的成本、响应质量及基于 Trace 的调用链,并先确认实际数据源与字段。

主要功能

  1. 01发现可用的 LLM 数据源
  2. 02识别部署中的实际字段名
  3. 03分析延迟、吞吐量和错误
  4. 04报告 Token 与已埋点成本
  5. 05检查质量信号和调用链

适用场景

  1. 01比较不同模型的 LLM 性能
  2. 02查看 Token 总量及可用成本数据
  3. 03调查故障和内容过滤事件
  4. 04定位 Trace 工作流中的瓶颈

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/elastic/agent-skills --skill observability-llm-obs

安装后在 Claude Code 中输入/observability-llm-obs确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
esql-recipes.md
genai-fields.md
integrations.md

详细介绍

LLM 和 Agent 式可观测性

仅根据实际摄取到 Elastic 中的数据,回答有关监控 LLM 和 Agent 式组件的问题——不使用其他信息。此技能回答四类问题:LLM 性能、成本和 Token 利用率、响应质量,以及调用链或 Agent 式工作流编排。

给定部署通常使用一种或多种摄取路径:APM/OTLP 跟踪,和/或集成指标与日志。实际使用哪种路径,需要通过发现来确认,不能想当然地认为两种都存在。有关 ES|QL 语法、命令和查询模式,请使用 elasticsearch-esql 技能。对于非 LLM 特定的服务级延迟和错误排查,请使用 observability-sre-triage 技能。

环境配置

此技能通过 elastic CLI 执行 Elasticsearch 操作。如果未安装 elastic CLI,请告知用户其用途。不要猜测凭据、直接调用 HTTP API,或尝试其他变通方法。

此技能以 HTTP 简写形式引用操作(例如,GET /、GET /_cat/indices、GET /{index}/_mapping、 GET /{index}/_settings/index.mode、POST /_query)。本文末尾的 操作 表格将每个简写映射到相应的 elastic CLI 命令——始终使用 CLI,而不是直接调用 HTTP API。

无法访问集群时的分析

上述 CLI 检查仅用于决定是否可以_查询集群_,不影响分析。如果用户已在问题中提供相关证据(指标值、计数、状态原因、日志行、告警负载、配置),请基于这些证据进行分析并给出结论。

如果确实需要用户尚未提供的数据,请说明要检查什么以及如何检查——指出能够明确回答问题的具体查询、索引和字段,然后再请求设置 CLI。即使无法连接集群,明确指出要检查的内容也有帮助;只要求设置 CLI 则没有帮助。

要完成的任务

  • 在查询任何内容之前,发现部署实际使用的 LLM 摄取路径
  • 发现此部署中实际使用的 LLM 字段名称,因为 GenAI 属性命名并不一致
  • 按模型、服务或时间报告 LLM 延迟、吞吐量和错误率
  • 报告 Token 利用率;仅当成本字段确实存在时才报告成本
  • 调查响应质量:失败、超时、结束原因、内容过滤器和护栏事件
  • 重建 Agent 式调用链,并找出多步骤工作流中的瓶颈 span
  • 将发现与基于 LLM 相关数据定义的 SLO 和告警规则关联起来

输出规范

适用于此技能生成的每条回复。

  • 给出证据最充分的结论。 当证据指向某个方向时,就明确说明。不要为了显得谨慎而降低置信度——面对明确的证据却含糊其辞,是缺陷,不是谦逊。
  • 只在结论中说明一次置信度。 不要在每条要点中重复说明。
  • 不要超出证据进行推测。 如果没有观察到某个原因,就不要将它写进答案。说明哪些内容未知,然后到此为止。
  • 如实报告缺失情况。 零行意味着数据缺失或未采集,绝不意味着底层情况正常。特别是,如果不存在成本字段,就说明成本未被监测——不要用猜测的每 Token 价格乘以 Token 数量,再把结果当作成本数据呈现。
  • 报告实际查到的数字。 引用查询返回的 Token 数量、延迟和错误率。不要将它们四舍五入成模糊的描述,也不要沿用本技能示例中的数字。
  • 不要凑字数。 不要复述问题,不要叙述运行了哪些查询(除非结果与之相关),也不要总结总结。
  • 以发现结尾。 不要在最后附上“要不要我深入调查?”之类的提议。可执行的后续事项应列在建议清单中,并表述为建议,而不是问题。

数据所在位置

接入路径索引模式可回答的问题
通过 OTLP 传输的 OTel / EDOT 跟踪数据traces-*.otel-*,或通用模式 traces-*单次请求的延迟、Token、模型、结束原因,以及调用链
Elastic APM Agent 跟踪数据traces-apm*,或通用模式 traces-*单次请求的延迟和结果;如果 SDK 添加了 GenAI 属性,也可获取这些属性
APM/OTel 指标metrics-apm*、metrics-*.otel-*聚合的服务级速率和延迟
Elastic LLM 集成指标metrics-<integration>.*(例如 metrics-aws_bedrock_agentcore.*)聚合 Token 数量、调用次数、延迟,有时还包括成本
Elastic LLM 集成日志logs-<integration>.*提示词/响应记录、护栏和内容过滤事件

使用通用的 traces-* 模式查找跟踪数据,无论数据是由 Elastic APM Agent 还是 OpenTelemetry 采集的都适用。监测数据可以由 EDOT、OpenLLMetry、OpenLIT 或 Langtrace 导出到 OTLP——它们都会将 LLM 和 Agent Span 写入跟踪数据流。

只有跟踪数据才能还原调用链。 trace.id、span.id 和 parent.id 是重建 Agent 调用链的唯一方式。集成指标已经过聚合,无法做到这一点——如果问题涉及编排,而现有数据只有集成指标,就说明无法根据现有数据还原调用链。

背景阅读: LLM 和 Agentic AI 可观测性, EDOT LLM 用例, Observability Labs — LLM 可观测性。

流程:确定有哪些可用数据

按顺序执行以下步骤。不要跳过步骤 5。

  1. 验证连接并检测版本。 调用 GET /。这将决定可用的查询语言功能:build_flavor: "serverless" 表示可以使用所有 ES|QL 功能,包括 TS、TRANGE 和 TBUCKET。否则,请使用 version.number:在 Stack 上,TS 在 9.2 中为预览版,在 9.4 中正式发布;TRANGE 在 9.3.0 中正式发布,因此对于完整的时间序列流程,应将 Stack 9.4 视为最低版本;低于此版本时,改用 FROM 和 BUCKET(@timestamp, ...)。判断错误会导致查询无法解析。

  2. 确定有哪些数据摄取路径。 这将决定此部署是否有 traces、集成数据或两者兼有,也会影响哪些问题根本无法回答。使用 GET /_data_stream/<name> 列出数据流(传入 traces-*、metrics-*、logs-*),或使用 GET /_resolve/index/<pattern> 解析模式。查找 trace 数据流、metrics-apm*,以及与已知 LLM 集成数据集匹配的任何 metrics-* 或 logs-*。如果两条路径都没有 LLM 数据,请如实说明并停止——不要根据对模型提供商的一般了解作答。

  3. 发现实际的 LLM 字段名称。 这将决定要写入 ES|QL 的确切字段路径,不能靠猜测。不同的埋点方式使用的命名各不相同:gen_ai.*、llm.* 或集成专用名称;语义约定本身也发生过变化(较旧的埋点方式会生成 gen_ai.system,较新的则会生成 gen_ai.provider.name)。使用 GET /_field_caps 并指定诸如 *gen_ai*、*llm*、*token*、*cost* 这样的字段模式,或读取 GET /<index>/_mapping,然后抽样检查文档,确认字段值已填充。不同数据摄取路径的属性嵌套方式不同——OTel 原生 trace 数据流会将 span 属性公开为 attributes.<name>(通常也会以裸字段 <name> 透传),而不是 span.attributes.<name>。编写查询前,请确认哪种形式能够解析。属性目录和解析规则请参阅 references/genai-fields.md。

  4. 判断是否存在成本字段。 成本不属于 OpenTelemetry GenAI 规范。某些埋点方式会添加诸如 llm.response.cost.usd_estimate 这样的自定义属性,某些集成会公开成本指标,但许多部署两者都没有。请在步骤 3 中明确查找。如果不存在,针对成本问题的答案应说明尚未对成本进行埋点——改为报告令牌数量,并指出这一缺口。

  5. 每个问题选择一个一致的数据源。 当 APM traces 和集成指标同时存在时,选定其中一种,并在整个答案中使用它。混用会导致重复计数,并为同一数量得出两个不同的数字,因为集成会轮询提供商自身的账单数据,而 traces 记录的是客户端观察到的情况。根据问题类型选择:traces 用于单次请求分析、调用链以及任何需要 trace 层级的问题;集成指标 用于较长时间窗口内的令牌和成本汇总。说明答案使用了哪个数据源。

  6. 在可能相关时检查告警和 SLO。 这将决定性能下降是否已被发现并跟踪。使用 GET kbn:/api/alerting/rules/_find 查找规则,使用 GET kbn:/api/observability/slos 查找 SLO,然后筛选目标为 LLM 相关服务或集成指标的项目——步骤 3 中的字段名称可帮助判断哪些规则相关。正在触发的告警,或状态为已违反或正在退化的 SLO,都是性能下降的证据。请注意,SLO API 的 sli.kql.custom 指标使用的是 KQL,而不是 ES|QL;这是 API 合约的规定,并不意味着建议在其他地方使用 KQL。

使用场景和查询模式

使用 POST /_query 编写查询。始终限定时间范围,在有 service.name 时添加该字段,并使用 LIMIT 限制结果数量。 如果只需查看趋势,而不是以精细粒度扫描较长时间范围,请使用较粗的时间分桶。

问题Traces 路径Integration 路径
延迟、吞吐量、错误率按 GenAI 操作或模型属性筛选;按时间桶使用 COUNT(*)、AVG(span.duration.us) 统计,并通过 event.outcome == "failure" 统计失败按模型维度统计请求速率、延迟和错误指标
Token 和成本按时间、模型或服务对输入和输出 Token 属性求和;仅在存在成本属性时才添加该属性按时间和模型汇总 Token 和成本指标
响应质量和安全性使用 event.outcome、error.type 和结束原因属性;仅在提示词和响应已捕获且未被删减时使用它们防护栏拦截、内容过滤事件和策略违规
调用链和编排仅限 Traces — 按 trace.id 分组,从 parent.id 沿层级追溯到 span.id,按 span 名称或 GenAI 操作聚合无法回答 — 指标已经过预聚合

在 Traces 路径中,每个 span 的延迟来自 duration(纳秒,在每个 OTel 原生 span 中都有值)或 span.duration.us(微秒,是一个 APM 兼容字段,在许多 span 中为 null — 按此字段排序可能会在不知情的情况下 漏掉最慢的步骤)。使用前请确认哪个字段有值。最慢的子 span 就是瓶颈。 按 span 名称或 GenAI 操作属性聚合,可查看工作流中各类步骤的分布 — 检索、大模型调用、工具使用。

有关特定集成的数据流和字段名称 — OpenAI、Azure OpenAI、Azure AI Foundry、Amazon Bedrock、Bedrock AgentCore、GCP Vertex AI — 请参阅 references/integrations.md。有关更长的完整查询示例, 包括 Trace 层级追溯和时间序列集成模式,请参阅 references/esql-recipes.md。

示例

以下字段路径仅供参考。运行任何操作前,请先根据步骤 3 确认实际路径——此技能 本身会先发现字段名称,正确的嵌套路径取决于数据摄取方式。

“每种模型消耗了多少令牌?”——确认令牌属性存在且可解析,然后按模型和时间段汇总。 报告返回的总量:

FROM traces-*
| WHERE @timestamp > NOW() - 24 hours AND attributes.gen_ai.request.model IS NOT NULL
| EVAL in_tok = TO_LONG(attributes.gen_ai.usage.input_tokens),
       out_tok = TO_LONG(attributes.gen_ai.usage.output_tokens)
| STATS input_tokens = SUM(in_tok), output_tokens = SUM(out_tok)
    BY hour = BUCKET(@timestamp, 1 hour), attributes.gen_ai.request.model
| SORT hour
| LIMIT 500

“我们的 LLM 支出是多少?”——查询前,使用 GET /_field_caps 搜索 *cost* 字段。如果没有, 则报告令牌使用情况,并明确说明此部署未采集成本数据;解决方法是在采集层添加成本 属性,或启用能够报告成本的集成。不要用臆测的价格乘以令牌数。

“哪个模型最慢,它是否频繁出错?”——一次查询延迟和错误率,并按模型分组:

FROM traces-*
| WHERE @timestamp > NOW() - 24 hours AND attributes.gen_ai.request.model IS NOT NULL
| STATS request_count = COUNT(*),
        failures = COUNT(*) WHERE event.outcome == "failure",
        avg_duration_us = AVG(span.duration.us)
    BY attributes.gen_ai.request.model
| EVAL error_rate = failures::double / request_count
| SORT avg_duration_us DESC
| LIMIT 100

“为什么我们的 Agent 运行缓慢?”——这需要追踪层级,因此需要追踪数据。找出包含多个 LLM 或工具 span 的 追踪,按这些 span 花费的时间排序,然后通过 trace.id 深入查看耗时最长的追踪, 找出瓶颈 span。由于 WHERE 限定了 LLM span,下面的总和是 LLM 耗时,而非端到端追踪 耗时——请明确标注列名,以免误读为实际延迟:

FROM traces-*
| WHERE @timestamp > NOW() - 3 hours AND attributes.gen_ai.operation.name IS NOT NULL
| STATS llm_span_count = COUNT(*), llm_duration_us = SUM(span.duration.us) BY trace.id
| WHERE llm_span_count > 1
| SORT llm_duration_us DESC
| LIMIT 50

“提示词会被拦截吗?”——检查追踪路径上的完成原因属性和 error.type,或检查 集成的护栏日志事件。诸如内容过滤器之类的完成原因是质量信号,而不是传输错误。

“是否已有针对这个问题的告警?”——查询 GET kbn:/api/alerting/rules/_find 和 GET kbn:/api/observability/slos,并根据步骤 2 中识别的 LLM 相关服务或集成指标进行筛选。

指南

  • 仅根据摄取到 Elastic 中的数据作答。 不要描述或依赖其他供应商的 UI、控制台或产品。 如果数据不在 Elastic 中,答案就是数据不在 Elastic 中。
  • 先发现,再查询。 通过 GET /_field_caps、GET /<index>/_mapping 或样本文档, 确认摄取路径(步骤 2)和字段名称(步骤 3)。切勿猜测属性路径。
  • 每个问题只使用一个一致的数据源。 不要在同一个答案中混合使用 APM 追踪和集成指标。
  • GenAI 规范中不包含成本。 只有数据中存在成本字段时,才能将成本数值视为可用。
  • 只有追踪才能还原链路。 如果问题涉及 Agent 编排,而现有数据只有集成指标, 应说明无法还原链路,而不是根据聚合数据进行推测。
  • 根据版本选择时间序列语法。 在 Serverless 或 Stack 9.4+ 上使用 TS、TRANGE 和 TBUCKET; 在更低版本上改用 FROM 和 BUCKET(@timestamp, ...)。为时间桶设置别名(BY bucket = TBUCKET(1 hour)), 并按别名排序。
  • 动态映射的属性可能发生类型冲突。 令牌属性在一个后备索引中经常被映射为 integer, 在滚动更新后的另一个索引中则被映射为 long,导致 ES|QL 拒绝该字段。请先在 EVAL 中使用 TO_LONG(...) 转换,再进行聚合。
  • 不依赖 Kibana UI。 优先使用 ES|QL 和 Elasticsearch API;仅在处理 SLO 和告警时使用 Kibana API。切勿 指示用户打开 Kibana UI。
  • ES|QL 语法和查询模式请参考 elasticsearch-esql 技能;在 Stack 9.4+ 和 Serverless 上适用 TS 命令参考, 其他版本则适用 FROM 命令参考。

Operations

HTTP API (shorthand)elastic CLI command
GET /elastic es info
GET /_data_stream/<name>elastic es indices get-data-stream --name '<name>'
GET /_resolve/index/<pattern>elastic es indices resolve-index --name '<pattern>'
GET /<index>/_mappingelastic es indices get-mapping --index '<index>'
GET /_field_capselastic es field-caps --index '<index>' --fields '<fields>'
POST /_queryelastic es esql query --format tsv --query '<esql>'
GET kbn:/api/alerting/rules/_findelastic kb alerting get-alerting-rules-find --filter '<filter>'
GET kbn:/api/observability/sloselastic kb slo find-slos-op --space-id '<space>' --kql-query '<kql>'

评论

支持 Markdown