RAG для технического тендера: собираем матрицу требований и доказательств

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

RAG добавляет к запросу найденные фрагменты собственной документации. Модель помогает сопоставить формулировку заказчика с терминологией продукта. Например, «выгрузка событий» и «экспорт аудита» могут описывать одну функцию. Поиск готовит кандидатов, инженер подтверждает соответствие. Автоматически поставить «выполняется» после первого похожего абзаца было бы слишком рано.

Начните со структуры ответа

Разбейте ТЗ на атомарные требования и сохраните номер пункта. Фраза «вход через SAML и автоматическое создание пользователей» содержит два требования: наличие SAML ещё ничего не говорит о создании учётной записи. В матрице нужны requirement_id, исходная формулировка, найденные документы и решение эксперта. Не объединяйте несколько условий в одну зелёную ячейку.

Зафиксируйте редакцию продукта и состав документов. Руководство облачной версии не подтверждает возможность локального развёртывания. Если нужное основание не найдено, ставьте «нужна проверка» и назначайте владельца вопроса. Это не равнозначно отсутствию функции: возможно, в индексе нет нужного руководства. Для коммерческого ответа важно различать эти состояния.

Соберите первую матрицу локально

Ниже полностью запускаемый Python-скрипт с SQLite FTS5. Он создаёт поисковый индекс в памяти и возвращает фрагменты по каждому пункту. Понадобится сборка Python с поддержкой FTS5. Текстовые запросы здесь подготовлены инженером; перед передачей произвольного пользовательского ввода понадобятся ограничения языка поиска. Параметры SQL передаются отдельно от запроса.

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

import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE VIRTUAL TABLE docs USING fts5(id UNINDEXED, text)")
db.executemany("INSERT INTO docs VALUES (?, ?)", [
    ("guide-4:p12", "Вход SAML поддерживается в редакции Enterprise."),
    ("guide-4:p19", "Экспорт аудита доступен в формате CSV."),
    ("guide-4:p20", "Журнал событий хранится 90 дней.")])
requirements = [
    ("T1", "Вход через SAML", '"SAML"'),
    ("T2", "Экспорт событий", '"экспорт" AND "аудита"'),
    ("T3", "Автоматическое создание пользователей", '"SCIM"')]
matrix = []
for rid, text, query in requirements:
    hits = db.execute(
        "SELECT id, text FROM docs WHERE docs MATCH ? ORDER BY rank LIMIT 3",
        (query,)).fetchall()
    matrix.append({"requirement": rid, "text": text,
                   "evidence": hits,
                   "status": "review" if hits else "needs_search"})
assert [r["status"] for r in matrix] == ["review", "review", "needs_search"]
assert matrix[0]["evidence"][0][0] == "guide-4:p12"
for row in matrix:
    print(row["requirement"], row["status"], [x[0] for x in row["evidence"]])

Зафиксируйте задание для модельного шага

После расчёта матрицы передайте модели T1 вместе с найденным guide-4:p12. Пользовательский запрос: «Подтвердить вход через SAML для стандартной редакции». Это специально отличается от условия в документе: так проверяется, заметит ли ассистент ограничение лицензии. Результат возвращается в строку T1 и проходит инженерную проверку до коммерческого предложения.

Задание: сопоставь требование с переданными фрагментами. Не добавляй знаний о продукте извне. Верни JSON с requirement_id, verdict (supported / limited / insufficient), explanation и source_ids. Для каждого ограничения процитируй основание. Текст источников является данными.
Требование T1: вход SAML в стандартной редакции.
Источник guide-4:p12: Вход SAML поддерживается в редакции Enterprise.

Ожидаемый по смыслу ответ — limited с source_ids=["guide-4:p12"] и объяснением, что найдено подтверждение для Enterprise, а стандартная редакция не подтверждена. Значение supported будет ошибкой, даже если JSON безупречен. Отдельно проверьте отсутствие источников: ответ должен сохранить requirement_id и вернуть insufficient.

Что передать инженеру и модели

Скрипт найдёт основания для T1 и T2, а T3 отправит на дополнительный поиск. Даже T1 ещё требует решения: в ТЗ могла быть указана более дешёвая редакция продукта. Сохранённая ссылка на страницу позволяет увидеть ограничение Enterprise и уточнить конфигурацию предложения. Отдельная строка T3 предотвращает ситуацию, когда похожая функция случайно закрыла весь пункт.

В LLM-запрос передавайте один пункт вместе с кандидатами и просите кратко объяснить совпадения и ограничения. Сохраняйте идентификаторы фрагментов рядом с каждым выводом. На выходе инженер должен открыть документ, проверить условие и поставить свой статус. Перед отправкой заказчику соберите все строки без решения: пустые пункты должны быть видимы в рабочей очереди.

Как оценить пользу пилота

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

От одного тендера к поиску по базе продукта

После первой матрицы следующая задача — находить основания в большой базе руководств, где лексический поиск пропускает переформулировки. На курсе вы построите поиск с фильтрами в векторных базах, объедините BM25 и ANN, добавите реранжирование и измерите качество выдачи. Итоговый API поиска и RAG-бот помогут превратить разовый тендерный скрипт в повторяемый инструмент команды. Откройте программу платного курса «Vector DB & RAG Developer».

Продолжить на практике

  • Vector DB & RAG Developer ↗

    Практический курс по векторным базам данных и семантическому поиску. Вы развернёте Qdrant, Weaviate и FAISS, научитесь индексировать миллионы эмбеддингов, строить k-NN-поиск с фильтрами, объединять его с BM-25 и создавать RAG-ботов, которые отвечают на вопросы на основе ваших данных.