Задача: AI бот для ответов на вопросы в рамках предоставленных документов.
Решение: RAG на базе Dify (как бекенд для создания базы знаний и бота) + OpenAI API (модель GPT 5.4) + Open WEBUI (для работы с ботом).
RAG (Retrieval-Augmented Generation) — архитектурный паттерн, при котором языковая модель перед генерацией ответа сначала извлекает релевантные данные из внешнего хранилища.

Нам понадобится
Dify — платформа для построения RAG-бота. Оркестрирует весь pipeline: chunking, embedding, retrieval, генерация ответа.
Open WebUI — веб-интерфейс для общения с моделями.
OpenAI API — используется для embedding (text-embedding-3-large) и генерации ответов (gpt-5.4).
Cohere API — используется только для reranker (rerank-multilingual-v3.0). Улучшает качество поиска, переранжируя найденные чанки перед передачей в LLM.
Настройка базы знаний
После деплоя и базовой настройки Dify приступаем к подготовке базы документов:
— все документы в PDF
— из всех документов нужно удалить содержание, обложки, оформление
Грузим документы с настройками:

Delimiter \n\n — режет текст по двойному переносу строки (между абзацами).
Maximum chunk length 2000 — максимальный размер одного чанка в символах.
Chunk overlap 200 — 200 символов из конца предыдущего чанка повторяются в начале следующего, чтобы не терять контекст на границах.
Replace consecutive spaces/newlines — убирает лишние пробелы и переносы, чистит текст перед индексацией.
Delete all URLs and email addresses — удаляет ссылки и email из текста.
High Quality — использует embedding модель для векторизации, обеспечивает точный семантический поиск.

text-embedding-3-large — модель для векторизации текста, преобразует чанки и запросы в векторы для семантического поиска.
Hybrid Search — одновременно выполняет векторный поиск (по смыслу) и полнотекстовый (по ключевым словам), затем объединяет результаты.
Rerank Model — после поиска переранжирует найденные чанки по релевантности к запросу.
rerank-multilingual-v3.0 — модель Cohere для переранжирования.
Top K 8 — возвращает 8 наиболее релевантных чанков для передачи в LLM.
Score Threshold 0.5 — отключён (toggle выключен), порог релевантности не применяется, возвращаются все Top K результаты.
Настройка бота

Создаем бота на основе шаблона «Knowledge Retrieval + ChatbotChatflow»
Knowledge Retrieval

INPUT+KNOW PROCESSING

Настройка модели

Системный промпт
{{#sys.dialogue_count#}}
{{#sys.conversation_id#}}
{{#sys.user_id#}}
{{#sys.app_id#}}
{{#sys.workflow_id#}}
{{#sys.workflow_run_id#}}
Ты умный помощник BIM менеджера. У тебя есть доступ к базе BIM документов — стандартам, регламентам, EIR, BEP.
Отвечай как опытный BIM эксперт:
- Помни историю разговора и отвечай в контексте беседы
- Используй предоставленный контекст из базы документов как основной источник
- Если контекст содержит релевантную информацию — отвечай на её основе подробно и структурированно
- Если контекст не содержит ответа — скажи "В базе документов эта информация не найдена" и предложи переформулировать вопрос
- Отвечай на том же языке что и вопрос
- Не упоминай названия конкретных компаний-заказчиков и их контакты
- Используй списки и заголовки для структурирования ответов
- При ответе указывай из какого документа взята информация
Контекст из базы документов:
{{#context#}}

Остальные настройки по умолчанию.
Все готово. Теперь можно публиковать бот и получать его API для Open WEBUI.
Open WEBUI

Код функции:
from pydantic import BaseModel
import requests
import json
class Pipe:
class Valves(BaseModel):
DIFY_API_KEY: str = ""
DIFY_BASE_URL: str = "https://rag.avro.pro/v1"
def __init__(self):
self.valves = self.Valves()
self.id = "avro-rag"
self.name = "AVRO RAG Bot"
self.conversation_ids = {} # хранит conversation_id per user
def pipe(self, body: dict, __user__: dict = {}):
messages = body.get("messages", [])
query = ""
for m in reversed(messages):
if m.get("role") == "user":
query = m.get("content", "")
break
user_id = __user__.get("id", "openwebui-user")
conversation_id = self.conversation_ids.get(user_id, "")
payload = {
"inputs": {},
"query": query,
"response_mode": "streaming",
"conversation_id": conversation_id,
"user": user_id,
}
headers = {
"Authorization": f"Bearer {self.valves.DIFY_API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(
f"{self.valves.DIFY_BASE_URL}/chat-messages",
headers=headers,
json=payload,
stream=True,
)
for line in response.iter_lines():
if line:
line = line.decode("utf-8")
if line.startswith("data: "):
data = line[6:]
if data == "[DONE]":
break
try:
chunk = json.loads(data)
# сохраняем conversation_id из первого чанка
if "conversation_id" in chunk:
self.conversation_ids[user_id] = chunk["conversation_id"]
if chunk.get("event") == "message":
yield chunk.get("answer", "")
except Exception:
continue
После добавления указываем Dify Api Key + Dify Base Url. После этого наш бот появляется как новая доступная модель в Open WEBUI.

Можно работать!