Skip to content

Commit 4e92c82

Browse files
add zero code exemples for anthropic
1 parent 22bbedf commit 4e92c82

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)