Игорь Градов
Игорь Градов
6 мин
ai

Локальный RAG на FastAPI и Ollama: add PDF, Word file без облака и подписок

Ниже работа с локальными документами выходит за рамки «поболтать с моделью» и превращается в инженерную систему с API, логами, источниками и диагностикой.

Локальный RAG на FastAPI и Ollama: add PDF, Word file без облака и подписок
Почему это важно

RAG (Retrieval-Augmented Generation, генерация с опорой на найденные документы) позволяет модели отвечать не «из головы», а по вашим файлам. Локальный вариант на FastAPI и Ollama держит данные на вашей машине, без облака и подписок.

Автор проекта описал путь от простого вызова локальной LLM до бэкенда с контрактом API, трассировкой запросов, источниками ответа и индексом документов. Не «production-ready» система, а учебный полигон с инженерными акцентами. Материал опубликован как открытый разбор архитектуры, цель которого показать, где именно заканчивается «чат с моделью» и начинается бэкенд-система по документации. Ниже воспроизвожу ключевые шаги и решения из этого разбора.

Что понадобится?

  • Python 3.10+ и установленный FastAPI с сервером Uvicorn
  • Ollama (опенсорс-инструмент для локального запуска LLM, работает на macOS, Linux, Windows)
  • Модель для генерации: в проекте использована gpt-oss:20b (запускается через Ollama)
  • Модель для эмбеддингов (векторных представлений текста): embeddinggemma (тоже через Ollama)
  • Документы в формате .md или .txt в локальной папке documents/
  • Фронтенд на HTML/CSS/JS (минимальный, чтобы отправлять вопросы и видеть ответ)
  • Примерное время: от 2 до 4 часов на первую работающую версию, если стек знаком

Пошаговая инструкция

1. Соберите минимальный бэкенд с эндпоинтом /ask

На старте схема проста: фронтенд отправляет POST /ask, FastAPI создаёт уникальный request_id, логирует запрос, вызывает модель через Ollama и возвращает ответ.

# Упрощённая схема (не полный код проекта)
@app.post("/ask")
async def ask(question: str):
    request_id = str(uuid4())
    log_request(request_id, question)
    answer = call_ollama(question)
    log_response(request_id, answer)
    return {"request_id": request_id, "answer": answer}

На этом этапе помощник уже отвечает, но по сути остаётся обычным чатом с моделью. Документы в процессе не участвуют.

2. Осознайте, почему простой вызов LLM ещё не система

Проблемы, которые автор выделяет на этом этапе:

  • Модель не знает локальные документы, если не передать их в контекст
  • Ответ невозможно проверить по источникам
  • Непонятно, что именно попало в промпт (prompt, запрос к модели)
  • Если ответ медленный, неясно, какой этап тормозит
  • Если документ изменился, неясно, обновился ли индекс
  • Модель может «галлюцинировать» (уверенно выдумывать), даже когда ответа нет

3. Добавьте загрузку и нарезку документов на чанки

Положите файлы .md и .txt в папку documents/. Для тех, кому нужно добавить PDF или Word (ollama rag add pdf word file), на этом этапе потребуется предварительная конвертация в текстовый формат: библиотеки вроде pdfplumber для PDF и python-docx для Word извлекут текст, после чего файл обрабатывается так же, как .txt.

Документ целиком редко удобно передавать в промпт. Нарежьте его на чанки (небольшие фрагменты фиксированной длины с перекрытием). Отдельный эндпоинт GET /documents/chunks позволяет убедиться, что бэкенд видит и корректно режет каждый файл.

4. Постройте эмбеддинги и векторное хранилище

Эмбеддинги (embedding, числовое представление смысла текста) считаются через Ollama и модель embeddinggemma. Каждый чанк превращается в вектор, все векторы складываются в хранилище в оперативной памяти (in-memory vector store).

Эндпоинт POST /documents/index/rebuild перечитывает документы, режет, считает эмбеддинги и обновляет хранилище. Эндпоинт GET /documents/index/status показывает текущее состояние индекса.

5. Подключите поиск и сборку промпта

При запросе через /ask бэкенд теперь ищет релевантные чанки по близости векторов, фильтрует по порогу score, проверяет точные термины и собирает из найденных фрагментов промпт для модели.

Упрощённый пайплайн обработки /ask после добавления RAG:

  1. Принять вопрос, создать request_id
  2. Найти релевантные чанки в векторном хранилище
  3. Отфильтровать источники по score
  4. Проверить наличие точных терминов (exact terms)
  5. Собрать промпт с найденным контекстом
  6. Вызвать Ollama
  7. Вернуть ответ, источники, тайминги и request_id

6. Оформите контракт ответа API

Автор использовал Pydantic-модели для строгого контракта. Ответ содержит не только текст, но и диагностику:

class AskResponse(BaseModel):
    request_id: str
    answer: str
    sources: list[Source]      # документ, путь, номер чанка, score, текст
    duration_ms: int
    timings: TimingBreakdown   # retrieval, filtering, prompt, generation, total

Такой JSON на выходе уже не игрушечный чат, а бэкенд-API с контрактом, диагностикой и привязкой к логам.

7. Добавьте диагностические эндпоинты

Полный набор эндпоинтов из проекта:

  • POST /ask — главный, для пользователя
  • GET /documents — какие документы видит бэкенд
  • GET /documents/chunks — нарезка на чанки
  • GET /documents/embeddings — статус эмбеддингов
  • POST /documents/index/rebuild — пересборка индекса
  • GET /documents/index/status — состояние индекса
  • POST /documents/search — поиск по чанкам без генерации
  • POST /rag/debug — полная отладка пайплайна

Эти эндпоинты появились не ради архитектурной красоты: когда каждый слой можно проверить отдельно, искать ошибки на порядок проще.

Пример: что ввели и что получили

Вопрос через POST /ask: «Когда нужно выполнять rebuild index?»

Ответ (сокращённо):

{
  "request_id": "8b7a8be9-4bfd-4b89-ac9c-5a26f01de229",
  "answer": "Rebuild index нужно выполнять после добавления, изменения или удаления документов...",
  "duration_ms": 60440,
  "timings": {
    "retrieval_ms": 2163,
    "generation_ms": 58276,
    "total_ms": 60440
  },
  "sources": [
    {
      "document": "operations.md",
      "chunk_index": 5,
      "score": 0.6547,
      "chunk": "...Пятый случай — смена embedding модели..."
    }
  ]
}

Видно: ответ опирается на конкретный чанк из operations.md, генерация заняла 58 секунд (основное время), поиск около 2 секунд. Источник можно проверить руками.

Частые ошибки
  • Забыли пересобрать индекс. Изменили или добавили документ (включая случай ollama rag add pdf word file после конвертации), а POST /documents/index/rebuild не вызвали. Модель ответит по старым данным или вообще мимо.
  • Чанки слишком большие или слишком мелкие. Крупный чанк не влезает в контекст модели, мелкий теряет смысл. Начните с 500 токенов (токен, единица текста для модели, примерно три четверти слова) и подбирайте под ваши документы.
  • Нет порога score. Без фильтрации по score модель получает нерелевантные фрагменты и галлюцинирует увереннее, чем без контекста вовсе.
  • Не смотрите тайминги. Если /ask работает 60 секунд, а generation_ms занимает 58 из них, проблема не в поиске, а в скорости инференса (inference, процесс генерации ответа моделью). Без разбивки по этапам вы оптимизируете не то.
  • Ждёте от in-memory хранилища масштаба. Хранилище в оперативной памяти годится для десятков и сотен документов. Для тысяч нужна полноценная векторная база данных (ChromaDB, Qdrant, FAISS).

Что делать с этим прямо сейчас?

Разработчикам и техническим авторам. Проект показывает скелет локального RAG-бэкенда с диагностикой. Можно взять архитектуру эндпоинтов как шаблон для внутреннего помощника по документации команды, не отправляя данные в облако.

Авторам Дзена и контент-маркетологам. Если пишете о технологиях, сам разбор подхода «от чата к системе» ложится в формат кейса или серии. Локальный RAG на своих текстах может помочь быстрее находить цитаты и факты по архиву публикаций.

Предпринимателям в РФ и СНГ. Ollama и FastAPI бесплатны, работают без зарубежных API-ключей и подписок. Данные остаются на вашем сервере. Для первого прототипа ИИ-помощника по внутренней базе знаний это рабочий вариант без бюджета на облако. Из российских аналогов для генерации можно попробовать GigaChat API от Сбера или YandexGPT, но они облачные, а не локальные.

Мнение редакции dzen.guru

Проект ценен не кодом, а инженерной логикой. Автор показал, что между «запустил модель и получил ответ» и «система, которой можно доверять ответ по документации» лежит десяток слоёв: request_id, тайминги, источники, пересборка индекса, порог релевантности. Я проверял похожие связки и могу подтвердить: без диагностических эндпоинтов отладка RAG превращается в гадание. Честная оговорка: in-memory хранилище, модель на 20 млрд параметров и локальный сервер подходят для пилота и обучения. Для нагруженного продакшена потребуется векторная база, более быстрый инференс и очередь запросов. Но как полигон для понимания, что такое RAG изнутри, связка FastAPI плюс Ollama работает.

Хотите внедрять ИИ-инструменты в свой контент-процесс?

В dzen.guru разбираем практические сценарии работы с нейросетями для авторов и предпринимателей.

Узнать больше

Локальный RAG не требует бюджета, не отправляет данные наружу и учит думать слоями. Начните с пяти документов и одного эндпоинта /ask, добавьте тайминги и источники, а потом решайте, нужен ли вам облачный масштаб или хватит сервера под столом.

Поделиться:TelegramVK
Игорь Градов
Игорь Градов

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».

Комментарии

Читайте также

AI-агенты молча пишут устаревший код: как бесплатный Context7 теряет данные без ошибки
ai

AI-агенты молча пишут устаревший код: как бесплатный Context7 теряет данные без ошибки

Компания Upstash, разработавшая открытый MCP-сервер Context7 для подачи документации ИИ-агентам, столкнулась с тем, что бесплатный тариф молча перестаёт…

5 мин
GM поставила 50 роботов на производстве, пока 1 300 уволенных рабочих ждут возвращения
ai

GM поставила 50 роботов на производстве, пока 1 300 уволенных рабочих ждут возвращения

General Motors установила около 50 роботизированных манипуляторов японской компании FANUC на своём флагманском заводе по выпуску электромобилей Factory Zero в…

5 мин
OpenAI запустила бесплатный bug bounty для чужого опенсорса: ИИ ищет дыры до хакеров
ai

OpenAI запустила бесплатный bug bounty для чужого опенсорса: ИИ ищет дыры до хакеров

OpenAI второго июня запустила «Patch the Planet», программу, в которой специалисты по безопасности и ИИ-инструменты бесплатно ищут уязвимости в открытых…

5 мин