# Что внутри агента

> [HTML-версия](https://learnvibecoding.ru/publiclessons/chto-vnutri-agenta) · [Индекс для LLM](https://learnvibecoding.ru/llms.txt) · [Политика использования материалов](https://learnvibecoding.ru/politika-materialov)
> Материалы защищены. Обучение LLM без согласия запрещено. При разрешённом использовании — обязательна прямая ссылка на страницу-источник.

**Курс:** Создаем своего агента обновленный

# Урок 5.2: Что внутри агента — цикл Мысль → Действие → Наблюдение

## Блок 1: Почему важно понимать что внутри

### Проблема типичная

Ты даёшь агенту задачу: "Помощь покупателю: он пишет что товар пришел поврежден"

Агент делает:
1. ✅ Находит заказ
2. ✅ Проверяет что товар действительно поврежден (фото)
3. ❌ **Потом отправляет письмо с опиской товара заново**
4. ❌ **Не предлагает замену или возврат**

Ты говоришь: "Почему он это не понял? Я же хотел чтобы предложил замену!"

Проблема: ты не понимаешь что происходит внутри, поэтому не знаешь **где агент запутался**.

Если ты знаешь как работает цикл Мысль→Действие→Наблюдение, ты сможешь:
- Понять на каком шаге агент ошибся
- Добавить правильный инструмент (например, initiate_return)
- Переписать промпт чтобы агент лучше понял задачу

---

## Блок 2: Цикл Мысль → Действие → Наблюдение

![Цикл Мысль → Действие → Наблюдение](https://supabase.learnvibecoding.ru/storage/v1/object/public/Pictures%20for%20course/Product,%20AI%20product,%20vibecoding/agent_cycle_loop.png)

Вот что происходит внутри агента. Это три шага которые повторяются:

```
         ╔═══════════════════════════════════════════════════════════╗
         ║         ЦИКЛ АГЕНТА (повторяется по кругу)                ║
         ╚═══════════════════════════════════════════════════════════╝

  ┌─────────────────────────────────────────────────────────────────┐
  │ ШАГ 1: МЫСЛЬ (Thought)                                           │
  │ ─────────────────────────────────────────────────────────────  │
  │ LLM читает задачу и говорит вслух: "Что я должен сделать?"     │
  │                                                                   │
  │ Вход: задача ("Товар поврежден, помоги")                        │
  │ Выход: план ("Мне нужно:                                        │
  │         1. Проверить заказ                                      │
  │         2. Подтвердить повреждение                              │
  │         3. Предложить замену или возврат")                      │
  └─────────────────────────────────────────────────────────────────┘
                              ↓
  ┌─────────────────────────────────────────────────────────────────┐
  │ ШАГ 2: ДЕЙСТВИЕ (Action)                                        │
  │ ─────────────────────────────────────────────────────────────  │
  │ LLM выбирает инструмент и вызывает его                          │
  │                                                                   │
  │ LLM думает: "Первый шаг — проверить заказ. Какой инструмент?"  │
  │ Ответ: "Нужен get_order_details(order_id=123)"                 │
  │                                                                  │
  │ Вызов инструмента:                                              │
  │ >>> get_order_details(order_id=123)                             │
  │ >>> return {                                                     │
  │      "order_id": 123,                                            │
  │      "item": "laptop",                                           │
  │      "status": "delivered",                                      │
  │      "customer": "john@example.com"                             │
  │ }                                                                │
  └─────────────────────────────────────────────────────────────────┘
                              ↓
  ┌─────────────────────────────────────────────────────────────────┐
  │ ШАГ 3: НАБЛЮДЕНИЕ (Observation)                                 │
  │ ─────────────────────────────────────────────────────────────  │
  │ LLM видит результат инструмента и решает что дальше             │
  │                                                                   │
  │ LLM читает результат:                                           │
  │ "Хорошо, заказ есть, статус 'delivered'. Теперь нужно          │
  │  проверить фото повреждения. Вызываю next_tool..."             │
  │                                                                  │
  │ Выход: "нужен следующий инструмент" ИЛИ "всё готово"          │
  └─────────────────────────────────────────────────────────────────┘
                              ↓
                    [ЦИКЛ ПОВТОРЯЕТСЯ или заканчивается]
```

### Реальный пример цикла

Давай посмотрим как это работает для одной задачи. Задача: "Клиент жалуется что не получил письмо подтверждение заказа. Найди где проблема."

```
════════════════════════════════════════════════════════════════════

ИТЕРАЦИЯ 1:

МЫСЛЬ (LLM думает):
  "Задача: найти почему клиент не получил письмо.
   Мне нужно:
   1. Проверить есть ли заказ (проверить в БД)
   2. Проверить отправилось ли письмо (посмотреть логи)
   3. Проверить попало ли в спам (посмотреть у провайдера если есть доступ)
   
   Начинаю с проверки заказа."

ДЕЙСТВИЕ:
  > Вызвать: find_order_by_email(email="john@example.com")
  > Результат: { "order_id": 456, "status": "confirmed", "date": "2025-05-06" }

НАБЛЮДЕНИЕ:
  "Заказ есть, со статусом 'confirmed'. Теперь проверю был ли отправлен email."

════════════════════════════════════════════════════════════════════

ИТЕРАЦИЯ 2:

МЫСЛЬ:
  "Хорошо, заказ подтвержден. Теперь нужно проверить отправилось ли письмо."

ДЕЙСТВИЕ:
  > Вызвать: check_email_logs(order_id=456)
  > Результат: { "email_sent": false, "reason": "SMTP_ERROR", "error": "Connection timeout" }

НАБЛЮДЕНИЕ:
  "Ага! Письмо вообще не отправилось. Причина: SMTP ошибка.
   Теперь у меня есть ответ на вопрос клиента.
   Я могу либо:
   - Отправить письмо заново (вызвать send_confirmation_email)
   - Объяснить клиенту что случилось
   
   Буду делать оба."

════════════════════════════════════════════════════════════════════

ИТЕРАЦИЯ 3:

МЫСЛЬ:
  "Нужно отправить письмо заново и объяснить клиенту."

ДЕЙСТВИЕ:
  > Вызвать: send_confirmation_email(order_id=456)
  > Результат: { "status": "sent", "email": "john@example.com" }

НАБЛЮДЕНИЕ:
  "Письмо отправлено успешно. Теперь напишу ответ клиенту."

════════════════════════════════════════════════════════════════════

ИТЕРАЦИЯ 4:

МЫСЛЬ:
  "Всё готово. Могу написать ответ."

ДЕЙСТВИЕ:
  > Вызвать: send_response_to_customer(
      order_id=456,
      message="Это произошло из-за технической ошибки SMTP. 
               Мы отправили письмо заново. 
               Проверьте почту (и папку спама)."
    )
  > Результат: { "status": "sent" }

НАБЛЮДЕНИЕ:
  "Ответ отправлен. Задача завершена."

════════════════════════════════════════════════════════════════════

ИТЕРАЦИЯ 5:

МЫСЛЬ:
  "Задача полностью выполнена. Останавливаю работу."

ДЕЙСТВИЕ:
  > Нет действия

НАБЛЮДЕНИЕ:
  > Агент заканчивает работу

════════════════════════════════════════════════════════════════════
```

**Видишь что произошло?**

Агент прошел 4 итерации. На каждой он:
1. Думал что дальше (основываясь на результате предыдущего)
2. Вызывал правильный инструмент
3. Смотрел результат и решал продолжать или останавливаться

Это не магия, это просто цикл.

---

## Блок 3: Мысль (Thought) — как LLM решает что делать

Это самый интересный шаг. Вот что происходит:

### Как работает мысль

```
INPUT: 
  - Исходная задача ("Клиент жалуется что товар поврежден")
  - История предыдущих действий (если это не первый шаг)
  - Доступные инструменты (список чего может сделать агент)

↓ (LLM обрабатывает)

PROCESS (внутри LLM):
  LLM читает: "Мне дали задачу. У меня есть эти инструменты.
               Какой следующий шаг логически правильный?"
  
  LLM думает вслух: "Сначала нужно проверить что товар реально поврежден.
                     Для этого нужен инструмент check_product_damage().
                     Потом, если повреждено, нужно предложить замену или возврат."

↓

OUTPUT:
  Текст: "Я проверю товар и предложу решение."
  Выбранный инструмент: check_product_damage
  Параметры: { order_id: 123, item_id: "A456" }
```

### Откуда LLM знает какой инструмент выбрать?

![Описания инструментов для LLM](https://supabase.learnvibecoding.ru/storage/v1/object/public/Pictures%20for%20course/Product,%20AI%20product,%20vibecoding/tool_descriptions_llm_v2.png)

Это происходит благодаря **описанию инструментов** которое ты даёшь агенту.

Примеры:

```
Ты говоришь агенту:
───────────────────

Инструмент 1: check_product_damage
  Описание: "Проверяет поврежден ли товар. Требует фото товара."
  Параметры: order_id, item_id
  Возвращает: { damaged: boolean, severity: "low"|"medium"|"high" }

Инструмент 2: initiate_return
  Описание: "Начинает процесс возврата товара"
  Параметры: order_id
  Возвращает: { return_id: string, status: "initiated" }

Инструмент 3: initiate_replacement
  Описание: "Отправляет замену товара"
  Параметры: order_id, reason: string
  Возвращает: { replacement_id: string, eta: string }

───────────────────

LLM использует эти описания чтобы решить какой инструмент нужен.

Когда задача "товар поврежден", LLM видит что есть инструмент
"check_product_damage" и выбирает его потому что описание совпадает с задачей.
```

### Частая ошибка: плохое описание инструмента

```
ПЛОХО:
  send_message(text: string)
  Описание: "Отправляет сообщение"
  
LLM не знает кому отправить, когда отправить, почему.

ХОРОШО:
  send_customer_notification(order_id, message_type: "status_update"|"problem"|"solution")
  Описание: "Отправляет уведомление клиенту о заказе. 
             message_type определяет тип уведомления:
             - 'status_update': информирует о статусе доставки
             - 'problem': сообщает о проблеме (повреждение, задержка)
             - 'solution': предлагает решение (замена, возврат)
             
             Пример: send_customer_notification(
               order_id=123,
               message_type='solution'
             )"

LLM теперь знает:
  - Кому отправить (клиент заказа)
  - Когда использовать (когда есть проблема или решение)
  - Какой параметр выбрать (solution для предложения замены)
```

---

## Блок 4: Действие (Action) — как агент вызывает инструмент

Самый скучный шаг, но важный.

### Что происходит

```
LLM решил: "нужен инструмент check_product_damage с параметрами order_id=123, item_id=A456"

↓

СИСТЕМА ВЫЗЫВАЕТ ИНСТРУМЕНТ:
  >>> check_product_damage(order_id=123, item_id="A456")
  
Инструмент это реальная функция в коде:
  def check_product_damage(order_id, item_id):
    # Получи фото товара
    photos = get_product_photos(order_id, item_id)
    # Проанализируй фото (это может быть AI анализ или человек смотрит)
    result = analyze_photos(photos)
    return {
      "damaged": result.is_damaged,
      "severity": result.damage_level,  # "low", "medium", "high"
      "description": result.description
    }

  ↓
  
  Возвращает результат:
  {
    "damaged": true,
    "severity": "high",
    "description": "Экран разбит, левый край помят"
  }
```

### Ошибка на этапе действия

Если инструмент сломан или вернул ошибку:

```
LLM: "Вызываю check_product_damage"

Инструмент: "ERROR: order_id 123 не найден в БД"

↓

Это видит LLM и переходит к НАБЛЮДЕНИЮ:
  "Ошибка: заказ не найден. Значит, я неправильно искал заказ в предыдущем шаге.
   Нужно попробовать заново или с другими параметрами."
```

---

## Блок 5: Наблюдение (Observation) — как агент реагирует на результат

Это самый важный шаг. Вот где агент показывает интеллект.

### Что происходит

```
LLM получил результат инструмента:
{
  "damaged": true,
  "severity": "high",
  "description": "Экран разбит, левый край помят"
}

↓

LLM АНАЛИЗИРУЕТ результат:

"Товар действительно повреждён, и повреждение серьёзное (high).
 Я должен предложить замену или возврат.
 
 Какой вариант выбрать?
 - Если товар дорогой и человека расстроит → замена
 - Если товар дешевый → возврат
 
 Проверю цену..."

↓

LLM принимает решение:

"Товар дорогой (MacBook стоит $1200+).
 Клиент расстроен. Предложу замену.
 Вызовут initiate_replacement()."

↓ (возвращается к МЫСЛИ)

СЛЕДУЮЩАЯ ИТЕРАЦИЯ ЦИКЛА:

МЫСЛЬ: "Нужно инициировать замену"
ДЕЙСТВИЕ: Вызвать initiate_replacement(order_id=123, reason="Товар получен с повреждениями экрана")
НАБЛЮДЕНИЕ: Замена инициирована, номер замены RMA-789
...
```

### Ключевое отличие: гибкое принятие решения

Агент не просто "если поврежден → замена". Агент анализирует результат и решает в зависимости от ситуации.

```
Если результат: "Товар слегка поцарапан (низкий уровень повреждения)"
→ Агент предложит скидку

Если результат: "Экран полностью разбит"  
→ Агент предложит замену или возврат

Если результат: "Ошибка: не удалось проанализировать фото"
→ Агент попросит клиента отправить более чёткое фото

Если результат: "Товар не повреждён, но клиент просит повесить на стену"
→ Агент предложит услугу установки (если есть такой инструмент)
```

Это в коде было бы 10 if/else. Агент это делает естественно.

---

## Блок 6: Когда цикл заканчивается

Агент останавливается когда одно из этого:

### 1. LLM решил что задача выполнена

```
НАБЛЮДЕНИЕ: "Всё готово. Товар заменяется, клиент уведомлен."

МЫСЛЬ: "Задача завершена, больше делать нечего."

ДЕЙСТВИЕ: Нет

НАБЛЮДЕНИЕ: Останавливаю работу.
```

### 2. Произошла ошибка которую не исправить

```
ДЕЙСТВИЕ: Вызвать send_email(...)

Инструмент вернул: ERROR: "Сервис email недоступен. Retry позже."

НАБЛЮДЕНИЕ: "Я не могу отправить письмо прямо сейчас. 
             Всё что я мог сделать — сделал.
             Останавливаю работу и сообщаю об ошибке."
```

### 3. Превышено максимальное количество итераций

```
Ты настроил: max_iterations = 10

После 10-й итерации агент останавливается независимо от того закончена задача или нет.

Это защита от бесконечного цикла.
```

### 4. Агент попросил помощь человека

```
МЫСЛЬ: "Ситуация сложная. Товар реально поврежден, 
         но клиент просит не просто замену, а ещё компенсацию.
         Это не мой уровень полномочий.
         Нужна помощь менеджера."

ДЕЙСТВИЕ: Вызвать escalate_to_manager(order_id=123, reason="...")

НАБЛЮДЕНИЕ: "Задача передана менеджеру. Мой цикл завершён."
```

---

## Блок 7: Визуальная карта того как это работает в коде

Когда ты пишешь агента, ты пишешь что-то типа этого (псевдокод):

```python
# Это то что ты пишешь один раз:
agent = Agent(
    llm=claude,
    tools=[
        check_product_damage,
        initiate_replacement,
        initiate_return,
        send_customer_notification,
        escalate_to_manager
    ],
    system_prompt="Ты customer support агент. Помогай клиентам решать проблемы с товарами."
)

# Это то что происходит сотни раз (в цикле):
result = agent.run(task="Клиент: мой товар пришел поврежденным")

# ВНУТРИ agent.run() происходит:
while not task_completed:
    # МЫСЛЬ
    thought = llm.think(
        task=task,
        tools=available_tools,
        previous_steps=history
    )
    # Выход: "Нужно проверить товар"
    
    # ДЕЙСТВИЕ  
    tool_name, parameters = thought.extract_tool_and_params()
    # tool_name = "check_product_damage", parameters = {order_id: 123}
    
    result = tools[tool_name](**parameters)
    # Инструмент вернул результат
    
    # НАБЛЮДЕНИЕ
    history.append({
        thought: thought,
        action: tool_name,
        observation: result
    })
    
    # Решить продолжать или заканчивать
    if thought.is_task_complete:
        task_completed = True
    
    iteration_count += 1
    if iteration_count > max_iterations:
        task_completed = True

return final_response
```

**Важное:** ты пишешь инструменты (функции), а агент пишет логику вызова.

---

## Блок 8: Где может быть ошибка в цикле

![Ошибки в цикле агента](https://supabase.learnvibecoding.ru/storage/v1/object/public/Pictures%20for%20course/Product,%20AI%20product,%20vibecoding/agent_cycle_errors.png)

### Ошибка на этапе МЫСЛЬ

```
❌ LLM не понял задачу
   Причина: система промпт написан плохо
   Пример: агент думает "клиент просит замену" вместо "клиент пишет что товар поврежден"
   Как исправить: переписать system_prompt

❌ LLM выбрал неправильный инструмент
   Причина: описание инструментов запутанное
   Пример: вместо check_product_damage выбрал send_message
   Как исправить: улучшить описание инструмента
```

### Ошибка на этапе ДЕЙСТВИЕ

```
❌ Инструмент вернул ошибку
   Причина: параметры неправильные или сервис недоступен
   Пример: check_product_damage не нашел заказ
   Как исправить: сделать инструмент more robust (проверка параметров)

❌ Инструмент вернул результат в неправильном формате
   Причина: ты не задал что инструмент должен возвращать
   Пример: вместо {damaged: true} вернул "yes"
   Как исправить: явно описать формат возврата
```

### Ошибка на этапе НАБЛЮДЕНИЕ

```
❌ LLM неправильно интерпретировал результат
   Причина: результат был неполный или неясный
   Пример: вернулось {damaged: true, severity: null}
           LLM не понял что severity не определена
   Как исправить: инструмент должен всегда возвращать полный результат

❌ LLM не знает что дальше делать
   Причина: результат не соответствует ни одному сценарию
   Пример: check_product_damage вернул "UNKNOWN" (камера не может определить)
           Агент не знает что с этим делать
   Как исправить: предусмотреть инструмент для этого сценария (попросить другое фото)
```

---

## Блок 9: Отличие от программы

Помнишь из урока 5.1 что агент это не просто программа со сложной логикой?

Вот почему:

### ПРОГРАММА

```python
def handle_damaged_product(order_id, damage_level):
    if damage_level == "low":
        offer_discount(order_id, 10%)
    elif damage_level == "medium":
        initiate_replacement(order_id)
    elif damage_level == "high":
        initiate_return(order_id)
    else:
        escalate_to_manager(order_id)
    
    send_notification(order_id)
```

**Проблема:** логика жёсткая. Если появится новый сценарий (например, "товар приехал не в том цвете"), нужно менять код.

### АГЕНТ

```python
agent = Agent(
    llm=claude,
    tools=[
        check_product_condition,
        offer_discount,
        initiate_replacement,
        initiate_return,
        escalate_to_manager,
        send_notification
    ],
    system_prompt="Помогай клиентам с проблемами товара"
)

result = agent.run("Товар пришел поврежденным")
```

**Преимущество:** LLM читает результат check_product_condition и сам решает что делать. Если условие новое — LLM всё равно выберет правильный инструмент.

---

## Блок 10: Карта процесса

```
ЗАДАЧА ПОСТУПАЕТ
      ↓
   ┌─────────────────────────────────────┐
   │  ИТЕРАЦИЯ N                         │
   │                                      │
   │  1. МЫСЛЬ (LLM думает)              │
   │     "Что делать дальше?"            │
   │     ↓ выбирает инструмент           │
   │                                      │
   │  2. ДЕЙСТВИЕ (вызов инструмента)    │
   │     get_data() → результат          │
   │     ↓                                │
   │                                      │
   │  3. НАБЛЮДЕНИЕ (LLM смотрит результат)
   │     "Что означает результат?"       │
   │     ↓ решает продолжать или стоп    │
   │                                      │
   └─────────────────────────────────────┘
           ↓
      Задача решена?  
      ├─ ДА → КОНЕЦ
      └─ НЕТ → вернись к МЫСЛИ (итерация N+1)
```

---

## ✅ Проверь себя

- [ ] **Назови три этапа цикла агента** Мысль, Действие, Наблюдение
- [ ] **Что происходит в МЫСЛИ?** LLM решает какой инструмент нужен
- [ ] **Что происходит в ДЕЙСТВИИ?** Инструмент вызывается и возвращает результат
- [ ] **Что происходит в НАБЛЮДЕНИИ?** LLM смотрит результат и решает продолжать или стоп
- [ ] **Почему агент это не программа?** LLM сам выбирает логику, не зафиксирована в коде
- [ ] **Где могут быть ошибки в цикле?** На всех трёх этапах (плохой промпт, сломанный инструмент, неправильная интерпретация)

[Все уроки](https://learnvibecoding.ru/publiclessons.md) · HTML: https://learnvibecoding.ru/publiclessons