Ми створимо чат-бота, який здатен розуміти ваше резюме або документи і відповідати на запитання, використовуючи LLM OpenAI та LangChain для ефективного управління процесом запитів і відповідей. Чат-бот також буде мати можливість взаємодіяти через Flask API та WebSocket для реального часу, а також буде розгорнутий на Google Cloud Run.
Архітектура
Для чіткості архітектури була спільно розроблена діаграма з ChatGPT (OpenAI).
Чому ми обрали LangChain, а не LlamaIndex
LlamaIndex — це потужний фреймворк для роботи з LLM додатками, що підтримують як структуровані, так і неструктуровані дані. Проте, для цього проєкту ми обрали LangChain з кількох причин:
-
Тісний контроль за запитами: LangChain дозволяє створювати налаштовані шаблони запитів, які дозволяють пріоритизувати професійний досвід, а також контролювати тон відповіді (наприклад, відхилення неприпустимих запитів).
-
Краще управління розрізами: Завдяки LangChain і його RecursiveCharacterTextSplitter ми можемо точно розділяти резюме на частини, що допомагає з покращенням якості пошуку через FAISS.
-
Інтеграція з WebSocket: LangChain добре інтегрується з Flask і WebSocket, що забезпечує зручну роботу з реальним часом через сокети.
-
Легкість і локальність: LangChain дозволяє створити простий локальний пайплайн, використовуючи тільки необхідні компоненти: завантажувачі документів, FAISS, OpenAI embeddings і LangChain для виведення.
Крок 1: Налаштування проєкту локально
Передумови:
- Встановлений Python 3.11
- Налаштований Google Cloud CLI
- API-ключ OpenAI (отримати на https://platform.openai.com/account/api-keys)
- Встановлений Docker для розгортання
Структура проєкту виглядає так:
context-chatbot/
├── app.py
├── langchain_pipeline.py
├── requirements.txt
├── Dockerfile
├── yourContenttofeed/
└── templates/
└── hello.html
Крок 2: Встановлення залежностей
У файлі requirements.txt:
Flask==3.1.0
flask-sock==0.7.0
flask-socketio==5.3.6
python-dotenv==1.0.1
openai==1.64.0
langchain==0.3.19
langchain-openai==0.3.7
langchain-community==0.3.18
langchain-text-splitters==0.3.6
faiss-cpu==1.10.0
unstructured==0.16.23
python-docx==1.1.2
beautifulsoup4==4.13.3
lxml==5.3.1
gunicorn==23.0.0
eventlet
gevent
gevent-websocket
І встановлюємо залежності:
python3.11 -m venv venv
source venv/bin/activate # Для Windows: venv\Scripts\activate
pip install -r requirements.txt
Крок 3: Створення пайплайну LangChain для Vivan
1. Завантаження змінних середовища
loaddotenv()
OPENAIAPIKEY = os.getenv("OPENAIAPI_KEY")
2. Завантаження та попередня обробка документів з ./htmlfiles
alldocuments = loadhtmlanddocxfiles("htmlfiles/")
splitdocs = splitdocumentsintochunks(alldocuments)
3. Перетворення частин на векторні вбудовування за допомогою OpenAI + FAISS
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.fromdocuments(splitdocs, embeddings)
4. Налаштування власних LangChain шаблонів
mapprompt = PromptTemplate(inputvariables=["context", "question"], template=MAPPROMPTTEMPLATE)
combineprompt = PromptTemplate(inputvariables=["summaries", "question"], template=COMBINEPROMPTTEMPLATE)
5. Створення ланцюга map-reduce для QA
mapchain = LLMChain(llm=OpenAI(temperature=0.7), prompt=mapprompt)
reducechain = StuffDocumentsChain(llmchain=LLMChain(llm=OpenAI(), prompt=combineprompt), documentvariable_name="summaries")
qachain = MapReduceDocumentsChain(
llmchain=mapchain,
reducedocumentschain=reducechain,
documentvariablename="context"
)
6. Функція для обробки запиту
def getanswer(query):
relevantdocs = vectorstore.similaritysearch(query)
return qachain.invoke({"inputdocuments": relevantdocs, "question": query})["output_text"]
Огляд того, що це робить:
- Читає файли .html та .docx з папки
- Розділяє їх на частини контексту
- Вбудовує і зберігає їх у FAISS
- Використовує власні шаблони LangChain для:
- Прив'язки кожної частини до відповіді
- Об'єднання кількох відповідей в одну високу якість
Крок 4: Створення Flask + WebSocket чат-бота
import os
from flask import Flask, rendertemplate, jsonify
from flasksock import Sock
from flasksocketio import SocketIO
from langchainpipeline import get_answer # Власна функція LangChain
def createapp():
# Ініціалізація Flask і WebSocket серверів
app = Flask(name)
socketio = SocketIO(app, corsallowedorigins="*", asyncmode="eventlet")
sock = Sock(app)
# --- Базові маршрути ---
@app.route('/')
def home():
return render_template('chat.html') # Завантажуємо інтерфейс чат-бота Vivan
@app.route('/hello')
def hello():
return render_template('hello.html') # Опціональна сторінка привітання
@app.route('/api/data', methods=['GET'])
def get_data():
return jsonify({'message': 'Sample API data', 'status': 'success'})
# --- Socket.IO події ---
@socketio.on("connect")
def handle_connect():
print("[INFO] Socket.IO клієнт підключений")
@socketio.on("disconnect")
def handle_disconnect():
print("[INFO] Socket.IO клієнт відключений")
@socketio.on("message")
def handle_message(message):
print(f"[INFO] Socket.IO повідомлення: {message}")
socketio.send("Повідомлення отримано")
# --- Необроблений WebSocket маршрут для STOMP клієнтів ---
@sock.route('/ws/stomp')
def stomp(ws):
print("[INFO] STOMP WebSocket підключено")
try:
while True:
message = ws.receive()
if not message:
break
if message.startswith("CONNECT"):
ws.send("CONNECTED\nversion:1.2\n\n\0")
else:
query = message.strip()
answer = get_answer(query) # LangChain Q&A
ws.send(answer)
except Exception as e:
print(f"[ERROR] WebSocket помилка: {e}")
return app, socketio
Запускаємо додаток
app, socketio = create_app()
if name == "main":
port = int(os.environ.get("PORT", 8080))
socketio.run(app, host="0.0.0.0", port=port)
Ключові концепції:
- Використовує flask-sock для підтримки WebSocket (/ws/stomp)
- Використовує flask-socketio для клієнтів на Socket.IO
- Маршрути / та /hello відображають HTML інтерфейси (наприклад, chat.html)
- Модульна функція get_answer() обробляє всю логіку LangChain
Ви, можливо, запитаєте:
“Чому Flask для сервера та чому порт 8080 замість стандартного 5000?”
🔥 Чому Flask?
Flask — це мінімалістичний веб-фреймворк Python, який дуже легко почати використовувати, особливо для додатків, орієнтованих на API, як цей чат-бот. Ось чому я вибрав його:
- 🧩 Легкість та розширюваність — додаєте лише те, що вам потрібно.
- Ідеально підходить для LLM додатків — для відкриття REST та WebSocket ендпоінтів.
- 🛠️ Чудово працює з Gunicorn і Eventlet — спрощує розгортання в продакшн.
- ✅ Дружній для початківців — проста документація і легке розгортання.
Тому навіть із такими великими фреймворками, як FastAPI чи Django, Flask є ідеальним вибором для чат-бота без складних ORM чи маршрутизації.
Чому порт 8080?
Google Cloud Run очікує, що ваш додаток буде слухати на порту 8080, а не на стандартному Flask порту 5000. Тому ми використовуємо:
socketio.run(app, host="0.0.0.0", port=8080)
І також відкриваємо його в Docker:
EXPOSE 8080
Крок 5: Dockerize ваш додаток:
Створіть Dockerfile:
FROM python:3.11-slim
ENV
FLASKRUNHOST=0.0.0.0
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt && \
python -m nltk.downloader -d /usr/local/share/nltk_data punkt
COPY . .
EXPOSE 8080
CMD ["gunicorn", "-k", "eventlet", "-w", "1", "-b", "0.0.0.0:8080", "app:app"]
Пояснення покроково:
- Використовуємо легковажний офіційний образ Python
- Завантажуємо punkt tokenizer для розділення тексту
- Встановлюємо залежності з requirements.txt
- Використовуємо Gunicorn для запуску Flask
Крок 6: Розгортання на Google Cloud Run:
Після того, як ви створили чат-бота, можна розгорнути його в хмарі. Процес виглядає так:
Перекладено з: 🧠 How to Build a Context-Aware Chatbot Using LangChain, Flask & OpenAI — and Deploy it on Google Cloud Run