Вернёмся к практике разработки фабрики контента. Как агент находит нужный факт в базе на 200+ карточек
Я вроде рассказал, как собрал агентам базу знаний-граф? Если не рассказывал, то там я пришёл к той же идее, что Карпатый описывал как LLM Wiki, — связный самоподдерживающийся граф концептов, где всё ссылается друг на друга в обе стороны. Могу отдельно рассказать про карточки и базу отдельно, если интересно.
Но база бесполезна, если агент не может достать из неё нужное. И вот тут началось самое весёлое. Наивный план был такой: агент формулирует запрос → ищем по тегам → отдаём карточки. Запустил. Агент спрашивает про «работу с базами данных» — находит ноль. Хотя в базе лежит жирный синтез с тегом databases.
Проблема — русский язык. Морфология, будь она неладна
Агент пишет запрос живым языком: «базами данных», «облака в России», «искусственного интеллекта». А теги в базе канонические: databases, cloud, ai. Точного совпадения нет. Падежи, порядок слов, синонимы — всё это ломает простой поиск.
Пришлось строить query expansion — разворачивать запрос перед поиском:
➡️ Синонимы и алиасы. «ИИ» и «субд» — это ai и databases. Ведётся словарь синонимических групп поверх таксономии: каждый канонический тег знает все свои народные варианты.
➡️ Лёгкий RU-стеммер. Отрезаю частое окончание, чтобы «облако», «облака», «облаком» сводились к одному стему. Намеренно тупой стеммер на ~10 правил, но его достаточно и он не тянет зависимостей.
➡️ Фразовый индекс по стемам. Многословный алиас «базы-данных» распознаётся во фразе «работа с базами данных» — по множеству стемов частей, несмотря на падеж и порядок слов. Внутри это frozenset стемов: пересеклись — попадание.
Синоним матчится не только против тегов файла, но и против его домена — это ловит карточки, где тема зашита в домен, а теги пустые.
fact-cards — отдельным потоком
Обычные синтезы ранжируются в общий шортлист. А вот проверяемые факты поднимаются отдельно с уровнем доверия (confidence) и допуском к публикации (allowed_use). Просроченные по expires из выдачи вырезаются молча, чтобы автор физически не смог процитировать протухшую цифру. Ретривер тут работает как фильтр доверия, а не просто поиск.
Playbook на каждый сценарий
Не «агент, посмотри базу». А конкретная карта: для этого типа материала подавай сначала fact-cards и позиционирование, конкурентов по релевантности, а вот эти слои вообще запрещены без явной проверки. Один сценарий — один playbook.
И самое важное — я это померил
Тут очень легко себя обмануть. Погонял поиск руками, пару раз он выдал что нужно и ты такой: «работает». А на деле ты проверил три запроса из тысячи возможных, и на четвёртом всё разваливается. «Вроде находит» — это не факт, это ощущение.
Чтобы перестать врать себе, я сделал скучную, но честную вещь: завёл метрики для поиска. Это просто список запросов, где я заранее, руками, отметил правильный ответ. Типа:
Запрос: «тренды систем управления базами данных»
Правильный ответ: вот эта карточка и вот эта
Таких пар у меня сейчас 15. Ключевой момент: правильный ответ я размечаю по смыслу, честно, а не подсматривая в то, что выдаёт мой же поиск. Иначе экзамен бессмысленный: я бы просто подгонял ответы под то, что система и так находит. Дальше прогоняю все 15 запросов через поиск и смотрю на три цифры.
Метрика 1: hit@5 — «нашёл ли вообще?»
Самый простой вопрос: в первых пяти результатах есть нужная карточка — да или нет? Считаю по всем запросам долю, где ответ «да». Сейчас это 1.0 — то есть по каждому из 15 запросов нужное лежит где-то в топ-5. Пока что промахов нет вообще. Почему именно топ-5, а не топ-1? Потому что агенту я и так отдаю несколько карточек — ему есть из чего выбрать. Мне важно, чтобы нужное попало в стопку, которую он получит.
Метрика 2: MRR — «а насколько высоко?»
Попасть в топ-5 мало. Одно дело — нужная карточка на 1-м месте, другое — на 5-м, за четырьмя лишними. MRR смотрит, на какой строчке стоит нужный ответ, и переводит это в оценку:
— ответ на 1-м месте → 1.0 (идеал)
— на 2-м →
Просмотры: 17