Files
agentic-codemod-pipeline/docs/adr/0005-backend-llm-per-platforma.md
2026-08-29 13:17:59 +02:00

74 lines
3.8 KiB
Markdown

# 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-choice` z parserem `hermes`;
bez tego vLLM zwraca opis wywołania w treści zamiast `tool_calls` i agent `coder`
nie 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-metal` jest 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.