Files
tracer-cloud--opensre/tests/benchmarks/toolcall_model_benchmark/pipeline_benchmark.py
T
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

241 lines
7.8 KiB
Python

"""Investigation pipeline benchmark: baseline vs split tool LLM routing.
Uses the same ``run_investigation`` entry point as production, injects synthetic
Grafana fixtures (no Tracer JWT required), and tracks token usage by
instrumenting API creates.
"""
from __future__ import annotations
import time
from collections.abc import Callable
from contextlib import contextmanager
from dataclasses import dataclass, field
from typing import Any
from core.llm import factory
from core.llm.factory import LLMRole, get_llm, reset_llm_clients
from core.llm.transports.sdk.llm_clients import LLMClient, OpenAILLMClient
from core.state import AgentState
from tests.benchmarks.toolcall_model_benchmark.pricing import estimate_run_cost_usd
from tests.synthetic.rds_postgres.run_suite import _build_resolved_integrations
from tests.synthetic.rds_postgres.scenario_loader import (
SUITE_DIR,
ScenarioFixture,
load_all_scenarios,
)
from tools.investigation.capability import run_investigation
from tools.investigation.state_factory import make_initial_state
__all__ = [
"LLMCallRecord",
"InvestigationBenchmarkRun",
"TokenTotals",
"configure_baseline_reasoning_for_tools",
"configure_split_models",
"estimate_run_cost_usd",
"get_fixture_by_id",
"make_investigation_state",
"reset_llm_singletons",
"run_investigation_bench",
]
@dataclass
class TokenTotals:
"""Accumulated LLM token usage (all providers summed into one counter)."""
input_tokens: int = 0
output_tokens: int = 0
@property
def total(self) -> int:
return self.input_tokens + self.output_tokens
@dataclass(frozen=True)
class LLMCallRecord:
"""One provider API completion (after retries succeed for that attempt)."""
call_index: int
model_id: str
input_tokens: int
output_tokens: int
latency_sec: float
@property
def total_tokens(self) -> int:
return self.input_tokens + self.output_tokens
@dataclass
class InvestigationBenchmarkRun:
label: str
wall_seconds: float
tokens: TokenTotals
tokens_by_model: dict[str, TokenTotals] = field(default_factory=dict)
llm_calls: list[LLMCallRecord] = field(default_factory=list)
final_state: dict[str, Any] = field(default_factory=dict)
def reset_llm_singletons() -> None:
"""Reset the cached LLM clients; delegates to core.llm.factory.reset_llm_clients."""
reset_llm_clients()
def configure_split_models() -> None:
"""Production-style split: reasoning model + separate toolcall model."""
reset_llm_singletons()
get_llm(LLMRole.REASONING)
get_llm(LLMRole.TOOLCALL)
def configure_baseline_reasoning_for_tools() -> None:
"""Ablation: tool nodes use the same client instance as reasoning."""
reset_llm_singletons()
reasoning = get_llm(LLMRole.REASONING)
factory._cache.store(LLMRole.TOOLCALL, reasoning)
def make_investigation_state(fixture: ScenarioFixture) -> AgentState:
alert = fixture.alert
return make_initial_state(raw_alert=alert)
def _add_usage(
totals: TokenTotals,
by_model: dict[str, TokenTotals],
model_key: str,
inp: int,
out: int,
) -> None:
totals.input_tokens += inp
totals.output_tokens += out
bucket = by_model.setdefault(model_key, TokenTotals())
bucket.input_tokens += inp
bucket.output_tokens += out
@contextmanager
def _track_llm_usage(
totals: TokenTotals,
tokens_by_model: dict[str, TokenTotals],
llm_calls: list[LLMCallRecord],
) -> Any:
"""Count tokens and record one row per successful API completion (incl. latency)."""
orig_anthropic = LLMClient.invoke
orig_openai = OpenAILLMClient.invoke
def anthropic_invoke(self: Any, prompt_or_messages: Any) -> Any:
self._ensure_client()
real_create = self._client.messages.create
def wrapped_create(*args: Any, **kwargs: Any) -> Any:
t0 = time.perf_counter()
resp = real_create(*args, **kwargs)
lat = time.perf_counter() - t0
u = getattr(resp, "usage", None)
if u is not None:
inp = int(getattr(u, "input_tokens", 0) or 0)
out = int(getattr(u, "output_tokens", 0) or 0)
model_key = str(kwargs.get("model") or getattr(self, "_model", "") or "unknown")
_add_usage(totals, tokens_by_model, model_key, inp, out)
llm_calls.append(
LLMCallRecord(
call_index=len(llm_calls) + 1,
model_id=model_key,
input_tokens=inp,
output_tokens=out,
latency_sec=lat,
)
)
return resp
self._client.messages.create = wrapped_create # type: ignore[method-assign]
try:
return orig_anthropic(self, prompt_or_messages)
finally:
self._client.messages.create = real_create # type: ignore[method-assign]
def openai_invoke(self: Any, prompt_or_messages: Any) -> Any:
self._ensure_client()
real_create = self._client.chat.completions.create
def wrapped_create(*args: Any, **kwargs: Any) -> Any:
t0 = time.perf_counter()
resp = real_create(*args, **kwargs)
lat = time.perf_counter() - t0
u = resp.usage
if u is not None:
inp = int(u.prompt_tokens or 0)
out = int(u.completion_tokens or 0)
model_key = str(kwargs.get("model") or getattr(self, "_model", "") or "unknown")
_add_usage(totals, tokens_by_model, model_key, inp, out)
llm_calls.append(
LLMCallRecord(
call_index=len(llm_calls) + 1,
model_id=model_key,
input_tokens=inp,
output_tokens=out,
latency_sec=lat,
)
)
return resp
self._client.chat.completions.create = wrapped_create # type: ignore[method-assign]
try:
return orig_openai(self, prompt_or_messages)
finally:
self._client.chat.completions.create = real_create # type: ignore[method-assign]
LLMClient.invoke = anthropic_invoke # type: ignore[assignment]
OpenAILLMClient.invoke = openai_invoke # type: ignore[assignment]
try:
yield
finally:
LLMClient.invoke = orig_anthropic # type: ignore[assignment]
OpenAILLMClient.invoke = orig_openai # type: ignore[assignment]
def run_investigation_bench(
fixture: ScenarioFixture,
*,
label: str,
configure_llm: Callable[[], None],
) -> InvestigationBenchmarkRun:
"""Run one full investigation for a synthetic RDS scenario; return timing + tokens."""
resolved = _build_resolved_integrations(fixture, use_mock_grafana=True)
assert resolved is not None
alert = fixture.alert
totals = TokenTotals()
tokens_by_model: dict[str, TokenTotals] = {}
llm_calls: list[LLMCallRecord] = []
configure_llm()
with _track_llm_usage(totals, tokens_by_model, llm_calls):
t0 = time.perf_counter()
out = run_investigation(alert, resolved_integrations=resolved)
elapsed = time.perf_counter() - t0
out_dict = dict(out) if isinstance(out, dict) else {}
return InvestigationBenchmarkRun(
label=label,
wall_seconds=elapsed,
tokens=totals,
tokens_by_model=dict(tokens_by_model),
llm_calls=list(llm_calls),
final_state=out_dict,
)
def get_fixture_by_id(scenario_id: str) -> ScenarioFixture:
fixtures = load_all_scenarios(SUITE_DIR)
for f in fixtures:
if f.scenario_id == scenario_id:
return f
raise ValueError(
f"Unknown scenario_id: {scenario_id!r}. Loaded {len(fixtures)} scenarios from {SUITE_DIR}."
)