diff --git a/.chloggen/811.yaml b/.chloggen/811.yaml new file mode 100644 index 0000000000..dd2304d58b --- /dev/null +++ b/.chloggen/811.yaml @@ -0,0 +1,4 @@ +change_type: enhancement +component: gen-ai +note: Adding metrics for GenAI clients. +issues: [811] diff --git a/docs/attributes-registry/gen-ai.md b/docs/attributes-registry/gen-ai.md index a58d9c3989..0bde9ff5fd 100644 --- a/docs/attributes-registry/gen-ai.md +++ b/docs/attributes-registry/gen-ai.md @@ -13,6 +13,7 @@ This document defines the attributes used to describe telemetry in the context o | Attribute | Type | Description | Examples | Stability | | -------------------------------- | -------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- | ---------------------------------------------------------------- | | `gen_ai.completion` | string | The full response received from the LLM. [1] | `[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| `gen_ai.operation.name` | string | The name of the operation being performed. | `chat`; `completion` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.prompt` | string | The full prompt sent to an LLM. [2] | `[{'role': 'user', 'content': 'What is the capital of France?'}]` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.request.max_tokens` | int | The maximum number of tokens the LLM generates for a request. | `100` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.request.model` | string | The name of the LLM a request is being made to. | `gpt-4` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | @@ -22,6 +23,7 @@ This document defines the attributes used to describe telemetry in the context o | `gen_ai.response.id` | string | The unique identifier for the completion. | `chatcmpl-123` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.response.model` | string | The name of the LLM a response was generated from. | `gpt-4-0613` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.system` | string | The Generative AI product as identified by the client instrumentation. [3] | `openai` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| `gen_ai.token.type` | string | The type of token being counted. | `input`; `output` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.usage.completion_tokens` | int | The number of tokens used in the LLM response (completion). | `180` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `gen_ai.usage.prompt_tokens` | int | The number of tokens used in the LLM prompt. | `100` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | @@ -36,3 +38,10 @@ This document defines the attributes used to describe telemetry in the context o | Value | Description | Stability | | -------- | ----------- | ---------------------------------------------------------------- | | `openai` | OpenAI | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + +`gen_ai.token.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| -------- | ------------------------------------------ | ---------------------------------------------------------------- | +| `input` | Input tokens (prompt, input, etc.) | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| `output` | Output tokens (completion, response, etc.) | ![Experimental](https://img.shields.io/badge/-experimental-blue) | diff --git a/docs/gen-ai/README.md b/docs/gen-ai/README.md index 1197a88522..17d5ef099d 100644 --- a/docs/gen-ai/README.md +++ b/docs/gen-ai/README.md @@ -18,6 +18,10 @@ This document defines semantic conventions for the following kind of Generative * LLMs +Semantic conventions for Generative AI operations are defined for the following signals: + +* [Metrics](gen-ai-metrics.md): Semantic Conventions for Generative AI operations - *metrics*. + Semantic conventions for LLM operations are defined for the following signals: * [LLM Spans](llm-spans.md): Semantic Conventions for LLM requests - *spans*. diff --git a/docs/gen-ai/gen-ai-metrics.md b/docs/gen-ai/gen-ai-metrics.md new file mode 100644 index 0000000000..e68f0bf183 --- /dev/null +++ b/docs/gen-ai/gen-ai-metrics.md @@ -0,0 +1,182 @@ + + +# Semantic Conventions for Generative AI Client Metrics + +**Status**: [Experimental][DocumentStatus] + +The conventions described in this section are specific to Generative AI client +applications. + +**Disclaimer:** These are initial Generative AI client metric instruments +and attributes but more may be added in the future. + + + + + +- [Generative AI Client Metrics](#generative-ai-client-metrics) + - [Metric: `gen_ai.client.token.usage`](#metric-gen_aiclienttokenusage) + - [Metric: `gen_ai.client.operation.duration`](#metric-gen_aiclientoperationduration) + + + +## Generative AI Client Metrics + +The following metric instruments describe Generative AI operations. An +operation may be a request to an LLM, a function call, or some other +distinct action within a larger Generative AI workflow. + +### Metric: `gen_ai.client.token.usage` + +This metric is [recommended][MetricRecommended] when an operation involves the usage +of tokens and the count is readily available. + +For example, if GenAI system returns usage information in the streaming response, it SHOULD be used. Or if GenAI system returns each token independently, instrumentation SHOULD count number of output tokens and record the result. + +If instrumentation cannot efficiently obtain number of input and/or output tokens, it MAY allow users to enable offline token counting. Otherwise it MUST NOT report usage metric. + +When systems report both used tokens and billable tokens, instrumentation MUST report billable tokens. + +This metric SHOULD be specified with [ExplicitBucketBoundaries] of [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864]. + + + + + + + + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `gen_ai.client.token.usage` | Histogram | `{token}` | Measures number of input and output tokens used | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + + + + + + + + + + + + + + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`gen_ai.operation.name`](/docs/attributes-registry/gen-ai.md) | string | The name of the operation being performed. | `chat`; `completion` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`gen_ai.request.model`](/docs/attributes-registry/gen-ai.md) | string | The name of the LLM a request is being made to. | `gpt-4` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`gen_ai.system`](/docs/attributes-registry/gen-ai.md) | string | The Generative AI product as identified by the client instrumentation. [1] | `openai` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`gen_ai.token.type`](/docs/attributes-registry/gen-ai.md) | string | The type of token being counted. | `input`; `output` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [2] | `80`; `8080`; `443` | `Conditionally Required` If `sever.address` is set. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`gen_ai.response.model`](/docs/attributes-registry/gen-ai.md) | string | The name of the LLM a response was generated from. | `gpt-4-0613` | `Recommended` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`server.address`](/docs/attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [3] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1]:** The actual GenAI product may differ from the one identified by the client. For example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system` is set to `openai` based on the instrumentation's best knowledge. + +**[2]:** When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + +**[3]:** When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. + + + +`gen_ai.system` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +| `openai` | OpenAI | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + + +`gen_ai.token.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +| `input` | Input tokens (prompt, input, etc.) | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| `output` | Output tokens (completion, response, etc.) | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + + + + + + + + +### Metric: `gen_ai.client.operation.duration` + +This metric is [required][MetricRequired]. + +This metric SHOULD be specified with [ExplicitBucketBoundaries] of [ 0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12,10.24, 20.48, 40.96, 81.92]. + + + + + + + + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `gen_ai.client.operation.duration` | Histogram | `s` | GenAI operation duration | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + + + + + + + + + + + + + + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`gen_ai.operation.name`](/docs/attributes-registry/gen-ai.md) | string | The name of the operation being performed. | `chat`; `completion` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`gen_ai.request.model`](/docs/attributes-registry/gen-ai.md) | string | The name of the LLM a request is being made to. | `gpt-4` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`gen_ai.system`](/docs/attributes-registry/gen-ai.md) | string | The Generative AI product as identified by the client instrumentation. [1] | `openai` | `Required` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [2] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Conditionally Required` if the operation ended in an error | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `Conditionally Required` If `sever.address` is set. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`gen_ai.response.model`](/docs/attributes-registry/gen-ai.md) | string | The name of the LLM a response was generated from. | `gpt-4-0613` | `Recommended` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`server.address`](/docs/attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [4] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1]:** The actual GenAI product may differ from the one identified by the client. For example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system` is set to `openai` based on the instrumentation's best knowledge. + +**[2]:** The `error.type` SHOULD match the error code returned by the Generative AI provider or the client library, +the canonical name of exception that occurred, or another low-cardinality error identifier. +Instrumentations SHOULD document the list of errors they report. + +**[3]:** When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + +**[4]:** When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. + + + +`error.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +| `_OTHER` | A fallback error value to be used when the instrumentation doesn't define a custom value. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + + +`gen_ai.system` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +| `openai` | OpenAI | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + + + + + + + + +[DocumentStatus]: https://github.com/open-telemetry/opentelemetry-specification/tree/v1.22.0/specification/document-status.md +[MetricRequired]: /docs/general/metric-requirement-level.md#required +[MetricRecommended]: /docs/general/metric-requirement-level.md#recommended +[ExplicitBucketBoundaries]: https://github.com/open-telemetry/opentelemetry-specification/tree/v1.31.0/specification/metrics/api.md#instrument-advisory-parameters diff --git a/model/metrics/gen-ai.yaml b/model/metrics/gen-ai.yaml new file mode 100644 index 0000000000..8398e8f0c6 --- /dev/null +++ b/model/metrics/gen-ai.yaml @@ -0,0 +1,45 @@ +groups: + - id: metric_attributes.gen_ai + type: attribute_group + brief: 'This group describes GenAI metrics attributes' + attributes: + - ref: server.address + requirement_level: recommended + - ref: server.port + requirement_level: + conditionally_required: If `sever.address` is set. + - ref: gen_ai.response.model + requirement_level: recommended + - ref: gen_ai.request.model + requirement_level: required + - ref: gen_ai.system + requirement_level: required + - ref: gen_ai.operation.name + requirement_level: required + - id: metric.gen_ai.client.token.usage + type: metric + metric_name: gen_ai.client.token.usage + brief: 'Measures number of input and output tokens used' + instrument: histogram + unit: "{token}" + stability: experimental + extends: metric_attributes.gen_ai + attributes: + - ref: gen_ai.token.type + requirement_level: required + - id: metric.gen_ai.client.operation.duration + type: metric + metric_name: gen_ai.client.operation.duration + brief: 'GenAI operation duration' + instrument: histogram + unit: "s" + stability: experimental + extends: metric_attributes.gen_ai + attributes: + - ref: error.type + requirement_level: + conditionally_required: "if the operation ended in an error" + note: | + The `error.type` SHOULD match the error code returned by the Generative AI provider or the client library, + the canonical name of exception that occurred, or another low-cardinality error identifier. + Instrumentations SHOULD document the list of errors they report. diff --git a/model/registry/gen-ai.yaml b/model/registry/gen-ai.yaml index ab2ea3700c..47ec27bf60 100644 --- a/model/registry/gen-ai.yaml +++ b/model/registry/gen-ai.yaml @@ -75,6 +75,20 @@ groups: brief: The number of tokens used in the LLM response (completion). examples: [180] tag: llm-generic-response + - id: token.type + stability: experimental + type: + members: + - id: input + stability: experimental + value: "input" + brief: 'Input tokens (prompt, input, etc.)' + - id: completion + stability: experimental + value: "output" + brief: 'Output tokens (completion, response, etc.)' + brief: The type of token being counted. + examples: ['input', 'output'] - id: prompt stability: experimental type: string @@ -89,3 +103,8 @@ groups: note: It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) examples: ["[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]"] tag: llm-generic-events + - id: operation.name + stability: experimental + type: string + brief: The name of the operation being performed. + examples: ['chat', 'completion']