Skip to content

Commit bca25e5

Browse files
codefromthecryptxrmx
authored andcommitted
elastic-opentelemetry-instrumentation-openai: add examples
1 parent 0eef232 commit bca25e5

File tree

5 files changed

+152
-2
lines changed

5 files changed

+152
-2
lines changed

instrumentation/elastic-opentelemetry-instrumentation-openai/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ pip install elastic-opentelemetry-instrumentation-openai
2323
This instrumentation supports *zero-code* / *autoinstrumentation*:
2424

2525
```
26-
opentelemetry-instrument python use_openai.py
26+
# "examples/chat.py" is a simple script using the openai client library.
27+
cd examples
28+
29+
opentelemetry-instrument python chat.py
2730
2831
# You can record more information about prompts as log events by enabling content capture.
29-
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true opentelemetry-instrument python use_openai.py
32+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true opentelemetry-instrument python chat.py
3033
```
3134

3235
Or manual instrumentation:
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# OpenAI Zero-Code Instrumentation Examples
2+
3+
This is an example of how to instrument OpenAI calls with zero code changes,
4+
using `opentelemetry-instrument` included in the Elastic Distribution of
5+
OpenTelemetry Python ([EDOT Python][edot-python]).
6+
7+
When OpenAI examples run, they export traces, metrics and logs to an OTLP
8+
compatible endpoint. Traces and metrics include details such as the model used
9+
and the duration of the LLM request. In the case of chat, Logs capture the
10+
request and the generated response. The combination of these provide a
11+
comprehensive view of the performance and behavior of your OpenAI usage.
12+
13+
## Install
14+
15+
First, set up a Python virtual environment like this:
16+
```bash
17+
python3 -m venv .venv
18+
source .venv/bin/activate
19+
pip install -r requirements.txt
20+
```
21+
22+
Next, install [EDOT Python][edot-python] and dotenv which is a portable way to
23+
load environment variables.
24+
```bash
25+
pip install "python-dotenv[cli]" elastic-opentelemetry
26+
```
27+
28+
Finally, run `edot-bootstrap` which analyzes the code to add relevant
29+
instrumentation, to record traces, metrics and logs.
30+
```bash
31+
edot-bootstrap --action=install
32+
```
33+
34+
## Configure
35+
36+
Minimally, update the [.env](.env) file with your `OPENAI_API_KEY`.
37+
38+
An OTLP compatible endpoint should be listening for traces, metrics and logs on
39+
`http://localhost:4317`. If not, update `OTEL_EXPORTER_OTLP_ENDPOINT` as well.
40+
41+
## Run
42+
43+
There are two examples, and they run the same way:
44+
45+
### Chat
46+
47+
[chat.py](chat.py) asks the LLM a geography question and prints the response.
48+
49+
Run it like this:
50+
```bash
51+
dotenv run -- opentelemetry-instrument python chat.py
52+
```
53+
54+
You should see something like "Atlantic Ocean" unless your LLM hallucinates!
55+
56+
### Embeddings
57+
58+
59+
[embeddings.py](embeddings.py) creates in-memory VectorDB embeddings about
60+
Elastic products. Then, it searches for one similar to a question.
61+
62+
Run it like this:
63+
```bash
64+
dotenv run -- opentelemetry-instrument python embeddings.py
65+
```
66+
67+
You should see something like "Connectors" unless your LLM hallucinates!
68+
69+
---
70+
71+
[edot-python]: https://github.com/elastic/elastic-otel-python/blob/main/docs/get-started.md
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
5+
import openai
6+
7+
CHAT_MODEL = os.environ.get("CHAT_MODEL", "gpt-4o-mini")
8+
9+
10+
def main():
11+
client = openai.Client()
12+
13+
messages = [
14+
{
15+
"role": "user",
16+
"content": "Answer in up to 3 words: Which ocean contains the falkland islands?",
17+
}
18+
]
19+
20+
chat_completion = client.chat.completions.create(model=CHAT_MODEL, messages=messages)
21+
print(chat_completion.choices[0].message.content)
22+
23+
24+
if __name__ == "__main__":
25+
main()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import os
2+
3+
import numpy as np
4+
import openai
5+
6+
EMBEDDINGS_MODEL = os.environ.get("EMBEDDINGS_MODEL", "text-embedding-3-small")
7+
8+
9+
def main():
10+
client = openai.Client()
11+
12+
products = [
13+
"Search: Ingest your data, and explore Elastic's machine learning and retrieval augmented generation (RAG) capabilities."
14+
"Observability: Unify your logs, metrics, traces, and profiling at scale in a single platform.",
15+
"Security: Protect, investigate, and respond to cyber threats with AI-driven security analytics."
16+
"Elasticsearch: Distributed, RESTful search and analytics.",
17+
"Kibana: Visualize your data. Navigate the Stack.",
18+
"Beats: Collect, parse, and ship in a lightweight fashion.",
19+
"Connectors: Connect popular databases, file systems, collaboration tools, and more.",
20+
"Logstash: Ingest, transform, enrich, and output.",
21+
]
22+
23+
# Generate embeddings for each product. Keep them in an array instead of a vector DB.
24+
product_embeddings = []
25+
for product in products:
26+
product_embeddings.append(create_embedding(client, product))
27+
28+
query_embedding = create_embedding(client, "What can help me connect to OpenAI?")
29+
30+
# Calculate cosine similarity between the query and document embeddings
31+
similarities = []
32+
for product_embedding in product_embeddings:
33+
similarity = np.dot(query_embedding, product_embedding) / (
34+
np.linalg.norm(query_embedding) * np.linalg.norm(product_embedding)
35+
)
36+
similarities.append(similarity)
37+
38+
# Get the index of the most similar document
39+
most_similar_index = np.argmax(similarities)
40+
41+
print(products[most_similar_index])
42+
43+
44+
def create_embedding(client, text):
45+
return client.embeddings.create(input=[text], model=EMBEDDINGS_MODEL, encoding_format="float").data[0].embedding
46+
47+
48+
if __name__ == "__main__":
49+
main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
openai~=1.57.2
2+
numpy~=2.2.0

0 commit comments

Comments
 (0)