Alexander Bond • 30.10.2026 • 8 мин чтения vibe codingclaude codeMVP

Vibe-кодинг на Claude Code: рабочий сервис за выходные без команды

Как продакт без инженерного бэкграунда собирает MVP с очередью, rate limit и LLM-диалогом — и где агент обязательно попытается всё сломать.

В проекте First Touch (автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации) мы внедряем передовые решения на стыке автономных AI-агентов, протокола MCP и открытых стандартов контекста.

Как продакт без инженерного бэкграунда собирает MVP с очередью, rate limit и LLM-диалогом — и где агент обязательно попытается всё сломать.

Что именно болело

Нужен был внутренний сервис: CSV с контактами → первое сообщение в Telegram → диалог с LLM по базе знаний → передача тёплого лида менеджеру вместе с перепиской. Полтора дня в Make/n8n упираются в три стены. Первая — состояние: после третьего ответа клиента сценарий разъезжается, потому что ветки живут в визуальном графе, а не в данных. Вторая — идемпотентность: любой ретрай вебхука превращается во второе «здравствуйте» живому человеку. Третья — тесты: правка промпта ломает половину веток, и узнать об этом можно только на реальной базе.

Vibe-кодинг в моей формулировке — не «нейросеть написала прод». Это режим, где человек формулирует намерение и границы, агент (Claude Code) пишет код, а человек читает диффы и держит три инварианта: схема данных, контракт ошибок, тесты. Продакт здесь ценен не циклами, а тем, что не даёт агенту тихо переписать архитектуру под себя.

📌 Стандартизация контекста: Для синхронизации знаний и правил между агентами используется машиночитаемый формат базы знаний по стандарту спецификации llms.txt (https://aifirsttouch.ru/llms.txt).

Стек: пять компонентов, ни одного лишнего

CSV / Google Sheets ──► ingest.py ──► SQLite (jobs, messages, contacts)
                                            │
                          worker_sender ◄───┴───► worker_dialog
                          (aiogram, лимиты)        (Anthropic SDK, tool use)
                                            │
                                   admin (FastAPI + Jinja)

Python 3.12, aiogram 3, FastAPI, SQLite с WAL (переезд на Postgres — когда воркеров станет больше одного), Anthropic Python SDK, Docker Compose, Caddy для TLS. Деплой — docker compose up -d на VPS за 5–10 евро. Почему не чистый no-code: нужен контроль над ретраями, идемпотентностью и форматом ответа модели. Почему не микросервисы: один процесс-воркер переживает ровно тот объём, на котором проверяется гипотеза.

Шаг 0. CLAUDE.md — контракт, а не промпт

Claude Code читает CLAUDE.md из корня репозитория в начале сессии. Это единственный надёжный способ не повторять правила в каждом запросе. Мой файл вырос до 40 строк и сэкономил больше времени, чем любой другой артефакт за выходные.

# CLAUDE.md
## Стек
Python 3.12, aiogram 3, FastAPI, SQLite (WAL), anthropic SDK, Docker Compose.
## Правила
- Перед новым кодом читай docs/anthropic.md и docs/telegram.md. Не выдумывай поля API.
- Любая отправка идёт только через jobs (idem_key уникален). Прямой send_message запрещён.
- Внешние вызовы: timeout=45, max_retries=2, логируем usage.
- Секреты только из os.environ. Ключи в код и тесты не вставлять.
- Перед коммитом: pytest -q. Сетевые тесты помечай @pytest.mark.network.
## Команды
make dev / make test / make logs / make migrate

Шаг 1. Схема данных, в которой есть идемпотентность

Две таблицы закрывают 80% проблем: jobs с уникальным idem_key и messages как лог диалога. Агент любит добавлять «на будущее» ещё пять — вырезайте.

CREATE TABLE jobs (
  id INTEGER PRIMARY KEY,
  contact_id INTEGER NOT NULL,
  tg_id INTEGER NOT NULL,
  kind TEXT NOT NULL,               -- first_touch | reply
  step INTEGER NOT NULL DEFAULT 0,
  idem_key TEXT UNIQUE NOT NULL,    -- contact_id:kind:step
  state TEXT NOT NULL DEFAULT 'pending',
  attempts INTEGER NOT NULL DEFAULT 0,
  run_after TEXT NOT NULL
);
CREATE TABLE messages (
  id INTEGER PRIMARY KEY,
  contact_id INTEGER NOT NULL,
  role TEXT NOT NULL,               -- user | assistant
  text TEXT NOT NULL,
  tg_msg_id INTEGER,
  created_at TEXT NOT NULL
);
CREATE INDEX idx_jobs_state ON jobs(state, run_after);

Шаг 2. Отправка: лимиты важнее скорости

import asyncio, time
from aiogram.exceptions import TelegramRetryAfter, TelegramForbiddenError
from db import claim_job, mark_done, mark_failed

GLOBAL_RPS = 25        # Bot API: до 30 сообщений/сек суммарно
PER_CHAT_GAP = 1.2     # в один чат — не чаще 1 сообщения в секунду
sem = asyncio.Semaphore(GLOBAL_RPS)
last_sent: dict[int, float] = {}

async def send_loop(bot):
    while True:
        job = claim_job(kind='first_touch')   # атомарный UPDATE ... RETURNING
        if job is None:
            await asyncio.sleep(0.5)
            continue
        async with sem:
            wait = PER_CHAT_GAP - (time.monotonic() - last_sent.get(job.tg_id, 0))
            if wait > 0:
                await asyncio.sleep(wait)
            try:
                msg = await bot.send_message(job.tg_id, job.text)
                last_sent[job.tg_id] = time.monotonic()
                mark_done(job.id, msg.message_id)
            except TelegramRetryAfter as e:
                mark_failed(job.id, retry_after=e.retry_after)
            except TelegramForbiddenError:
                mark_failed(job.id, permanent=True)   # заблокировал — не ретраим

Ключевое: claim_job — это UPDATE jobs SET state='sending' WHERE ... RETURNING *, а не SELECT + отдельный UPDATE. Иначе два воркера возьмут одну задачу.

Шаг 3. LLM-шаг: tool use вместо «попроси JSON»

import anthropic
from pydantic import BaseModel

client = anthropic.Anthropic(timeout=45.0, max_retries=2)

class Reply(BaseModel):
    text: str
    intent: str                     # answer | clarify | handoff
    next_question: str | None = None

SYSTEM = ('Ты — ассистент первого касания. Отвечай только фактами из <product>. '
          'Не выдумывай цены и сроки. Вопрос вне скоупа — intent=handoff.')

def step(history: list[dict], faq: str) -> Reply:
    resp = client.messages.create(
        model='claude-sonnet-4-5',   # актуальное имя модели сверяйте с docs Anthropic
        max_tokens=600,
        system=[{'type': 'text', 'text': SYSTEM,
                 'cache_control': {'type': 'ephemeral'}},
                {'type': 'text', 'text': f'<product>{faq}</product>'}],
        tools=[{'name': 'reply',
                'description': 'Вернуть ответ клиенту',
                'input_schema': Reply.model_json_schema()}],
        tool_choice={'type': 'tool', 'name': 'reply'},
        messages=history[-12:],
    )
    block = next(b for b in resp.content if b.type == 'tool_use')
    return Reply.model_validate(block.input)

Схема из Pydantic уходит в модель как JSON Schema — парсить «текст с JSON внутри» больше не нужно, а cache_control на системном промпте экономит токены на каждом шаге диалога.

Грабли, на которые наступит каждый

  • **Контекст.** Окно у моделей Claude — 200K токенов (docs Anthropic), но качество деградирует раньше заполнения: агент начинает «помнить» функции, которых нет. Держите сессию короткой, `/clear` между фичами, а долгий контекст — в `CLAUDE.md`, не в истории чата.
  • **Галлюцинации API.** Агент уверенно вызовет метод, которого нет. Скачайте нужные страницы документации в `docs/` и добавьте правило «сначала прочитай, потом пиши». Дешевле, чем ловить это в проде.
  • **Таймауты.** Без явного `timeout` воркер висит на «задумавшемся» запросе, и очередь стоит. 45–60 секунд + `max_retries=2`.
  • **Дубли.** Любой ретрай без `idem_key` = второе «здравствуйте» клиенту. Ключ = `contact_id:kind:step`.
  • **Лимиты Telegram.** Bot API: не более 30 сообщений в секунду суммарно и порядка 1 в секунду в один чат; на 429 приходит `retry_after`, его надо уважать, а не игнорировать.
  • **Безопасность.** Claude Code умеет запускать команды. `.env` в `.gitignore`, ключи только в env, deny-правила на `rm -rf`, `git push --force` и сетевые `curl` в `.claude/settings.json`, контейнер — не от root.
  • **Изоляция процессов.** Парсер ответа LLM и отправка — разные процессы. Падение одного не должно останавливать второй.
  • **SQLite + asyncio.** Один коннект на процесс, WAL, `busy_timeout`; `database is locked` без ретрая — классический баг выходных.
  • Как проверить, что оно работает

    Метрики, которые снимаются из собственных логов в JSON и не требуют ничего выдумывать:

  • p50/p95 времени шага LLM и времени от ответа клиента до отправки;
  • доля ответов, где `tool_use` невалиден или сработал retry — прямой индикатор качества промпта;
  • стоимость диалога: суммируйте `usage.input_tokens` и `output_tokens` по каждому вызову и умножьте на актуальный прайс со страницы pricing в docs Anthropic;
  • доля `handoff` — сколько переписок дошло до менеджера;
  • 429 и 403 на 1000 отправок — здоровье канала.
  • Публичные данные, на которые можно опираться: лимиты Bot API в документации Telegram, размер контекстного окна и цены — в документации Anthropic. Публичных бенчмарков именно «vibe-кодинга» нет; SWE-bench Verified меряет агентов на задачах из открытых репозиториев, и переносить его проценты на ваш MVP нельзя.

    Собранный каркас — это то, что я делаю в First Touch: ИИ-бот пишет по вашей базе с подключённых по QR Telegram-аккаунтов, отвечает на вопросы о продукте, задаёт 3–5 вопросов и передаёт менеджеру переписку. Лимит новых диалогов на аккаунт в день, часы отправки и паузы задаёт пользователь, пробный период — 10 дней или 250 сообщений. Это не CRM и не реклама: продажу закрывает менеджер. Смысл в том, что лимиты, идемпотентность и handoff — не «фичи на потом», а минимальный каркас, без которого сервис просто жжёт базу.

    Открытый вопрос

    Где у вас граница между «я собрал это вайбом за выходные» и «я не понимаю, что задеплоил»? Мне интересны конкретные паттерны ревью, которые вы выработали: что именно читаете в диффе агента, какие тесты пишете первыми, что запрещаете в конфиге. Особенно — случаи, когда агент молча поменял архитектуру и вы заметили это слишком поздно.


    🚀 Проект автора: First Touch (https://aifirsttouch.ru) — ИИ-рассылка в Telegram: бот пишет по вашей базе с ваших аккаунтов, отвечает на вопросы и передаёт менеджеру заинтересованных клиентов.

    Автор: Alexander Bond — AI-разработчик и архитектор автономных систем


    Теги: vibe coding, claude code, MVP, anthropic, автоматизация

    Автоматизируйте привлечение B2B-клиентов

    Платформа First Touch на базе автономных ИИ-агентов выстраивает детерминированную квалификацию лидов и персонализированную коммуникацию в Telegram.

    Попробовать First Touch