Разработка автономной AI-системы ведения переписки с клиентами

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка автономной AI-системы ведения переписки с клиентами
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    901
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1119
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    853

Разработка автономной AI-системы коммуникации с клиентами

Автономная система коммуникации управляет полным циклом диалога с клиентом: инициирует коммуникацию по триггерам, поддерживает многоходовые разговоры с сохранением контекста, адаптирует тон под клиента, выполняет действия (бронирование, оплата, изменение заказа) внутри диалога и корректно передаёт разговор оператору при необходимости.

Отличие от FAQ-бота: система понимает intent, управляет состоянием диалога, помнит историю взаимодействий с клиентом и способна выполнять многошаговые сценарии.

Архитектура диалоговой системы

from langgraph.graph import StateGraph, END
from langgraph.checkpoint.postgres import PostgresSaver
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from typing import TypedDict, Annotated, Optional
import operator

class ConversationState(TypedDict):
    # Идентификация
    session_id: str
    customer_id: str
    channel: str              # "whatsapp", "telegram", "web_chat", "sms"

    # История диалога
    messages: Annotated[list, operator.add]

    # Профиль клиента
    customer_profile: Optional[dict]
    customer_tier: str        # "standard", "premium", "vip"
    preferred_language: str   # "ru", "en"

    # Состояние диалога
    current_intent: Optional[str]
    dialog_context: dict      # Накопленные данные текущего сценария
    pending_confirmations: list[dict]  # Ожидают подтверждения клиента

    # Выполненные действия
    completed_actions: Annotated[list, operator.add]

    # Управление передачей
    escalated: bool
    escalation_reason: Optional[str]
    escalation_priority: Optional[str]

Контекстный менеджер клиента

class CustomerContextManager:
    """Загружает и обновляет профиль клиента"""

    async def load_context(self, customer_id: str) -> dict:
        profile_task = crm.get_customer(customer_id)
        orders_task = orders_db.get_recent(customer_id, limit=10)
        preferences_task = preference_store.get(customer_id)
        loyalty_task = loyalty_service.get_status(customer_id)

        results = await asyncio.gather(
            profile_task, orders_task, preferences_task, loyalty_task,
            return_exceptions=True,
        )

        return {
            "profile": results[0] if not isinstance(results[0], Exception) else {},
            "recent_orders": results[1] if not isinstance(results[1], Exception) else [],
            "preferences": results[2] if not isinstance(results[2], Exception) else {},
            "loyalty": results[3] if not isinstance(results[3], Exception) else {},
        }

    def build_system_context(self, customer_context: dict) -> str:
        profile = customer_context.get("profile", {})
        loyalty = customer_context.get("loyalty", {})

        context_parts = [
            f"Клиент: {profile.get('name', 'клиент')}",
            f"Статус: {loyalty.get('tier', 'standard')}",
            f"Язык: {profile.get('preferred_language', 'ru')}",
        ]

        orders = customer_context.get("recent_orders", [])
        if orders:
            last_order = orders[0]
            context_parts.append(
                f"Последний заказ: #{last_order['id']} от {last_order['date']}, "
                f"статус: {last_order['status']}"
            )

        return "\n".join(context_parts)

Система обнаружения намерений и управления сценариями

from pydantic import BaseModel
from typing import Literal

class IntentDetection(BaseModel):
    intent: Literal[
        "order_status", "order_change", "order_cancel",
        "delivery_issue", "return_request", "payment_issue",
        "product_question", "complaint", "compliment",
        "account_management", "general_question", "farewell",
    ]
    confidence: float
    entities: dict           # Извлечённые сущности (номер заказа, дата и т.д.)
    requires_action: bool    # Нужно выполнить действие в системе
    needs_clarification: bool  # Нужны дополнительные данные от клиента

SYSTEM_PROMPT_TEMPLATE = """Ты — AI-ассистент клиентской службы компании "{company_name}".

Информация о клиенте:
{customer_context}

Правила общения:
- Обращайся к клиенту по имени
- Тон: {tone} (зависит от статуса клиента)
- Язык: {language}
- Никогда не обещай то, что не можешь выполнить
- При ошибках — признавай и предлагай решение
- Не раскрывай внутренние системы и базы данных

Доступные действия:
- Статус заказа
- Изменение адреса доставки (если заказ не передан курьеру)
- Инициирование возврата
- Перенос даты доставки
- Передача оператору

Если не знаешь ответа — честно скажи об этом и предложи передать специалисту."""

def build_system_prompt(state: ConversationState) -> str:
    tone_map = {
        "standard": "профессиональный, дружелюбный",
        "premium": "персональный, внимательный",
        "vip": "эксклюзивный, максимально персонализированный",
    }

    return SYSTEM_PROMPT_TEMPLATE.format(
        company_name="RetailCo",
        customer_context=state.get("customer_profile", {}).get("context", ""),
        tone=tone_map.get(state["customer_tier"], "профессиональный"),
        language=state["preferred_language"],
    )

Исполнение действий внутри диалога

async def execute_dialog_action(action_name: str, params: dict, state: ConversationState) -> dict:
    """Выполняет действие и возвращает результат для включения в диалог"""

    action_handlers = {
        "get_order_status": lambda p: orders_api.get_status(p["order_id"]),
        "change_delivery_address": lambda p: orders_api.update_address(
            p["order_id"], p["new_address"]
        ),
        "initiate_return": lambda p: returns_service.create_request(
            order_id=p["order_id"],
            reason=p["reason"],
            customer_id=state["customer_id"],
        ),
        "reschedule_delivery": lambda p: delivery_api.reschedule(
            p["order_id"], p["new_date"]
        ),
    }

    handler = action_handlers.get(action_name)
    if not handler:
        return {"success": False, "error": f"Неизвестное действие: {action_name}"}

    try:
        result = await handler(params)
        return {"success": True, "data": result}
    except Exception as e:
        return {"success": False, "error": str(e)}

Управление подтверждениями (Confirmation Flow)

def needs_confirmation(action_name: str) -> bool:
    """Действия, требующие подтверждения клиента"""
    return action_name in {"cancel_order", "initiate_return", "change_payment_method"}

async def handle_pending_confirmation(state: ConversationState) -> ConversationState:
    """Обрабатывает ответ клиента на запрос подтверждения"""

    if not state["pending_confirmations"]:
        return state

    last_message = state["messages"][-1].content.lower()
    confirmation_words = {"да", "yes", "подтверждаю", "согласен", "ок", "ok"}
    rejection_words = {"нет", "no", "отмена", "отказываюсь", "стоп"}

    if any(word in last_message for word in confirmation_words):
        # Выполняем ожидающее действие
        pending = state["pending_confirmations"][0]
        result = await execute_dialog_action(pending["action"], pending["params"], state)
        return {
            **state,
            "pending_confirmations": state["pending_confirmations"][1:],
            "completed_actions": [{"action": pending["action"], "result": result}],
        }
    elif any(word in last_message for word in rejection_words):
        return {
            **state,
            "pending_confirmations": [],
            "messages": [AIMessage("Хорошо, действие отменено. Чем ещё могу помочь?")],
        }

    # Неоднозначный ответ — переспрашиваем
    return {
        **state,
        "messages": [AIMessage("Пожалуйста, ответьте 'да' для подтверждения или 'нет' для отмены.")],
    }

Триггерная коммуникация

class OutboundCommunicationEngine:
    """Инициирует исходящую коммуникацию по бизнес-триггерам"""

    TRIGGER_TEMPLATES = {
        "order_shipped": {
            "message": "Ваш заказ #{order_id} отправлен! Трекинг: {tracking_url}. Ожидаемая доставка: {eta}.",
            "channel_priority": ["sms", "whatsapp", "email"],
        },
        "delivery_delay": {
            "message": "Сообщаем о задержке доставки заказа #{order_id}. Новая дата: {new_eta}. Извините за неудобства.",
            "channel_priority": ["whatsapp", "telegram", "sms"],
        },
        "return_approved": {
            "message": "Ваш возврат по заказу #{order_id} одобрен. Средства вернутся в течение {refund_days} дней.",
            "channel_priority": ["email", "whatsapp"],
        },
    }

    async def send_trigger_message(self, customer_id: str, trigger: str, params: dict):
        template_config = self.TRIGGER_TEMPLATES.get(trigger)
        if not template_config:
            return

        # Персонализируем сообщение через LLM
        customer = await crm.get_customer(customer_id)
        base_message = template_config["message"].format(**params)

        if customer.get("tier") in ("premium", "vip"):
            # VIP получает более персонализированное сообщение
            personalized = await personalize_message(base_message, customer)
        else:
            personalized = base_message

        channel = await self.get_preferred_channel(customer_id, template_config["channel_priority"])
        await channel_dispatcher.send(customer_id, channel, personalized)

Практический кейс: телеком-оператор, 18 000 диалогов/день

Компания: региональный телеком с 850 000 абонентов, контакт-центр 120 операторов.

Реализованные сценарии:

  • Проверка баланса и трафика
  • Подключение/отключение услуг
  • Разблокировка номера (верификация по кодовому слову)
  • Диагностика технических проблем (по алгоритму)
  • Обработка жалоб на качество связи (создание тикета + компенсация автоматически по правилам)
  • Прием платежей через dialog (redirect к платёжной форме)

Результаты:

  • Автономное закрытие диалогов: 67%
  • Среднее время ответа: 4.5 мин → 8 секунд
  • CSAT (Customer Satisfaction Score): 3.8/5.0 → 4.2/5.0 (неожиданный рост за счёт скорости)
  • Операторы сфокусировались на жалобах и сложных случаях
  • NPS: +7 баллов за квартал

Сложности: настройка тональности для angry customers (4 недели итераций). VIP-клиенты ожидают «живого» общения — добавлена опция немедленной передачи человеку.

Сроки

  • Архитектура и базовый диалоговый движок: 2–3 недели
  • Реализация сценариев (каждый ~3–5 дней): от 3 недель
  • Интеграция с каналами коммуникации: 1–2 недели
  • Интеграция с CRM/ERP/API: 2–3 недели
  • Обучение, тестирование, запуск: 2–3 недели
  • Итого: 10–14 недель