Библиотека · Поддержка клиентов и голосовые агенты

AI Customer Support — тикет-система, RAG по базе знаний, умная поддержка

Строитель65 минОбновлено: октябрь 2026
60 из 105 в библиотеке

Время: ~25 мин теории + 40 мин практики

Суть урока

Представь умный ресепшн в большой больнице. Все пациенты сначала идут к нему. Большую часть вопросов он решает сам: объясняет как записаться, где парковка, какие документы нужны. Часть — готовит краткую сводку и передаёт нужному врачу. Критичные случаи — сразу сигнализирует дежурному. Врачи занимаются только тем, для чего они нужны.

AI Customer Support работает так же. Не вместо команды поддержки — рядом с ней. Берёт на себя типовое, освобождает людей для сложного.

В этом уроке строим полноценную систему: тикет-систему с классификацией, RAG по базе знаний компании, автоответы и умную эскалацию. Результат — основа, из которой можно собрать услугу для клиентов.

Ключевые концепции

  • RAG (Retrieval-Augmented Generation) — Claude отвечает опираясь на конкретные документы, не выдумывает
  • Классификация тикетов — типовой / нетипичный / критичный
  • Эскалация — автоматическая передача сложных случаев человеку
  • Deflection Rate — процент вопросов которые AI решил без человека
  • CSAT — оценка клиента (Customer Satisfaction Score)

Теория

Зачем AI Customer Support

Без AI первый ответ в поддержке часто приходит через несколько часов. Это нормально для сложного вопроса. Но большинство вопросов типовые: "как сменить тариф", "где моя посылка", "как подключить интеграцию". На них клиент ждёт часами и получает ответ из двух строк который агент скопировал из FAQ.

С AI:

  • Типовой вопрос → автоответ за 30 секунд (клиент доволен)
  • Нетипичный → AI-драфт для агента, агент редактирует → 5 минут вместо 20
  • Критичный → немедленная эскалация + уведомление агента

Агент теперь занимается только нетипичным и критичным. Объём его работы заметно падает, а качество ответов на сложное растёт, потому что есть фокус.


Архитектура системы

Код
Клиент пишет вопрос
    ↓
Классификация (Claude): типовой / нетипичный / критичный
    ↓
Типовой → RAG по базе знаний → автоответ (большая часть, ориентир 80%)
Нетипичный → AI-драфт для агента → агент редактирует → отправляет (ориентир 15%)
Критичный → немедленная эскалация + уведомление → агент сам отвечает (ориентир 5%)

Три слоя:

  1. Классификатор — решает куда маршрутизировать
  2. RAG по базе знаний — находит точный ответ из документов
  3. Интеграция с каналом (Intercom / Telegram / email) — принимает вопрос и отправляет ответ

RAG — шпаргалка которую AI всегда помнит

RAG расшифровывается как Retrieval-Augmented Generation. Звучит сложно, суть простая.

Обычный Claude отвечает из своих общих знаний. Это хорошо для общих вопросов. Плохо — если нужен ответ о конкретной компании: её тарифах, политике возвратов, особенностях продукта.

RAG — это когда ты даёшь Claude шпаргалку прямо в промпте. Документы FAQ, инструкции, политики — всё это вставляется в системный промпт или контекст. Claude видит базу знаний и отвечает строго из неё. Если ответа в базе нет — говорит об этом честно, не выдумывает.

Образ: не студент который пытается вспомнить — а студент со шпаргалкой. Отвечает точно. Ссылается на источник. Если в шпаргалке нет — так и говорит.


Практика

Шаг 1. Структура базы знаний

Создай папку knowledge-base/ с MD файлами. По одному файлу на каждую тему:

Код
knowledge-base/
  billing.md          — вопросы об оплате
  shipping.md         — доставка и возвраты
  integrations.md     — подключение интеграций
  plans.md            — тарифные планы
  account.md          — управление аккаунтом

Пример billing.md:

markdown
## Как изменить тарифный план

Зайдите в личный кабинет → Настройки → Тарифный план → выберите новый план.
Изменение вступает в силу немедленно. Доплата рассчитывается пропорционально.

## Возврат средств

Возврат возможен в течение 14 дней после оплаты при первом заказе.
Для возврата напишите на billing@company.com с темой "Возврат" и номером заказа.
Срок обработки — 5 рабочих дней.

## Чем отличаются планы Basic и Pro

Basic: до 5 пользователей, 10 GB хранилища, email-поддержка.
Pro: неограниченно пользователей, 100 GB хранилища, приоритетная поддержка, API доступ.

Шаг 2. Загрузка базы знаний и ответ на тикет

python
import anthropic
import json
import time
from pathlib import Path
from datetime import datetime, timezone

client = anthropic.Anthropic()


def load_knowledge_base(kb_path: str) -> str:
    """Загружает базу знаний из MD файлов"""
    kb_content = []
    for md_file in Path(kb_path).glob("**/*.md"):
        kb_content.append(f"\n## {md_file.stem}\n{md_file.read_text()}")
    return "\n".join(kb_content)


KB = load_knowledge_base("knowledge-base/")


def answer_support_ticket(question: str) -> dict:
    """Классифицирует тикет и отвечает или эскалирует"""

    start_time = time.time()

    response = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=800,
        system=f"""Ты AI-агент поддержки клиентов.

БАЗА ЗНАНИЙ КОМПАНИИ:
{KB}

Правила:
1. Если ответ есть в базе знаний — ответь точно используя её, не добавляй ничего от себя
2. В конце ответа укажи: Источник: [название раздела базы знаний]
3. Если ответа в базе знаний нет — напиши в первой строке ESCALATE и объясни почему нужен человек
4. Если вопрос касается возврата денег — ВСЕГДА пиши ESCALATE (даже если ответ в базе есть)
5. Если вопрос о технической неполадке у клиента — ESCALATE
6. Тон: дружелюбный, конкретный, без воды""",
        messages=[{"role": "user", "content": question}]
    )

    answer = "".join(b.text for b in response.content if b.type == "text")
    response_time = time.time() - start_time

    return {
        "answer": answer,
        "needs_human": answer.strip().startswith("ESCALATE"),
        "response_time_sec": round(response_time, 2),
        "confidence": "low" if answer.strip().startswith("ESCALATE") else "high"
    }


def track_metrics(result: dict, question: str):
    """Записывает метрики в лог"""
    log_entry = {
        "ts": datetime.now(timezone.utc).isoformat(),
        "escalated": result["needs_human"],
        "response_time_sec": result["response_time_sec"],
        "confidence": result["confidence"],
        "question_length": len(question)
    }
    with open("support-metrics.jsonl", "a") as f:
        f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")


# Пример использования
if __name__ == "__main__":
    questions = [
        "Как изменить тарифный план?",
        "Хочу вернуть деньги за подписку",
        "У меня не работает интеграция с Slack, всё сломалось"
    ]

    for question in questions:
        print(f"\nВопрос: {question}")
        result = answer_support_ticket(question)
        track_metrics(result, question)

        if result["needs_human"]:
            print(f"ЭСКАЛАЦИЯ -> передаём живому агенту")
            print(f"Причина: {result['answer']}")
        else:
            print(f"Автоответ ({result['response_time_sec']} сек):")
            print(result["answer"])

Шаг 3. Интеграция с Intercom

python
from flask import Flask, request
import requests
import os

app = Flask(__name__)

INTERCOM_TOKEN = os.environ["INTERCOM_TOKEN"]
AI_BOT_ID = os.environ["INTERCOM_BOT_ID"]


def assign_to_human_agent(conversation_id: str, priority: str = "normal"):
    """Назначает тикет живому агенту и ставит метку"""
    requests.post(
        f"https://api.intercom.io/conversations/{conversation_id}/parts",
        headers={
            "Authorization": f"Bearer {INTERCOM_TOKEN}",
            "Content-Type": "application/json"
        },
        json={
            "type": "admin",
            "admin_id": AI_BOT_ID,
            "message_type": "assignment",
            "assignee_id": None  # назначит команде, не конкретному агенту
        }
    )

    # Ставим метку приоритета
    if priority == "high":
        requests.post(
            f"https://api.intercom.io/conversations/{conversation_id}/tags",
            headers={"Authorization": f"Bearer {INTERCOM_TOKEN}"},
            json={"id": os.environ["INTERCOM_HIGH_PRIORITY_TAG_ID"]}
        )


@app.post("/intercom-webhook")
def handle_message():
    data = request.json

    if data.get("type") != "conversation.user.created":
        return {"status": "ignored"}

    item = data["data"]["item"]
    conversation_id = item["id"]
    parts = item["conversation_parts"]["conversation_parts"]

    if not parts:
        return {"status": "no_message"}

    message = parts[0]["body"]

    # AI отвечает
    result = answer_support_ticket(message)
    track_metrics(result, message)

    if not result["needs_human"]:
        # Отправляем автоответ от имени бота
        requests.post(
            f"https://api.intercom.io/conversations/{conversation_id}/reply",
            headers={
                "Authorization": f"Bearer {INTERCOM_TOKEN}",
                "Content-Type": "application/json"
            },
            json={
                "type": "admin",
                "admin_id": AI_BOT_ID,
                "message_type": "comment",
                "body": result["answer"]
            }
        )
    else:
        # Сообщаем клиенту что подключаем человека
        requests.post(
            f"https://api.intercom.io/conversations/{conversation_id}/reply",
            headers={
                "Authorization": f"Bearer {INTERCOM_TOKEN}",
                "Content-Type": "application/json"
            },
            json={
                "type": "admin",
                "admin_id": AI_BOT_ID,
                "message_type": "comment",
                "body": "Ваш вопрос передан специалисту. Ответим в течение 2 часов."
            }
        )
        assign_to_human_agent(conversation_id, priority="high")

    return {"status": "ok"}


if __name__ == "__main__":
    app.run(port=5000)

Шаг 4. Telegram-бот для поддержки

Если у клиента нет Intercom — Telegram бот закрывает задачу за пару часов.

python
import asyncio
import os
from telegram import Update, Bot
from telegram.ext import Application, MessageHandler, filters

TELEGRAM_BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
SUPPORT_TEAM_CHAT = os.environ["SUPPORT_TEAM_CHAT_ID"]

bot = Bot(token=TELEGRAM_BOT_TOKEN)


async def handle_support_message(update: Update, context):
    user_message = update.message.text
    user_id = update.effective_user.id
    username = update.effective_user.username or str(user_id)

    # Индикатор что бот работает
    await update.message.reply_text("Проверяю...")

    result = answer_support_ticket(user_message)
    track_metrics(result, user_message)

    if not result["needs_human"]:
        await update.message.reply_text(result["answer"])
    else:
        # Клиенту — сообщение что подключаем человека
        await update.message.reply_text(
            "Ваш вопрос требует внимания специалиста. "
            "Ответим в течение 2 часов рабочего времени."
        )
        # Команде — уведомление с полным контекстом
        escalation_text = (
            f"Эскалация от @{username} (id: {user_id})\n\n"
            f"Вопрос: {user_message}\n\n"
            f"Причина эскалации: {result['answer']}"
        )
        await bot.send_message(
            chat_id=SUPPORT_TEAM_CHAT,
            text=escalation_text
        )


def run_bot():
    application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
    application.add_handler(
        MessageHandler(filters.TEXT & ~filters.COMMAND, handle_support_message)
    )
    application.run_polling()


if __name__ == "__main__":
    run_bot()

Шаг 5. Метрики

Без метрик не знаешь работает ли система. Четыре числа которые нужно отслеживать:

Метрика Что измеряет Цель
First Response Time Время до первого ответа < 1 мин (AI), < 4ч (человек)
Deflection Rate % тикетов решённых без человека > 75%
Resolution Rate % тикетов закрытых с первого ответа > 60%
CSAT Score Оценка клиента 1-5 > 4.2
python
def generate_support_report(metrics_file: str = "support-metrics.jsonl") -> dict:
    """Считает основные метрики за период"""
    entries = []
    with open(metrics_file) as f:
        for line in f:
            entries.append(json.loads(line))

    if not entries:
        return {"error": "нет данных"}

    total = len(entries)
    escalated = sum(1 for e in entries if e["escalated"])
    deflection_rate = round((total - escalated) / total * 100, 1)
    avg_response_time = round(
        sum(e["response_time_sec"] for e in entries) / total, 2
    )

    return {
        "total_tickets": total,
        "escalated": escalated,
        "auto_resolved": total - escalated,
        "deflection_rate_pct": deflection_rate,
        "avg_response_time_sec": avg_response_time
    }


# Пример вывода:
# {
#   "total_tickets": 150,
#   "escalated": 28,
#   "auto_resolved": 122,
#   "deflection_rate_pct": 81.3,
#   "avg_response_time_sec": 2.4
# }

Шаг 6. Обновление базы знаний

База знаний устаревает. Новые тарифы, новые фичи, изменились правила возвратов. Простой процесс обновления:

  1. Редактируешь MD файл в knowledge-base/
  2. Перезапускаешь сервер (или добавляешь hot-reload)
  3. Claude мгновенно отвечает по новым данным

Это главное преимущество MD-файлов перед векторными базами: обновление за 30 секунд, не нужна переиндексация. Подход работает, пока база знаний помещается в контекст модели. Если база большая, а вопросов много, включай prompt caching (урок Prompt Caching и Batch API): повторяющаяся часть промпта обходится дешевле.


Инструменты и ресурсы

Инструмент Для чего Цена
Intercom Основная тикет-система (enterprise) Платно, тарифы на сайте
Crisp Альтернатива Intercom (проще и дешевле) Тарифы на сайте
Telegram Bot API Бесплатный канал поддержки Бесплатно
Flask Webhook сервер для интеграций Бесплатно
Python-telegram-bot Telegram бот библиотека Бесплатно
Claude Sonnet Основная модель (баланс цена/качество) Зависит от размера базы знаний и ответа; Актуальное сейчас

Стек минимального MVP:

  • Python 3.11+
  • anthropic — SDK Claude
  • python-telegram-bot — если Telegram
  • flask — если webhook интеграция
  • MD файлы — база знаний

Build-to-Sell

Это можно оформить как услугу для небольших компаний, у которых поддержкой занимаются 1-3 человека. Найдутся ли клиенты и сколько они заплатят, зависит от ниши, рынка и твоей работы. Гарантий нет.

Экономика для клиента:

Считай вместе с клиентом по его данным. Часы в день на типовые вопросы × ставка сотрудника = стоимость этих вопросов за день. AI освобождает только часть этих часов: сложные тикеты и проверка ответов остаются людям. Срок окупаемости = цена услуги ÷ реальная экономия в день. Пример с вымышленными числами: 4 часа × $15 = $60 в день до внедрения, а если AI закрывает половину вопросов, экономия около $30 в день.

Структура предложения:

Цены назначай по своим затратам и ценности для клиента, подробнее в уроке Как назначить цену.

Вариант Что включает
Setup Разработка + настройка + первая база знаний
Ежемесячное сопровождение Хостинг + мониторинг + обновления базы знаний
Enterprise Custom интеграция + обучение команды

Время разработки MVP: 4-6 часов (Telegram бот + Claude + MD FAQ).

Что продаёшь клиенту:

  • Telegram-бот или интеграция с Intercom/Crisp
  • Настроенная база знаний из их FAQ
  • Дашборд метрик (Deflection Rate, время ответа)
  • Документация по обновлению базы знаний

Ключевые выводы

  • AI Customer Support — не замена команды. Усиление: типовое берёт на себя AI, сложное остаётся людям
  • 80/15/5 — ориентир, а не закон: большая часть автоответ, меньшая AI-драфт для агента, остальное эскалация; пропорции у каждой компании свои
  • RAG с MD файлами — простейший путь к точным ответам. Обновление базы знаний за 30 секунд
  • Три метрики которые важны клиенту: Deflection Rate (> 75%), First Response Time (< 1 мин), CSAT (> 4.2)
  • Минимальный MVP собирается за несколько часов. Как услугу его можно оформить из трёх частей: setup, ежемесячное сопровождение и интеграции под заказ

Следующий урок

→ Call Support AI — Vapi + Bland.ai, голосовые звонки в поддержке

Разбираем следующий уровень: не текстовые тикеты, а голосовые звонки. Как AI принимает звонок, отвечает по базе знаний и передаёт сложные случаи человеку.

Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс