Маппинг ReAct на команды Vibe-Check
Updated Jul 2026
Связь теории и практики
Паттерн ReAct абстрактен: наблюдение, размышление, действие, оценка. Чтобы сделать его конкретным, нужно отобразить каждую фазу на реальные команды, которые ИИ-агент может выполнять. CLI vibe-check предоставляет именно такие команды, что делает его практической реализацией цикла ReAct для браузерного тестирования.
Отображение фаз на команды
| Фаза ReAct | Активность тестирования | Команды Vibe-Check |
|---|---|---|
| Observe | Чтение текущего состояния страницы | vibe-check text "body", vibe-check url, vibe-check screenshot, vibe-check find-all "selector" |
| Think | Решение, что тестировать на основе наблюдения | Агент рассуждает внутренне (нет команды -- вывод LLM) |
| Act | Выполнение тестового действия | vibe-check type "selector" "text", vibe-check click "selector", vibe-check navigate "url" |
| Evaluate | Проверка результата относительно ожиданий | vibe-check text ".error", vibe-check url, vibe-check find "selector" |
Команды наблюдения подробно
Фаза наблюдения заключается в сборе состояния. Разные команды раскрывают разные аспекты:
# Get the full visible text of the page (for content analysis)
vibe-check text "body"
# Get text from a specific element (for targeted checks)
vibe-check text ".notification-banner"
# Get the current URL (for navigation verification)
vibe-check url
# Take a screenshot (for visual state capture)
vibe-check screenshot -o current-state.png
# Find all elements matching a selector (for structural analysis)
vibe-check find-all "button"
# Get HTML of a section (for deep structural analysis)
vibe-check html
# Evaluate JavaScript (for dynamic state)
vibe-check eval "document.querySelectorAll('.error').length"
Команды действия подробно
# Navigation
vibe-check navigate "https://app.example.com/login"
# Form interaction
vibe-check type "input[name=email]" "user@test.com"
vibe-check type "input[name=password]" "secret123"
vibe-check select "#country" "United States"
# Clicking
vibe-check click "button[type=submit]"
vibe-check click "#menu-toggle"
# Keyboard
vibe-check keys "Enter"
vibe-check keys "Ctrl+a"
# Scrolling
vibe-check scroll down
vibe-check scroll "footer"
# Hovering
vibe-check hover ".dropdown-trigger"
# Waiting
vibe-check wait "#loading-spinner" --state=hidden
vibe-check wait ".content" --state=visible
Полный тест ReAct с использованием Vibe-Check
Вот как агент проходит через тест входа, используя цикл ReAct и команды vibe-check:
TEST OBJECTIVE: Verify that submitting the login form with empty fields
shows appropriate validation errors.
STEP 1 — OBSERVE:
$ vibe-check navigate "https://app.example.com/login"
$ vibe-check text "body"
→ "Login to Your Account | Email | Password | Sign In | Forgot Password?"
STEP 2 — THINK:
"I see a login form with email and password fields and a Sign In button.
My objective is to test empty field submission. I should click Sign In
without filling in any fields."
STEP 3 — ACT:
$ vibe-check click "button:has-text('Sign In')"
STEP 4 — OBSERVE:
$ vibe-check text ".error-message"
→ "Email is required"
$ vibe-check find-all ".field-error"
→ [
{ "selector": "#email-error", "text": "Email is required" },
{ "selector": "#password-error", "text": "Password is required" }
]
STEP 5 — THINK:
"Two validation errors appeared: one for email and one for password.
Both say the field is required. This matches expected behavior.
Let me also verify we stayed on the login page (no navigation)."
STEP 6 — OBSERVE:
$ vibe-check url
→ "https://app.example.com/login"
STEP 7 — THINK:
"URL has not changed. We are still on the login page. Both required
field errors are shown. Test objective is met."
STEP 8 — EVALUATE:
DONE pass "Empty form submission correctly shows validation errors
for both email ('Email is required') and password ('Password is required').
Page did not navigate away from /login."
Реализация агента на Python
import subprocess
import json
class VibeCheckReActAgent:
"""A ReAct test agent using vibe-check CLI commands."""
def __init__(self, llm, max_steps=15):
self.llm = llm
self.max_steps = max_steps
self.history = []
def vibe(self, command: str) -> str:
"""Execute a vibe-check command and return output."""
result = subprocess.run(
f"vibe-check {command}",
shell=True, capture_output=True, text=True, timeout=30
)
if result.returncode != 0:
return f"ERROR: {result.stderr.strip()}"
return result.stdout.strip()
def observe(self) -> dict:
"""Gather current page state using vibe-check commands."""
return {
"url": self.vibe("url"),
"text": self.vibe('text "body"')[:2000],
"title": self.vibe("title"),
"errors": self.vibe('eval "document.querySelectorAll(\'.error\').length"'),
}
def run(self, objective: str) -> dict:
"""Execute a test using the ReAct loop."""
for step in range(self.max_steps):
# OBSERVE
state = self.observe()
# THINK + decide
prompt = f"""
You are a QA test agent. Your objective: {objective}
Current state:
- URL: {state['url']}
- Page text (first 2000 chars): {state['text']}
- Error count: {state['errors']}
History (last 5 actions):
{json.dumps(self.history[-5:], indent=2)}
Respond with exactly ONE action:
VIBE <command> — execute a vibe-check command
PASS <reason> — test passed, explain why
FAIL <reason> — test failed, explain why
"""
response = self.llm.generate(prompt).strip()
self.history.append({"step": step, "state_url": state["url"], "action": response})
# ACT or EVALUATE
if response.startswith("VIBE "):
command = response[5:]
output = self.vibe(command)
self.history[-1]["output"] = output
elif response.startswith("PASS "):
return {"status": "pass", "reason": response[5:], "steps": step + 1}
elif response.startswith("FAIL "):
return {"status": "fail", "reason": response[5:], "steps": step + 1}
return {"status": "timeout", "reason": f"Exceeded {self.max_steps} steps", "steps": self.max_steps}
Паттерны восстановления после ошибок
Один из самых мощных аспектов маппинга ReAct на vibe-check -- способность агента восстанавливаться после ошибок:
Восстановление при отсутствии селектора
Agent tries: vibe-check click "#submit-btn"
Output: ERROR: No element found for selector '#submit-btn'
Agent observes: vibe-check find-all "button"
Output: [
{"selector": "button.primary-action", "text": "Submit"},
{"selector": "button.cancel", "text": "Cancel"}
]
Agent reasons: "The submit button exists but has a different selector.
I should use 'button.primary-action' instead."
Agent acts: vibe-check click "button.primary-action"
Output: success
Восстановление при неожиданном состоянии
Agent tries: vibe-check click "#checkout-btn"
Output: success
Agent observes: vibe-check text "body"
Output: "Your session has expired. Please log in again."
Agent reasons: "Session expired during checkout. This is an environment
issue. I need to log in again before continuing the test."
Agent acts:
vibe-check type "#email" "test@example.com"
vibe-check type "#password" "password123"
vibe-check click "#login-btn"
// Then retries the checkout
Соображения производительности
| Метрика | Агент Vibe-Check | Прямой скрипт Playwright |
|---|---|---|
| Шагов на тест | 8-20 | Фиксировано (известно при написании) |
| Время на шаг (LLM) | 200-500 мс | 0 мс (нет рассуждений) |
| Время на шаг (браузер) | 100-300 мс | 100-300 мс |
| Общее время теста | 5-15 секунд | 1-3 секунды |
| Адаптивность | Высокая | Нулевая |
| Сложность отладки | Средняя (трассировка истории) | Низкая (линейный скрипт) |
Ключевой вывод
CLI vibe-check обеспечивает естественное отображение абстрактного паттерна ReAct на конкретные команды браузерной автоматизации. Каждая фаза ReAct имеет соответствующие команды vibe-check: наблюдение через text/url/find-all/screenshot, действие через click/type/navigate и оценка через проверки с помощью text и url, подобные утверждениям. Это отображение превращает теоретический цикл ReAct в практичного, реализуемого тестового агента.