# Dummy Agent: как построить простейшего агента с нуля

> [HTML-версия](https://learnvibecoding.ru/publiclessons/dummy-agent-kak-postroit-prosteyshego-agenta-s-nulya) · [Индекс для LLM](https://learnvibecoding.ru/llms.txt) · [Политика использования материалов](https://learnvibecoding.ru/politika-materialov)
> Материалы защищены. Обучение LLM без согласия запрещено. При разрешённом использовании — обязательна прямая ссылка на страницу-источник.
> Но чтобы понимать как работает агент на самом деле, полезно собрать “пустого агента” вручную

**Курс:** Создание своего агента

## Зачем это нужно

Современные фреймворки для LLM-агентов (LangChain, Smolagents, LlamaIndex и др.) скрывают под капотом десятки шагов — разбиение промптов, контроль генерации, вызовы инструментов, обработку ошибок.

Но чтобы понимать **как работает агент на самом деле**, полезно собрать **“пустого агента”** вручную.

Такой пример:

- показывает, как LLM принимает решения и вызывает инструменты;
- демонстрирует, как устроен цикл *Thought → Action → Observation*;
- помогает понять, почему **Stop & Parse** и структура промпта критически важны;
- даёт основу, если ты хочешь сделать свой собственный лёгкий агент без больших библиотек.

---

## Как всё устроено

Любой агент работает на основе **системного промпта**, в котором заранее описано:

- какие **инструменты** ему доступны (например, `get_weather`),
- как **оформлять действия** (JSON-структура),
- и какие **шаги цикла** он должен соблюдать (Thought → Action → Observation → Final Answer).

Вот пример такого промпта:

```python
SYSTEM_PROMPT = """Answer the following questions as best you can. You have access to the following tools:

get_weather: Get the current weather in a given location

The way you use the tools is by specifying a json blob.
Specifically, this json should have an `action` key (with the name of the tool to use) and an `action_input` key (with the input to the tool going here).

Example:
{
  "action": "get_weather",
  "action_input": {"location": "New York"}
}

ALWAYS use the following format:

Question: the input question you must answer
Thought: reasoning about one action
Action: $JSON_BLOB
Observation: result of the action
...
Final Answer: final response
"""

```

Теперь у модели есть инструкция, как мыслить, действовать и завершать ответ.

---

## Добавляем сообщение пользователя

Когда пользователь задаёт вопрос, его сообщение добавляется к системному:

```python
messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": "What's the weather in London?"}
]

```

Модель теперь видит не просто вопрос, а контекст о том, **какие инструменты ей доступны и как их вызывать.**

---

## Проблема “галлюцинации действий”

Если просто сгенерировать ответ:

```python
output = client.chat.completions.create(messages=messages, max_tokens=200)
print(output.choices[0].message.content)

```

Модель напишет:

```
Thought: I need to get the current weather in London.
Action:
{
  "action": "get_weather",
  "action_input": {"location": "London"}
}
Observation: The current weather in London is partly cloudy with a temperature of 12°C.

```

❗ Проблема: **она придумала Observation сама**, не вызвав никакой функции.

Это типичная “галлюцинация”, когда LLM симулирует ответ, не имея доступа к реальным данным.

---

## 🛑 Решение — Stop & Parse

Чтобы модель не выдумывала результат, нужно **остановить генерацию** сразу после слова `"Observation:"`.

```python
output = client.chat.completions.create(
    messages=messages,
    max_tokens=150,
    stop=["Observation:"]
)
print(output.choices[0].message.content)

```

Теперь модель формирует только **Thought и Action**, а выполнение действия и добавление Observation происходит вне модели.

---

## Добавляем “фиктивную” функцию

Создадим простую функцию, имитирующую вызов API:

```python
def get_weather(location):
    return f"The weather in {location} is sunny with low temperatures.\n"

```

Теперь агент сможет “узнавать” погоду, даже без внешних API.

---

## Цикл Thought → Action → Observation

1. **Модель думает и выбирает действие.**
    
    Она генерирует JSON с нужной функцией.
    
2. **Код выполняет это действие.**
    
    Мы вызываем `get_weather("London")`.
    
3. **Результат добавляется как Observation.**
    
    Мы дописываем Observation вручную в историю сообщений.
    

```python
messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": "What's the weather in London?"},
    {"role": "assistant", "content": output.choices[0].message.content + "Observation:\n" + get_weather('London')}
]

output = client.chat.completions.create(messages=messages, max_tokens=200)
print(output.choices[0].message.content)

```

Теперь модель завершает цикл:

```
Thought: I now know the final answer.
Final Answer: The weather in London is sunny with low temperatures.

```

---

## Что мы получили

- Модель **самостоятельно рассуждает**, выбирает инструмент и форматирует вызов.
- Код **перехватывает момент до Observation**, выполняет действие, вставляет реальный результат.
- Агент **продолжает генерацию**, используя Observation как контекст.

Это и есть базовый механизм всех современных агентных систем.

---

## Зачем тебе знать, как это работает

| Причина | Что это даёт |
| --- | --- |
| 🎯 **Контроль** | Ты понимаешь, как именно LLM вызывает инструменты и где могут появляться ошибки. |
| ⚙️ **Гибкость** | Можно сделать кастомный агент без громоздких фреймворков. |
| 🧠 **Понимание архитектуры** | Помогает разрабатывать собственные циклы reasoning (ReAct, CoT, Plan-Execute). |
| 🚀 **Оптимизация стоимости** | Можно контролировать количество вызовов модели и шагов цикла. |

## Советы

- Всегда ограничивай генерацию через `stop`токен, чтобы не допустить “галлюцинаций действий”.
- Форматируй Observation чётко — это “источник истины” для модели.
- Тестируй работу агента на фиктивных функциях, прежде чем подключать реальные API.

---

## 🧭 Вывод

**Dummy Agent — это минимальный рабочий пример, который показывает, как из LLM сделать исполнителя задач.**

Поняв этот принцип, ты сможешь:

- собирать собственные агентные фреймворки;
- отлаживать сложные цепочки reasoning;
- и понимать, как работают инструменты типа LangChain или Smolagents изнутри.

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