ZeroPost
Все статьи

Как я за день сделал чат-бота на Claude API и что из этого вышло

ZeroPost AI11 октября 2026 г. 4 мин чтения
Как я за день сделал чат-бота на Claude API и что из этого вышло

Заказ был простой: внутренний чат-бот для техподдержки. Компания небольшая, 30 человек, саппорт по сути ведёт один человек — и он уже задолбался отвечать на одно и то же по десять раз на дню. Мне дали неделю и бюджет, который я честно не назову вслух. Обычная история для фрилансера.

Раньше я бы взял LangChain, напихал туда всего по максимуму и месяц разбирался, почему ничего не работает. В этот раз решил попробовать иначе — и за субботу сделал то, что раньше делал неделю.

Делюсь, что понял на практике.

Почему именно Claude API, а не готовый фреймворк

Был соблазн взять что-то типа Botpress или готовый конструктор. Но там ты привязан к их логике, к их ограничениям, и кастомизация уходит в ад. А тут задача конкретная: бот отвечает на вопросы по продукту компании, знает внутреннюю базу знаний и не галлюцинирует безбожно.

Claude хорош в двух вещах, которые здесь критичны. Во-первых — длинный контекст. Я могу засунуть в один запрос всю базу знаний и не париться насчёт RAG-архитектуры для простого случая. Во-вторых — он реально читает инструкции. Если сказать «отвечай только по базе знаний, если не знаешь — говори "я не знаю"» — он так и делает, в отличие от той же GPT-3.5, которая любит додумать.

Что я использовал и почему

Стек минимальный: Python, FastAPI и клиент Anthropic. Никаких LangChain, LlamaIndex и прочего. Честно скажу — сначала хотел добавить LangChain для «серьёзности». Потом сел и подумал: зачем? Мне нужно отправлять запросы, получать ответы, хранить историю переписки. Это можно сделать на чистом клиенте за 50 строк кода.

from anthropic import Anthropic
client = Anthropic()

response = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    system="Ты техподдержка компании X. Отвечай кратко и по делу.",
    messages=[
        {"role": "user", "content": "Как восстановить пароль?"}
    ]
)

Вот и весь бот. Ладно, не весь — дальше добавился роутинг, обработка ошибок и интеграция с базой знаний. Но основа — это действительно десятки строк.

Как я боролся с галлюцинациями

Первая версия отвечала уверенно и красиво. Вот только половина ответов была выдумана. Клиент покачал головой и сказал фразу, которую я запомню: «Лучше бот, который говорит "я не знаю", чем бот, который врёт».

Решение оказалось простым. Я не стал городить RAG с эмбеддингами и векторными базами — это оверкилл для базы знаний в 50 страниц текста. Вместо этого сделал так.

Инструкция в system prompt говорит: «Тебе дана база знаний. Если вопрос можно ответить на её основе — отвечай. Если информации недостаточно — напиши "Я не нашёл точного ответа в базе знаний. Передам вопрос команде поддержки."» А дальше просто передаю текст базы знаний в каждый запрос как первый user message. Да, токены расходуются, но при таком объёме это копейки. Зато ноль галлюцинаций по существу — проверил на 40 тестовых вопросах.

Для большой базы знаний я бы уже смотрел в сторону векторного поиска. Но для 50 страниц — избыточно.

История переписки: где я обжёгся

Сначала сделал наивно: хранил историю в памяти процесса. Запустил — вроде работает. Потом деплой, перезапуск пода — и у пользователя чистая история. Обидно.

Переделал на хранение сессий в Redis. Теперь у каждого пользователя ключ с историей переписки, и при каждом запросе я достаю последние N сообщений и докидываю в массив messages. Поскольку у Claude есть лимит контекста — 200K для новых моделей — я ещё сделал простой тримминг: если история длиннее 20 сообщений, обрезаю до последних 10.

def build_context(session_id: str, new_message: str) -> list:
    history = redis.lrange(f"session:{session_id}", 0, -1)
    context = [json.loads(m) for m in history]
    context.append({"role": "user", "content": new_message})
    
    # Тримминг если контекст большой
    if len(context) > 20:
        context = context[-10:]
    return context

Мелочь, но без неё бот терял нить разговора на третьем сообщении.

Формат ответов — отдельная боль

Поначалу бот отвечал простынями текста. Юзеры говорили: «Это читать? Серьёзно?» Понял, что надо ограничивать длину и задавать формат.

В system prompt добавил: «Отвечай не более трёх предложений. Используй списки только если пунктов больше трёх.» И результат сразу другой — лаконичный, по делу.

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

Что в итоге

За субботу сделал рабочего бота. За воскресенье — интеграцию с веб-интерфейсом. За понедельник — первый фидбек от заказчика. Он сказал: «Работает лучше, чем я ожидал от прототипа». Это было приятно.

Что понял для себя.

Для простого бота с конкретной задачей — если тебе нужно просто отвечать на вопросы — возможно, хватит чего-то попроще. Но вот где важна логика, много контекста и соблюдение инструкций — Claude подходит отлично. Особенно с длинным контекстом.

Не городи фреймворки без необходимости. Мне понадобилось два дня, чтобы перестать бояться написать бота на чистом API. А всё оказалось проще, чем я думал.

Если есть что-то, что хочешь уточнить — пиши в комментариях. Разберёмся вместе.

Зеро
Понравилась заметка?
Зеро публикует новые материалы каждый день в Telegram. Подпишитесь — следующая уже завтра.
✈️ В канал