← Wróć do artykułów

Architektura systemów z LLM na produkcji: Wzorce projektowe, determinizm i inżynieria systemowa

Zbudowanie prototypu opartego o model językowy (LLM) zajmuje dzisiaj jedno popołudnie: kilkadziesiąt linii kodu w Pythonie lub TypeScript, klucz API od OpenAI, Anthropic czy Google i mamy działający czat.

Prawdziwe problemy inżynieryjne zaczynają się w momencie wdrożenia na produkcję:

  • Model sporadycznie zwraca niepoprawny JSON i wywraca parser w backendzie.
  • Agent wykonujący zapytania SQL lub wywołujący API zapętla się, generując setki dolarów kosztu w kilka minut.
  • Wyszukiwanie wektorowe gubi kluczowe numery seryjne i kody błędów, bo embeddingi traktują je jako szum.
  • P99 czasu odpowiedzi rośnie do 12 sekund, a koszty tokenów rosną szybciej niż baza aktywnych użytkowników.

Przejście od „zabawy promptem” do dojrzałego systemu produkcyjnego wymaga traktowania LLM jako niedeterministycznego koprocesora, a nie wyroczni. Poniżej przedstawiamy wzorce architektoniczne, które sprawdzają się w rzeczywistych wdrożeniach enterprise.


1. Wymuszenie determinizmu: Strict Structured Outputs

Najczęstszy błąd początkujących zespołów to proszenie modelu w prompcie systemowym: “Zwróć odpowiedź wyłącznie w formacie JSON”, a następnie parsowanie wyniku za pomocą json.loads() lub wyrażeń regularnych. Prędzej czy później model doda komentarz przed nawiasem klamrowym albo urwie składnię w połowie odpowiedzi.

W systemach produkcyjnych stosuje się mechanizm Constrained Decoding / JSON Schema Enforcement na poziomie silnika generowania (np. Structured Outputs z flagą strict: true):

[ Zapytanie klienta ]
         │
         ▼
[ LLM Execution Engine ]  <──  [ Ścisły schemat JSON Schema ]
         │                     (Wymuszenie gramatyki na tokenach)
         ▼
[ Gwarantowany poprawny JSON ]
         │
         ▼
[ Parser z walidacją typów ]  (np. Pydantic / Zod / Go struct)
         │
         ▼
[ Baza danych / Logika biznesowa ]

Kiedy silnik modelu ogranicza przestrzeń próbkowania kolejnych tokenów (ang. logit biasing lub gramatyki CFG), model fizycznie nie może wygenerować tokena, który złamałby strukturę JSON-a. Dzięki temu warstwa aplikacji otrzymuje gwarancję poprawności typu jeszcze przed wykonaniem kodu biznesowego.


2. Bezpieczne pętle agentowe i Function Calling

Wzorce agentowe (ReAct – Reasoning + Acting) dają modelom możliwość podejmowania decyzji o wywołaniu zewnętrznych narzędzi (kalkulator, zapytanie do bazy danych, wysłanie e-maila). Pozostawienie agenta bez nadzoru to proszenie się o incydent produkcyjny.

Każdy produkcyjny runtime agenta musi implementować trzy zabezpieczenia:

// Szkic maszyny stanów agenta z bezpiecznymi ograniczeniami
type AgentExecutor struct {
    MaxIterations int           // Sztywne odcięcie (np. max 5 kroków)
    Timeout       time.Duration // Twardy deadline per żądanie
    ToolAllowlist []string      // Rygorystyczna lista dozwolonych funkcji
}

func (ae *AgentExecutor) Execute(ctx context.Context, plan *Plan) (*Result, error) {
    ctx, cancel := context.WithTimeout(ctx, ae.Timeout)
    defer cancel()

    for step := 1; step <= ae.MaxIterations; step++ {
        // 1. Ewaluacja stanu przez model
        // 2. Jeśli model żąda 'tool_call':
        //    - weryfikacja uprawnień (RBAC)
        //    - weryfikacja idempotencji
        //    - wykonanie narzędzia w piaskownicy
        // 3. Jeśli model zwrócił stan końcowy -> return
    }
    return nil, errors.New("agent_iteration_limit_exceeded")
}
  • Idempotencja narzędzi: Każde narzędzie o charakterze mutującym (np. create_order, cancel_subscription) musi przyjmować unikalny idempotency_key generowany przez warstwę orkiestracji. Jeśli agent spróbuje wywołać to samo narzędzie dwukrotnie w jednej pętli, drugi call jest bezpiecznym no-opem.
  • Human-in-the-Loop dla akcji o wysokim ryzyku: Akcje niszczące (usunięcie danych, przelewy powyżej określonego progu) zatrzymują pętlę agenta, zapisują stan w kolejce i generują powiadomienie do operatora w panelu administracyjnym.

3. Retrieval: Dlaczego samo wyszukiwanie wektorowe nie wystarcza

Prosty RAG oparty o kalkulację cosine similarity na embeddingach doskonale radzi sobie z pytaniami ogólnymi (“Jaka jest polityka zwrotów?”), ale zupełnie zawodzi w systemach technicznych i enterprise:

  • Zapytanie o kod błędu ERR_TMF_620_404 zostanie dopasowane do ogólnych artykułów o protokole HTTP zamiast do właściwego schematu TMF.
  • Zapytanie o numer faktury FV/2026/09/112 zostanie rozbite przez tokenizer na losowe pod-tokeny.

Rozwiązaniem produkcyjnym jest Hybrydowy Retrieval (Dense + Sparse) z Re-rankingiem:

                  [ Zapytanie użytkownika ]
                              │
               ┌──────────────┴──────────────┐
               ▼                             ▼
       [ Dense Search ]               [ Sparse Search ]
     (Wektory cosine/dot)            (BM25 / Full-Text)
       Top-50 wyników                 Top-50 wyników
               └──────────────┬──────────────┘
                              │
                              ▼
                     [ Reciprocal Rank ]
                     [ Fusion (RRF)    ]
                              │ Top-30 kandydatów
                              ▼
                   [ Cross-Encoder Re-ranker ]
                   (np. Cohere / BGE-Reranker)
                              │ Top-5 najbardziej trafnych
                              ▼
                   [ Kontekst dla LLM ]
  1. Dense (wektorowe) znajduje powiązania semantyczne i synonimy.
  2. Sparse (BM25 w Postgresie lub Elasticsearch) bezbłędnie trafia w kody błędów, identyfikatory i precyzyjne nazwiska.
  3. Cross-Encoder Re-ranker analizuje pełne pary (zapytanie, fragment) z uwzględnieniem uwagi na poziomie tokenów, redukując szum z 50 fragmentów do 3-5 precyzyjnych akapitów. Oszczędza to tokeny w oknie kontekstowym i drastycznie redukuje halucynacje.

4. Architektura kaskadowa (Model Routing)

Wysyłanie każdego zapytania użytkownika do największych i najdroższych modeli (takich jak GPT-4o czy Claude 3.5 Sonnet) to marnotrawstwo budżetu i gwarancja wysokiej latencji (często 2–4 sekundy na pierwsze tokeny).

W architekturze korporacyjnej stosuje się Model Router:

  1. Warstwa 1 (Triage & Classification): Lekki, szybki model (np. Gemini 1.5 Flash, GPT-4o-mini lub lokalny Llama-3-8B) klasyfikuje intencję użytkownika w 150 ms przy ułamkowym koszcie.
  2. Ścieżka prosta (FAQ, proste transformacje): Odpowiedź jest generowana bezpośrednio przez mały model lub pobierana z Semantic Cache (Redis / pgvector).
  3. Ścieżka złożona (Wielokrokowa analiza, synteza prawna, generowanie kodu): Ruch jest kierowany do dużego modelu reasoningowego.

W praktyce 60–80% ruchu w aplikacjach B2B może zostać bezstratnie obsłużone przez tańszą i szybszą ścieżkę, zmniejszając rachunek za API o ponad połowę.


5. Obserwowalność: Trzy metryki, które musisz monitorować

Jeśli nie logujesz każdego wywołania LLM z metrykami strukturalnymi, wdrażanie systemu na produkcję to lot na oślep. Narzędzia takie jak Langfuse czy standard OpenTelemetry Semantic Conventions for Generative AI pozwalają śledzić:

  • Token Economics per Tenant: Dokładny koszt generowania w podziale na organizacje (kluczowe w aplikacjach Multi-Tenant SaaS, aby nie subsydiować stratnych klientów).
  • TTFT (Time-to-First-Token) i Token-per-second: Separacja czasu potrzebnego na wyszukiwanie w bazie danych od czasu generowania tekstu przez model.
  • Ewaluacja w locie (RAG Triad): Automatyczne próbkowanie odpowiedzi i weryfikacja:
    • Context Relevance (czy retrieval wyciągnął właściwe fragmenty?),
    • Groundedness (czy odpowiedź modelu ma pokrycie w faktach z kontekstu?),
    • Answer Relevance (czy odpowiedź rzeczywiście odpowiada na pytanie klienta?).

Podsumowanie

W erze produkcyjnych systemów LLM wartość inżynierska nie leży w pisaniu wyszukanych promptów. Leży w architekturze odpornej na błędy: rygorystycznej walidacji schematów, hybrydowym wyszukiwaniu informacji, izolacji stanów maszyn agentowych i precyzyjnej kontroli kosztów. Traktuj LLM jak zewnętrzny serwis sieciowy, który może zwrócić błąd, opóźnić się lub skłamać – a Twój system będzie działał stabilnie.