AAYMA
RU
Войти

ТойМатч

Сервис подбора до трёх event-подрядчиков под той, свадьбу или корпоратив: у каждой карточки объяснение фактами, а если подходящих меньше трёх…

Доведённый продукт
Команда «AND?» 22💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: AND?
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт

Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор

Суть

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

Как устроено

Запрос из формы получает LLM-агент, который через tool calling вызывает search_contractors. Дальше детерминированный Python: жёсткие фильтры (город, категория, занятость на дату, формат, бюджет, часы, язык), скоринг с фиксированными WEIGHTS, топ-3 и диагностика _diagnose. Затем LLM пишет объяснения по посчитанным фактам, не меняя порядок. Цикл агента хранит состояние в БД (Run.messages, Run.pending) и поддерживает паузу на подтверждение человеком. Без ключа работает mock-режим.

Ключевые решения

  • function/tool calling
  • жёсткие фильтры + взвешенный скоринг
  • диагностика пустой выдачи
  • mock-LLM режим
  • eval-прогон кейсов

Особенности

Ядро агента не привязано к предметной области: домен подключается одним файлом в core/domains/ и одной переменной в .env. Порядок карточек детерминирован, LLM только объясняет. Есть журнал шагов агента в UI, «плашки честности» и готовые подсказки вида «сдвиньте одно условие».

Стек

Python 3.12 · Django 5.2 · SQLite · gunicorn · Next.js 16 · React 19 · TypeScript · Docker Compose

Модели

OpenAI gpt-5.4-mini · OpenAI-совместимый API


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-769bc54e-and.

README

README.md

ТойМатч

ТойМатч подбирает event-подрядчиков под той, свадьбу или корпоратив: три карточки из каталога, у каждой своя причина, почему именно она. Название - от «той» и «match».

Команда: AND · Задача: #79-lite «Умный подбор подрядчиков» · Трек: Креативные индустрии

Коротко

  • Что решает. Заказчик мероприятия задаёт город, дату, тип события, категорию подрядчика и бюджет - сервис возвращает до трёх подходящих подрядчиков из каталога, и у каждого объяснение фактами, почему он здесь. Если подходящих меньше трёх или нет совсем, говорит почему и что изменить в запросе.
  • Как запустить. docker compose up --build в корне клона - без .env и ключей, интерфейс на http://localhost:3000. Без Docker: python scripts/dev.py setup, затем backend и frontend в двух терминалах. Подробнее
  • Попробовать без установки. Публичная версия: https://frontend-production-ad7c4.up.railway.app - та же версия, что в main, живая модель gpt-5.4-mini, доступна минимум до 30.09.2026. Проверка по README от неё не зависит: всё ниже запускается из клона без сети и ключей.
  • Технологии. Python и Django, Next.js и TypeScript, SQLite; языковая модель через OpenAI-совместимый API, без ключа - mock-режим. Подробнее
  • Как проверить. python scripts/verify.py печатает OK; вручную - пять запросов, по одному на каждый исход. Подробнее

На macOS и Linux интерпретатор Python обычно вызывается как python3: во всех командах этого README подставляйте его вместо python.


Описание решения и его назначение

Сервис помогает заказчику мероприятия в Казахстане выбрать event-подрядчика из каталога: вместо длинного списка - до трёх карточек, и у каждой объяснение, почему она здесь.

Заказчик уже выбрал город, дату, тип мероприятия и категорию подрядчика и задаёт бюджет; длительность, язык и пожелания - по желанию. Сервис отсекает занятых на эту дату и не подходящих по формату, бюджету, языку и часам, ранжирует оставшихся по фиксированной формуле и объясняет каждую карточку фактами: запас по бюджету, форматы, языки, цитата из описания. Если подходящих меньше трёх или нет совсем, он говорит, что именно помешало и какое одно изменение запроса даст результат.

Отбор и порядок карточек - детерминированный код, модель только пишет объяснения. Поэтому тот же запрос всегда даёт тот же порядок (требование 5 ТЗ), а отбор работает и без ключей к модели. Модель встроена как агент: она сама вызывает инструмент поиска, читает посчитанные факты и пишет по ним объяснения. Каждый шаг виден в журнале. Механизм подтверждения человеком в ядре есть, но в этой Задаче не задействован: ТЗ исключает бронирование, заявки и уведомления подрядчику.

Описание архитектуры

форма запроса ──> LLM: вызывает search_contractors с параметрами          ← агентный шаг
                        │
                        ▼  чистый Python: детерминированно, без сети и ключей
     жёсткие фильтры: город, категория, занятость на дату, формат, бюджет, часы, язык
                        ▼
     скоринг с фиксированными весами (WEIGHTS) ──> до 3 карточек + посчитанные факты
                        ▼
     меньше трёх? ──> диагностика: что помешало, какая дата, какой бюджет, сезон
                        │
                        ▼
                  LLM: объяснения к карточкам по фактам, порядок не меняет
                        ▼
     интерфейс: исход, карточки, плашки честности, «почему» и «что сделать», журнал шагов
СлойГдеЗа что отвечает
Цикл агентаbackend/agent/core/loop.pyшаг за шагом ведёт запуск, ставит на паузу, продолжает
Доступ к моделиbackend/agent/core/llm.pyединственное место вызова LLM; здесь же mock-режим
Реестр инструментовbackend/agent/core/tools.pyрегистрация, JSON-схемы, безопасный вызов
Предметная областьbackend/agent/core/domains/contractors.pyфильтры _reasons, скоринг _score и WEIGHTS, диагностика _diagnose, инструменты search_contractors и diagnose_request, промпт и демо-примеры
Каталогbackend/agent/data/contractors.csv66 профилей от организатора, читается без сети
Системный промптbackend/agent/core/prompts.pyобщая часть + BRIEF активного домена
HTTP APIbackend/agent/views.py, urls.pyJSON-эндпоинты под /api/
Интерфейсfrontend/app/page.tsx, frontend/components/форма запроса, исход и карточки (Results.tsx), журнал шагов (Journal.tsx)
Команды разработкиscripts/dev.py, scripts/verify.py, scripts/check_llm.pyустановка, запуск, тесты, сквозная проверка, проверка провайдера
Прогон качестваbackend/agent/evals/набор кейсов и отчёт о результатах в docs/EVAL.md

Состояние запуска целиком лежит в БД (Run.messages, Run.pending), поэтому запуск можно поставить на паузу ради человека и продолжить позже. Ядро не знает о предметной области: смена Задачи = новый файл в core/domains/ и одна строка в .env.

API

МетодПутьЧто делает
GET/api/healthрежим работы, модель, активный домен
GET/api/optionsсловари формы из каталога: города, категории, форматы, языки
GET/api/samplesготовые демо-запросы активного домена
POST/api/runs {task, input}запустить подбор: task - запрос, собранный формой, input - пусто
GET/api/runs/<id>статус и все шаги (интерфейс опрашивает раз в секунду)
POST/api/runs/<id>/approve {approve: bool}решение человека по действию, меняющему внешнюю систему; в этой Задаче таких действий нет, эндпоинт остаётся частью ядра

Контракт продублирован в frontend/lib/types.ts - при изменении views.py правится в том же коммите.

Используемые технологии

  • Backend: Python 3.12+, Django 5.2+ (без DRF), SQLite; gunicorn в контейнере.
  • Frontend: Next.js 16 (App Router), React 19, TypeScript 5 в режиме strict, react-markdown; без UI-библиотек.
  • Модель: любая с поддержкой tool calling через OpenAI-совместимый API.
  • Запуск: Docker Compose либо локальные venv + npm.

Инструкции по установке

Вариант 1 (рекомендуемый) - Docker

git clone https://github.com/BAITC-Hacks/hack-769bc54e-and.git
cd hack-769bc54e-and
docker compose up --build

Файл .env не нужен: без ключа приложение поднимается в mock-режиме (см. «Параметры окружения»).

Вариант 2 - локально

git clone https://github.com/BAITC-Hacks/hack-769bc54e-and.git
cd hack-769bc54e-and
python scripts/dev.py setup      # или, если есть make: make setup

Создаёт .env из .env.example, ставит виртуальное окружение и зависимости бэкенда, применяет миграции и ставит зависимости фронтенда. scripts/dev.py использует только стандартную библиотеку и работает на Windows, macOS и Linux - make ставить не нужно.

То же самое вручную:

cp .env.example .env
python -m venv backend/.venv
backend/.venv/bin/python -m pip install -r backend/requirements.txt   # Windows: backend/.venv/Scripts/python.exe
backend/.venv/bin/python backend/manage.py migrate
cd frontend && npm install

Инструкции по запуску

Docker

docker compose up --build

Локально (два терминала)

python scripts/dev.py backend     # терминал 1 -> http://localhost:8000
python scripts/dev.py frontend    # терминал 2 -> http://localhost:3000

С make - короче: make backend, make frontend.

Если порт занят

bind: address already in use на 3000 или 8000 означает, что порт держит другой процесс, а не что проект сломан. Найти и освободить:

# Linux / macOS
lsof -ti tcp:3000 | xargs kill
# Windows PowerShell
Get-NetTCPConnection -LocalPort 3000 -State Listen | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }

Либо запустить на других портах: docker compose up с ports: ["3001:3000"], тогда NEXT_PUBLIC_API_URL должен указывать на фактический адрес бэкенда.

Необходимые зависимости

  • Docker 24+ и Docker Compose v2.24+ - для варианта 1. Более старый Compose не понимает необязательный env_file и без .env не запустится. Docker Desktop должен быть запущен.
  • Python 3.12+ (команда python или python3) и Node.js 22+ - для варианта 2.
  • Python-пакеты - backend/requirements.txt, Node-пакеты - frontend/package.json.
  • Доступ в интернет нужен для работы с настоящей моделью и для веб-шрифтов Google Fonts; без сети интерфейс переходит на системный шрифт. Основной сценарий проверяется без интернета и без ключей.

Параметры окружения

Все параметры задаются в .env в корне (шаблон - .env.example). Переменные не обязательны: без .env используются значения по умолчанию.

ПеременнаяПо умолчаниюНазначение
AGENT_DOMAINcontractorsимя модуля предметной области из backend/agent/core/domains/
OPENAI_API_KEYпустоключ провайдера. Пусто → автоматически включается mock-режим
OPENAI_BASE_URLпустопусто = api.openai.com. Любой OpenAI-совместимый endpoint
OPENAI_MODELпустомодель с поддержкой tool calling. Пусто → mock-режим
LLM_MOCK01 - заскриптованная «модель» без сети. Включается сам, если пуст OPENAI_API_KEY или OPENAI_MODEL
AGENT_MAX_STEPS12предел вызовов модели за один запуск
DJANGO_SECRET_KEYdev-only-change-meключ Django
DJANGO_DEBUG1режим отладки
NEXT_PUBLIC_API_URLhttp://localhost:8000адрес API для фронтенда

Проверка без наших учётных записей (п. 5.6.6 Положения). При пустом OPENAI_API_KEY приложение работает в mock-режиме: настоящая модель заменена заскриптованным сценарием, но отбор, порядок карточек, диагностика, вызовы инструментов и журнал - настоящие, потому что их делает код, а не модель. Объяснения в карточках в этом режиме собирает код из посчитанных фактов - в том же формате, что пишет модель: ведущий факт, цена относительно бюджета, форматы, языки. Личные аккаунты и платные подписки участников для проверки не требуются. Чтобы увидеть работу с настоящей моделью, впишите в .env OPENAI_API_KEY и OPENAI_MODEL, поставьте LLM_MOCK=0 и перезапустите бэкенд. Перед этим стоит проверить провайдера:

python scripts/dev.py llm

Команда покажет endpoint, список доступных моделей и сделает один пробный вызов с tool calling - именно на нём держится агент, и поддерживают его не все модели. Смена провайдера - одна строка OPENAI_BASE_URL, код не меняется.

Это же место позволяет подключить свою модель на своём GPU: NIM-контейнер или vLLM отдают OpenAI-совместимый /v1, поэтому достаточно указать адрес инстанса. Решение не привязано к вендору - один и тот же агент работает на облачном API и на self-hosted модели. При self-hosted не оставляйте OPENAI_API_KEY пустым: пустой ключ включает mock-режим, подойдёт любая непустая строка.

Порядок проверки основного сценария работы

Автоматически

При запущенном приложении:

python scripts/verify.py            # или: python scripts/dev.py verify

Скрипт (только стандартная библиотека Python) проходит весь путь: /api/health → примеры → запуск подбора → готовый ответ. Печатает OK и возвращает код 0, если сценарий пройден.

Ожидаемый вывод:

health      ok    домен=contractors, mock (без ключа)
samples     ok    5 шт., берём «Ведущий на свадьбу, 15 октября»
run         ok    id=...
report      ok    шагов: 4 (thought, tool_call, tool_result, final)
note        подтверждение человека в этом сценарии не потребовалось

OK: основной сценарий пройден

Тот же скрипт проверяет публичную версию, там вместо mock в первой строке будет модель gpt-5.4-mini:

python scripts/verify.py --api https://backend-production-93859.up.railway.app

Как выглядят объяснения настоящей модели

Проверка без ключа показывает объяснения, собранные кодом. Тексты, которые пишет модель на тех же запросах, сохранены дословно в docs/REAL_EXAMPLES.md: пять исходов, gpt-5.4-mini, с датой и временем прогона. Их можно сверить с JSON инструмента, который лежит рядом в журнале.

Вручную, в браузере

  1. Открыть http://localhost:3000 или публичную версию https://frontend-production-ad7c4.up.railway.app.
  2. Заполнить пять обязательных полей и нажать «Подобрать подрядчиков». Пока поле не заполнено, кнопка неактивна, а под ней написано, чего не хватает.
  3. Справа появятся плашка исхода и карточки; под ними свёрнутый журнал шагов агента, он раскрывается по нажатию на «Как получен результат».

Запросы, на которых видны все исходы (формат везде - свадьба, кроме последнего):

КатегорияГородДатаБюджет, ₸Что увидите
ВедущийАлматы15.10.20261 000 000«Полная выдача»: проходят 5 из 10, показаны 3 лучших - здесь видно ранжирование; объяснения и плашки честности
ВедущийАлматы26.12.20261 000 000«Меньше трёх»: одна карточка, заняты 9 из 10, «Почему» и «Что можно сделать» - тот же запрос, другая дата
ИнструменталистАлматы15.10.20261 000 000редкая категория: все 3 профиля в выдаче
ОтельАлматы26.12.20263 000 000«Никто не подошёл»: причины отсева, подсказка и сезонная заметка про декабрь
Лайв-бэндАстана20.11.20261 500 000«Нет в каталоге»: в Астане такой категории нет, подсказка - где она есть; формат - корпоратив

После выдачи доступны две кнопки. «Скрыть имена» убирает имена, категории, цены и цитаты, а упоминания имени в тексте заменяет многоточием: карточки должно быть можно различить по одним объяснениям (требование ТЗ к объяснениям). «А если другая дата?» показывает выдачу на вторую дату рядом с первой и отмечает, кто есть только на одной из них, - например, «Ведущий» на 15.10 и 26.12.

Повторный запуск того же запроса даёт тот же порядок карточек. Ответ с настоящей моделью укладывается в 10 секунд (см. docs/EVAL.md), в mock-режиме - мгновенно.

Тесты

python scripts/dev.py check     # тесты Django + tsc --noEmit
python scripts/dev.py eval      # прогон кейсов, отчёт в docs/EVAL.md

docs/EVAL.md - отчёт о прогоне качества: какие проверки выполняются и что они дали на кейсах из backend/agent/evals/cases.contractors.json. Кейсов 10, по требованиям Definition of Done; последний прогон на настоящей модели - 10 из 10, все ответы быстрее ориентира 10 с. Отчёт показывает качество на наборе примеров, а не на одном удачном прогоне.

Принятые допущения

Ответов от организаторов на уточняющие вопросы не будет, поэтому мы работали по тексту ТЗ и двум присланным файлам. В двенадцати местах ТЗ допускает больше одного прочтения, и каждое из них мы закрыли решением, а не вопросом. Ниже - что решили, почему и чем это проверяется. Тесты лежат в backend/agent/tests.py и запускаются командой python scripts/dev.py check.

Меняют поведение отбора

1. Бюджет - потолок на одного подрядчика. Поле называется price_from_kzt, «цена от, ₸ за мероприятие», а вход по ТЗ - «бюджет (₸)» в одном ряду с категорией, то есть на одну позицию. Фильтр: price_from ≤ бюджет. Проверка: test_diagnosis_names_the_budget_that_would_help.

2. Детерминизм обязателен для порядка, текст объяснений может отличаться. Требование 5 говорит про порядок карточек. Порядок задаёт код и от модели не зависит вообще; формулировки пишет LLM, и между запусками они могут разниться. Проверка: test_order_is_deterministic - пять прогонов, один порядок.

3. Язык - жёсткий фильтр, но только когда он указан. В ТЗ язык опционален. Указан - подрядчик обязан его заявить: клиент, которому нужен казахский, не обрадуется ведущему без казахского. Не указан - фильтр не применяется, но широта языков даёт небольшой плюс в скоринге. Последствие: запрос с казахским отсекает 42 профиля из 66. Это намеренно. Длительность работает так же: указана - отсекает тех, у кого max_hours меньше запрошенного; профили без часов проходят (допущение 7). В ТЗ (требование 6) названы только занятость, бюджет и формат, язык и часы отсекают жёстко по нашему решению.

4. Не проходящий по бюджету в карточки не попадает, но виден среди отсеянных. Требование 3 запрещает показывать занятых на дату. Про бюджет такого запрета нет, но карточка - это рекомендация, а рекомендовать то, что клиенту не по карману, нечестно. Поэтому такие кандидаты уходят в список отсеянных (rejected в ответе поиска) с точной причиной и процентом превышения, а подсказки (suggestions) называют минимальный достаточный бюджет.

Краевые случаи

5. Дата вне окна 23.09–31.12.2026 - предупреждение, а не отказ. Календарь занятости в датасете ограничен этим окном. Вне его мы не знаем, кто занят, и молча считать всех свободными значило бы соврать. Поиск отрабатывает, но ответ содержит warning о том, что данных о занятости на эту дату нет, и интерфейс его показывает. Проверка: test_date_outside_the_calendar_window_is_flagged.

6. «Зарубежье» - отдельный город, в выдачу по Алматы и Астане не подмешивается. В датасете такой профиль один. Клиент, ищущий подрядчика в Астане, не ждёт зарубежного. Если категории нет в его городе, подсказки честно скажут, где она есть.

7. max_hours = null проходит любой фильтр по длительности. ТЗ прямо говорит: пусто означает, что работа не привязана к присутствию - флорист, декоратор, сувениры. Отсекать их по часам значило бы терять правильных кандидатов. Проверка: test_profile_without_max_hours_survives_duration_filter.

8. Категория обязательна на входе. По легенде клиент уже получил каталог по своей категории, а требование 6 предусматривает исход «в этом городе такой категории нет» - значит, категорию задаёт пользователь. Поиск «по всем категориям сразу» не поддерживается.

Данные и подача

9. Свои синтетические профили не добавляли. ТЗ это разрешает, но 66 профилей хватает на все сценарии Definition of Done, включая пустой результат и редкие категории. Добавление своих записей размывает границу между данными организатора и нашими. Если добавим - только с synthetic: true и видимой пометкой в карточке; механизм пометки уже работает на 13 синтетических профилях из исходного датасета.

10. Интерфейс и объяснения - на русском. Описания подрядчиков в датасете русские, работаем в казахстанском контексте. Промпты и описания инструментов - на английском, как и остальной код.

11. Профиль с несколькими категориями полноправен в каждой. categories - список, фильтр работает по вхождению. Проверка: test_category_filter_matches_any_of_the_profile_categories.

12. Источник данных - присланный CSV, положенный в репозиторий. ТЗ упоминает .jsonl как основной формат, но нам прислали .csv и HTML-превью. Файл лежит в backend/agent/data/contractors.csv: проверяющий разворачивает проект без доступа к Google Drive и без интернета.

Использованные сторонние компоненты

Раскрытие по п. 5.4.4 Положения.

КомпонентЛицензияРоль в проекте
Django, django-cors-headersBSD-3-ClauseHTTP-слой и ORM
gunicornMITзапуск бэкенда в контейнере
python-dotenvBSD-3-Clauseчтение .env
openai (python SDK)Apache-2.0доступ к модели
Next.js, React, react-domMITинтерфейс
react-markdownMITотображение объяснений модели
TypeScriptApache-2.0типизация фронтенда
Golos Text, JetBrains Mono (Google Fonts)OFL-1.1шрифты
Базовые образы Docker python:3.12-slim, node:22-slimPSF-2.0, MITконтейнеры бэкенда и фронтенда
Датасет event-подрядчиков, 66 профилейпредоставлен организатором вместе с ТЗ Задачи #79-liteкаталог для подбора, backend/agent/data/contractors.csv; не изменялся, наблюдения - docs/DATASET_NOTES.md
Языковая модель OpenAI через API (в последнем прогоне - gpt-5.4-mini)условия провайдеравызов инструмента и тексты объяснений; не дообучалась

Готовых чужих решений в проекте нет. Модель не дообучалась: ТЗ это исключает.

Что было готово до начала соревновательной части

Раскрытие по п. 5.4.4.2 и 5.4.5 Положения.

До 23.09.2026, 13:00 командой самостоятельно был подготовлен технический шаблон: каркас Django + Next.js, цикл агента, реестр инструментов, механизм подтверждения человеком, журнал шагов, mock-режим, Docker-сборка и тесты. Шаблон не содержит функциональности, относящейся к Задаче хакатона, и не является готовым продуктом.

Функциональность, решающая Задачу, целиком разработана в соревновательной части: домен подбора backend/agent/core/domains/contractors.py, его тесты в backend/agent/tests.py и кейсы backend/agent/evals/cases.contractors.json, эндпоинт /api/options в backend/agent/views.py, форма запроса в frontend/app/page.tsx, исход и карточки в frontend/components/Results.tsx и frontend/lib/results.ts, а также SCOPE.md, TASKS.md и docs/DATASET_NOTES.md. Датасет получен от организатора в день хакатона. История разработки - в коммитах этого репозитория.

Использование AI-инструментов

Разрешено п. 5.4.12 Положения. Команда пользовалась тремя инструментами:

  • Claude Code - написание и ревью кода, тесты, документация. Коммиты, сделанные с его помощью, помечены в истории строкой Co-Authored-By: Claude.
  • Codex (OpenAI) - генерация и рефакторинг кода.
  • ChatGPT - разбор ТЗ и тексты.

Правила для кодинг-агентов - в AGENTS.md: тест на каждое изменение отбора, зелёный python scripts/dev.py check перед коммитом, неизменная архитектура «отбор - код, объяснения - модель». Внутри самого продукта модель вызывается только через backend/agent/core/llm.py.

Команда и вклад участников

Вклад каждого виден в истории коммитов: имя в первом столбце совпадает с автором в git.

УчастникGitHubЧто делал
Damir Doskulov (капитан)@dsklffразбор Задачи и план; домен подбора - фильтры, скоринг, диагностика, подсказки; тесты и eval, прогон на живой модели; SCOPE.md, TASKS.md
Nurbek Gabdullin@nurbekgabdullinформа запроса, /api/options со словарями каталога, плашки честности в карточках
Amantur Amangeldiyev@amangeldiyevкарточки подбора, три исхода и диагностика в интерфейсе, правки формы; допущения в README, заметки о датасете, почасовой журнал

Известные упрощения

Заявлены честно, чтобы эксперт не тратил время на их поиск:

  • фоновые потоки вместо очереди задач (для продакшена - Celery/RQ, интерфейс тот же);
  • SQLite вместо полноценной СУБД;
  • нет авторизации, CORS открыт, ALLOWED_HOSTS = ["*"] - конфигурация для демонстрации;
  • релевантность описания считается лексически, по основам слов, а не эмбеддингами: так отбор работает без сети и ключей;
  • каталог кэшируется при первом обращении - после правки CSV нужен перезапуск бэкенда;
  • данные о занятости есть только на окно 23.09–31.12.2026;
  • веса скоринга подобраны вручную и зафиксированы в WEIGHTS;
  • длина объяснения (1–2 предложения) задана промптом и проверяется прогоном, а не кодом: в редких случаях модель пишет три предложения.

Подробнее - в SCOPE.md, раздел «Известные ограничения».

Внутренние документы

TASKS.md - доска задач команды · CLAUDE.md - разбор Задачи · SCOPE.md - границы решения и известные ограничения · AGENTS.md - правила разработки · docs/POLOZHENIE.md - Положение хакатона · docs/HOURLY.md - почасовой журнал работы · docs/EVAL.md - отчёт о прогоне качества: что проверяется и результаты · docs/TEAM_WORKFLOW.md - как работаем втроём · docs/DEMO_CHECKLIST.md - сценарий демонстрации · docs/PITCH.md - заготовка питча · docs/DATASET_NOTES.md - что мы нашли в датасете · docs/W_REVIEW.md - проверка W1–W8 и сценарии воспроизведения.

Критерии оценки → где это в решении

Пять критериев технического отбора Задачи и где эксперт найдёт каждый: в коде, в демо и в проверках. Запросы из столбца «В демо» - из раздела «Порядок проверки основного сценария работы».

КритерийВ кодеВ демоЧем проверено
Соответствие задаче и работоспособность (25)вход и жёсткие фильтры - search_contractors, _reasons в contractors.py; не больше трёх карточек - MAX_CARDS; исходы - поле outcome; интерфейс - Results.tsxпять запросов из таблицы проверки: полная выдача, меньше трёх, редкая категория, никто не подошёл, нет в каталоге; «А если другая дата?» - две выдачи рядомtest_never_more_than_three_cards, test_busy_contractor_is_excluded, test_three_outcomes_are_distinguishable, test_two_dates_give_different_results в tests.py; python scripts/verify.py → OK
Техническая реализация, AI и agentic AI (25)цикл агента - loop.py, реестр инструментов - tools.py, единственный вызов модели - llm.py; модель сама вызывает search_contractors и diagnose_request, а объяснения пишет по формату REPORT_FORMAT; порядок задаёт код - _score, WEIGHTSжурнал под результатом: рассуждение → вызов инструмента → результат → ответ; повторный запуск даёт тот же порядокtest_order_is_deterministic, test_equal_scores_are_ordered_by_meaning_not_by_id, test_ranking_uses_the_human_text_not_the_model_argument; 10 из 10 кейсов на настоящей модели - EVAL.md
README и воспроизводимость (25)датасет в репозитории - contractors.csv; mock-режим без ключей - LLM_MOCK в llm.py; команды без make - dev.py; сквозная проверка - verify.pydocker compose up --build из чистого клона без .env, затем python scripts/verify.pypython scripts/dev.py check: тесты Django и tsc --noEmit; двенадцать допущений с тестами - раздел «Принятые допущения»
Ценность и применимость (15)факты для объяснения - _score; цитата-доказательство - _quote; чем кандидат отличается от соседей - _standouts; что изменить в запросе - _suggestions, _nearby_dates, _budget_needed; сезон - _season_note; плашки честности - flags и HonestyBadges в Results.tsx«Ведущий, 15.10»: у каждой карточки своё объяснение - цена относительно бюджета, форматы, языки - и цитата из описания; «Отель, 26.12»: почему никого нет и что сделать; «Скрыть имена» - карточки различимы по одним объяснениямtest_quote_is_always_a_real_fragment_of_the_description, test_cards_carry_comparative_facts, test_diagnosis_names_the_budget_that_would_help, test_suggestions_never_offer_what_is_already_shown, test_cards_carry_honesty_flags
Потенциал развития и оригинальность (10)диагностика «сдвиньте одно условие» - _diagnose, _relaxed; смена провайдера и self-hosted модель - одна строка OPENAI_BASE_URL (раздел «Параметры окружения»); новая Задача - новый файл в domains/«Ведущий, 26.12» против «15.10»: одна карточка вместо трёх, подсказка перенести дату и сезонная заметкаtest_diagnosis_reports_when_no_single_change_helps, test_exhausted_rare_category_says_so_instead_of_advising, test_availability_note_differs_between_dates

Куда развивать. Релевантность описания через эмбеддинги вместо основ слов - ТЗ это разрешает, и отбор останется детерминированным, если посчитать векторы заранее. Подбор комплекта одного уровня: ведущий, фотограф и зал под общий бюджет. Для этого подбор по одной категории уже даёт всё нужное - факты, диагностику и честные исходы.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
69
Авторы
4
Файлы
69
Ветки
9

Авторы коммитов

Damir Doskulov 32amangeldiyev 22Nurbek Gabdullin 14Nurbek Gabdullin 1

История коммитов

  • 2026-09-23 17:53docs: C9 — видео переснято с публичной версии и живой модельюamangeldiyev
  • 2026-09-23 17:49час 5: финальное ревью, публичная версия на Railway, ТойМатч, демо и сверка чек-листаamangeldiyev
  • 2026-09-23 17:37Correct participant name in README.mdNurbek Gabdullin
  • 2026-09-23 17:36docs: C10 — публичная версия передеплоена на 5717e44amangeldiyev
  • 2026-09-23 17:31docs: короткое тире в абзаце про публичную версиюDamir Doskulov
  • 2026-09-23 17:31docs: ТойМатч - новое имя и слоган, README сверен и без длинных тиреDamir Doskulov
  • 2026-09-23 17:25docs: C10–C11 — публичная версия на Railway, ссылка в READMEamangeldiyev
  • 2026-09-23 17:21fix: финальное ревью — имена скрыты целиком, ранжирование в демо, цитаты, документыDamir Doskulov
Все коммиты (69)
  • 2026-09-23 16:53fix: show every rejected contractor with all reasons (W3)Nurbek Gabdullin
  • 2026-09-23 16:53fix: keep date comparison tied to its submitted request (W2)Nurbek Gabdullin
  • 2026-09-23 16:53fix: preserve verbatim evidence quotes (W5)Nurbek Gabdullin
  • 2026-09-23 16:53feat: explain honesty badges and verify W acceptance scenarios (W6)Nurbek Gabdullin
  • 2026-09-23 16:48docs: C9 — видео-демо записано, осталось выложить по ссылкеamangeldiyev
  • 2026-09-23 16:48docs: README — как выглядят объяснения без ключа после 55336adamangeldiyev
  • 2026-09-23 16:47docs: C7 — сценарий демо на 2 минуты под нашу Задачу, прогон по таймеруamangeldiyev
  • 2026-09-23 16:47docs: C8–C12 — чистый клон, сверка чек-листа, деплой снятamangeldiyev
  • 2026-09-23 16:46feat: обязательные поля формы помечены звёздочкойDamir Doskulov
  • 2026-09-23 16:38fix: полное ревью после слияния — занятость на экране, объяснения без ключаDamir Doskulov
  • 2026-09-23 16:25час 4: B6–B10, ревью домена, README под проверку экспертом, чистый клон с Docker без ключейamangeldiyev
  • 2026-09-23 16:24fix: третье ревью — выделения по делу, цитата у всех, готовая первая строкаDamir Doskulov
  • 2026-09-23 16:20docs: README сразу отвечает на четыре вопроса эксперта и запускается на macOSamangeldiyev
  • 2026-09-23 16:17feat: source options from domain vocabularyNurbek Gabdullin
  • 2026-09-23 16:17feat: show collapsed rejected candidatesNurbek Gabdullin
  • 2026-09-23 16:17fix: render diagnosis hints verbatimNurbek Gabdullin
  • 2026-09-23 16:17feat: show response time with resultsNurbek Gabdullin
  • 2026-09-23 16:17chore: verify strict frontend typesNurbek Gabdullin
  • 2026-09-23 16:16chore: подтверждён допуск — чистый клон без ключей проходит сценарийDamir Doskulov
  • 2026-09-23 16:11fix: второе ревью — уникальные выделения, чистый сигнал, ответ без ключаDamir Doskulov
  • 2026-09-23 16:09docs: C3 — README заполнен и описывает наш продукт, а не шаблонamangeldiyev
  • 2026-09-23 16:09docs: C4 — таблица «критерий → где в коде, в демо и чем проверено»amangeldiyev
  • 2026-09-23 16:09docs: C6 снята — синтетические профили для демо не нужныamangeldiyev
  • 2026-09-23 16:08docs: C2 — датасет прочитан глазами, заметки в docs/DATASET_NOTES.mdamangeldiyev
  • 2026-09-23 16:02feat: прогон проверяет качество объяснений, а не только их наличиеDamir Doskulov
  • 2026-09-23 16:00feat: add anonymous explanation modeNurbek Gabdullin
  • 2026-09-23 16:00feat: compare contractor results by dateNurbek Gabdullin
  • 2026-09-23 15:58час 3: форма и API, карточки, плашки, три исхода, допущения в README, правки по ревьюamangeldiyev
  • 2026-09-23 15:55fix: плашки честности не приписывают команде данные организатораamangeldiyev
  • 2026-09-23 15:53docs: SCOPE.md сверен с кодом после правок по ревьюDamir Doskulov
  • 2026-09-23 15:53fix: внешнее ревью — честная диагностика, живые совпадения, сравнимые карточкиDamir Doskulov
  • 2026-09-23 15:52docs: C1 — принятые допущения перенесены из SCOPE.md в READMEamangeldiyev
  • 2026-09-23 15:46feat: B5 — три исхода различимы, пустого экрана нетamangeldiyev
  • 2026-09-23 15:40feat: show contractor honesty badgesNurbek Gabdullin
  • 2026-09-23 15:32feat: словарь каталога в схеме инструмента и честная реакция на чужие значенияDamir Doskulov
  • 2026-09-23 15:29feat: демо закрывает требование 17, диагностика едет вместе с поискомDamir Doskulov
  • 2026-09-23 15:22fix: B1 — форма принимает круглый бюджет и не засоряет подбор подписямиamangeldiyev
  • 2026-09-23 15:21feat: B3 — карточки подбора вместо markdown-отчётаamangeldiyev
  • 2026-09-23 15:15docs: новая волна задач A по итогам аудита доменаDamir Doskulov
  • 2026-09-23 15:14feat: expose contractor catalog optionsNurbek Gabdullin
  • 2026-09-23 15:14feat: add structured contractor request formNurbek Gabdullin
  • 2026-09-23 15:12feat: B3 — карточки подбора вместо markdown-отчётаamangeldiyev
  • 2026-09-23 15:05docs: SCOPE.md с принятыми допущениями, AGENTS.md под нашу ЗадачуDamir Doskulov
  • 2026-09-23 15:05B — продукт и интерфейс - B1amangeldiyev
  • 2026-09-23 15:03fix: четыре дефекта по итогам ревью доменаDamir Doskulov
  • 2026-09-23 14:57chore: сквозной прогон стека на живой моделиDamir Doskulov
  • 2026-09-23 14:56perf: замер моделей и гарантия подсказок на детерминированном слоеDamir Doskulov
  • 2026-09-23 14:50feat: готовые подсказки «сдвиньте одно условие», сезон и проверка двух датDamir Doskulov
  • 2026-09-23 14:45feat: цитата-доказательство и чистка эха запросаDamir Doskulov
  • 2026-09-23 14:43feat: ответ в виде карточек и запрет общих фразDamir Doskulov
  • 2026-09-23 14:38docs: TASKS.md — единая доска задач командыDamir Doskulov
  • 2026-09-23 14:36feat: домен подбора подрядчиков — фильтры, скоринг, диагностикаDamir Doskulov
  • 2026-09-23 14:20docs: CLAUDE.md — разбор Задачи #79-lite и план работыDamir Doskulov
  • 2026-09-23 14:03Merge remote-tracking branch 'hack/main'Damir Doskulov
  • 2026-09-23 14:03chore: CLAUDE.md не попадает в репозиторийDamir Doskulov
  • 2026-09-23 13:08docs: путь self-hosted модели (NVIDIA Brev) и ловушка с пустым ключомDamir Doskulov
  • 2026-09-23 13:01fix: пустой OPENAI_BASE_URL ломал клиента, а промпт — паузу на человекаDamir Doskulov
  • 2026-09-23 12:36feat: форма ввода шире — CSV читается без горизонтальной прокруткиDamir Doskulov
  • 2026-09-23 12:32feat: интерфейс под демо — время шагов, итог цифрами, фокус на журналеDamir Doskulov
  • 2026-09-23 12:17fix: убран неиспользуемый листинг запусков и устаревшие подсказкиDamir Doskulov
  • 2026-09-23 11:13chore: стартовый шаблон agentic-приложения для HackAlem AIDamir Doskulov
Структура репозитория (69 файлов)
.env.example
.gitignore
AGENTS.md
CLAUDE.md
Makefile
README.md
SCOPE.md
TASKS.md
backend/.dockerignore
backend/Dockerfile
backend/agent/__init__.py
backend/agent/apps.py
backend/agent/core/__init__.py
backend/agent/core/domains/__init__.py
backend/agent/core/domains/_contract.py
backend/agent/core/domains/contractors.py
backend/agent/core/domains/example.py
backend/agent/core/llm.py
backend/agent/core/loop.py
backend/agent/core/prompts.py
backend/agent/core/tools.py
backend/agent/data/contractors.csv
backend/agent/evals/__init__.py
backend/agent/evals/cases.contractors.json
backend/agent/evals/cases.json
backend/agent/evals/run.py
backend/agent/migrations/0001_initial.py
backend/agent/migrations/0002_run_completion_tokens_run_prompt_tokens.py
backend/agent/migrations/__init__.py
backend/agent/models.py
backend/agent/tests.py
backend/agent/urls.py
backend/agent/views.py
backend/config/__init__.py
backend/config/settings.py
backend/config/urls.py
backend/config/wsgi.py
backend/manage.py
backend/requirements.txt
docker-compose.yml
docs/DATASET_NOTES.md
docs/DEMO_CHECKLIST.md
docs/EVAL.md
docs/HOURLY.md
docs/PITCH.md
docs/POLOZHENIE.md
docs/REAL_EXAMPLES.md
docs/TEAM_WORKFLOW.md
docs/W_REVIEW.md
frontend/.dockerignore
frontend/AGENTS.md
frontend/Dockerfile
frontend/app/globals.css
frontend/app/layout.tsx
frontend/app/page.tsx
frontend/components/Journal.tsx
frontend/components/Results.tsx
frontend/lib/api.ts
frontend/lib/brand.ts
frontend/lib/results.ts
frontend/lib/types.ts
frontend/next-env.d.ts
frontend/next.config.ts
frontend/package-lock.json
frontend/package.json
frontend/tsconfig.json
scripts/check_llm.py
scripts/dev.py
scripts/verify.py
Ветки (9)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.