Як побудувати автономну AI-систему діалогів із клієнтами
Клієнти скаржаться на довге очікування відповіді, а FAQ-боти втрачають контекст уже на другому повідомленні. Традиційні рішення не можуть виконати дію — перенаправити платіж або змінити замовлення. Ми розробляємо автономні AI-системи, які ведуть повноцінний діалог, приймають рішення та здійснюють транзакції. Наша система керує повним циклом: ініціює комунікацію за тригерами, підтримує багатоходові розмови, адаптує тон під клієнта, виконує дії всередині діалогу та коректно передає розмову оператору при необхідності. Це не FAQ-бот — це інтелектуальний асистент, що розуміє наміри та зберігає історію. В основі лежить Large language model, яка обробляє природну мову та генерує відповіді.
Як автономна AI-система вирішує проблеми клієнтської переписки?
Втрата контексту. Клієнт повідомляє номер замовлення, потім уточнює дату, потім змінює адресу — звичайний бот не пов'язує ці повідомлення. Наша система зберігає історію в графі станів і будує профіль із CRM, замовлень та лояльності. Неможливість виконати дію зникає: ми надаємо системі доступ до API та виконуємо дії всередині діалогу з підтвердженням від клієнта. Неадаптивна тональність більше не проблема — динамічно підбираємо тон залежно від статусу (standard, premium, VIP). Високе навантаження на контакт-центр знижується: автономна система бере на себе 70% діалогів, залишаючи складні випадки людям.
Як ми будуємо діалогову систему: стек та конфігурації
Використовуємо перевірений стек: LangGraph для управління станами, OpenAI GPT-4o для генерації, PostgreSQL з pgvector для зберігання контексту та asyncio для паралельного завантаження профілю. Ключовий елемент — граф станів, де кожен вузол відповідає за частину діалогу. Ось покрокова інструкція.
Крок 1: Стан діалогу
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]
Крок 2: Контекстний менеджер клієнта
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']}, статус: {last_order['status']}"
)
return "\n".join(context_parts)
Крок 3: Виявлення намірів та динамічний промпт
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"],
)
Крок 4: Виконання дій та управління підтвердженнями
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)}
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("Будь ласка, дайте відповідь 'так' для підтвердження або 'ні' для скасування.")],
}
Крок 5: Тригерна комунікація
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
customer = await crm.get_customer(customer_id)
base_message = template_config["message"].format(**params)
if customer.get("tier") in ("premium", "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)
Деталі реалізації графа станів
Граф реалізований за допомогою LangGraph. Кожен вузол — це функція, яка приймає стан і повертає оновлений стан. Переходи між вузлами визначаються умовами на основі намірів та підтверджень. Для відмовостійкості використовується PostgreSQL з чекпоінтами, що дозволяє відновлювати діалог після збою.Яких результатів дає впровадження автономної AI-системи?
З нашої практики: впровадили систему для регіонального телекому з 850 000 абонентів та 120 операторами. Реалізували сценарії перевірки балансу, підключення послуг, розблокування номера, діагностики та обробки скарг. Результати: автономне закриття 67% діалогів, середній час відповіді знизився з 4,5 хвилин до 8 секунд, CSAT виріс з 3,8 до 4,2. Оператори зосередилися на складних випадках, NPS збільшився на 7 пунктів. Складність: налаштування тональності для angry customers зайняло 4 тижні, VIP-клієнти отримали опцію негайної передачі людині. Система окупається в середньому за 6 місяців за рахунок скорочення штату операторів.
Що входить у роботу
- Аудит поточних сценаріїв та точок інтеграції
- Проектування архітектури діалогового двигуна
- Реалізація базових сценаріїв (5–10 штук)
- Інтеграція з каналами зв'язку та CRM/ERP
- Налаштування моделей LLM та векторизація контенту
- Навчання системи на історії діалогів
- Тестування та запуск у продакшн
- Документація та навчання вашої команди
- Підтримка на етапі стабілізації
| Етап | Тривалість |
|---|---|
| Архітектура та базовий двигун | 2–3 тижні |
| Реалізація сценаріїв (за кожен) | 3–5 днів |
| Інтеграція з каналами | 1–2 тижні |
| Інтеграція з CRM/API | 2–3 тижні |
| Навчання, тестування, запуск | 2–3 тижні |
| Разом | 10–14 тижнів |
Вартість розраховується індивідуально. Оцінимо ваш проєкт за 1–2 дні. Замовте розробку під ключ — гарантуємо якість та сертифікованих інженерів з досвідом роботи з LLM.
Порівняння автономної AI-системи та FAQ-бота
Автономна система на базі LLM вирішує завдання, які не під силу простому боту. Вона розуміє наміри, запам'ятовує контекст та виконує дії. Порівняйте самі:
| Критерій | FAQ-бот | Автономна AI-система |
|---|---|---|
| Розуміння контексту | Ні, кожен запит незалежний | Так, зберігає історію та профіль |
| Виконання дій | Ні, тільки посилання | Так, через API з підтвердженням |
| Адаптація тону | Однаковий для всіх | Залежить від статусу клієнта |
| Передача оператору | Тільки посилання | Плавна передача з історією |
| Навчання | Ручне | Автоматичне через анотації |
Наші системи протестовані на пікових навантаженнях до 18 000 діалогів на день. Сертифіковані рішення, повна документація та гарантія результату. Зв'яжіться з нами для консультації — оцінимо ваш проєкт і запропонуємо оптимальне рішення.







