Rozwój systemów rozproszonych z AI
Rozwój systemów rozproszonych z agentami AI zaczyna się od kontraktu: najpierw zmienia się kontrakt OpenAPI lub AsyncAPI, a dopiero potem kod, i każdą zmianę sprawdza automat. Claude Code, Codex i Cursor budują potem po jednym kroku sagi, jednym konsumencie albo jednej wersji schematu naraz, a każdy z nich zamyka test kontraktu, test kompensacji albo ślad, który przechodzi przez wszystkie przeskoki.
Dodajesz jedno pole do API order-service i trzy inne usługi zaczynają zwracać 500 na stagingu. Ślad urywa się po dwóch przeskokach, bo konsument Kafki nie przekazał kontekstu śledzenia, a saga płatności pominęła zwrot środków. Agent, którego prowadziłeś, widział tylko otwarte repozytorium, więc potraktował order-service jak samodzielną aplikację.
Ten przewodnik jest dla programistów, którzy odpowiadają za jedną usługę w systemie złożonym z wielu repozytoriów, oraz dla tech leadów, którzy muszą sprawić, żeby zmiany agenta na granicach usług dało się bezpiecznie scalać. Zakłada, że piszesz specyfikację przed promptem; jeśli nie, zacznij od spec-driven development.
Co daje praca agenta od kontraktu
Dział zatytułowany „Co daje praca agenta od kontraktu”- Sekcję integracyjną do
CLAUDE.md,AGENTS.mdalbo reguły projektu w Cursorze, która mówi agentowi pracującemu w jednym repozytorium, jakich kontraktów ma przestrzegać - Pięciokrokową pętlę zmiany granicy usługi, w której każdy krok kończy się kontrolą głośno sygnalizującą błąd
- Prompty do skopiowania: endpoint od kontraktu, krok sagi z kompensacją, konsument zachowujący ślad, migracja schematu z podwójną publikacją i plan zmian w wielu repozytoriach
- Bramki CI, dzięki którym scalasz zmianę agenta między usługami bez czytania każdej linii: lint kontraktu, testy kontraktowe, testy kompensacji i test ciągłości śladu
- Zweryfikowane serwery MCP (Sentry, Grafana, Kubernetes), dzięki którym agent czyta żywą telemetrię zamiast zgadywać
- Procedury naprawcze dla urwanych śladów, osieroconego stanu sagi, dryfu kontraktu i podrobionych pakietów MCP
Dlaczego agent psuje usługi, których nie widzi?
Dział zatytułowany „Dlaczego agent psuje usługi, których nie widzi?”Mikrousługi dzielą jeden system między repozytoria, języki i zespoły. Agent wczytuje jedno repozytorium, więc jego domyślne założenie, że ta usługa działa samodzielnie, jest błędne dokładnie tam, gdzie psuje się produkcja. Rozwiązanie: trzymaj kontrakty wewnątrz każdego repozytorium (katalog contracts/, submoduł Git albo opublikowany pakiet) i wymień je w pliku, który agent zawsze czyta.
Dodaj sekcję integracyjną do CLAUDE.md. Claude Code czyta też AGENTS.md, gdy w repozytorium nie ma CLAUDE.md (od v2.1.277 w kanale latest), więc jeden wspólny plik może obsłużyć Claude Code i Codeksa.
## Service boundaries (order-service)Contracts live in contracts/ and are the source of truth:- contracts/payment-api.yaml (OpenAPI 3.1): payment-service REST API- contracts/inventory-events.yaml (AsyncAPI): events we consume- contracts/order-events.yaml (AsyncAPI): events we publish
Rules:- Never hand-write an HTTP client. Regenerate with `npm run generate-clients`.- Change the contract first, in its own commit, and stop for review.- Every consumer extracts trace context from message headers; every producer injects it.- Every saga step ships with a compensation and a test that triggers it.- Run `npm run contracts:check` and `npm test` before you say a task is done.Umieść tę samą sekcję w AGENTS.md w katalogu głównym repozytorium. Codex wczytuje go na starcie każdego zadania w zaufanym projekcie (od 0.150.0 niezaufany projekt go nie dostarcza). Wymień repozytoria sąsiednie, żeby plan zmiany między usługami mógł wskazać, które z nich wymagają kolejnych pull requestów:
## Related services- org/payment-service, org/inventory-service, org/notification-service- Shared contracts: org/service-contracts (vendored into contracts/)When a change touches a contract, list every downstream service that must change and in which order.Utwórz regułę projektu stosowaną zawsze, z tą samą treścią co w zakładce Claude Code, a gdy zadanie dotyczy konkretnej granicy, wskaż kontrakt w czacie przez @contracts/payment-api.yaml. Format pliku reguły i jej zakres opisuje strona reguły projektu w Cursorze.
Jak zmienić granicę usługi z pomocą agenta?
Dział zatytułowany „Jak zmienić granicę usługi z pomocą agenta?”Każda zmiana granicy przechodzi tę samą pętlę. Każdy krok kończy się kontrolą, którą uruchamiasz, a nie diffem, który czytasz.
- Zmień kontrakt i nic poza nim. Agent edytuje
contracts/*.yamlw osobnym commicie i się zatrzymuje. Przeglądasz krótki diff YAML-a zamiast kodu handlerów zbudowanego na jego podstawie. - Zabezpiecz kontrakt bramką. CI lintuje specyfikację i uruchamia testy kontraktowe dla każdego konsumenta, więc zmiana łamiąca zgodność pada, zanim ktokolwiek ją zaimplementuje.
- Generuj, a potem implementuj pod testy. Klienci i szkielety serwera powstają z kontraktu; agent pisze logikę biznesową, dopóki padające testy nie przejdą.
- Udowodnij ścieżkę w czasie działania. Test ciągłości śladu, a dla sag test kompensacji, pokazują, że zmiana działa przez cały przeskok, a nie tylko wewnątrz usługi.
- Wdrażaj w zgodnych krokach. Producenci i konsumenci wdrażają się niezależnie, więc stary i nowy format muszą być jednocześnie poprawne, dopóki metryka nie pokaże, że przeszli wszyscy konsumenci.
Zmień kontrakt przed kodem
Dział zatytułowany „Zmień kontrakt przed kodem”Zatrzymanie w kroku 4 to sedno tego promptu. Przegląd kontraktu jest krótki i przesądza o wszystkim dalej; przegląd handlera jest długi i przesądza o niewielu rzeczach.
Wyłap dryf kontraktu w CI
Dział zatytułowany „Wyłap dryf kontraktu w CI”Większość dryfu, zanim trafi na staging, łapią dwie kontrole: linter specyfikacji przy każdej zmianie kontraktu oraz testy kontraktowe sterowane przez konsumenta w Pact (@pact-foundation/pact w npm, 17.1.4 na 2026-09-26), uruchamiane w potoku zarówno konsumenta, jak i dostawcy. Połącz je w jeden skrypt, żeby agent i CI uruchamiały to samo polecenie:
{ "scripts": { "contracts:check": "spectral lint contracts/*-api.yaml && asyncapi validate contracts/order-events.yaml && npm run test:pact" }}spectral pochodzi z @stoplight/spectral-cli i wymaga pliku .spectral.yaml w katalogu głównym repozytorium (minimum to extends: ["spectral:oas"]); asyncapi pochodzi z @asyncapi/cli. Gdy ręcznie poprawiany klient i tak się rozjedzie, poproś o audyt, który daje dowody, a nie zapewnienia:
Jak zbudować krok sagi, któremu można zaufać?
Dział zatytułowany „Jak zbudować krok sagi, któremu można zaufać?”Saga to miejsce, w którym kod rozproszony napisany przez agenta najczęściej wygląda dobrze, a działa źle. Scenariusz pozytywny (happy path) działa; kompensacji brakuje, wykonuje się dwa razy albo nie ma limitu czasu. Buduj po jednym kroku i każ agentowi napisać test wyzwalający kompensację przed kodem, który ją wykonuje.
To, jak utrzymać tę pętlę krótką, zależy od narzędzia:
Dodaj hook PostToolUse do .claude/settings.json, żeby zestaw testów sagi uruchamiał się po każdej edycji, a regresja we wcześniejszym kroku wychodziła w tej samej turze. To kod wyjścia 2 przekazuje błąd z powrotem do Claude; każdy inny niezerowy kod tylko pokazuje wynik tobie:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "npm test -- saga --silent 1>&2 || exit 2" }] } ] }}Projektowanie hooków i ich koszt opisuje strona hooki agenta.
Prowadź pracę nad sagą w osobnym zarządzanym worktree, z wbudowanym profilem uprawnień :workspace (w wersji beta w Codeksie 0.157.1; zapis tylko w obrębie checkoutu). Najpierw zapisz powyższy prompt sagi jako docs/saga-step.md:
codex --worktree -c default_permissions=':workspace' \ "Implement the reserve-inventory saga step per the prompt in docs/saga-step.md. Run npm test -- saga after each change."Wklej prompt do Agenta w repozytorium usługi i pozwól mu uruchamiać npm test -- saga w terminalu. Każdy krok sagi prowadź w osobnym worktree (izolowanym checkoucie Git w Cursorze), żeby zła kompensacja nie mieszała się z ukończonym krokiem. W diffie najpierw patrz na plik testu: agent, który osłabił asercję, to błąd, który masz wyłapać.
Jak zachować kontekst śladu przez asynchroniczne przeskoki?
Dział zatytułowany „Jak zachować kontekst śladu przez asynchroniczne przeskoki?”Powracający błąd produkcyjny w przepływach opartych na zdarzeniach to ślad, który się urywa: konsument czyta wiadomość z Kafki, ale nie wyciąga kontekstu śledzenia z nagłówków, więc każdy kolejny span zaczyna nowy ślad. Zrób z propagacji wymaganie sprawdzane testem, a nie uwagę w prompcie.
Zinstrumentuj jedną usługę od początku do końca, zanim zrobisz z tego szablon. Poproś agenta o dodanie automatycznej instrumentacji OpenTelemetry (@opentelemetry/sdk-node z @opentelemetry/auto-instrumentations-node) do jednej usługi, eksport przez OTLP do lokalnego Jaegera, wysłanie jednego żądania i podanie identyfikatora śladu, który masz znaleźć. Gdy ślad pojawi się razem z własnym spanem, ten sam moduł staje się wspólnym pakietem importowanym przez pozostałe usługi. Stronę operacyjną, czyli dashboardy i alerty, opisuje monitorowanie i obserwowalność.
Jak zmienić schemat zdarzenia, nie psując konsumentów?
Dział zatytułowany „Jak zmienić schemat zdarzenia, nie psując konsumentów?”Format danych przekraczający granicę usługi zmienia się sekwencją, a nie jednym commitem. Oba formaty pozostają poprawne, dopóki metryka, a nie założenie, nie pokaże, że przeszli wszyscy konsumenci.
- Dodaj nową wersję schematu obok starej w kontrakcie.
- Wdróż konsumentów, którzy akceptują obie wersje.
- Wdróż producenta publikującego obie wersje (albo nową wersję z zachowanymi starymi polami).
- Obserwuj metrykę dla każdego konsumenta pokazującą, którą wersję czyta każda usługa, aż stara spadnie do zera.
- Przestań publikować starą wersję, a potem usuń ją z kontraktu.
Jak skoordynować jedną funkcję w kilku repozytoriach?
Dział zatytułowany „Jak skoordynować jedną funkcję w kilku repozytoriach?”Funkcja taka jak punkty lojalnościowe dotyka customer, order, payment i notification. Najpierw, w jednej sesji planowania, poproś o kontrakty i kolejność zależności, a potem uruchom po jednym ograniczonym zadaniu implementacyjnym na repozytorium.
Po zatwierdzeniu kontraktów narzędzia rozdzielają pracę na różne sposoby. W pętlach Claude Code i Codeksa ../contracts to lokalny checkout współdzielonego repozytorium kontraktów (org/service-contracts) z zatwierdzonymi zmianami w loyalty/, leżący obok repozytoriów usług:
Prowadź każde repozytorium w trybie headless, z dostępem do narzędzi zawężonym do tego, czego wymaga zadanie:
for svc in customer order payment notification; do (cd "../$svc-service" && claude -p \ "Implement the loyalty-points changes for this service per ../contracts/loyalty/. Add or update the Pact tests the plan lists. Run npm run contracts:check and npm test; stop and report if either fails." \ --add-dir ../contracts \ --allowedTools "Read" "Edit" "Write" "Bash(npm test:*)" "Bash(npm run contracts:check)" \ --disallowedTools "Edit(../contracts/**)" "Write(../contracts/**)")done--add-dir daje agentowi dostęp narzędzi do ../contracts, a dozwolone Edit i Write działałyby także tam. Reguły --disallowedTools blokują zapis do zatwierdzonych kontraktów, a reguły odmowy mają pierwszeństwo przed regułami zezwolenia. Regułę CODEOWNERS albo kontrolę CI w repozytorium kontraktów zachowaj jako zabezpieczenie awaryjne i odrzucaj każde uruchomienie, które ich dotknie.
Uruchom po jednym nieinteraktywnym zadaniu na repozytorium z profilem uprawnień :workspace. Nie ma tu --add-dir: w Codeksie ta flaga daje prawo zapisu do katalogu, a kontrakty trzeba tylko czytać, więc zatwierdzone kontrakty zostają poza zasięgiem zmian agenta:
for svc in customer order payment notification; do codex -a never exec -C "../$svc-service" \ -c default_permissions=':workspace' \ "Implement the loyalty-points changes for this service per ../contracts/loyalty/. Add or update the Pact tests the plan lists. Run npm run contracts:check and npm test; stop and report if either fails."doneŻeby uruchomić zadania zdalnie, użyj zadań w chmurze Codeksa (codex cloud, eksperymentalne w 0.157.1), po jednym na repozytorium.
Uruchom osobnego agenta w chmurze (Cloud Agent) dla każdego repozytorium, z zatwierdzonym planem jako promptem, tak żeby zmianę w każdym repozytorium przeglądać osobno. Implementuj w kolejności zależności z planu i nie zaczynaj konsumenta, dopóki testy kontraktowe dostawcy nie są zielone. Konfigurację specyficzną dla Cursora opisuje strona praca z wieloma repozytoriami w Cursorze. Wzorce mikrousług specyficzne dla Cursora opisuje strona mikrousługi w Cursorze.
Przy więcej niż kilku repozytoriach zajrzyj do wzorców orkiestracji: rozdzielanie zadań, ponowienia i kolejność scalania.
Które serwery MCP dają agentowi żywą telemetrię?
Dział zatytułowany „Które serwery MCP dają agentowi żywą telemetrię?”Agent, który może odpytać błędy, metryki i stan klastra, wnioskuje z dowodów, a nie z twojego zrzutu ekranu. W pracy deweloperskiej trzymaj te serwery w trybie tylko do odczytu: agent bada, a produkcję zmieniasz ty albo CI.
| Serwer | Co daje agentowi | Pakiet lub endpoint (sprawdzone 2026-09-26) |
|---|---|---|
| Sentry (oficjalny) | Zgłoszenia, zdarzenia, ślady, wydania | Zdalny https://mcp.sentry.dev/mcp (OAuth); @sentry/mcp-server 0.42.0 dla Sentry hostowanego u siebie |
| Grafana (oficjalny) | Dashboardy, zapytania do Prometheusa i Loki, incydenty | PyPI mcp-grafana 1.6.3 (uvx mcp-grafana) albo Docker grafana/mcp-grafana; --disable-write włącza tryb tylko do odczytu |
Kubernetes (społecznościowy, organizacja containers) | Pody, logi, zdarzenia we wszystkich kontekstach kubeconfig | npm kubernetes-mcp-server 0.0.67; ustawienia takie jak read_only = true trafiają do pliku TOML przekazanego przez --config |
Aby serwer Kubernetes działał tylko do odczytu i udostępniał wyłącznie podstawowe narzędzia, zapisz te dwie linie jako ~/.config/k8s-mcp.toml:
read_only = truetoolsets = ["core"]claude mcp add --transport http sentry https://mcp.sentry.dev/mcpclaude mcp add grafana -e GRAFANA_URL="$GRAFANA_URL" \ -e GRAFANA_SERVICE_ACCOUNT_TOKEN="$GRAFANA_SERVICE_ACCOUNT_TOKEN" \ -- uvx mcp-grafana --disable-writeclaude mcp add kubernetes -- npx -y kubernetes-mcp-server@latest --config ~/.config/k8s-mcp.tomlcodex mcp add sentry --url https://mcp.sentry.dev/mcp && codex mcp login sentrycodex mcp add grafana --env GRAFANA_URL="$GRAFANA_URL" \ --env GRAFANA_SERVICE_ACCOUNT_TOKEN="$GRAFANA_SERVICE_ACCOUNT_TOKEN" \ -- uvx mcp-grafana --disable-writecodex mcp add kubernetes -- npx -y kubernetes-mcp-server@latest --config ~/.config/k8s-mcp.tomlDodaj serwery w ustawieniach MCP Cursora, w kształcie JSON mcpServers. Zdalny serwer Sentry potrzebuje tylko adresu URL; Grafana i Kubernetes dostają to samo polecenie i argumenty co w wierszach Claude Code, a ${env:NAZWA} czyta każdą wartość ze zmiennej środowiskowej:
{ "mcpServers": { "sentry": { "url": "https://mcp.sentry.dev/mcp" }, "grafana": { "command": "uvx", "args": ["mcp-grafana", "--disable-write"], "env": { "GRAFANA_URL": "${env:GRAFANA_URL}", "GRAFANA_SERVICE_ACCOUNT_TOKEN": "${env:GRAFANA_SERVICE_ACCOUNT_TOKEN}" } }, "kubernetes": { "command": "npx", "args": ["-y", "kubernetes-mcp-server@latest", "--config", "~/.config/k8s-mcp.toml"] } }}Gdzie leży ten plik i jak przekazać zmienne środowiskowe, opisuje konfiguracja MCP w Cursorze.
Skąd wiesz, że zmiana działa, jeśli nie czytasz każdego diffu?
Dział zatytułowany „Skąd wiesz, że zmiana działa, jeśli nie czytasz każdego diffu?”Każde ryzyko w zmianie rozproszonej ma kontrolę, która zawodzi samodzielnie. Diff czytasz tylko w kontrakcie i plikach testów; resztę udowadniają bramki.
| Ryzyko | Kontrola, która to udowadnia | Gdzie działa | Kto zatwierdza |
|---|---|---|---|
| Zmiana API lub zdarzenia łamiąca zgodność | contracts:check: lint specyfikacji plus testy Pact w potokach konsumenta i dostawcy | Każdy PR | Właściciel usługi zatwierdza commit z kontraktem |
| Klient rozjechany z kontraktem | Generowani klienci i tabela audytu kontraktu opisana wyżej | Każdy PR | CI (build pada) |
| Brakująca lub podwójna kompensacja | Test dla każdego kroku sagi, który wstrzykuje błąd w kolejnym kroku i sprawdza kompensację dokładnie raz | Każdy PR | Autor; recenzent sprawdza, że test istnieje i pada bez kodu |
| Urwany ślad na przeskoku | Test ciągłości śladu ze znanym traceparent | Każdy PR konsumentów i producentów | CI |
| Konsumenci wciąż na starym schemacie | Licznik schema_version dla każdego konsumenta | Staging i produkcja | Tech lead zatwierdza usunięcie starej wersji |
| Złe wdrożenie | Canary z automatycznym wycofaniem, gdy rośnie odsetek błędów lub opóźnienie | Potok wdrożeniowy | CI; próg ustala dyżurny |
Test potwierdzający kompensację jest tyle wart, ile jego asercja, więc wymagaj od agenta pokazania przebiegu padającego przed zielonym. Jak ufać testom, których nie czytałeś, opisuje strona siła wyroczni; bramki wdrożenia – progressive delivery.
Co się psuje w systemach rozproszonych budowanych przez agenta?
Dział zatytułowany „Co się psuje w systemach rozproszonych budowanych przez agenta?”- Ślad urywa się na granicy asynchronicznej. Żądanie pokazuje w Jaegerze dwa przeskoki, a potem znika. Konsument nie wyciągnął kontekstu śledzenia z nagłówków wiadomości. Znajdź w konsumencie odczyt nagłówków, dodaj go promptem o konsumencie zachowującym ślad i zachowaj test, który sprawdza ten sam
traceIdpo obu stronach. Nie akceptuj „dodałem tracing” bez tego testu. - Saga zostawia osierocony stan. Płatność przeszła, a rezerwacja magazynowa nigdy nie została zwolniona. Odtwórz problem, wstrzykując błąd w kroku po tym, który podejrzewasz, i sprawdź, że kompensacja wykonuje się dokładnie raz. Zbuduj ten krok od nowa promptem „najpierw padający test”.
- Agent traktuje usługę jak samodzielną. Wygenerowany kod wymyśla kształt endpointu albo pomija konwencje ponowień i dead-letter. W repozytorium brakuje sekcji integracyjnej w
CLAUDE.md,AGENTS.mdalbo regule Cursora; dodaj ją i wymień pliki kontraktów, zanim obwinisz model. - Agent zalicza test, osłabiając go. Obok poprawki pojawia się zmieniony
expect, nowyskipalbo wydłużony timeout. Chroń testy kontraktów i sag przed edycją przez agenta (reguła CODEOWNERS albo hook blokujący zapis) i zajrzyj do ochrony wyroczni. - Zmiana kontraktu psuje konsumentów na produkcji. Pominięto fazę podwójnej publikacji. Wycofaj producenta, publikuj obie wersje i usuń starą dopiero wtedy, gdy jej licznik konsumentów pokazuje zero.
- Projekt to rozproszony monolit. Dwie usługi piszą do tej samej tabeli albo trzy muszą wdrażać się razem. Agenci nie zgłaszają tego sami. Zapytaj: „List every place two services share a database, a write path, or a lockstep deploy” i rozwiąż te miejsca, zanim zaczniesz dalej dzielić system. Projektowanie granic opisuje domain-driven design z AI.
- Serwer MCP się łączy, ale nic nie zwraca. Brakuje tokenu albo token wygasł, nazwa zmiennej środowiskowej jest błędna (
GRAFANA_SERVICE_ACCOUNT_TOKEN, a nie przestarzałyGRAFANA_API_KEY) albo logowanie OAuth do Sentry nie zostało dokończone. Uruchomclaude mcp listlubcodex mcp list, powtórz logowanie, a jeślinpm viewpokazuje nieznanego wydawcę, zainstalowałeś podróbkę.
Dokąd dalej z mikrousługami
Dział zatytułowany „Dokąd dalej z mikrousługami”- Wzorce testów integracyjnych: testy kontraktowe i kontrole granic usług bez kruchych mocków
- Tworzenie API z AI: projektowanie i rozwijanie API pojedynczej usługi, które opisują te kontrakty
- Monitorowanie i obserwowalność: dashboardy, alerty i pętla debugowania przez MCP na produkcji
- Reagowanie na incydenty: dyżur wspierany przez agenta, gdy awaria między usługami cię budzi
- Potoki CI/CD: wpięcie
contracts:checki automatycznego wycofania canary do potoku - Praca z monorepo: alternatywa, gdy możesz trzymać usługi w jednym repozytorium