ReAct prompting to wzorzec, w którym model językowy na przemian rozumuje i działa: zapisuje myśl o tym, co zrobić, wykonuje działanie, na przykład wyszukiwanie albo wywołanie narzędzia, czyta wynik i dopiero wtedy decyduje o kolejnym kroku. Nazwa to skrót od Reason + Act (rozumuj i działaj) i pochodzi z pracy Yao i współautorów z 2022 roku "ReAct: Synergizing Reasoning and Acting in Language Models". Nie ma związku z Reactem, biblioteką JavaScript do budowania interfejsów użytkownika.
Większość agentów AI, które przeglądają strony, uruchamiają kod albo edytują pliki, działa na jakiejś wersji tej pętli. Gdy przejdziesz ją raz ręcznie, zachowanie agentów znacznie łatwiej przewidzieć i debugować.
Pętla Thought, Action, Observation
Prompt ReAct prosi model o pisanie trzech rodzajów linii.
- Thought: rozumowanie o bieżącej sytuacji i o tym, jakich informacji brakuje.
- Action: jedno wywołanie narzędzia w stałym formacie, na przykład
search[query],read_file[path]albofinish[answer]. - Observation: wynik tego działania. Tej linii model nie pisze. Twój program (albo ty) wykonuje działanie i dopisuje prawdziwy wynik do zapisu rozmowy.
Potem cały zapis wraca do modelu, który pisze kolejną linię Thought. Pętla kończy się, gdy model wybierze działanie kończące. Model nigdy sam nie uruchamia narzędzia; tylko o to prosi, a kod wokół niego decyduje, czy spełnić prośbę.
Dlaczego rozumowanie plus działanie wygrywa z każdym z osobna
Autorzy porównali ReAct z promptami, które tylko rozumują (chain of thought), i z promptami, które tylko działają (wywołania narzędzi bez zapisanego rozumowania). Przy odpowiadaniu na pytania i sprawdzaniu faktów z narzędziem do przeszukiwania Wikipedii samo rozumowanie często budowało pewny siebie wywód na fakcie, który model zmyślił, a ReAct mógł ten fakt sprawdzić. Najlepsze wyniki w odpowiadaniu na pytania dało połączenie ReAct z chain of thought, z przełączaniem się z jednej metody na drugą, gdy pierwsza nie dała pewnej odpowiedzi. Samo działanie miało kłopot z rozłożeniem celu na części i złożeniem znalezionych informacji w odpowiedź; zapisane myśli utrzymywały plan na widoku. W dwóch zadaniach interaktywnych, tekstowej grze domowej i symulowanym sklepie internetowym, ReAct z jednym albo dwoma przykładami w prompcie wypadł lepiej niż trenowane modele bazowe, z którymi porównywali go autorzy.
Ogólna lekcja: chain of thought pomaga modelowi planować, narzędzia dają mu fakty, a żadne z nich nie wystarcza do zadania, które wymaga obu.
Agent ReAct tura po turze
Poniższy blok to mały agent programistyczny z dwoma narzędziami. Każda zakładka to ta sama rozmowa krok później: linie Observation to to, co program wkleił po wykonaniu poprzedniego działania. Czytaj odpowiedzi po kolei.
Thought: Nie wiem, który test nie przechodzi ani w jaki sposób. Uruchomienie testów pokaże dokładną asercję, zanim zacznę czytać kod. Action: run_tests[tests/test_cart.py]
Zwróć uwagę na dwie rzeczy. Pierwsze działanie to uruchomienie testów, a nie zgadywanie: model zebrał dowody, zanim zaczął czytać kod. A każda myśl odnosi się do najnowszej obserwacji, czego chain of thought nie potrafi.
Wypróbuj ReAct w aplikacji czatowej
Żeby zobaczyć pętlę, nie potrzebujesz kodu. W ChatGPT, Claude albo Gemini możesz sam być narzędziem: model prosi o działanie, ty je wykonujesz i wklejasz wynik.
Thought: Głośny wentylator w spoczynku zwykle oznacza, że coś w tle używa procesora albo że wentylator ma kłopot z chłodzeniem (kurz, zablokowane otwory wentylacyjne). Sprawdzenie użycia procesora najpierw rozdziela te dwa przypadki.
Action: Otwórz Menedżer zadań (Ctrl+Shift+Esc w Windows) albo Monitor aktywności (Aplikacje > Narzędzia na Macu). Posortuj procesy według użycia procesora, odczekaj 30 sekund i podaj mi trzy procesy z góry listy wraz z ich procentowym użyciem procesora.
Te same instrukcje z prawdziwą funkcją za każdym działaniem to już agent.
Minimalna pętla ReAct w Pythonie
W kodzie program wysyła zapis rozmowy, znajduje w odpowiedzi linię Action, uruchamia pasującą funkcję, dopisuje Observation i powtarza. Ten szkic korzysta z OpenAI Python SDK i promptu systemowego z powyższego agenta programistycznego.
import re
import subprocess
from pathlib import Path
from openai import OpenAI
client = OpenAI()
MODEL = "your-model-id" # e.g. from your provider's model list
PROJECT = Path.cwd().resolve()
READABLE = {".py", ".md", ".txt", ".toml", ".cfg"}
def inside_project(arg):
# The model chooses arg: resolve it and refuse anything outside the project.
path = (PROJECT / arg).resolve()
if not path.is_relative_to(PROJECT):
raise ValueError(f"{arg} is outside the project")
return path
def run_tests(arg):
path = inside_project(arg)
if not (path.is_file() and path.name.startswith("test_") and path.suffix == ".py"):
raise ValueError(f"{arg} is not a test file")
result = subprocess.run(["pytest", str(path), "-q"], capture_output=True, text=True)
return result.stdout[-2000:]
def read_file(arg):
path = inside_project(arg)
if not path.is_file() or path.suffix not in READABLE:
raise ValueError(f"{arg} is not a file this agent may read")
return path.read_text()[:20000]
TOOLS = {"run_tests": run_tests, "read_file": read_file}
def react(task, system_prompt, max_steps=8):
transcript = f"Task: {task}\n"
for _ in range(max_steps):
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": transcript},
],
temperature=0,
)
text = response.choices[0].message.content
match = re.search(r"Action: (\w+)\[(.*)\]", text)
if not match:
return text
transcript += text[: match.end()] + "\n"
tool, arg = match.groups()
if tool == "finish":
return arg
try:
observation = TOOLS[tool](arg) if tool in TOOLS else f"Unknown tool: {tool}"
except Exception as error: # a missing file becomes an observation, not a crash
observation = f"Error: {error}"
transcript += f"Observation:\n{observation}\n"
return "Stopped after max_steps without an answer."
Znaczenie mają cztery szczegóły. Zapis rozmowy jest ucinany tuż po linii Action, bo modele czasem piszą dalej i wymyślają własną linię Observation. Narzędzie, które zawodzi (na przykład przez złą nazwę pliku), staje się obserwacją, na którą model może zareagować, zamiast przerywać pętlę. Limit kroków zatrzymuje model, który zapętla się w nieskończoność. A wynik testów jest przycinany, bo ogromny log testów zapełniłby okno kontekstu; decydowanie o tym, co trafia do tego okna, to context engineering.
Oba narzędzia sprawdzają też swój argument, zanim cokolwiek zrobią. Ten argument wybiera model, więc to narzędzie jest właściwym miejscem na ograniczenia: inside_project odrzuca każdą ścieżkę, która po rozwinięciu wychodzi poza folder projektu (łącznie ze sztuczkami z ../), run_tests akceptuje tylko pliki test_*.py, a read_file otwiera tylko kilka typów plików źródłowych i tekstowych i zwraca najwyżej 20 000 znaków, więc plik .env ani klucz SSH nigdy nie trafią do następnego zapytania. Uruchomienie pytest nadal wykonuje kod twojego projektu, więc uruchamiaj takiego agenta w kontenerze albo w jednorazowej kopii repozytorium, nigdy na maszynie, na której są sekrety.
Obecne API od OpenAI, Anthropic i Google oferują też natywne wywoływanie narzędzi: opisujesz każde narzędzie nazwą i schematem JSON, a model zwraca ustrukturyzowane wywołanie narzędzia zamiast linii Action:. Pętla jest identyczna; znika tylko parsowanie.
Bezpieczeństwo w pętli ReAct
Agent czyta tekst, którego nie napisał: strony internetowe, pliki, wyniki narzędzi. Każdy z nich może zawierać instrukcje skierowane do modelu, a to jest prompt injection. Dawaj każdemu narzędziu najmniejszy dostęp, jakiego potrzebuje (tylko do odczytu, gdzie się da), proś człowieka o potwierdzenie wszystkiego, co usuwa, wysyła albo płaci, i traktuj działania, o które prosi model, jako niezaufane wejście do sprawdzenia, a nie polecenia do ślepego wykonania.
Najczęściej zadawane pytania
Czym jest ReAct prompting?
ReAct (skrót od Reason + Act, czyli rozumuj i działaj) to wzorzec promptowania, w którym model językowy pisze krótki fragment rozumowania, potem działanie, na przykład wyszukiwanie albo wywołanie narzędzia, a następnie czyta wynik, zanim znów zacznie rozumować. Pochodzi z pracy Yao i współautorów z 2022 roku "ReAct: Synergizing Reasoning and Acting in Language Models". Nie ma nic wspólnego z biblioteką React do JavaScriptu.
Czym są Thought, Action i Observation w ReAct?
Thought (myśl) to rozumowanie modelu o tym, co zrobić dalej. Action (działanie) to wywołanie narzędzia w stałym formacie, na przykład search[python 3.13 release notes]. Observation (obserwacja) to wynik narzędzia, który twój program uzyskuje, wykonując działanie, i dopisuje do promptu. Pętla się powtarza, aż model wykona działanie kończące z odpowiedzią.
Czym różni się ReAct od chain of thought?
Chain of thought rozumuje na podstawie tego, co model już wie, więc błędny fakt na początku łańcucha pozostaje błędny. ReAct przeplata rozumowanie z działaniami, które pobierają prawdziwe informacje, więc model może sprawdzić fakt, zobaczyć, że test nie przechodzi, albo przeczytać plik, zanim pójdzie dalej. Autorzy pracy o ReAct wykazali, że oparcie rozumowania na wynikach wyszukiwania ogranicza wymyślone fakty, które produkował sam chain of thought.
Czy agenci AI nadal używają ReAct?
Samej pętli tak. Większość dzisiejszych agentów rozumuje, wywołuje narzędzie, czyta wynik i znowu decyduje, a to jest cykl ReAct. Zmienił się format: zamiast parsować linie Action: z tekstu, obecne API mają natywne wywoływanie narzędzi, w którym model zwraca ustrukturyzowane żądanie narzędzia, a twój kod odsyła wynik.
Czy mogę używać ReAct w ChatGPT bez kodu?
Tak, jeśli sam grasz rolę narzędzia. Poproś model, żeby odpowiadał jedną linią Thought i jedną linią Action, a potem się zatrzymywał. Ty wykonujesz działanie (wyszukujesz, otwierasz plik, uruchamiasz polecenie), wklejasz wynik jako Observation i powtarzasz. To powolne, ale dokładnie pokazuje, jak agent decyduje, co zrobić dalej.