Przepisy na Python
ENPrzepisy na backend w Pythonie dla agentów AI to prompty i bramki weryfikacyjne, dzięki którym Claude Code, Codex i Cursor tworzą produkcyjne usługi FastAPI i Django: walidowaną konfigurację, schematy Pydantic v2, asynchroniczne SQLAlchemy 2.1 odporne na współbieżność, idempotentne zadania Celery, odporne klienty HTTP i logi z redakcją sekretów. Kod przyjmujesz na podstawie wyników bramek, a nie lektury linijka po linijce.
Twoja usługa FastAPI przechodzi wszystkie testy napisane przez agenta. Potem pierwszy test obciążeniowy zamraża pętlę zdarzeń, bo handler wywołuje requests.get(), zapytanie asynchroniczne rzuca MissingGreenlet na relacji, której nikt nie załadował, a ponowione zadanie Celery obciąża klienta dwa razy. Kod wyglądał idiomatycznie, a testy działały na SQLite z mockami, więc nie miały szansy niczego z tego wyłapać.
Ta strona jest dla programistów, którzy budują backendy w Pythonie z agentem i chcą przestać przeglądać każdy handler wzrokiem. Produkcyjne szczegóły trafiają do promptów, a dowód dostarcza maszyna.
Co dają ci te przepisy na Pythona
Dział zatytułowany „Co dają ci te przepisy na Pythona”- Blok reguł
AGENTS.mddla typowanego, asynchronicznego Pythona, którego przestrzegają wszystkie trzy narzędzia, oraz bramkęmake check, którą agent uruchamia, zanim powie „gotowe” - Osiem promptów do skopiowania: szkielet FastAPI z lifespanem i konfiguracją, walidacja Pydantic v2, asynchroniczne repozytorium SQLAlchemy, które nie sprzeda więcej, niż ma na stanie, idempotentne zadania Celery, klient httpx z timeoutami i ponowieniami, structlog z redakcją, API w Django REST Framework z izolacją tenantów oraz sprzątanie przestarzałych idiomów
- Tabelę weryfikacji, która mówi, która bramka łapie który błąd, więc czytasz wynik bramek zamiast diffa
- Kroki naprawcze dla siedmiu najczęstszych awarii Pythona napisanego przez agenta
Przygotuj konwencje Pythona i bramkę, którą agent musi przejść
Dział zatytułowany „Przygotuj konwencje Pythona i bramkę, którą agent musi przejść”Większość pracy wykonują dwa artefakty: plik reguł, który agent czyta przy każdym zadaniu, i jedno polecenie, które kończy się błędem, gdy kod nie jest gotowy. Przygotuj oba, zanim poprosisz o jakikolwiek kod.
-
Przypnij interpreter i narzędzia. Aktualną stabilną linią jest Python 3.14, a PEP 790 planuje wydanie Pythona 3.15.0 na 2026-10-01. Zostań przy 3.14, dopóki twoje zależności nie zadeklarują wsparcia dla 3.15. Z uv (terminal):
Okno terminala uv python pin 3.14uv add fastapi "pydantic-settings" "sqlalchemy[postgresql-asyncpg]" alembic structlog httpxuv add --dev pytest pytest-asyncio pytest-cov "testcontainers[postgres]" respx ruff mypyAktualne wydania na PyPI 2026-09-26:
fastapi0.141.1,pydantic2.13.5,pydantic-settings2.15.0,sqlalchemy2.1.1,alembic1.20.0,pytest9.1.1,pytest-asyncio1.4.0,ruff0.16.9,mypy2.3.1,testcontainers4.15.0,celery5.6.3,django6.1.1. Dodatek[postgresql-asyncpg]ma znaczenie: SQLAlchemy 2.1 nie instaluje już domyślniegreenlet, a rozszerzenie asynchroniczne bez niego nie działa. -
Skonfiguruj narzędzia w
pyproject.toml. Najwięcej łapią dwa ustawienia: regułyASYNCwskazują blokujące wywołania wewnątrzasync def, afilterwarnings = ["error"]zamienia każde ostrzeżenie o deprecjacji, w tym idiomy z Pydantic v1, w nieudany test.[tool.ruff]target-version = "py314"[tool.ruff.lint]select = ["E", "F", "I", "B", "UP", "ASYNC", "S", "RUF"][tool.ruff.lint.per-file-ignores]"tests/**" = ["S101"][tool.mypy]strict = trueplugins = ["pydantic.mypy"][tool.pytest.ini_options]asyncio_mode = "auto"asyncio_default_fixture_loop_scope = "function"filterwarnings = ["error"] -
Dodaj bramkę. To definicja „gotowe” dla każdego promptu na tej stronie. W pliku
Makefile(linie receptury zaczynają się od tabulatora):check:uv run ruff format --check .uv run ruff check .uv run mypy appuv run pytest --cov=app --cov-fail-under=80uv export --locked --no-dev --no-emit-project --format requirements.txt -o .audit.txtuvx pip-audit --disable-pip -r .audit.txtDwie ostatnie linie audytują zablokowane zależności runtime bez ich instalowania. Dodaj
.audit.txtdo.gitignore. -
Zapisz reguły Pythona w
AGENTS.mdw katalogu głównym repozytorium. Codex czytaAGENTS.mdnatywnie; zakładki niżej pokazują, jak ten sam tekst trafia do Claude Code i Cursora.## Python conventions- Python 3.14, uv, fully typed. mypy --strict must pass; no bare `Any`,no `# type: ignore` without a reason in the same comment.- Pydantic v2 only: model_config = ConfigDict(...), @field_validator,@model_validator, model_dump(). Never class Config, @validator, or .dict().- Settings come from one pydantic-settings class in app/core/config.py.No os.getenv or os.environ anywhere else.- Inside async def: no requests, no time.sleep, no sync SQLAlchemy sessions,no blocking file I/O. Use httpx.AsyncClient, asyncio.sleep, AsyncSession.- SQLAlchemy 2.x style: select(), Mapped[], mapped_column(). Relationshipsuse lazy="raise"; load them explicitly with selectinload().- Every outbound HTTP call has an explicit timeout.- Tests: pytest with pytest-asyncio in auto mode. Database tests useTestcontainers Postgres, not SQLite and not mocks.- Never edit an existing test assertion, add pytest.mark.skip or xfail, orloosen filterwarnings to make a test pass. If a test looks wrong, stop andsay why.- Done means `make check` passes. Paste its last 20 lines in your final message.
Najważniejsze są dwie ostatnie reguły. Pierwsza nie pozwala agentowi osłabiać testów, żeby dojść do zielonego wyniku; strona chroń wyrocznię wyjaśnia, dlaczego to najczęstszy sposób, w jaki praca agenta udaje sukces. Druga zamienia „chyba działa” w dowód, który przeczytasz w dziesięć sekund.
Podłącz reguły i bramkę w każdym narzędziu
Dział zatytułowany „Podłącz reguły i bramkę w każdym narzędziu”Reguły i prompty są identyczne we wszystkich narzędziach. Różni się to, jak każde narzędzie wczytuje reguły, formatuje zmiany i recenzuje wynik.
Claude Code czyta najpierw CLAUDE.md, więc utwórz plik, który importuje wspólne reguły. Składnia @path wstawia zawartość pliku do kontekstu przy starcie:
@AGENTS.mdFormatuj i automatycznie poprawiaj każdy plik Pythona edytowany przez agenta hookiem PostToolUse w .claude/settings.json:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "jq -r '.tool_input.file_path' | grep -E '\\.py$' | xargs -r sh -c 'uv run ruff format \"$@\" && uv run ruff check --fix \"$@\"' _" } ] } ] }}Przejście do definicji i diagnostykę typów daje agentowi wtyczka pyright-lsp z oficjalnego marketplace’u Anthropic. Wtyczka rejestruje tylko serwer, więc najpierw zainstaluj Pyright (terminal):
uv tool install pyrightclaude plugin install pyright-lsp@claude-plugins-officialZanim otworzysz pull request, uruchom w sesji /code-review, żeby dostać drugą opinię o diffie.
Codex czyta AGENTS.md bezpośrednio, więc żaden dodatkowy plik nie jest potrzebny. Uruchom zadanie z zapisem w obszarze roboczym i pytaniem o zgodę na wszystko szersze (terminal):
codex -s workspace-write -a on-request "Implement POST /api/v1/orders as described in docs/tasks/orders.md. Done means make check passes."Przed wypchnięciem zrecenzuj gałąź względem main:
codex review --base mainUtwórz regułę projektu w ustawieniach Rules Cursora z tą samą listą, ograniczoną do plików *.py, żeby agent wczytywał ją przy każdej pracy z Pythonem. Przy wieloplikowych promptach z tej strony używaj Plan Mode, żeby zatwierdzić listę plików, zanim powstanie jakikolwiek kod. Niezależne przepisy uruchamiaj w Worktrees, a pull request daj do recenzji Bugbotowi.
Zacznij w każdym narzędziu od domyślnego modelu i najpierw zwiększ ustawienie effort, a dopiero potem zmień model; aktualne domyślne modele znajdziesz w hubie modeli.
Daj agentowi aktualną dokumentację bibliotek
Dział zatytułowany „Daj agentowi aktualną dokumentację bibliotek”Stos Pythona z tej strony zmienił się szybciej niż większość danych treningowych: FastAPI porzuciło wsparcie pydantic.v1 w wersji 0.128.0 (2025-12-27), pytest-asyncio 1.0 usunęło fixture event_loop, a SQLAlchemy 2.1 zmieniło sposób instalacji wsparcia async. Serwer MCP Context7 dostarcza agentowi dokumentację dla konkretnych wersji. Klucz API jest opcjonalny, więc wystarczy sam zdalny URL (terminal):
claude mcp add --transport http context7 https://mcp.context7.com/mcpcodex mcp add context7 --url https://mcp.context7.com/mcpDodaj serwer o nazwie context7 z adresem https://mcp.context7.com/mcp w .cursor/mcp.json albo w ustawieniach MCP Cursora.
Potem zakończ prompt słowami „use context7 for SQLAlchemy 2.1 and pytest-asyncio 1.x”. Każdy serwer MCP dokłada do kontekstu definicje swoich narzędzi, więc podłączaj go w projektach, które go potrzebują, a nie globalnie.
Zbuduj produkcyjną usługę FastAPI z agentem, krok po kroku
Dział zatytułowany „Zbuduj produkcyjną usługę FastAPI z agentem, krok po kroku”Każdy krok to jeden prompt i sprawdzenie, które go dowodzi. Wykonuj je po kolei: późniejsze prompty zakładają, że szkielet, moduł konfiguracji i moduł bazy danych już istnieją.
Jak postawić usługę FastAPI, która czysto startuje i się zamyka?
Dział zatytułowany „Jak postawić usługę FastAPI, która czysto startuje i się zamyka?”Najczęstsze braki w pierwszym podejściu to walidacja przy starcie i zamykanie. Agent czyta zmienne środowiskowe tam, gdzie ich potrzebuje, i tworzy silnik bazy danych przy imporcie, więc brakująca zmienna wychodzi jako 500 przy pierwszym żądaniu, a silnik nigdy nie jest zwalniany.
Dobra odpowiedź ma taki rdzeń:
@asynccontextmanagerasync def lifespan(app: FastAPI) -> AsyncIterator[None]: settings = get_settings() engine = create_async_engine(str(settings.DATABASE_URL), pool_pre_ping=True) app.state.sessionmaker = async_sessionmaker(engine, expire_on_commit=False) yield await engine.dispose()Sam ASGITransport nie uruchamia lifespanu, dlatego prompt wymienia LifespanManager (pakiet asgi-lifespan na PyPI). Bez niego testy mogą przechodzić, choć nigdy nie utworzyły silnika, który rzekomo sprawdzają.
Jak dostać walidację Pydantic v2, która precyzyjnie odrzuca złe dane?
Dział zatytułowany „Jak dostać walidację Pydantic v2, która precyzyjnie odrzuca złe dane?”Agenci wytrenowani na latach kodu z Pydantic v1 wciąż piszą class Config, @validator i .dict(). Ustawienie filterwarnings = ["error"] zamienia każdy z tych idiomów w nieudany test, bo Pydantic v2 emituje dla nich ostrzeżenie o deprecjacji.
Asercje na loc i type zamiast na treści komunikatu sprawiają, że testy są stabilne między wydaniami Pydantic, a mimo to padają, gdy zniknie jakaś reguła.
Jak dostać asynchroniczne zapytania SQLAlchemy, które wytrzymają równoległe zamówienia?
Dział zatytułowany „Jak dostać asynchroniczne zapytania SQLAlchemy, które wytrzymają równoległe zamówienia?”Pierwsze podejście agenta do „sprawdź stan, potem zmniejsz” ładuje produkt, porównuje wartości w Pythonie i zapisuje wynik. Dwa równoległe zamówienia czytają stock = 1 i oba się udają. SQLite z jednym połączeniem nie pokaże tego błędu; pokaże go tylko Postgres z równoległymi sesjami.
lazy="raise" zamienia klasyczny błąd async, czyli niejawne leniwe ładowanie, które na produkcji kończy się MissingGreenlet, w natychmiastowy błąd w pierwszym teście, który dotknie relacji. Liczy się też ścieżka importu: w testcontainers 4.15.0 stary moduł testcontainers.postgres emituje ostrzeżenie o deprecjacji, które twoje ustawienie filterwarnings zamienia w porażkę.
Żeby agent czytał prawdziwy schemat zamiast zgadywać nazwy kolumn, podłącz bazodanowy serwer MCP do deweloperskiej bazy przez rolę tylko do odczytu. Przewodnik po bazodanowych serwerach MCP porównuje serwery i ich przełączniki trybu tylko do odczytu. O bezpiecznych migracjach dużych tabel przeczytasz we wzorcach migracji baz danych.
Jak przenieść wolną pracę do Celery bez zdublowanych efektów ubocznych?
Dział zatytułowany „Jak przenieść wolną pracę do Celery bez zdublowanych efektów ubocznych?”Ponowienia w Celery są bezpieczne tylko wtedy, gdy zadanie jest idempotentne. Przy acks_late awaria workera albo zadanie, które trwa dłużej niż visibility timeout brokera Redis, zostaje dostarczone ponownie, a drugie wykonanie powtarza każdy efekt uboczny.
Agent zwykle pomija dwa szczegóły. celery.contrib.pytest nie rejestruje się jako wtyczka pytest automatycznie, więc jego fixture’y nie istnieją, dopóki conftest.py go nie wskaże. A task_always_eager uruchamia zadanie w procesie testu, więc nie pokaże ponownego dostarczenia przez broker ani utraty workera; tryb eager zostaw wyłącznie do testów jednostkowych samej treści zadania. W Django 6 wbudowany framework django.tasks definiuje i kolejkuje zadania, ale do ich wykonania w tle nadal potrzebny jest zewnętrzny backend z workerem; wbudowane backendy wykonują zadania tylko natychmiast albo je odrzucają.
Jak wołać zewnętrzne API bez zamrażania pętli zdarzeń?
Dział zatytułowany „Jak wołać zewnętrzne API bez zamrażania pętli zdarzeń?”Klienty pisane przez agenta psują się na trzy sposoby: synchroniczne wywołanie requests wewnątrz async def, brak timeoutu albo pętla ponowień, która w nieskończoność ponawia 400. Pierwszy przypadek łapią w bramce reguły ASYNC Ruffa; dwa pozostałe załatwia prompt.
Najważniejsze są przypadki „bez ponowienia”. Implementacja, która ponawia wszystko, przechodzi każdy test ścieżki sukcesu, a na produkcji mnoży zwroty pieniędzy.
Jak dostać ustrukturyzowane logi, które nigdy nie ujawniają sekretów?
Dział zatytułowany „Jak dostać ustrukturyzowane logi, które nigdy nie ujawniają sekretów?”Asercja z dwoma równoległymi żądaniami dowodzi, że zmienne kontekstowe są czyszczone i przypisane do jednego żądania. Nieprzetestowany procesor redakcji psuje się po cichu, gdy nazwy kluczy się rozjadą.
Jak utrzymać izolację tenantów w API Django REST Framework?
Dział zatytułowany „Jak utrzymać izolację tenantów w API Django REST Framework?”W wielodostępnej aplikacji Django groźny błąd to jeden viewset, który zapomina filtrować po organizacji. Przechodzi każdy test pisany z perspektywy właściciela.
Test przechodzący po wszystkich trasach to bramka, która się skaluje: gdy agent za miesiąc doda nowy viewset i zapomni o mixinie, zestaw testów padnie, zanim ktokolwiek przeczyta nowy plik.
Jak posprzątać przestarzałe idiomy Pythona, które agent wciąż przywraca?
Dział zatytułowany „Jak posprzątać przestarzałe idiomy Pythona, które agent wciąż przywraca?”Uruchom ten prompt raz na istniejącym kodzie, zanim zaczniesz przepisy, i ponownie za każdym razem, gdy bramka deprecjacji zrobi się czerwona po aktualizacji zależności.
Jak zweryfikować Python napisany przez agenta bez czytania każdej linii?
Dział zatytułowany „Jak zweryfikować Python napisany przez agenta bez czytania każdej linii?”Czytaj wynik bramek i listy przypadków testowych, nie diff. Każda bramka poniżej łapie klasę błędów, która w recenzji wygląda dobrze.
| Bramka | Polecenie | Co łapie |
|---|---|---|
| Format i lint | ruff format --check, ruff check z ASYNC, S, B, UP | Blokujące wywołania w async def, zaszyte sekrety, SQL sklejany ze stringów, przestarzałą składnię |
| Typy | mypy --strict z wtyczką Pydantic | Niezgodne kształty danych między warstwami, nieobsłużone None, brakujące await na typowanych korutynach |
| Deprecjacje | filterwarnings = ["error"] | Idiomy Pydantic v1, usunięte wzorce pytest-asyncio, przestarzałe importy |
| Testy jednostkowe i HTTP | pytest z httpx.AsyncClient i respx | Kody statusu, treść błędów, walidację, ponowienia, redakcję |
| Testy integracyjne | Testcontainers z Postgresem i Redisem | Wyścigi, np. sprzedaż ponad stan, brakujące ograniczenia, ponownie dostarczone zadania Celery, wycieki między tenantami |
| Próg pokrycia | pytest --cov-fail-under=80 | Całe moduły, których agent nie przetestował |
| Zależności | pip-audit na wyeksportowanym lockfile’u | Znane podatności w zależnościach runtime |
| Agent recenzujący | /code-review (Claude Code), codex review --base main (Codex), Bugbot (Cursor) | Błędy logiczne i brakujące przypadki, których bramki nie wyrażą |
Pokrycie dowodzi, że linie się wykonały, a nie że asercje są mocne. Mocniejszy dowód jakości samych testów opisuje strona o testach mutacyjnych i sile wyroczni.
Uruchamiaj bramkę w CI przy każdym pull requeście; plik workflow znajdziesz we wzorcach potoków CI/CD. Inżynier odpowiedzialny za usługę zatwierdza trzy rzeczy: listy przypadków testowych, które agent napisał przed kodem, zieloną bramkę oraz wyniki testów współbieżności i macierzy uprawnień. Ludzka lektura trafia do fragmentów wskazanych przez agenta recenzującego i do kodu, który dotyka uwierzytelniania, pieniędzy albo granic między tenantami. Jak podzielić tę pracę w zespole, opisuje recenzja PR-ów agenta, a bramki bezpieczeństwa dla agentów dodają niezależnego recenzenta bezpieczeństwa.
Kiedy Python napisany przez agenta psuje się na produkcji
Dział zatytułowany „Kiedy Python napisany przez agenta psuje się na produkcji”Każda z poniższych awarii przechodzi zestaw testów happy path. Każda ma objaw, który da się wykryć, i sposób naprawy.
- Pętla zdarzeń staje pod obciążeniem. Objaw: p99 opóźnień skacze dla wszystkich endpointów, gdy wywoływany jest jeden wolny upstream, a CPU pozostaje niskie. Przyczyna: blokujące wywołanie (
requests,time.sleep, synchroniczna sesja ORM,open()) wewnątrzasync def. Naprawa: włącz regułyASYNCRuffa, jeśli są wyłączone, a potem wydaj prompt: „Fix every ASYNC finding with an async equivalent, or move the call toasyncio.to_threadwith a comment saying why. Done means make check passes.” MissingGreenlettylko na produkcji. Objaw:sqlalchemy.exc.MissingGreenletna endpoincie, który w testach działał. Przyczyna: niejawne leniwe ładowanie relacji w kodzie async, często w serializatorze odpowiedzi. Naprawa: ustawlazy="raise"na każdej relacji, uruchom testy i dodajselectinload()tam, gdzie teraz coś pada.- Async SQLAlchemy nie startuje po aktualizacji. Objaw: błąd informujący, że wymagana jest biblioteka
greenlet. Przyczyna: SQLAlchemy 2.1 przeniosłogreenletdo dodatku[asyncio]. Naprawa: zadeklaruj zależnośćsqlalchemy[postgresql-asyncpg](albosqlalchemy[asyncio]) i zacommituj zaktualizowanyuv.lock. - Sprzedaż ponad stan albo podwójne efekty uboczne. Objaw: ujemny stan magazynu, zdublowane raporty albo zdublowane zwroty po skoku ruchu lub restarcie workera. Przyczyna: logika „odczytaj, a potem zapisz” w Pythonie albo nieidempotentne zadanie dostarczone ponownie. Naprawa: dodaj współbieżny test na Testcontainers z przepisu na zamówienia, a potem wydaj prompt: „Find every place that reads a value, decides in Python, and writes it back. Replace each with a conditional UPDATE or a row lock, and add a concurrent test for each.”
- Zestaw testów pada po aktualizacji pytest-asyncio. Objaw: błędy wspominające fixture
event_loop. Przyczyna: agent użył wzorca sprzed wersji 1.0, czyli nadpisania fixture’aevent_loop, a pytest-asyncio 1.0 ten fixture usunęło. Naprawa: uruchom prompt sprzątający przestarzałe idiomy; zastępuje ten fixture ustawieniemloop_scope. - Jeden tenant widzi dane innego. Objaw: zgłoszenie do supportu albo log dostępu z identyfikatorami innej organizacji. Przyczyna: nowy viewset lub zapytanie bez filtra tenanta. Naprawa: dodaj test mixinu przechodzący po wszystkich trasach z przepisu na Django, żeby luka nie wróciła, i przejrzyj logi z okresu, którego dotyczy problem.
- Agent osłabia test, żeby dojść do zielonego wyniku. Objaw: poluzowana asercja, usunięty przypadek, dodany
skiplubxfailalbo zmienionefilterwarningsw tym samym diffie co poprawka. Naprawa: przywróć plik testu, powtórz regułę zAGENTS.mdi spraw, żeby CI padało, gdy pull request zmienia istniejący pliktest_*.pyalbo konfigurację pytest bez etykietytest-change.
Dokąd dalej z usługami w Pythonie
Dział zatytułowany „Dokąd dalej z usługami w Pythonie”- Najpierw przygotuj repozytorium dla agenta, jeśli jeszcze nie jest gotowe: kod gotowy dla agenta.
- Zaprojektuj kontrakt API przed handlerami: wzorce tworzenia API.
- Wzmocnij warstwę danych: dobre praktyki ORM i wzorce migracji baz danych.
- Buduj potoki danych i zadania wsadowe w Pythonie: przepisy na inżynierię danych.
- Wdróż usługę: wzorce Dockera oraz wzorce monitoringu i logowania.
- Zdecyduj, co agent może uruchamiać bez nadzoru: uprawnienia i sandboxing.
- Porównaj z innym stosem backendowym: przepisy na Node.js/Express albo wróć do przeglądu przepisów backendowych.
Czy ten artykuł Ci pomógł?
Jedno kliknięcie, bez logowania.
Co z tym zrobisz?
Jak się czytało?
Co przeszkadzało? Możesz zaznaczyć kilka
Twoja rola?
Dzięki. Czytam każdą odpowiedź. Michał Jaskólski
Pomógł Ci ten artykuł?
Każde to jedno kliknięcie. Zamknij, kiedy chcesz.
bez logowania