Hub Python Library documentation
Kum Havuzları
Kum Havuzları
Sandboxes, deneysel bir özelliktir. API, varsayılanlar ve davranış, haber verilmeksizin değişebilir. Paylaşılan sandbox'lar, aynı güven sınırındaki iş yükleri için tasarlanmıştır; izolasyonları, her türden sandbox arası saldırıya karşı koruma garantisi vermez. Birbirine güvenmeyen iş yükleri için ayrılmış sandbox'lar kullanın ve uzun ömürlü veya geniş kapsamlı kimlik bilgilerini sandbox iş yüklerine erişilebilir kılmaktan kaçının.
Sandbox, saniyeler içinde başlatabileceğiniz, canlı yayınlanan çıktıyla komut çalıştırabileceğiniz ve dosyaları içeriye/dışarıya taşıyabileceğiniz izole bir bulut makinesidir; tüm bunlar Python veya CLI üzerinden yapılabilir. Sandbox'lar Jobs üzerine inşa edilmiştir: arka planda bir sandbox, HTTP üzerinden komut çalıştırma ve dosya aktarımı sunan küçük bir sunucu çalıştıran bir Job'dan ibarettir.
Kendi makineniz dışında bir yerde kod çalıştırmanız gerektiğinde iyi birer seçenektir:
- Güvenilmeyen veya yapay zeka tarafından üretilen kodun çalıştırılması — bir ajanın dosya sisteminize erişim vermeden keyfi kod çalıştırmasına izin verin. Bunun için özel bir kum havuzu kullanın: kendi başına bir sanal makinedir.
- Tekrarlanabilir derlemeler ve deneyler — temiz, iyi tanımlanmış bir görüntü üzerinde, CPU veya GPU'da çalıştırın.
- İşleri dağıtma — yüzlerce paralel ortamı (RL rollouts, değerlendirme, toplu araç çalıştırma) düşük maliyetle başlatma.
/bin/sh içeren herhangi bir Docker görüntüsü çalışır — Python, pip veya ajanın önceden yüklü olması gerekmez (başlangıçta küçük bir statik sunucu ikili dosyası enjekte edilir).
Bu işin perde arkasında nasıl çalıştığını merak ediyor musunuz — iş içi sunucu, durumdan bağımsız kimlik doğrulama veya tek bir Job'un birçok izole edilmiş sandbox barındırma biçimi? Sandboxes kavramsal rehberi'ne göz atın.
İki tür kum havuzu
Sandbox elde etmenin iki yolu vardır. İkisi de aynı Sandbox nesnesini (aynı run, files, connect, kill) size verir; aralarındaki tek fark, altta yatan makinenin nasıl tahsis edildiğidir:
| Sandbox.create() — özel | SandboxPool — ortak / havuz | |
|---|---|---|
| eşleme | bir İş = bir kum havuzu (tam bir sanal makine) | bir İş = çok sayıda kum havuzu (tek VM, sıkıştırılmış) |
| izolasyon | tam VM | uid + Landlock (aynı kullanıcı güveni) |
| soğuk başlatma | ~6 sn / sandbox | İlk host için ~6s, ardından her biri için ~1 gidiş-dönüş |
| maliyet | her kum için bir sanal makine | her host için bir VM, birçok sandbox arasında paylaştırılmış |
| GPU | ✅ | ❌ (Sadece CPU) |
| en iyi olduğu | tek bir kum havuzu, GPU iş yükleri, güvenilmeyen kod | birçok ucuz CPU kum havuzu (RL rollouts, fan-out) |
Kural: GPU gerektiriyorsanız veya birbirine güvenilmeyen kod çalıştırmanız gerekiyorsa → ayrılmış. Yüzlerce ucuz CPU kum havuzu gerektiriyorsanız → havuz.
Hızlı Başlangıç
>>> from huggingface_hub import Sandbox
>>> with Sandbox.create() as sbx: # ready in ~6s
... result = sbx.run("python -c 'print(40 + 2)'") # ~100ms per command
... print(result.stdout)
42İstediğiniz görüntüyü ve donanım çeşidini seçin:
>>> sbx = Sandbox.create(image="alpine:3.20")
>>> sbx = Sandbox.create(image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel", flavor="a10g-small")Komutları çalıştırma
Sandbox.run() bir komutu çalıştırır ve tamamlanmasını bekler. Bir kabuk dizgesi veya argv listesi geçirin:
>>> sbx.run("pip install -q numpy") # string → runs through /bin/sh -c
>>> sbx.run(["python", "-c", "import numpy; print(numpy.__version__)"]) # list → exec'd directly
# Live output streaming, plus env, cwd, timeout, stdin
>>> sbx.run("make -j4", cwd="/app", env={"CC": "gcc"}, timeout=600, on_stdout=print, on_stderr=print)Varsayılan olarak mod, türden çıkarılır (bir dize /bin/sh -c üzerinden çalıştırılır, bir liste ise argv olarak doğrudan yürütülür). Bunu açıkça belirtmek için shell= parametresini iletin — bu, ["echo hi"] gibi tek öğeli bir listenin "echo hi" adlı tek bir program olarak yürütülmesi gibi klasik bir hatadan kaçınmak için kullanışlıdır:
>>> sbx.run("echo $HOME && ls | wc -l", shell=True) # force the shell (pipes, globs, $VARS)
>>> sbx.run(["git", "commit", "-m", msg], shell=False) # force argv (no quoting surprises)shell=True bir dize gerektirirken shell=False bir liste gerektirir; yanlış türün geçirilmesi bir ValueError hatası oluşturur.
Sıfır dışı bir kodla sonlanan bir komut SandboxCommandError hatası fırlatır (stdout, stderr ve exit_code eklenir). Hata fırlatmak yerine SandboxCommandResult nesnesini geri almak için check=False parametresini iletin:
>>> result = sbx.run("test -f /tmp/missing", check=False)
>>> result.exit_code
1Arka plan süreçleri
Uzun süreli bir süreci (bir sunucu, bir izleyici, bir eğitim çalışması) beklemeden başlatmak için background=True parametresini iletin. run, bir SandboxCommandResult yerine hemen bir SandboxProcess döndürür:
>>> proc = sbx.run("python -m http.server 8000", background=True)
>>> proc
SandboxProcess(pid=1234, cmd='python -m http.server 8000', tag=None, started_at_ms=1700000000000, running=True, exit_code=None)Bir sandbox’un süreçlerini listeleyin ve işiniz bittiğinde birini durdurun. Tamamlanan süreçler, sandbox silinene kadar listede kalır (running=False ve exit_code değerleriyle birlikte), böylece bir sürecin hâlâ aktif mi yoksa zaten sonlanmış mı olduğunu anlayabilirsiniz:
>>> sbx.processes()
[SandboxProcess(pid=1234, cmd='python -m http.server 8000', tag=None, started_at_ms=1700000000000, running=True, exit_code=None)]
>>> proc.kill()Akış/yalnızca bekleme seçenekleri (timeout, stdin, on_stdout, on_stderr, check) arka plan modunda geçerli değildir — yalnızca env, cwd ve shell parametreleri dikkate alınır.
Dosyalar
>>> sbx.files.write("/app/script.py", "print('hi')") # str | bytes | file-like
>>> sbx.files.read_text("/app/script.py")
"print('hi')"
>>> sbx.files.upload("local_data.csv", "/data/data.csv") # local -> sandbox
>>> sbx.files.download("/data/results.bin", "results.bin") # sandbox -> local
>>> sbx.files.list("/data")
[FileEntry(name='data.csv', path='/data/data.csv', type='file', size=5324, ...)]Diğer yardımcılar: stat, exists, mkdir, delete.
Bir kum havuzunun içindeki bir sunucuya erişim
Sandbox içinde bir sunucu başlatın (arka planda), ardından dışarıdan Sandbox.proxy_url_for() ile erişin — istek, iş içi sandbox sunucusu tarafından iç sunucunuza yönlendirilir, bu nedenle ek bir genel port açmanıza gerek yoktur. Düz HTTP, Server-Sent Events ve WebSocket için çalışır. Kimlik doğrulama için URL'yi Sandbox.proxy_headers ile eşleştirin (WebSocket/HTTP istemcinizin bunları göndermesi gerekir):
>>> import httpx2
>>> with Sandbox.create() as sbx:
... sbx.files.write("app.py", "...") # a server exposing e.g. /hello and /ws
... sbx.run("uvicorn app:app --host 127.0.0.1 --port 8000", background=True)
... # plain HTTP
... r = httpx2.get(sbx.proxy_url_for(8000, "/hello"), headers=sbx.proxy_headers)
... # WebSocket: ask for a wss:// URL
... ws_url = sbx.proxy_url_for(8000, "/ws", scheme="wss://")proxy_headers kullanırken HTTP istemcinizde yönlendirmeleri devre dışı bırakın (httpx için follow_redirects=False, requests için allow_redirects=False). Bir uygulama başka bir kökene yönlendirebilir ve bu özel kimlik doğrulama başlıkları oraya iletilmemelidir.
Pooled sandboxes, sandbox başına yetenek token'ı döndüren bir sunucu gerektirir. Eksik token'lar bir hatadır; yönetim token'ını kullanmak yerine host'u yükseltin ve yeniden başlatın.
İç sunucunun dinlemesi gereken yer, sandbox türüne bağlıdır:
- Özel (Sandbox.create()):
127.0.0.1:<port>üzerinde normal bir TCP portu bağlayın. - Pool / paylaşımlı (SandboxPool): havuzlanmış sandbox'lar bir TCP portuna bağlanamaz (Landlock), bu nedenle
$SBX_PROXY_DIR/<port>.sockadresinde bir unix socket üzerinde dinleyin (bu ortam değişkeni her sandbox'ta ayarlanır), örneğinuvicorn app:app --uds $SBX_PROXY_DIR/8000.sock. İstemci tarafı (proxy_url_for/proxy_headers) her iki durumda da aynıdır.
Yaşam Döngüsü
Bir sandbox, onu oluşturan süreçten daha uzun süre yaşar — şimdi oluşturabilir ve aynı HF token'ına sahip herhangi bir makineden, kopyalanacak bir durum olmadan daha sonra yeniden bağlanabilirsiniz:
>>> sbx = Sandbox.create()
>>> sbx.id
'687f911eaea852de79c4a50a'
# Later, from anywhere:
>>> sbx = Sandbox.connect("687f911eaea852de79c4a50a")
>>> sbx.kill() # terminate nowidle_timeout(varsayılan 10 dakika) asıl kurtarıcıdır: hiçbir API çağrısı yapılmadığında ve hiçbir süreç çalışmadığında sandbox’u kapatır, böylece terk edilmiş sandbox’lar faturalandırmayı durdurur. Oluşturma sırasında ayarlayın (Sandbox.create(idle_timeout="30m")) veya devre dışı bırakmak içinNonegeçin.- İşin, yapılandırılabilir olmayan bir kesin üst sınır olarak, 24 saatlik sabit bir maksimum ömrü vardır.
forward_hf_token=True, HF token'ınızı kum havuzunda çalışan koda açıkça ifşa eder (HF_TOKENolarak).forward_hf_token=Falseolsa bile, kum havuzunu kimlik bilgileriniz için sert bir sınır olarak görmeyin — bu sayfanın başındaki uyarıya bakın.
Aynı anda birçok sandbox: SandboxPool
Birçok sandbox'a (paralel RL rollouts, fan-out değerlendirme, toplu araç çalıştırma) ihtiyaç duyduğunuzda, her sandbox için ayrı bir Job oluşturmak israf eder: her biri tam bir VM soğuk başlatma maliyeti öder ve birkaç MB RAM gerektiren bir iş yükü için tüm bir makineyi meşgul eder. SandboxPool bunun yerine birçok hafif sandbox'u birkaç paylaşılan host Job içine sıkıştırır — faturalandırılan tek bir VM onlarca sandbox'a hizmet eder, böylece sandbox başına maliyet bu faktör kadar düşer ve sandbox başına soğuk başlatma süresi yaklaşık bir ağ gidiş-dönüşüne eşittir.
>>> from huggingface_hub import SandboxPool
>>> with SandboxPool(image="python:3.12", flavor="cpu-basic", warm_up=2) as pool:
... boxes = [pool.create() for _ in range(100)] # packed across the 2 warm host VMs
... print(boxes[0].run("echo hi").stdout) # each box is a normal Sandbox
hiHer create() çağrısı tek bir tam Sandbox döndürür; dağıtmak için bunu tekrar tekrar çağırın. Havuz, gerektiğinde host Job'ları başlatır, host başına sandboxes_per_host sandbox yerleştirir ve close() çağrıldığında (veya bir host boşta kaldığında, faturalama önlemi olarak) her şeyi sonlandırır. Tipik dağıtım deseni:
>>> from concurrent.futures import ThreadPoolExecutor
>>> with SandboxPool(image="python:3.12", warm_up=4) as pool:
... boxes = [pool.create() for _ in tasks]
... with ThreadPoolExecutor(32) as ex:
... outputs = list(ex.map(lambda b, t: b.run(t.cmd).stdout, boxes, tasks))Env ve idle_timeout kum havuzu başına tanımlanır (create()'ye ait olup havuza ait değildir), bu nedenle tek bir havuzdaki kum havuzlarının farklı ortamları olabilir:
>>> sbx = pool.create(env={"SEED": "42"}, idle_timeout="5m", forward_hf_token=True)Bir havuzlanmış sandbox, tam bir Sandbox'dır, ancak bazı girdiler sandbox başına değil, host tarafından sabitlenir — bu nedenle SandboxPool.create(), Sandbox.create()'den daha küçük bir argüman seti kabul eder:
| Girdi | Sandbox.create (özel) | SandboxPool.create (havuzlu) |
|---|---|---|
image, flavor | kum havuzu başına | havuz tarafından sabitlenir (ana makinede bir kez ayarlanır) |
volumes | kum havuzu başına | mevcut değil (host açılışında bağlandı) |
env | kum havuzu başına | kum havuzu başına |
idle_timeout | kum havuzu başına | kum havuzu başına |
forward_hf_token | kum havuzu başına | kum havuzu başına |
Pooled sandboxes, uzun ömürlü bir host job paylaşır; bu nedenle dedicated sandboxes’larda bulunan şifreli Job-secrets kanalı yoktur. Ancak bir pooled sandbox’ın env değeri, sandbox oluşturulduğunda (job başlatıldığında değil) host sunucusuna iletilir; bu yüzden hiçbir job’un metadata alanında saklanmaz — olası secret’ları düz env olarak iletin.
Talep üzerine büyütme ve önceden ısıtma
pool.create() her seferinde bir tane sandbox oluşturur ve yeni bir host başlatmadan önce hâlâ boş kapasitesi olan bir hostu yeniden kullanır — böylece işler geldikçe sandbox'lar oluşturabilirsiniz ve bunlar sıcak hostlara kendiliğinden yerleşir:
>>> pool = SandboxPool(image="python:3.12", flavor="cpu-basic")
>>> sbx = pool.create() # boots the first host (~6s)
>>> sbx = pool.create() # packs onto the same warm host (~one round-trip, no new VM)İlk birkaç çağrıda host soğuk başlatılmasını önlemek için, hostları warm_up=N ile (ilk create() çağrısında başlatılır) veya başlangıçta pool.warm(N) çağrılarak önceden ayarlayın.
Süreçler ve makineler arasında havuzların yeniden kullanımı
Sıcak konaklar, iş etiketleri aracılığıyla keşfedildiğinden yeniden kullanım, süreçler arasında çalışır: daha önceki bir çalıştırmanın ayakta bıraktığı konaklara bağlanır, kendi konaklarını başlatmaz; aynı image/flavor/name değerlerine sahip, tamamen yeni bir SandboxPool için geçerlidir. Ayrı havuzların konakları paylaşmaması için name= parametresini iletin.
Yerel durum içermeyen başka bir makineden yeniden bağlanmak için, SandboxPool.connect() ile havuz kimliği üzerinden yeniden bağlantı kurun — bu yöntem çalışan bir ana makineyi bulur, havuz yapılandırmasını (görsel, lezzet, paketleme yoğunluğu) o ana makine işinden yeniden oluşturur ve daha fazlasını create() etmeye hazır hale gelir:
>>> pool = SandboxPool.connect("pool-ae9f7efe0bc7") # from anywhere, no config needed
>>> sbx = pool.create()connect() ile oluşturulan bir havuz, paylaşılan hostların sahibi değildir (diğer istemciler bunları kullanıyor olabilir), bu nedenle — Sandbox.connect() gibi — with bloğundan çıkılması (veya close() çağrılması) yalnızca yerel HTTP istemcilerini serbest bırakır ve hostların çalışmaya devam etmesine izin verir. Bir havuzun hostlarını pool delete / hf sandbox pool delete <id> ile açıkça sonlandırın.
Bir host içindeki sandbox'lar, ayrı uid'ler ve sandbox başına Landlock kural setleri ile ayrıştırılır. Paylaşılan sandbox'lar, kullanıcının kendi paralel iş yükleri için tasarlanmıştır ve tüm sandboxlar arası saldırılardan izolasyon garanti edilmez. Karşılıklı güvensiz kod için veya GPU için Sandbox.create() kullanın (sandbox başına ayrı bir VM). Takaslar, kavramsal kılavuzda ayrıntılı olarak açıklanmıştır: izolasyonun nasıl çalıştığı ve — iki mod arasında seçim yapıyorsanız daha önemli olan — bilinen kısıtlamaların tam listesi.
CLI'den
hf sandbox komutu, Python API'sini yansıtır. Özel bir sandbox:
>>> hf sandbox create
✓ Sandbox ready id=687f911eaea852de79c4a50a image=python:3.12 elapsed=6.0s
# Attach labels to the underlying Job
>>> hf sandbox create --label controller-run=run-42 --label team=data-infra
>>> hf sandbox exec 687f911eaea852de79c4a50a -- python -c "print('hi')"
hi
>>> hf sandbox cp data.csv 687f911eaea852de79c4a50a:/data/data.csv
>>> hf sandbox kill 687f911eaea852de79c4a50ahf sandbox exec çıktısını canlı olarak aktarır ve komutun çıkış koduyla sonlanır; bu sayede betiklerde bir araya getirilebilir:
hf sandbox exec $ID -- pytest && echo "tests passed"Arka planda uzun süreli bir süreci hf sandbox spawn ile başlatın (pid'sini yazdırır), ardından süreçleri listeleyin veya durdurun. Listeleme, her sürecin durumunu (running veya exited (<code>)) gösterir:
>>> hf sandbox spawn $ID -- python -m http.server 8000
✓ Process started sandbox=687f... pid=1234
>>> hf sandbox process ls $ID
pid status cmd
1234 running python -m http.server 8000
>>> hf sandbox process kill $ID 1234Birçok ucuz paylaşımlı sandbox için havuzu bir kez ısıtın ve ardından ihtiyaca göre içine oluşturma yapın:
# Warm a pool -> prints a pool id (billing starts: a host VM is now running)
>>> hf sandbox pool create python:3.12 --flavor cpu-basic
✓ Pool created id=pool-ae9f7efe0bc7 image=python:3.12 flavor=cpu-basic host=687f... elapsed=5.7s
# Each create packs onto a host with room (found by the pool id, from any machine);
# only when every host is full does it boot a duplicate. Env is per-sandbox (pooled
# sandboxes share a host, so there's no encrypted-secrets channel — use --env).
>>> hf sandbox create --pool pool-ae9f7efe0bc7 --env LOG_LEVEL=debug
>>> hf sandbox create --pool pool-ae9f7efe0bc7
>>> hf sandbox pool ls
>>> hf sandbox pool delete pool-ae9f7efe0bc7 # terminate the pool's hosts (and their sandboxes)hf sandbox create --pool komutu paylaşımlı bir sandbox oluşturur; kimliği <host_job_id>.<local_id> biçimindedir ve özel bir kimliğin geçerli olduğu her yerde (exec, cp, kill) çalışır. Bir havuzun yerel durumu yoktur — yalnızca havuz kimliğiyle bulunan çalışan host VM'lerinden ibarettir — bu nedenle herhangi bir makineden çalışır ve tüm host'ları ortadan kalktığında (kill edilip veya boşta kalma zaman aşımına uğradığında) var olmaktan çıkar.