Osiem wyspecjalizowanych agentów zamiast jednego. Moja architektura orkiestracji w OpenCode

Gdy zaczynałem pracę z autonomicznymi agentami kodującymi, próbowałem robić to tak, jak większość: jeden asystent, do którego wrzucałem całe zadanie i liczyłem na to, że ogarnie architekturę, napisze backend, zepnie frontend, przygotuje testy i jeszcze zrobi ładny commit. Szybko okazało się, że to ślepa uliczka. Taki model po kilkunastu minutach gubi wątek, zapomina o wytycznych bezpieczeństwa, a w skrajnych przypadkach potrafi wyczyścić historię repozytorium, bo próbował po swojemu „naprawić konflikt”.

Żeby nad tym zapanować, przygotowałem własny szablon orkiestracji oparty o OpenCode i podzieliłem pracę na dziewięć ściśle odseparowanych bytów: jednego koordynatora oraz ośmiu wyspecjalizowanych inżynierów.

Zasada żelazna: Orchestrator nie pisze kodu

W mojej konfiguracji główny agent, czyli Orchestrator, pełni wyłącznie rolę analityka i kierownika projektu. Ma kategoryczny zakaz dotykania plików z kodem źródłowym. Jego zadaniem jest odebranie zapytania od użytkownika, rozbicie go na mniejsze kroki i rozdzielenie pracy do odpowiednich subagentów.

Nie ma tu miejsca na samowolkę. Jeśli zadanie dotyczy nowego modułu API, Orchestrator nie próbuje go tworzyć – zleca zadanie inżynierowi backendu, po czym czeka na wynik i dopiero wtedy decyduje o kolejnych krokach.

Osiem ról do konkretnych zadań

Każdy z ośmiu subagentów ma ściśle zdefiniowaną rolę, własny zestaw instrukcji systemowych oraz osobne narzędzia:

  • Frontend Engineer – buduje interfejsy w React lub Next.js, dba o style i stan aplikacji.
  • Backend Engineer – tworzy punkty końcowe API, schematy baz danych, uwierzytelnianie i logikę serwerową.
  • Research Engineer – przeszukuje sieć, analizuje dokumentację bibliotek i pobiera dane przez narzędzia scrapujące.
  • QA Engineer – pisze i uruchamia testy jednostkowe oraz integracyjne, weryfikując pokrycie kodu.
  • Write Engineer – zajmuje się wyłącznie dokumentacją techniczną, plikami README i przewodnikami dla programistów.
  • Blogger – przygotowuje treści na bloga i do mediów społecznościowych, pilnując m.in. zasady, by grafika wyróżniająca nie dublowała się wewnątrz treści.
  • Reviewer – przeprowadza audyt bezpieczeństwa pod kątem luk OWASP, wycieków sekretów i jakości kodu.
  • DevOps – odpowiada za potoki CI/CD, konteneryzację w Dockerze, wersjonowanie i publikację wydań.

Twarde bezpieczeństwo i model najmniejszych uprawnień

Największym problemem agentów AI pozostaje kwestia bezpieczeństwa. Model, który ma nieograniczony dostęp do powłoki systemowej, wcześniej czy później popełni błąd. Dlatego w plikach konfiguracyjnych agentów zastosowałem zasadę najmniejszych uprawnień.

Agenci programistyczni (Frontend i Backend) mogą edytować pliki i uruchamiać procesy deweloperskie, ale mają zablokowane operacje na repozytorium Gita. Z kolei agenci dokumentacyjni (Write i Blogger) mogą modyfikować wyłącznie pliki z rozszerzeniem Markdown, a ich dostęp do basha jest ograniczony do minimum.

Jedynym agentem, który ma uprawnienia do tworzenia rewizji, tagowania wydań i wypychania zmian do serwera, jest DevOps. Zanim jednak kod do niego trafi, musi przejść przez weryfikację Reviewera i testy u inżyniera QA. Taki łańcuch eliminuje sytuacje, w których niesprawdzony lub zepsuty kod ląduje w głównym drzewie projektu.

Plik stanu zamiast puchnącego kontekstu

Przekazywanie całej historii rozmowy między tyloma agentami błyskawicznie zapchałoby okno kontekstowe i wygenerowało ogromne koszty. Zamiast tego zastosowałem mechanizm oparty o plik WORKFLOW_STATE.md.

Orchestrator zapisuje w nim aktualny stan prac, listę zadań i statusy wykonania. Każdy subagent na początku swojej tury odczytuje ten plik, wykonuje przydzielony fragment, aktualizuje stan i oddaje sterowanie. Historia czatu nie jest jedynym źródłem prawdy, dzięki czemu kontekst każdego modelu pozostaje czysty i skupiony wyłącznie na bieżącym zadaniu.

Routing przez OmniRoute i wyjątek dla OpenAI

Każda rola korzysta z modelu najlepiej dopasowanego do jej specyfiki. Odpowiada za to skonfigurowany w homelabie router OmniRoute, do którego OpenCode odpytuje dedykowane profile (np. omniroute/agent-backend czy omniroute/agent-reviewer). Pod spodem router dobiera odpowiednie zestawy modeli, realizuje kompresję tokenów i obsługuje automatyczne przekierowania w razie niedostępności dostawcy.

Wyjątek zrobiłem dla OpenAI. Klucze do tego dostawcy są skonfigurowane w OpenCode bezpośrednio, z pominięciem lokalnego routera. Wynika to z warunków świadczenia usług (ToS) OpenAI – bezpośrednie połączenie z oficjalnego punktu końcowego eliminuje ryzyko uznania ruchu za podejrzany i blokady konta. Służy u mnie przede wszystkim jako niezależny, awaryjny model zapasowy w regułach wtyczki fallbackowej.

Lokalne Forgejo przez protokół MCP

Większość gotowych rozwiązań agentowych zakłada korzystanie z GitHuba. W moim homelabie serwerem kontroli wersji jest instancja Forgejo (repo.noop.re). Agenci komunikują się z nią lokalnie przez protokół kontekstowy MCP (Model Context Protocol). Zbudowane obrazy kontenerów trafiają bezpośrednio do prywatnego rejestru, a potoki testowe wykonują się w lokalnych Forgejo Actions. Całe środowisko wytwórcze działa u mnie, w obrębie własnej sieci.

Szablon do powielania

Całą tę architekturę zamknąłem w szablonie oc-agents-orchestrator. Skrypt inicjalizacyjny tworzy nowy projekt z kompletem zdefiniowanych agentów, reguł uprawnień i potoków CI w kilka sekund, a skrypt synchronizujący pozwala aktualizować konfiguracje we wszystkich projektach, gdy reguły agentów ewoluują.