Демка · 9 сентября 2026
TenderLens
TenderLens принимает HTML, PDF, XML, JSON и TXT, приводит документы к одному контракту и режет их на стабильные chunks. Индексация идёт через NATS JetStream. bge-m3 в MWS считает embeddings, pgvector ищет близкие фрагменты, а gpt-oss-120b формирует ответ только по найденному контексту и возвращает источники.
Опубликованный стенд с реальными моделями MWS, pgvector, NATS и синтетическим корпусом
01 / Задача
Поиск по документам: FastAPI и pgvector
Задача — собрать проверяемый поиск по разнородным тендерным файлам. От исходного документа до ответа остаётся трасса document → chunk → embedding → hit → citation, поэтому результат можно вернуть к конкретному фрагменту.
Сценарий: Поиск и разбор набора документов.
Что делал
- Нормализация документов, событийная индексация и хранение chunks в PostgreSQL.
- Search и Ask API с источниками, отдельным no-context ответом и порогом релевантности.
- MWS-провайдер для embeddings и Chat Completions, проверка deployment IDs и размерности векторов.
- Публичный стенд с сессионным и общим rate limit. Ключ MWS остаётся на сервере.
02 / Реализация
Что отличает реализацию
Каждый ответ проходит одну трассу: document → chunk → bge-m3 → pgvector → gpt-oss-120b → citation. Повтор события не размножает chunks. Посторонний запрос отсекается до генерации. Корпус синтетический; очередь, индексатор, БД, векторный поиск и обе модели MWS работают реально.
Скриншоты
Экраны, формы, ошибкиСкриншоты, схемы и исходные материалы сохранены на языке оригинала; подписи и описание переведены.
03 / Технологии
Что использовано
Доли по размеру прикладных файлов Git в закреплённой версии. Каждый файл отнесён к одной подсистеме по правилам scripts/generate-stack-share.mjs; тесты, ассеты, зависимости и generated-файлы исключены. Округление — до 0,1%. Это состав кода, а не уровень владения технологиями.
FastAPI / Pydantic
HTTP-контракты, валидация, Search и Ask.
MWS Model Hub
bge-m3 для embeddings; gpt-oss-120b для ответа по контексту.
NATS JetStream
Доставка событий индексатору и повтор.
PostgreSQL / pgvector
Документы, attachments, chunks и cosine search.
SQLAlchemy / Python
Нормализация, извлечение, chunking и проверка content_hash.
04 / Решения
Как устроен проект
- Seed отправляет TenderChangedV1 через NATS; индексатор извлекает текст и атомарно заменяет chunks при изменении content_hash.
- bge-m3 возвращает 1024-компонентные embeddings. Индексатор пишет имя модели рядом с каждым chunk, а PostgreSQL VECTOR(1024) выполняет cosine search.
- Ask передаёт gpt-oss-120b только найденные фрагменты. Документы в prompt помечены как данные, а не инструкции.
- Порог 0,40 выбран после замера релевантных и посторонних запросов. Если подходящих chunks нет, generation endpoint не вызывается.
- Внешний crawler на публичном стенде выключен. Корпус синтетический, очередь, БД, векторный поиск и MWS inference работают реально.
05 / Проверка
Сценарии демки
- Найдите документ о серверах: первый результат должен содержать гарантию 36 месяцев и метку bge-m3.
- Переключитесь на Ask: gpt-oss-120b должен ответить по найденным фрагментам и показать источники.
- Выберите «Нет контекста»: при score ниже 0,40 сервис возвращает отказ без вызова модели генерации.
- Проверьте состояние корпуса: четыре документа, 16 chunks и ready у каждой записи.
Результаты проверок
- Опубликованы десять кадров версии 6c005b6: desktop, mobile, Search, Ask, no-context и validation.
- Четыре ready-документа переиндексированы в 16 векторов bge-m3 размерности 1024.
- В галерейной browser-проверке 9 сентября 2026 desktop Search занял 298 мс, Ask — 1145 мс, no-context — 115 мс; mobile Search — 137 мс, Ask — 1936 мс. Это одиночные измерения, не benchmark.
- Для релевантных тестовых запросов top cosine был 0,604–0,927; для двух посторонних — 0,278 и 0,370. Production threshold выставлен 0,40.
- Текущий снимок двух контейнеров TenderLens: около 121,4 MiB RAM суммарно при простое. Модели выполняются в MWS и не занимают RAM/GPU VPS.
- На момент снимка 9 сентября 2026 было доступно около 5,05 GiB RAM и 105,7 GiB диска на VPS.
Ограничения
- Четыре синтетических документа и 16 chunks — небольшой демонстрационный корпус, а не база реальных закупок.
- Качество модели на независимом наборе не измерялось. Показанные cosine scores описывают только запросы из проверки 9 сентября 2026.
- Лимит — 5 Search/Ask запросов в минуту на сессию и 12 запросов в минуту на весь процесс. Запросы пользователей не сохраняются.
- Inference зависит от доступности двух deployment в MWS. При недоступности провайдера readiness становится красным, автоматического перехода на fake нет.
- Worker health подтверждает соединение при старте; отдельный детектор зависшего вычисления не реализован.
Технические заметки
Модули, API, схема данных, запуск и результаты проверок.
Открыть учебник →Документация →Материалы ↓