Опирается на: @vision.md · @conventions.md · @00_project_idea.md · @workflow.md
Правило: одна итерация = один проверяемый результат. Не переходить дальше, пока текущий шаг не протестирован.
| Итерация | Название | Статус | Проверка |
|---|---|---|---|
| 0 | Каркас проекта | ✅ | uv sync без ошибок |
| 1 | Демо-данные Kaggle | ✅ | JSON читается, ≥5 датасетов |
| 2 | Ingestion | ✅ | documents.jsonl создан |
| 3 | Chunking | ✅ | chunks.jsonl, тест chunking |
| 4 | Индекс TF-IDF | ✅ | файлы в data/index/ |
| 5 | Retrieval | ✅ | top-k + score в консоли |
| 6 | Demo-ответ | ✅ | ответ + источники без UI |
| 7 | Streamlit UI | ✅ | 3 demo-вопроса в браузере |
| 8 | Тесты и README | ✅ | pytest green, README воспроизводим |
| 9 | Документ о данных и репозитории | ✅ | doc/DATA.md — источники, назначение |
| 10 | Домашнее задание | ✅ | homework/ — планирование + итерации |
Легенда: ⬜ не начато · 🔄 в работе · ✅ готово · ❌ блокер
Текущая итерация: 10
Готовность MVP: 11 / 11
-
pyproject.toml— зависимости: streamlit, scikit-learn, pytest -
.gitignore—.venv/,data/index/,__pycache__/ - Папки:
app/,scripts/,data/raw/,data/processed/,data/index/,tests/ -
app/config.py— пути,top_k, размер чанка
Проверка:
uv venv && uv sync
uv run python -c "import app.config"-
data/raw/datasets.json— 9 жалоб CFPB (изrows.csv) - Поля:
id(номер записи 0…n),name,text(на русском) -
data/raw/rows.csvв.gitignore(скачивается локально с Kaggle)
Проверка:
uv run python -c "import json; d=json.load(open('data/raw/datasets.json')); print(len(d['datasets']))"-
scripts/ingest.py— JSON →data/processed/documents.jsonl - Очистка текста, метаданные (
doc_id,name,source_file)
Проверка:
uv run python scripts/ingest.py
# → documents.jsonl, строк = числу датасетов-
app/chunker.py— нарезка по абзацам, max 400, overlap 50 - Выход:
data/processed/chunks.jsonl
Проверка:
uv run python -c "from app.chunker import ..." # или через build_index позже
uv run pytest tests/test_chunking.py -v-
scripts/build_index.py— ingest + chunk + TF-IDF fit - Сохранение:
data/index/vectorizer.pkl,matrix.npz,chunks.jsonl
Проверка:
uv run python scripts/build_index.py
# → три файла в data/index/-
app/retriever.py— загрузка индекса, cosine top-k - Возврат:
text,doc_id,score
Проверка:
uv run python -c "
from app.retriever import Retriever
r = Retriever()
print(r.search('безработица переменные', k=3))
"-
app/prompts.py— system-правила (только по контексту, отказ без данных) -
app/generator.py— ответ из top-k + список источников
Проверка:
uv run python -c "
from app.generator import ask
print(ask('Какие переменные в датасете про безработицу?'))
"
# → текст + sources с doc_id-
app/main.py— поле вопроса, top-k фрагменты, ответ, источники - Сообщение, если индекс не собран
Проверка:
uv run streamlit run app/main.pyDemo-вопросы:
- «Какие переменные в датасете про безработицу?»
- «За какой период данные об инфляции?»
- «Как приготовить борщ?» → отказ
-
tests/test_chunking.py,tests/test_retrieval.py— 3–5 тестов - Корневой
README.md— uv, build_index, streamlit, demo-вопросы
Проверка:
uv run pytest tests/ -v
# README: запуск с нуля на чистой машине-
doc/DATA.md— какие данные использованы, откуда, что индексируем / не индексируем - Раздел «Назначение репозитория» — для кого, что демонстрирует, границы MVP
- Ссылки на источники (Kaggle / CFPB и т.п.), лицензия, дата выгрузки
- Ссылка из корневого
README.mdнаdoc/DATA.md
Проверка:
# файл существует, обязательные разделы на месте
uv run python -c "
from pathlib import Path
p = Path('doc/DATA.md')
t = p.read_text(encoding='utf-8')
for s in ['## Источники данных', '## Назначение репозитория', '## Что индексируем']:
assert s in t, f'нет раздела: {s}'
print('OK')
"Структура: сначала планирование (md-файлы по одному), потом реализация (каждая итерация — отдельный шаг).
-
homework/README.md— цель задания, порядок шагов, критерии сдачи -
homework/00_planning/README.md— обзор фазы планирования - Шаги планирования (отдельный файл на каждый md в
doc/):-
homework/00_planning/step_01_project_idea.md→ @00_project_idea.md -
homework/00_planning/step_02_vision.md→ @vision.md -
homework/00_planning/step_03_conventions.md→ @conventions.md -
homework/00_planning/step_04_tasklist.md→ @tasklist.md -
homework/00_planning/step_05_workflow.md→ @workflow.md
-
-
homework/01_implementation/README.md— обзор фазы реализации - Шаги реализации (отдельный файл на каждую итерацию 0–8):
-
iter_00_scaffold.md…iter_08_tests_readme.md
-
- В каждом step-файле: что сделать, какие файлы, как проверить, ожидаемый результат
Проверка:
uv run python -c "
from pathlib import Path
required = [
'homework/README.md',
'homework/00_planning/README.md',
'homework/00_planning/step_01_project_idea.md',
'homework/00_planning/step_05_workflow.md',
'homework/01_implementation/README.md',
'homework/01_implementation/iter_00_scaffold.md',
'homework/01_implementation/iter_08_tests_readme.md',
]
for f in required:
assert Path(f).exists(), f'нет файла: {f}'
print('OK:', len(required), 'файлов')
"- Все итерации ✅ в таблице прогресса
- 3 demo-вопроса — ответ с источником; 1 negative — отказ
- Студент может пройти путь:
data/raw/→ index → Streamlit -
doc/DATA.mdописывает данные и назначение репозитория -
homework/— студент может пройти задание шаг за шагом (планирование → итерации)