Урок 2. Цикл ReAct
ReAct (Reasoning + Acting) — главный режим работы агента: рассуждение → действие → наблюдение → снова рассуждение. Вся история шагов — траектория — добавляется в контекст, поэтому агент «помнит», что уже сделал.
┌─────────────────────────┐
│1. КОНТЕКСТ │◀
│system + вся история ││
└────────────┬────────────┘│
│ │
▼ │
┌─────────────────────────┐│
│2. LLM решает ││
│мысль или вызов JSON? ││
└─────┬──────────────┬────┘│
вызов│ │ финальный текст
▼ ▼ │
┌─────────────────┐┌─────────┐│
│ 3. ИНСТРУМЕНТ ││4. ГОТОВО││
│ (действие) ││ ответ ││
└────────┬────────┘└─────────┘│
│ наблюдение │
└────────────────────┐
Что прочитать
- Цикл ReAct — петля «рассуждение — действие — наблюдение»
- Агентный цикл в коде — как цикл выглядит в программе
- Вызов инструментов — что происходит в момент «действие»
В коде
Скелет цикла — всё, что будет в нашем CLI-агенте:
messages = [system_prompt, user_task]
for step in range(MAX_STEPS): # Harness-ограждение: предел шагов
reply = chat(messages) # 1. рассуждение (или вызов)
call = parse_tool(reply) # LLM ответил JSON-вызовом?
if not call:
print(reply) # 4. финальный ответ — выходим
break
obs = run_tool(call) # 2. действие
messages += [ # 3. наблюдение — в контекст
{"role": "assistant", "content": reply},
{"role": "user", "content": f"Наблюдение: {obs}"},
]
for (let step = 0; step < MAX_STEPS; step++) {
const reply = await chat(messages); // 1. рассуждение
const call = parseTool(reply); // JSON-вызов?
if (!call) { console.log(reply); break; } // 4. финальный ответ
const obs = runTool(call); // 2. действие
messages.push({ role: "assistant", content: reply }, // 3.
{ role: "user", content: "Наблюдение: " + obs });
}
Ключевая деталь: результат инструмента возвращается в контекст как «наблюдение» — это и есть глаза агента из урока 1.
Практика
Для своего агента из урока 1 напиши псевдокод цикла: что повторяется, где остановка, что попадает в траекторию. Прогони мысленно одну задачу — какие действия он выберет по шагам.
Связано: Урок 1. Формула агента, Урок 3. Harness и ограждения