Átadható specifikáció: a munkakörnyezethez ne csak eszközlista, hanem tiszta telepítési parancs, platform- és verziómátrix, minimális smoke test, függőséglakat és adat-hozzáférési szabály is tartozzon.
A gyakorlóprojekt a Northstar prediktív feladat: a rendelés
pillanatában becsüljük, hogy a kézbesítés 7 napon túli lesz-e
(target_late). A bemenet a mellékelt labor
customers.csv, orders.csv és
order_items.csv fájlja; a megfigyelési egység az
order_id; a cutoff 2025-05-01T00:00:00+00:00.
A feladat most nem maga a modell, hanem az, hogy a munkaasztalt úgy
adjuk át, hogy egy friss CPU-gép a labor readme-je alapján ugyanazt a
splitet és ugyanazt az elfogadási kontrollt reprodukálja.
Előzetes nagyságrendi becslés: az orders.csv 2400 sora
15 oszlop esetén, ha minden oszlop 8 byte-os numerikus érték lenne,
;
a mellékelt tételekkel együtt is néhány MB-os szinten maradunk. Ez tehát
memóriában elférő, egygépes feladat; a Spark, a GPU vagy a menedzselt
klaszter nem indokolt. Ez becslés, nem futási mérés.
A munkaasztal-specifikáció hét rétege nem egymás melletti csomaglista, hanem futtatási lánc. A Mikor érdemes másik ökoszisztémát választani? alfejezetben használt döntési fegyelem és az Eszközbevezetés, licenc és verziófrissítés alfejezetben bevezetett ellenőrzött érték–forrás–dátum–állapot sor itt konkrét rétegtesztként jelenik meg.
| Réteg | Kötelező választás | Alternatíva / opcionális | Elfogadási teszt |
|---|---|---|---|
interpreter |
CPython 3.12 a projekt
.venv-jében |
pyenv, conda/mamba | sys.version_info[:2] == (3,12) és
sys.executable a projekt .venv alatt |
packages |
uv lock feloldás, majd
uv sync --locked |
venv+pip, pip-tools | a lock-feloldás sikeres, a labor alap numerikus csomagjai importálhatók |
data engine |
pandas feature-tábla, DuckDB SQL, Parquet checkpoint | Polars, SQLite | COUNT(*) = 2400, séma-ellenőrzés,
manifest.json hash |
tracking |
artifacts/split.json + egy
futástábla |
MLflow | kötelező kulcsok, train/purged/test sorszámok |
execution |
helyi CPU, uv run,
JupyterLab |
CI futás, Docker | a starter script exit-kódja 0, a nyers bemenet változatlan |
reporting |
notebook + Modellkártya | Quarto/HTML | nbconvert exit 0, a kártyában „Nem támogatott
használat” szakasz |
handoff |
README, lock, manifest, modellkártya, runbook | Docker image | tiszta gépről uv sync --locked + script +
hash-egyezés |
A lap elfogadását egy logikai ÉS-lánc írja le:
ahol az -edik rétegteszt kimenete; a vektor alakja , értékkészlete , mértékegysége darab sikeres teszt. A specifikáció akkor elfogadott, ha ; egyetlen 0 is elutasítást jelent. Ez azért fontos, mert a stack nem „részben reprodukálható”: ha a kernel rossz interpreterre mutat, a tökéletes lock sem segít.
A hét réteg közül a interpreter és a
packages különválasztása szándékos. Az interpreter az a
program, amely a Python-bytecode-ot végrehajtja; a packages a projekthez
tartozó könyvtárak lockolt halmaza. A notebook maga nem interpreter:
csak egy kliens, amely egy regisztrált kernelén keresztül beszél
valamelyik Pythonhoz. Ezért a notebook típusa nem dönti el, hogy a labor
.venv-jét futtatjuk-e.
Az átadandó egyoldalas lap fejléce a konkrét projektet köti a hét réteghez:
# Northstar stack-spec
projekt: rendeléskori target_late predikció
megfigyelési egység: order_id
cutoff: 2025-05-01T00:00:00+00:00
invariánsok: orders sorcount=2400, manifest SHA-256,
split train+purged+test=2400
futtatási hely: egyetlen CPU-gép, helyi labor
A táblázat hét sora e fejléc alá kerül; a leadott lapban minden
sorhoz egy rövid, idézhető forrás vagy ellenőrzési utasítás tartozik. A
következő platformjelölt munkamenet mutatja a minimális láncot.
Munkakönyvtár: a repository lab/ mappája; platform:
Linux/macOS Bash. A lab még nem szállít feloldott lockot, ezért az első
lépés a feloldás.
cd lab
uv lock # a mellékelt laborhoz nincs szállított uv.lock
uv sync --locked # ezután már a lock a mérvadó
uv run python -c "import sys; print(sys.version.split()[0], sys.executable)"
uv run python generate_data.py
uv run python quickcheck.py
uv run python starter_experiment.py
python -m json.tool artifacts/split.json | head -n 20Fontos: ezt a munkamenetet ebben az írási módban nem futtattam; a labor tényleges ellenőrzött kimenetét a mellékelt eredményjegyzék tartalmazza. Az itt látható parancsfolyam tehát a specifikáció előírt sorrendje, nem most mért futási eredmény.
A kézi kontroll a rétegekre:
SELECT count(*) AS n_orders
FROM read_csv_auto('data/orders.csv');Várt érték: 2400. Az adatfájlra számított SHA-256-ot a
manifest.json ugyanazon fájlhoz tartozó mezőjével
hasonlítjuk össze; a hash csak akkor fogadható el, ha a manifestből
kiolvasott értékkel egyezik, nem egy korábbi kényelmes másolatból írt
konstans. A sys.executable várt alakja a projekt
.venv alatti Python, nem a rendszer
/usr/bin/python3.
Ha , akkor állítható, hogy az adott gépen a hét réteg lánca zárt: a projekt Pythonja a projekt lockolt csomagkészletét látja, az adatellenőrzés sor- és hash-szinten átment, a split műtermék létrejött, és a leadási csomag rendelkezik az ismétléshez szükséges elemekkel. Ez nem állítja, hogy a modell illeszkedése vagy a statisztikai következtetés helyes; az a modellértékelés és a Robusztusság és korlátokkal írt modellkártya alfejezetben leírt modellkártya dolga. A stack-teszt tehát szükséges környezeti kapu, nem elégséges tudományos minősítés.
A manifest-hash szerepe az, hogy a megváltozott bemenetet azonnal elkapja. Ha valaki újragenerálja az adatot más seeddel, a sor- és hash-invariáns megtörik, és a handoff-teszt elutasít. Így a „működött nálam” állítás helyett ellenőrzött predikátumok döntenek.
Értelmezés. A specifikáció szerint az
interpreter és a packages teszt is zöld, de a
Jupyter notebookban a pandas.__version__ értéke 2.1.4,
miközben a projekt Pythonja a 2.2.3-at importálja. Melyik rétegben van a
hiba? Mit kell összehasonlítani, és mi a javítás?
Megvalósítás. Írj a repository gyökerébe egy
stack_probe.py szkriptet, amely nem importál
projektfüggő könyvtárat, és a standard kimenetre JSON-t ír a következő
mezőkkel: interpreter-verzió, sys.executable, a
lab/pyproject.toml és a lab/uv.lock megléte,
valamint a lab/data/orders.csv mérete byte-ban. A kilépési
kód legyen 0, ha az interpreter 3.12 és mindkét projektfájl létezik,
különben 1.
Hibadiagnózis. Egy tiszta gépen a
uv sync --locked parancsot a repository gyökerében
futtatták, és „sikeres” üzenetet kaptak. Ezután a
uv run python starter_experiment.py a
ModuleNotFoundError hibát adja a duckdb
modulra. Adj három ellenőrző parancsot, és magyarázd el, miért nem látja
a projekt csomagjait a futtatás. Mit kell javítani?
Megváltozott feltétel. A forrásadatok Parquet-re
váltanak, és a méret 12 GB-ra nő; a megfigyelési egység továbbra is
rendelés, és a számításnak egyetlen CPU-gépen kell maradnia. Írd át a
data engine, az execution és a
handoff sor elfogadási tesztjét. Mely kritériumot kell a
korábbi Elosztott kísérlet és adatelhelyezés
alfejezetből idehozni?
1. megoldás. A hiba a packages és az
execution határán, a kernel-interpreter illesztésben van. A
notebookban a sys.executable értéket kell összehasonlítani
a uv run python -c "import sys; print(sys.executable)"
kimenetével. Ha a kettő különbözik, a notebook nem a projekt
.venv-jét használja. A javítás a projekt kerneljének
regisztrálása – például a Kernelregisztráció és
tiszta újrafuttatás alfejezetben tárgyalt kernelspec-ellenőrzéssel
–, majd a notebook újraindítása. A verziók puszta kijelzése nem
bizonyítja, hogy a notebook azon az interpreteren fut.
2. megoldás. Az alábbi szkript szándékosan standard library-s, hogy akkor is diagnosztizáljon, ha a függőségek nincsenek telepítve. A pontos elérési utat a labor aktuális README-jéhez kell igazítani, ha a CSV máshol fekszik.
from pathlib import Path
import json
import sys
def main() -> int:
lab = Path("lab")
pyproject = lab / "pyproject.toml"
lock = lab / "uv.lock"
orders = lab / "data" / "orders.csv"
report = {
"interpreter": {
"version": f"{sys.version_info.major}.{sys.version_info.minor}",
"executable": sys.executable,
"ok": sys.version_info[:2] == (3, 12),
},
"packages": {
"pyproject_exists": pyproject.exists(),
"lock_exists": lock.exists(),
},
"data": {
"orders_exists": orders.exists(),
"orders_bytes": orders.stat().st_size if orders.exists() else None,
},
}
report["packages"]["ok"] = (
report["packages"]["pyproject_exists"]
and report["packages"]["lock_exists"]
)
report["data"]["ok"] = (
report["data"]["orders_exists"]
and report["data"]["orders_bytes"] is not None
)
print(json.dumps(report, indent=2, ensure_ascii=False))
ok = (
report["interpreter"]["ok"]
and report["packages"]["ok"]
and report["data"]["ok"]
)
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())Az ellenőrzés kimeneti sémája JSON; a várt kulcsok hiánya vagy a
false érték egyetlen pillantással azonosítja a hibás
réteget. A működést legalább egyszer a saját gépen futtatni kell; a
fenti kód ellenőrizetlen sablon mindaddig, amíg a tanuló nem
futtatja.
3. megoldás. A három parancs:
pwd
ls pyproject.toml
uv run python -c "import duckdb; print(duckdb.__version__)"A hiba oka a munkakönyvtár: a uv sync --locked a
repository gyökerében nem a lab/pyproject.toml lockját
telepítette, ezért a starter_experiment.py futtatása sem a
projekt virtuális környezetét látta. Az első parancs megmutatja a
tényleges könyvtárat, a második azt, hogy ott nincs
pyproject.toml, a harmadik pedig reprodukálja a hiányzó
modulhibát. A javítás: cd lab, majd ott
uv sync --locked, végül
uv run python starter_experiment.py. A „sikeres” szöveg
önmagában nem állapotleírás; a futtatókönyvtárral és az interpreterrel
együtt értelmezendő.
4. megoldás. A három módosított sor:
data engine: DuckDB read_parquet vagy
Polars lazy; a teljes pandas-betöltés megszűnik kötelező lépésként.
Elfogadási teszt: a Parquet COUNT(*) egyezik a manifesttel,
és a séma ellenőrzése nem igényel teljes memóriába olvasást.execution: uv run méréssel kiegészítve;
kötelező a csúcs-RSS és a futásidő rögzítése. Elfogadási teszt: a mért
csúcs-RSS a csapat által előre rögzített korlát alatt marad, és nem lép
fel out-of-memory.handoff: partíciószintű manifest hash és sorcount a
teljes fájl szintje mellett. Elfogadási teszt: a tiszta gépi ismétlés
partíciónként is visszaadja a hash- és count-invariánst.Az Elosztott kísérlet és adatelhelyezés költségmodelljéből ide tartozik az adatelhelyezés és az amortizációs kérdés: 12 GB helyi Parquet esetén a helyi DuckDB/Polars akkor marad ésszerű, ha a compute az adat közelében van, és a feladat egyszeri nagy szkennelés helyett több lépcsőben újrafelhasználható checkpointot képez. A fenti küszöbök nem mért értékek; a projekt saját gépi mérését kell a specifikáció forrásaként feltüntetni.
A tipikus hiba az, hogy a „minden eszköz telepítve” lista
helyettesíti az architektúrát. Ellenpélda: a terminálban a
python -c "import duckdb" sikeres, a notebookban az
import duckdb mégsem fut. A felhasználó a rendszer-Python
pip list kimenetéből tudja, hogy „a DuckDB telepítve van”,
és elfogadja a munkaasztalt. A notebook kernelje azonban másik
interpreterre mutat, így a csomagok halmaza nem az, amelyet a
rendszerhéj listáz. A helyes állítás nem az, hogy „minden név jelen
van”, hanem az, hogy az
predikátum a projekt .venv-jében, a lockon keresztül, a
kernel ugyanazon sys.executable értékével teljesül. Ez az
Eszközbevezetés, licenc és verziófrissítés
alfejezetben tanult ellenőrzött forrás–dátum–állapot elvet ismétli: a
puszta képernyőlista nem bizonyíték.
Önellenőrzés a leadott lapra: mind a hét sorban megtalálható-e kötelező választás, alternatíva és elfogadási teszt; a teszt megad-e belépő adatot és várt invariánst; a handoff-sor tartalmaz-e hash- és count-ellenőrzést; és a lap fejléce rögzíti-e a megfigyelési egységet és a cutoffot?
A saját data science munkaasztal nem csomaglista, hanem hét rétegből álló predikátumlánc: interpreter, packages, data engine, tracking, execution, reporting, handoff. A Northstar laborhoz a minimális választás CPython 3.12, uv lock és sync, pandas/DuckDB/Parquet, split-manifest, helyi CPU-s uv run, notebook és modellkártya, valamint readme-lock-manifest runbook. Az egyoldalas specifikáció soronként kötelező választást, alternatívát és elfogadási tesztet ad; a lap esetben zöld, de ez csak környezeti kapu, nem modellminősítés. Következőként a Probléma és adatszerződés befagyasztása záróprojekt ezen a specifikáción fagyasztja be a prediktív projekt adatszerződését.