CodeWorlds
Powrót do kolekcji
Przewodnik13 min czytaniaZespół CodeWorlds

OpenHands, agent kodujący w kontenerze bez nadzoru

OpenHands uruchamia agenta w kontenerze, dawniej OpenDevin. Wersja, licencja z trzech źródeł, polityki potwierdzeń, koszt tokenów i cennik chmury.

OpenHands, agent kodujący w kontenerze bez nadzoru

OpenHands to otwarty agent programistyczny, który dostaje opis zadania, startuje we własnym środowisku i sam pisze kod, wykonuje polecenia w powłoce, czyta wynik testów i poprawia własne błędy. Różnica wobec asystenta w edytorze jest zasadnicza: nikt nie zatwierdza kolejnych kroków, dopóki sam tego nie skonfigurujesz.

Czym różni się od asystenta w edytorze

Asystent w edytorze pracuje w rytmie propozycja, spojrzenie człowieka, akceptacja. Widzisz każdą zmianę pliku, zanim wyląduje na dysku, i każde polecenie powłoki, zanim się wykona. Ten rytm kosztuje Twoją uwagę, ale daje punkt zatrzymania przed każdym nieodwracalnym krokiem.

OpenHands przesuwa ten punkt zatrzymania na sam koniec. Wysyłasz zadanie, agent wchodzi w pętlę: wybiera narzędzie, wykonuje je, ogląda wynik, wybiera następne. Pętla kręci się do skutku albo do limitu, a Ty patrzysz na dziennik zdarzeń, jeśli chcesz. Efektem bywa gotowa gałąź z zestawem zmian i opisem, co zostało zrobione.

Konsekwencje są dwie i obie trzeba znać przed pierwszym uruchomieniem. Pierwsza dotyczy bezpieczeństwa. Agent, który sam wykonuje polecenia, wykona też polecenie destrukcyjne, jeśli uzna je za krok w stronę celu. Twarda instrukcja z pliku README brzmi wprost: uruchomienie serwera agenta bez piaskownicy daje mu pełny dostęp do systemu plików maszyny, na której go zainstalowałeś. To nie jest ostrzeżenie asekuracyjne, tylko opis stanu faktycznego.

Druga dotyczy pieniędzy. Każdy obrót pętli to wywołanie modelu z całą dotychczasową historią w kontekście. Sesja, która trwa sto kroków, wysyła kontekst sto razy, a kontekst rośnie z każdym odczytanym plikiem i każdym wynikiem polecenia. Asystent w edytorze też pali tokeny, ale pali je w tempie, które sam narzucasz, bo między turami stoi człowiek.

Jest jeszcze trzecia różnica, mniej oczywista i często decydująca o wyborze. Agent w kontenerze da się wywołać z kodu, z harmonogramu albo z zaczepu w systemie zgłoszeń, bo nie potrzebuje otwartego okna edytora. Do zadań powtarzalnych, takich jak aktualizacja zależności albo przegląd zgłoszenia, to zupełnie inna klasa narzędzia niż Cursor czy Cline.

Nazwy, wersje i licencja z trzech źródeł

Projekt zmieniał nazwę dwa razy i to jedyny powód, dla którego starsze poradniki prowadzą donikąd. Zaczął jako OpenDevin, przemianowano go na OpenHands, a organizacja na GitHubie z All-Hands-AI stała się OpenHands. Wszystkie stare adresy przekierowują: github.com/OpenDevin/OpenDevin i github.com/All-Hands-AI/OpenHands kończą na github.com/OpenHands/OpenHands, a domena all-hands.dev na openhands.dev. Jeśli szukasz czegoś w archiwalnym wątku, szukaj po obu nazwach.

Repozytorium powstało 13 marca 2024 roku i na 21 sierpnia 2026 roku ma 84 668 gwiazdek, 11 037 rozgałęzień oraz 523 otwarte zgłoszenia. Nie jest zarchiwizowane, ostatnia zmiana w gałęzi głównej pochodzi z tego samego dnia. Strona projektu podaje w nagłówku 80,8 tysiąca gwiazdek, czyli liczbę niższą niż interfejs programistyczny GitHuba, i tej rozbieżności nie da się rozstrzygnąć z zewnątrz. Podaję obie.

Kod właśnie się przeprowadza i to stan przejściowy, nie docelowy. Plik README w głównym repozytorium mówi wprost, że silnik agenta i serwer agenta mieszkają teraz w OpenHands/software-agent-sdk, a konsola przeglądarkowa, nazwana Agent Canvas, w OpenHands/agent-canvas. Sama konsola ma odznakę stanu beta. Przy planowaniu wdrożenia to istotne, bo dokumentacja i nazwy pakietów zmieniały się w ciągu ostatnich miesięcy szybciej niż zwykle.

Wersje wyglądają tak. Pakiet openhands-ai w rejestrze PyPI stoi na 1.11.0 z 9 lipca 2026 roku, wymaga Pythona w zakresie od 3.12 do 3.13 włącznie i ciągnie za sobą między innymi litellm w wersji 1.84.1, docker 7.1.0 oraz browsergym-core 0.13.3. Tempo wydań w tym roku było równe: 1.3.0 w lutym, 1.5.0 w marcu, 1.7.0 w maju, 1.9.0 na początku lipca, a między 6 a 9 lipca wyszło pięć wydań pod rząd. Pakiet @openhands/agent-canvas w rejestrze npm ma wersję 1.14.0 z 17 sierpnia 2026 roku. Rodzina pakietów SDK, czyli openhands-sdk, openhands-tools i openhands-workspace, stoi na 1.42.1 z 12 sierpnia 2026 roku.

Licencja sprawdzona z trzech źródeł wypada w większości czysto, z jednym wyjątkiem, który warto wpisać do rejestru zależności. Plik LICENSE w repozytorium OpenHands/OpenHands to zwykły tekst MIT z notą „Copyright 2025 OpenHands contributors". Pole metadanych w PyPI dla openhands-ai podaje License-Expression: MIT, a opublikowane archiwum źródłowe zawiera plik LICENSE. Rejestr npm podaje dla @openhands/agent-canvas licencję MIT, a paczka zawiera plik package/LICENSE. Do tego miejsca zgodność jest pełna.

Rozjazd zaczyna się w dwóch punktach. Po pierwsze, plik LICENSE w archiwum openhands-ai 1.11.0 otwiera się preambułą mówiącą, że zawartość katalogu enterprise/ podlega licencji zdefiniowanej w enterprise/LICENSE. Tego katalogu nie ma ani w archiwum, ani w gałęzi głównej repozytorium, a wskazany plik zwraca błąd 404. Zapis jest więc martwy, ale narzędzie skanujące licencje zobaczy warunkowe ograniczenie i zgłosi je do wyjaśnienia. Po drugie, i to poważniejsze, pakiety openhands-sdk, openhands-tools oraz openhands-workspace w wersji 1.42.1 nie mają w PyPI ani pola license, ani license_expression, ani klasyfikatora licencji, a ich archiwa źródłowe nie zawierają żadnego pliku licencyjnego. Repozytorium OpenHands/software-agent-sdk jest przy tym oznaczone jako MIT. Jeśli osadzasz SDK w produkcie komercyjnym, sam pakiet nie niesie żadnego dowodu na warunki, na jakich go dostałeś.

Uruchomienie i granice piaskownicy

Najkrótsza droga prowadzi przez rejestr npm i uruchamia całość na Twojej maszynie. Wymaga Node w wersji 22.12 lub nowszej oraz narzędzia uv.

Code
Bash
npm install -g @openhands/agent-canvas
agent-canvas

# rozdzielenie warstw, gdy backend ma stać na innej maszynie
agent-canvas --frontend-only
agent-canvas --backend-only

Ten wariant nie ma piaskownicy. Serwer agenta działa bezpośrednio na hoście, więc agent widzi cały Twój katalog domowy, klucze SSH, pliki .env i historię powłoki. Do zabawy z projektem zabawkowym wystarczy, do pracy nad prawdziwym repozytorium nie.

Wariant z kontenerem ogranicza widoczność do jednego katalogu, który mu wskażesz.

Code
Bash
export PROJECTS_PATH="$HOME/projects"
mkdir -p "$PROJECTS_PATH" "$HOME/.openhands"

docker run -it --rm \
  -p 8000:8000 \
  -v "$HOME/.openhands:/home/openhands/.openhands" \
  -v "${PROJECTS_PATH}:/projects" \
  ghcr.io/openhands/agent-canvas:1.14.0

Interfejs stoi pod adresem http://localhost:8000. Zmienna PROJECTS_PATH wyznacza granicę: agent sięgnie po dowolny projekt wewnątrz tego katalogu i po nic poza nim. Katalog .openhands trzyma ustawienia i historię rozmów, więc podmontowanie go zachowuje stan między uruchomieniami kontenera.

Granica jest jednak węższa, niż się wydaje. Kontener chroni system plików hosta, ale nie chroni sieci, do której ma dostęp, ani sekretów, które sam mu przekażesz, ani zdalnego repozytorium, do którego dałeś mu token z prawem zapisu. Agent z tokenem GitHuba może wypchnąć gałąź, otworzyć zadanie scalenia i zamknąć cudze zgłoszenie, i żaden kontener tego nie powstrzyma. Jeśli szukasz izolacji rozumianej jako osobna maszyna wirtualna z krótkim czasem życia, to jest zadanie dla E2B, a nie dla lokalnego kontenera.

Trzeci wariant to serwer agenta postawiony na osobnej maszynie w chmurze, do którego konsola łączy się zdalnie. To układ sensowny, gdy agenci mają pracować, kiedy Twój laptop jest zamknięty, albo gdy zadania odpalają się z zaczepów w usługach zewnętrznych.

SDK i sterowanie pętlą agenta

Osobną drogą jest osadzenie agenta we własnym kodzie. Pakiet openhands-sdk daje trzy pojęcia: model, agenta i rozmowę. Nazwy pól poniżej pochodzą wprost z wersji 1.42.1.

Code
Python
from pydantic import SecretStr

from openhands.sdk import LLM, Agent, Conversation
from openhands.tools.preset.default import get_default_tools

model = LLM(
    model="anthropic/claude-sonnet-5",
    api_key=SecretStr(klucz_api),
    num_retries=5,
    max_output_tokens=16000,
    caching_prompt=True,
)

agent = Agent(
    llm=model,
    tools=get_default_tools(enable_browser=False),
)

rozmowa = Conversation(
    agent=agent,
    workspace="/projects/sklep",
    persistence_dir="/projects/.stan",
    max_iteration_per_run=120,
    stuck_detection=True,
    max_budget_per_run=3.0,
)

rozmowa.send_message("Napraw failujacy test w tests/test_koszyk.py i nie ruszaj reszty.")
rozmowa.run()
rozmowa.close()

Pole model przyjmuje identyfikator w konwencji LiteLLM, bo warstwa wywołań opiera się na LiteLLM i przez to obsługuje dostawców zbiorczych, na przykład OpenRouter. Do agenta trafia lista narzędzi, a zestaw domyślny to terminal, edytor plików i menedżer zadań, opcjonalnie z przeglądarką. Wyłączenie przeglądarki skraca opis narzędzi w prompcie i tym samym obniża koszt każdej tury.

Trzy pola rozmowy pilnują, żeby pętla się zatrzymała. max_iteration_per_run ogranicza liczbę kroków i domyślnie wynosi 500, co przy nieudanym zadaniu jest bardzo dużo. stuck_detection wykrywa zapętlenie, w tym powtarzającą się parę akcji i obserwacji, powtarzający się błąd oraz monolog agenta bez żadnej akcji. max_budget_per_run przerywa przebieg po przekroczeniu zadanej kwoty w dolarach, licząc łącznie wszystkie modele użyte w przebiegu, także ten od streszczania historii.

Do wyboru są też środowiska pracy inne niż lokalny katalog. Klasa DockerWorkspace z pakietu openhands-workspace startuje kontener sama i przyjmuje między innymi working_dir, server_image, host_port, volumes, forward_env, network oraz health_check_timeout. Obok niej stoją APIRemoteWorkspace, ApptainerWorkspace i OpenHandsCloudWorkspace.

Człowiek w pętli, potwierdzenia i ryzyko

Praca bez człowieka w pętli to domyślny tryb, ale nie jedyny. SDK daje trzy polityki potwierdzeń i skalę ryzyka o czterech poziomach.

Code
Python
from openhands.sdk.security import (
    AlwaysConfirm,
    ConfirmRisky,
    NeverConfirm,
    SecurityRisk,
)

# każda akcja czeka na zgodę człowieka
rozmowa.set_confirmation_policy(AlwaysConfirm())

# zgoda tylko przy akcjach ocenionych jako ryzykowne
rozmowa.set_confirmation_policy(ConfirmRisky(threshold=SecurityRisk.MEDIUM))

# pełna autonomia, brak punktów zatrzymania
rozmowa.set_confirmation_policy(NeverConfirm())

Wyliczenie SecurityRisk ma wartości UNKNOWN, LOW, MEDIUM i HIGH, przy czym porównania z UNKNOWN zgłaszają wyjątek, bo nieznane ryzyko nie da się ustawić na skali. Polityka ConfirmRisky domyślnie stawia próg na HIGH i pyta o zgodę dla akcji na tym poziomie oraz wyżej.

Ocenę ryzyka wystawia analizator, a tych jest kilka rodzajów: LLMSecurityAnalyzer pyta model, PatternSecurityAnalyzer dopasowuje wzorce, PolicyRailSecurityAnalyzer sprawdza reguły, a EnsembleSecurityAnalyzer łączy kilka źródeł oceny. W ustawieniach warstwy aplikacyjnej pole security_analyzer przyjmuje wartość llm albo none i domyślnie stoi na llm, w powiązaniu z trybem potwierdzeń.

Sensowny układ dla realnej pracy wygląda tak. Do zadań na kopii repozytorium, w kontenerze, bez tokenu z prawem zapisu, NeverConfirm jest w porządku, bo najgorsze, co się stanie, to zmarnowane tokeny. Do zadań dotykających gałęzi zdalnej albo środowiska z danymi, ConfirmRisky z progiem MEDIUM daje rozsądny kompromis. AlwaysConfirm sprowadza narzędzie do roli asystenta i wtedy Aider w terminalu jest zwykle wygodniejszy.

Koszt tokenów i wariant chmurowy

Długa sesja agenta kosztuje więcej, niż podpowiada intuicja, bo historia rośnie, a każda tura wysyła ją w całości. Pomiar zdejmuje się z rozmowy jedną linią.

Code
Python
metryki = rozmowa.conversation_stats.get_combined_metrics()

print(metryki.accumulated_cost)
print(metryki.accumulated_token_usage.prompt_tokens)
print(metryki.accumulated_token_usage.completion_tokens)
print(metryki.accumulated_token_usage.cache_read_tokens)
print(metryki.accumulated_token_usage.reasoning_tokens)

Pole cache_read_tokens jest tu najważniejsze. Jeśli przy włączonym caching_prompt zostaje na zerze, bufor promptu nie działa i płacisz pełną stawkę za powtarzany kontekst, co przy stu turach robi ogromną różnicę. Mechanizm buforowania po stronie dostawcy opisałem szerzej przy okazji modeli Claude.

Drugim hamulcem kosztów jest streszczanie historii. Kondensator podmienia stary fragment rozmowy na streszczenie, zamiast wysyłać go w kółko.

Code
Python
from openhands.sdk.context.condenser import LLMSummarizingCondenser

agent = Agent(
    llm=model,
    tools=get_default_tools(enable_browser=False),
    condenser=LLMSummarizingCondenser(
        llm=model,
        max_size=120,
        keep_first=2,
    ),
)

Domyślnie max_size wynosi 240 zdarzeń, a keep_first dwa, więc dwa pierwsze zdarzenia zostają nietknięte, bo w nich siedzi treść zadania. Obniżenie max_size tnie rachunek, ale zwiększa szansę, że agent zapomni ustalenie z początku sesji i zacznie chodzić w kółko.

Wariant chmurowy jest i ma cennik, choć bez podanej kwoty w części komercyjnej. Strona cennika wymienia trzy plany. Lokalny plan otwartoźródłowy jest darmowy i bez limitu dziennej liczby rozmów. Plan Individual w chmurze jest darmowy, obsługuje jednego użytkownika i ogranicza rozmowy do dziesięciu dziennie, przy czym model podłączasz własnym kluczem albo korzystasz z dostawcy OpenHands rozliczanego, jak podaje dostawca, po kosztach i bez narzutu, w trybie płatności za zużycie. Plan Enterprise ma cenę ustalaną indywidualnie i dodaje wdrożenie we własnej sieci wirtualnej, logowanie przez SAML i SSO, nielimitowaną liczbę użytkowników i równoległych rozmów, wsparcie priorytetowe oraz wspólny kanał na Slacku. Kwoty za Enterprise nie ma nigdzie w materiałach publicznych, więc jej nie podaję.

OpenHands a alternatywy

CechaOpenHandsClineAiderCursor
Postać narzędziaserwer agenta i konsola w przeglądarcerozszerzenie, CLI i SDKnarzędzie wiersza poleceńosobny edytor
Licencja kodu klientaMITApache 2.0Apache 2.0zamknięta
Rozliczenie inferencjiwłasny klucz albo dostawca po kosztachwłasny klucz albo kredytywłasny kluczabonament
Repozytorium publiczneOpenHands/OpenHandscline/clineAider-AI/aiderbrak
Gwiazdki na GitHubie84,7 tys.66,6 tys.48,4 tys.nie dotyczy

Wybór rozstrzyga jedno pytanie: czy zadanie ma się wykonać, kiedy Ciebie przy tym nie ma. Jeśli tak, czyli przy nocnej aktualizacji zależności, przy przeglądzie zgłoszeń albo przy zadaniu odpalanym z harmonogramu, OpenHands robi rzecz, której trzy pozostałe narzędzia nie robią wcale albo robią bocznymi drzwiami. Jeśli nie, czyli przy zwykłym pisaniu kodu z podglądem każdej zmiany, narzędzie w edytorze jest szybsze, tańsze i mniej ryzykowne.

Ryzyko przywiązania do dostawcy jest tu niskie po stronie modelu, bo klucz jest Twój i przełączenie na innego dostawcę to zmiana jednego łańcucha znaków. Jest wyższe po stronie samego projektu, i to z konkretnego powodu: kod przeprowadza się właśnie między repozytoriami, konsola jest w becie, a cała konstrukcja opiera się na jednej spółce i społeczności wokół niej. Przy wdrożeniu na lata przypnij konkretne wersje pakietów i licz się z tym, że nazwy modułów mogą się przesunąć.

Typowe błędy

Pierwszy to uruchomienie bez piaskownicy na maszynie roboczej. Wariant z rejestru npm stawia serwer agenta bezpośrednio na hoście, więc agent widzi klucze SSH i pliki z sekretami. Jeśli nie robisz tego w kontenerze, przynajmniej rób to na osobnym koncie systemowym.

Drugi to zostawienie domyślnego limitu kroków. Wartość max_iteration_per_run to 500, a nieudane zadanie potrafi wykorzystać cały ten budżet i nic nie dowieźć. Przy pierwszych uruchomieniach ustaw kilkadziesiąt i dopiero potem podnoś.

Trzeci to brak limitu kwotowego. Bez max_budget_per_run jedyną granicą jest liczba kroków, a koszt kroku rośnie razem z historią, więc dwustukrokowa sesja bywa kilkukrotnie droższa niż stukrokowa.

Czwarty to token z prawem zapisu do repozytorium podany na starcie. Agent użyje go tak, jak uzna za stosowne. Bezpieczniejszy układ to token tylko do odczytu i wypchnięcie gałęzi Twoją ręką po przejrzeniu wyniku.

Piąty to kopiowanie znacznika obrazu z pliku README. W dokumentacji stoi tam wersja z etykietą kandydata do wydania, a w rejestrze npm bieżąca wersja jest wyraźnie wyższa. Sprawdź numer w rejestrze, zanim wpiszesz go do polecenia.

Szósty to szukanie dokumentacji po starej nazwie. Materiały opisujące OpenDevin albo organizację All-Hands-AI dotyczą tego samego projektu, ale sprzed przebudowy, i nazwy pakietów oraz układ katalogów już się nie zgadzają.

Siódmy to potraktowanie SDK jako pakietu o jasnym statusie prawnym. Archiwa openhands-sdk, openhands-tools i openhands-workspace w wersji 1.42.1 nie zawierają pliku licencyjnego ani pola licencji w metadanych. Przy audycie zależności zapisz źródło ustalenia, czyli repozytorium, bo z samej paczki tego nie wyczytasz.

FAQ

Czy OpenHands i OpenDevin to ten sam projekt?

Tak. OpenDevin to pierwotna nazwa, którą zmieniono na OpenHands, a organizacja na GitHubie z All-Hands-AI przeszła na OpenHands. Stare adresy przekierowują na github.com/OpenHands/OpenHands, a domena all-hands.dev na openhands.dev.

Na jakiej licencji jest OpenHands?

Repozytorium główne i pakiet openhands-ai są na licencji MIT, potwierdzonej w pliku LICENSE, w metadanych PyPI oraz w opublikowanym archiwum. Pakiety SDK w wersji 1.42.1 są wyjątkiem: nie mają pola licencji w rejestrze ani pliku licencyjnego w archiwum, choć ich repozytorium jest oznaczone jako MIT.

Ile kosztuje wariant chmurowy?

Plan lokalny i plan Individual w chmurze są darmowe, przy czym Individual ogranicza rozmowy do dziesięciu dziennie i obsługuje jednego użytkownika. Model podłączasz własnym kluczem albo korzystasz z dostawcy OpenHands rozliczanego według deklaracji po kosztach. Plan Enterprise ma cenę ustalaną indywidualnie i nie jest podana publicznie.

Czy da się wymusić potwierdzanie akcji przez człowieka?

Tak. Metoda set_confirmation_policy na obiekcie rozmowy przyjmuje AlwaysConfirm, NeverConfirm albo ConfirmRisky z progiem na skali SecurityRisk, gdzie dostępne poziomy to LOW, MEDIUM i HIGH.

Jak ograniczyć koszt długiej sesji?

Trzema pokrętłami naraz: limitem kroków przez max_iteration_per_run, limitem kwotowym przez max_budget_per_run i streszczaniem historii przez LLMSummarizingCondenser z obniżonym max_size. Sprawdź przy tym pole cache_read_tokens w metrykach, bo działający bufor promptu obniża rachunek najmocniej.

Czy OpenHands zastąpi asystenta w edytorze?

Nie w codziennym pisaniu kodu, gdzie chcesz widzieć każdą zmianę. Zastąpi go w zadaniach, które mają się wykonać bez Ciebie: aktualizacja zależności, przygotowanie gałęzi z poprawką, przegląd zgłoszenia. Wielu zespołom opłaca się mieć oba narzędzia i używać ich do różnych rzeczy.

Dokumentację znajdziesz na stronie dokumentacji OpenHands, kod źródłowy w repozytorium na GitHubie, a plany i limity na stronie cennika.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie