Русский
Что агенты на самом деле делают с полями поиска
Что это: в сентябре мы измерили три необязательных поля, которые агент передаёт вместе с поиском, — short_query, rephrased_query и expected_answer, — но заполняла их сильная модель в скрипте. В октябре мы их выпустили и посмотрели, что с ними делают Claude Haiku и Claude Sonnet через Claude Code. Четыре опыта, около 1 500 прогонов агентов. Коротко: поля работают, когда их хорошо заполняют; агенты в основном заполняют плохо; если их подталкивать заполнять больше, становится хуже; а одно простое число в результате поиска изменило поведение сильнее любой формулировки.
Как мерили
Три базы:
- русская документация продукта, 100 заметок, 42 вопроса с размеченной правильной страницей;
- русский базовый набор бенчмарка Obsidian Help, 58 вопросов;
- синтетическое английское руководство к выдуманному продукту: 12 длинных заметок (4 000–10 000 слов, по 15–35 разделов) и 40 коротких, 56 вопросов с одним проверяемым ответом, большая часть — глубоко внутри длинной заметки.
Агенты работали через Claude Code CLI, подключён был только MCP-сервер базы, векторный поиск включён (bge-m3). Для оценки поиска мы записывали первый вызов search и прогоняли его по серверу заново с разными полями, считая MRR@10 и nDCG@5 по разметке. Каждое сравнение парное, с bootstrap-интервалом 95%; на 40–60 вопросах разница что-то значит, только начиная примерно с ±0.1 MRR.
Как агенты заполняют поля
Первый вызов search на базе документации:
| Кто пишет | short_query |
rephrased_query |
expected_answer |
переписал query |
|---|---|---|---|---|
| Haiku | 89% | 86% | 14% | 72% |
| Sonnet | 91% | 53% | 0% | 15% |
| сильная модель, видит только вопрос и описания | 100% | 100% | 100% | — |
Sonnet ни разу не написал expected_answer. Haiku написала его в одном случае из семи и почти в трёх случаях из четырёх переписала query, хотя описание просит этого не делать.
Как меняется MRR@10, если добавить к запросу каждое поле (интервал 95%):
| Кто пишет | + short_query |
+ rephrased_query |
+ expected_answer |
все три |
|---|---|---|---|---|
| Haiku | +0.01 | +0.05 | +0.01 | +0.05 |
| Sonnet | +0.09 | 0.00 | — | +0.04 |
| сильная модель | +0.10 | +0.04 | +0.12 [+0.03, +0.21] | +0.14 [+0.01, +0.27] |
Выше шума только expected_answer от сильной модели и все три поля вместе. На этой базе механизм работает примерно так же, как в сентябре на Obsidian Help (там было +0.10). Ограничивает его агент: поле, которое помогает больше всего, настоящие агенты пропускают.
rephrased_query никому не помог выше шума, а у Sonnet поверх short_query сделал хуже 4 вопроса против 1 лучше. Мы его оставили: в qmd, по образцу которого сделаны поля, такое поле есть, а 42 вопроса не доказывают «бесполезно» так же, как не доказывают «полезно».
ИЛИ для short_query
Полнотекстовый поиск trip2g требует всех слов запроса. short_query — это два-три слова, поэтому ИЛИ там казалось безопасным: длинный query сохраняет И ради точности, короткое поле получает ИЛИ ради полноты. MRR@10 для query + short_query:
| Кто пишет | И | ИЛИ | И, а если пусто — ИЛИ |
|---|---|---|---|
| Haiku | 0.521 | 0.595 (+0.07 [+0.01, +0.16]) | 0.537 |
| Sonnet | 0.654 | 0.559 (−0.09) | 0.630 |
| сильная модель | 0.663 | 0.593 (−0.07) | 0.656 |
ИЛИ спасает неудачные слова Haiku и топит точные слова остальных. В этой базе слово, которым называется главная сущность продукта, есть почти на каждой странице, поэтому short_query: "копия агента" через ИЛИ возвращает почти случайный список, а слияние по рангу даёт ему тот же вес, что и точным спискам. Это июльский результат, только на уровне поля. Запасной вариант почти не срабатывает: из двух-трёх слов И редко возвращает пусто. Оставили И.
Просить агентов заполнять поля
Раз полезное поле не заполняют, можно попросить. Пять формулировок, на базе документации и Obsidian Help, Haiku и Sonnet, 1 000 прогонов:
- V0: выпущенный текст («Optional. …»);
- V1:
expected_answerпомечено «Recommended», с «ответ знать не обязательно, это поле никто не видит»; - V2: «You SHOULD fill this whenever you understand the question» на всех трёх полях и «заполняй все три при каждом поиске» в описании инструмента;
- V3: V2 плюс «если не уверен, да или нет, не утверждай ни то ни другое»;
- V4: только фраза в описании инструмента.
В V2, V3 и V4 доля вызовов со всеми тремя полями выросла на 44–51 процентный пункт; у Sonnet expected_answer на базе документации — с 0% до 100%. Одна фраза в описании инструмента (V4) сработала так же, как переписывание каждого поля.
Поиск не сдвинулся. Общая разница MRR с V0 — от +0.001 до +0.027 при интервале 95% около ±0.045, в каждом варианте. А expected_answer начал врать: на вопросах, где правда — «нет», заполненное поле утверждало «да» в 30–40% вызовов («откройте карточку агента и выберите „Клонировать“» для функции, которой нет). Строка-защита в V3 этого не остановила. Там, где неверная догадка встречалась с правильной страницей, она выталкивала её из первой десятки.
Описания мы оставили как есть. Агент, которого подталкивают угадывать, угадывает, а догадка, сказанная как факт, для поиска хуже, чем никакой.
Показать длину заметки
Раньше результат поиска ничего не говорил о размере заметки, и агент до открытия не мог отличить руководство на 9 000 слов от абзаца. Мы добавили в каждый результат два числа: size_tokens — ту же оценку, которой пользуется нарезка на куски, и sections — сколько заголовков может пройти expand. Потом синтетическое руководство, три варианта: S0 без чисел, S1 с ними, S2 с ними и фразой в описании инструмента («заметку больше ~2 000 токенов с несколькими разделами не читай целиком: прочитай найденный раздел или сначала вызови expand»).
Вопросы о длинных заметках, по два прогона:
| верно | прочитал длинную целиком | прочитал по разделу | получил от инструментов | |
|---|---|---|---|---|
| Haiku S0 | 90% | 0.76 на вопрос | 0.24 | 30 тыс. символов |
| Haiku S1 | 83% | 0.36 | 0.68 | 16 тыс. |
| Haiku S2 | 79% | 0.12 | 1.02 | 12 тыс. |
| Sonnet S0 | 88% | 0.49 | 0.43 | 20 тыс. |
| Sonnet S1 | 90% | 0.04 | 0.92 | 6 тыс. |
| Sonnet S2 | 88% | 0.02 | 1.20 | 7 тыс. |
Сами два числа сократили чтение длинных заметок целиком и объём того, что вернули инструменты, вдвое-втрое у обеих моделей, выше шума. Прогоны Sonnet стали примерно вдвое дешевле при той же точности. Дополнительная фраза Sonnet ничего не добавила, а Haiku стоила около десяти пунктов точности: ей сказали читать по разделам, и она читала не тот раздел. На вопросах о коротких заметках ничего не изменилось.
Числа мы выпустили, фразу — нет.
Что из этого следует
- Узкое место — агент, а не сервер. Каждое поле работает, когда его хорошо заполнили. Настоящие агенты заполняют дешёвые поля, пропускают полезное и переписывают запрос, который их просили не трогать.
- Формулировка меняет поведение, а не результат. Одна фраза сдвинула долю заполнения на пятьдесят пунктов, поиск — ни на что измеримое, и заставила агента утверждать то, чего он не знал.
- Факт лучше указания.
size_tokens— это число, а не совет, и обе модели правильно им воспользовались, хотя им не говорили, что с ним делать. Указание сверху сделало слабую модель хуже. - Мерить надо тем агентом, который будет этим пользоваться. Сентябрьские числа были верны для сильной модели, заполняющей поля в скрипте. В руках агентов, которыми пользуются люди, большей части этой прибавки нет.
Предыдущая часть этой работы — дефекты, поверх починки которых делались эти прогоны, — в статье Три месяца бенчмарков, а модель так и не прочитала ни одной заметки.