narcolepticchicken commited on
Commit
0ec5e6d
·
verified ·
1 Parent(s): 7986a0b

Upload aco/benchmark.py

Browse files
Files changed (1) hide show
  1. aco/benchmark.py +175 -2
aco/benchmark.py CHANGED
@@ -1,2 +1,175 @@
1
- tier, use_tools, use_verifier = config(task)
2
- result = self.agent.run_task(task, tier, use_tools=use_tools, use_verifier=use_verifier)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ACO Benchmark Suite compares cost optimization configs across 5 task types."""
2
+
3
+ import json, time, hashlib, random
4
+ from typing import Dict, List, Tuple, Callable
5
+ from dataclasses import dataclass, field
6
+
7
+
8
+ @dataclass
9
+ class StepMetrics:
10
+ step_num: int; model_used: str; input_tokens: int; output_tokens: int
11
+ context_size: int = 0; tool_calls: int = 0; verifier_calls: int = 0
12
+ retries: int = 0; latency_ms: float = 0.0; cost_usd: float = 0.0
13
+
14
+ @dataclass
15
+ class TaskResult:
16
+ task_id: str; task_type: str; success: bool
17
+ steps: list = field(default_factory=list); total_cost_usd: float = 0.0
18
+ total_llm_calls: int = 0; total_tool_calls: int = 0; total_retries: int = 0
19
+ false_done: bool = False
20
+
21
+ @dataclass
22
+ class RunReport:
23
+ config_name: str; config_description: str = ""
24
+ results: list = field(default_factory=list)
25
+ @property
26
+ def success_rate(self):
27
+ return sum(1 for r in self.results if r.success)/max(len(self.results),1)
28
+ @property
29
+ def avg_cost_per_success(self):
30
+ s = [r.total_cost_usd for r in self.results if r.success]
31
+ return sum(s)/len(s) if s else float('inf')
32
+ @property
33
+ def avg_llm_calls(self):
34
+ return sum(r.total_llm_calls for r in self.results)/max(len(self.results),1)
35
+ @property
36
+ def avg_tool_calls(self):
37
+ return sum(r.total_tool_calls for r in self.results)/max(len(self.results),1)
38
+ @property
39
+ def false_done_rate(self):
40
+ return sum(1 for r in self.results if r.false_done)/max(len(self.results),1)
41
+
42
+
43
+ PRICING = {
44
+ "gpt-4.1-mini": (0.15, 0.60), "gpt-4o": (2.50, 10.0),
45
+ "claude-sonnet-4": (3.0, 15.0), "llama-3.1-8b": (0.06, 0.06),
46
+ "claude-haiku": (0.80, 4.0), "gemini-flash": (0.075, 0.30),
47
+ }
48
+ TIER_MODELS = {"cheap": "llama-3.1-8b", "medium": "gpt-4.1-mini", "frontier": "claude-sonnet-4"}
49
+ SUCCESS_RATES = {
50
+ "cheap": {"coding": 0.55, "research": 0.40, "tool_use": 0.50, "qa": 0.60, "long_horizon": 0.30},
51
+ "medium": {"coding": 0.78, "research": 0.65, "tool_use": 0.75, "qa": 0.85, "long_horizon": 0.55},
52
+ "frontier": {"coding": 0.92, "research": 0.85, "tool_use": 0.90, "qa": 0.95, "long_horizon": 0.80},
53
+ }
54
+ ALL_TASKS = {
55
+ "coding": [
56
+ ("code_1", "Write a Python function to sort a list of dicts by key", "easy"),
57
+ ("code_2", "Fix the race condition in this multithreaded queue", "hard"),
58
+ ("code_3", "Add input validation to all API endpoints", "medium"),
59
+ ("code_4", "Migrate from SQLAlchemy 1.4 to 2.0 async API", "hard"),
60
+ ("code_5", "Write unit tests for the User model", "medium"),
61
+ ],
62
+ "research": [
63
+ ("research_1", "What's the SOTA for cost-aware LLM routing?", "medium"),
64
+ ("research_2", "Find all papers about speculative decoding for agents", "hard"),
65
+ ("research_3", "How does Anthropic's prompt caching work?", "easy"),
66
+ ("research_4", "Survey test-time compute allocation 2023-2025", "hard"),
67
+ ("research_5", "What datasets exist for training agent cost routers?", "medium"),
68
+ ],
69
+ "tool_use": [
70
+ ("tool_1", "What's the weather in Paris today?", "easy"),
71
+ ("tool_2", "Find top 5 restaurants in Tokyo with ratings", "medium"),
72
+ ("tool_3", "Compare GDP of France and Germany over last decade", "medium"),
73
+ ("tool_4", "Translate 'hello' to Japanese", "easy"),
74
+ ("tool_5", "Compound interest on $10k at 5% over 20 years", "easy"),
75
+ ],
76
+ "qa": [
77
+ ("qa_1", "What is the capital of France?", "easy"),
78
+ ("qa_2", "Explain difference between TCP and UDP", "easy"),
79
+ ("qa_3", "GDPR Article 22 implications for automated decisions?", "hard"),
80
+ ("qa_4", "Review this contract for liability clauses", "hard"),
81
+ ("qa_5", "Summarize key findings from IPCC AR6 report", "medium"),
82
+ ],
83
+ "long_horizon": [
84
+ ("long_1", "Set up complete CI/CD pipeline for Python project", "hard"),
85
+ ("long_2", "Research, design, and implement a caching layer", "hard"),
86
+ ("long_3", "Write README, add tests, set up pre-commit hooks", "medium"),
87
+ ("long_4", "Migrate DB schema, update models, add rollback", "hard"),
88
+ ("long_5", "Audit codebase for security vulnerabilities, fix top 3", "hard"),
89
+ ],
90
+ }
91
+
92
+
93
+ class SimulatedAgent:
94
+ def __init__(self, seed=42):
95
+ self.rng = random.Random(seed)
96
+ def run_task(self, task_id, text, tier, task_type, difficulty, use_tools, use_verifier):
97
+ model = TIER_MODELS[tier]; ip, op = PRICING[model]
98
+ base_p = SUCCESS_RATES[tier].get(task_type, 0.7)
99
+ diff_m = {"easy": 1.15, "medium": 1.0, "hard": 0.80}
100
+ p = min(0.99, base_p * diff_m[difficulty])
101
+ nsteps = {"easy": self.rng.randint(1,3), "medium": self.rng.randint(2,5), "hard": self.rng.randint(3,8)}[difficulty]
102
+ result = TaskResult(task_id=task_id, task_type=task_type, success=False)
103
+ for i in range(nsteps):
104
+ it = self.rng.randint(200,3000); ot = self.rng.randint(50,1500)
105
+ tc = self.rng.randint(0,3) if use_tools else 0
106
+ tf = self.rng.randint(0,1) if tc>0 else 0
107
+ vc = 1 if use_verifier else 0
108
+ rt = self.rng.randint(0,2) if tf>0 else 0
109
+ cost = it/1e6*ip + ot/1e6*op
110
+ result.steps.append(StepMetrics(i+1, model, it, ot, it+ot, tc, vc, rt, it*2+ot*10, cost))
111
+ result.total_cost_usd += cost; result.total_llm_calls += 1
112
+ result.total_tool_calls += tc; result.total_retries += rt
113
+ result.success = self.rng.random() < (p * (1 - 0.03*result.total_retries))
114
+ return result
115
+
116
+
117
+ class BenchmarkRunner:
118
+ def __init__(self, agent=None):
119
+ self.agent = agent or SimulatedAgent()
120
+ self.reports = {}
121
+ def run_config(self, name, desc, router_fn):
122
+ report = RunReport(name, desc)
123
+ for task_type, tasks in ALL_TASKS.items():
124
+ for tid, text, diff in tasks:
125
+ tier, tools, verifier = router_fn(text, diff, task_type)
126
+ result = self.agent.run_task(tid, text, tier, task_type, diff, tools, verifier)
127
+ report.results.append(result)
128
+ self.reports[name] = report
129
+ return report
130
+ def run_all_baselines(self):
131
+ self.run_config("A_always_frontier", "Frontier + tools + verifier",
132
+ lambda t,d,tt: ("frontier", True, True))
133
+ self.run_config("B_always_cheap", "Cheap model, no tools",
134
+ lambda t,d,tt: ("cheap", False, False))
135
+ self.run_config("C_static_routing", "Static: easy→cheap, medium→medium, hard→frontier",
136
+ lambda t,d,tt: ({"easy":"cheap","medium":"medium","hard":"frontier"}[d],
137
+ d!="easy", d=="hard"))
138
+ self.run_config("D_prompt_router", "Keyword-based heuristic routing",
139
+ lambda t,d,tt: self._prompt_route(t, d, tt))
140
+ def _prompt_route(self, text, diff, tt):
141
+ t = text.lower()
142
+ if any(k in t for k in ["fix","debug","migrate","critical","vulnerability"]):
143
+ return ("frontier", True, True)
144
+ if any(k in t for k in ["test","add","write","survey","find","setup"]):
145
+ return ("medium", True, False)
146
+ return ("cheap", False, False)
147
+ def compare(self):
148
+ if "A_always_frontier" not in self.reports: return {}
149
+ bl = self.reports["A_always_frontier"]
150
+ bs = bl.success_rate; bc = bl.avg_cost_per_success
151
+ comp = {}
152
+ for name, rpt in self.reports.items():
153
+ sr = rpt.success_rate; cs = rpt.avg_cost_per_success
154
+ cr = ((bc-cs)/bc*100) if sr >= bs*0.95 else None
155
+ comp[name] = {"success": f"{sr:.1%}", "cost_per_success": f"${cs:.4f}",
156
+ "cost_reduction": f"{cr:.1f}%" if cr else "N/A",
157
+ "llm_calls": f"{rpt.avg_llm_calls:.1f}",
158
+ "tool_calls": f"{rpt.avg_tool_calls:.1f}",
159
+ "false_done": f"{rpt.false_done_rate:.1%}"}
160
+ return comp
161
+ def print_report(self):
162
+ comp = self.compare()
163
+ print(f"\n{'='*100}")
164
+ print("ACO BENCHMARK COMPARISON (25 tasks)")
165
+ print(f"{'='*100}")
166
+ print(f"{'Config':<25} {'Success':>8} {'Cost/Success':>13} {'Reduction':>12} {'LLM':>6} {'Tools':>7} {'FalseDONE':>10}")
167
+ print("-"*100)
168
+ for n,s in comp.items():
169
+ print(f"{n:<25} {s['success']:>8} {s['cost_per_success']:>13} {s['cost_reduction']:>12} {s['llm_calls']:>6} {s['tool_calls']:>7} {s['false_done']:>10}")
170
+ print("="*100)
171
+
172
+ if __name__ == "__main__":
173
+ runner = BenchmarkRunner()
174
+ runner.run_all_baselines()
175
+ runner.print_report()