Інтеграція AI чат-бота (ChatGPT/Claude)
Інтеграція AI чат-бота — це не просто «проксі до OpenAI API». Завдання включає управління контекстом розмови, стримінг відповідей для нормального UX, систему промптів, обробку граничних випадків та контроль витрат на токени.
Вибір провайдера
| Провайдер | Моделі | Контекст | Сильні сторони |
|---|---|---|---|
| OpenAI | GPT-4o, GPT-4o-mini, o1 | 128K | Широка екосистема, function calling |
| Anthropic | Claude 3.5 Sonnet, Claude 3 Opus | 200K | Довгий контекст, точність інструкцій |
| Gemini 1.5 Pro/Flash | 1M | Найбільший контекст | |
| Mistral | Mistral Large, Mistral 7B | 32K | Self-hosted варіант |
Для типового вебсайтового чат-бота (підтримка, FAQ, консультант) — GPT-4o-mini або Claude 3.5 Haiku достатні за якістю та значно дешевші за флагмани.
Серверний проксі: навіщо потрібен
API-ключі ніколи не йдуть у браузер. Серверний ендпоінт необхідний для:
- Авторизації (тільки залоговані користувачі)
- Rate limiting (не більше X повідомлень на день)
- Логування діалогів
- Додавання системного промпту (користувач не бачить)
- Контролю витрат
// api/chat.js (Next.js Route Handler)
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const SYSTEM_PROMPT = `Ви асистент служби підтримки магазину "Техніка Pro".
Відповідайте тільки на запитання про товари, доставку та повернення.
Якщо запитання не за темою — ввічливо перенаправте до оператора.
Відповідайте тією ж мовою, що й користувач.`;
export async function POST(request) {
const session = await getSession(request);
if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 });
const { messages } = await request.json();
// Rate limiting
const count = await redis.incr(`chat:${session.userId}:${today()}`);
if (count > 50) return Response.json({ error: 'Limit reached' }, { status: 429 });
// Обмежуємо історію останніми 10 повідомленнями
const recentMessages = messages.slice(-10);
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
stream: true,
messages: [
{ role: 'system', content: SYSTEM_PROMPT },
...recentMessages,
],
max_tokens: 500,
temperature: 0.3, // Нижче = більш передбачувана відповідь
});
return new Response(stream.toReadableStream());
}
Стримінг відповідей на клієнті
Стримінг критичний для UX: користувач бачить відповідь по мірі генерації, не чекаючи 3–5 секунд:
async function sendMessage(userMessage) {
setMessages(prev => [...prev, { role: 'user', content: userMessage }]);
setIsStreaming(true);
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: [...messages, { role: 'user', content: userMessage }] }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let assistantMessage = '';
// Додаємо порожнє повідомлення асистента
setMessages(prev => [...prev, { role: 'assistant', content: '' }]);
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// OpenAI streaming format: data: {"choices":[{"delta":{"content":"..."}}]}
const lines = chunk.split('\n').filter(l => l.startsWith('data: '));
for (const line of lines) {
if (line === 'data: [DONE]') break;
const json = JSON.parse(line.slice(6));
const delta = json.choices[0]?.delta?.content || '';
assistantMessage += delta;
// Оновлюємо останнє повідомлення
setMessages(prev => [
...prev.slice(0, -1),
{ role: 'assistant', content: assistantMessage },
]);
}
}
setIsStreaming(false);
}
Управління контекстом розмови
Моделі мають контекстне вікно. При довгих діалогах потрібна стратегія:
Ковзне вікно — просто останні N повідомлень:
const contextMessages = messages.slice(-10);
Summarization — стиснення старої частини діалогу:
async function compressHistory(messages) {
if (messages.length <= 10) return messages;
const toCompress = messages.slice(0, -6);
const recent = messages.slice(-6);
const summary = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'user',
content: `Коротко підсумуй цю розмову:\n${toCompress.map(m => `${m.role}: ${m.content}`).join('\n')}`,
},
],
max_tokens: 200,
});
return [
{ role: 'system', content: `Попередній підсумок розмови: ${summary.choices[0].message.content}` },
...recent,
];
}
Функції та інструменти (Function Calling)
Чат-бот може викликати функції — перевірити статус замовлення, шукати товари, записати на консультацію:
const tools = [
{
type: 'function',
function: {
name: 'get_order_status',
description: 'Отримати статус замовлення за номером',
parameters: {
type: 'object',
properties: {
order_number: { type: 'string', description: 'Номер замовлення' },
},
required: ['order_number'],
},
},
},
{
type: 'function',
function: {
name: 'search_products',
description: 'Пошук товарів за запитом',
parameters: {
type: 'object',
properties: {
query: { type: 'string' },
max_price: { type: 'number' },
},
required: ['query'],
},
},
},
];
// Обробка виклику функції
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages,
tools,
tool_choice: 'auto',
});
const message = response.choices[0].message;
if (message.tool_calls) {
const toolResults = await Promise.all(
message.tool_calls.map(async (call) => {
const result = await executeFunction(call.function.name, JSON.parse(call.function.arguments));
return {
role: 'tool',
tool_call_id: call.id,
content: JSON.stringify(result),
};
})
);
// Відправляємо результати назад для фінальної відповіді
const finalResponse = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [...messages, message, ...toolResults],
});
}
Терміни
- Базовий чат-бот з системним промптом та стримінгом — 2–3 дні
- З function calling (замовлення, пошук, запис) — плюс 2–3 дні
- Віджет з історією діалогів, захопленням лідів, handoff до оператора — 5–7 днів
- Мультимовний бот з маршрутизацією за намірами — плюс 2–3 дні







