Skip to content

Commit 5c009b3

Browse files
keith-deckerzhirafovod
authored andcommitted
WIP gen_ai chat refactor
1 parent 2743109 commit 5c009b3

File tree

6 files changed

+70
-11
lines changed

6 files changed

+70
-11
lines changed

util/opentelemetry-util-genai/README.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@ The GenAI Utils package will include boilerplate and helpers to standardize inst
66
This package will provide APIs and decorators to minimize the work needed to instrument genai libraries,
77
while providing standardization for generating both types of otel, "spans and metrics" and "spans, metrics and events"
88

9+
This package provides these span attributes.
10+
-> gen_ai.operation.name: Str(chat)
11+
-> gen_ai.system: Str(ChatOpenAI)
12+
-> gen_ai.request.model: Str(gpt-3.5-turbo)
13+
-> gen_ai.request.top_p: Double(0.9)
14+
-> gen_ai.request.frequency_penalty: Double(0.5)
15+
-> gen_ai.request.presence_penalty: Double(0.5)
16+
-> gen_ai.request.stop_sequences: Slice(["\n","Human:","AI:"])
17+
-> gen_ai.request.seed: Int(100)
18+
-> gen_ai.request.max_tokens: Int(100)
19+
-> gen_ai.provider.name: Str(openai)
20+
-> gen_ai.request.temperature: Double(0.1)
21+
-> gen_ai.response.finish_reasons: Slice(["stop"])
22+
-> gen_ai.response.model: Str(gpt-3.5-turbo-0125)
23+
-> gen_ai.response.id: Str(chatcmpl-Bz8yrvPnydD9pObv625n2CGBPHS13)
24+
-> gen_ai.usage.input_tokens: Int(24)
25+
-> gen_ai.usage.output_tokens: Int(7)
26+
927
Installation
1028
------------
1129

util/opentelemetry-util-genai/src/opentelemetry/util/genai/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,23 @@ def __init__(self, emitter_type_full: bool = True, **kwargs):
4242
__name__,
4343
__version__,
4444
tracer_provider,
45-
schema_url=Schemas.V1_28_0.value,
45+
schema_url=Schemas.V1_36_0.value,
4646
)
4747

4848
meter_provider = kwargs.get("meter_provider")
4949
self._meter = get_meter(
5050
__name__,
5151
__version__,
5252
meter_provider,
53-
schema_url=Schemas.V1_28_0.value,
53+
schema_url=Schemas.V1_36_0.value,
5454
)
5555

5656
event_logger_provider = kwargs.get("event_logger_provider")
5757
self._event_logger = get_event_logger(
5858
__name__,
5959
__version__,
6060
event_logger_provider=event_logger_provider,
61-
schema_url=Schemas.V1_28_0.value,
61+
schema_url=Schemas.V1_36_0.value,
6262
)
6363

6464
self._emitter = (

util/opentelemetry-util-genai/src/opentelemetry/util/genai/data.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ class Message:
77
type: str
88
name: str
99

10+
def _to_part_dict(self):
11+
"""Convert the message to a dictionary suitable for OpenTelemetry semconvs.
12+
13+
Ref: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/gen-ai.md#gen-ai-input-messages
14+
"""
15+
16+
# Support tool_call and tool_call response
17+
return {
18+
"role": self.type,
19+
"parts": [
20+
{
21+
"content": self.content,
22+
"type": "text",
23+
}
24+
],
25+
}
26+
1027

1128
@dataclass
1229
class ChatGeneration:

util/opentelemetry-util-genai/src/opentelemetry/util/genai/emitters.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use_span,
3535
)
3636
from opentelemetry.trace.status import Status, StatusCode
37+
from opentelemetry.util.types import Attributes
3738

3839
from .data import Error
3940
from .instruments import Instruments
@@ -59,8 +60,11 @@ def _get_property_value(obj, property_name) -> object:
5960

6061

6162
def _message_to_event(message, system, framework) -> Optional[Event]:
63+
# TODO: Convert to logs.
6264
content = _get_property_value(message, "content")
6365
if content:
66+
# update this to event.gen_ai.client.inference.operation.details: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-events.md
67+
6468
message_type = _get_property_value(message, "type")
6569
message_type = "user" if message_type == "human" else message_type
6670
body = {"content": content}
@@ -80,6 +84,7 @@ def _message_to_event(message, system, framework) -> Optional[Event]:
8084
def _chat_generation_to_event(
8185
chat_generation, index, system, framework
8286
) -> Optional[Event]:
87+
# TODO: Convert to logs.
8388
if chat_generation.content:
8489
attributes = {
8590
# TODO: add below to opentelemetry.semconv._incubating.attributes.gen_ai_attributes
@@ -478,14 +483,23 @@ def emit(self, invocation: LLMInvocation):
478483
GenAI.GEN_AI_USAGE_OUTPUT_TOKENS, completion_tokens
479484
)
480485

486+
message_parts: List[Attributes] = []
481487
for index, message in enumerate(invocation.messages):
482-
content = message.content
483-
span.set_attribute(f"gen_ai.prompt.{index}.content", content)
484-
span.set_attribute(f"gen_ai.prompt.{index}.role", message.type)
488+
message_parts.append(message._to_part_dict())
489+
490+
if len(message_parts) > 0:
491+
span.set_attribute("gen_ai.input.messages", message_parts)
492+
493+
# for index, message in enumerate(invocation.messages):
494+
# content = message.content
495+
# # Set these attributes to upcoming semconv: https://github.com/open-telemetry/semantic-conventions/pull/2179
496+
# span.set_attribute(f"gen_ai.input.messages.{index}.content", [content._to_part_dict()])
497+
# span.set_attribute(f"gen_ai.input.messages.{index}.role", message.type)
485498

486499
for index, chat_generation in enumerate(
487500
invocation.chat_generations
488501
):
502+
# Set these attributes to upcoming semconv: https://github.com/open-telemetry/semantic-conventions/pull/2179
489503
span.set_attribute(
490504
f"gen_ai.completion.{index}.content",
491505
chat_generation.content,

util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from dataclasses import dataclass
16-
from enum import Enum
17-
from typing import Any, Literal, Optional, Union
15+
import time
16+
from dataclasses import dataclass, field
17+
from typing import Any, Dict, List, Optional
18+
from uuid import UUID
19+
20+
from .data import ChatGeneration, Message
1821

1922

2023
class ContentCapturingMode(Enum):
@@ -68,4 +71,12 @@ class OutputMessage:
6871
role: str
6972
parts: list[MessagePart]
7073
finish_reason: Union[str, FinishReason]
71-
74+
run_id: UUID
75+
parent_run_id: Optional[UUID] = None
76+
start_time: float = field(default_factory=time.time)
77+
end_time: Optional[float] = None
78+
messages: List[Message] = field(default_factory=list)
79+
chat_generations: List[ChatGeneration] = field(default_factory=list)
80+
attributes: Dict[str, Any] = field(default_factory=dict)
81+
span_id: int = 0
82+
trace_id: int = 0

util/opentelemetry-util-genai/tests/test_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
<<<<<<< HEAD
21
# Copyright The OpenTelemetry Authors
32
#
43
# Licensed under the Apache License, Version 2.0 (the "License");

0 commit comments

Comments
 (0)