3.8 KiB
ADR-0005: Backend LLM wybierany per platforma, atrapa jako test double
- Status: przyjęty
- Data: 2026-08-29
Kontekst
Docelowo pipeline korzysta z vLLM wystawionego na OpenShifcie. Do pracy nad samym pipeline'em potrzebny jest jednak model uruchamialny lokalnie - i tu kończy się jednorodność: nie istnieje jedna komenda uruchamiająca vLLM na Linuksie i na macOS.
- Linux z GPU NVIDIA: kontener
vllm/vllm-openai, ścieżka najbliższa produkcji. - macOS na Apple Silicon: Docker nie ma dostępu do Metala, więc kontener odpada.
Zostaje natywny plugin społecznościowy
vllm-project/vllm-metal(backend MLX), instalowany skryptem do własnego venva, wymagający arm64 Pythona 3.12 i Xcode CLT. - Maszyna bez GPU i bez Apple Silicon: żaden z powyższych nie ma sensu.
Osobny problem: testy. Tryb --offline sprawdza RuleBrain, ale nie dotyka tego,
co jest w tym projekcie najbardziej kruche - budowy agentów z definicji APM,
wywoływania narzędzi przez model i parsowania strukturalnych wyjść. Uzależnienie
tego testu od GPU oznaczałoby, że nie uruchomi go nikt poza jedną maszyną.
Decyzja
Kontrakt jest jeden: endpoint zgodny z API OpenAI pod CODEMOD_LLM_BASE_URL.
Backendy różnią się wyłącznie tym, jak ten endpoint powstaje. Konfiguracja mieszka
w llm/models.yml (jedno źródło prawdy: adresy, modele per rola, argumenty serwera),
a task llm:up wykrywa platformę i uruchamia właściwy wariant:
| Backend | Kiedy | Jak |
|---|---|---|
vllm-gpu |
Linux + NVIDIA + Docker | docker compose --profile vllm-gpu |
vllm-metal |
macOS Apple Silicon | natywny plugin MLX, vllm serve |
ollama |
awaryjnie, obie platformy | natywnie (Metal) lub kontener |
mock |
testy, CI | llm/mock_server.py, stdlib, bez pobierania |
Atrapa (mock) to test double, nie symulator modelu: odpowiada z góry ustalonymi
wywołaniami narzędzi i strukturami zestrojonymi z fixture'em acme-app, a routing
odpowiedzi opiera na nazwie agenta wstrzykiwanej przez agno do komunikatu systemowego.
Dzięki niej tests/test_llm_path.py przepuszcza pełny przebieg przez LlmBrain
na każdym MR, bez GPU i bez sieci.
Konsekwencje
Pozytywne
- Projekt startuje od zera na Linuksie i na macOS jedną komendą; różnice platformowe
są schowane za
task llm:up, a nie rozsypane po README. - Ścieżka agentowa jest testowana automatycznie, nie tylko ręcznie na czyjejś maszynie.
- Podmiana modelu lub backendu to zmiana w
llm/models.yml, nie w kodzie. - Wszystkie backendy wymuszają
--enable-auto-tool-choicez parseremhermes; bez tego vLLM zwraca opis wywołania w treści zamiasttool_callsi agentcodernie tknąłby żadnego pliku.
Negatywne
- Cztery ścieżki uruchomieniowe do utrzymania. Ograniczamy koszt tym, że wiedza o nich jest w jednym pliku YAML plus jednym skrypcie, a nie w zadaniach.
vllm-metaljest pluginem społecznościowym - może się rozjechać z upstreamem vLLM. Dlatego Ollama zostaje jako wariant awaryjny na macOS.- Atrapa jest zestrojona z fixture'em: zmiana fixture'u wymaga aktualizacji scenariusza. To świadomy koszt - alternatywą jest brak testu tej ścieżki.
- Model 4B wystarcza do sprawdzenia hydrauliki, ale nie do realnych migracji.
Do pracy trzeba większego - stąd tabela rekomendacji per rola w
llm/models.yml.
Rozważane alternatywy
- Tylko vLLM, macOS niech używa zdalnego endpointu. Odpada: uniemożliwia pracę offline i uzależnia każdego developera od środowiska współdzielonego.
- Tylko Ollama. Prostsze, ale rozjeżdża się z produkcją (inne API tool-callingu, inne kwantyzacje), więc testy przestałyby cokolwiek mówić o zachowaniu na vLLM.
- Brak atrapy, testy tylko na realnym modelu. Niedeterministyczne i niedostępne w CI; test, który czasem przechodzi, jest gorszy niż brak testu.