Strona główna / Artykuły / RAG dostępny wyłącznie w VPC na jednym EC2: Ollama, Qdrant i LangChain

RAG dostępny wyłącznie w VPC na jednym EC2: Ollama, Qdrant i LangChain

Zastąp wiedzę plemienną cytowanym asystentem w formie podręcznika, który nigdy nie pozwala dokumentom opuścić twojego konta AWS — trzy kontenery na GPU EC2.

1723 słów

Problem nieoficjalnego źródła wiedzy

Każda organizacja inżynieryjna ma osoby, które znają odpowiedzi: jak działa proces wdrażania, co przewiduje polityka urlopów, dlaczego Kafka prześcignęło SQS. To działa dopóki te osoby nie są na urlopie, nie zmieniają zespołu lub nowy pracownik nie potrzebuje prawdy o 23:00 podczas incydentu.

Lepsze rozwiązanie: każdy może wpisać „Czy mogę wdrożyć coś w piątek?” i otrzymać udokumentowaną odpowiedź w ciągu sekund — opartą na rzeczywistych instrukcjach obsługi z odniesieniem do źródła. Nie przypuszczenie. Nie wytwór wyobraźni.

Jedno ograniczenie kierowało projektem: żaden dokument wewnętrzny nie opuszcza konta AWS. Żadnych kluczy OpenAI. Żadnej hostowanej bazy wektorowej. Wszystko musiało działać wewnątrz VPC na pojedynczym serwerze EC2.

Co otrzymujesz

Prosty czat w Streamlit. Zadaj pytanie; rozwiń źródła, aby zobaczyć, który plik i sekcja stanowiły podstawę odpowiedzi. Przykład: informacje o zależnościach usługi płatniczej pochodzą z deployment-runbook.md, a nie są to wymyślone nazwy hostów.

Architektura — trzy kontenery

Komenda docker compose up uruchamia:

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 — lokalny model embeddingowy oraz model do czatowania (na przykład llama3.1). Brak kluczy API, brak opłat za token.
  • Qdrant — przechowuje wektory i szybko wyszukuje najbliższe sąsiednie elementy.
  • LangChain — proces wyszukiwania → pakowanie kontekstu → generowanie odpowiedzi, wraz z cytatami.

Wszystko to działa na instancji GPU EC2 w obrębie VPC, dzięki czemu korpusy danych nigdy nie opuszczają tej sieci.

Łączenie ścieżek zadawania pytań

Łańcuch w stylu LCEL wyszukuje dane, formatuje je i formułuje pytania dla lokalnego modelu do czatowania:

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
    )
)

Pobieranie danych pozostaje leksykalne i gęste zgodnie z Twoimi ustawieniami; generowanie odbywa się za pomocą Ollamy. Citacje pochodzą z metadanych w fragmentach danych zwracanych przez Qdrant.

Uwagi dotyczące przetwarzania i operacji

Umieść pliki w formacie markdown oraz instrukcje obsługi w ścieżce przetwarzania, podziel je na fragmenty, włącz do nich modele embedding lokalnie, a następnie zapisz je w Qdrant. Uruchom proces ponownie, gdy dokumency ulegną zmianie. Monitoruj użytek dysku przez modele, pamięci GPU przy jednoczesnych zapytaniach oraz grupy bezpieczeństwa, aby tylko VPN/bastion mogły uzyskać dostęp do Streamlit i Qdrant.

Dlaczego ten model jest najlepszy do przechowywania wiedzy wewnętrznej

Rezygnujesz z maksymalnej jakości modelu na rzecz siły przyciągania danych i kontroli kosztów. W przypadku pytania „co mówi nasza instrukcja obsługi?” taka decyzja jest słuszna. Gdy Aarona nie ma, instrukcja nadal odpowiada — a citacja wskazuje, gdzie sprawdzić informacje.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Zrób proces wdrażania monotonnym: użyj compose up, kontrol health oraz jednego miejsca do rotacji modeli. To właśnie monotonia pozwala narzędziom wewnętrznym przetrwać kontakt z rzeczywistymi harmonogramami dyżurów.

Ograniczenie: dane nigdy nie opuszczają VPC

Niezłomna zasada ta kształtowała każdą decyzję dotyczącą dostawców. Usługi zarządzane API kompatybilne z OpenAI były wykluczone, podobnie jak bazy danych wektorowych hostowanych online. Nawet „tymczasowe” przesyłki do środowiska testowego nie były dozwolone. Pozostała tylko jedna instancja GPU EC2, plik compose oraz zasady dotyczące IAM i grup bezpieczeństwa.

Jeśli wasz zespół prawniczy nie jest w stanie wyznaczyć granic dla ENI w EC2, ta architektura nie jest dla was. Jeśli to możliwe, unikniecie problemów bez konieczności wysyłania plików PDF do osób trzecich.

Szczegóły pipeline’u do pobierania danych

Instrukcje obsługi i procedury rozwiązywania problemów trafiają do określonego katalogu w formacie markdown. Proces dzieli je na nakładające się fragmenty, integruje za pomocą lokalnego modelu embeddingowego Ollama i wprowadza dane do Qdrant wraz z metadanymi dotyczącymi ścieżki i sekcji. W przypadku awarii należy przerwać proces wprowadzania danych dla danego pliku, zamiast po cichu pominąć część dokumentu polityki.

Ponownie wgraj plik, gdy zmieni się jego hash. Unikaj ponownego wgrywania całego korpusu przy każdej drobnej modyfikacji, jeśli możesz porównywać pliki po ich ścieżkach.

Zachowanie podczas wyszukiwania

Aplikacja Streamlit wysyła pytanie użytkownika do narzędzia wyszukiwania skonfigurowanego z małą wartością k. Pobrane teksty są formatowane jako instrukcja, która każe modelowi czatowemu odpowiadać wyłącznie na podstawie kontekstu oraz odmawiać odpowiedzi, gdy kontekst jest niewystarczający. Citaty są wyświetlane na podstawie metadanych, dzięki czemu osoba użytkowniczka może otworzyć dokładną sekcję podręcznika.

To zachowanie polegające na odmowie odpowiedzi przy niewystarczającym kontekście jest ważniejsze niż ustawienia temperatury. Płynne bzdury z fałszywymi cytatami są gorsze od odpowiedzi „Nie widzę tego w podręcznikach”.

Możliwe awarie, na które należy się przygotować

Przeciążenie GPU, gdy ktoś używa większego modelu do czatowania bez zwiększenia rozmiaru instancji. Rosnący dysk Qdrant w przypadku przetwarzania niepotrzebnego pliku binarnego. Przestarzałe odpowiedzi po zmianie procesu, których nikt nie ponownie nie zaimportował. Stosy Compose, które przypisują porty do 0.0.0.0 w publicznej podsieci — należy je utrzymywać prywatne.

Osoba pełniąca dyżur powinna umieć restartować Ollamę, odbudowywać wolumen Qdrant na podstawie oryginalnego pliku markdown oraz sprawdzać, czy odpowiedź nadal odwołuje się do właściwego pliku.

Jak wygląda „ukończenie” projektu

Nowy pracownik już drugiego dnia może zadawać pytania dotyczące wdrażania bez kontaktowania Aarona. Odpowiedzi zawierają pełne ścieżki. Granice VPC są pod stałą kontrolą. Koszt to jeden EC2 plus przechowywanie — przewidywalny. To wystarczający poziom sukcesu dla wewnętrznego asystenta wiedzy; dążenie do wyższej jakości modeli należy rozważyć dopiero wtedy, gdy odwołania do plików są wiarygodne.

Pozycje pokrewne