Демка · 9 сентября 2026

TenderLens

Что где лежит в коде, как запускается и что проверялось.
Версия 6c005b6ef863 · подготовлено 8 сентября 2026

О проекте

Задача — собрать проверяемый поиск по разнородным тендерным файлам. От исходного документа до ответа остаётся трасса document → chunk → embedding → hit → citation, поэтому результат можно вернуть к конкретному фрагменту.

TenderLens принимает HTML, PDF, XML, JSON и TXT, приводит документы к одному контракту и режет их на стабильные chunks. Индексация идёт через NATS JetStream. bge-m3 в MWS считает embeddings, pgvector ищет близкие фрагменты, а gpt-oss-120b формирует ответ только по найденному контексту и возвращает источники.

Что отличает реализацию

Каждый ответ проходит одну трассу: document → chunk → bge-m3 → pgvector → gpt-oss-120b → citation. Повтор события не размножает chunks. Посторонний запрос отсекается до генерации. Корпус синтетический; очередь, индексатор, БД, векторный поиск и обе модели MWS работают реально.

Состав прикладного кода

Python / FastAPI 36.6%Python parsers / indexing 35.2%JavaScript / HTML / CSS 15%Python / pgvector 9.8%Python / NATS 3.4%

Доли по размеру прикладных файлов Git в закреплённой версии. Каждый файл отнесён к одной подсистеме по правилам scripts/generate-stack-share.mjs; тесты, ассеты, зависимости и generated-файлы исключены. Округление — до 0,1%. Это состав кода, а не уровень владения технологиями.

  • Четыре синтетических документа и 16 chunks — небольшой демонстрационный корпус, а не база реальных закупок.
  • Качество модели на независимом наборе не измерялось. Показанные cosine scores описывают только запросы из проверки 9 сентября 2026.
  • Лимит — 5 Search/Ask запросов в минуту на сессию и 12 запросов в минуту на весь процесс. Запросы пользователей не сохраняются.
  • Inference зависит от доступности двух deployment в MWS. При недоступности провайдера readiness становится красным, автоматического перехода на fake нет.
  • Worker health подтверждает соединение при старте; отдельный детектор зависшего вычисления не реализован.

Скриншоты, схемы и исходные материалы сохранены на языке оригинала; подписи и описание переведены.

Архитектура и схемы

  • 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 работают реально.
Компоненты опубликованного демо
Компоненты опубликованного демо · Mermaid ↓
Основной сценарий
Основной сценарий · Mermaid ↓
Размещение опубликованной версии
Размещение опубликованной версии · Mermaid ↓
Состав данных и границы хранения
Состав данных и границы хранения · Mermaid ↓
Исходный интеграционный контур; crawler выключен в публичной демке
Исходный интеграционный контур; crawler выключен в публичной демке · Mermaid ↓

Code-map: файлы и связи

Карта привязана к версии 6c005b6ef863. В таблице — экран или API, связанный модуль и данные.

ФункцияЭкран / APIМодульДанные / проверка
Начальная индексацияCLI portfoliocli._upsert_demo_record, NatsBroker, IndexerServicesources, tenders, attachments, chunks
EmbeddingsIndexer workerMwsAIProvider.embed, IndexerServicebge-m3, VECTOR(1024), embedding_model
Поискapi/v1/searchSearchService, MwsAIProvider.embedcosine distance, порог 0,40
Ответ по базеapi/v1/askSearchService, MwsAIProvider.generateнайденные chunks, gpt-oss-120b, citations
Повтор событияapi/demo/replayNatsBroker / content_hash guardобщий read-only корпус
Сессия и лимитыcookie / middlewareportfolio, auth, rate_limitapi_keys, 5/session, 12/process

Как работать с картой

  1. Перед изменением найти функцию и пройти связи до API, состояния и хранилища.
  2. Проверить входы, ошибки, повторные события и зависимые сценарии.
  3. После изменения обновить карту и затронутые схемы вместе с кодом.
  4. Выполнить связанные проверки и привязать новые материалы к версии исходников.

Сценарии и API

  1. Найдите документ о серверах: первый результат должен содержать гарантию 36 месяцев и метку bge-m3.
  2. Переключитесь на Ask: gpt-oss-120b должен ответить по найденным фрагментам и показать источники.
  3. Выберите «Нет контекста»: при score ниже 0,40 сервис возвращает отказ без вызова модели генерации.
  4. Проверьте состояние корпуса: четыре документа, 16 chunks и ready у каждой записи.

Проверка опубликованной версии

CI: CI ↗ · 84c37f0f · исторический запуск другой версии · 2026-08-27T06:43:00Z

CI: Documentation ↗ · 84c37f0f · исторический запуск другой версии · 2026-08-27T06:43:00Z

  • Black, Flake8 и MyPy пройдены для версии 6c005b6.
  • 129 unit/API тестов пройдены; MkDocs собран в strict режиме, сгенерированный code reference актуален.
  • Production-образ проверен с реальными MWS endpoints: readiness, embedding 1024 и grounded Ask.
  • В опубликованной версии Search, Ask и no-context прошли через внешний HTTPS; ошибок console и failed requests нет.
  • Viewport 390 px проверен без горизонтального overflow.
  • GitHub workflow для этой ветки не запускался; указанные проверки выполнены локально и на опубликованном стенде.

Эти проверки относятся к указанной версии. Коммерческие показатели и качество моделей на независимой выборке здесь не измерялись.

Измерения

Контейнеры TenderLens: RAM при простое и лимит · 9 сентября 2026, одиночный снимок
Контейнеры TenderLens: RAM при простое и лимит · 9 сентября 2026, одиночный снимок · Исходные данные ↓
Время запросов через HTTPS и MWS · 9 сентября 2026, по одному запуску
Время запросов через HTTPS и MWS · 9 сентября 2026, по одному запуску · Исходные данные ↓
  • Опубликованы десять кадров версии 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.

Запуск и эксплуатация

Публичная версия работает в AI_MODE=mws. API и indexer обращаются к OpenAI-совместимым MWS endpoints по HTTPS. API key передаётся контейнерам как server-side secret и не попадает в браузер, образ или Git.

bge-m3 используется и при индексации, и при запросе. После смены embedding deployment весь корпус нужно переиндексировать: векторы разных моделей в одном индексе не смешиваются. Readiness проверяет список доступных deployment IDs.

Dockerfile.portfolio собирается вне VPS; API и worker используют один закреплённый образ с отдельными лимитами. PostgreSQL и NATS доступны только во внутренней Docker-сети, API опубликован через Nginx.

После миграций CLI seed создаёт четыре синтетических документа. Повтор события безопасен благодаря content_hash. После рестарта проверяются ready у четырёх документов, 16 chunks, модель bge-m3 и размерность 1024.

Сессионный лимит равен пяти запросам в текущую UTC-минуту, общий лимит процесса — двенадцати. No-context запрос останавливается до Chat Completions. Пользовательские запросы не пишутся в БД.

Откат сохраняет предыдущий образ и release-конфигурацию. Смена embedding provider требует обратной переиндексации. Общий docker prune не используется.

Code-map связывает экран или API с модулем и данными. При правке проверяются обычный запрос, no-context, rate limit, повтор события, readiness и отсутствие ключа MWS в клиентских файлах и логах.

Стек

FastAPI / PydanticHTTP-контракты, валидация, Search и Ask.
MWS Model Hubbge-m3 для embeddings; gpt-oss-120b для ответа по контексту.
NATS JetStreamДоставка событий индексатору и повтор.
PostgreSQL / pgvectorДокументы, attachments, chunks и cosine search.
SQLAlchemy / PythonНормализация, извлечение, chunking и проверка content_hash.

Материалы и исходники

История реализации: с 20 августа 2026. Публичный стенд: с 7 сентября 2026. Реальные модели MWS подключены 9 сентября 2026.

Архив материалов на языке оригинала.