- Skill ID
- elastic/agent-skills/observability-llm-obs
- Publisher
- elastic
- Repository
- agent-skills
- Installs
- 0
- Files
- 4
- Requires
- >
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
elastic/agent-skills/observability-llm-obsInstalls these files- SKILL.md
- references/esql-recipes.md
- references/genai-fields.md
- references/integrations.md
What this skill tells the agent
LLM and Agentic Observability
Answer questions about monitoring LLMs and agentic components using data actually ingested into Elastic — nothing else. The four questions this skill answers are LLM performance, cost and token utilization, response quality, and call chaining or agentic workflow orchestration.
A given deployment typically uses one or more ingestion paths: APM/OTLP traces, and/or integration metrics and logs. Which one exists is a discovery result, not an assumption — never assume both are present. For ES|QL syntax, commands, and query patterns, use the elasticsearch-esql skill. For service-level latency and error triage that is not LLM-specific, use the observability-sre-triage skill.
<!-- begin-partial: preamble -->
Environment Configuration
This skill executes Elasticsearch operations through the elastic CLI. If the `elastic` CLI is not installed, tell the user what it is needed for. Do not guess credentials, call the HTTP API directly, or attempt other workarounds.
This skill references operations in HTTP-shorthand form (e.g., GET /, GET /_cat/indices, GET /{index}/_mapping, GET /{index}/_settings/index.mode, POST /_query). The Operations table at the end of this document maps each shorthand to the equivalent elastic CLI command — always use the CLI rather than calling the HTTP API directly.
<!-- end-partial: preamble -->
Analysis without cluster access
The CLI check above gates _querying the cluster_ — it does not gate analysis. When the user has already supplied the evidence in their question (metric values, counts, status reasons, log lines, alert payloads, configuration), reason from that evidence and deliver the conclusion.
When you genuinely do need data the user has not provided, still say what you would check and how — name the specific query, index, and field that would settle the question — and then ask for CLI setup. An answer that names the check is useful without a cluster; one that only asks for setup is not.
Jobs to be done
- Discover which LLM ingestion path a deployment actually uses before querying anything
- Discover the real LLM field names in this deployment, because GenAI attribute naming is not consistent
- Report LLM latency, throughput, and error rate by model, service, or time
- Report token utilization, and report cost only when a cost field genuinely exists
- Investigate response quality: failures, timeouts, finish reasons, content filters, and guardrail events
- Reconstruct agentic call chains and find the bottleneck span in a multi-step workflow
- Correlate findings with SLOs and alerting rules defined on LLM-related data
Output discipline
Applies to every response produced under this skill.
- Commit to the best-supported conclusion. When the evidence points one way, say so. Do not downgrade confidence to sound cautious — hedging on unambiguous evidence is a defect, not humility.
- State confidence once, in the conclusion. Do not restate it per bullet.
- Do not speculate past the evidence. If a cause was not observed, it does not go in the answer. Say what is unknown and stop.
- Report absence as absence. Zero rows means the data is missing or not collected; it never means the underlying condition is healthy. In particular, if no cost field exists, say cost is not instrumented — do not multiply token counts by a guessed per-token price and present the product as a cost figure.
- Report the numbers actually found. Quote the token counts, latencies, and error rates the query returned. Do not round them into vague characterizations, and do not carry forward a number from an example in this skill.
- Do not pad. No restating the question, no narrating which queries were run unless the result mattered, no summarizing the summary.
- End on the finding. No trailing offers such as "want me to dig deeper?". Actionable follow-ups belong in a recommendations list, phrased as recommendations, not as questions.
Where the data lives
| Ingestion path | Index patterns | What it can answer |
|---|---|---|
| OTel / EDOT traces via OTLP | traces-*.otel-*, or the generic traces-* | Per-request latency, tokens, models, finish reasons, and call chains |
| Elastic APM agent traces | traces-apm*, or the generic traces-* | Per-request latency and outcome; GenAI attributes if the SDK adds them |
| APM/OTel metrics | metrics-apm*, metrics-*.otel-* | Aggregated service-level rates and latencies |
| Elastic LLM integration metrics | metrics-<integration>.* (for example metrics-aws_bedrock_agentcore.*) | Aggregate token counts, invocations, latency, sometimes cost |
| Elastic LLM integration logs | logs-<integration>.* | Prompt/response records, guardrail and content-filter events |
Use the generic traces-* pattern to find trace data regardless of whether an Elastic APM agent or OpenTelemetry collected it. Instrumentation can come from EDOT, OpenLLMetry, OpenLIT, or Langtrace exporting to OTLP — all of them land LLM and agent spans in the trace data streams.
Only traces can reconstruct a call chain. trace.id, span.id, and parent.id are the only way to rebuild an agentic call chain. Integration metrics are pre-aggregated and cannot do it — if the question is about orchestration and only integration metrics exist, say the chain cannot be reconstructed from the available data.
Background reading: LLM and agentic AI observability, EDOT LLM use cases, Observability Labs — LLM Observability.
Process: determine what data is available
Run these in order. Do not skip to step 5.
- Verify the connection and detect the version. Call
GET /. The decision this drives is which query language surface is available:build_flavor: "serverless"means all ES|QL features includingTS,TRANGE, andTBUCKETare available. Otherwise useversion.number: on Stack,TSis preview in 9.2 and GA in 9.4, andTRANGEis GA in 9.3.0, so treat Stack 9.4 as the floor for the whole time-series path and fall back toFROMwithBUCKET(@timestamp, ...)below it. Getting this wrong produces a query that fails to parse.
- Determine which ingestion paths exist. The decision is whether this deployment has traces, integration data, or both — and it changes which questions are answerable at all. List data streams with
GET /_data_stream/<name>(passtraces-*,metrics-*,logs-*) or resolve patterns withGET /_resolve/index/<pattern>. Look for trace data streams,metrics-apm*, and anymetrics-*orlogs-*matching a known LLM integration dataset. If neither path has LLM data, say so and stop — do not answer from general knowledge about the model provider.
- Discover the real LLM field names. The decision is which exact field paths to write into ES|QL, and it cannot be guessed. Naming differs across instrumentations:
gen_ai.*versusllm.*versus integration-specific names, and the semantic conventions themselves have shifted (older instrumentation emitsgen_ai.system, newer emits
More from elastic
Use this skill in a project
Open any RiverX project, search the Skills panel for elastic/agent-skills/observability-llm-obs, and install it in one click.
