Разбор

ИИ-агент квалифицирует лиды в amoCRM: горячие, тёплые, холодные — автоматически за 30 секунд

Менеджеры тратят одинаковое время на горячих и холодных лидов — и теряют горячих, пока возятся с холодными. Webhook amoCRM + Python + Claude оценивает каждый лид по BANT за 30 секунд и обновляет карточку до того, как менеджер откроет CRM.

• 7 мин чтения

Компания MIT провела исследование: если не позвонить лиду в течение первого часа после заявки — шансы квалифицировать его падают в 7 раз. Через 24 часа — в 60 раз. При этом большинство отделов продаж обрабатывают заявки в порядке очереди — горячий лид с бюджетом 5 млн ждёт того же времени, что и студент, который «просто интересуется».

30 сек
— столько нужно агенту, чтобы оценить лид по BANT, поставить тег и добавить примечание в amoCRM до того, как менеджер откроет карточку

Почему менеджеры теряют горячих лидов

Картина в большинстве B2B-отделов продаж выглядит одинаково: все входящие заявки падают в одну воронку и обрабатываются по очереди. Менеджер открывает CRM утром и видит 12 лидов. Он начинает с первого. Первый — холодный: студент сравнивает цены для курсовой. Второй — тёплый: компания изучает рынок, решение не скоро. Третий — горячий: директор хочет подписать договор до конца месяца и уже разговаривал с вашим конкурентом.

К третьему менеджер добирается через час.

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

Проблема не в менеджерах — они работают так, как им позволяет инструмент. Инструмент не умеет расставлять приоритеты автоматически.

🔥Горячий

Есть бюджет, ЛПР на связи, чёткая потребность, нужно быстро

🌤Тёплый

Интерес есть, но бюджет не утверждён или решение не скоро

❄️Холодный

Любопытство, нет бюджета, не тот человек или не та потребность

Типичное распределение в B2B: 15% горячих, 45% тёплых, 40% холодных. При этом горячие дают 70–80% выручки. Но обрабатываются — в произвольном порядке.

Как работает автоквалификация

Схема простая: новый лид попадает в amoCRM → CRM отправляет webhook на ваш сервер → Python принимает запрос → Claude получает данные лида и оценивает по BANT → Python обновляет карточку через amoCRM API: теги, примечание, статус.

📋amoCRMновый лид → webhook
🐍FastAPIпарсинг данных
🤖Claude SonnetBANT-оценка
amoCRM APIтеги + примечание

Всё происходит до того, как менеджер открыл CRM. Он видит карточку уже с тегом «горячий» и кратким объяснением почему. Менеджеру не нужно ничего изучать — нужно просто позвонить.

BANT в промпте: как объяснить Claude критерии

BANT — четыре критерия квалификации лида: Budget (бюджет), Authority (полномочия принимать решение), Need (потребность), Timeline (временные рамки). Чем больше галочек — тем горячее лид.

КритерийЧто проверяемСигналы в данных лида
BudgetЕсть деньги на покупкуУпомянул бюджет, UTM указывает на платный запрос, должность — директор/руководитель
AuthorityЛПР или влияет на решениеДолжность в форме, домен корпоративной почты, написал от имени компании
NeedЕсть конкретная проблемаОписал задачу в тексте, использовал профессиональные термины, пришёл по целевому запросу
TimelineНужно в ближайшее времяНаписал «срочно», «до конца месяца», «уже ищем», пришёл с горячего запроса

Claude получает данные лида в структурированном виде и промпт с чёткими инструкциями. Промпт — это не «оцени лида», а точные критерии с примерами:

📝 BANT-промпт для Claude
BANT_PROMPT = """Ты помощник по квалификации лидов. 
Проанализируй данные лида и оцени по критериям BANT.

КРИТЕРИИ ОЦЕНКИ:

Budget (Бюджет):
- Высокий: упомянул бюджет, должность директор/владелец/руководитель, B2B-сегмент
- Средний: корпоративная почта, пришёл с коммерческого запроса
- Низкий: частное лицо, нет упоминания бюджета, учебный/информационный запрос

Authority (Полномочия):
- Высокий: должность ЛПР в форме, пишет от имени компании, принимает решение
- Средний: не указал должность, но корпоративная почта
- Низкий: явно не ЛПР, «согласовываю с руководством», студент

Need (Потребность):
- Высокий: описал конкретную задачу с деталями, использует профессиональные термины
- Средний: общий интерес без конкретики
- Низкий: «просто интересуюсь», нет описания задачи

Timeline (Срочность):
- Высокий: «срочно», «до конца месяца», «уже выбираем», «переходим от конкурента»
- Средний: «планируем», «рассматриваем»
- Низкий: «когда-нибудь», «на будущее», нет указания срока

ДАННЫЕ ЛИДА:
{lead_data}

Верни JSON строго в таком формате:
{{
"status": "горячий" | "тёплый" | "холодный",
"score": {{
  "budget": "высокий" | "средний" | "низкий",
  "authority": "высокий" | "средний" | "низкий", 
  "need": "высокий" | "средний" | "низкий",
  "timeline": "высокий" | "средний" | "низкий"
}},
"reasoning": "2-3 предложения почему такой статус",
"next_action": "конкретное действие менеджера"
}}

Правило: если данных мало — ставь "тёплый", не "холодный". 
Лучше перепроверить тёплого, чем потерять горячего."""

Конкретный код: FastAPI webhook + Claude + amoCRM API

amoCRM отправляет webhook в формате application/x-www-form-urlencoded — не JSON. FastAPI читает тело через await request.form().

🐍 qualify_leads.py — pip install fastapi uvicorn anthropic httpx python-multipart
import json
import httpx
import anthropic
from fastapi import FastAPI, Request

app = FastAPI()

# Настройки
AMOCRM_DOMAIN = "yourcompany.amocrm.ru"
AMOCRM_TOKEN = "YOUR_ACCESS_TOKEN"      # OAuth 2.0 токен amoCRM
CLAUDE_API_KEY = "YOUR_CLAUDE_KEY"

AMO_HEADERS = {
  "Authorization": f"Bearer {AMOCRM_TOKEN}",
  "Content-Type": "application/json",
}

BANT_PROMPT = """Ты помощник по квалификации лидов.
Проанализируй данные лида и оцени по критериям BANT.
[... полный промпт из раздела выше ...]
Верни JSON строго в описанном формате."""


def parse_amo_webhook(form_data: dict) -> dict:
  """amoCRM шлёт bracket-нотацию: leads[add][0][id] = 12345"""
  lead = {}
  for key, value in form_data.items():
      # Берём первый добавленный лид
      if key.startswith("leads[add][0]["):
          field = key.replace("leads[add][0][", "").rstrip("]")
          lead[field] = value
  return lead


async def get_lead_details(lead_id: str) -> dict:
  """Получаем полные данные лида через amoCRM API v4."""
  async with httpx.AsyncClient() as client:
      # Лид с кастомными полями и контактами
      r = await client.get(
          f"https://{AMOCRM_DOMAIN}/api/v4/leads/{lead_id}",
          headers=AMO_HEADERS,
          params={"with": "contacts,custom_fields_values"},
      )
      r.raise_for_status()
      return r.json()


async def qualify_with_claude(lead_details: dict) -> dict:
  """Отправляем данные в Claude, получаем BANT-оценку."""
  # Собираем данные для анализа
  custom_fields = {
      cf["field_name"]: cf.get("values", [{}])[0].get("value", "")
      for cf in lead_details.get("custom_fields_values") or []
  }

  lead_data = {
      "name": lead_details.get("name", ""),
      "pipeline": lead_details.get("_embedded", {}).get("pipeline", {}).get("name", ""),
      "source": custom_fields.get("Источник", ""),
      "utm_source": custom_fields.get("UTM Source", ""),
      "utm_medium": custom_fields.get("UTM Medium", ""),
      "message": custom_fields.get("Сообщение", ""),
      "company": custom_fields.get("Компания", ""),
      "position": custom_fields.get("Должность", ""),
  }

  client = anthropic.Anthropic(api_key=CLAUDE_API_KEY)
  message = client.messages.create(
      model="claude-sonnet-4-6",
      max_tokens=512,
      messages=[{
          "role": "user",
          "content": BANT_PROMPT.replace("{lead_data}", json.dumps(lead_data, ensure_ascii=False, indent=2))
      }]
  )

  # Claude возвращает JSON — парсим
  response_text = message.content[0].text
  # Ищем JSON в ответе
  start = response_text.find("{")
  end = response_text.rfind("}") + 1
  return json.loads(response_text[start:end])


async def update_lead_in_amo(lead_id: str, qualification: dict):
  """Обновляем карточку лида: теги + примечание."""
  status = qualification["status"]
  reasoning = qualification.get("reasoning", "")
  next_action = qualification.get("next_action", "")

  async with httpx.AsyncClient() as client:
      # 1. Добавляем тег к лиду через PATCH /api/v4/leads/{id}
      tag_data = {
          "_embedded": {
              "tags": [{"name": f"квалификация:{status}"}]
          }
      }
      await client.patch(
          f"https://{AMOCRM_DOMAIN}/api/v4/leads/{lead_id}",
          headers=AMO_HEADERS,
          json=tag_data,
      )

      # 2. Добавляем примечание с объяснением
      note_text = (
          f"🤖 Автоквалификация: {status.upper()}

"
          f"BANT: B={qualification['score']['budget']} | "
          f"A={qualification['score']['authority']} | "
          f"N={qualification['score']['need']} | "
          f"T={qualification['score']['timeline']}

"
          f"Вывод: {reasoning}

"
          f"Следующий шаг: {next_action}"
      )
      note_data = {
          "note_type": "common",
          "params": {"text": note_text},
      }
      await client.post(
          f"https://{AMOCRM_DOMAIN}/api/v4/leads/{lead_id}/notes",
          headers=AMO_HEADERS,
          json=[note_data],
      )


@app.post("/webhook/amo-lead")
async def handle_new_lead(request: Request):
  """Принимаем webhook от amoCRM о новом лиде."""
  form_data = dict(await request.form())
  lead_basic = parse_amo_webhook(form_data)

  lead_id = lead_basic.get("id")
  if not lead_id:
      return {"status": "skipped", "reason": "no lead id"}

  # Полные данные, оценка, обновление карточки
  lead_details = await get_lead_details(lead_id)
  qualification = await qualify_with_claude(lead_details)
  await update_lead_in_amo(lead_id, qualification)

  return {"status": "ok", "lead_id": lead_id, "qualification": qualification["status"]}

# Запуск: uvicorn qualify_leads:app --host 0.0.0.0 --port 8000

Несколько моментов по коду:

amoCRM хранит кастомные поля по-разному в зависимости от типа — для текстовых values[0].value, для множественных список объектов. Стоит добавить проверки на None перед обращением к полям.

OAuth-токен amoCRM живёт 24 часа. Для продакшена нужно реализовать refresh через refresh_token — сохранить пару токенов в переменных окружения и обновлять автоматически при получении 401.

Хостинг: Railway.app или Render.com запускают FastAPI-приложение бесплатно. Нужен публичный HTTPS-эндпоинт — именно туда настраивается webhook в amoCRM.

Кейс: digital-агентство, 80 лидов в месяц

Digital-агентство из Москвы, специализация — контекстная реклама и SEO для B2B. 80 входящих лидов в месяц из разных источников: сайт, Яндекс.Директ, сарафан, партнёры.

До внедрения: два менеджера по продажам тратили суммарно 4 часа в день на первичную обработку лидов. Звонили всем подряд, пытаясь понять кто готов к сделке, а кто «просто посмотреть». Конверсия в договор — 8%.

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

После внедрения автоквалификации: каждый лид получает оценку за 30 секунд. Горячие — первыми в список. Менеджеры видят не просто очередь, а приоритизированную очередь с объяснением.

До автоквалификации
Время на квалификацию4 часа/день
Время до первого звонкадо 3 часов
Конверсия в договор8%
Затраты на квалификацию~20 000 ₽/мес
После внедрения
Время на квалификацию20 минут/день
Время до первого звонкадо 15 минут
Конверсия в договор13%
Затраты на квалификацию~1 500 ₽/мес

Конверсия выросла с 8% до 13%. Не за счёт новых лидов — за счёт того, что горячие лиды перестали ждать в очереди.

Проверь свой отдел продаж

Диагностика: теряете ли вы горячих лидов?

4 вопроса — узнайте потенциал автоквалификации для вашего отдела

Вопрос 1 из 4
Как менеджеры сейчас обрабатывают входящие лиды?
Вопрос 2 из 4
Через сколько времени после заявки менеджер делает первый звонок?
Вопрос 3 из 4
Сколько времени уходит на первичную квалификацию одного лида (до первого осмысленного разговора)?
Вопрос 4 из 4
Бывало ли что горячий лид ушёл к конкуренту пока ждал звонка?

Как запустить: пошагово

1
Получить OAuth-токен amoCRM

В amoCRM: Настройки → Интеграции → Создать интеграцию. Указать redirect URI (можно localhost для тестирования). Пройти OAuth и сохранить access_token + refresh_token. Токен живёт 24 часа, refresh — 3 месяца.

amocrm.ru → Настройки → Интеграции → + Добавить
2
Развернуть FastAPI-приложение

Нужен публичный HTTPS-эндпоинт. Самый быстрый вариант — Railway.app: подключить GitHub-репозиторий, добавить переменные окружения AMOCRM_TOKEN и CLAUDE_API_KEY. Деплой занимает 3–5 минут.

pip install fastapi uvicorn anthropic httpx python-multipart
3
Настроить webhook в amoCRM

Настройки → Интеграции → Webhooks → Добавить. URL: ваш эндпоинт + /webhook/amo-lead. Событие: «Добавление лида». Убедиться что amoCRM шлёт POST и получает 200 OK в ответ.

POST https://yourapp.railway.app/webhook/amo-lead
4
Настроить кастомные поля в форме

Чем больше данных о лиде — тем точнее оценка. Добавить поля «Должность», «Компания», «Сообщение» и передавать UTM-метки через скрытые поля формы. Агент сделает больше с полными данными.

Настройки → Поля → Лиды → + Добавить поле
5
Проверить первые 10 квалификаций вручную

После запуска сравнивать оценку агента с оценкой менеджера по первым лидам. Если агент систематически ошибается по какому-то критерию — скорректировать промпт. Обычно 2–3 итерации дают приемлемую точность.

uvicorn qualify_leads:app —reload (тест локально)

Что нельзя автоматизировать

Честно про ограничения. Агент хорош для первичной сортировки по косвенным признакам — но есть решения, которые он не принимает.

Финальное решение о сделке — всегда за человеком. Агент может ошибиться: написать «холодный» про лида, который просто коротко заполнил форму. Или «горячий» про конкурента, который мониторит ваши цены. Это инструмент первого фильтра, не замена опытного менеджера.

Переговоры и работа с возражениями — агент не может позвонить и выяснить настоящую причину обращения. Он работает только с тем, что написано.

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

Долгосрочное развитие лида — если лид сегодня холодный, это не значит «навсегда холодный». Агент не ведёт историю и не напоминает вернуться к лиду через три месяца. Это отдельная задача для CRM-автоматизации.


Агентство из кейса потратило на настройку три дня — включая итерации с промптом. Первый месяц отдел продаж сравнивал оценки агента со своими вручную. На втором месяце перестали — агент ошибался реже, чем они успевали проверить. Время на квалификацию упало с 4 часов до 20 минут в день. Горячие лиды теперь получают звонок в среднем через 8 минут после заявки.

Похожие кейсы

Источники

Источники

Часто задаваемые вопросы

Как ИИ-агент определяет, горячий лид или холодный?
Агент анализирует все доступные данные о лиде через Claude: источник трафика, UTM-метки, первое сообщение и ответы на форму. Затем оценивает по четырём критериям BANT — Budget (бюджет), Authority (полномочия), Need (потребность), Timeline (срочность). На основе этой оценки присваивает статус горячий/тёплый/холодный и записывает объяснение в примечание карточки.
Сколько стоит автоквалификация одного лида через Claude API?
Один вызов Claude Sonnet для анализа лида стоит примерно 0.3–0.8 рублей в зависимости от объёма данных. При потоке 80 лидов в месяц — около 24–64 рублей на API. Для сравнения: час работы менеджера по квалификации стоит 300–700 рублей.
Работает ли решение с Битрикс24?
Архитектура аналогичная: Битрикс24 умеет отправлять webhook на события добавления лида. Отличие в формате данных и API для обратного обновления карточки. Основная логика — Python + Claude — остаётся без изменений, меняется только парсинг входящего webhook и вызовы REST API Битрикс24.
Что делает агент, если данных о лиде мало?
Claude получает инструкцию на этот случай: при недостатке данных ставить статус тёплый (не холодный) и явно указывать в примечании, каких данных не хватает. Это страховка от ложно-негативной квалификации — лучше перепроверить тёплого, чем потерять горячего из-за неполной формы.
Нужно ли программирование для запуска агента?
Базовый Python на уровне 'запустить скрипт и поменять переменные'. Нужно уметь установить pip-зависимости, зарегистрировать webhook в amoCRM и развернуть FastAPI-приложение на сервере или в облаке. Весь код — в статье. Хостинг — Railway, Render или любой VPS с Python.
Может ли агент ошибиться в квалификации?
Да. Claude делает вывод на основе косвенных признаков — текста сообщения, UTM, источника. Он не умеет читать мысли и не знает контекста вашего бизнеса лучше вас. Поэтому финальное решение о переходе сделки в следующий этап всегда остаётся за менеджером. Агент экономит время первичной сортировки, но не заменяет суждение человека.
Обсуждение

    Пока без комментариев. Будьте первым.

    Войдите, чтобы отправить комментарий

    Вы сможете комментировать статьи, сохранять материалы

    или войдите по email

    Бесплатная диагностика · 30 минут · без обязательств

    Маркетинг работает, но продажи не растут?

    Отвечу на 3–5 вопросов о вашем бизнесе — и мы вместе разберём, где именно теряются клиенты и что с этим делать.

    Без продаж. Без навязчивых звонков.