-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathrun.py
More file actions
150 lines (117 loc) · 4.78 KB
/
run.py
File metadata and controls
150 lines (117 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
"""Run an Anthropic Claude dice agent with standard OTLP export — no agentevals SDK.
Demonstrates zero-code integration: any OTel-instrumented agent streams
traces and logs to agentevals by pointing the OTLP exporter at the receiver.
The only agentevals-specific setup is the OTLP endpoint and resource
attributes. The agent code itself is unchanged.
Prerequisites:
1. pip install -r requirements.txt
2. agentevals serve --dev
3. export ANTHROPIC_API_KEY="your-key-here"
Usage:
python examples/zero-code-examples/anthropic/run.py
"""
import json
import os
import random
import anthropic
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
load_dotenv(override=True)
TOOLS = [
{
"name": "roll_die",
"description": "Roll a single die with the given number of sides and return the result.",
"input_schema": {
"type": "object",
"properties": {"n_sides": {"type": "integer", "description": "Number of sides on the die."}},
"required": ["n_sides"],
},
},
{
"name": "check_prime",
"description": "Return true if the given number is prime, false otherwise.",
"input_schema": {
"type": "object",
"properties": {"number": {"type": "integer", "description": "The number to check."}},
"required": ["number"],
},
},
]
def roll_die(n_sides: int) -> int:
return random.randint(1, n_sides)
def check_prime(number: int) -> bool:
if number < 2:
return False
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
return False
return True
def run_agent(client: anthropic.Anthropic, query: str) -> str:
messages = [{"role": "user", "content": query}]
while True:
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
tools=TOOLS,
messages=messages,
)
if response.stop_reason == "end_turn":
for block in response.content:
if hasattr(block, "text"):
return block.text
return ""
tool_results = []
for block in response.content:
if block.type == "tool_use":
if block.name == "roll_die":
result = roll_die(**block.input)
elif block.name == "check_prime":
result = check_prime(**block.input)
else:
result = "Unknown tool"
tool_results.append({"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result)})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
def main():
if not os.getenv("ANTHROPIC_API_KEY"):
print("ANTHROPIC_API_KEY not set.")
return
endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")
print(f"OTLP endpoint: {endpoint}")
os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = "true"
os.environ.setdefault(
"OTEL_RESOURCE_ATTRIBUTES",
"agentevals.eval_set_id=anthropic_agent_eval,agentevals.session_name=anthropic-zero-code",
)
resource = Resource.create()
tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(), schedule_delay_millis=1000))
trace.set_tracer_provider(tracer_provider)
logger_provider = LoggerProvider(resource=resource)
logger_provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter(), schedule_delay_millis=1000))
set_logger_provider(logger_provider)
AnthropicInstrumentor().instrument()
client = anthropic.Anthropic()
test_queries = [
"Roll a 20-sided die for me",
"Is the number you rolled prime?",
]
for i, query in enumerate(test_queries, 1):
print(f"\n[{i}/{len(test_queries)}] User: {query}")
response = run_agent(client, query)
print(f" Agent: {response}")
print()
tracer_provider.force_flush()
logger_provider.force_flush()
print("All traces and logs flushed to OTLP receiver.")
if __name__ == "__main__":
main()