Spaces:
Running
Running
| from __future__ import annotations | |
| import heapq | |
| import math | |
| import random | |
| from dataclasses import asdict, dataclass | |
| from statistics import mean | |
| from typing import Any | |
| from .latency import AnalyticalLatencyModel | |
| from .metrics import percentile | |
| from .profiles import get_accelerator, get_model | |
| AGENT_ROLES = ("planner", "retriever", "reasoner", "verifier", "writer") | |
| END = "END" | |
| ROLE_PREFIX_TOKENS = { | |
| "planner": 512, | |
| "retriever": 768, | |
| "reasoner": 896, | |
| "verifier": 640, | |
| "writer": 576, | |
| } | |
| # Structured workflow transitions used to make online execution learning | |
| # meaningful. Rows sum to one. The shifted matrix changes the mix of external | |
| # retrieval/verification work without changing the model or hardware profile. | |
| BASE_TRANSITIONS: dict[str, dict[str, float]] = { | |
| "planner": {"retriever": 0.52, "reasoner": 0.28, "writer": 0.12, END: 0.08}, | |
| "retriever": {"reasoner": 0.50, "verifier": 0.20, "retriever": 0.10, "writer": 0.12, END: 0.08}, | |
| "reasoner": {"verifier": 0.32, "retriever": 0.18, "writer": 0.30, "reasoner": 0.10, END: 0.10}, | |
| "verifier": {"reasoner": 0.24, "retriever": 0.12, "writer": 0.34, END: 0.30}, | |
| "writer": {"verifier": 0.22, "reasoner": 0.10, "retriever": 0.05, END: 0.63}, | |
| } | |
| SHIFTED_TRANSITIONS: dict[str, dict[str, float]] = { | |
| "planner": {"retriever": 0.72, "reasoner": 0.14, "writer": 0.06, END: 0.08}, | |
| "retriever": {"reasoner": 0.30, "verifier": 0.30, "retriever": 0.24, "writer": 0.08, END: 0.08}, | |
| "reasoner": {"verifier": 0.24, "retriever": 0.36, "writer": 0.18, "reasoner": 0.12, END: 0.10}, | |
| "verifier": {"reasoner": 0.18, "retriever": 0.28, "writer": 0.24, END: 0.30}, | |
| "writer": {"verifier": 0.34, "reasoner": 0.08, "retriever": 0.10, END: 0.48}, | |
| } | |
| ROLE_GAP_MULTIPLIERS = { | |
| "planner": 0.35, | |
| "retriever": 1.45, | |
| "reasoner": 0.55, | |
| "verifier": 0.75, | |
| "writer": 0.30, | |
| } | |
| PREFETCH_POLICIES = {"none", "cumulative", "decayed", "multistep", "utility", "oracle", "oracle_horizon"} | |
| class ExecutionLearningConfig: | |
| model: str = "Qwen2.5-3B" | |
| accelerator: str = "L4" | |
| quantization: str = "int8" | |
| seed: int = 7 | |
| duration_s: float = 120.0 | |
| workflow_rate_rps: float = 0.18 | |
| dynamic_prompt_tokens_mean: int = 320 | |
| dynamic_prompt_cv: float = 0.40 | |
| output_tokens_mean: int = 64 | |
| output_tokens_cv: float = 0.45 | |
| tool_gap_mean_s: float = 1.2 | |
| tool_gap_cv: float = 0.65 | |
| max_steps: int = 8 | |
| shift_fraction: float = 0.55 | |
| prefix_cache_budget_fraction: float = 0.62 | |
| host_bandwidth_gbps: float = 32.0 | |
| transfer_base_ms: float = 0.15 | |
| prefetch_policy: str = "decayed" | |
| transition_decay: float = 0.85 | |
| confidence_threshold: float = 0.55 | |
| prior_strength: float = 0.35 | |
| forecast_horizon: int = 3 | |
| prefetch_top_k: int = 2 | |
| forecast_discount: float = 0.75 | |
| forecast_min_score: float = 0.10 | |
| utility_threshold_ms: float = 0.0 | |
| timeline_points: int = 240 | |
| def from_dict(cls, data: dict[str, Any]) -> "ExecutionLearningConfig": | |
| allowed = cls.__dataclass_fields__.keys() | |
| cfg = cls(**{key: data[key] for key in allowed if key in data}) | |
| cfg.duration_s = max(float(cfg.duration_s), 20.0) | |
| cfg.workflow_rate_rps = max(float(cfg.workflow_rate_rps), 0.01) | |
| cfg.max_steps = max(2, min(int(cfg.max_steps), 16)) | |
| cfg.shift_fraction = min(max(float(cfg.shift_fraction), 0.05), 0.95) | |
| cfg.prefix_cache_budget_fraction = min(max(float(cfg.prefix_cache_budget_fraction), 0.10), 1.50) | |
| cfg.host_bandwidth_gbps = max(float(cfg.host_bandwidth_gbps), 0.1) | |
| cfg.transfer_base_ms = max(float(cfg.transfer_base_ms), 0.0) | |
| cfg.transition_decay = min(max(float(cfg.transition_decay), 0.20), 1.0) | |
| cfg.confidence_threshold = min(max(float(cfg.confidence_threshold), 0.0), 1.0) | |
| cfg.prior_strength = max(float(cfg.prior_strength), 0.01) | |
| cfg.forecast_horizon = max(1, min(int(cfg.forecast_horizon), 6)) | |
| cfg.prefetch_top_k = max(1, min(int(cfg.prefetch_top_k), len(AGENT_ROLES))) | |
| cfg.forecast_discount = min(max(float(cfg.forecast_discount), 0.05), 1.0) | |
| cfg.forecast_min_score = min(max(float(cfg.forecast_min_score), 0.0), 1.0) | |
| cfg.utility_threshold_ms = float(cfg.utility_threshold_ms) | |
| cfg.timeline_points = max(40, min(int(cfg.timeline_points), 1000)) | |
| if cfg.prefetch_policy not in PREFETCH_POLICIES: | |
| raise ValueError(f"Unsupported execution prefetch policy: {cfg.prefetch_policy}") | |
| return cfg | |
| def to_dict(self) -> dict[str, Any]: | |
| return asdict(self) | |
| class WorkflowStep: | |
| role: str | |
| dynamic_prompt_tokens: int | |
| output_tokens: int | |
| gap_after_s: float | |
| shifted_regime: bool | |
| class WorkflowSpec: | |
| workflow_id: int | |
| arrival_time: float | |
| steps: list[WorkflowStep] | |
| class PrefixEntry: | |
| role: str | |
| size_gb: float | |
| last_access: float | |
| available_time: float | |
| source: str | |
| generation: int | |
| used: bool = False | |
| class OnlineTransitionPredictor: | |
| """First-order online execution model with optional exponential forgetting. | |
| The predictor never observes a transition before the next role is revealed. | |
| ``decay=1`` is cumulative counting. Smaller values forget older transitions | |
| and can adapt after a workflow-regime shift. | |
| """ | |
| def __init__(self, *, decay: float = 0.85, prior_strength: float = 0.35) -> None: | |
| self.decay = min(max(float(decay), 0.20), 1.0) | |
| self.prior_strength = max(float(prior_strength), 0.01) | |
| self.targets = (*AGENT_ROLES, END) | |
| self.rows: dict[str, dict[str, float]] = { | |
| role: {target: self.prior_strength for target in self.targets} | |
| for role in AGENT_ROLES | |
| } | |
| self.observations = 0 | |
| def predict(self, current_role: str) -> tuple[str, float, dict[str, float]]: | |
| row = self.rows[current_role] | |
| total = sum(row.values()) or 1.0 | |
| probabilities = {target: value / total for target, value in row.items()} | |
| best = max(self.targets, key=lambda target: (probabilities[target], -self.targets.index(target))) | |
| return best, probabilities[best], probabilities | |
| def forecast( | |
| self, | |
| current_role: str, | |
| *, | |
| horizon: int = 3, | |
| discount: float = 0.75, | |
| ) -> dict[str, Any]: | |
| """Roll the learned first-order matrix forward without future trace access. | |
| ``role_scores`` are discounted expected future visits, not calibrated | |
| probabilities of at-least-one reuse. They are therefore used as a | |
| ranking signal and are normalized separately for UI/decision thresholds. | |
| """ | |
| horizon = max(1, min(int(horizon), 8)) | |
| discount = min(max(float(discount), 0.0), 1.0) | |
| distributions: list[dict[str, float]] = [] | |
| current: dict[str, float] = {target: 0.0 for target in self.targets} | |
| current[current_role] = 1.0 | |
| role_scores = {role: 0.0 for role in AGENT_ROLES} | |
| for depth in range(1, horizon + 1): | |
| nxt = {target: 0.0 for target in self.targets} | |
| for source, mass in current.items(): | |
| if mass <= 0.0: | |
| continue | |
| if source == END: | |
| nxt[END] += mass | |
| continue | |
| _, _, probs = self.predict(source) | |
| for target, probability in probs.items(): | |
| nxt[target] += mass * probability | |
| distributions.append(nxt) | |
| weight = discount ** (depth - 1) | |
| for role in AGENT_ROLES: | |
| role_scores[role] += weight * nxt.get(role, 0.0) | |
| current = nxt | |
| total_score = sum(role_scores.values()) | |
| normalized = { | |
| role: (score / total_score if total_score > 1e-12 else 0.0) | |
| for role, score in role_scores.items() | |
| } | |
| ranked = sorted(AGENT_ROLES, key=lambda role: (-role_scores[role], role)) | |
| return { | |
| "horizon": horizon, | |
| "discount": discount, | |
| "distributions": distributions, | |
| "role_scores": role_scores, | |
| "normalized_scores": normalized, | |
| "ranked_roles": ranked, | |
| } | |
| def observe(self, current_role: str, next_role: str) -> None: | |
| row = self.rows[current_role] | |
| if self.decay < 1.0: | |
| for target in self.targets: | |
| row[target] = max(self.prior_strength * 0.05, row[target] * self.decay) | |
| row[next_role] = row.get(next_role, 0.0) + 1.0 | |
| self.observations += 1 | |
| def snapshot(self) -> dict[str, Any]: | |
| matrix = {} | |
| for role in AGENT_ROLES: | |
| _, _, probs = self.predict(role) | |
| matrix[role] = probs | |
| return { | |
| "decay": self.decay, | |
| "prior_strength": self.prior_strength, | |
| "observations": self.observations, | |
| "probabilities": matrix, | |
| } | |
| def _sample_positive_lognormal(rng: random.Random, mean_value: float, cv: float, minimum: float) -> float: | |
| mean_value = max(float(mean_value), minimum) | |
| cv = max(float(cv), 0.0) | |
| if cv <= 1e-12: | |
| return mean_value | |
| sigma2 = math.log1p(cv * cv) | |
| sigma = math.sqrt(sigma2) | |
| mu = math.log(max(mean_value, 1e-9)) - sigma2 / 2.0 | |
| return max(minimum, rng.lognormvariate(mu, sigma)) | |
| def _sample_int(rng: random.Random, mean_value: float, cv: float, minimum: int = 1) -> int: | |
| return max(minimum, int(round(_sample_positive_lognormal(rng, mean_value, cv, float(minimum))))) | |
| def _sample_transition(rng: random.Random, role: str, shifted: bool) -> str: | |
| matrix = SHIFTED_TRANSITIONS if shifted else BASE_TRANSITIONS | |
| row = matrix[role] | |
| targets = tuple(row) | |
| return rng.choices(targets, weights=[row[target] for target in targets], k=1)[0] | |
| def generate_workflows(cfg: ExecutionLearningConfig) -> list[WorkflowSpec]: | |
| rng = random.Random(cfg.seed ^ 0xE91A7) | |
| workflows: list[WorkflowSpec] = [] | |
| now = 0.0 | |
| workflow_id = 0 | |
| while True: | |
| now += rng.expovariate(cfg.workflow_rate_rps) | |
| if now > cfg.duration_s: | |
| break | |
| shifted = now >= cfg.duration_s * cfg.shift_fraction | |
| role = "planner" | |
| steps: list[WorkflowStep] = [] | |
| for step_idx in range(cfg.max_steps): | |
| dynamic_prompt = _sample_int(rng, cfg.dynamic_prompt_tokens_mean, cfg.dynamic_prompt_cv, 32) | |
| output = _sample_int(rng, cfg.output_tokens_mean, cfg.output_tokens_cv, 1) | |
| next_role = _sample_transition(rng, role, shifted) | |
| if next_role == END or step_idx == cfg.max_steps - 1: | |
| gap = 0.0 | |
| else: | |
| mean_gap = cfg.tool_gap_mean_s * ROLE_GAP_MULTIPLIERS.get(next_role, 1.0) | |
| if shifted and next_role in {"retriever", "verifier"}: | |
| mean_gap *= 1.35 | |
| gap = _sample_positive_lognormal(rng, mean_gap, cfg.tool_gap_cv, 0.0) | |
| steps.append(WorkflowStep(role, dynamic_prompt, output, gap, shifted)) | |
| if next_role == END or step_idx == cfg.max_steps - 1: | |
| break | |
| role = next_role | |
| workflows.append(WorkflowSpec(workflow_id, now, steps)) | |
| workflow_id += 1 | |
| return workflows | |
| def _prediction_calibration(rows: list[dict[str, Any]], bins: int = 10) -> dict[str, Any]: | |
| if not rows: | |
| return {"count": 0, "brier": 0.0, "log_loss": 0.0, "ece": 0.0, "bins": []} | |
| targets = (*AGENT_ROLES, END) | |
| brier_total = 0.0 | |
| log_total = 0.0 | |
| buckets: list[list[tuple[float, float]]] = [[] for _ in range(max(2, bins))] | |
| for row in rows: | |
| probs = row.get("probabilities", {}) | |
| actual = str(row.get("actual_next_role", END)) | |
| brier_total += sum((float(probs.get(target, 0.0)) - (1.0 if target == actual else 0.0)) ** 2 for target in targets) | |
| actual_p = max(float(probs.get(actual, 0.0)), 1e-12) | |
| log_total += -math.log(actual_p) | |
| confidence = min(max(float(row.get("confidence", 0.0)), 0.0), 1.0) | |
| correct = 1.0 if row.get("prediction_correct") else 0.0 | |
| index = min(int(confidence * len(buckets)), len(buckets) - 1) | |
| buckets[index].append((confidence, correct)) | |
| ece = 0.0 | |
| rendered = [] | |
| for index, bucket in enumerate(buckets): | |
| if not bucket: | |
| continue | |
| avg_conf = mean(value[0] for value in bucket) | |
| accuracy = mean(value[1] for value in bucket) | |
| weight = len(bucket) / len(rows) | |
| ece += weight * abs(avg_conf - accuracy) | |
| rendered.append( | |
| { | |
| "lower": index / len(buckets), | |
| "upper": (index + 1) / len(buckets), | |
| "count": len(bucket), | |
| "mean_confidence": avg_conf, | |
| "accuracy": accuracy, | |
| } | |
| ) | |
| return { | |
| "count": len(rows), | |
| "brier": brier_total / len(rows), | |
| "log_loss": log_total / len(rows), | |
| "ece": ece, | |
| "bins": rendered, | |
| } | |
| class ExecutionLearningSimulator: | |
| """Reference simulator for online workflow learning and prefix prefetch. | |
| This lab intentionally isolates cross-workflow *agent-prefix* caching from the | |
| session-KV simulator. It uses one serial compute station plus one serialized | |
| prefix-transfer link and a bounded shared HBM prefix cache. Static agent | |
| prefixes are always available in the modeled host tier; policy decisions | |
| determine whether likely next prefixes are prefetched into HBM during gaps. | |
| """ | |
| def __init__(self, cfg: ExecutionLearningConfig, workflows: list[WorkflowSpec] | None = None): | |
| self.cfg = cfg | |
| self.model = get_model(cfg.model) | |
| self.accelerator = get_accelerator(cfg.accelerator) | |
| self.latency = AnalyticalLatencyModel(self.model, self.accelerator, cfg.quantization) | |
| self.workflows = workflows if workflows is not None else generate_workflows(cfg) | |
| self.predictor = OnlineTransitionPredictor(decay=cfg.transition_decay, prior_strength=cfg.prior_strength) | |
| self.events: list[tuple[float, int, str, tuple[Any, ...]]] = [] | |
| self.event_seq = 0 | |
| self.now = 0.0 | |
| self.server_busy_until = 0.0 | |
| self.transfer_busy_until = 0.0 | |
| self.queue: list[tuple[int, int, float]] = [] | |
| self.cache: dict[str, PrefixEntry] = {} | |
| self.prefix_source: dict[str, str] = {} | |
| self.pending_predictions: dict[tuple[int, int], dict[str, Any]] = {} | |
| self.step_rows: list[dict[str, Any]] = [] | |
| self.prediction_rows: list[dict[str, Any]] = [] | |
| self.timeline: list[dict[str, Any]] = [] | |
| self.last_memory_time = 0.0 | |
| self.hbm_gb_seconds = 0.0 | |
| self.peak_hbm_gb = 0.0 | |
| self.pressure_evictions = 0 | |
| self.prefetch_attempts = 0 | |
| self.prefetch_correct = 0 | |
| self.prefetch_useful = 0 | |
| self.prefetch_bytes = 0.0 | |
| self.prefetch_useful_bytes = 0.0 | |
| self.unused_prefetch_bytes = 0.0 | |
| self.wrong_step_prefetch_bytes = 0.0 | |
| self.transfer_latencies_ms: list[float] = [] | |
| self.prefix_hits = 0 | |
| self.prefetch_hits = 0 | |
| self.prefill_tokens_saved = 0 | |
| self.workflow_completion: dict[int, float] = {} | |
| kv_bytes = self.latency.kv_bytes_per_token() | |
| self.role_size_gb = {role: ROLE_PREFIX_TOKENS[role] * kv_bytes / 1e9 for role in AGENT_ROLES} | |
| reference_working_set = sum(self.role_size_gb.values()) | |
| self.cache_capacity_gb = max(reference_working_set * cfg.prefix_cache_budget_fraction, min(self.role_size_gb.values())) | |
| for workflow in self.workflows: | |
| if workflow.steps: | |
| self._push(workflow.arrival_time, "step_ready", workflow.workflow_id, 0) | |
| def _push(self, when: float, kind: str, *payload: Any) -> None: | |
| self.event_seq += 1 | |
| heapq.heappush(self.events, (float(when), self.event_seq, kind, tuple(payload))) | |
| def _used_gb(self) -> float: | |
| return sum(entry.size_gb for entry in self.cache.values()) | |
| def _integrate_memory(self, new_time: float) -> None: | |
| new_time = max(float(new_time), self.last_memory_time) | |
| elapsed = new_time - self.last_memory_time | |
| self.hbm_gb_seconds += self._used_gb() * elapsed | |
| self.last_memory_time = new_time | |
| self.peak_hbm_gb = max(self.peak_hbm_gb, self._used_gb()) | |
| def _record_timeline(self) -> None: | |
| min_gap = max(self.cfg.duration_s / self.cfg.timeline_points, 0.08) | |
| if self.timeline and self.now - self.timeline[-1]["time_s"] < min_gap: | |
| return | |
| self.timeline.append( | |
| { | |
| "time_s": self.now, | |
| "queued_steps": len(self.queue), | |
| "server_busy": 1 if self.server_busy_until > self.now + 1e-12 else 0, | |
| "prefix_hbm_gb": self._used_gb(), | |
| "cached_roles": len(self.cache), | |
| "transfer_busy": 1 if self.transfer_busy_until > self.now + 1e-12 else 0, | |
| } | |
| ) | |
| if len(self.timeline) > self.cfg.timeline_points * 2: | |
| self.timeline = self.timeline[::2] | |
| def _mark_unused_prefetch(self, entry: PrefixEntry) -> None: | |
| if entry.source == "prefetch" and not entry.used: | |
| self.unused_prefetch_bytes += entry.size_gb * 1e9 | |
| def _candidate_eviction_cost_ms(self, role: str, forecast_scores: dict[str, float]) -> float: | |
| """Approximate downstream cost of evicting forecast-relevant cached prefixes.""" | |
| size_gb = self.role_size_gb[role] | |
| existing = self.cache.get(role) | |
| current_without = self._used_gb() - (existing.size_gb if existing else 0.0) | |
| overflow = max(0.0, current_without + size_gb - self.cache_capacity_gb) | |
| if overflow <= 1e-12: | |
| return 0.0 | |
| cost_ms = 0.0 | |
| reclaimed = 0.0 | |
| candidates = sorted( | |
| [entry for key, entry in self.cache.items() if key != role], | |
| key=lambda entry: (entry.last_access, entry.role), | |
| ) | |
| for victim in candidates: | |
| if reclaimed >= overflow - 1e-12: | |
| break | |
| reuse_score = max(float(forecast_scores.get(victim.role, 0.0)), 0.0) | |
| recompute_ms = self.latency.prefill_seconds([ROLE_PREFIX_TOKENS[victim.role]]) * 1000.0 | |
| cost_ms += reuse_score * recompute_ms | |
| reclaimed += victim.size_gb | |
| return cost_ms | |
| def _prefetch_utility_ms(self, role: str, forecast_scores: dict[str, float]) -> float: | |
| score = max(float(forecast_scores.get(role, 0.0)), 0.0) | |
| saved_ms = self.latency.prefill_seconds([ROLE_PREFIX_TOKENS[role]]) * 1000.0 | |
| transfer_ms = self.cfg.transfer_base_ms + self.role_size_gb[role] / self.cfg.host_bandwidth_gbps * 1000.0 | |
| eviction_ms = self._candidate_eviction_cost_ms(role, forecast_scores) | |
| return score * saved_ms - transfer_ms - eviction_ms | |
| def _evict_for(self, role: str, size_gb: float) -> bool: | |
| existing = self.cache.get(role) | |
| current_without_role = self._used_gb() - (existing.size_gb if existing else 0.0) | |
| if size_gb > self.cache_capacity_gb + 1e-12: | |
| return False | |
| while current_without_role + size_gb > self.cache_capacity_gb + 1e-12: | |
| candidates = [entry for key, entry in self.cache.items() if key != role] | |
| if not candidates: | |
| return False | |
| victim = min(candidates, key=lambda entry: (entry.last_access, entry.role)) | |
| self._integrate_memory(self.now) | |
| self._mark_unused_prefetch(victim) | |
| self.cache.pop(victim.role, None) | |
| self.prefix_source.pop(victim.role, None) | |
| self.pressure_evictions += 1 | |
| current_without_role = self._used_gb() - (existing.size_gb if existing and role in self.cache else 0.0) | |
| return True | |
| def _install_prefix(self, role: str, *, available_time: float, source: str) -> int | None: | |
| size_gb = self.role_size_gb[role] | |
| if not self._evict_for(role, size_gb): | |
| return None | |
| self._integrate_memory(self.now) | |
| previous = self.cache.get(role) | |
| if previous is not None: | |
| self._mark_unused_prefetch(previous) | |
| generation = (previous.generation + 1) if previous else 1 | |
| self.cache[role] = PrefixEntry(role, size_gb, self.now, available_time, source, generation) | |
| self.prefix_source[role] = source | |
| self.peak_hbm_gb = max(self.peak_hbm_gb, self._used_gb()) | |
| self._record_timeline() | |
| return generation | |
| def _prefetch(self, role: str) -> dict[str, Any]: | |
| entry = self.cache.get(role) | |
| if entry is not None: | |
| return {"attempted": False, "reason": "already_cached", "role": role, "available_time": entry.available_time} | |
| size_gb = self.role_size_gb[role] | |
| transfer_s = self.cfg.transfer_base_ms / 1000.0 + size_gb / self.cfg.host_bandwidth_gbps | |
| start = max(self.now, self.transfer_busy_until) | |
| available = start + transfer_s | |
| generation = self._install_prefix(role, available_time=available, source="prefetch") | |
| if generation is None: | |
| return {"attempted": False, "reason": "capacity_reject", "role": role, "available_time": available} | |
| self.transfer_busy_until = available | |
| self.prefetch_attempts += 1 | |
| self.prefetch_bytes += size_gb * 1e9 | |
| self.transfer_latencies_ms.append((available - self.now) * 1000.0) | |
| self._push(available, "prefetch_complete", role, generation) | |
| return {"attempted": True, "reason": "scheduled", "role": role, "available_time": available, "size_gb": size_gb} | |
| def _actual_next_role(self, workflow_id: int, step_index: int) -> str: | |
| workflow = self.workflows[workflow_id] | |
| if step_index + 1 >= len(workflow.steps): | |
| return END | |
| return workflow.steps[step_index + 1].role | |
| def _actual_future_roles(self, workflow_id: int, step_index: int, horizon: int) -> list[str]: | |
| workflow = self.workflows[workflow_id] | |
| roles = [step.role for step in workflow.steps[step_index + 1 : step_index + 1 + max(1, horizon)]] | |
| return roles | |
| def _planned_prefetch_roles( | |
| self, | |
| workflow_id: int, | |
| step_index: int, | |
| current_role: str, | |
| ) -> tuple[str, float, dict[str, float], dict[str, Any], list[dict[str, Any]]]: | |
| actual_next = self._actual_next_role(workflow_id, step_index) | |
| predicted_role, confidence, probabilities = self.predictor.predict(current_role) | |
| forecast = self.predictor.forecast( | |
| current_role, | |
| horizon=self.cfg.forecast_horizon, | |
| discount=self.cfg.forecast_discount, | |
| ) | |
| plans: list[dict[str, Any]] = [] | |
| if self.cfg.prefetch_policy == "oracle": | |
| predicted_role = actual_next | |
| confidence = 1.0 | |
| probabilities = {target: 0.0 for target in (*AGENT_ROLES, END)} | |
| probabilities[predicted_role] = 1.0 | |
| if actual_next != END: | |
| plans = [{"role": actual_next, "score": 1.0, "utility_ms": None, "oracle": True}] | |
| return predicted_role, confidence, probabilities, forecast, plans | |
| if self.cfg.prefetch_policy == "oracle_horizon": | |
| actual_future = self._actual_future_roles(workflow_id, step_index, self.cfg.forecast_horizon) | |
| predicted_role = actual_next | |
| confidence = 1.0 | |
| probabilities = {target: 0.0 for target in (*AGENT_ROLES, END)} | |
| probabilities[predicted_role] = 1.0 | |
| seen: set[str] = set() | |
| for role in actual_future: | |
| if role not in seen: | |
| plans.append({"role": role, "score": 1.0, "utility_ms": None, "oracle": True}) | |
| seen.add(role) | |
| if len(plans) >= self.cfg.prefetch_top_k: | |
| break | |
| return predicted_role, confidence, probabilities, forecast, plans | |
| if self.cfg.prefetch_policy in {"none", "cumulative", "decayed"}: | |
| if self.cfg.prefetch_policy != "none" and predicted_role != END and confidence >= self.cfg.confidence_threshold: | |
| plans = [{"role": predicted_role, "score": confidence, "utility_ms": None, "oracle": False}] | |
| return predicted_role, confidence, probabilities, forecast, plans | |
| ranked = forecast["ranked_roles"] | |
| normalized = forecast["normalized_scores"] | |
| raw_scores = forecast["role_scores"] | |
| for role in ranked: | |
| if len(plans) >= self.cfg.prefetch_top_k: | |
| break | |
| normalized_score = float(normalized.get(role, 0.0)) | |
| if normalized_score < self.cfg.forecast_min_score: | |
| continue | |
| utility_ms = self._prefetch_utility_ms(role, raw_scores) | |
| if self.cfg.prefetch_policy == "utility" and utility_ms < self.cfg.utility_threshold_ms: | |
| continue | |
| plans.append( | |
| { | |
| "role": role, | |
| "score": normalized_score, | |
| "raw_score": float(raw_scores.get(role, 0.0)), | |
| "utility_ms": utility_ms, | |
| "oracle": False, | |
| } | |
| ) | |
| return predicted_role, confidence, probabilities, forecast, plans | |
| def _schedule_prediction(self, workflow_id: int, step_index: int, current_role: str) -> None: | |
| actual_next = self._actual_next_role(workflow_id, step_index) | |
| predicted_role, confidence, probabilities, forecast, plans = self._planned_prefetch_roles( | |
| workflow_id, step_index, current_role | |
| ) | |
| attempted_roles: list[str] = [] | |
| attempt_sizes: dict[str, float] = {} | |
| attempt_reasons: dict[str, str] = {} | |
| for plan in plans: | |
| role = str(plan["role"]) | |
| result = self._prefetch(role) | |
| attempt_reasons[role] = str(result.get("reason", "unknown")) | |
| if result.get("attempted"): | |
| attempted_roles.append(role) | |
| attempt_sizes[role] = float(result.get("size_gb", 0.0)) | |
| if self.cfg.prefetch_policy == "none": | |
| decision_reason = "learn_only" | |
| elif not plans: | |
| decision_reason = "no_candidate" | |
| elif attempted_roles: | |
| decision_reason = "scheduled" | |
| else: | |
| decision_reason = ",".join(sorted(set(attempt_reasons.values()))) or "not_scheduled" | |
| self.pending_predictions[(workflow_id, step_index)] = { | |
| "workflow_id": workflow_id, | |
| "step_index": step_index + 1, | |
| "current_role": current_role, | |
| "predicted_role": predicted_role, | |
| "confidence": confidence, | |
| "probabilities": probabilities, | |
| "forecast_horizon": self.cfg.forecast_horizon, | |
| "forecast_discount": self.cfg.forecast_discount, | |
| "forecast_role_scores": forecast["role_scores"], | |
| "forecast_normalized_scores": forecast["normalized_scores"], | |
| "forecast_roles": [str(plan["role"]) for plan in plans], | |
| "forecast_plans": plans, | |
| "prefetch_attempted": bool(attempted_roles), | |
| "prefetch_roles": attempted_roles, | |
| "prefetch_reasons": attempt_reasons, | |
| "prefetch_reason": decision_reason, | |
| "prefetch_sizes_gb": attempt_sizes, | |
| "prefetch_size_gb": sum(attempt_sizes.values()), | |
| "shifted_regime": self.workflows[workflow_id].steps[step_index].shifted_regime, | |
| } | |
| if actual_next == END: | |
| self._observe_transition(workflow_id, step_index, actual_next) | |
| def _observe_transition(self, workflow_id: int, step_index: int, actual_next: str) -> None: | |
| key = (workflow_id, step_index) | |
| pending = self.pending_predictions.pop(key, None) | |
| workflow = self.workflows[workflow_id] | |
| current_role = workflow.steps[step_index].role | |
| if pending is None: | |
| return | |
| predicted_role = str(pending["predicted_role"]) | |
| attempted_roles = [str(role) for role in pending.get("prefetch_roles", [])] | |
| correct = predicted_role == actual_next | |
| if actual_next != END and actual_next in attempted_roles: | |
| self.prefetch_correct += 1 | |
| immediate_wrong_bytes = 0.0 | |
| for role in attempted_roles: | |
| if role != actual_next: | |
| immediate_wrong_bytes += float(pending.get("prefetch_sizes_gb", {}).get(role, 0.0)) * 1e9 | |
| self.wrong_step_prefetch_bytes += immediate_wrong_bytes | |
| future_roles = self._actual_future_roles(workflow_id, step_index, int(pending.get("forecast_horizon", 1))) | |
| actual_future_set = set(future_roles) | |
| forecast_roles = [str(role) for role in pending.get("forecast_roles", [])] | |
| forecast_set = set(forecast_roles) | |
| forecast_recall = ( | |
| len(actual_future_set & forecast_set) / len(actual_future_set) | |
| if actual_future_set | |
| else None | |
| ) | |
| self.prediction_rows.append( | |
| pending | |
| | { | |
| "actual_next_role": actual_next, | |
| "actual_future_roles": future_roles, | |
| "prediction_correct": correct, | |
| "forecast_next_hit": actual_next in forecast_set if actual_next != END else predicted_role == END, | |
| "forecast_recall": forecast_recall, | |
| "immediate_wrong_prefetch_gb": immediate_wrong_bytes / 1e9, | |
| "post_shift": bool(pending["shifted_regime"]), | |
| } | |
| ) | |
| if self.cfg.prefetch_policy not in {"oracle", "oracle_horizon"}: | |
| self.predictor.observe(current_role, actual_next) | |
| def _start_next(self) -> None: | |
| if self.server_busy_until > self.now + 1e-12 or not self.queue: | |
| return | |
| workflow_id, step_index, ready_time = self.queue.pop(0) | |
| workflow = self.workflows[workflow_id] | |
| step = workflow.steps[step_index] | |
| role = step.role | |
| entry = self.cache.get(role) | |
| prefix_tokens = ROLE_PREFIX_TOKENS[role] | |
| prefix_wait_s = 0.0 | |
| cache_hit = False | |
| cache_source = "miss" | |
| if entry is not None and entry.available_time <= self.now + 1e-12: | |
| cache_hit = True | |
| cache_source = self.prefix_source.get(role, entry.source) | |
| elif entry is not None: | |
| # If a prefetch is almost complete, waiting can be cheaper than | |
| # recomputing the whole static prefix. Otherwise the step proceeds | |
| # immediately with a reactive prefill and the pending prefetch is | |
| # treated as not useful for this invocation. | |
| remaining = max(0.0, entry.available_time - self.now) | |
| full_prefix_s = self.latency.prefill_seconds([prefix_tokens]) | |
| if remaining < full_prefix_s: | |
| prefix_wait_s = remaining | |
| cache_hit = True | |
| cache_source = "prefetch_wait" | |
| if cache_hit: | |
| self.prefix_hits += 1 | |
| if cache_source.startswith("prefetch"): | |
| self.prefetch_hits += 1 | |
| self.prefill_tokens_saved += prefix_tokens | |
| if entry is not None: | |
| if entry.source == "prefetch" and not entry.used: | |
| entry.used = True | |
| self.prefetch_useful += 1 | |
| self.prefetch_useful_bytes += entry.size_gb * 1e9 | |
| entry.last_access = self.now + prefix_wait_s | |
| prefill_tokens = max(step.dynamic_prompt_tokens, 1) | |
| else: | |
| prefill_tokens = max(prefix_tokens + step.dynamic_prompt_tokens, 1) | |
| prefill_s = self.latency.prefill_seconds([prefill_tokens]) | |
| context = prefill_tokens | |
| first_decode_s = self.latency.decode_step_seconds([context]) | |
| midpoint = context + max(step.output_tokens // 2, 1) | |
| decode_step_s = self.latency.decode_step_seconds([midpoint]) | |
| service_s = prefix_wait_s + prefill_s + step.output_tokens * decode_step_s | |
| ttft_s = (self.now - ready_time) + prefix_wait_s + prefill_s + first_decode_s | |
| self.server_busy_until = self.now + service_s | |
| self._push( | |
| self.server_busy_until, | |
| "step_complete", | |
| workflow_id, | |
| step_index, | |
| ready_time, | |
| ttft_s, | |
| service_s, | |
| cache_hit, | |
| cache_source, | |
| prefill_tokens, | |
| ) | |
| def _finish_step( | |
| self, | |
| workflow_id: int, | |
| step_index: int, | |
| ready_time: float, | |
| ttft_s: float, | |
| service_s: float, | |
| cache_hit: bool, | |
| cache_source: str, | |
| prefill_tokens: int, | |
| ) -> None: | |
| workflow = self.workflows[workflow_id] | |
| step = workflow.steps[step_index] | |
| role = step.role | |
| # Reactive execution materializes the role prefix after a miss. | |
| if not cache_hit: | |
| self._install_prefix(role, available_time=self.now, source="reactive") | |
| elif role in self.cache: | |
| self.cache[role].last_access = self.now | |
| self.step_rows.append( | |
| { | |
| "workflow_id": workflow_id, | |
| "step_index": step_index + 1, | |
| "role": role, | |
| "shifted_regime": step.shifted_regime, | |
| "ready_time": ready_time, | |
| "completion_time": self.now, | |
| "cache_hit": cache_hit, | |
| "cache_source": cache_source, | |
| "prefix_tokens": ROLE_PREFIX_TOKENS[role], | |
| "dynamic_prompt_tokens": step.dynamic_prompt_tokens, | |
| "prefill_tokens": prefill_tokens, | |
| "output_tokens": step.output_tokens, | |
| "ttft_ms": ttft_s * 1000.0, | |
| "e2e_ms": (self.now - ready_time) * 1000.0, | |
| "queue_ms": max(0.0, (self.now - ready_time - service_s) * 1000.0), | |
| } | |
| ) | |
| self._schedule_prediction(workflow_id, step_index, role) | |
| actual_next = self._actual_next_role(workflow_id, step_index) | |
| if actual_next == END: | |
| self.workflow_completion[workflow_id] = self.now | |
| else: | |
| gap = step.gap_after_s | |
| ready_at = self.now + gap | |
| self._push(ready_at, "transition_observed", workflow_id, step_index, actual_next) | |
| self._push(ready_at, "step_ready", workflow_id, step_index + 1) | |
| self.server_busy_until = self.now | |
| self._start_next() | |
| def run(self) -> dict[str, Any]: | |
| self._record_timeline() | |
| while self.events: | |
| event_time, _, kind, payload = heapq.heappop(self.events) | |
| self._integrate_memory(event_time) | |
| self.now = event_time | |
| if kind == "step_ready": | |
| workflow_id, step_index = int(payload[0]), int(payload[1]) | |
| self.queue.append((workflow_id, step_index, self.now)) | |
| self._start_next() | |
| elif kind == "step_complete": | |
| self._finish_step( | |
| int(payload[0]), int(payload[1]), float(payload[2]), float(payload[3]), float(payload[4]), | |
| bool(payload[5]), str(payload[6]), int(payload[7]), | |
| ) | |
| elif kind == "transition_observed": | |
| self._observe_transition(int(payload[0]), int(payload[1]), str(payload[2])) | |
| elif kind == "prefetch_complete": | |
| role, generation = str(payload[0]), int(payload[1]) | |
| entry = self.cache.get(role) | |
| if entry is not None and entry.generation == generation and entry.available_time <= self.now + 1e-12: | |
| entry.last_access = self.now | |
| self._record_timeline() | |
| self._integrate_memory(self.now) | |
| self._record_timeline() | |
| step_ttft = [float(row["ttft_ms"]) for row in self.step_rows] | |
| step_e2e = [float(row["e2e_ms"]) for row in self.step_rows] | |
| workflow_e2e = [ | |
| (self.workflow_completion[wf.workflow_id] - wf.arrival_time) * 1000.0 | |
| for wf in self.workflows | |
| if wf.workflow_id in self.workflow_completion | |
| ] | |
| horizon = max([*self.workflow_completion.values(), self.cfg.duration_s, 1e-9]) | |
| predictions = self.prediction_rows | |
| pre = [row for row in predictions if not row["post_shift"]] | |
| post = [row for row in predictions if row["post_shift"]] | |
| def accuracy(rows: list[dict[str, Any]]) -> float: | |
| return sum(1 for row in rows if row["prediction_correct"]) / len(rows) if rows else 0.0 | |
| # Account for prefetched entries that remained unused through the end of the run. | |
| for entry in list(self.cache.values()): | |
| self._mark_unused_prefetch(entry) | |
| prefetch_precision = self.prefetch_correct / self.prefetch_attempts if self.prefetch_attempts else 0.0 | |
| prefetch_coverage = ( | |
| sum(1 for row in predictions if row.get("prefetch_attempted")) / len(predictions) | |
| if predictions else 0.0 | |
| ) | |
| prefetch_utilization = self.prefetch_useful / self.prefetch_attempts if self.prefetch_attempts else 0.0 | |
| forecast_recall_values = [ | |
| float(row["forecast_recall"]) for row in predictions if row.get("forecast_recall") is not None | |
| ] | |
| forecast_recall = mean(forecast_recall_values) if forecast_recall_values else 0.0 | |
| workflow_count = len(self.workflows) | |
| completed_count = len(self.workflow_completion) | |
| summary = { | |
| "workflows_generated": workflow_count, | |
| "workflows_completed": completed_count, | |
| "steps_completed": len(self.step_rows), | |
| "workflow_completion_rate": completed_count / workflow_count if workflow_count else 0.0, | |
| "workflow_throughput_rps": completed_count / horizon, | |
| "simulated_makespan_s": horizon, | |
| } | |
| resource = { | |
| "prefix_cache_capacity_gb": self.cache_capacity_gb, | |
| "mean_prefix_hbm_gb": self.hbm_gb_seconds / horizon, | |
| "peak_prefix_hbm_gb": self.peak_hbm_gb, | |
| "hbm_gb_seconds": self.hbm_gb_seconds, | |
| "prefix_hit_rate": self.prefix_hits / len(self.step_rows) if self.step_rows else 0.0, | |
| "prefetch_hit_rate": self.prefetch_hits / len(self.step_rows) if self.step_rows else 0.0, | |
| "prefill_tokens_saved": self.prefill_tokens_saved, | |
| "pressure_evictions": self.pressure_evictions, | |
| "prefetch_attempts": self.prefetch_attempts, | |
| "prefetch_correct": self.prefetch_correct, | |
| "prefetch_precision": prefetch_precision, | |
| "prefetch_coverage": prefetch_coverage, | |
| "prefetch_utilization": prefetch_utilization, | |
| "prefetch_attempts_per_prediction": self.prefetch_attempts / len(predictions) if predictions else 0.0, | |
| "forecast_recall": forecast_recall, | |
| "prefetch_gb": self.prefetch_bytes / 1e9, | |
| "prefetch_useful_gb": self.prefetch_useful_bytes / 1e9, | |
| "unused_prefetch_gb": self.unused_prefetch_bytes / 1e9, | |
| "wrong_step_prefetch_gb": self.wrong_step_prefetch_bytes / 1e9, | |
| "p95_prefetch_transfer_ms": percentile(self.transfer_latencies_ms, 0.95), | |
| } | |
| prediction = { | |
| "count": len(predictions), | |
| "top1_accuracy": accuracy(predictions), | |
| "pre_shift_accuracy": accuracy(pre), | |
| "post_shift_accuracy": accuracy(post), | |
| "calibration": _prediction_calibration(predictions), | |
| "pre_shift_calibration": _prediction_calibration(pre), | |
| "post_shift_calibration": _prediction_calibration(post), | |
| "rows": predictions[:4000], | |
| "predictor": self.predictor.snapshot(), | |
| } | |
| latency = { | |
| "step_ttft_ms": {"p50": percentile(step_ttft, 0.50), "p95": percentile(step_ttft, 0.95), "p99": percentile(step_ttft, 0.99)}, | |
| "step_e2e_ms": {"p50": percentile(step_e2e, 0.50), "p95": percentile(step_e2e, 0.95), "p99": percentile(step_e2e, 0.99)}, | |
| "workflow_e2e_ms": {"p50": percentile(workflow_e2e, 0.50), "p95": percentile(workflow_e2e, 0.95), "p99": percentile(workflow_e2e, 0.99)}, | |
| } | |
| return { | |
| "config": self.cfg.to_dict(), | |
| "provenance": { | |
| "simulator": "InferScale-Sim", | |
| "mode": "online-agent-execution-learning", | |
| "latency_profile_type": "analytical-reference", | |
| "execution_model": "online-transition-multistep-prefix-prefetch-reference", | |
| "prefetch_policy": self.cfg.prefetch_policy, | |
| "lookahead": "oracle-upper-bound" if self.cfg.prefetch_policy in {"oracle", "oracle_horizon"} else "no-future-transition-lookahead", | |
| "warning": "Execution Learning isolates cross-workflow static-prefix prediction/prefetch from session-KV retention and dynamic batching.", | |
| }, | |
| "summary": summary, | |
| "latency": latency, | |
| "resource": resource, | |
| "prediction": prediction, | |
| "steps": self.step_rows[:4000], | |
| "timeline": self.timeline, | |
| "role_prefix_tokens": ROLE_PREFIX_TOKENS, | |
| } | |
| def run_execution_learning(config: dict[str, Any], workflows: list[WorkflowSpec] | None = None) -> dict[str, Any]: | |
| cfg = ExecutionLearningConfig.from_dict(config) | |
| return ExecutionLearningSimulator(cfg, workflows=workflows).run() | |
| def _common_workflows(cfg: ExecutionLearningConfig) -> list[WorkflowSpec]: | |
| return generate_workflows(cfg) | |
| def _row(label: str, result: dict[str, Any]) -> dict[str, Any]: | |
| return { | |
| "label": label, | |
| "prefetch_policy": result["config"]["prefetch_policy"], | |
| "p95_step_ttft_ms": result["latency"]["step_ttft_ms"]["p95"], | |
| "p95_workflow_e2e_ms": result["latency"]["workflow_e2e_ms"]["p95"], | |
| "workflow_throughput_rps": result["summary"]["workflow_throughput_rps"], | |
| "prefix_hit_rate": result["resource"]["prefix_hit_rate"], | |
| "prefetch_precision": result["resource"]["prefetch_precision"], | |
| "prefetch_coverage": result["resource"]["prefetch_coverage"], | |
| "prefetch_utilization": result["resource"].get("prefetch_utilization", 0.0), | |
| "forecast_recall": result["resource"].get("forecast_recall", 0.0), | |
| "mean_hbm_gb": result["resource"]["mean_prefix_hbm_gb"], | |
| "pressure_evictions": result["resource"].get("pressure_evictions", 0), | |
| "wrong_step_prefetch_gb": result["resource"]["wrong_step_prefetch_gb"], | |
| "unused_prefetch_gb": result["resource"].get("unused_prefetch_gb", 0.0), | |
| "prefill_tokens_saved": result["resource"]["prefill_tokens_saved"], | |
| "top1_accuracy": result["prediction"]["top1_accuracy"], | |
| "brier": result["prediction"].get("calibration", {}).get("brier", 0.0), | |
| "ece": result["prediction"].get("calibration", {}).get("ece", 0.0), | |
| "post_shift_ece": result["prediction"].get("post_shift_calibration", {}).get("ece", 0.0), | |
| "pre_shift_accuracy": result["prediction"]["pre_shift_accuracy"], | |
| "post_shift_accuracy": result["prediction"]["post_shift_accuracy"], | |
| } | |
| def execution_prefetch_study(config: dict[str, Any]) -> dict[str, Any]: | |
| base = ExecutionLearningConfig.from_dict(config) | |
| workflows = _common_workflows(base) | |
| candidates = [ | |
| ("Learn only / no prefetch", "none", base.transition_decay), | |
| ("Cumulative transitions", "cumulative", 1.0), | |
| ("Decayed transitions", "decayed", base.transition_decay), | |
| ("Oracle next-role", "oracle", 1.0), | |
| ] | |
| rows: list[dict[str, Any]] = [] | |
| results: dict[str, dict[str, Any]] = {} | |
| for label, policy, decay in candidates: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.prefetch_policy = policy | |
| cfg.transition_decay = decay | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| results[label] = result | |
| rows.append(_row(label, result)) | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "online-transition-prefetch-policy-comparison", | |
| "rows": rows, | |
| "results": results, | |
| "shift_fraction": base.shift_fraction, | |
| "note": "Oracle next-role sees the realized next agent and is an upper bound; online policies update only after a transition is observed.", | |
| } | |
| def _pearson(xs: list[float], ys: list[float]) -> float: | |
| if len(xs) < 2 or len(xs) != len(ys): | |
| return 0.0 | |
| mx = mean(xs) | |
| my = mean(ys) | |
| numerator = sum((x - mx) * (y - my) for x, y in zip(xs, ys, strict=True)) | |
| sx = math.sqrt(sum((x - mx) ** 2 for x in xs)) | |
| sy = math.sqrt(sum((y - my) ** 2 for y in ys)) | |
| if sx <= 1e-12 or sy <= 1e-12: | |
| return 0.0 | |
| return numerator / (sx * sy) | |
| def execution_threshold_sweep( | |
| config: dict[str, Any], thresholds: list[float] | None = None | |
| ) -> dict[str, Any]: | |
| base = ExecutionLearningConfig.from_dict(config) | |
| base.prefetch_policy = "decayed" | |
| workflows = _common_workflows(base) | |
| values = thresholds or [0.0, 0.35, 0.50, 0.60, 0.70, 0.80, 0.90] | |
| cleaned = sorted({min(max(float(value), 0.0), 1.0) for value in values}) | |
| rows = [] | |
| for threshold in cleaned: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.confidence_threshold = threshold | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| rows.append(_row(f"threshold {threshold:.2f}", result) | {"threshold": threshold}) | |
| association = { | |
| "coverage_vs_ttft_r": _pearson( | |
| [float(row["prefetch_coverage"]) for row in rows], | |
| [float(row["p95_step_ttft_ms"]) for row in rows], | |
| ), | |
| "precision_vs_wrong_prefetch_r": _pearson( | |
| [float(row["prefetch_precision"]) for row in rows], | |
| [float(row["wrong_step_prefetch_gb"]) for row in rows], | |
| ), | |
| } | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "prefetch-confidence-threshold-frontier", | |
| "rows": rows, | |
| "association": association, | |
| "note": "Correlations summarize this simulated sweep only; they are descriptive, not causal estimates.", | |
| } | |
| def execution_decay_sweep( | |
| config: dict[str, Any], decay_values: list[float] | None = None | |
| ) -> dict[str, Any]: | |
| base = ExecutionLearningConfig.from_dict(config) | |
| base.prefetch_policy = "decayed" | |
| workflows = _common_workflows(base) | |
| values = decay_values or [0.50, 0.65, 0.75, 0.85, 0.92, 0.97, 1.00] | |
| cleaned = sorted({min(max(float(value), 0.20), 1.0) for value in values}) | |
| rows = [] | |
| for decay in cleaned: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.transition_decay = decay | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| rows.append(_row(f"decay {decay:.2f}", result) | {"decay": decay}) | |
| best_accuracy = max(rows, key=lambda row: (row["post_shift_accuracy"], -row["p95_step_ttft_ms"])) if rows else None | |
| best_ttft = min(rows, key=lambda row: (row["p95_step_ttft_ms"], -row["post_shift_accuracy"])) if rows else None | |
| association = { | |
| "post_shift_accuracy_vs_ttft_r": _pearson( | |
| [float(row["post_shift_accuracy"]) for row in rows], | |
| [float(row["p95_step_ttft_ms"]) for row in rows], | |
| ), | |
| "post_shift_accuracy_vs_prefix_hit_r": _pearson( | |
| [float(row["post_shift_accuracy"]) for row in rows], | |
| [float(row["prefix_hit_rate"]) for row in rows], | |
| ), | |
| } | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "transition-forgetting-rate-sweep", | |
| "rows": rows, | |
| "best_post_shift_accuracy_decay": best_accuracy["decay"] if best_accuracy else None, | |
| "best_ttft_decay": best_ttft["decay"] if best_ttft else None, | |
| "association": association, | |
| "note": "Better next-role prediction need not minimize serving latency because cache occupancy and transfer timing mediate the effect.", | |
| } | |
| def execution_planning_study(config: dict[str, Any]) -> dict[str, Any]: | |
| """Compare one-step, multi-step, utility-aware, and clairvoyant planning.""" | |
| base = ExecutionLearningConfig.from_dict(config) | |
| workflows = _common_workflows(base) | |
| candidates = [ | |
| ("Top-1 decayed", "decayed"), | |
| ("Multi-step top-k", "multistep"), | |
| ("Utility-aware multi-step", "utility"), | |
| ("Oracle future-set", "oracle_horizon"), | |
| ] | |
| rows: list[dict[str, Any]] = [] | |
| results: dict[str, dict[str, Any]] = {} | |
| for label, policy in candidates: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.prefetch_policy = policy | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| results[label] = result | |
| rows.append(_row(label, result)) | |
| best_ttft = min(rows, key=lambda row: row["p95_step_ttft_ms"]) if rows else None | |
| best_efficiency = max( | |
| rows, | |
| key=lambda row: ( | |
| row["prefill_tokens_saved"] / max(row["mean_hbm_gb"], 1e-9), | |
| -row["p95_step_ttft_ms"], | |
| ), | |
| ) if rows else None | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "multi-step-prefetch-planning", | |
| "rows": rows, | |
| "results": results, | |
| "best_ttft_policy": best_ttft["label"] if best_ttft else None, | |
| "best_prefill_per_hbm_policy": best_efficiency["label"] if best_efficiency else None, | |
| "note": "Oracle future-set sees realized future roles only as an information upper bound; online multi-step policies roll the learned transition matrix forward without future trace access.", | |
| } | |
| def execution_horizon_sweep( | |
| config: dict[str, Any], horizon_values: list[int] | None = None | |
| ) -> dict[str, Any]: | |
| base = ExecutionLearningConfig.from_dict(config) | |
| base.prefetch_policy = "utility" | |
| workflows = _common_workflows(base) | |
| values = horizon_values or [1, 2, 3, 4, 5] | |
| cleaned = sorted({max(1, min(int(value), 6)) for value in values}) | |
| rows: list[dict[str, Any]] = [] | |
| for horizon in cleaned: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.forecast_horizon = horizon | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| rows.append(_row(f"horizon {horizon}", result) | {"horizon": horizon}) | |
| best_ttft = min(rows, key=lambda row: (row["p95_step_ttft_ms"], row["unused_prefetch_gb"])) if rows else None | |
| best_utilization = max(rows, key=lambda row: (row["prefetch_utilization"], -row["unused_prefetch_gb"])) if rows else None | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "forecast-horizon-sweep", | |
| "rows": rows, | |
| "best_ttft_horizon": best_ttft["horizon"] if best_ttft else None, | |
| "best_utilization_horizon": best_utilization["horizon"] if best_utilization else None, | |
| "note": "Longer forecasts can expose future reuse but may spend bandwidth and cache capacity on prefixes that are not consumed before eviction.", | |
| } | |
| def execution_budget_sweep( | |
| config: dict[str, Any], budget_values: list[float] | None = None | |
| ) -> dict[str, Any]: | |
| base = ExecutionLearningConfig.from_dict(config) | |
| workflows = _common_workflows(base) | |
| values = budget_values or [0.30, 0.50, 0.75, 1.00] | |
| cleaned = sorted({min(max(float(value), 0.10), 1.50) for value in values}) | |
| policies = [ | |
| ("Top-1", "decayed"), | |
| ("Multi-step", "multistep"), | |
| ("Utility-aware", "utility"), | |
| ] | |
| rows: list[dict[str, Any]] = [] | |
| for budget in cleaned: | |
| for label, policy in policies: | |
| cfg = ExecutionLearningConfig.from_dict(base.to_dict()) | |
| cfg.prefix_cache_budget_fraction = budget | |
| cfg.prefetch_policy = policy | |
| result = run_execution_learning(cfg.to_dict(), workflows) | |
| rows.append(_row(label, result) | {"budget": budget, "policy_label": label}) | |
| winners = [] | |
| for budget in cleaned: | |
| group = [row for row in rows if abs(float(row["budget"]) - budget) < 1e-12] | |
| if group: | |
| winner = min(group, key=lambda row: (row["p95_step_ttft_ms"], row["unused_prefetch_gb"])) | |
| winners.append({"budget": budget, "policy": winner["policy_label"], "p95_step_ttft_ms": winner["p95_step_ttft_ms"]}) | |
| return { | |
| "protocol": "common-shifted-agent-workflow-trace", | |
| "study": "prefix-cache-budget-policy-sweep", | |
| "rows": rows, | |
| "winners": winners, | |
| "note": "All policies see the same workflows at each cache budget; the sweep exposes when broader forecasting helps versus when it increases cache pressure.", | |
| } | |