Online Quality Signal

Система, распределяющая запросы между исполнителями — провайдерами, моделями, инструментами, субагентами, — может собирать оценку о них сама, из исходов собственных запросов. Такой рейтинг ошибается двумя способами по умолчанию: путает «вызов прошёл» с «ответ хороший» и верит первым десяти наблюдениям. Оба дефекта лечатся до того, как сигнал получает право на что-либо влиять.

Два разных качества, которые нельзя складывать

Из горячего пути наблюдается только операционное качество, и его состав перечислим: коды ответа, отказы соединения, ограничение частоты, разбор ответа не удался, стрим оборвался, генерация упёрлась в лимит выходных токенов, вызов успешен, но вывод пуст, задержка и время до первого фрагмента.

Всё это говорит о транспорте и форме, а не о пользе ответа. Отсюда правило, которое стоит записать буквально: успешный код ответа не является свидетельством качества — ровно тот же дефект, вокруг которого построена Agent Failure Modes, только теперь он попадает не в мониторинг, а в контур принятия решений, что хуже.

Семантическое качество — ценность самого сгенерированного текста — приходит только от оценщика: судьи, эвала, разметки, обратной связи пользователя (LLM as Judge). Пока оценщика нет, семантической оценки нет, а не «хорошо»: она остаётся пустой и не подмешивается в операционную. Слияние двух шкал в одно число выглядит удобно ровно до первого разбора, когда выясняется, что провайдер понижен за таймауты сети, а не за плохие ответы, — и чинили не то.

Малая выборка: сжатие к нейтральному

Второй дефект механический, и лечится он тоже механически. Наблюдаемая форма:

confidence = min(1, наблюдений / N)          # N порядка полусотни
оценка     = нейтраль + confidence × (операционная − нейтраль)

Смысл в том, что оценка сжимается к нейтральному значению тем сильнее, чем меньше за ней наблюдений. Три следствия, и все три обязаны быть проверены тестами, потому что на глаз они неразличимы:

  • холодный исполнитель получает ровно нейтраль — он не штрафуется за отсутствие истории и не может обойти того, у кого тысячи наблюдений;
  • семь удачных вызовов подряд не выводят в лидеры — оценка подтягивается к нейтрали, и оптимистичная инициализация перестаёт быть выигрышной стратегией;
  • после нескольких десятков наблюдений оценка сходится к настоящей, а деградация и восстановление идут постепенно: одиночный сбой не разрушает исполнителя с хорошей историей.

Без сжатия рейтинг систематически выигрывает тот, у кого наблюдений меньше: одна удача даёт единицу, а тысяча честных вызовов — что-то вроде 0,97. Это не редкий случай, это поведение по умолчанию у любого счётчика долей.

Нейтральное значение — то, которое не двигает ранжирование на выбранной шкале; конкретное число зависит от того, как шкала устроена, и переносить его как константу нельзя.

Отдельно стоит держать сглаживание: скользящее среднее с экспоненциальным весом даёт постепенность, но платит запаздыванием. Резкая деградация ловится не рейтингом, а размыкателем; рейтинг отвечает за медленный дрейф.

Мягкое предпочтение против жёсткого исключения

Вопросов два, и путать их нельзя:

Вопрос Кто отвечает Свойство ответа
можно ли слать размыкатель, исчерпанная квота, отказ авторизации, блокировка исполнителя двоичный, обратимый по своему правилу
стоит ли слать рейтинг качества непрерывный, вероятностный

Рейтинг имеет право только понижать предпочтение. Исполнитель с просевшей оценкой получает меньше трафика, но не отключается — потому что оценка вероятностна, на малой выборке врёт, и её ошибка не должна становиться необратимой в пределах запроса. Обратное тоже верно: жёсткие исключения рейтингом не отменяются — открытый размыкатель остаётся открытым, какой бы хорошей ни была история.

Эта же граница объясняет, почему просевшее качество не лечится увеличением веса: вес меняет силу предпочтения, а не его природу.

Замкнутый контур и его цена на горячем пути

Контур короткий: исход запроса → обновление оценки → следующее решение о маршруте. Ценность в том, что он замыкается сам, без выгрузки логов и ручного разбора.

Цена платится на горячем пути, и требования к ней жёсткие:

  • одна эмиссия на завершённый запрос, включая пути отказа, — иначе выборка смещается в сторону успехов;
  • приёмник обязан быть O(1) и без синхронного ввода-вывода: он только обновляет состояние в памяти или кладёт в очередь. Запись в базу и отправка телеметрии — асинхронно и позже;
  • при перегрузке приёмник теряет события и никогда не тормозит поток. Буфер ограничен, старое вытесняется, счётчик потерь виден. Обратное давление от канала обратной связи на путь запроса — дефект, а не защита;
  • отсутствующий оценщик не меняет маршрутизацию: без него семантическая часть просто пуста, а система работает целиком.

Порядок величин у такой эмиссии — доли микросекунды на запрос, то есть она не входит в бюджет задержки; но это измерение конкретной реализации на конкретной машине, а не переносимая гарантия.

Канал исходов — не шина уведомлений интерфейса

Ошибка, которую делают почти всегда: переиспользовать существующую событийную шину панели мониторинга как канал обратной связи. Это разные вещи, и различие устойчивое:

Шина уведомлений Канал исходов
что типизировано имя события структура исхода
нагрузка непрозрачная, для отображения перечислимые поля: задержка, токены, стоимость, исход, причина завершения
потребитель интерфейс оценка качества, экспорт телеметрии, объяснение решений
требование доставить в интерфейс не потерять смещённо и не тормозить путь запроса

Переиспользование одного как другого ломает обе стороны: интерфейс начинает получать поля, которые ему не нужны, а настройка маршрутизации — читать нагрузку, о структуре которой нет договорённости.

Объяснимость — часть механизма, а не удобство

Рейтинг, который влияет на маршрут, но не предъявляется наружу, неотличим от случайности при разборе. Минимум, который делает его проверяемым: недавние фактические решения и снимок текущего состояния оценок по каждому исполнителю, доступные отдельным запросом.

Ограничение к этому прилагается сразу: события несут только метаданные маршрутизации и никогда не промпты, тела ответов и учётные данные. Иначе канал объяснимости становится каналом утечки, и его придётся закрыть — а вместе с ним потерять единственный способ разобрать поведение маршрутизатора.

Чего сигнал не даёт

  • Он не измеряет пользу ответа — это делает оценщик, и без него контур настраивает систему по транспортным признакам.
  • Он не различает виды задач. Оценка накапливается на исполнителя, а не на пару «исполнитель + вид задачи»; исполнитель, хороший на коротких задачах и слабый на длинном контексте, получит одно усреднённое число. Разделение по видам задачи — отдельное решение, и оно дробит и без того малую выборку.
  • Он не заменяет эвалы. Контур оптимизирует выбор внутри имеющегося набора исполнителей и ничего не говорит о том, решается ли задача вообще (Agent Evals).

Связано с

  • Cascade Routing — куда этот сигнал подаётся: выбор ступени и порядок кандидатов
  • Agent Failure Modes — почему успешный код ответа ничего не говорит о качестве
  • Quality Metric Design — метрика качества продукта, которую строят людьми; здесь система оценивает себя сама
  • LLM as Judge — единственный источник семантической половины сигнала
  • Agent Observability — куда уходят те же события в виде трассировки
  • Unknown Not A Value — отсутствующая семантическая оценка остаётся отсутствующей, а не хорошей
  • Source Independence — почему оценщик, обслуживаемый тем же провайдером, не даёт независимой оценки