За 5 этапов курса мы изучили все кирпичики: API, промпты, агентов, инструменты, память, RAG, fine-tuning, мульти-агентные системы, оптимизацию. Каждый урок — отдельный навык. Но реальный AI-продукт — это не один кирпичик, а здание из десятков компонентов, которые должны работать вместе. Этот урок — про то, как собрать всё изученное в одну систему. Как архитектор проектирует дом до того, как положить первый кирпич — так и AI-продукт нужно спроектировать до того, как написать первую строку кода.
Можно сесть и начать писать код: вот API-вызов, вот база данных, вот Telegram-бот. Для простого проекта это работает. Но когда продукт растёт — начинаются проблемы:
Без архитектуры:
"Добавим RAG" → воткнули в основной файл
"Нужна память" → добавили SQLite рядом
"Нужен второй агент" → скопировали код, поменяли промпт
"Нужен мониторинг" → ещё один скрипт
"Упало в продакшене" → где ошибка? В RAG? В агенте? В базе?
Через 3 месяца: 5000 строк в одном файле, всё связано со всем,
изменение в одном месте ломает три других.
Архитектура — это план системы до написания кода. Она отвечает на вопросы: - Из каких частей состоит продукт? - Как эти части общаются друг с другом? - Что произойдёт, если одна часть сломается? - Как добавить новую функцию, не сломав старые?
Представь, что ты строишь дом. Можно начать класть кирпичи без чертежа — и через месяц обнаружить, что забыл про канализацию, электрика не влезает в стены, а дверь выходит в стену соседа. Архитектор рисует план заранее: вот несущие стены, вот трубы, вот электропроводка. Каждый элемент на своём месте.
AI-продукт — тот же дом. API — это электричество (энергия). База данных — фундамент (хранение). Агент — жилец (логика). RAG — библиотека (знания). Архитектура — чертёж, который объединяет всё это в работающую систему.
Любой AI-продукт состоит из набора компонентов. Не все нужны в каждом проекте — но полезно знать, какие бывают:
┌──────────────────────────────────────────────────────────────┐
│ КОМПОНЕНТЫ AI-ПРОДУКТА │
│ │
│ ИНТЕРФЕЙС (как пользователь взаимодействует) │
│ Telegram-бот, веб-чат, API, мобильное приложение │
│ (урок 4.1) │
│ │
│ ОРКЕСТРАТОР (мозг системы) │
│ Принимает запрос → решает что делать → возвращает ответ │
│ Может быть: один агент, маршрутизатор, мульти-агент │
│ (уроки 3.1-3.5, 5.2) │
│ │
│ МОДЕЛИ (AI-движки) │
│ Claude, GPT, open-source модели │
│ Разные модели для разных задач (урок 5.4) │
│ │
│ ИНСТРУМЕНТЫ (руки агента) │
│ Поиск в базе, вызов API, запись в файл, отправка email │
│ (урок 3.2) │
│ │
│ ПАМЯТЬ (что система помнит) │
│ Краткосрочная: история чата │
│ Долгосрочная: база данных, факты о пользователе │
│ (уроки 3.3, 4.2) │
│ │
│ ЗНАНИЯ (откуда система берёт информацию) │
│ RAG: векторная база с документами (урок 5.1) │
│ Fine-tuning: навыки, вшитые в модель (урок 5.3) │
│ │
│ БЕЗОПАСНОСТЬ (защита) │
│ Валидация входа, rate limiting, фильтрация вывода │
│ (урок 4.5) │
│ │
│ МОНИТОРИНГ (наблюдение) │
│ Логи, расходы, ошибки, качество ответов │
│ (урок 5.4) │
│ │
│ ИНФРАСТРУКТУРА (где всё работает) │
│ Сервер, деплой, база данных, очереди │
│ (уроки 4.2, 4.3) │
│ │
└──────────────────────────────────────────────────────────────┘
Самый важный принцип архитектуры: каждый компонент делает одну вещь и делает её хорошо.
Плохо: один файл делает всё
bot.py (3000 строк)
├── Обработка сообщений Telegram
├── Вызов Claude API
├── Поиск в RAG
├── Запись в базу данных
├── Подсчёт расходов
├── Валидация входа
└── Логирование
Проблема: чтобы изменить RAG — нужно разбираться
в 3000 строках кода. Ошибка в подсчёте расходов
может сломать Telegram-бота.
Хорошо: каждый файл отвечает за своё
bot.py → обработка сообщений (50 строк)
orchestrator.py → логика: что делать с запросом (100 строк)
rag.py → поиск по документам (80 строк)
memory.py → работа с базой данных (60 строк)
llm.py → вызовы Claude API (40 строк)
cost_tracker.py → подсчёт расходов (50 строк)
security.py → валидация и фильтрация (40 строк)
Преимущество: нужно изменить RAG → открываешь один файл.
Ошибка в cost_tracker → бот продолжает работать.
В ресторане повар, официант и кассир — разные люди. Повар готовит, официант обслуживает, кассир считает деньги. Если повар заболел — кассир не пытается готовить. Приходит другой повар и встаёт на то же место.
В AI-продукте так же: если нужно заменить Claude на GPT — меняешь только llm.py. Остальные компоненты не знают и не заботятся, какая модель внутри.
Самая простая архитектура. Подходит для MVP и небольших продуктов.
┌──────────┐ ┌──────────────┐ ┌─────────┐
│ Telegram │────▶│ Оркестратор │────▶│ Claude │
│ бот │◀────│ (1 агент) │◀────│ API │
└──────────┘ └──────┬───────┘ └─────────┘
│
┌────▼────┐
│ SQLite │
│ (память)│
└─────────┘
Когда использовать: бот отвечает на вопросы, помнит контекст, не требует поиска по документам.
Пример: персональный AI-ассистент, FAQ-бот, бот для заметок.
# Структура проекта
simple_bot/
bot.py # Telegram-интерфейс
agent.py # Оркестратор (один агент)
memory.py # SQLite для истории
.env # API-ключи
requirements.txt
# agent.py — простой агент
from anthropic import Anthropic
client = Anthropic()
def process_message(user_id, message, history):
"""
Принимает сообщение пользователя, возвращает ответ.
Это единственная точка входа — бот вызывает только эту функцию.
"""
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
system="Ты — персональный ассистент. Отвечай кратко и полезно.",
messages=history + [{"role": "user", "content": message}]
)
return response.content[0].text
Добавляем поиск по документам. Бот не просто болтает — он отвечает на основе конкретных данных.
┌──────────┐ ┌──────────────┐ ┌─────────┐
│ Telegram │────▶│ Оркестратор │────▶│ Claude │
│ бот │◀────│ │◀────│ API │
└──────────┘ └──────┬───────┘ └─────────┘
│
┌──────┴──────┐
│ │
┌────▼────┐ ┌────▼─────┐
│ SQLite │ │ ChromaDB │
│ (память)│ │ (RAG) │
└─────────┘ └──────────┘
Когда использовать: бот должен отвечать по документации, базе знаний, FAQ компании.
Пример: бот поддержки клиентов, внутренний ассистент компании, юридический помощник.
# Структура проекта
rag_bot/
bot.py # Telegram-интерфейс
orchestrator.py # Решает: нужен RAG или обычный ответ
rag.py # Поиск по документам (из урока 5.1)
memory.py # SQLite для истории
llm.py # Вызовы Claude API
load_docs.py # Загрузка документов в ChromaDB
my-docs/ # Папка с документами
.env
# orchestrator.py — решает, нужен ли RAG
from rag import search_documents
from llm import ask_claude
from memory import get_history, save_message
def process_message(user_id, message):
"""
Главная логика:
1. Ищем релевантные документы
2. Если нашли — отправляем с контекстом
3. Если нет — отвечаем без контекста
"""
history = get_history(user_id)
# Поиск в документах
docs = search_documents(message, n_results=3)
if docs and docs[0]["distance"] < 1.0:
# Нашли релевантные документы — используем RAG
context = "\n\n".join([d["text"] for d in docs])
answer = ask_claude(
message=message,
history=history,
system=f"Отвечай на основе документов:\n\n{context}"
)
else:
# Документы не найдены — обычный ответ
answer = ask_claude(
message=message,
history=history,
system="Ты — помощник компании. Если не знаешь ответ — скажи."
)
save_message(user_id, message, answer)
return answer
Разные типы запросов → разные обработчики. Маленькая модель решает, куда направить запрос.
┌──────────────┐
┌───▶│ RAG-агент │──▶ ChromaDB
│ └──────────────┘
┌──────────┐ ┌───────┴──┐
│ Telegram │───▶│ Маршрути- │──┐ ┌──────────────┐
│ бот │◀───│ затор │──┼▶│ Чат-агент │──▶ Claude
└──────────┘ │ (Haiku) │ │ └──────────────┘
└───────┬──┘ │
│ │ ┌──────────────┐
└─────┴▶│ Агент задач │──▶ Tools
└──────────────┘
Когда использовать: бот выполняет разные типы задач, и для каждого типа нужна своя логика.
Пример: ассистент, который и отвечает на вопросы, и ставит напоминания, и ищет по документам.
# router.py — маршрутизатор запросов
from llm import classify, ask_claude
from rag import search_and_answer
from tasks import handle_task
def route(user_id, message):
"""
Haiku классифицирует запрос → направляет нужному агенту.
Стоимость классификации: ~$0.0001 (ничтожная).
"""
# Шаг 1: Haiku определяет тип запроса
intent = classify(message)
# Возвращает: "question", "task", "chat"
# Шаг 2: Направляем нужному обработчику
if intent == "question":
# Вопрос по документам → RAG
return search_and_answer(message)
elif intent == "task":
# Задача: напоминание, расчёт, действие → агент с инструментами
return handle_task(user_id, message)
else:
# Обычный разговор → чат-агент
return ask_claude(message)
# llm.py — обёртка над Claude API
from anthropic import Anthropic
client = Anthropic()
def classify(message):
"""Haiku классифицирует тип запроса. Дёшево и быстро."""
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=20,
messages=[{
"role": "user",
"content": f"""Классифицируй запрос. Ответь одним словом:
question — вопрос, требующий поиска информации
task — задача, действие, напоминание
chat — обычный разговор
Запрос: {message}"""
}]
)
return response.content[0].text.strip().lower()
def ask_claude(message, history=None, system=None, model="claude-sonnet-4-6"):
"""Универсальная обёртка для вызова Claude."""
messages = (history or []) + [{"role": "user", "content": message}]
response = client.messages.create(
model=model,
max_tokens=1024,
system=system or "Ты — полезный ассистент.",
messages=messages
)
return response.content[0].text
Запрос проходит через цепочку шагов. Каждый шаг — отдельный компонент.
Запрос ──▶ Валидация ──▶ Обогащение ──▶ Генерация ──▶ Проверка ──▶ Ответ
(security) (RAG/память) (Claude) (фильтр)
Когда использовать: каждый запрос должен пройти фиксированные этапы обработки.
Пример: бот поддержки с проверкой безопасности, поиском контекста и фильтрацией ответа.
# pipeline.py — конвейер обработки запроса
from security import validate_input, filter_output
from rag import find_context
from memory import get_history, save_message
from llm import ask_claude
from cost_tracker import log_cost
def process(user_id, message):
"""
Конвейер: запрос проходит 5 шагов последовательно.
Если шаг падает — возвращаем безопасный ответ.
"""
# Шаг 1: Валидация (безопасность)
is_safe, reason = validate_input(message)
if not is_safe:
return f"Не могу обработать этот запрос: {reason}"
# Шаг 2: Обогащение (собираем контекст)
history = get_history(user_id, limit=10)
context = find_context(message) # RAG-поиск
# Шаг 3: Генерация (вызов модели)
system = "Ты — помощник техподдержки."
if context:
system += f"\n\nКонтекст из документов:\n{context}"
answer = ask_claude(message, history=history, system=system)
# Шаг 4: Фильтрация вывода (безопасность)
answer = filter_output(answer)
# Шаг 5: Сохранение и логирование
save_message(user_id, message, answer)
return answer
Ключевое: каждый шаг — отдельная функция из отдельного файла. Если нужно добавить новый шаг (например, перевод) — вставляешь его между шагами 3 и 4.
Несколько специализированных агентов под управлением оркестратора. Самый сложный, но самый мощный паттерн.
┌──────────────────────┐
│ ОРКЕСТРАТОР │
│ (планирует, делегирует)│
└──┬────────┬────────┬──┘
│ │ │
┌────────▼─┐ ┌───▼────┐ ┌▼─────────┐
│ RAG-агент│ │Аналитик│ │ Писатель │
│(документы)│ │(данные)│ │ (тексты) │
└────┬─────┘ └───┬────┘ └─────┬─────┘
│ │ │
┌────▼────┐ ┌───▼────┐ Claude
│ChromaDB │ │ SQL │
└─────────┘ └────────┘
Когда использовать: задача требует разных навыков, контекст одного агента переполняется, подзадачи можно выполнять параллельно.
Пример: AI-аналитик, который ищет данные, анализирует их и пишет отчёт. Подробно разобрано в уроке 5.2.
Что строишь?
│
├── Простой чат-бот, FAQ
│ → Паттерн 1: Простой бот
│ → Один файл agent.py + память
│
├── Бот с доступом к документам
│ → Паттерн 2: Бот + RAG
│ → orchestrator + rag + memory
│
├── Бот с разными типами задач
│ → Паттерн 3: Маршрутизатор
│ → router + специализированные обработчики
│
├── Продакшн-бот с безопасностью и мониторингом
│ → Паттерн 4: Конвейер
│ → pipeline с шагами: валидация → контекст → генерация → фильтр
│
└── Сложная система с несколькими AI-специалистами
→ Паттерн 5: Мульти-агент
→ orchestrator + агенты (урок 5.2)
Принцип: начинай с Паттерна 1. Усложняй только когда простое не работает. Тот же принцип, что и для всего остального в курсе.
my-bot/
├── bot.py # Telegram-интерфейс
├── agent.py # Логика агента
├── memory.py # Работа с SQLite
├── .env # API-ключи (НЕ в git!)
├── .gitignore # Исключения для git
├── requirements.txt # Зависимости (pip freeze)
└── README.md # Как запустить
support-bot/
├── bot.py # Telegram-интерфейс
├── router.py # Маршрутизатор запросов
├── agents/
│ ├── chat.py # Чат-агент
│ ├── rag.py # RAG-агент
│ └── tasks.py # Агент задач
├── core/
│ ├── llm.py # Обёртка Claude API
│ ├── memory.py # Работа с SQLite
│ └── security.py # Валидация и фильтрация
├── data/
│ ├── docs/ # Документы для RAG
│ └── chroma_db/ # Векторная база
├── monitoring/
│ ├── cost_tracker.py # Подсчёт расходов
│ └── logger.py # Логирование
├── .env
├── .gitignore
├── requirements.txt
└── README.md
bot.py — точка входа. Знает только про router.
Не знает про Claude, RAG или базу данных.
router.py — принимает решения. Знает про агентов.
Не знает, как агенты устроены внутри.
agents/ — каждый агент в своём файле. Знает про llm.py.
Не знает про Telegram или другие агенты.
core/ — общие компоненты. llm.py, memory.py, security.py.
Не знают, кто их вызывает.
monitoring/ — наблюдение. Можно удалить — система работает.
Но без мониторинга не видно проблем.
Каждый уровень знает только про уровень ниже. Telegram не знает про Claude. Claude не знает про Telegram. Связывает их оркестратор.
В реальном продукте всё ломается. API не отвечает, база данных падает, пользователь отправляет мусор. Архитектура должна это учитывать.
Проблема 1: Claude API не отвечает (таймаут, 500 ошибка)
Решение: retry с задержкой + fallback
→ Попробовать ещё раз через 2 секунды
→ Если 3 попытки не помогли — ответить заготовкой:
"Извините, сейчас не могу ответить. Попробуйте позже."
Проблема 2: RAG не находит документы
Решение: fallback на обычный ответ
→ "В документах не нашёл ответа, но вот что я думаю..."
→ Или: "Не нашёл информацию. Обратитесь в поддержку: ..."
Проблема 3: Пользователь отправляет prompt injection
Решение: валидация входа (урок 4.5)
→ Проверять сообщение ДО отправки в Claude
→ Фильтровать вывод ПОСЛЕ получения ответа
Проблема 4: Превышен бюджет на API
Решение: лимиты (урок 5.4)
→ Дневной лимит: $5
→ Лимит на пользователя: 50 запросов/день
→ Если лимит исчерпан: "Лимит запросов на сегодня достигнут."
Проблема 5: Модель галлюцинирует (выдаёт ложную информацию)
Решение: RAG + проверка
→ Отвечать ТОЛЬКО на основе документов
→ Системный промпт: "Если информации нет — скажи, что не знаешь."
→ Для критических задач: человек проверяет ответ перед отправкой
# llm.py — вызов Claude с обработкой ошибок
import time
from anthropic import Anthropic, APIError, APITimeoutError
client = Anthropic()
def ask_claude(message, system=None, model="claude-sonnet-4-6", max_retries=3):
"""
Вызов Claude с автоматическим повтором при ошибках.
Если все попытки провалились — возвращает fallback-ответ.
"""
for attempt in range(max_retries):
try:
response = client.messages.create(
model=model,
max_tokens=1024,
system=system or "Ты — полезный ассистент.",
messages=[{"role": "user", "content": message}]
)
return response.content[0].text
except APITimeoutError:
# API не ответил вовремя — ждём и пробуем снова
if attempt < max_retries - 1:
wait = 2 ** attempt # 1с, 2с, 4с (экспоненциальная задержка)
time.sleep(wait)
else:
return "Извините, сервис временно недоступен. Попробуйте позже."
except APIError as e:
# Ошибка API (429 = слишком много запросов, 500 = сервер упал)
if e.status_code == 429:
time.sleep(5) # rate limit — ждём подольше
elif attempt == max_retries - 1:
return "Произошла ошибка. Попробуйте позже."
Вместо того чтобы бомбить API повторными запросами — каждый следующий повтор ждёт дольше:
Попытка 1: ошибка → ждём 1 секунду
Попытка 2: ошибка → ждём 2 секунды
Попытка 3: ошибка → ждём 4 секунды
Попытка 4: все попытки исчерпаны → возвращаем fallback
Аналогия. Звонишь другу — занято. Перезваниваешь через минуту — занято. Через 5 минут — занято. Через 15 минут — не берёт. Не звонишь каждые 2 секунды — это раздражает и не помогает.
10 пользователей: всё работает, SQLite хватает
100 пользователей: всё ещё нормально
1000 пользователей: SQLite начинает тормозить, API-счёт растёт
10 000: нужна очередь, кеширование, мониторинг
Этап 1: до 100 пользователей (MVP)
├── SQLite для памяти
├── ChromaDB для RAG
├── Один сервер
└── Haiku для простых задач
Этап 2: 100-1000 пользователей
├── PostgreSQL вместо SQLite (надёжнее при параллельных запросах)
├── Prompt caching (экономия 90%)
├── Маршрутизатор моделей (Haiku/Sonnet)
└── Логирование расходов
Этап 3: 1000-10 000 пользователей
├── Очередь задач (Redis + Celery или аналог)
│ Запросы складываются в очередь, обрабатываются по порядку.
│ Пользователь не ждёт — получает "Обрабатываю..." и потом ответ.
├── Кеширование ответов
│ Одинаковые вопросы → одинаковый ответ из кеша (без вызова API).
├── Batch API для фоновых задач
└── Мониторинг (Grafana, Prometheus или простые логи)
Если 100 пользователей в день спрашивают «Как оформить возврат?» — зачем вызывать Claude 100 раз?
# cache.py — простой кеш ответов
import json
import hashlib
import time
CACHE_FILE = "response_cache.json"
CACHE_TTL = 3600 # 1 час (секунды)
def get_cache_key(message):
"""Создаёт уникальный ключ из текста сообщения."""
return hashlib.md5(message.lower().strip().encode()).hexdigest()
# md5 превращает любой текст в уникальную строку из 32 символов
# "Как оформить возврат?" → "a1b2c3d4e5f6..."
def get_cached(message):
"""Ищет ответ в кеше. Возвращает None, если не найден или устарел."""
key = get_cache_key(message)
try:
with open(CACHE_FILE) as f:
cache = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return None
entry = cache.get(key)
if entry and time.time() - entry["timestamp"] < CACHE_TTL:
return entry["response"] # Нашли! Возвращаем без вызова API
return None
def save_to_cache(message, response):
"""Сохраняет ответ в кеш."""
key = get_cache_key(message)
try:
with open(CACHE_FILE) as f:
cache = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
cache = {}
cache[key] = {"response": response, "timestamp": time.time()}
with open(CACHE_FILE, "w") as f:
json.dump(cache, f)
# Использование в оркестраторе:
def process(message):
# Сначала проверяем кеш
cached = get_cached(message)
if cached:
return cached # Бесплатно!
# Кеша нет — вызываем Claude
answer = ask_claude(message)
# Сохраняем в кеш для следующих
save_to_cache(message, answer)
return answer
┌──────────────────────────────────────────────────────────────┐
│ БОТ ПОДДЕРЖКИ КЛИЕНТОВ │
│ │
│ Пользователь │
│ │ │
│ ▼ │
│ [Telegram / Веб-чат / WhatsApp] │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Валидация │ ← Проверка на prompt injection │
│ └──────┬──────┘ │
│ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Маршрутизатор│────▶│ Определение │ │
│ │ (Haiku) │ │ категории │ │
│ └──────┬──────┘ └──────────────┘ │
│ │ │
│ ┌────┼────┐ │
│ ▼ ▼ ▼ │
│ [FAQ] [Заказ] [Жалоба] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ RAG API Sonnet ── "Эскалация: передаю человеку" │
│ │ магазина │ │
│ ▼ │ ▼ │
│ Haiku ▼ Запись в │
│ │ Haiku CRM │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────┐ │
│ │ Фильтр │ ← Убираем PII, проверяем корректность │
│ └─────┬─────┘ │
│ ▼ │
│ [Ответ пользователю] │
│ │
│ + Мониторинг: расходы, время ответа, удовлетворённость │
│ + Память: SQLite (история), ChromaDB (документы) │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ AI-АССИСТЕНТ ДЛЯ АНАЛИТИКИ │
│ │
│ "Покажи продажи за прошлый месяц по категориям" │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Оркестратор │ (Sonnet — понимает задачу) │
│ │ "Нужно: данные │ │
│ │ + анализ │ │
│ │ + визуализация" │ │
│ └────┬─────┬────────┘ │
│ │ │ │
│ ┌────▼──┐ ┌▼──────────┐ │
│ │SQL- │ │ Аналитик │ │
│ │агент │ │ │ │
│ │(Haiku)│ │ (Sonnet) │ │
│ └───┬───┘ └─────┬─────┘ │
│ │ │ │
│ ▼ ▼ │
│ PostgreSQL "Продажи выросли │
│ → таблица на 15%..." │
│ данных │ │
│ │ ▼ │
│ └──▶ ┌──────────┐ │
│ │ Генератор │ │
│ │ отчёта │ │
│ └─────┬────┘ │
│ ▼ │
│ [Отчёт с графиком │
│ в Telegram] │
└──────────────────────────────────────────────────────────────┘
Перед тем как показать продукт пользователям — проверь:
ФУНКЦИОНАЛЬНОСТЬ
□ Бот отвечает на типовые вопросы корректно
□ Бот говорит "не знаю", когда не знает (а не выдумывает)
□ История чата сохраняется между сессиями
□ RAG находит релевантные документы (если используется)
БЕЗОПАСНОСТЬ (урок 4.5)
□ API-ключи в .env, не в коде
□ .env добавлен в .gitignore
□ Есть защита от prompt injection
□ Вывод фильтруется (нет PII, нет вредного контента)
□ Rate limiting: ограничение запросов на пользователя
СТОИМОСТЬ (урок 5.4)
□ Правильная модель для каждой задачи (не Opus для FAQ)
□ Prompt caching включен (если повторяющийся контекст)
□ max_tokens ограничен (не 4096 для простого ответа)
□ Дневной бюджет установлен
□ Расходы логируются
НАДЁЖНОСТЬ
□ Ошибки API обрабатываются (retry + fallback)
□ Если база недоступна — бот не падает
□ Если бюджет исчерпан — пользователь получает сообщение
□ Логи записываются для отладки
ДЕПЛОЙ (урок 4.3)
□ Бот работает на сервере (не на ноутбуке)
□ systemd перезапускает при падении
□ Есть способ обновить код без потери данных
Выбери AI-продукт (можно свой или из списка): - Бот-ассистент для интернет-магазина - AI-помощник для изучения английского - Бот, который анализирует расходы из чеков
Нарисуй схему архитектуры: какие компоненты, как связаны, какие модели используешь. Используй ASCII-диаграммы как в этом уроке.
Возьми бота из урока 4.1 и преврати его в конвейер (Паттерн 4):
1. Вынеси логику в отдельные файлы: llm.py, memory.py, security.py
2. Добавь pipeline.py с шагами: валидация → контекст → генерация → фильтр
3. Добавь cost_tracker.py из урока 5.4
Добавь кеш ответов из этого урока. Проверь: если два пользователя задают одинаковый вопрос — второй получает ответ мгновенно (без вызова API). Подсчитай, сколько API-вызовов экономит кеш за день.
Задача 1: Зачем разделять код на отдельные файлы?
Задача 2: Когда использовать маршрутизатор, а когда конвейер?
Задача 3: Почему exponential backoff лучше, чем повторять запрос сразу?
Задача 4: У тебя 1000 пользователей в день задают одни и те же 50 вопросов. Какие стратегии применить?
Задача 5: Что должен делать бот, если Claude API не отвечает?
| Термин | Что значит |
|---|---|
| Архитектура | План системы: из каких частей состоит, как они связаны, как взаимодействуют |
| Компонент | Отдельная часть системы с одной ответственностью (бот, агент, память, RAG) |
| Разделение ответственности | Принцип: каждый компонент делает одну вещь. Изменение одного не ломает другие |
| Оркестратор | Центральный компонент, который принимает запрос и решает, что с ним делать |
| Маршрутизатор (router) | Компонент, который направляет запрос нужному обработчику по типу задачи |
| Конвейер (pipeline) | Последовательность шагов, через которые проходит каждый запрос |
| Fallback | Запасной ответ, когда основная логика сломалась (API не отвечает, база упала) |
| Retry | Повторная попытка запроса после ошибки |
| Exponential backoff | Стратегия повтора с увеличивающейся задержкой: 1с → 2с → 4с → 8с |
| Rate limiting | Ограничение количества запросов на пользователя за период времени |
| Кеширование ответов | Сохранение ответов на частые вопросы, чтобы не вызывать API повторно |
| TTL (Time to Live) | Время жизни записи в кеше. После TTL запись считается устаревшей |
| MVP | Minimum Viable Product — минимальный работающий продукт для проверки идеи |
| Масштабирование | Способность системы работать с растущим количеством пользователей |
| Очередь задач | Механизм (Redis, Celery), где запросы складываются в очередь и обрабатываются по порядку |
| Эскалация | Передача сложного запроса от бота живому оператору |
Архитектура = план системы до написания кода
Главный принцип:
Каждый компонент делает одну вещь.
bot.py не знает про Claude. llm.py не знает про Telegram.
5 паттернов (от простого к сложному):
1. Простой бот — один агент + память
2. Бот + RAG — агент + поиск по документам
3. Маршрутизатор — разные запросы → разные обработчики
4. Конвейер — валидация → контекст → генерация → фильтр
5. Мульти-агент — оркестратор + специализированные агенты
Обработка ошибок:
• Retry с exponential backoff (1с → 2с → 4с)
• Fallback-ответ, если всё сломалось
• Лимиты бюджета и rate limiting
• Логирование для отладки
Масштабирование:
10 пользователей → SQLite, один сервер
1000 → PostgreSQL, prompt caching, маршрутизатор
10 000 → очередь, кеш ответов, batch API
Начинай с Паттерна 1. Усложняй только когда простое не работает.
Это последний урок курса AI Academy. За 5 этапов пройден путь от «что такое терминал» до проектирования архитектуры AI-продуктов. Вот карта того, что теперь доступно:
┌──────────────────────────────────────────────────────────────┐
│ ТВОЙ НАБОР НАВЫКОВ │
│ │
│ Фундамент: терминал, Python, Git, файлы │
│ Понимание AI: LLM, API, промпты, токены, стоимость │
│ Агенты: tools, память, Agent SDK, мульти-шаг │
│ Продукты: Telegram-бот, БД, деплой, безопасность │
│ Экспертный: RAG, мульти-агенты, fine-tuning, │
│ оптимизация, архитектура │
│ │
│ Этого достаточно, чтобы: │
│ → Создать AI-продукт с нуля │
│ → Задеплоить его на сервер │
│ → Сделать его безопасным и экономичным │
│ → Масштабировать на тысячи пользователей │
│ → Понимать архитектуру любого AI-продукта на рынке │
│ │
└──────────────────────────────────────────────────────────────┘
Дальше — практика. Лучший способ закрепить знания — построить свой продукт. Взять идею, спроектировать архитектуру, написать код, задеплоить и показать людям. Всё, что для этого нужно — в этом курсе.