Генерация сайта из документов с помощью ИИ: инструкция для передачи дел | AiManual
AiManual Logo Ai / Manual.
16 Янв 2026 Гайд

Документы в свалке? Сделайте из них интерактивную базу знаний за два вечера

Пошаговый гайд по созданию интерактивной базы знаний из документов за 2 вечера. ИИ для структурирования, RAG для поиска, Docker для развертывания.

Проблема: почему передача дел похожа на археологические раскопки

Новый CEO приходит в компанию. Или старший инженер уходит в другой проект. Или вы просто хотите передать часть задач коллеге. Что получает человек? Папку с документами. Нет, не красивый Confluence с навигацией. Обычную папку в Google Drive или, что хуже, архив на почте.

Внутри: PDF-отчеты за 2021 год, скриншоты Slack-переписок, таблицы Excel с непонятными формулами, заметки в формате «мысль дня». Никакой структуры. Никаких связей. Попробуйте найти ответ на вопрос «почему мы используем именно эту версию библиотеки?» — придется перелопатить десяток файлов.

Типичная ошибка: думать, что «документы есть, значит знания сохранены». Это иллюзия. Знания существуют в связях между документами, в контексте, в неявных договоренностях. Папка с файлами — это кладбище знаний.

Решение: не Confluence, а живой сайт с мозгом

Создаем не просто статичный сайт с навигацией. Создаем интерактивную систему, где можно:

  • Задать вопрос на естественном языке («Как мы выбирали поставщика облака?»)
  • Получить ответ со ссылками на исходные документы
  • Видеть связи между темами (финансы → выбор облака → конкретный контракт)
  • Обновлять информацию добавлением новых документов

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

💡
Почему именно сайт, а не просто чат-бот? Сайт дает визуальную структуру, возможность навигации, разделение по темам. Это не черный ящик, где вы вводите запрос и надеетесь на лучшее. Вы видите, как информация организована, можете изучать ее иерархически.

Шаг 0: Подготовка — собираем все, что есть

Не фильтруйте. Не пытайтесь сразу структурировать. Скачайте все:

  • PDF-отчеты, презентации
  • Документы Word, Google Docs (экспорт в PDF или текст)
  • Таблицы Excel/Google Sheets
  • Скриншоты переписок (да, их тоже можно обработать, если есть текст)
  • Даже голосовые заметки — есть инструменты для транскрибации

Сложите все в одну папку. Назовите ее raw_documents. Если файлов больше 100, разделите на подпапки по годам или темам — это упростит дальнейшую обработку.

1 Извлекаем текст: из PDF, картинок, таблиц

Здесь нужны инструменты OCR и парсеры. Не пытайтесь делать все вручную.

Для PDF используйте pdftotext (из пакета poppler) или библиотеку PyPDF2/PyMuPDF в Python. Для таблиц — pandas. Для изображений со текстом — Tesseract OCR.

Пример скрипта на Python для обработки папки:

import os
import fitz  # PyMuPDF
from PIL import Image
import pytesseract
import pandas as pd

def extract_text_from_pdf(pdf_path):
    doc = fitz.open(pdf_path)
    text = ""
    for page in doc:
        text += page.get_text()
    return text

def process_folder(input_folder, output_folder):
    os.makedirs(output_folder, exist_ok=True)
    for filename in os.listdir(input_folder):
        filepath = os.path.join(input_folder, filename)
        if filename.endswith('.pdf'):
            text = extract_text_from_pdf(filepath)
        # Добавьте обработку других форматов
        output_path = os.path.join(output_folder, f"{os.path.splitext(filename)[0]}.txt")
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(text)

Не забудьте про кодировки. Русский текст в старых документах часто сохраняется в cp1251. Используйте chardet для автоматического определения кодировки.

2 Разбиваем на фрагменты: почему нельзя кормить ИИ целыми документами

Большой документ на 50 страниц — это слишком много для контекста модели. Нужно разбить текст на фрагменты по 500-1000 символов с перекрытием (overlap) в 100 символов. Перекрытие нужно, чтобы контекст не обрывался на середине предложения.

Используйте библиотеку LangChain или простой скрипт:

def split_text(text, chunk_size=1000, overlap=100):
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunk = text[start:end]
        chunks.append(chunk)
        start += chunk_size - overlap
    return chunks

Сохраняйте метаданные для каждого фрагмента: исходный файл, номер страницы (для PDF), дата документа. Потом это понадобится для ссылок в ответах.

3 Векторная база: превращаем текст в числа для поиска

Здесь начинается магия. Текст преобразуется в векторы (эмбендинги) — числовые представления смысла. Похожие по смыслу фрагменты будут иметь близкие векторы.

Локальный вариант: Ollama с моделью nomic-embed-text (хорошо работает с русским). Облачный вариант: OpenAI API (text-embedding-3-small) или бесплатные альтернативы типа Jina Embeddings.

База данных для векторов:

  • Chroma — проще всего, работает из коробки
  • Qdrant — производительнее, есть Docker-образ
  • Weaviate — больше возможностей для фильтрации

Пример с Chroma:

import chromadb
from chromadb.config import Settings
from sentence_transformers import SentenceTransformer

# Инициализация
client = chromadb.Client(Settings(persist_directory="./chroma_db"))
collection = client.create_collection(name="knowledge_base")

# Модель для эмбеддингов (локальная)
model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

# Преобразование и сохранение
for i, chunk in enumerate(text_chunks):
    embedding = model.encode(chunk).tolist()
    collection.add(
        documents=[chunk],
        embeddings=[embedding],
        metadatas=[{"source": filename, "page": page_num}],
        ids=[f"doc_{i}"]
    )

💡
Не экономьте на метаданных. Добавляйте не только имя файла, но и тип документа (отчет, переписка, контракт), дату, автора. Потом это позволит фильтровать результаты: «Покажи только документы от Ивана за 2023 год».

4 Сервер вопросов и ответов: мозг системы

Теперь нужен сервер, который будет принимать вопросы, искать релевантные фрагменты в векторной базе и генерировать ответы.

FastAPI + LangChain — отличный выбор:

from fastapi import FastAPI
from pydantic import BaseModel
from langchain.chains import RetrievalQA
from langchain.llms import Ollama
from langchain.embeddings import OllamaEmbeddings
from langchain.vectorstores import Chroma

app = FastAPI()

# Загрузка векторной базы
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})  # 5 наиболее релевантных фрагментов

# Инициализация локальной модели через Ollama
llm = Ollama(model="llama3.1", temperature=0.1)  # temperature=0.1 для более точных ответов

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True
)

class Question(BaseModel):
    query: str

@app.post("/ask")
async def ask_question(question: Question):
    result = qa_chain({"query": question.query})
    return {
        "answer": result["result"],
        "sources": [
            {
                "source": doc.metadata["source"],
                "page": doc.metadata.get("page", "N/A")
            }
            for doc in result["source_documents"]
        ]
    }

Запустите этот сервер локально или в Docker-контейнере. Теперь у вас есть API, который отвечает на вопросы на основе ваших документов.

5 Интерфейс: простой веб-сайт вместо сложного чат-бота

Многие останавливаются на этапе API и делают чат-интерфейс. Ошибка. Для базы знаний нужен именно сайт с:

  • Поисковой строкой
  • Древовидной навигацией по темам
  • Страницами с автоматически сгенерированными статьями
  • Ссылками между статьями

Используйте Streamlit для прототипа или Next.js + Tailwind CSS для более серьезного решения.

Ключевая идея: генерируйте не только ответы на вопросы, но и статические страницы по основным темам. Как найти темы? Попросите ИИ проанализировать документы и выделить основные категории:

prompt = """
Проанализируй следующие документы и выдели 10 основных тем, которые в них обсуждаются.
Верни результат в формате JSON:
{
  "topics": [
    {
      "name": "Название темы",
      "description": "Краткое описание",
      "keywords": ["ключевое", "слово"]
    }
  ]
}
Документы:
{тексты_документов}
"""

Для каждой темы создайте страницу с обзором, используя ИИ. Затем свяжите эти страницы гиперссылками.

Ошибки, которые гарантированно испортят результат

Ошибка Почему это проблема Как исправить
Кормить ИИ сырыми документами без обработки Модель теряет контекст, отвечает ерундой или игнорирует важные детали Обязательно разбивайте на фрагменты с перекрытием
Использовать только OpenAI без fallback API может упасть, закончатся деньги, а доступ к знаниям нужен сейчас Используйте локальные модели (Ollama + локальные модели) как основной вариант
Игнорировать метаданные Пользователь получает ответ, но не понимает, откуда он взят Всегда сохраняйте источник, дату, автора, тип документа
Не настраивать параметры поиска Система возвращает слишком много или слишком мало результатов Экспериментируйте с k (количество фрагментов) и score_threshold (порог схожести)

Что делать, если ИИ генерирует ерунду

Такое случается. Особенно с локальными моделями. Вместо того чтобы сдаваться, сделайте три вещи:

  1. Проверьте качество фрагментов. Если фрагмент обрывается на середине предложения, ИИ не поймет контекст. Увеличьте перекрытие до 150-200 символов.
  2. Добавьте system prompt. Явно укажите модели: «Ты — помощник, который отвечает только на основе предоставленных документов. Если в документах нет информации, скажи 'Информация не найдена'».
  3. Используйте цепочки (chains). Вместо одного запроса к модели разбейте задачу: сначала поиск релевантных фрагментов, затем их суммаризация, затем ответ на вопрос.

Если ИИ продолжает галлюцинировать, возможно, проблема в самой модели. Попробуйте другие — сравнение моделей для кодинга поможет выбрать подходящую.

Деплой: как сделать базу знаний доступной для команды

Локальный сервер на вашем ноутбуке бесполезен. Нужно развернуть систему так, чтобы доступ был у всех, кому нужен.

Варианты:

  • Docker Compose — все компоненты (векторная база, бэкенд, фронтенд) в контейнерах. Развертывание одной командой.
  • Cloud Run (GCP) или Railway — если не хотите возиться с сервером.
  • На собственном сервере — больше контроля, но нужно следить за обновлениями.

Пример docker-compose.yml для базового стека:

version: '3.8'

services:
  qdrant:
    image: qdrant/qdrant
    ports:
      - "6333:6333"
    volumes:
      - ./qdrant_storage:/storage

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - QDRANT_HOST=qdrant
      - QDRANT_PORT=6333
    depends_on:
      - qdrant

  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    depends_on:
      - backend

Не забывайте про безопасность. Не выставляйте API публично без авторизации. Используйте базовую HTTP-аутентификацию или JWT-токены.

Что дальше: от статичной базы к живой системе

Сайт готов. Но знания не статичны. Новые документы появляются каждый день. Как обновлять базу?

1. Автоматическое добавление. Настройте webhook, который при появлении нового документа в Google Drive/Dropbox автоматически обрабатывает его и добавляет в векторную базу.

2. Обратная связь. Добавьте кнопки «Полезно»/«Не полезно» под ответами. Собирайте feedback для улучшения поиска.

3. Визуализация связей. Используйте граф знаний — покажите, как документы связаны между собой. Это помогает понять контекст лучше, чем простой список.

4. Мультимодальность. Добавьте обработку не только текста, но и изображений, видео, аудио. Как это работает — в статье про Multi-modal RAG.

Самое главное — не пытайтесь сделать идеальную систему с первого раза. Соберите минимально рабочую версию за два вечера. Дайте ее коллегам. Посмотрите, какие вопросы они задают. Какие ответы получают. Итеративно улучшайте.

Потому что база знаний, которой никто не пользуется, — это просто еще один забытый документ в папке.