Orchestrates feedback collection and online model updates. Stores compact feature vectors (no raw prompts) for recent requests. When feedback arrives, adjusts the Perceptron weights toward the corrected tier and periodically persists the updated model.
| 52 | |
| 53 | |
| 54 | class FeedbackCollector: |
| 55 | """Orchestrates feedback collection and online model updates. |
| 56 | |
| 57 | Stores compact feature vectors (no raw prompts) for recent requests. |
| 58 | When feedback arrives, adjusts the Perceptron weights toward the |
| 59 | corrected tier and periodically persists the updated model. |
| 60 | """ |
| 61 | |
| 62 | def __init__( |
| 63 | self, |
| 64 | max_updates_per_hour: int = 100, |
| 65 | save_every: int = 10, |
| 66 | model_experience: Any = None, |
| 67 | now_fn: Any = None, |
| 68 | buffer_path: Path | None = None, |
| 69 | ) -> None: |
| 70 | self._buffer: dict[str, RequestContext] = {} |
| 71 | self._max_hourly = max_updates_per_hour |
| 72 | self._save_every = save_every |
| 73 | self._model_experience = model_experience |
| 74 | self._now = now_fn or time.time |
| 75 | self._update_ts: list[float] = [] |
| 76 | self._total_updates: int = 0 |
| 77 | self._since_save: int = 0 |
| 78 | self._buffer_path = buffer_path |
| 79 | if self._buffer_path: |
| 80 | self._load_buffer() |
| 81 | |
| 82 | # ─── Public API ─── |
| 83 | |
| 84 | def capture( |
| 85 | self, |
| 86 | request_id: str, |
| 87 | features: dict[str, float], |
| 88 | tier: str, |
| 89 | *, |
| 90 | model: str = "", |
| 91 | mode: str = "auto", |
| 92 | ) -> None: |
| 93 | """Buffer compact features for a routed request (no raw prompts stored).""" |
| 94 | compact = {k: v for k, v in features.items() if not k.startswith("ngram_")} |
| 95 | self._buffer[request_id] = RequestContext( |
| 96 | features=compact, |
| 97 | tier=_normalize_tier(tier), |
| 98 | timestamp=self._now(), |
| 99 | model=model, |
| 100 | mode=mode, |
| 101 | ) |
| 102 | self._save_buffer() |
| 103 | |
| 104 | def rebind_request( |
| 105 | self, |
| 106 | request_id: str, |
| 107 | *, |
| 108 | tier: str | None = None, |
| 109 | model: str | None = None, |
| 110 | mode: str | None = None, |
| 111 | ) -> None: |
no outgoing calls