Головна / Статті / RAG лише у VPC на одному EC2: Ollama, Qdrant та LangChain

RAG лише у VPC на одному EC2: Ollama, Qdrant та LangChain

Замініть племінні знання на асистента у вигляді посібника з посиланнями, який ніколи не дозволяє документам виходити за межі вашого облікового запису AWS — три контейнери на GPU EC2.

1723 слів

Проблема неофіційного джерела знань

У кожній інженерній команді є люди, які знають відповіді: як працює процес розгортання, що передбачає політика відпусток, чому Kafka переміг SQS. Це працює доти, доки ці люди не будуть у відпустці, не змінять команду чи поки новий співробітник у ніч о 11 не буде потребувати інформації під час інциденту.

Кращий варіант: будь-хто пише «Чи можу я розгорнути щось у п’ятницю?» і отримує задокументовану відповідь протягом кількох секунд — ґрунтовану на реальних інструкціях з посиланням. Це не припущення. І не вигадка.

Одне обмеження спрямувало дизайн: жоден внутрішній документ не залишає облікового запису AWS. Жодних ключів OpenAI. Жодних хостованих векторних БД. Усе мусило працювати всередині VPC на одному сервері EC2.

Що ви отримуєте

Простий чат у Streamlit. Задайте запитання; розгорніть джерела, щоб побачити, який файл та розділ стали основою відповіді. Приклад: інформація про залежності платіжного сервісу надається з deployment-runbook.md, без вигадування імен хостів.

Архітектура — три контейнери

Команда docker compose up запускає:

version: "3.9"

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    restart: unless-stopped

  qdrant:
    image: qdrant/qdrant:v1.18.2
    container_name: qdrant
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage
    environment:
      - QDRANT__SERVICE__ENABLE_CORS=true
    restart: unless-stopped

  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: rag-app
    ports:
      - "8501:8501"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - QDRANT_URL=http://qdrant:6333
      - COLLECTION=company_docs
      - EMBED_MODEL=nomic-embed-text
      - LLM_MODEL=llama3.1:8b
      - S3_CORPUS_BUCKET=${S3_CORPUS_BUCKET}
      - S3_CORPUS_PREFIX=${S3_CORPUS_PREFIX:-corpus/}
      - AWS_REGION=${AWS_REGION:-us-east-1}
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
    volumes:
      - corpus_data:/app/corpus
      - ./scripts:/app/scripts
    depends_on:
      - ollama
      - qdrant
    restart: unless-stopped

volumes:
  ollama_data:
  qdrant_data:
  corpus_data:
  • Ollama — локальна модель ембеддингу та модель чату (наприклад, llama3.1). Жодних API-ключів, жодних оплат за кожен токен.
  • Qdrant — зберігає вектори та швидко знаходить найближчі сусіди.
  • LangChain — процес отримання даних → пакування контексту → генерація відповіді з посиланнями.

Усе це розташовано на екземплярі GPU EC2 у межах VPC, тож корпуси даних ніколи не виходять за межі цієї мережі.

Підключення шляху запиту

Ланцюг у стилі LCEL отримує дані, форматує їх та надсилає запит локальній моделі чату:

from operator import itemgetter
from langchain_core.runnables import RunnableLambda, RunnableParallel

chain = RunnableParallel(
    question=itemgetter("question"),           # pass question through
    docs=itemgetter("question") | retriever,   # embed + search Qdrant
).assign(
    answer=(
        {"context": itemgetter("docs") | RunnableLambda(format_docs),
         "question": itemgetter("question")}
        | prompt_template    # inject into system/human message
        | llm                # send to Ollama
        | str_parser         # extract text from response
    )
)

Процес отримання даних залишається лексично насиченим згідно з вашими налаштуваннями; генерація відбувається через Ollama. Цитати беруться з метаданих фрагментів, які повертає Qdrant.

Примітки щодо імпорту та операцій

Помістіть markdown-документи та посібники у шлях імпорту, розділіть їх на фрагменти, інтегруйте за допомогою локальної моделі ембеддингу та внесіть зміни до Qdrant. Перезапустіть процес при зміні документів. Слідкуйте за використанням диска для зберігання моделей, пам’яті GPU для одночасних запитів та групами безпеки, щоб лише VPN чи бастіон могли отримати доступ до Streamlit та Qdrant.

Чому ця схема є ефективною для внутрішніх знань

Ви жертвуєте максимальною якістю моделей заради економії ресурсів та контролю витрат. Для запитань на кшталт „Що сказано в нашому посібнику?“ такий компроміс є доцільним. Коли Аарона немає, посібник все одно дає відповідь — а цитата вказує, де можна перевірити інформацію.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Зробіть процес розгортання простим: використовуйте compose up, перевірки стану та єдине місце для заміни моделей. Саме простота допомагає внутрішнім інструментам витримувати роботу з реальними графіками чергування.

Обмеження: дані ніколи не виходять за межі VPC

Це непохитне правило визначало кожен вибір постачальника. API, сумісні з OpenAI та які потребують керування, були виключені. Векторні бази даних, розміщені на серверах, також були виключені. Навіть „тимчасові“ завантаження для тестування були заборонені. Це залишило лише одну інстанцію EC2 з GPU, файл compose та правила IAM/груп безпеки.

Якщо ваша юридична команда не може чітко визначити межі ENI у EC2, ця архітектура не підходить вам. Якщо ж це можливо, ви отримаєте необхідні дозволи без необхідності надсилати PDF-файли третій стороні.

Деталі конвеєра обробки даних

Інструкції та процедури вирішення проблем зберігаються у форматі markdown у відповідному каталозі. Завдання розділяє їх на частини, вбудовує дані за допомогою локальної моделі ембеддингу через Ollama та додає інформацію про шлях та розділ у Qdrant. У разі збою слід припинити обробку цього файлу, а не просто проігнорувати частину документа з правилами.

Поновіть вбудовування, коли змінюється хеш файлу. Якщо можливо відрізняти зміни за шляхом, уникайте повторного вбудовування всього корпусу після кожної незначної зміни.

Поведінка під час запиту

Додаток Streamlit надсилає запит користувача до системи пошуку, налаштованої з невеликим значенням k. Отримані тексти форматуються у запит, який просить модель чату відповідати лише на основі контексту та відмовлятися, якщо контекст недостатній. Цитування формуються з метаданих, щоб людина могла відкрити саме ту частину посібника.

Ця поведінка з відмовою при недостатньому контексті має більше значення, ніж налаштування температури. Плавні нісенітниці з фальшивими цитатами гірші, ніж відповідь „Я не бачу цього у посібниках“.

Варіанти збоїв, на які потрібно звернути увагу

Проблема нестачі пам’яті GPU, коли хтось завантажує більшу модель чату, не збільшуючи розмір інстанції. Зростання обсягу диска Qdrant у разі завантаження бінарних даних непотрібного типу. Устарілі відповіді після зміни процесу, які ніхто не оновлював. Стеки Compose, які прив’язують порти до 0.0.0.0 у публічному сабнеті — треба зберігати їх приватними.

Спеціаліст, який перебуває у режимі чергування, повинен знати, як перезапустити Ollama, відновити об’єм Qdrant з початкового markdown-файлу та перевірити, чи посилання на „золоте“ запитання все ще веде до правильного файлу.

Як виглядає „готовий“ продукт

Новий співробітник вже на другий день може ставити запитання щодо розгортання без звернення до Аарона. Відповіді містять шляхи до файлів. Межі VPC постійно перевіряються. Витрати складаються з однієї інстанції EC2 та простору зберігання — це передбачувано. Цього достатньо для внутрішнього асистента знань; на якість передових моделей варто звертати увагу лише після того, як посилання стануть надійними.