20 KiB
План реализации «Контракт-чек» (Ollama Cloud / hosted LLM)
Примечание: этот документ описывает исходную «ленивую» архитектуру с arq+Redis (очередь), Selectel S3 (хранилище) и единым Docker-образом с
MODE=api|worker|bot. Этап 0 (прототип) актуален. Этапы 1+ supersededARCHITECTURE.md, где реализована production-архитектура: RabbitMQ-конвейер, MinIO, 4 worker-а (extract, prescreen, analyze, notify), aiogram-бот, B2B API, 7 Dockerfile-ов вsrv/, dependency-groups (PEP 735).
Принцип: ленивая архитектура. Каждый этап — минимальный работающий срез. Никаких абстракций «на потом». K8s, RabbitMQ, микросервисы — не нужны до $10k MRR.
LLM: Ollama Cloud — hosted-инференс открытых моделей. Те же модели и API (
/api/chat,format: json), что и у локального Ollama, но без своего железа: платим подписку + metered overage, инференс бежит у Ollama (NCP-партнёры, в основном США).
О выборе Ollama Cloud
- API: стандартный Ollama HTTP API на cloud-эндпоинте. Авторизация —
API-ключ (bearer) из настроек аккаунта Ollama. Структурный вывод через
format: json(или JSON-schema) для парсимого отчёта. - Модели: только cloud-enabled (см.
ollama.com/search?c=cloud). Рекомендация —qwen2.5:14b(сильный русский + reasoning). Fallback — более лёгкаяqwen2.5:7bпри 429/квоте. Теги БЕЗ суффикса-instruct(его нет в Ollama):qwen2.5:14b,llama3.1:8b,gemma2:9bи т.п. format: json≠ соответствие схеме. Ollama гарантирует синтаксис JSON; соответствие вашей pydantic-схеме проверяем на клиенте + цикл repair/retry. Не полагаемся на модель.
Стоимость и лимиты Ollama Cloud (актуально на момент планирования)
| План | Цена | Конкарренси | Назначение | Статус |
|---|---|---|---|---|
| Free | $0 | 1 | тесты | открыт |
| Pro | $20/мес | 3 | рабочая лошадка MVP | открыт |
| Max | $100/мес | 10 | тяжёлый поток | приостановлен |
| Team | $25/seat | — | команда (5 seat min) | waitlist |
| Enterprise | custom | custom | продакшн SaaS | по запросу |
- Usage: rolling-лимиты — сессия 5 ч + недельный 7 дн. Pro = 50× Free. При превышении — metered overage (добиваем баланс, оплата по токенам модели). Жёсткой стены нет, но конкарренси = 3 на Pro.
- Хостинг: в основном США (подключаются EU/Singapore). Это ломает 152-ФЗ data-residency, см. раздел «Риски».
Экономика проекта (честно)
- Опекс фиксированный до квоты: VPS ~4 €/мес + Ollama Cloud Pro $20/мес + Selectel S3 (копейки). Итого ~$25–30/мес на старте.
- Рост объёма → metered overage Ollama Cloud по токенам. Маржа на pay-per-doc (199 ₽) остаётся, если один договор съедает мало квоты. Это обязательно измерить на этапе 0 (квота/документ).
- В отличие от локального Ollama — нет потолка по железу, но есть потолок по конкарренси (3) и плавающий cost при overage. В отличие от GigaChat — cost в $, не в ₽, и нет РФ-локализации данных.
Архитектура — hexagonal (ports & adapters)
Ядро и адаптеры разделены. Это снимает связность «бот знает про БД/S3/LLM» и позволяет добавлять каналы доставки (CLI, веб, B2B API) без дублирования бизнес-логики.
- Ядро (application core):
api(FastAPI/uvicorn) — владеет БД, S3, кредитами, оплатой; принимает документы, резервирует кредит на enqueue, ставит arq-задачи в redis, отдаёт отчёты/профиль. Аутентификация адаптеров — общийSERVICE_TOKEN.worker(arq) — разбирает очередь: S3 → экстракт → (OCR) → chunker → analyzer → Ollama Cloud → Report. Idempotency + refund при ошибке.- Общий доменный пакет
contract_check/(extractor,chunker,llm_client,analyzer,checklist,report_schema,ocr,storage,db,models,payments,quota) — используется только ядром.
- Адаптеры (delivery = HTTP-клиенты к
api):bot(aiogram) — Telegram: приём документа →POST /documents(multipart) → отдача отчёта. Не трогает БД/S3/redis/LLM.cli— пользовательский/отладочный CLI поверх api (новый, отдельный от прототипа).web(React SPA) — этап 2, тоже HTTP-клиент к api.
- Прототип
prototype.py(stage 0) — standalone, in-process LLM; артефакт go/no-go, не адаптер и не ядро.
Следствие для планирования: api + worker строятся на этапе 1 (боту-адаптеру нужен api). Этап 2 = добавление адаптера
web+ подписок (api уже есть).
Этап 0 — Прототип (1 выходной)
Цель: доказать, что модель через Ollama Cloud реально находит риски, и измерить задержку + квоту на один договор (для юнит-экономики).
Деливерэбл: один файл prototype.py — end-to-end.
PDF/DOCX → pymupdf/python-docx → текст →
prompt с чек-листом → Ollama Cloud (format: json) → отчёт в markdown
Что делаем:
- Завести аккаунт Ollama, взять API-ключ, положить в
.env. - Поставить
pymupdf,httpxв venv. - Один скрипт: читает PDF → достаёт текст → промпт с чек-листом из 10 пунктов → дёргает Ollama Cloud → печатает отчёт.
- Прогнать 3–5 реальных договоров (NDA, оказание услуг, поставка).
- Зафиксировать: качество находок, задержка (сек), % битых JSON, сколько квоты/токенов на договор.
Чего НЕ делаем: база, веб, бот, оплату, деплой. Один скрипт локально.
Критерий успеха: отчёт по реальному договору содержит хотя бы 3 осмысленные находки с цитатами; задержка < 60 сек; квота/договор даёт понятную маржинальность при 199 ₽.
Этап 1 — Telegram-бот MVP (2–3 недели)
Цель: первые платящие пользователи. Бот = самый быстрый путь до ЦА.
1.1 Структура проекта
contract_check/
├── pyproject.toml # hatchling, deps (core + adapters)
├── docker-compose.yml # postgres, redis, api, worker, bot (+ profile app = prototype)
├── .env.example
├── src/contract_check/
│ ├── main.py # диспетчер: MODE=api|worker|bot|cli
│ ├── prototype.py # stage-0 standalone (in-process LLM) — НЕ в hexagonal
│ │ # ── ЯДРО (application core): владеет БД/S3/кредитами/LLM ──
│ ├── api.py # FastAPI: /documents, /reports/{id}, /me, /healthz
│ ├── worker.py # arq analyze_document(doc_id): S3→extract→OCR→analyze→Report
│ ├── analyzer.py extractor.py chunker.py ocr.py
│ ├── llm_client.py checklist.py report_schema.py
│ ├── storage.py db.py models.py payments.py quota.py
│ │ # ── АДАПТЕРЫ (delivery): HTTP-клиенты к api, без БД/S3/LLM ──
│ ├── bot.py # aiogram: приём документа → POST /documents → отчёт
│ └── cli.py # CLI поверх api (новый, не прототип)
├── migrations/ # alembic
└── tests/
1.2 База данных — 3 таблицы
users (id, telegram_id, created_at, credits_left)
documents (id, user_id, s3_key, status, created_at)
reports (id, document_id, content_json, created_at)
credits_left — prepaid-кредиты (pay-per-doc). Подписок в v1 нет.
status хранить как TEXT + CHECK, не Postgres-ENUM (миграции проще).
1.3 Поток (резервирование кредита на enqueue)
Юзер кидает PDF в бот
→ бот (adapter): multipart'ом шлёт файл в api: POST /documents (+ SERVICE_TOKEN)
→ api (core): get_or_create_user, проверяет credits_left > 0, РЕЗЕРВИРУЕТ (-= 1),
грузит файл в S3, создаёт Document(status=queued), ставит arq-таску → 202 + job_id
→ worker (core): idempotency guard по status, достаёт из S3 → текст → (OCR если скан)
→ worker: chunker при необходимости → analyzer → Ollama Cloud → отчёт
→ worker: pydantic-валидация + repair-loop; пишет Report, status=done
→ при ошибке: status=failed, ВОЗВРАТ кредита (+1)
→ бот: опрашивает GET /reports/{id} (или push), отправляет отчёт
(с разбивкой/файлом при >4096 симв.), футер-disclaimer
1.4 Оплата (минимум)
- ЮKassa: бот генерирует ссылку на оплату N ₽ → webhook пополняет
credits_left. - Один тариф: 199 ₽ = 1 документ. Без подписок.
1.5 Деплой
- Один VPS (Hetzner CX22 ~4 €/мес или Selectel под РФ-локацию БД).
- Docker Compose:
postgres,redis,api,worker,bot. Без GPU. (Бот — адаптер к api; веб-адаптерwebдобавится на этапе 2.) - S3 — Selectel Object Storage.
- Домен + HTTPS только для webhook ЮKassa; на старте ngrok (с оговоркой: URL на free-ngrok меняется → лучше сразу дешёвый домен + Caddy).
1.6 Критерий успеха
10 платящих. MRR ~2 000 ₽. Отчёты не вызывают жалоб «ничего не нашёл». Ollama Cloud Pro покрывает нагрузку без ухода в overage.
Этап 2 — Веб + подписки (3–4 недели)
Цель: B2B-веб-интерфейс и подписки.
2.1 Что добавляем
apiуже построен на этапе 1 (T-E1-015). На этапе 2 добавляем: роуты подписок/счетов, Telegram Login auth (сессия/JWT) для веб-адаптера, и сам веб-адаптерweb(React SPA) — ещё один HTTP-клиент к api.- React SPA (Vite): загрузка, история, профиль, подписка. Отдаётся статикой
позже (отдельный
web-контейнер / Nginx). - Auth: Telegram Login Widget (нужен публичный HTTPS-домен в BotFather) → сессия/JWT.
- Подписки: solo (1 490 ₽), team (3 990 ₽). ЮKassa recurring.
2.2 Что меняем в базе
ALTER TABLE users ADD COLUMN plan TEXT DEFAULT 'free';
ALTER TABLE users ADD COLUMN plan_renews_at TIMESTAMP;
CREATE TABLE invoices (id, user_id, amount, status, provider, external_id, created_at);
credits_left остаётся для pay-per-doc; подписка = безлимит с monthly
reset через cron-arq-таску.
2.3 Архитектура — без изменений в ядре
api и worker работают с этапа 1; на этапе 2 добавляется только адаптер
web (React, статика) перед Nginx → HTTPS (Let's Encrypt). Hexagonal-граница
сохранена: web — такой же HTTP-клиент к api, как bot. LLM по-прежнему
Ollama Cloud; при росте — Enterprise тариф или переход на свой GPU.
2.4 Критерий успеха
50 платящих. MRR ~30 000 ₽. Есть хотя бы один team-клиент.
Этап 3 — B2B API (2 недели, только если есть спрос)
Цель: сторонние сервисы дёргают анализ через API.
3.1 Что добавляем
- API-ключи: таблица
api_keys, headerX-API-Key. - Rate-limit: Redis (token bucket). Лимит = конкарренси/квота Ollama Cloud (3 на Pro), а не ₽.
POST /api/v1/analyze(multipart) → 202 + job_id →GET /api/v1/reports/{id}.- Дашборд: ключи, usage, счета.
3.2 Чего НЕ делаем
- Нет SDK, нет вебхуков (клиент поллит), нет OAuth2.
- Один тариф API: 9 900 ₽/мес за 100 запросов.
3.3 Критерий успеха
3 API-клиента. MRR +30 000 ₽.
Инфраструктура — сводка
| Компонент | Этап 0 | Этап 1 | Этап 2–3 |
|---|---|---|---|
| Compute | ноутбук | 1 VPS (Docker Compose) | 1 VPS (апгрейд RAM) |
| LLM | Ollama Cloud (Free/Pro) | Ollama Cloud Pro | Ollama Cloud Pro/Enterprise |
| DB | — | Postgres (в compose) | Postgres (+ backup cron) |
| Queue | — | Redis (в compose) | Redis (тот же) |
| Object storage | — | Selectel S3 | Selectel S3 |
| OCR | — | Tesseract (локально) | Tesseract (+ Yandex Vision) |
| Payments | — | ЮKassa | ЮKassa + CloudPayments |
| Monitoring | — | Docker logs | Uptime Kuma + Sentry (free) |
| CI/CD | — | git push → ssh deploy | GitHub Actions → build → deploy |
K8s / RabbitMQ / Kafka / Elasticsearch / vLLM / TGI — НЕ НУЖНЫ. Один VPS + Ollama Cloud держит всё до заметного объёма. Свой GPU — только если Ollama Cloud overage станет дороже self-host (отдельное решение позже).
Чек-лист пунктов анализа (v1)
Содержимое checklist.py — один список, без БД:
- Неустойки / штрафы (размер, односторонний)
- Подсудность (чужой регион)
- Сроки оплаты (условия, просрочка)
- IP-права (кому отходят результаты)
- Одностороннее изменение условий
- Гарантии и их срок
- Форс-мажор (формулировки)
- НДС (включён / сверх)
- Ответственность сторон (cap, исключения)
- Расторжение (условия, уведомление)
Сроки (реалистично, соло, вечера/выходные)
| Этап | Что | Время |
|---|---|---|
| 0 | Прототип | 1 выходной |
| 1 | Telegram-бот MVP | 2–3 недели |
| 2 | Веб + подписки | 3–4 недели |
| 3 | B2B API | 2 недели |
До первого платящего (0+1): ~3–4 недели. Заложить ~1–2 дня на подбор cloud-модели и тюнинг промпта (локальные/open модели капризнее GPT-4o).
Риски Ollama Cloud (честно)
- 152-ФЗ / data-residency. Контракт улетает в Ollama Cloud (США). Это тот же класс риска, что и GPT-4o. Митигация: disclaimer, обезличивание ПДн перед отправкой, либо при необходимости — отказ от Ollama Cloud в пользу РФ-LLM (GigaChat/YandexGPT) или своего GPU-бокса. Не позиционировать продукт как «данные не покидают РФ».
- Квота/конкарренси. Pro = 3 одновременных модели + rolling usage. Бурст платящих юзеров упрётся в очередь/429. Трекать usage, алертить у лимита, при росте — overage-баланс или Enterprise.
- Качество open-моделей. 14B галлюцинирует/пересказывает цитаты сильнее GPT-4o/GigaChat. Всегда: цитата + номер пункта + ремонт-цикл валидации JSON. Disclaimer «не заменяет юриста» — в каждый отчёт.
- Зависимость от одного провайдера. Один аккаунт Ollama (нельзя несколько). Иметь готовый план Б: GigaChat/YandexGPT-фолбэк или свой GPU при блокировке/превышении квоты.
Что сознательно отложено (YAGNI)
- Multi-tenant / организации / роли — пока все юзеры = solo.
- Шаблоны договоров (генерация) — другой продукт.
- ЭЦП / Госуслуги — чужой регуляторный ад.
- Команда юристов (human-in-the-loop) — только если попросят.
- Mobile app — веб + бот закрывают 100%.
- White-label — один продукт, один бренд.
- Свой GPU / vLLM / TGI / RAG-над-векторной-базой — пока Ollama Cloud дешевле; пересмотрим при выходе overage в минус.