AI ответы по базе знаний

Задача: AI бот для ответов на вопросы в рамках предоставленных документов.

Решение: RAG на базе Dify (как бекенд для создания базы знаний и бота) + OpenAI API (модель GPT 5.4) + Open WEBUI (для работы с ботом).

RAG (Retrieval-Augmented Generation) — архитектурный паттерн, при котором языковая модель перед генерацией ответа сначала извлекает релевантные данные из внешнего хранилища.

https://www.aiintime.com/post/what-is-rag

Нам понадобится

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.

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