Суть урока
Лекция — это архитектор показывает чертёж дома. Lab — это ты с бригадой кладёшь кирпичи по дням, и к воскресенью в доме горит свет и в нём живёт первый жилец.
Этот урок — не теория. Это пошаговая стройка реального AI-продукта по дням недели. Не "как теоретически делают Telegram-ботов". А "вот ты в понедельник, вот что делаешь час за часом — и в воскресенье у тебя задеплоенный бот в production, первый клиент подключён, Stripe готов выставлять инвойсы каждый месяц".
После основных уроков курса ты знаешь "как теоретически". Сейчас доказываешь себе, что можешь поставить продукт за неделю end-to-end.
Важно: суммы в этом уроке (например, $500 в месяц) — примеры для расчёта, а не прогноз дохода и не рекомендация цены. Найдёшь ли ты клиента и сколько он будет платить, зависит от ниши, рынка и твоей работы: курс результат не гарантирует.
🎯 End state Day 7
В воскресенье вечером у тебя на руках:
- ✅ Telegram-бот задеплоен на Cloudflare Workers, отвечает 24/7
- ✅ Первый клиент подключён, биллинг через Stripe настроен (сумму вы согласуете сами; $500/мес в уроке — пример)
- ✅ Подключённый инструмент (Stripe API или email — зависит от ниши)
- ✅ State management через Cloudflare KV (бот помнит контекст)
- ✅ Rate limiting + cost guardrails (не разорит тебя на API)
- ✅ Audit log всех взаимодействий
- ✅ Мониторинг вызовов (в уроке — Helicone, см. примечание в Дне 7)
- ✅ Шаблон onboarding для клиентов №2-10
Экономика: пример расчёта — в разделе «Real cost breakdown» в конце урока. Цифры там условные: считай по своим тарифам и своей цене.
📋 Pre-requisites
Чтобы Lab имел смысл, у тебя должно быть:
- ✓ Платный тариф Claude с Claude Code (Pro или Max; актуальные цены: Актуальное сейчас)
- ✓ API-ключ из Claude Console: API оплачивается отдельно от подписки
- ✓ Claude Code установлен и работает (см. урок Установка и настройка)
- ✓ Cloudflare account (бесплатный tier хватит)
- ✓ Stripe account (для билинга)
- ✓ Telegram account
- ✓ Прошёл основные уроки курса (понимаешь CLAUDE.md, hooks, deploy basics)
- ✓ ~30 часов времени в течение 7 дней (4-5 часов/день)
- ✓ Готовность звонить незнакомым людям (Day 1 — discovery calls)
DAY 1 (5 часов): Ниша + первое customer interview
Цель дня: вечером ты знаешь конкретную нишу + конкретную боль + 2-3 реальных потенциальных клиента согласились созвониться.
Час 1: Pick niche — методология 3 вопросов
Не выбирай "малый бизнес". Это не ниша, это вселенная. Ниша — это пересечение:
- Какую группу людей ты знаешь лучше других? (риелторы Эквадора, дантисты Москвы, фитнес-тренеры Майами)
- У кого из них болит так, что они уже платят деньги за слабые решения? (например за Calendly + Zoom + Notion + ассистента-фрилансера)
- Какую часть боли может закрыть Telegram-бот с LLM внутри? (lead qualification, appointment booking, FAQ автоответ, follow-up sequences)
Записывай ответы. Пересечение трёх ответов = твоя ниша.
Час 2: 20 потенциальных клиентов
Открываешь Google Sheets. Колонки: имя, компания, контакт, источник, статус.
20 строк. Источники: LinkedIn (поиск по нише), Instagram, локальные бизнес-чаты в Telegram, рекомендации знакомых.
НЕ масс-парсинг. 20 живых имён которых ты можешь обосновать "почему именно этот человек подходит".
Час 3: Cold outreach 5 контактам
Шаблон сообщения (адаптируй под нишу):
Привет, [Имя]! Я строю AI-помощника для [ниша] — отвечает в Telegram на типовые вопросы клиентов, квалифицирует лиды, бронирует встречи. Без шаблонов. Не продаю — изучаю проблемы. 15 минут на созвон расскажешь как у тебя сейчас устроена работа с клиентами? Что бесит? В благодарность за время — пришлю отчёт-выжимку по индустрии (3 страницы, 3 конкретных идеи как сэкономить часы в неделю). Когда удобно — завтра или послезавтра?
Отправь 5 DM. В разные платформы. НЕ копипаст — переписывай первые 2 строки под человека.
Час 4-5: 2-3 discovery calls
Часть из 5 ответит; если не ответил никто — меняй текст или нишу. Созвон 15 минут. Скрипт:
1. (2 мин) Расскажи о себе и бизнесе. 2. (5 мин) Как сейчас устроена работа с клиентами после первого контакта? Кто отвечает на сообщения? Сколько уходит часов в день? 3. (3 мин) Какие 3 вопроса клиенты задают ЧАЩЕ ВСЕГО? 4. (2 мин) Если бы у тебя был помощник который отвечает на эти 3 вопроса в Telegram 24/7 — сколько это стоило бы тебе сэкономленного времени в часах в неделю? 5. (3 мин) Если бы такой инструмент стоил [твоя цена] в месяц — это дорого, нормально или дёшево? Почему?
Записывай дословно. Не "оптимизируй" в голове.
Output Day 1
В конце дня в Google Doc:
- Ниша (одна строка)
- 3 боли клиентов (дословные цитаты)
- 3 типовых вопроса от клиентов которые бот будет закрывать
- Реакция на твою цену (готовы / дорого / нормально)
- Имя первого человека готового стать тест-клиентом
Если нет первого тест-клиента — Day 2 не начинаешь. Возвращайся в Час 3.
DAY 2 (5 часов): MVP design + CLAUDE.md + scaffold
Цель дня: есть дизайн 3 happy paths + написан CLAUDE.md + Worker scaffold создан + бот в BotFather зарегистрирован.
Час 1: Conversation flows (3 happy paths)
На бумаге или в Miro нарисуй 3 диалога которые бот должен пройти end-to-end.
Пример для риелтора Эквадора:
Flow 1: Качественный лид
Клиент: Здравствуйте, ищу квартиру в Куэнке до $80K
Бот: Привет! Помогу подобрать. 3 вопроса:
1. Сколько спален нужно?
2. Район важен или гибко?
3. Срок переезда?
Клиент: 2 спальни, центр, через 3 месяца
Бот: Записал. Это качественный лид — передаю риелтору.
Он позвонит сегодня до 18:00. Подтверди номер для звонка.Flow 2: FAQ автоответ
Клиент: А нужна ли виза для покупки квартиры?
Бот: Иностранцы могут покупать недвижимость в Эквадоре без визы.
Нужен только паспорт + RUC (получаешь за 1 день).
Хочешь подробнее обсудить с риелтором — напиши "созвон".Ответ бота в этом примере условный: юридические факты бот берёт только из FAQ, который проверил клиент.
Flow 3: Не наш клиент
Клиент: А ипотеку для меня сделаете?
Бот: Мы работаем с прямыми покупками, не с ипотекой.
По ипотеке могу порекомендовать [партнёр] — напишу контакт?Зачем это сейчас: Day 3 ты не будешь придумывать "что бот должен говорить". Только реализовывать что нарисовано.
Час 2: CLAUDE.md system prompt
Создай папку проекта:
mkdir telegram-bot-prod && cd telegram-bot-prod
git initCLAUDE.md (это будет system prompt для LLM):
# Помощник риелтора в Куэнке, Эквадор
## Роль
Ты — первый контакт клиентов риелторской компании в Куэнке.
Отвечаешь в Telegram. Цель — квалифицировать лида и передать
человеку, либо ответить на FAQ.
## Стиль
- Кратко, дружелюбно, на ВЫ
- Без воды и эмодзи в каждой строке
- Если не знаешь ответ — НЕ выдумывай, скажи "уточню у риелтора"
## 3 happy paths
[Скопируй сюда flows из Часа 1]
## Что НИКОГДА не делаешь
- Не обещаешь цены без согласования с риелтором
- Не утверждаешь юридические факты ("100% легально")
- Не отправляешь персональные данные клиента наружу
- Не работаешь с темой ипотеки (направляешь к партнёру)
## Когда передавать человеку
- Клиент готов смотреть квартиру в течение месяца
- Клиент задаёт вопрос которого нет в FAQ
- Клиент пишет "хочу созвон" / "позвоните"
## Tools
- save_lead(name, phone, budget, bedrooms) — сохраняет в KV
- notify_realtor(lead_id) — отправляет уведомление риелторуЭто продуктовая конституция бота. Меняешь её — меняется поведение.
Час 3-4: Cloudflare Worker scaffold
Setup:
npm create cloudflare@latest -- telegram-bot
# мастер спросит шаблон (Hello World) и язык (TypeScript); флаги команды меняются,
# актуальный вариант смотри в документации Cloudflare
cd telegram-bot
npm install @anthropic-ai/sdksrc/index.ts — minimal scaffold:
import Anthropic from "@anthropic-ai/sdk";
export interface Env {
ANTHROPIC_API_KEY: string;
TELEGRAM_BOT_TOKEN: string;
TELEGRAM_WEBHOOK_SECRET: string;
BOT_KV: KVNamespace;
SYSTEM_PROMPT: string;
}
interface TelegramUpdate {
update_id: number;
message?: {
message_id: number;
from: { id: number; first_name: string; username?: string };
chat: { id: number };
text?: string;
};
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Webhook secret verification
const secret = request.headers.get("X-Telegram-Bot-Api-Secret-Token");
if (secret !== env.TELEGRAM_WEBHOOK_SECRET) {
return new Response("Forbidden", { status: 403 });
}
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
const update: TelegramUpdate = await request.json();
if (!update.message?.text) {
return new Response("OK"); // ignore non-text
}
const chatId = update.message.chat.id;
const userText = update.message.text;
// TODO Day 3: real LLM call here
const reply = `Echo: ${userText}`;
await sendTelegramMessage(env, chatId, reply);
return new Response("OK");
},
};
async function sendTelegramMessage(env: Env, chatId: number, text: string) {
const url = `https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage`;
await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ chat_id: chatId, text }),
});
}wrangler.toml:
name = "telegram-bot"
main = "src/index.ts"
compatibility_date = "2026-10-01"
[[kv_namespaces]]
binding = "BOT_KV"
id = "your-kv-namespace-id" # создадим позжеНовые проекты Cloudflare создаёт с файлом wrangler.jsonc; формат wrangler.toml тоже поддерживается. Если мастер создал wrangler.jsonc, перенеси туда те же поля.
Установи secrets (НИКОГДА не коммить):
wrangler secret put ANTHROPIC_API_KEY
wrangler secret put TELEGRAM_BOT_TOKEN
wrangler secret put TELEGRAM_WEBHOOK_SECRET # генерируй openssl rand -hex 32Час 5: Telegram bot через BotFather
В Telegram → @BotFather → /newbot → имя + username → получаешь токен.
Подключаешь webhook (после первого wrangler deploy):
WEBHOOK_URL="https://telegram-bot.your-subdomain.workers.dev"
SECRET="<тот же что в wrangler secret>"
curl -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" \
-H "Content-Type: application/json" \
-d "{\"url\":\"${WEBHOOK_URL}\",\"secret_token\":\"${SECRET}\"}"Напиши боту "привет" в Telegram. Должен ответить "Echo: привет". Работает — переходи к Day 3.
DAY 3 (5 часов): Core conversation handling
Цель дня: бот отвечает осмысленно через LLM, errors не валят его, каждое взаимодействие в audit log.
Час 1-3: Webhook + LLM + response
Заменяешь // TODO Day 3 на реальный вызов:
import Anthropic from "@anthropic-ai/sdk";
async function generateReply(
env: Env,
userText: string,
conversationHistory: Array<{ role: "user" | "assistant"; content: string }>,
): Promise<string> {
const client = new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
const response = await client.messages.create({
model: "claude-sonnet-5-5", // вынеси в переменную окружения; актуальные модели: «Актуальное сейчас»
max_tokens: 500,
system: env.SYSTEM_PROMPT, // загружено из KV или wrangler vars
messages: [
...conversationHistory,
{ role: "user", content: userText },
],
});
// Извлекаем текст из response
const textBlock = response.content.find((b) => b.type === "text");
return textBlock && textBlock.type === "text"
? textBlock.text
: "Извините, не понял. Можете переформулировать?";
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const secret = request.headers.get("X-Telegram-Bot-Api-Secret-Token");
if (secret !== env.TELEGRAM_WEBHOOK_SECRET) {
return new Response("Forbidden", { status: 403 });
}
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
const update: TelegramUpdate = await request.json();
if (!update.message?.text) return new Response("OK");
const chatId = update.message.chat.id;
const userText = update.message.text;
try {
// Загружаем историю беседы из KV (Day 4 расширим)
const historyKey = `chat:${chatId}:history`;
const historyRaw = await env.BOT_KV.get(historyKey);
const history: Array<{ role: "user" | "assistant"; content: string }> =
historyRaw ? JSON.parse(historyRaw) : [];
// Генерим ответ
const reply = await generateReply(env, userText, history);
// Обновляем историю (last 10 messages)
const updatedHistory = [
...history,
{ role: "user" as const, content: userText },
{ role: "assistant" as const, content: reply },
].slice(-20);
await env.BOT_KV.put(historyKey, JSON.stringify(updatedHistory), {
expirationTtl: 60 * 60 * 24 * 7, // 7 days
});
// Audit log
await logEvent(env, {
ts: new Date().toISOString(),
chat_id: chatId,
user_text: userText,
bot_reply: reply,
tokens: 0, // TODO заполним из response
});
await sendTelegramMessage(env, chatId, reply);
} catch (e) {
console.error("Bot error:", e);
await sendTelegramMessage(
env,
chatId,
"Извините, временная проблема. Попробуйте через минуту.",
);
}
return new Response("OK");
},
};Час 4-5: Error handling + audit log
logEvent — пишем в KV или внешний сервис:
interface AuditEntry {
ts: string;
chat_id: number;
user_text: string;
bot_reply: string;
tokens: number;
}
async function logEvent(env: Env, entry: AuditEntry): Promise<void> {
const key = `audit:${entry.ts}:${entry.chat_id}`;
await env.BOT_KV.put(key, JSON.stringify(entry), {
expirationTtl: 60 * 60 * 24 * 90, // 90 days retention
});
}Защитные паттерны:
// Лимит длины сообщения от пользователя
if (userText.length > 1000) {
await sendTelegramMessage(
env,
chatId,
"Сообщение слишком длинное. Сократите до 1000 символов.",
);
return new Response("OK");
}
// Timeout для LLM call
const replyPromise = generateReply(env, userText, history);
const timeoutPromise = new Promise<string>((_, reject) =>
setTimeout(() => reject(new Error("LLM timeout")), 15000),
);
const reply = await Promise.race([replyPromise, timeoutPromise]);Deploy:
wrangler deployНапиши боту 5 разных сообщений. Все должны получить осмысленные ответы. История диалога сохраняется (попробуй "а ты помнишь что я тебе говорил выше?").
DAY 4 (5 часов): Connect tools (MCP integration + state)
Цель дня: бот делает не только разговор — реально работает с инструментами (Stripe, email или твой Use Case API).
Час 1-2: Tool integration
Для риелтора Эквадора нужно: сохранить лида + уведомить риелтора в Telegram.
Расширяем CLAUDE.md (system prompt) с tools:
const tools: Anthropic.Tool[] = [
{
name: "save_lead",
description: "Сохраняет квалифицированного лида в базу",
input_schema: {
type: "object",
properties: {
name: { type: "string", description: "Имя клиента" },
phone: { type: "string", description: "Телефон с кодом страны" },
budget_usd: { type: "number", description: "Бюджет в USD" },
bedrooms: { type: "number", description: "Кол-во спален" },
timeline_months: { type: "number", description: "Срок переезда" },
},
required: ["name", "phone", "budget_usd", "bedrooms"],
},
},
{
name: "notify_realtor",
description: "Отправляет уведомление риелтору о новом лиде",
input_schema: {
type: "object",
properties: {
lead_id: { type: "string" },
urgency: { type: "string", enum: ["high", "medium", "low"] },
},
required: ["lead_id", "urgency"],
},
},
];Tool execution loop:
async function generateReplyWithTools(
env: Env,
userText: string,
history: Array<Anthropic.MessageParam>,
): Promise<string> {
const client = new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
const messages: Array<Anthropic.MessageParam> = [
...history,
{ role: "user", content: userText },
];
// Loop max 5 раз чтобы избежать infinite tool calls
for (let i = 0; i < 5; i++) {
const response = await client.messages.create({
model: "claude-sonnet-5-5", // вынеси в переменную окружения; актуальные модели: «Актуальное сейчас»
max_tokens: 1000,
system: env.SYSTEM_PROMPT,
tools,
messages,
});
if (response.stop_reason === "end_turn") {
const textBlock = response.content.find((b) => b.type === "text");
return textBlock && textBlock.type === "text" ? textBlock.text : "";
}
if (response.stop_reason === "tool_use") {
messages.push({ role: "assistant", content: response.content });
const toolResults: Array<Anthropic.ToolResultBlockParam> = [];
for (const block of response.content) {
if (block.type === "tool_use") {
const result = await executeTool(env, block.name, block.input);
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result),
});
}
}
messages.push({ role: "user", content: toolResults });
continue;
}
break;
}
return "Извините, не смог обработать запрос. Попробуйте ещё раз.";
}
async function executeTool(
env: Env,
name: string,
input: unknown,
): Promise<unknown> {
if (name === "save_lead") {
const lead = input as {
name: string;
phone: string;
budget_usd: number;
bedrooms: number;
};
const leadId = `lead_${Date.now()}`;
await env.BOT_KV.put(`leads:${leadId}`, JSON.stringify(lead));
return { lead_id: leadId, status: "saved" };
}
if (name === "notify_realtor") {
const { lead_id, urgency } = input as { lead_id: string; urgency: string };
// Реальный notify через Telegram на чат риелтора
const realtorChatId = Number(env.REALTOR_CHAT_ID);
await sendTelegramMessage(
env,
realtorChatId,
`Новый лид (${urgency}): ${lead_id}`,
);
return { status: "notified" };
}
return { error: `Unknown tool: ${name}` };
}Час 3-4: State management (KV pattern)
Уже частично сделали в Day 3. Расширяем — храним не только историю, но и профиль клиента:
interface ClientProfile {
chat_id: number;
first_seen: string;
name?: string;
phone?: string;
budget_usd?: number;
bedrooms?: number;
status: "new" | "qualifying" | "qualified" | "passed_to_realtor";
last_interaction: string;
}
async function loadProfile(env: Env, chatId: number): Promise<ClientProfile> {
const raw = await env.BOT_KV.get(`profile:${chatId}`);
if (raw) return JSON.parse(raw);
return {
chat_id: chatId,
first_seen: new Date().toISOString(),
status: "new",
last_interaction: new Date().toISOString(),
};
}
async function saveProfile(env: Env, profile: ClientProfile): Promise<void> {
profile.last_interaction = new Date().toISOString();
await env.BOT_KV.put(`profile:${profile.chat_id}`, JSON.stringify(profile), {
expirationTtl: 60 * 60 * 24 * 365, // год
});
}Профиль передаёшь в system prompt чтобы бот помнил контекст между сессиями:
const profile = await loadProfile(env, chatId);
const systemWithContext = `${env.SYSTEM_PROMPT}
## Профиль текущего клиента
${JSON.stringify(profile, null, 2)}
Используй эту информацию чтобы не задавать вопросы на которые уже знаешь
ответ. Обновляй профиль через tools.`;Час 5: Testing harness
Создаёшь tests/conversation.test.ts:
import { describe, test, expect } from "vitest";
describe("Bot conversation flows", () => {
test("Flow 1: качественный лид сохраняется", async () => {
const responses = await simulateConversation([
"Здравствуйте, ищу квартиру в Куэнке до $80K",
"2 спальни, центр, через 3 месяца",
"Меня зовут [клиент], связь через бот",
]);
expect(responses).toContain("записал");
// Проверяем что lead сохранён в KV
const leads = await env.BOT_KV.list({ prefix: "leads:" });
expect(leads.keys.length).toBeGreaterThan(0);
});
test("Flow 2: FAQ закрывается без передачи риелтору", async () => {
const reply = await simulateConversation([
"А нужна ли виза для покупки квартиры?",
]);
expect(reply[0]).toMatch(/виза.*не нужна|без визы/i);
});
test("Flow 3: ипотека → направление к партнёру", async () => {
const reply = await simulateConversation(["А ипотеку для меня сделаете?"]);
expect(reply[0]).toMatch(/ипотек|партнёр/i);
});
});Запусти: npx vitest. Все 3 теста должны быть зелёными.
DAY 5 (4 часа): Polish + safety + production deploy
Цель дня: бот не разорит тебя, не упадёт под нагрузкой, и задеплоен в production.
Час 1: Rate limiting per user
Не дай одному клиенту жечь твой API key:
async function checkRateLimit(env: Env, chatId: number): Promise<boolean> {
const key = `ratelimit:${chatId}`;
const countRaw = await env.BOT_KV.get(key);
const count = countRaw ? parseInt(countRaw) : 0;
if (count >= 30) return false; // max 30 messages в минуту
await env.BOT_KV.put(key, String(count + 1), { expirationTtl: 60 });
return true;
}
// В fetch handler:
if (!(await checkRateLimit(env, chatId))) {
await sendTelegramMessage(
env,
chatId,
"Слишком много сообщений. Подождите минуту.",
);
return new Response("OK");
}Час 2: Cost guardrails
Daily cost cap чтобы случайный bug не сжёг лишние деньги за ночь:
async function checkDailyCost(env: Env): Promise<boolean> {
const today = new Date().toISOString().split("T")[0];
const key = `cost:${today}`;
const costRaw = await env.BOT_KV.get(key);
const costCents = costRaw ? parseInt(costRaw) : 0;
return costCents < 1000; // $10/день hard cap
}
async function recordCost(env: Env, tokens: number): Promise<void> {
const today = new Date().toISOString().split("T")[0];
const key = `cost:${today}`;
const costRaw = await env.BOT_KV.get(key);
const currentCents = costRaw ? parseInt(costRaw) : 0;
// Грубая завышенная оценка: 1 цент за каждые 100 токенов. Нужна как предохранитель;
// актуальные цены токенов — на странице «Актуальное сейчас»
const addCents = Math.ceil(tokens / 100);
await env.BOT_KV.put(key, String(currentCents + addCents), {
expirationTtl: 60 * 60 * 48,
});
}
// В fetch:
if (!(await checkDailyCost(env))) {
await sendTelegramMessage(
env,
chatId,
"Сервис временно перегружен. Завтра возобновится.",
);
return new Response("OK");
}Час 3: Helpful error messages
Шаблоны частых ошибок (вместо stack trace):
const ERROR_MESSAGES = {
timeout:
"Думаю слишком долго. Попробуйте задать вопрос проще или повторить через минуту.",
rate_limit:
"Слишком много сообщений подряд. Подождите минуту — отвечу.",
api_down:
"У нас технические проблемы. Риелтор получил уведомление и перезвонит лично.",
unknown_topic:
"Не совсем понял ваш вопрос. Передаю риелтору — он перезвонит в течение часа.",
};Час 4: Production deploy
# Проверяем секреты в production
wrangler secret list
# Deploy
wrangler deploy
# Verify webhook
curl "https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo"В Cloudflare dashboard → Workers → твой бот → Logs (real-time). Должны видеть incoming requests.
Smoke tests на production:
- Полный Flow 1 (квалифицированный лид)
- Flow 2 (FAQ)
- Flow 3 (не наш клиент)
- Edge case: длинное сообщение (>1000 символов)
- Edge case: 35 сообщений за минуту (rate limit срабатывает)
Все прошли — Day 6.
DAY 6 (5 часов): First customer onboarding
Цель дня: реальный клиент начинает использовать бота для своего бизнеса. К концу дня — первые лиды через бот.
Час 1-2: Customer onboarding flow
Создай чеклист onboarding (можно в Notion / Markdown):
# Onboarding чеклист для клиента ## Перед звонком (мы делаем) - [ ] Создан выделенный Telegram бот для клиента (свой токен) - [ ] CLAUDE.md адаптирован под бизнес клиента - [ ] Имя компании, тон голоса - [ ] 3 happy paths из их реальных диалогов - [ ] FAQ из их базы (5-10 типовых вопросов) - [ ] Tools настроены (если нужен лид-сейв — куда писать) - [ ] Notify-чат риелтора получен и проверен ## На звонке (30 минут) - [ ] Покажи бота в действии (3 happy paths live) - [ ] Объясни как редактировать FAQ (доступ к CLAUDE.md) - [ ] Расскажи как смотреть лиды (KV или Google Sheet sync) - [ ] Покажи как добавить тебя в чат если бот зависнет - [ ] Обсуди billing — сумма и способ оплаты через Stripe, инвойс на email - [ ] Договорись о trial period (7 дней) либо сразу первый платёж ## После звонка - [ ] Отправь Stripe invoice - [ ] Подключи продакшен webhook к их Telegram-каналу - [ ] Установи мониторинг на их трафик (Helicone tag по client_id) - [ ] Напиши follow-up через 24 часа: "Как первый день?"
Час 3-4: 30-min onboarding call
Структура:
0-5 мин: small talk + контекст 5-15 мин: live demo (3 happy paths) 15-25 мин: настройка под их бизнес (правки в CLAUDE.md live) 25-30 мин: billing + next steps
Главное правило: клиент должен сам написать первое сообщение боту на звонке и получить ответ. Это момент "вау" который продаёт.
Час 5: Handle first day live issues
Что будет чаще всего:
- Бот ответил не то на специфичный вопрос → правишь CLAUDE.md (FAQ секция)
- Tool сработал не так → правишь tool description / parameters
- Клиент хочет ещё один happy path → добавляешь
Каждое исправление коммитишь:
git commit -m "fix(bot): добавить FAQ про комиссию риелтора"
wrangler deployЦикл фидбека — минуты, не дни. Это и есть live ops.
Output Day 6
- Бот в production у клиента
- 2-5 лидов прошли через бот (хотя бы в тестовом режиме)
- Клиент видел реальный value, готов платить
DAY 7 (3 часа): Pricing + sustainability
Цель дня: деньги получены, мониторинг настроен, план на неделю 2.
Час 1: Stripe invoice
# Через Stripe CLI или dashboard
stripe customers create \
--name="Имя клиента" \
--email="<client_email>"
# Invoice
stripe invoices create \
--customer=cus_XXX \
--collection_method=send_invoice \
--days_until_due=7
# Сумма ниже — пример (50000 центов = $500); подставь свою цену
stripe invoice_items create \
--customer=cus_XXX \
--invoice=in_XXX \
--description="Telegram AI бот — 1 месяц" \
--amount=50000 \
--currency=usd
stripe invoices send --id=in_XXXИли проще: в Stripe Dashboard → Invoices → Create. 5 минут руками.
Для recurring (Month 2+): создай Subscription с ценой, о которой вы договорились, autopay через Stripe Customer Portal.
Час 2: Мониторинг вызовов (Helicone)
В уроке для мониторинга используется Helicone: прокси между твоим кодом и API, который показывает каждый вызов и его стоимость. Важно: с марта 2026 Helicone входит в Mintlify и работает в режиме поддержки (исправления и поддержка новых моделей, без новых функций). Условия бесплатного уровня смотри на сайте сервиса. Альтернативы: Langfuse, Portkey или раздел usage в Claude Console.
// Замени Anthropic SDK init:
const client = new Anthropic({
apiKey: env.ANTHROPIC_API_KEY,
baseURL: "https://anthropic.helicone.ai", // proxy через Helicone
defaultHeaders: {
"Helicone-Auth": `Bearer ${env.HELICONE_API_KEY}`,
"Helicone-Property-Client": "client_001", // тег по клиенту
},
});Регистрируешь на helicone.ai → копируешь key → wrangler secret put HELICONE_API_KEY. Видишь все вызовы: cost, latency, error rate. Без своего dashboard.
Час 3: Retrospective + week 2 plan
Открой блокнот, ответь честно:
- Что сработало? (например: cold DM работают если первая строка персональная)
- Что НЕ сработало? (например: 2 из 5 потенциальных клиентов отказались на этапе цены — слишком дорого для них)
- Что я узнал о нише? (например: они уже платят за Calendly и ассистента-фрилансера, поэтому цену надо обосновать дополнительными возможностями)
- Один следующий клиент — кто и как?
Заведи Week 2 spreadsheet:
Day 8: 10 outreach DM (используем что сработало в Week 1) Day 9: 3 discovery calls Day 10: 1 onboarding call Day 11: support текущего клиента + правки на основе фидбека Day 12: 2 onboarding calls (если 2 лида созрели) Day 13: invoice 2 новых клиента Day 14: retro Week 2
Цель Week 2: расширить воронку: больше разговоров и подключений. Конкретные цифры задай сам по результатам первой недели.
💰 Real cost breakdown
Цифры ниже — оценки автора, чтобы показать структуру расходов. Это не прайс-лист и не прогноз дохода. Актуальные цены токенов и тарифов: Актуальное сейчас.
| Период | Расходы твои | Источник |
|---|---|---|
| Day 1-2 (research + design) | $0 | только время |
| Day 3 (LLM testing) | небольшие | Anthropic API smoke tests |
| Day 4 (tool dev) | небольшие | tool execution tests |
| Day 5 (load testing) | небольшие | rate limit + cost cap проверки |
| Day 6 (live с клиентом) | небольшие | реальные диалоги |
| Day 7 (Stripe + monitoring) | $0 | бесплатные уровни сервисов |
| Итого setup | десятки долларов | зависит от тарифов и числа тестов |
| Month 1 ops (1 клиент) | LLM + Cloudflare | Workers Free: 100 000 запросов в день; платный план от $5 в месяц (на октябрь 2026) |
| Выручка | зависит от договорённости | цену и условия определяешь сам |
Что съест экономику при росте:
- Запросов больше, чем даёт бесплатный план Workers → платный план Cloudflare
- Растёт расход токенов → prompt caching (повторяющийся контекст стоит заметно дешевле) и Batch API для несрочных задач
- Поддержка отнимает больше пары часов в неделю → виртуальный ассистент или автоматизация
С ростом числа клиентов растёт и поддержка. Заранее считай экономику на одного клиента: цена минус токены, инфраструктура и твоё время.
⚠️ Common pitfalls
Day 1: ниша слишком широкая
❌ "AI-бот для малого бизнеса" ✅ "AI-бот для риелторов в Куэнке которые продают иностранцам"
Широкая ниша = generic outreach = почти нет ответов.
Day 3: skip error handling
Если в Day 3 ты "пока что без try/catch, потом добавлю" — в Day 6 на live звонке бот упадёт перед клиентом. Перед клиентом. Это не та история которую хочешь рассказывать.
Day 6: забыл Stripe ToS / refund policy
Без письменного refund policy первый недовольный клиент устроит chargeback и Stripe может ограничить твой аккаунт. Простейший вариант: "Pro-rated refund в первые 14 дней, дальше no refund, можно отменить subscription любым числом." Условия возвратов зависят от страны; это не юридическая консультация.
Day 7: не настроил monitoring
Через 2 недели одно tool execution начинает падать в edge case. Ты узнаёшь от клиента "у нас не работает". С мониторингом (например, Helicone) — узнаёшь сам, а не от клиента.
Любой день: vendor lock-in
Если хардкодишь имя модели в 15 местах — переключиться на Haiku или Gemini для cost optimization будет день работы. Один константа MODEL_NAME в env vars решает проблему за 30 секунд.
✅ What you have at end Day 7
Конкретно. Не "потенциал". Не "опыт". Реальные артефакты:
- Working Telegram bot в Cloudflare Workers production — отвечает 24/7, deployed, monitored
- Первый клиент подключён — условия оплаты согласованы
- Stripe billing — invoice отправлен, recurring настроен (если клиент согласился платить)
- Audit log — все взаимодействия сохранены 90 дней (основа для аудита)
- Cost monitoring — дашборд мониторинга, видишь токены и цену по клиенту
- Rate limiting + cost cap — система не разорится от bug или abuse
- Customer onboarding template — для клиентов №2-10 (уже не с нуля)
- 3 verified happy paths — реально работают на реальном бизнесе
- Cold outreach playbook — что писать, в какой канал, какой response rate ты получил
- Retrospective — что работает, что нет, plan Week 2
📈 Scaling plan (Week 2-4, кратко)
Week 2 (расширяем воронку):
- 30 cold DM используя working Week 1 шаблоны
- 6-8 discovery calls
- 2-3 onboarding
- Затраты: 25 часов твоего времени
Week 3-4 (шаблонизируем):
- Шаблонизируй onboarding (auto-setup нового bot за 30 минут)
- Виртуальный ассистент на подготовку списков и первичную переписку
- Customer success: weekly check-in письма (auto)
- Затраты: 20 часов / неделю
Month 2:
- Случайный referral начнёт работать
- Можно пересмотреть цену для новых клиентов, если ниша позволяет
- Подумай про "white label" — бот под брендом клиента (premium tier)
Где НЕ масштабироваться:
- Не делай "AI бот для всего на свете" — теряешь нишу
- Не нанимай sales людей на раннем этапе — слишком рано
- Не пиши свой dashboard — готового мониторинга хватит надолго
🔗 Cross-references
- Telegram-боты с Claude API — Telegram bot theory (что такое webhook, BotFather, polling vs webhook)
- Hooks — автоматические правила и Hooks LIVE — Claude Code hooks (для local dev workflow)
- Деплой — Cloudflare Workers — Deploy basics (Cloudflare Workers, secrets, wrangler)
- Первые клиенты — First clients и cold outreach методология
- Мультиагентная оркестрация — если захочешь несколько ботов с разными ролями
📚 Источники
- Cloudflare Workers Telegram Tutorial — https://developers.cloudflare.com/workers/tutorials/
- Telegram Bot API — https://core.telegram.org/bots/api
- Anthropic SDK для TypeScript — https://github.com/anthropics/anthropic-sdk-typescript
- Stripe Subscriptions — https://docs.stripe.com/billing/subscriptions/overview
- Helicone (LLM monitoring) — https://www.helicone.ai/
- Cloudflare KV — https://developers.cloudflare.com/kv/
Ключевые выводы
Lab — это не урок. Это 7 дней реальной работы где результат — рабочий бот в production и первый клиент, с которым согласованы условия. Если в воскресенье вечером у тебя только "потенциал" — Lab провален, начни Week 2 как Week 1.
Customer first, code second. Day 1 идёт на discovery calls, а не на код. Без проверенной боли — самый красивый бот не нужен никому. Без оплаченного контракта — продукт ещё не существует.
Экономика бота — это не магия AI. Это правильная ниша + правильная цена + правильные guardrails. Цена оправдана, когда экономит клиенту время, которое стоит дороже твоего сервиса; считай это на цифрах конкретного клиента.
Следующий урок
Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс