Menu

ReAct промптинг: цикл «рассуждай и действуй»

ReAct промптинг заставляет модель чередовать рассуждение о задаче и вызов инструмента, читая каждый результат, прежде чем решить, каким будет следующий шаг. Это цикл, на котором работает большинство ИИ-агентов.

Каждый промпт на этой странице можно изменить и открыть в ChatGPT, Claude или другом ИИ-приложении.

ReAct промптинг: это схема, в которой языковая модель чередует рассуждение и действие. Она пишет мысль о том, что делать, выполняет действие, например поиск или вызов инструмента, читает результат и только потом решает, каким будет следующий шаг. Название: сокращение от Reason + Act («рассуждай и действуй»), оно пришло из работы Yao et al. 2022, «ReAct: Synergizing Reasoning and Acting in Language Models». К React, JavaScript-библиотеке для создания интерфейсов, она отношения не имеет.

Большинство ИИ-агентов, которые ходят по сайтам, запускают код или редактируют файлы, работают на какой-то версии этого цикла. Если один раз пройти его вручную, поведение агентов становится гораздо проще предсказывать и отлаживать.

Цикл Thought, Action, Observation

Промпт ReAct просит модель писать строки трёх видов.

  • Thought (мысль): рассуждение о текущей ситуации и о том, какой информации не хватает.
  • Action (действие): один вызов инструмента в фиксированном формате, например search[query], read_file[path] или finish[answer].
  • Observation (наблюдение): результат этого действия. Эту строку модель не пишет. Её добавляет ваша программа (или вы), выполнив действие и вставив в запись диалога настоящий вывод.

Затем вся запись снова уходит модели, и та пишет следующую мысль. Цикл заканчивается, когда модель выбирает завершающее действие. Модель сама никогда не запускает инструмент; она только просит, а решение, выполнять ли запрос, принимает код вокруг неё.

Почему рассуждение плюс действие лучше каждого по отдельности

В статье ReAct сравнили с промптами, которые только рассуждают (chain of thought), и промптами, которые только действуют (вызовы инструментов без записанных рассуждений). На ответах на вопросы и проверке фактов с инструментом поиска по Википедии одно лишь рассуждение часто строило уверенный аргумент на факте, который модель выдумала, а ReAct мог этот факт найти; лучшие результаты в ответах на вопросы дало сочетание ReAct с chain of thought, когда при неуверенном ответе одного метода переключались на другой. Одно лишь действие плохо справлялось с разбиением цели на части и со сведением найденного в ответ; записанные мысли держали план на виду. На двух интерактивных задачах, текстовой игре по дому и симуляции интернет-магазина, ReAct с одним-двумя примерами в промпте показал себя лучше обученных базовых систем, с которыми сравнивали авторы.

Общий вывод: chain of thought помогает модели планировать, инструменты дают ей факты, и ни того ни другого по отдельности не хватает для задачи, которой нужно и то и другое.

ReAct-агент, реплика за репликой

Блок ниже: небольшой агент для кода с двумя инструментами. Каждая вкладка: тот же диалог на шаг позже; строки Observation: это то, что программа вставила обратно после выполнения предыдущего действия. Метки Thought, Action и Observation оставлены на английском, потому что их ищет код ниже. Читайте ответы по порядку.

System prompt
Решай задачу, повторяя Thought, Action и Observation. Thought: рассуди, что ты знаешь и что делать дальше. Action: ровно одно из run_tests[path] запускает pytest на файле и возвращает вывод read_file[path] возвращает содержимое файла finish[answer] завершает задачу твоим ответом Напиши одну Thought и одну Action, затем остановись. Observation тебе дадут.
Задача: tests/test_cart.py начал падать после вчерашнего слияния. Найди причину.
Try it
Chat apps receive the system prompt as the start of your message, so this tries its wording, not its priority. To test it as standing instructions, put it in the app's custom instructions or the API's system field.
Example replyReplies vary between models and runs.

Thought: Я не знаю, какой тест падает и как. Запуск тестов покажет точное утверждение до того, как я начну читать код. Action: run_tests[tests/test_cart.py]

Обратите внимание на две вещи. Первое действие: запуск тестов, а не догадка; модель собрала доказательства, прежде чем читать код. И каждая мысль опирается на последнее наблюдение, а этого chain of thought сделать не может.

Попробуйте ReAct в чат-приложении

Чтобы увидеть цикл, код не нужен. В ChatGPT, Claude или Gemini инструментом можете быть вы: модель просит действие, вы его выполняете и вставляете результат.

Будь инструментами модели
Fill in
Я хочу ответить на вопрос: Почему вентилятор ноутбука громко шумит, даже когда я ничего не делаю? Помоги мне, работая в цикле. Каждый твой ответ содержит ровно одну Мысль (что ты знаешь на данный момент и чего не хватает) и одно Действие: конкретную вещь, которую мне нужно проверить, запустить или найти, с точными шагами. Затем остановись и жди. Я отвечу результатом в виде «Наблюдение: ...». Когда доказательств будет достаточно, ответь «Ответ:» и своим выводом. Не угадывай ответ, пока нет доказательств.
Try it
Example replyReplies vary between models and runs.

Мысль: громкий вентилятор в простое обычно означает, что что-то в фоне нагружает процессор или вентилятору трудно охлаждать (пыль, закрытые вентиляционные отверстия). Если сначала проверить загрузку процессора, эти два случая разделятся.

Действие: откройте Диспетчер задач (Ctrl+Shift+Esc в Windows) или Мониторинг системы (Программы > Утилиты на Mac). Отсортируйте процессы по загрузке ЦП, подождите 30 секунд и назовите мне три верхних процесса и их процент загрузки ЦП.

Те же инструкции, но с настоящей функцией за каждым действием, и есть агент.

Минимальный цикл ReAct на Python

В коде программа отправляет запись диалога, находит в ответе строку Action, запускает соответствующую функцию, добавляет Observation и повторяет. Этот набросок использует Python SDK от OpenAI и системный промпт агента для кода из примера выше.

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."

Здесь важны четыре детали. Запись обрезается сразу после Action, потому что модели иногда продолжают писать и выдумывают собственное Observation. Сбой инструмента (скажем, неверное имя файла) становится наблюдением, на которое модель может отреагировать, а не роняет цикл. Ограничение на число шагов останавливает модель, которая зациклилась. А вывод тестов обрезается, потому что огромный лог тестов заполнил бы контекстное окно; решать, что попадает в это окно, и есть контекст-инжиниринг.

Оба инструмента к тому же проверяют аргумент, прежде чем что-либо делать. Аргумент выбирает модель, поэтому ограничения должны жить в самом инструменте: inside_project отклоняет любой путь, ведущий за пределы папки проекта (в том числе через ../), run_tests принимает только файлы test_*.py, а read_file открывает лишь несколько типов файлов с кодом и текстом и возвращает не больше 20 000 символов, так что файл .env или SSH-ключ никогда не попадут в следующий запрос. Запуск pytest всё равно выполняет код вашего проекта, поэтому запускайте такого агента в контейнере или в одноразовой копии репозитория, но не на машине с секретами.

Современные API от OpenAI, Anthropic и Google также предлагают встроенный вызов инструментов: вы описываете каждый инструмент именем и JSON-схемой, и модель возвращает структурированный вызов инструмента вместо строки Action:. Цикл тот же; исчезает только разбор текста.

Безопасность в цикле ReAct

Агент читает текст, который написал не он: веб-страницы, файлы, вывод инструментов. В любом из них могут быть инструкции, адресованные модели, это промпт-инъекция. Давайте каждому инструменту минимально необходимый доступ (где можно, только чтение), просите человека подтверждать всё, что удаляет, отправляет или платит, и считайте запрошенные моделью действия непроверенным вводом, который нужно проверить, а не командами, которые можно выполнять вслепую.

Часто задаваемые вопросы

Что такое ReAct промптинг?

ReAct (сокращение от Reason + Act, «рассуждай и действуй»): это схема промптинга, при которой языковая модель пишет короткое рассуждение, затем действие, например поиск или вызов инструмента, а потом читает результат и только после этого рассуждает снова. Она пришла из работы Yao et al. 2022, «ReAct: Synergizing Reasoning and Acting in Language Models». К JavaScript-библиотеке React она отношения не имеет.

Что такое Thought, Action и Observation в ReAct?

Thought (мысль): рассуждение модели о том, что делать дальше. Action (действие): вызов инструмента в фиксированном формате, например search[python 3.13 release notes]. Observation (наблюдение): вывод инструмента, который ваша программа получает, выполнив действие, и добавляет в промпт. Цикл повторяется, пока модель не выберет завершающее действие со своим ответом.

Чем ReAct отличается от chain of thought?

Chain of thought рассуждает на основе того, что модель уже знает, поэтому неверный факт в начале цепочки так и остаётся неверным. ReAct перемежает рассуждение с действиями, которые добывают реальную информацию, так что модель может проверить факт, увидеть упавший тест или прочитать файл, прежде чем продолжить. В статье о ReAct обнаружили, что опора рассуждения на результаты поиска сократила число выдуманных фактов, которые давал один chain of thought.

Используют ли ИИ-агенты ReAct сегодня?

Цикл: да. Большинство агентов сегодня рассуждают, вызывают инструмент, читают результат и решают снова, и это и есть цикл ReAct. Изменился формат: вместо разбора строк Action: из текста в современных API есть встроенный вызов инструментов, при котором модель возвращает структурированный запрос к инструменту, а ваш код отправляет обратно результат.

Можно ли использовать ReAct в ChatGPT без кода?

Да, если играть роль инструмента самому. Попросите модель отвечать одной мыслью и одним действием и останавливаться. Вы выполняете действие (поиск, открыть файл, запустить команду), вставляете результат как наблюдение и повторяете. Это медленно, но точно показывает, как агент решает, что делать дальше.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ